Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
            }
        }
Ejemplo n.º 4
0
        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));
                }
            }
        }
Ejemplo n.º 5
0
        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));
        }