private void FillHole(CommitAttempt attempt, Int64 checkpointId)
 {
     try
     {
         var holeFillDoc = attempt.ToEmptyCommit(
             checkpointId,
             _systemBucketName
             );
         PersistedCommits.InsertOne(holeFillDoc);
     }
     catch (OutOfMemoryException)
     {
         throw;
     }
     catch (Exception e)
     {
         Logger.LogWarning(e, Messages.FillHoleError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId, e);
     }
 }
Beispiel #2
0
        public virtual ICommit Commit(CommitAttempt attempt)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug(Messages.AttemptingToCommit, attempt.Events.Count, attempt.StreamId, attempt.CommitSequence);
            }

            return(TryMongo(() =>
            {
                Int64 checkpointId;
                var commitDoc = attempt.ToMongoCommit(
                    checkpointId = _checkpointGenerator.Next(),
                    _serializer
                    );

                bool retry = true;
                while (retry)
                {
                    try
                    {
                        // for concurrency / duplicate commit detection safe mode is required
                        PersistedCommits.InsertOne(commitDoc);

                        retry = false;
                        if (!_options.DisableSnapshotSupport)
                        {
                            UpdateStreamHeadInBackgroundThread(attempt.BucketId, attempt.StreamId, attempt.StreamRevision, attempt.Events.Count);
                        }

                        if (Logger.IsDebugEnabled)
                        {
                            Logger.Debug(Messages.CommitPersisted, attempt.CommitId);
                        }
                    }
                    catch (MongoException e)
                    {
                        if (!e.Message.Contains(ConcurrencyException))
                        {
                            if (Logger.IsErrorEnabled)
                            {
                                Logger.Error(Messages.GenericPersistingError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId, e);
                            }
                            throw;
                        }

                        // checkpoint index?
                        if (e.Message.Contains(MongoCommitIndexes.CheckpointNumberMMApV1) ||
                            e.Message.Contains(MongoCommitIndexes.CheckpointNumberWiredTiger))
                        {
                            if (Logger.IsWarnEnabled)
                            {
                                Logger.Warn(Messages.DuplicatedCheckpointTokenError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId);
                            }
                            _checkpointGenerator.SignalDuplicateId(checkpointId);
                            commitDoc[MongoCommitFields.CheckpointNumber] = checkpointId = _checkpointGenerator.Next();
                        }
                        else
                        {
                            if (_options.ConcurrencyStrategy == ConcurrencyExceptionStrategy.FillHole)
                            {
                                FillHole(attempt, checkpointId);
                            }

                            if (e.Message.Contains(MongoCommitIndexes.CommitId))
                            {
                                var msg = String.Format(Messages.DuplicatedCommitError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId);
                                if (Logger.IsInfoEnabled)
                                {
                                    Logger.Info(msg);
                                }
                                throw new DuplicateCommitException(msg);
                            }

                            ICommit savedCommit = PersistedCommits
                                                  .FindSync(attempt.ToMongoCommitIdQuery())
                                                  .FirstOrDefault()
                                                  .ToCommit(_serializer);

                            if (savedCommit != null && savedCommit.CommitId == attempt.CommitId)
                            {
                                var msg = String.Format(Messages.DuplicatedCommitError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId);
                                if (Logger.IsInfoEnabled)
                                {
                                    Logger.Info(msg);
                                }
                                throw new DuplicateCommitException(msg);
                            }

                            if (Logger.IsInfoEnabled)
                            {
                                Logger.Info(Messages.ConcurrencyExceptionError, attempt.CommitId, checkpointId, attempt.BucketId, attempt.StreamId, e);
                            }
                            throw new ConcurrencyException();
                        }
                    }
                }

                return commitDoc.ToCommit(_serializer);
            }));
        }