public virtual ICommit Commit(CommitAttempt attempt) { Logger.Debug(Messages.AttemptingToCommit, attempt.Events.Count, attempt.StreamId, attempt.CommitSequence); return(TryMongo(() => { BsonDocument commitDoc = attempt.ToMongoCommit(_getNextCheckpointNumber, _serializer); try { // for concurrency / duplicate commit detection safe mode is required PersistedCommits.Insert(commitDoc, WriteConcern.Acknowledged); UpdateStreamHeadAsync(attempt.BucketId, attempt.StreamId, attempt.StreamRevision, attempt.Events.Count); Logger.Debug(Messages.CommitPersisted, attempt.CommitId); } catch (MongoException e) { if (!e.Message.Contains(ConcurrencyException)) { throw; } ICommit savedCommit = PersistedCommits.FindOne(attempt.ToMongoCommitIdQuery()).ToCommit(_serializer); if (savedCommit.CommitId == attempt.CommitId) { throw new DuplicateCommitException(); } Logger.Debug(Messages.ConcurrentWriteDetected); throw new ConcurrencyException(); } return commitDoc.ToCommit(_serializer); })); }
private ICommit PersistWithServerSideOptimisticLoop(CommitAttempt attempt) { BsonDocument commitDoc = attempt.ToMongoCommit(_checkpointZero, _serializer); return(TryMongo(() => { var result = PersistedCommits.Database.Eval(new EvalArgs() { Code = _updateScript, Lock = false, Args = new BsonValue[] { commitDoc } }); if (!result.IsBsonDocument) { throw new Exception("Invalid response. Check server side js"); } if (result.AsBsonDocument.Contains("id")) { commitDoc["_id"] = result["id"]; UpdateStreamHeadAsync(attempt.BucketId, attempt.StreamId, attempt.StreamRevision, attempt.Events.Count); Logger.Debug(Messages.CommitPersisted, attempt.CommitId); } else if (result.AsBsonDocument.Contains("err")) { var errorDocument = result.AsBsonDocument; if (errorDocument["code"] != ConcurrencyExceptionCode) { throw new Exception(errorDocument["err"].AsString); } ICommit savedCommit = PersistedCommits.FindOne(attempt.ToMongoCommitIdQuery()).ToCommit(_serializer); if (savedCommit.CommitId == attempt.CommitId) { throw new DuplicateCommitException(String.Format( "Duplicated Commit: bucketId [{0}]: commitId [{1}] - streamId [{2}] - streamRevision [{3}]", attempt.BucketId, attempt.CommitId, attempt.StreamId, attempt.StreamRevision)); } Logger.Debug(Messages.ConcurrentWriteDetected); throw new ConcurrencyException(String.Format( "Concurrency exception forbucketId [{0}]: commitId [{1}] - streamId [{2}] - streamRevision [{3}]\n Inner provider error: {4}", attempt.BucketId, attempt.CommitId, attempt.StreamId, attempt.StreamRevision, errorDocument["err"].AsString)); } else { throw new Exception("Invalid response. Check server side js"); } return commitDoc.ToCommit(_serializer); })); }
private ICommit PersistWithClientSideOptimisticLoop(CommitAttempt attempt) { return(TryMongo(() => { BsonDocument commitDoc = attempt.ToMongoCommit( _getNextCheckpointNumber(), _serializer ); bool retry = true; while (retry) { try { // for concurrency / duplicate commit detection safe mode is required PersistedCommits.Insert(commitDoc, _insertCommitWriteConcern); retry = false; UpdateStreamHeadAsync(attempt.BucketId, attempt.StreamId, attempt.StreamRevision, attempt.Events.Count); Logger.Debug(Messages.CommitPersisted, attempt.CommitId); } catch (MongoException e) { if (!e.Message.Contains(ConcurrencyException)) { throw; } // checkpoint index? if (e.Message.Contains(MongoCommitIndexes.CheckpointNumberMMApV1) || e.Message.Contains(MongoCommitIndexes.CheckpointNumberWiredTiger)) { commitDoc[MongoCommitFields.CheckpointNumber] = _getNextCheckpointNumber().LongValue; } else { ICommit savedCommit = PersistedCommits.FindOne(attempt.ToMongoCommitIdQuery()).ToCommit(_serializer); if (savedCommit.CommitId == attempt.CommitId) { throw new DuplicateCommitException(); } Logger.Debug(Messages.ConcurrentWriteDetected); throw new ConcurrencyException(); } } } return commitDoc.ToCommit(_serializer); })); }
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); })); }