private PrepareLogRecord ReadPrepareInternal(TFReaderLease reader, string streamId, int eventNumber) { // we assume that you already did check for stream deletion Ensure.NotNullOrEmpty(streamId, "streamId"); Ensure.Nonnegative(eventNumber, "eventNumber"); var streamHash = _hasher.Hash(streamId); long position; if (_tableIndex.TryGetOneValue(streamHash, eventNumber, out position)) { var rec = ReadPrepareInternal(reader, position); if (rec != null && rec.EventStreamId == streamId) { return(rec); } foreach (var indexEntry in _tableIndex.GetRange(streamHash, eventNumber, eventNumber)) { Interlocked.Increment(ref _hashCollisions); if (indexEntry.Position == position) // already checked that { continue; } rec = ReadPrepareInternal(reader, indexEntry.Position); if (rec != null && rec.EventStreamId == streamId) { return(rec); } } } return(null); }
private PrepareLogRecord ReadPrepareSkipScan(TFReaderLease reader, string streamId, long eventNumber) { long position; if (_tableIndex.TryGetOneValue(streamId, eventNumber, out position)) { var rec = ReadPrepareInternal(reader, position); if (rec != null && rec.EventStreamId == streamId) { return(rec); } foreach (var indexEntry in _tableIndex.GetRange(streamId, eventNumber, eventNumber)) { Interlocked.Increment(ref _hashCollisions); if (indexEntry.Position == position) { continue; } rec = ReadPrepareInternal(reader, indexEntry.Position); if (rec != null && rec.EventStreamId == streamId) { return(rec); } } } return(null); }
public void Commit(CommitLogRecord commit) { bool first = true; int eventNumber = -1; uint streamHash = 0; string eventStreamId = null; foreach (var prepare in GetTransactionPrepares(commit.TransactionPosition)) { if (first) { streamHash = _hasher.Hash(prepare.EventStreamId); eventStreamId = prepare.EventStreamId; first = false; } else { Debug.Assert(prepare.EventStreamId == eventStreamId); } bool addToIndex = false; if ((prepare.Flags & PrepareFlags.StreamDelete) != 0) { eventNumber = EventNumber.DeletedStream; _committedEvents.PutRecord(prepare.EventId, Tuple.Create(eventStreamId, eventNumber), throwOnDuplicate: false); addToIndex = commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint; } else if ((prepare.Flags & PrepareFlags.Data) != 0) { eventNumber = commit.EventNumber + prepare.TransactionOffset; _committedEvents.PutRecord(prepare.EventId, Tuple.Create(eventStreamId, eventNumber), throwOnDuplicate: false); addToIndex = commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint; } // could be just empty prepares for TransactionBegin and TransactionEnd, for instance // or records which are rebuilt but are already in PTables if (addToIndex) { #if DEBUG long pos; if (_tableIndex.TryGetOneValue(streamHash, eventNumber, out pos)) { EventRecord rec; if (ReadEvent(eventStreamId, eventNumber, out rec) == SingleReadResult.Success) { Debugger.Break(); throw new Exception( string.Format( "Trying to add duplicate event #{0} for stream {1}(hash {2})\nCommit: {3}\nPrepare: {4}.", eventNumber, eventStreamId, streamHash, commit, prepare)); } } #endif _tableIndex.Add(commit.LogPosition, streamHash, eventNumber, prepare.LogPosition); _bus.Publish(new ReplicationMessage.EventCommited(commit.LogPosition, eventNumber, prepare)); } _lastCommitPosition = Math.Max(_lastCommitPosition, commit.LogPosition); } }
public void Commit(CommitLogRecord commit) { if (_threadId.HasValue && _threadId != Thread.CurrentThread.ManagedThreadId) { Debugger.Break(); throw new Exception("Access to commit from multiple threads."); } _threadId = Thread.CurrentThread.ManagedThreadId; _tableIndex.CommitCheckpoint.Write(commit.LogPosition); bool first = true; int number = -1; uint streamHash = 0; string eventStreamId = null; foreach (var prepare in GetTransactionPrepares(commit.TransactionPosition)) { if (first) { streamHash = _hasher.Hash(prepare.EventStreamId); eventStreamId = prepare.EventStreamId; first = false; } else { Debug.Assert(prepare.EventStreamId == eventStreamId); } bool addToIndex = false; if ((prepare.Flags & PrepareFlags.StreamDelete) != 0) { //Debug.Assert(number == -1); number = EventNumber.DeletedStream; if (commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint) { addToIndex = true; } } else if ((prepare.Flags & PrepareFlags.Data) != 0) { if (prepare.ExpectedVersion == ExpectedVersion.Any) { if (number == -1) { number = commit.EventNumber - 1; } number = number + 1; } else { Debug.Assert(number == -1 || number == prepare.ExpectedVersion); number = prepare.ExpectedVersion + 1; } if (commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint) { addToIndex = true; } } // could be just empty prepares for TransactionBegin and TransactionEnd, for instance if (addToIndex) { long pos; if (_tableIndex.TryGetOneValue(streamHash, number, out pos)) { EventRecord rec; if (TryReadRecord(eventStreamId, number, out rec) == SingleReadResult.Success) { Debugger.Break(); throw new Exception( string.Format( "Trying to add duplicate event #{0} for stream {1}(hash {2})\nCommit: {3}\nPrepare: {4}.", number, eventStreamId, streamHash, commit, prepare)); } } _tableIndex.Add(streamHash, number, prepare.LogPosition); _bus.Publish(new ReplicationMessage.EventCommited(commit.LogPosition, number, prepare)); } } }
public void Commit(CommitLogRecord commit) { var lastCommitPosition = Interlocked.Read(ref _lastCommitPosition); if (commit.LogPosition < lastCommitPosition || (commit.LogPosition == lastCommitPosition && !_indexRebuild)) { return; // already committed } bool first = true; int eventNumber = -1; uint streamHash = 0; string streamId = null; foreach (var prepare in GetTransactionPrepares(commit.TransactionPosition)) { if (first) { streamHash = _hasher.Hash(prepare.EventStreamId); streamId = prepare.EventStreamId; first = false; } else { Debug.Assert(prepare.EventStreamId == streamId); } bool addToIndex = false; if ((prepare.Flags & PrepareFlags.StreamDelete) != 0) { eventNumber = EventNumber.DeletedStream; _committedEvents.PutRecord(prepare.EventId, Tuple.Create(streamId, eventNumber), throwOnDuplicate: false); addToIndex = commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint; } else if ((prepare.Flags & PrepareFlags.Data) != 0) { eventNumber = commit.EventNumber + prepare.TransactionOffset; _committedEvents.PutRecord(prepare.EventId, Tuple.Create(streamId, eventNumber), throwOnDuplicate: false); addToIndex = commit.LogPosition > _persistedCommitCheckpoint || commit.LogPosition == _persistedCommitCheckpoint && prepare.LogPosition > _persistedPrepareCheckpoint; } // could be just empty prepares for TransactionBegin and TransactionEnd, for instance // or records which are rebuilt but are already in PTables if (addToIndex) { #if CHECK_COMMIT_DUPLICATES long pos; if (_tableIndex.TryGetOneValue(streamHash, eventNumber, out pos)) { ReadEventResult res = ((IReadIndex)this).ReadEvent(eventStreamId, eventNumber); if (res.Result == SingleReadResult.Success) { Debugger.Break(); throw new Exception( string.Format( "Trying to add duplicate event #{0} for stream {1}(hash {2})\nCommit: {3}\nPrepare: {4}.", eventNumber, eventStreamId, streamHash, commit, prepare)); } } #endif _tableIndex.Add(commit.LogPosition, streamHash, eventNumber, prepare.LogPosition); _bus.Publish(new StorageMessage.EventCommited(commit.LogPosition, eventNumber, prepare)); } } if (first) { throw new Exception("No prepares for commit found!"); } var newLastCommitPosition = commit.LogPosition > lastCommitPosition ? commit.LogPosition : lastCommitPosition; if (Interlocked.CompareExchange(ref _lastCommitPosition, newLastCommitPosition, lastCommitPosition) != lastCommitPosition) { throw new Exception("Concurrency error in ReadIndex.Commit: _lastCommitPosition was modified during Commit execution!"); } _streamInfoCache.Put(streamId, key => new StreamCacheInfo(eventNumber, null), (key, old) => new StreamCacheInfo(eventNumber, old.Metadata)); }