Пример #1
0
        private async Task Bail(TransactionalStatus status, bool force = false)
        {
            List <Task> pending = new List <Task>();

            pending.Add(RWLock.AbortExecutingTransactions());
            this.RWLock.AbortQueuedTransactions();

            // abort all entries in the commit queue
            foreach (var entry in commitQueue.Elements)
            {
                pending.Add(NotifyOfAbort(entry, status));
            }
            commitQueue.Clear();

            await Task.WhenAll(pending);

            if (++failCounter >= 10 || force)
            {
                logger.Debug("StorageWorker triggering grain Deactivation");
                this.deactivate();
            }
            await this.Restore();
        }
Пример #2
0
        private async Task Bail(TransactionalStatus status, bool force = false)
        {
            await RWLock.AbortExecutingTransactions();

            // abort all entries in the commit queue
            foreach (var entry in commitQueue.Elements)
            {
                await NotifyOfAbort(entry, status);
            }
            commitQueue.Clear();

            this.RWLock.AbortQueuedTransactions();

            if (++failCounter >= 10 || force)
            {
                logger.Debug("StorageWorker triggering grain Deactivation");
                this.deactivate();
            }
            else
            {
                await this.Restore();
            }
        }
Пример #3
0
        private async Task StorageWork()
        {
            try
            {
                if (problemFlag != TransactionalStatus.Ok)
                {
                    RWLock.AbortExecutingTransactions();

                    // abort all entries in the commit queue
                    foreach (var entry in commitQueue.Elements)
                    {
                        NotifyOfAbort(entry, problemFlag);
                    }
                    commitQueue.Clear();

                    if (problemFlag == TransactionalStatus.StorageConflict)
                    {
                        logger.Debug("deactivating after storage conflict");
                        this.deactivate();
                        this.RWLock.AbortQueuedTransactions();
                    }
                    else
                    {
                        logger.Debug($"restoring state after status={problemFlag}");
                        // recover, clear storageFlag, then allow next queued transaction(s) to enter lock
                        await NotifyOfRestore();
                    }
                }
                else
                {
                    // count committable entries at the bottom of the commit queue
                    int committableEntries = 0;
                    while (committableEntries < commitQueue.Count && commitQueue[committableEntries].ReadyToCommit)
                    {
                        committableEntries++;
                    }

                    // process all committable entries, assembling a storage batch
                    if (committableEntries > 0)
                    {
                        // process all committable entries, adding storage events to the storage batch
                        CollectEventsForBatch(committableEntries);
                        if (problemFlag != TransactionalStatus.Ok)
                        {
                            return;
                        }

                        if (logger.IsEnabled(LogLevel.Debug))
                        {
                            var r = commitQueue.Count > committableEntries ? commitQueue[committableEntries].ToString() : "";
                            logger.Debug($"batchcommit={committableEntries} leave={commitQueue.Count - committableEntries} {r}");
                        }
                    }
                    else
                    {
                        // send or re-send messages and detect timeouts
                        CheckProgressOfCommitQueue();
                    }

                    // store the current storage batch, if it is not empty
                    StorageBatch <TState> batchBeingSentToStorage = null;
                    if (this.storageBatch.BatchSize > 0)
                    {
                        // get the next batch in place so it can be filled while we store the old one
                        batchBeingSentToStorage = this.storageBatch;
                        this.storageBatch       = new StorageBatch <TState>(batchBeingSentToStorage);

                        // perform the actual store, and record the e-tag
                        this.storageBatch.ETag = await batchBeingSentToStorage.Store(storage);
                    }

                    if (committableEntries > 0)
                    {
                        // update stable state
                        var lastCommittedEntry = commitQueue[committableEntries - 1];
                        this.stableState          = lastCommittedEntry.State;
                        this.stableSequenceNumber = lastCommittedEntry.SequenceNumber;
                        if (logger.IsEnabled(LogLevel.Trace))
                        {
                            logger.Trace($"Stable state version: {this.stableSequenceNumber}");
                        }


                        // remove committed entries from commit queue
                        commitQueue.RemoveFromFront(committableEntries);
                        storageWorker.Notify();  // we have to re-check for work
                    }

                    if (batchBeingSentToStorage != null)
                    {
                        batchBeingSentToStorage.RunFollowUpActions();
                        storageWorker.Notify();  // we have to re-check for work
                    }
                }
            }
            catch (InconsistentStateException e)
            {
                logger.Warn(888, $"reload from storage triggered by e-tag mismatch {e}");

                problemFlag = TransactionalStatus.StorageConflict;
            }
            catch (Exception e)
            {
                logger.Warn(888, $"exception in storageWorker", e);

                problemFlag = TransactionalStatus.UnknownException;
            } finally
            {
                if (problemFlag == TransactionalStatus.Ok)
                {
                    this.failCounter = 0;
                }
                else
                {
                    // after exceptions, we try again, but with limits
                    if (++failCounter < 10)
                    {
                        await Task.Delay(100);

                        // this restarts the worker, which sees the problem flag and recovers.
                        storageWorker.Notify();
                    }
                    else
                    {
                        // bail out
                        logger.Warn(999, $"storageWorker is bailing out");
                    }
                }
            }
        }