Esempio n. 1
0
        /// <inheritdoc/>
        protected override void ProcessNotifications()
        {
            // discard notifications that are behind our already confirmed state
            while (notifications.Count > 0 && notifications.ElementAt(0).Key < GlobalStateCache.GlobalVersion)
            {
                Services.Log(Severity.Verbose, "discarding notification {0}", notifications.ElementAt(0).Value);
                notifications.RemoveAt(0);
            }

            // process notifications that reflect next global version
            while (notifications.Count > 0 && notifications.ElementAt(0).Key == GlobalStateCache.GlobalVersion)
            {
                var updateNotification = notifications.ElementAt(0).Value;
                notifications.RemoveAt(0);

                // Apply all operations in pending
                foreach (var u in updateNotification.Updates)
                {
                    try
                    {
                        Host.UpdateView(GlobalStateCache.State, u);
                    }
                    catch (Exception e)
                    {
                        Services.CaughtUserCodeException("UpdateView", nameof(ProcessNotifications), e);
                    }
                }

                GlobalStateCache.GlobalVersion = updateNotification.Version;

                GlobalStateCache.FlipBit(updateNotification.Origin);

                GlobalStateCache.ETag = updateNotification.ETag;

                Services.Log(Severity.Verbose, "notification success ({0} updates) {1}", updateNotification.Updates.Count, GlobalStateCache);
            }

            Services.Log(Severity.Verbose2, "unprocessed notifications in queue: {0}", notifications.Count);

            base.ProcessNotifications();
        }
Esempio n. 2
0
        /// <inheritdoc/>
        protected override async Task <int> WriteAsync()
        {
            enter_operation("WriteAsync");

            var  state   = CopyTentativeState();
            var  updates = GetCurrentBatchOfUpdates();
            bool batchsuccessfullywritten = false;

            var nextglobalstate = new GrainStateWithMetaDataAndETag <TLogView>(state);

            nextglobalstate.WriteVector   = GlobalStateCache.WriteVector;
            nextglobalstate.GlobalVersion = GlobalStateCache.GlobalVersion + updates.Length;
            nextglobalstate.ETag          = GlobalStateCache.ETag;

            var writebit = nextglobalstate.FlipBit(Services.MyClusterId);

            try
            {
                // for manual testing
                //await Task.Delay(5000);

                await globalStorageProvider.WriteStateAsync(grainTypeName, Services.GrainReference, nextglobalstate);

                batchsuccessfullywritten = true;

                GlobalStateCache = nextglobalstate;

                Services.Log(Severity.Verbose, "write ({0} updates) success {1}", updates.Length, GlobalStateCache);

                LastPrimaryIssue.Resolve(Host, Services);
            }
            catch (Exception e)
            {
                LastPrimaryIssue.Record(new UpdateStateStorageFailed()
                {
                    Exception = e
                }, Host, Services);
            }

            if (!batchsuccessfullywritten)
            {
                Services.Log(Severity.Verbose, "write apparently failed {0} {1}", nextglobalstate, LastPrimaryIssue);

                while (true) // be stubborn until we can read what is there
                {
                    await LastPrimaryIssue.DelayBeforeRetry();

                    try
                    {
                        await globalStorageProvider.ReadStateAsync(grainTypeName, Services.GrainReference, GlobalStateCache);

                        Services.Log(Severity.Verbose, "read success {0}", GlobalStateCache);

                        LastPrimaryIssue.Resolve(Host, Services);

                        break;
                    }
                    catch (Exception e)
                    {
                        LastPrimaryIssue.Record(new ReadFromStateStorageFailed()
                        {
                            Exception = e
                        }, Host, Services);
                    }

                    Services.Log(Severity.Verbose, "read failed {0}", LastPrimaryIssue);
                }

                // check if last apparently failed write was in fact successful

                if (writebit == GlobalStateCache.GetBit(Services.MyClusterId))
                {
                    GlobalStateCache = nextglobalstate;

                    Services.Log(Severity.Verbose, "last write ({0} updates) was actually a success {1}", updates.Length, GlobalStateCache);

                    batchsuccessfullywritten = true;
                }
            }


            // broadcast notifications to all other clusters
            if (batchsuccessfullywritten)
            {
                BroadcastNotification(new UpdateNotificationMessage()
                {
                    Version = GlobalStateCache.GlobalVersion,
                    Updates = updates.Select(se => se.Entry).ToList(),
                    Origin  = Services.MyClusterId,
                    ETag    = GlobalStateCache.ETag
                });
            }

            exit_operation("WriteAsync");

            if (!batchsuccessfullywritten)
            {
                return(0);
            }

            return(updates.Length);
        }