示例#1
0
        public void PreCommit(IList <PrepareLogRecord> commitedPrepares)
        {
            if (commitedPrepares.Count == 0)
            {
                return;
            }

            var    lastPrepare = commitedPrepares[commitedPrepares.Count - 1];
            string streamId    = lastPrepare.EventStreamId;
            long   eventNumber = EventNumber.Invalid;

            foreach (var prepare in commitedPrepares)
            {
                if (prepare.Flags.HasNoneOf(PrepareFlags.StreamDelete | PrepareFlags.Data))
                {
                    continue;
                }

                if (prepare.EventStreamId != streamId)
                {
                    throw new Exception(string.Format("Expected stream: {0}, actual: {1}.", streamId,
                                                      prepare.EventStreamId));
                }

                eventNumber =
                    prepare.ExpectedVersion + 1;                     /* for committed prepare expected version is always explicit */
                _committedEvents.PutRecord(prepare.EventId, new EventInfo(streamId, eventNumber),
                                           throwOnDuplicate: false);
            }

            _notProcessedCommits.Enqueue(new CommitInfo(streamId, lastPrepare.LogPosition));
            _streamVersions.Put(streamId, eventNumber, 1);
            if (SystemStreams.IsMetastream(streamId))
            {
                var rawMeta = lastPrepare.Data;
                _streamRawMetas.Put(SystemStreams.OriginalStreamOf(streamId), new StreamMeta(rawMeta, null), +1);
            }
        }
示例#2
0
        public Task <RawStreamMetadataResult> GetStreamMetadataAsRawBytesAsync(string stream,
                                                                               UserCredentials userCredentials = null)
        {
            return(ReadEventAsync(SystemStreams.MetastreamOf(stream), -1, false,
                                  GetUserCredentials(_settings, userCredentials)).ContinueWith(t => {
                if (t.Exception != null)
                {
                    throw t.Exception.InnerException;
                }

                var res = t.Result;
                switch (res.Status)
                {
                case EventReadStatus.Success:
                    if (res.Event == null)
                    {
                        throw new Exception("Event is null while operation result is Success.");
                    }
                    var evnt = res.Event.Value.OriginalEvent;
                    if (evnt == null)
                    {
                        return new RawStreamMetadataResult(stream, false, -1, Empty.ByteArray);
                    }
                    return new RawStreamMetadataResult(stream, false, evnt.EventNumber, evnt.Data);

                case EventReadStatus.NotFound:
                case EventReadStatus.NoStream:
                    return new RawStreamMetadataResult(stream, false, -1, Empty.ByteArray);

                case EventReadStatus.StreamDeleted:
                    return new RawStreamMetadataResult(stream, true, long.MaxValue, Empty.ByteArray);

                default:
                    throw new ArgumentOutOfRangeException(string.Format("Unexpected ReadEventResult: {0}.",
                                                                        res.Status));
                }
            }));
        }
示例#3
0
        private StreamMetadata GetStreamMetadataUncached(TFReaderLease reader, string streamId)
        {
            var metastreamId    = SystemStreams.MetastreamOf(streamId);
            var metaEventNumber = GetStreamLastEventNumberCached(reader, metastreamId);

            if (metaEventNumber == ExpectedVersion.NoStream || metaEventNumber == EventNumber.DeletedStream)
            {
                return(StreamMetadata.Empty);
            }

            PrepareLogRecord prepare = ReadPrepareInternal(reader, metastreamId, metaEventNumber);

            if (prepare == null)
            {
                throw new Exception(string.Format("ReadPrepareInternal could not find metaevent #{0} on metastream '{1}'. "
                                                  + "That should never happen.", metaEventNumber, metastreamId));
            }

            if (prepare.Data.Length == 0 || prepare.Flags.HasNoneOf(PrepareFlags.IsJson))
            {
                return(StreamMetadata.Empty);
            }

            try
            {
                var metadata = StreamMetadata.FromJsonBytes(prepare.Data);
                if (prepare.Version == LogRecordVersion.LogRecordV0 && metadata.TruncateBefore == int.MaxValue)
                {
                    metadata = new StreamMetadata(metadata.MaxCount, metadata.MaxAge, EventNumber.DeletedStream,
                                                  metadata.TempStream, metadata.CacheControl, metadata.Acl);
                }
                return(metadata);
            }
            catch (Exception)
            {
                return(StreamMetadata.Empty);
            }
        }
示例#4
0
        public void BeginMarkParkedMessagesReprocessed(long sequence, Action completed)
        {
            var metaStreamId = SystemStreams.MetastreamOf(ParkedStreamId);

            _ioDispatcher.WriteEvent(
                metaStreamId, ExpectedVersion.Any, CreateStreamMetadataEvent(sequence), SystemAccounts.System,
                msg => {
                switch (msg.Result)
                {
                case OperationResult.Success:
                    _lastTruncateBefore = sequence;
                    completed?.Invoke();
                    break;

                default:
                    Log.Error("An error occured truncating the parked message stream {stream} due to {e}.",
                              ParkedStreamId, msg.Result);
                    Log.Error("Messages were not removed on retry");
                    completed?.Invoke();
                    break;
                }
            });
        }
示例#5
0
        public Task <WriteResult> SetStreamMetadataAsync(string stream, long expectedMetastreamVersion, byte[] metadata, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            if (SystemStreams.IsMetastream(stream))
            {
                throw new ArgumentException(string.Format("Setting metadata for metastream '{0}' is not supported.", stream), "stream");
            }

            var metaevent  = new EventData(Guid.NewGuid(), SystemEventTypes.StreamMetadata, true, metadata ?? Empty.ByteArray, null);
            var metastream = SystemStreams.MetastreamOf(stream);

            var source = new TaskCompletionSource <WriteResult>(TaskCreationOptions.RunContinuationsAsynchronously);

            var envelope = new EmbeddedResponseEnvelope(
                new EmbeddedResponders.AppendToStream(source, metastream, expectedMetastreamVersion));

            var corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.WriteEvents(corrId, corrId, envelope, false, metastream,
                                                                                                                                                                                     expectedMetastreamVersion, metaevent.ConvertToEvent(), user));

            return(source.Task);
        }
示例#6
0
 public StorageMessage.EffectiveAcl GetEffectiveAcl(string streamId)
 {
     using (var reader = _backend.BorrowReader()) {
         var       sysSettings = _backend.GetSystemSettings() ?? SystemSettings.Default;
         StreamAcl acl;
         StreamAcl sysAcl;
         StreamAcl defAcl;
         var       meta = GetStreamMetadataCached(reader, streamId);
         if (SystemStreams.IsSystemStream(streamId))
         {
             defAcl = SystemSettings.Default.SystemStreamAcl;
             sysAcl = sysSettings.SystemStreamAcl ?? defAcl;
             acl    = meta.Acl ?? sysAcl;
         }
         else
         {
             defAcl = SystemSettings.Default.UserStreamAcl;
             sysAcl = sysSettings.UserStreamAcl ?? defAcl;
             acl    = meta.Acl ?? sysAcl;
         }
         return(new StorageMessage.EffectiveAcl(acl, sysAcl, defAcl));
     }
 }
示例#7
0
        public async Task should_be_able_to_subscribe_to_all_with_volatile_subscription()
        {
            var evnt = new EventData(Guid.NewGuid(), "EventType", false, new byte[10], new byte[15]);

            EventStore.ClientAPI.ResolvedEvent receivedEvent = new EventStore.ClientAPI.ResolvedEvent();
            var mre = new ManualResetEvent(false);
            await _store.SubscribeToAllAsync(true, (s, e) => {
                if (SystemStreams.IsSystemStream(e.OriginalStreamId))
                {
                    return(Task.CompletedTask);
                }

                receivedEvent = e;
                mre.Set();
                return(Task.CompletedTask);
            }, userCredentials : DefaultData.AdminCredentials);

            await _store.AppendToStreamAsync(_volatileStreamTwo, intMaxValue + 2, evnt);

            Assert.That(mre.WaitOne(TimeSpan.FromSeconds(5)), "Timed out waiting for events to appear");

            Assert.AreEqual(evnt.EventId, receivedEvent.Event.EventId);
        }
        public async Task <WriteResult> SetStreamMetadataAsync(string stream, long expectedMetastreamVersion, byte[] metadata, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            if (SystemStreams.IsMetastream(stream))
            {
                throw new ArgumentException(string.Format("Setting metadata for metastream '{0}' is not supported.", stream), nameof(stream));
            }

            var source = new TaskCompletionSource <WriteResult>(TaskCreationOptions.RunContinuationsAsynchronously);

            var metaevent = new EventData(Guid.NewGuid(), SystemEventTypes.StreamMetadata, true, metadata ?? Empty.ByteArray, null);
            var operation = new AppendToStreamOperation(Settings.Log,
                                                        source,
                                                        Settings.RequireMaster,
                                                        SystemStreams.MetastreamOf(stream),
                                                        expectedMetastreamVersion,
                                                        new[] { metaevent },
                                                        userCredentials);

            await EnqueueOperation(operation).ConfigureAwait(false);

            return(await source.Task.ConfigureAwait(false));
        }
示例#9
0
        public bool GetOrAddId(string name, out long streamNumber, out long createdId, out string createdName)
        {
            Ensure.NotNullOrEmpty(name, "name");
            if (SystemStreams.IsMetastream(name))
            {
                throw new ArgumentException(nameof(name));
            }

            var oldNext = _next;

            streamNumber = _dict.GetOrAdd(name, n => {
                _next             += 2;
                var streamNumber   = _next;
                _dict[n]           = streamNumber;
                _rev[streamNumber] = n;
                return(streamNumber);
            });

            // return true if we found an existing entry. i.e. did not have to allocate from _next
            createdId   = streamNumber;
            createdName = name;
            return(oldNext == _next);
        }
示例#10
0
        private ClientMessage.ReadEventCompleted ReadEvent(ClientMessage.ReadEvent msg)
        {
            using (HistogramService.Measure(_readerReadHistogram))
            {
                try
                {
                    var access = _readIndex.CheckStreamAccess(msg.EventStreamId, StreamAccessType.Read, msg.User);
                    if (!access.Granted)
                    {
                        return(NoData(msg, ReadEventResult.AccessDenied));
                    }

                    var result = _readIndex.ReadEvent(msg.EventStreamId, msg.EventNumber);
                    var record = result.Result == ReadEventResult.Success && msg.ResolveLinkTos
                                         ? ResolveLinkToEvent(result.Record, msg.User, null)
                                         : ResolvedEvent.ForUnresolvedEvent(result.Record);
                    if (record == null)
                    {
                        return(NoData(msg, ReadEventResult.AccessDenied));
                    }
                    if ((result.Result == ReadEventResult.NoStream ||
                         result.Result == ReadEventResult.NotFound) &&
                        result.OriginalStreamExists &&
                        SystemStreams.IsSystemStream(msg.EventStreamId))
                    {
                        return(NoData(msg, ReadEventResult.Success));
                    }
                    return(new ClientMessage.ReadEventCompleted(msg.CorrelationId, msg.EventStreamId, result.Result,
                                                                record.Value, result.Metadata, access.Public, null));
                }
                catch (Exception exc)
                {
                    Log.ErrorException(exc, "Error during processing ReadEvent request.");
                    return(NoData(msg, ReadEventResult.Error, exc.Message));
                }
            }
        }
        private void SetMaxAge()
        {
            var metaStreamId = SystemStreams.MetastreamOf(SystemStreams.ScavengesStream);

            _ioDispatcher.ReadBackward(metaStreamId, -1, 1, false, SystemAccount.Principal, readResult => {
                if (readResult.Result == ReadStreamResult.Success || readResult.Result == ReadStreamResult.NoStream)
                {
                    if (readResult.Events.Length == 1)
                    {
                        var currentMetadata = StreamMetadata.FromJsonBytes(readResult.Events[0].Event.Data);

                        if (currentMetadata.MaxAge == _scavengeHistoryMaxAge)
                        {
                            Log.Debug("Max age already set for the {stream} stream.", SystemStreams.ScavengesStream);
                            return;
                        }
                    }

                    Log.Debug("Setting max age for the {stream} stream to {maxAge}.", SystemStreams.ScavengesStream,
                              _scavengeHistoryMaxAge);

                    var metadata        = new StreamMetadata(maxAge: _scavengeHistoryMaxAge);
                    var metaStreamEvent = new Event(Guid.NewGuid(), SystemEventTypes.StreamMetadata, isJson: true,
                                                    data: metadata.ToJsonBytes(), metadata: null);
                    _ioDispatcher.WriteEvent(metaStreamId, ExpectedVersion.Any, metaStreamEvent,
                                             SystemAccount.Principal, m => {
                        if (m.Result != OperationResult.Success)
                        {
                            Log.Error(
                                "Failed to write the $maxAge of {days} days metadata for the {stream} stream. Reason: {reason}",
                                _scavengeHistoryMaxAge.TotalDays, SystemStreams.ScavengesStream, m.Result);
                        }
                    });
                }
            });
        }
示例#12
0
        public long LookupId(string streamName)
        {
            long streamId;

            if (SystemStreams.IsMetastream(streamName))
            {
                streamName = SystemStreams.OriginalStreamOf(streamName);
                streamId   = LookupId(streamName);
                return(_metastreams.MetaStreamOf(streamId));
            }

            if (LogV3SystemStreams.TryGetVirtualStreamId(streamName, out streamId))
            {
                return(streamId);
            }

            var result = _wrapped.LookupId(streamName);

            return(result == default
                                ? SystemStreams.IsSystemStream(streamName)
                                        ? LogV3SystemStreams.NoSystemStream
                                        : LogV3SystemStreams.NoUserStream
                                : result);
        }
示例#13
0
        public void ScavengeStarted(bool alwaysKeepScavenged, bool mergeChunks, int startFromChunk, int threads)
        {
            var metadataEventId = Guid.NewGuid();
            var metaStreamId    = SystemStreams.MetastreamOf(_streamName);
            var acl             = new StreamAcl(
                new string[] { "$ops" },
                new string[] { },
                new string[] { },
                new string[] { },
                new string[] { }
                );
            var metadata        = new StreamMetadata(maxAge: _scavengeHistoryMaxAge, acl: acl);
            var metaStreamEvent = new Event(metadataEventId, SystemEventTypes.StreamMetadata, isJson: true,
                                            data: metadata.ToJsonBytes(), metadata: null);

            _ioDispatcher.WriteEvent(metaStreamId, ExpectedVersion.Any, metaStreamEvent, SystemAccounts.System, m => {
                if (m.Result != OperationResult.Success)
                {
                    Log.Error(
                        "Failed to write the $maxAge of {days} days metadata for the {stream} stream. Reason: {reason}",
                        _scavengeHistoryMaxAge.TotalDays, _streamName, m.Result);
                }
            });

            var scavengeStartedEvent = new Event(Guid.NewGuid(), SystemEventTypes.ScavengeStarted, true,
                                                 new Dictionary <string, object> {
                { "scavengeId", _scavengeId },
                { "nodeEndpoint", _nodeId },
                { "alwaysKeepScavenged", alwaysKeepScavenged },
                { "mergeChunks", mergeChunks },
                { "startFromChunk", startFromChunk },
                { "threads", threads },
            }.ToJsonBytes(), null);

            WriteScavengeDetailEvent(_streamName, scavengeStartedEvent, _retryAttempts);
        }
        public void Handle(ClientMessage.DeleteStream message)
        {
            List <EventRecord> list;

            if (_deletedStreams.Contains(message.EventStreamId))
            {
                message.Envelope.ReplyWith(new ClientMessage.DeleteStreamCompleted(message.CorrelationId, OperationResult.StreamDeleted, string.Empty));
                return;
            }
            if (!_streams.TryGetValue(message.EventStreamId, out list) || list == null)
            {
                message.Envelope.ReplyWith(new ClientMessage.DeleteStreamCompleted(message.CorrelationId, OperationResult.WrongExpectedVersion, string.Empty));
                return;
            }
            _deletedStreams.Add(message.EventStreamId);

            ProcessWrite <Message>(
                null, message.CorrelationId, SystemStreams.MetastreamOf(message.EventStreamId), ExpectedVersion.Any,
                new Event[]
                { new Event(Guid.NewGuid(), SystemEventTypes.StreamMetadata, true, CreateStreamDeletedEventJson(), null) },
                null, null);

            message.Envelope.ReplyWith(new ClientMessage.DeleteStreamCompleted(message.CorrelationId, OperationResult.Success, string.Empty));
        }
示例#15
0
 private static void UpdateStreamAclWithRetry(
     this IODispatcher ioDispatcher,
     CancellationScope cancellationScope,
     string streamId,
     int expectedVersion,
     IPrincipal principal,
     StreamMetadata metadata,
     Action <ClientMessage.WriteEventsCompleted> handler,
     IEnumerator <Step> steps)
 {
     PerformWithRetry(
         ioDispatcher,
         handler,
         steps,
         expectedVersion == ExpectedVersion.Any,
         TimeSpan.FromMilliseconds(100),
         action =>
         cancellationScope.Register(
             ioDispatcher.WriteEvents(
                 SystemStreams.MetastreamOf(streamId),
                 expectedVersion,
                 new[]
     {
         new Event(Guid.NewGuid(), SystemEventTypes.StreamMetadata, true, metadata.ToJsonBytes(),
                   null)
     },
                 principal,
                 response =>
     {
         if (cancellationScope.Cancelled(response.CorrelationId))
         {
             return;
         }
         action(response, response.Result);
     })));
 }
        protected EventRecord WriteStreamMetadata(string eventStreamId, int eventNumber, string metadata, DateTime?timestamp = null)
        {
            var prepare = LogRecord.SingleWrite(WriterCheckpoint.ReadNonFlushed(),
                                                Guid.NewGuid(),
                                                Guid.NewGuid(),
                                                SystemStreams.MetastreamOf(eventStreamId),
                                                eventNumber - 1,
                                                SystemEventTypes.StreamMetadata,
                                                Helper.UTF8NoBom.GetBytes(metadata),
                                                null,
                                                timestamp ?? DateTime.UtcNow,
                                                PrepareFlags.IsJson);
            long pos;

            Assert.IsTrue(Writer.Write(prepare, out pos));

            var commit = LogRecord.Commit(WriterCheckpoint.ReadNonFlushed(), prepare.CorrelationId, prepare.LogPosition, eventNumber);

            Assert.IsTrue(Writer.Write(commit, out pos));

            var eventRecord = new EventRecord(eventNumber, prepare);

            return(eventRecord);
        }
示例#17
0
        public async Task reads_all_existing_events_after_position_and_keep_listening_to_new_ones()
        {
            var events = _fixture.CreateTestEvents(20).ToArray();

            var appeared = new TaskCompletionSource <bool>();
            var dropped  = new TaskCompletionSource <(SubscriptionDroppedReason, Exception)>();

            var beforeEvents = events.Take(10);
            var afterEvents  = events.Skip(10);

            using var enumerator = events.AsEnumerable().GetEnumerator();

            enumerator.MoveNext();

            var position = await _fixture.Client.ReadAllAsync(Direction.Forwards, Position.Start, 1)
                           .Select(x => x.OriginalEvent.Position)
                           .FirstAsync();

            foreach (var @event in beforeEvents)
            {
                await _fixture.Client.AppendToStreamAsync($"stream-{@event.EventId:n}", AnyStreamRevision.NoStream,
                                                          new[] { @event });
            }

            using var subscription =
                      await _fixture.Client.SubscribeToAllAsync(position, EventAppeared, false, SubscriptionDropped);

            foreach (var @event in afterEvents)
            {
                await _fixture.Client.AppendToStreamAsync($"stream-{@event.EventId:n}", AnyStreamRevision.NoStream,
                                                          new[] { @event });
            }

            await appeared.Task.WithTimeout();

            Assert.False(dropped.Task.IsCompleted);

            subscription.Dispose();

            var(reason, ex) = await dropped.Task.WithTimeout();

            Assert.Equal(SubscriptionDroppedReason.Disposed, reason);
            Assert.Null(ex);

            Task EventAppeared(StreamSubscription s, ResolvedEvent e, CancellationToken ct)
            {
                if (position >= e.OriginalEvent.Position)
                {
                    appeared.TrySetException(new Exception());
                }

                if (!SystemStreams.IsSystemStream(e.OriginalStreamId))
                {
                    try {
                        Assert.Equal(enumerator.Current.EventId, e.OriginalEvent.EventId);
                        if (!enumerator.MoveNext())
                        {
                            appeared.TrySetResult(true);
                        }
                    } catch (Exception ex) {
                        appeared.TrySetException(ex);
                        throw;
                    }
                }

                return(Task.CompletedTask);
            }

            void SubscriptionDropped(StreamSubscription s, SubscriptionDroppedReason reason, Exception ex) =>
            dropped.SetResult((reason, ex));
        }
示例#18
0
        private StreamAccess CheckStreamAccessInternal(TFReaderLease reader, string streamId,
                                                       StreamAccessType streamAccessType, IPrincipal user)
        {
            if (SystemStreams.IsMetastream(streamId))
            {
                switch (streamAccessType)
                {
                case StreamAccessType.Read:
                    return(CheckStreamAccessInternal(reader, SystemStreams.OriginalStreamOf(streamId), StreamAccessType.MetaRead, user));

                case StreamAccessType.Write:
                    return(CheckStreamAccessInternal(reader, SystemStreams.OriginalStreamOf(streamId), StreamAccessType.MetaWrite, user));

                case StreamAccessType.Delete:
                case StreamAccessType.MetaRead:
                case StreamAccessType.MetaWrite:
                    return(new StreamAccess(false));

                default:
                    throw new ArgumentOutOfRangeException("streamAccessType");
                }
            }

            if ((streamAccessType == StreamAccessType.Write || streamAccessType == StreamAccessType.Delete) &&
                streamId == SystemStreams.AllStream)
            {
                return(new StreamAccess(false));
            }

            var       sysSettings = _cache.GetSystemSettings() ?? SystemSettings.Default;
            var       meta        = GetStreamMetadataCached(reader, streamId);
            StreamAcl acl;
            StreamAcl sysAcl;
            StreamAcl defAcl;

            if (SystemStreams.IsSystemStream(streamId))
            {
                defAcl = SystemSettings.Default.SystemStreamAcl;
                sysAcl = sysSettings.SystemStreamAcl ?? defAcl;
                acl    = meta.Acl ?? sysAcl;
            }
            else
            {
                defAcl = SystemSettings.Default.UserStreamAcl;
                sysAcl = sysSettings.UserStreamAcl ?? defAcl;
                acl    = meta.Acl ?? sysAcl;
            }
            string[] roles;
            switch (streamAccessType)
            {
            case StreamAccessType.Read: roles = acl.ReadRoles ?? sysAcl.ReadRoles ?? defAcl.ReadRoles; break;

            case StreamAccessType.Write: roles = acl.WriteRoles ?? sysAcl.WriteRoles ?? defAcl.WriteRoles; break;

            case StreamAccessType.Delete: roles = acl.DeleteRoles ?? sysAcl.DeleteRoles ?? defAcl.DeleteRoles; break;

            case StreamAccessType.MetaRead: roles = acl.MetaReadRoles ?? sysAcl.MetaReadRoles ?? defAcl.MetaReadRoles; break;

            case StreamAccessType.MetaWrite: roles = acl.MetaWriteRoles ?? sysAcl.MetaWriteRoles ?? defAcl.MetaWriteRoles; break;

            default: throw new ArgumentOutOfRangeException("streamAccessType");
            }

            var isPublic = roles.Contains(x => x == SystemRoles.All);

            if (isPublic)
            {
                return(new StreamAccess(true, true));
            }
            if (user == null)
            {
                return(new StreamAccess(false));
            }
            if (user.IsInRole(SystemRoles.Admins))
            {
                return(new StreamAccess(true));
            }
            for (int i = 0; i < roles.Length; ++i)
            {
                if (user.IsInRole(roles[i]))
                {
                    return(new StreamAccess(true));
                }
            }
            return(new StreamAccess(false));
        }
示例#19
0
        public CommitCheckResult CheckCommit(string streamId, long expectedVersion, IEnumerable <Guid> eventIds)
        {
            var curVersion = GetStreamLastEventNumber(streamId);

            if (curVersion == EventNumber.DeletedStream)
            {
                return(new CommitCheckResult(CommitDecision.Deleted, streamId, curVersion, -1, -1, false));
            }
            if (curVersion == EventNumber.Invalid)
            {
                return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false));
            }

            if (expectedVersion == ExpectedVersion.StreamExists)
            {
                if (IsSoftDeleted(streamId))
                {
                    return(new CommitCheckResult(CommitDecision.Deleted, streamId, curVersion, -1, -1, true));
                }

                if (curVersion < 0)
                {
                    var metadataVersion = GetStreamLastEventNumber(SystemStreams.MetastreamOf(streamId));
                    if (metadataVersion < 0)
                    {
                        return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1,
                                                     false));
                    }
                }
            }

            // idempotency checks
            if (expectedVersion == ExpectedVersion.Any || expectedVersion == ExpectedVersion.StreamExists)
            {
                var  first            = true;
                long startEventNumber = -1;
                long endEventNumber   = -1;
                foreach (var eventId in eventIds)
                {
                    EventInfo prepInfo;
                    if (!_committedEvents.TryGetRecord(eventId, out prepInfo) || prepInfo.StreamId != streamId)
                    {
                        return(new CommitCheckResult(first ? CommitDecision.Ok : CommitDecision.CorruptedIdempotency,
                                                     streamId, curVersion, -1, -1, first && IsSoftDeleted(streamId)));
                    }
                    if (first)
                    {
                        startEventNumber = prepInfo.EventNumber;
                    }
                    endEventNumber = prepInfo.EventNumber;
                    first          = false;
                }

                if (first)                /*no data in transaction*/
                {
                    return(new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, IsSoftDeleted(streamId)));
                }
                else
                {
                    var isReplicated = _indexReader.GetStreamLastEventNumber(streamId) >= endEventNumber;
                    //TODO(clc): the new index should hold the log positions removing this read
                    //n.b. the index will never have the event in the case of NotReady as it only committed records are indexed
                    //in that case the position will need to come from the pre-index
                    var idempotentEvent = _indexReader.ReadEvent(streamId, endEventNumber);
                    var logPos          = idempotentEvent.Result == ReadEventResult.Success
                                                ? idempotentEvent.Record.LogPosition : -1;
                    if (isReplicated)
                    {
                        return(new CommitCheckResult(CommitDecision.Idempotent, streamId, curVersion, startEventNumber, endEventNumber, false, logPos));
                    }
                    else
                    {
                        return(new CommitCheckResult(CommitDecision.IdempotentNotReady, streamId, curVersion, startEventNumber, endEventNumber, false, logPos));
                    }
                }
            }

            if (expectedVersion < curVersion)
            {
                var eventNumber = expectedVersion;
                foreach (var eventId in eventIds)
                {
                    eventNumber += 1;

                    EventInfo prepInfo;
                    if (_committedEvents.TryGetRecord(eventId, out prepInfo) &&
                        prepInfo.StreamId == streamId &&
                        prepInfo.EventNumber == eventNumber)
                    {
                        continue;
                    }

                    var res = _indexReader.ReadPrepare(streamId, eventNumber);
                    if (res != null && res.EventId == eventId)
                    {
                        continue;
                    }

                    var first = eventNumber == expectedVersion + 1;
                    if (!first)
                    {
                        return(new CommitCheckResult(CommitDecision.CorruptedIdempotency, streamId, curVersion, -1, -1,
                                                     false));
                    }

                    if (expectedVersion == ExpectedVersion.NoStream && IsSoftDeleted(streamId))
                    {
                        return(new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, true));
                    }

                    return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1,
                                                 false));
                }

                if (eventNumber == expectedVersion)                /* no data in transaction */
                {
                    return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false));
                }
                else
                {
                    var isReplicated = _indexReader.GetStreamLastEventNumber(streamId) >= eventNumber;
                    //TODO(clc): the new index should hold the log positions removing this read
                    //n.b. the index will never have the event in the case of NotReady as it only committed records are indexed
                    //in that case the position will need to come from the pre-index
                    var idempotentEvent = _indexReader.ReadEvent(streamId, eventNumber);
                    var logPos          = idempotentEvent.Result == ReadEventResult.Success
                                                ? idempotentEvent.Record.LogPosition : -1;
                    if (isReplicated)
                    {
                        return(new CommitCheckResult(CommitDecision.Idempotent, streamId, curVersion, expectedVersion + 1, eventNumber, false, logPos));
                    }
                    else
                    {
                        return(new CommitCheckResult(CommitDecision.IdempotentNotReady, streamId, curVersion, expectedVersion + 1, eventNumber, false, logPos));
                    }
                }
            }

            if (expectedVersion > curVersion)
            {
                return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false));
            }

            // expectedVersion == currentVersion
            return(new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, IsSoftDeleted(streamId)));
        }
 public string OriginalStreamOf(string streamId) => SystemStreams.OriginalStreamOf(streamId);
示例#21
0
 public DeleteWithExistingMetadata()
 {
     _streamName         = Guid.NewGuid().ToString();
     _metadataStreamName = SystemStreams.MetastreamOf(_streamName);
 }
 public bool IsSystemStream(string streamId) => SystemStreams.IsSystemStream(streamId);
 public string MetaStreamOf(string streamId) => SystemStreams.MetastreamOf(streamId);
示例#24
0
        public CommitCheckResult CheckCommit(string streamId, long expectedVersion, IEnumerable <Guid> eventIds)
        {
            var curVersion = GetStreamLastEventNumber(streamId);

            if (curVersion == EventNumber.DeletedStream)
            {
                return(new CommitCheckResult(CommitDecision.Deleted, streamId, curVersion, -1, -1, false));
            }
            if (curVersion == EventNumber.Invalid)
            {
                return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false));
            }

            if (expectedVersion == ExpectedVersion.StreamExists)
            {
                if (IsSoftDeleted(streamId))
                {
                    return(new CommitCheckResult(CommitDecision.Deleted, streamId, curVersion, -1, -1, true));
                }

                if (curVersion < 0)
                {
                    var metadataVersion = GetStreamLastEventNumber(SystemStreams.MetastreamOf(streamId));
                    if (metadataVersion < 0)
                    {
                        return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1,
                                                     false));
                    }
                }
            }

            // idempotency checks
            if (expectedVersion == ExpectedVersion.Any || expectedVersion == ExpectedVersion.StreamExists)
            {
                var  first            = true;
                long startEventNumber = -1;
                long endEventNumber   = -1;
                foreach (var eventId in eventIds)
                {
                    EventInfo prepInfo;
                    if (!_committedEvents.TryGetRecord(eventId, out prepInfo) || prepInfo.StreamId != streamId)
                    {
                        return(new CommitCheckResult(first ? CommitDecision.Ok : CommitDecision.CorruptedIdempotency,
                                                     streamId, curVersion, -1, -1, first && IsSoftDeleted(streamId)));
                    }
                    if (first)
                    {
                        startEventNumber = prepInfo.EventNumber;
                    }
                    endEventNumber = prepInfo.EventNumber;
                    first          = false;
                }

                return(first                 /* no data in transaction */
                                        ? new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, IsSoftDeleted(streamId))
                                        : new CommitCheckResult(CommitDecision.Idempotent, streamId, curVersion, startEventNumber,
                                                                endEventNumber, false));
            }

            if (expectedVersion < curVersion)
            {
                var eventNumber = expectedVersion;
                foreach (var eventId in eventIds)
                {
                    eventNumber += 1;

                    EventInfo prepInfo;
                    if (_committedEvents.TryGetRecord(eventId, out prepInfo) &&
                        prepInfo.StreamId == streamId &&
                        prepInfo.EventNumber == eventNumber)
                    {
                        continue;
                    }

                    var res = _indexReader.ReadPrepare(streamId, eventNumber);
                    if (res != null && res.EventId == eventId)
                    {
                        continue;
                    }

                    var first = eventNumber == expectedVersion + 1;
                    if (!first)
                    {
                        return(new CommitCheckResult(CommitDecision.CorruptedIdempotency, streamId, curVersion, -1, -1,
                                                     false));
                    }

                    if (expectedVersion == ExpectedVersion.NoStream && IsSoftDeleted(streamId))
                    {
                        return(new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, true));
                    }

                    return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1,
                                                 false));
                }

                return(eventNumber == expectedVersion                 /* no data in transaction */
                                        ? new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false)
                                        : new CommitCheckResult(CommitDecision.Idempotent, streamId, curVersion, expectedVersion + 1,
                                                                eventNumber, false));
            }

            if (expectedVersion > curVersion)
            {
                return(new CommitCheckResult(CommitDecision.WrongExpectedVersion, streamId, curVersion, -1, -1, false));
            }

            // expectedVersion == currentVersion
            return(new CommitCheckResult(CommitDecision.Ok, streamId, curVersion, -1, -1, IsSoftDeleted(streamId)));
        }
示例#25
0
        void IHandle <StorageMessage.WritePrepares> .Handle(StorageMessage.WritePrepares msg)
        {
            Interlocked.Decrement(ref FlushMessagesInQueue);

            try
            {
                if (msg.LiveUntil < DateTime.UtcNow)
                {
                    return;
                }

                string streamId    = msg.EventStreamId;
                var    commitCheck = _indexWriter.CheckCommit(streamId, msg.ExpectedVersion,
                                                              msg.Events.Select(x => x.EventId));
                if (commitCheck.Decision != CommitDecision.Ok)
                {
                    ActOnCommitCheckFailure(msg.Envelope, msg.CorrelationId, commitCheck);
                    return;
                }

                var prepares    = new List <PrepareLogRecord>();
                var logPosition = Writer.Checkpoint.ReadNonFlushed();
                if (msg.Events.Length > 0)
                {
                    var transactionPosition = logPosition;
                    for (int i = 0; i < msg.Events.Length; ++i)
                    {
                        var evnt  = msg.Events[i];
                        var flags = PrepareFlags.Data | PrepareFlags.IsCommitted;
                        if (i == 0)
                        {
                            flags |= PrepareFlags.TransactionBegin;
                        }
                        if (i == msg.Events.Length - 1)
                        {
                            flags |= PrepareFlags.TransactionEnd;
                        }
                        if (evnt.IsJson)
                        {
                            flags |= PrepareFlags.IsJson;
                        }

                        // when IsCommitted ExpectedVersion is always explicit
                        var expectedVersion = commitCheck.CurrentVersion + i;
                        var res             = WritePrepareWithRetry(
                            LogRecord.Prepare(logPosition, msg.CorrelationId, evnt.EventId,
                                              transactionPosition, i, streamId,
                                              expectedVersion, flags, evnt.EventType, evnt.Data, evnt.Metadata));
                        logPosition = res.NewPos;
                        if (i == 0)
                        {
                            transactionPosition = res.WrittenPos;
                        }
                        // transaction position could be changed due to switching to new chunk
                        prepares.Add(res.Prepare);
                    }
                }
                else
                {
                    WritePrepareWithRetry(
                        LogRecord.Prepare(logPosition, msg.CorrelationId, Guid.NewGuid(), logPosition, -1,
                                          streamId, commitCheck.CurrentVersion,
                                          PrepareFlags.TransactionBegin | PrepareFlags.TransactionEnd | PrepareFlags.IsCommitted,
                                          null, Empty.ByteArray, Empty.ByteArray));
                }

                bool softUndeleteMetastream = SystemStreams.IsMetastream(streamId) &&
                                              _indexWriter.IsSoftDeleted(SystemStreams.OriginalStreamOf(streamId));

                _indexWriter.PreCommit(prepares);

                if (commitCheck.IsSoftDeleted)
                {
                    SoftUndeleteStream(streamId, commitCheck.CurrentVersion + 1);
                }
                if (softUndeleteMetastream)
                {
                    SoftUndeleteMetastream(streamId);
                }
            }
            catch (Exception exc)
            {
                Log.ErrorException(exc, "Exception in writer.");
                throw;
            }
            finally
            {
                Flush();
            }
        }
示例#26
0
        public int Commit(IList <PrepareLogRecord> commitedPrepares)
        {
            int eventNumber = EventNumber.Invalid;

            if (commitedPrepares.Count == 0)
            {
                return(eventNumber);
            }

            var lastCommitPosition = Interlocked.Read(ref _lastCommitPosition);
            var lastPrepare        = commitedPrepares[commitedPrepares.Count - 1];

            string streamId     = lastPrepare.EventStreamId;
            uint   streamHash   = _hasher.Hash(streamId);
            var    indexEntries = new List <IndexEntry>();
            var    prepares     = new List <PrepareLogRecord>();

            foreach (var prepare in commitedPrepares)
            {
                if (prepare.Flags.HasNoneOf(PrepareFlags.StreamDelete | PrepareFlags.Data))
                {
                    continue;
                }

                if (prepare.EventStreamId != streamId)
                {
                    throw new Exception(string.Format("Expected stream: {0}, actual: {1}.", streamId, prepare.EventStreamId));
                }

                if (prepare.LogPosition < lastCommitPosition || (prepare.LogPosition == lastCommitPosition && !_indexRebuild))
                {
                    continue;                              // already committed
                }
                eventNumber = prepare.ExpectedVersion + 1; /* for committed prepare expected version is always explicit */

                if (new TFPos(prepare.LogPosition, prepare.LogPosition) > new TFPos(_persistedCommitPos, _persistedPreparePos))
                {
                    indexEntries.Add(new IndexEntry(streamHash, eventNumber, prepare.LogPosition));
                    prepares.Add(prepare);
                }
            }

            if (indexEntries.Count > 0)
            {
                if (_additionalCommitChecks)
                {
                    CheckStreamVersion(streamId, indexEntries[0].Version, null);    // TODO AN: bad passing null commit
                    CheckDuplicateEvents(streamHash, null, indexEntries, prepares); // TODO AN: bad passing null commit
                }
                _tableIndex.AddEntries(lastPrepare.LogPosition, indexEntries);      // atomically add a whole bulk of entries
            }

            if (eventNumber != EventNumber.Invalid)
            {
                if (eventNumber < 0)
                {
                    throw new Exception(string.Format("EventNumber {0} is incorrect.", eventNumber));
                }

                _backend.SetStreamLastEventNumber(streamId, eventNumber);
                if (SystemStreams.IsMetastream(streamId))
                {
                    _backend.SetStreamMetadata(SystemStreams.OriginalStreamOf(streamId), null); // invalidate cached metadata
                }
                if (streamId == SystemStreams.SettingsStream)
                {
                    _backend.SetSystemSettings(DeserializeSystemSettings(prepares[prepares.Count - 1].Data));
                }
            }

            var newLastCommitPosition = Math.Max(lastPrepare.LogPosition, lastCommitPosition);

            if (Interlocked.CompareExchange(ref _lastCommitPosition, newLastCommitPosition, lastCommitPosition) != lastCommitPosition)
            {
                throw new Exception("Concurrency error in ReadIndex.Commit: _lastCommitPosition was modified during Commit execution!");
            }

            for (int i = 0, n = indexEntries.Count; i < n; ++i)
            {
                _bus.Publish(new StorageMessage.EventCommited(prepares[i].LogPosition, new EventRecord(indexEntries[i].Version, prepares[i])));
            }

            return(eventNumber);
        }
示例#27
0
        public long Commit(IList <PrepareLogRecord> commitedPrepares, bool isTfEof, bool cacheLastEventNumber)
        {
            long eventNumber = EventNumber.Invalid;

            if (commitedPrepares.Count == 0)
            {
                return(eventNumber);
            }

            var lastIndexedPosition = _indexChk.Read();
            var lastPrepare         = commitedPrepares[commitedPrepares.Count - 1];

            string streamId     = lastPrepare.EventStreamId;
            var    indexEntries = new List <IndexKey>();
            var    prepares     = new List <PrepareLogRecord>();

            foreach (var prepare in commitedPrepares)
            {
                if (prepare.Flags.HasNoneOf(PrepareFlags.StreamDelete | PrepareFlags.Data))
                {
                    continue;
                }

                if (prepare.EventStreamId != streamId)
                {
                    var sb = new StringBuilder();
                    sb.Append(string.Format("ERROR: Expected stream: {0}, actual: {1}.", streamId,
                                            prepare.EventStreamId));
                    sb.Append(Environment.NewLine);
                    sb.Append(Environment.NewLine);
                    sb.Append("Prepares: (" + commitedPrepares.Count + ")");
                    sb.Append(Environment.NewLine);
                    for (int i = 0; i < commitedPrepares.Count; i++)
                    {
                        var p = commitedPrepares[i];
                        sb.Append("Stream ID: " + p.EventStreamId);
                        sb.Append(Environment.NewLine);
                        sb.Append("LogPosition: " + p.LogPosition);
                        sb.Append(Environment.NewLine);
                        sb.Append("Flags: " + p.Flags);
                        sb.Append(Environment.NewLine);
                        sb.Append("Type: " + p.EventType);
                        sb.Append(Environment.NewLine);
                        sb.Append("MetaData: " + Encoding.UTF8.GetString(p.Metadata));
                        sb.Append(Environment.NewLine);
                        sb.Append("Data: " + Encoding.UTF8.GetString(p.Data));
                        sb.Append(Environment.NewLine);
                    }

                    throw new Exception(sb.ToString());
                }

                if (prepare.LogPosition < lastIndexedPosition ||
                    (prepare.LogPosition == lastIndexedPosition && !_indexRebuild))
                {
                    continue;                     // already committed
                }
                eventNumber =
                    prepare.ExpectedVersion + 1;                     /* for committed prepare expected version is always explicit */

                if (new TFPos(prepare.LogPosition, prepare.LogPosition) >
                    new TFPos(_persistedCommitPos, _persistedPreparePos))
                {
                    indexEntries.Add(new IndexKey(streamId, eventNumber, prepare.LogPosition));
                    prepares.Add(prepare);
                }
            }

            if (indexEntries.Count > 0)
            {
                if (_additionalCommitChecks && cacheLastEventNumber)
                {
                    CheckStreamVersion(streamId, indexEntries[0].Version, null);                     // TODO AN: bad passing null commit
                    CheckDuplicateEvents(streamId, null, indexEntries, prepares);                    // TODO AN: bad passing null commit
                }

                _tableIndex.AddEntries(lastPrepare.LogPosition, indexEntries);                 // atomically add a whole bulk of entries
            }

            if (eventNumber != EventNumber.Invalid)
            {
                if (eventNumber < 0)
                {
                    throw new Exception(string.Format("EventNumber {0} is incorrect.", eventNumber));
                }

                if (cacheLastEventNumber)
                {
                    _backend.SetStreamLastEventNumber(streamId, eventNumber);
                }

                if (SystemStreams.IsMetastream(streamId))
                {
                    _backend.SetStreamMetadata(SystemStreams.OriginalStreamOf(streamId),
                                               null);  // invalidate cached metadata
                }
                if (streamId == SystemStreams.SettingsStream)
                {
                    _backend.SetSystemSettings(DeserializeSystemSettings(prepares[prepares.Count - 1].Data));
                }
            }

            var newLastIndexedPosition = Math.Max(lastPrepare.LogPosition, lastIndexedPosition);

            if (_indexChk.Read() != lastIndexedPosition)
            {
                throw new Exception(
                          "Concurrency error in ReadIndex.Commit: _lastCommitPosition was modified during Commit execution!");
            }
            _indexChk.Write(newLastIndexedPosition);
            _indexChk.Flush();

            if (!_indexRebuild)
            {
                for (int i = 0, n = indexEntries.Count; i < n; ++i)
                {
                    _bus.Publish(
                        new StorageMessage.EventCommitted(
                            prepares[i].LogPosition,
                            new EventRecord(indexEntries[i].Version, prepares[i]),
                            isTfEof && i == n - 1));
                }
            }

            return(eventNumber);
        }
        public DbResult CreateDb()
        {
            var records = new LogRecord[_chunkRecs.Count][];

            for (int i = 0; i < records.Length; ++i)
            {
                records[i] = new LogRecord[_chunkRecs[i].Length];
            }

            var transactions            = new Dictionary <int, TransactionInfo>();
            var streams                 = new Dictionary <string, StreamInfo>();
            var streamUncommitedVersion = new Dictionary <string, long>();

            for (int i = 0; i < _chunkRecs.Count; ++i)
            {
                for (int j = 0; j < _chunkRecs[i].Length; ++j)
                {
                    var rec = _chunkRecs[i][j];

                    TransactionInfo transInfo;
                    bool            transCreate = transactions.TryGetValue(rec.Transaction, out transInfo);
                    if (!transCreate)
                    {
                        if (rec.Type == Rec.RecType.Commit)
                        {
                            throw new Exception("Commit for non-existing transaction.");
                        }

                        transactions[rec.Transaction] = transInfo = new TransactionInfo(rec.StreamId, rec.Id, rec.Id);

                        streams[rec.StreamId] = new StreamInfo(-1);
                        streamUncommitedVersion[rec.StreamId] = -1;
                    }
                    else
                    {
                        if (rec.Type == Rec.RecType.TransStart)
                        {
                            throw new Exception(string.Format("Unexpected record type: {0}.", rec.Type));
                        }
                    }

                    if (transInfo.StreamId != rec.StreamId)
                    {
                        throw new Exception(string.Format("Wrong stream id for transaction. Transaction StreamId: {0}, record StreamId: {1}.",
                                                          transInfo.StreamId,
                                                          rec.StreamId));
                    }

                    if (rec.Type != Rec.RecType.Commit && transInfo.IsDelete)
                    {
                        throw new Exception("Transaction with records after delete record.");
                    }

                    if (rec.Type == Rec.RecType.Delete)
                    {
                        transInfo.IsDelete = true;
                    }

                    transInfo.LastPrepareId = rec.Id;
                }
            }

            for (int i = 0; i < _chunkRecs.Count; ++i)
            {
                var chunk = i == 0 ? _db.Manager.GetChunk(0) : _db.Manager.AddNewChunk();
                _db.Config.WriterCheckpoint.Write(i * (long)_db.Config.ChunkSize);

                for (int j = 0; j < _chunkRecs[i].Length; ++j)
                {
                    var rec       = _chunkRecs[i][j];
                    var transInfo = transactions[rec.Transaction];
                    var logPos    = _db.Config.WriterCheckpoint.ReadNonFlushed();

                    long streamVersion = streamUncommitedVersion[rec.StreamId];
                    if (streamVersion == -1 &&
                        rec.Type != Rec.RecType.TransStart &&
                        rec.Type != Rec.RecType.Prepare &&
                        rec.Type != Rec.RecType.Delete)
                    {
                        throw new Exception(string.Format("Stream {0} is empty.", rec.StreamId));
                    }
                    if (streamVersion == EventNumber.DeletedStream && rec.Type != Rec.RecType.Commit)
                    {
                        throw new Exception(string.Format("Stream {0} was deleted, but we need to write some more prepares.", rec.StreamId));
                    }

                    if (transInfo.FirstPrepareId == rec.Id)
                    {
                        transInfo.TransactionPosition    = logPos;
                        transInfo.TransactionEventNumber = streamVersion + 1;
                        transInfo.TransactionOffset      = 0;
                    }

                    LogRecord record;

                    var expectedVersion = transInfo.FirstPrepareId == rec.Id ? streamVersion : ExpectedVersion.Any;
                    switch (rec.Type)
                    {
                    case Rec.RecType.Prepare:
                    {
                        record = CreateLogRecord(rec, transInfo, logPos, expectedVersion);

                        if (SystemStreams.IsMetastream(rec.StreamId))
                        {
                            transInfo.StreamMetadata = rec.Metadata;
                        }

                        streamUncommitedVersion[rec.StreamId] += 1;
                        break;
                    }

                    case Rec.RecType.Delete:
                    {
                        record = CreateLogRecord(rec, transInfo, logPos, expectedVersion);

                        streamUncommitedVersion[rec.StreamId] = rec.Version == LogRecordVersion.LogRecordV0 ? int.MaxValue : EventNumber.DeletedStream;
                        break;
                    }

                    case Rec.RecType.TransStart:
                    case Rec.RecType.TransEnd:
                    {
                        record = CreateLogRecord(rec, transInfo, logPos, expectedVersion);
                        break;
                    }

                    case Rec.RecType.Commit:
                    {
                        record = CreateLogRecord(rec, transInfo, logPos, expectedVersion);

                        if (transInfo.StreamMetadata != null)
                        {
                            var streamId = SystemStreams.OriginalStreamOf(rec.StreamId);
                            if (!streams.ContainsKey(streamId))
                            {
                                streams.Add(streamId, new StreamInfo(-1));
                            }
                            streams[streamId].StreamMetadata = transInfo.StreamMetadata;
                        }

                        if (transInfo.IsDelete)
                        {
                            streams[rec.StreamId].StreamVersion = EventNumber.DeletedStream;
                        }
                        else
                        {
                            streams[rec.StreamId].StreamVersion = transInfo.TransactionEventNumber + transInfo.TransactionOffset - 1;
                        }
                        break;
                    }

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    var writerRes = chunk.TryAppend(record);
                    if (!writerRes.Success)
                    {
                        throw new Exception(string.Format("Could not write log record: {0}", record));
                    }
                    _db.Config.WriterCheckpoint.Write(i * (long)_db.Config.ChunkSize + writerRes.NewPosition);

                    records[i][j] = record;
                }

                if (i < _chunkRecs.Count - 1 || (_completeLast && i == _chunkRecs.Count - 1))
                {
                    chunk.Complete();
                }
                else
                {
                    chunk.Flush();
                }
            }
            return(new DbResult(_db, records, streams));
        }
示例#29
0
 private void PublishWriteMetaStream()
 {
     _ioDispatcher.WriteEvent(
         SystemStreams.MetastreamOf(_streamId), ExpectedVersion.Any, _submittedWriteMetaStreamEvent, _writeAs,
         HandleMetadataWriteCompleted);
 }
示例#30
0
        public long Commit(CommitLogRecord commit, bool isTfEof, bool cacheLastEventNumber)
        {
            long eventNumber = EventNumber.Invalid;

            var lastIndexedPosition = _indexChk.Read();

            if (commit.LogPosition < lastIndexedPosition || (commit.LogPosition == lastIndexedPosition && !_indexRebuild))
            {
                return(eventNumber);                // already committed
            }
            string streamId     = null;
            var    indexEntries = new List <IndexKey>();
            var    prepares     = new List <PrepareLogRecord>();

            foreach (var prepare in GetTransactionPrepares(commit.TransactionPosition, commit.LogPosition))
            {
                if (prepare.Flags.HasNoneOf(PrepareFlags.StreamDelete | PrepareFlags.Data))
                {
                    continue;
                }

                if (streamId == null)
                {
                    streamId = prepare.EventStreamId;
                }
                else
                {
                    if (prepare.EventStreamId != streamId)
                    {
                        throw new Exception(string.Format("Expected stream: {0}, actual: {1}. LogPosition: {2}",
                                                          streamId, prepare.EventStreamId, commit.LogPosition));
                    }
                }

                eventNumber = prepare.Flags.HasAllOf(PrepareFlags.StreamDelete)
                                        ? EventNumber.DeletedStream
                                        : commit.FirstEventNumber + prepare.TransactionOffset;

                if (new TFPos(commit.LogPosition, prepare.LogPosition) >
                    new TFPos(_persistedCommitPos, _persistedPreparePos))
                {
                    indexEntries.Add(new IndexKey(streamId, eventNumber, prepare.LogPosition));
                    prepares.Add(prepare);
                }
            }

            if (indexEntries.Count > 0)
            {
                if (_additionalCommitChecks && cacheLastEventNumber)
                {
                    CheckStreamVersion(streamId, indexEntries[0].Version, commit);
                    CheckDuplicateEvents(streamId, commit, indexEntries, prepares);
                }

                _tableIndex.AddEntries(commit.LogPosition, indexEntries);                 // atomically add a whole bulk of entries
            }

            if (eventNumber != EventNumber.Invalid)
            {
                if (eventNumber < 0)
                {
                    throw new Exception(string.Format("EventNumber {0} is incorrect.", eventNumber));
                }

                if (cacheLastEventNumber)
                {
                    _backend.SetStreamLastEventNumber(streamId, eventNumber);
                }

                if (SystemStreams.IsMetastream(streamId))
                {
                    _backend.SetStreamMetadata(SystemStreams.OriginalStreamOf(streamId),
                                               null);  // invalidate cached metadata
                }
                if (streamId == SystemStreams.SettingsStream)
                {
                    _backend.SetSystemSettings(DeserializeSystemSettings(prepares[prepares.Count - 1].Data));
                }
            }

            var newLastIndexedPosition = Math.Max(commit.LogPosition, lastIndexedPosition);

            if (_indexChk.Read() != lastIndexedPosition)
            {
                throw new Exception(
                          "Concurrency error in ReadIndex.Commit: _lastCommitPosition was modified during Commit execution!");
            }
            _indexChk.Write(newLastIndexedPosition);
            _indexChk.Flush();

            if (!_indexRebuild)
            {
                for (int i = 0, n = indexEntries.Count; i < n; ++i)
                {
                    _bus.Publish(
                        new StorageMessage.EventCommitted(
                            commit.LogPosition,
                            new EventRecord(indexEntries[i].Version, prepares[i]),
                            isTfEof && i == n - 1));
                }
            }

            return(eventNumber);
        }