public virtual void Commit(Commit attempt) { Logger.Debug(Messages.AttemptingToCommit, attempt.Events.Count, attempt.StreamId, attempt.CommitSequence); TryMongo(() => { BsonDocument commit = attempt.ToMongoCommit(_serializer); try { // for concurrency / duplicate commit detection safe mode is required PersistedCommits.Insert(commit, 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; } Commit savedCommit = PersistedCommits.FindOne(attempt.ToMongoCommitIdQuery()).ToCommit(_serializer); if (savedCommit.CommitId == attempt.CommitId) { throw new DuplicateCommitException(); } Logger.Debug(Messages.ConcurrentWriteDetected); throw new ConcurrencyException(); } }); }
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); })); }