public PartitionManager( ITransactionFileReader reader, ITransactionFileWriter writer, LogV3RecordFactory recordFactory) { _reader = reader; _writer = writer; _recordFactory = recordFactory; }
private SingleReadResult TryReadRecordInternal(ITransactionFileReader reader, string eventStreamId, int version, out EventRecord record) { Ensure.NotNull(eventStreamId, "eventStreamId"); Ensure.Nonnegative(version, "version"); record = null; if (IsStreamDeletedInternal(reader, eventStreamId)) { return(SingleReadResult.StreamDeleted); } var success = TryGetRecordInternal(reader, eventStreamId, version, out record); if (success) { return(SingleReadResult.Success); } if (version == 0) { return(SingleReadResult.NoStream); } EventRecord rec; return(TryGetRecordInternal(reader, eventStreamId, 0, out rec) ? SingleReadResult.NotFound : SingleReadResult.NoStream); }
public virtual void TestFixtureSetUp() { _logFormat = LogFormatHelper <TLogFormat, TStreamId> .LogFormat; _publisher = new InMemoryBus("publisher"); _tfReader = new FakeInMemoryTfReader(RecordOffset); _tableIndex = new FakeInMemoryTableIndex <TStreamId>(); _readerPool = new ObjectPool <ITransactionFileReader>( "ReadIndex readers pool", 5, 100, () => _tfReader); _indexBackend = new IndexBackend <TStreamId>(_readerPool, 100000, 100000); var logFormat = LogFormatHelper <TLogFormat, TStreamId> .LogFormat; _streamIds = logFormat.StreamIds; _streamNames = logFormat.StreamNames; _systemStreams = logFormat.SystemStreams; _factory = logFormat.StreamNamesProvider; _validator = logFormat.StreamIdValidator; var emptyStreamId = logFormat.EmptyStreamId; _sizer = logFormat.StreamIdSizer; _indexReader = new IndexReader <TStreamId>(_indexBackend, _tableIndex, _factory, _validator, new StreamMetadata(maxCount: 100000), 100, false); _indexWriter = new IndexWriter <TStreamId>(_indexBackend, _indexReader, _streamIds, _streamNames, _systemStreams, emptyStreamId, _sizer); _indexCommitter = new Core.Services.Storage.ReaderIndex.IndexCommitter <TStreamId>(_publisher, _indexBackend, _indexReader, _tableIndex, _streamNames, _systemStreams, new InMemoryCheckpoint(-1), false); WriteEvents(); }
private int GetLastStreamEventNumberInternal(ITransactionFileReader reader, string eventStreamId) { Ensure.NotNull(eventStreamId, "eventStreamId"); var streamHash = _hasher.Hash(eventStreamId); IndexEntry latestEntry; if (!_tableIndex.TryGetLatestEntry(streamHash, out latestEntry)) { return(ExpectedVersion.NoStream); } var prepare = GetPrepareInternal(reader, latestEntry.Position); if (prepare.EventStreamId == eventStreamId) // LUCKY!!! { return(latestEntry.Version); } foreach (var indexEntry in _tableIndex.GetRange(streamHash, 0, int.MaxValue)) { var p = GetPrepareInternal(reader, indexEntry.Position); if (p.EventStreamId == eventStreamId) { return(indexEntry.Version); // AT LAST!!! } } return(ExpectedVersion.NoStream); // no such event stream }
private static EventRecord GetEventRecord(ITransactionFileReader reader, IndexEntry indexEntry) { var prepare = ReadPrepareInternal(reader, indexEntry.Position); var eventRecord = new EventRecord(indexEntry.Version, prepare); return(eventRecord); }
private int GetLastStreamEventNumberInternal(ITransactionFileReader reader, string streamId) { Ensure.NotNull(streamId, "streamId"); var streamHash = _hasher.Hash(streamId); IndexEntry latestEntry; if (!_tableIndex.TryGetLatestEntry(streamHash, out latestEntry)) { return(ExpectedVersion.NoStream); } var prepare = ReadPrepareInternal(reader, latestEntry.Position); if (prepare.EventStreamId == streamId) // LUCKY!!! { return(latestEntry.Version); } // TODO AN here lie the problem of out of memory if the stream have A LOT of events in them foreach (var indexEntry in _tableIndex.GetRange(streamHash, 0, int.MaxValue)) { var p = ReadPrepareInternal(reader, indexEntry.Position); if (p.EventStreamId == streamId) { return(indexEntry.Version); // AT LAST!!! } } return(ExpectedVersion.NoStream); // no such event stream }
public override async Task TestFixtureSetUp() { await base.TestFixtureSetUp(); _logFormat = LogFormatHelper <TLogFormat, TStreamId> .LogFormatFactory.Create(new() { IndexDirectory = GetFilePathFor("index"), }); _provider = _logFormat.StreamNamesProvider; _publisher = new InMemoryBus("publisher"); _tfReader = new FakeInMemoryTfReader(RecordOffset); _tableIndex = new FakeInMemoryTableIndex <TStreamId>(); _provider.SetTableIndex(_tableIndex); _readerPool = new ObjectPool <ITransactionFileReader>( "ReadIndex readers pool", 5, 100, () => _tfReader); _indexBackend = new IndexBackend <TStreamId>(_readerPool, 100000, 100000); _streamIds = _logFormat.StreamIds; _validator = _logFormat.StreamIdValidator; var emptyStreamId = _logFormat.EmptyStreamId; _sizer = _logFormat.StreamIdSizer; _indexReader = new IndexReader <TStreamId>(_indexBackend, _tableIndex, _provider, _validator, _logFormat.StreamExistenceFilterReader, new StreamMetadata(maxCount: 100000), 100, false); _streamNames = _logFormat.StreamNames; _systemStreams = _logFormat.SystemStreams; _indexWriter = new IndexWriter <TStreamId>(_indexBackend, _indexReader, _streamIds, _streamNames, _systemStreams, emptyStreamId, _sizer); _indexCommitter = new IndexCommitter <TStreamId>(_publisher, _indexBackend, _indexReader, _tableIndex, _logFormat.StreamNameIndexConfirmer, _streamNames, _logFormat.EventTypeIndexConfirmer, _logFormat.EventTypes, _systemStreams, _logFormat.StreamExistenceFilter, _logFormat.StreamExistenceFilterInitializer, new InMemoryCheckpoint(-1), false); WriteEvents(); }
private EventRecord ResolveLinkToEventInternal(ITransactionFileReader reader, EventRecord eventRecord) { EventRecord record = null; if (eventRecord.EventType == SystemEventTypes.LinkTo) { bool faulted = false; int eventNumber = -1; string streamId = null; try { string[] parts = Encoding.UTF8.GetString(eventRecord.Data).Split('@'); eventNumber = int.Parse(parts[0]); streamId = parts[1]; } catch (Exception exc) { faulted = true; Log.ErrorException(exc, "Error while resolving link for event record: {0}", eventRecord.ToString()); } if (faulted) { return(null); } GetStreamRecord(reader, streamId, eventNumber, out record); } return(record); }
private PrepareLogRecord GetPrepareInternal(ITransactionFileReader reader, long pos) { var result = reader.TryReadAt(pos); if (!result.Success) { throw new InvalidOperationException("Couldn't read record which is supposed to be in file."); } Debug.Assert(result.LogRecord.RecordType == LogRecordType.Prepare, "Incorrect type of log record, expected Prepare record."); return((PrepareLogRecord)result.LogRecord); }
private static PrepareLogRecord ReadPrepareInternal(ITransactionFileReader reader, long pos) { var result = reader.TryReadAt(pos); // TODO AN need to change this to account for possibly scavenged records, shouldn't throw exception, // TODO AN rather return meaningful result if (!result.Success) { throw new InvalidOperationException("Couldn't read record which is supposed to be in file."); } Debug.Assert(result.LogRecord.RecordType == LogRecordType.Prepare, "Incorrect type of log record, expected Prepare record."); return((PrepareLogRecord)result.LogRecord); }
public virtual void TestFixtureSetUp() { _publisher = new InMemoryBus("publisher"); _tfReader = new FakeInMemoryTfReader(RecordOffset); _tableIndex = new FakeInMemoryTableIndex(); _readerPool = new ObjectPool <ITransactionFileReader>( "ReadIndex readers pool", 5, 100, () => _tfReader); _indexBackend = new IndexBackend(_readerPool, 100000, 100000); _indexReader = new IndexReader(_indexBackend, _tableIndex, new StreamMetadata(maxCount: 100000), 100, false); _indexWriter = new IndexWriter(_indexBackend, _indexReader); _indexCommitter = new IndexCommitter(_publisher, _indexBackend, _indexReader, _tableIndex, false); WriteEvents(); }
private SingleReadResult ReadEventInternal(ITransactionFileReader reader, string streamId, int version, out EventRecord record) { Ensure.NotNull(streamId, "streamId"); Ensure.Nonnegative(version, "eventNumber"); record = null; if (IsStreamDeletedInternal(reader, streamId)) { return(SingleReadResult.StreamDeleted); } StreamMetadata metadata; bool streamExists; bool useMetadata = GetStreamMetadataInternal(reader, streamId, out streamExists, out metadata); if (!streamExists) { return(SingleReadResult.NoStream); } if (useMetadata && metadata.MaxCount.HasValue) { var lastStreamEventNumber = GetLastStreamEventNumberInternal(reader, streamId); var minEventNumber = lastStreamEventNumber - metadata.MaxCount.Value + 1; if (version < minEventNumber || version > lastStreamEventNumber) { return(SingleReadResult.NotFound); } } EventRecord rec; var success = GetStreamRecord(reader, streamId, version, out rec); if (success) { if (useMetadata && metadata.MaxAge.HasValue && rec.TimeStamp < DateTime.UtcNow - metadata.MaxAge.Value) { return(SingleReadResult.NotFound); } record = rec; return(SingleReadResult.Success); } return(SingleReadResult.NotFound); }
private bool GetStreamMetadataInternal(ITransactionFileReader reader, string streamId, out bool streamExists, out StreamMetadata metadata) { metadata = new StreamMetadata(null, null); streamExists = false; EventRecord record; if (!GetStreamRecord(reader, streamId, 0, out record)) { return(false); } streamExists = true; if (record.Metadata == null || record.Metadata.Length == 0) { return(false); } try { var json = Encoding.UTF8.GetString(record.Metadata); var jObj = JObject.Parse(json); int maxAge = -1; int maxCount = -1; JToken prop; if (jObj.TryGetValue(SystemMetadata.MaxAge, out prop) && prop.Type == JTokenType.Integer) { maxAge = prop.Value <int>(); } if (jObj.TryGetValue(SystemMetadata.MaxCount, out prop) && prop.Type == JTokenType.Integer) { maxCount = prop.Value <int>(); } metadata = new StreamMetadata(maxCount > 0 ? maxCount : (int?)null, maxAge > 0 ? TimeSpan.FromSeconds(maxAge) : (TimeSpan?)null); return(true); } catch (Exception) { return(false); } }
private bool TryGetRecordInternal(ITransactionFileReader reader, string eventStreamId, int version, out EventRecord record) { // we assume that you already did check for stream deletion Ensure.NotNull(eventStreamId, "eventStreamId"); Ensure.Nonnegative(version, "version"); record = null; var streamHash = _hasher.Hash(eventStreamId); long position; if (_tableIndex.TryGetOneValue(streamHash, version, out position)) { record = ReadEventRecord(reader, new IndexEntry(streamHash, version, position)); if (record.EventStreamId == eventStreamId) { _succReadCount += 1; return(true); } _failedReadCount += 1; foreach (var indexEntry in _tableIndex.GetRange(streamHash, version, version)) { if (indexEntry.Position == record.LogPosition) // already checked that { continue; } record = ReadEventRecord(reader, indexEntry); if (record.EventStreamId == eventStreamId) { _succReadCount += 1; return(true); } _failedReadCount += 1; } } return(false); }
private bool GetStreamMetadataUncached(ITransactionFileReader reader, string streamId, out StreamMetadata metadata) { EventRecord record; if (!GetStreamRecord(reader, streamId, 0, out record)) { throw new Exception("GetStreamMetadata couldn't find 0th event on stream. That should never happen."); } metadata = new StreamMetadata(null, null); if (record.Metadata == null || record.Metadata.Length == 0) { return(false); } try { var json = Encoding.UTF8.GetString(record.Metadata); var jObj = JObject.Parse(json); int maxAge = -1; int maxCount = -1; JToken prop; if (jObj.TryGetValue(SystemMetadata.MaxAge, out prop) && prop.Type == JTokenType.Integer) { maxAge = prop.Value <int>(); } if (jObj.TryGetValue(SystemMetadata.MaxCount, out prop) && prop.Type == JTokenType.Integer) { maxCount = prop.Value <int>(); } metadata = new StreamMetadata(maxCount > 0 ? maxCount : (int?)null, maxAge > 0 ? TimeSpan.FromSeconds(maxAge) : (TimeSpan?)null); return(true); } catch (Exception) { return(false); } }
private void TestMethodRoFile(ITransactionFileReader reader) { // Arrange const string resourceFile = "Tranzactii_pe_perioada.csv"; // Act var transactions = reader.Read(GlobalSettings.GetResourceFilePath(resourceFile), new CultureInfo("ro-RO")); // Assert Assert.IsTrue(transactions.Count == 3); var lastTransaction = transactions[transactions.Count - 1]; Assert.IsTrue((lastTransaction.TransactionDate == new DateTime(2016, 4, 29)) && (lastTransaction.TransactionType == TransactionType.Debit) && (lastTransaction.TransactionDetails == "Cumparare POS") && (lastTransaction.Amount == 13.9m)); var totalDebits = transactions.Where(t => t.TransactionType == TransactionType.Debit).Sum(t => t.Amount); Assert.IsTrue(totalDebits == 257.57m); }
private ReadEventResult ReadEventInternal(ITransactionFileReader reader, string streamId, int version) { Ensure.NotNull(streamId, "streamId"); Ensure.Nonnegative(version, "eventNumber"); var lastEventNumber = GetLastStreamEventNumberCached(reader, streamId); if (lastEventNumber == EventNumber.DeletedStream) { return(new ReadEventResult(SingleReadResult.StreamDeleted)); } if (lastEventNumber == ExpectedVersion.NoStream) { return(new ReadEventResult(SingleReadResult.NoStream)); } StreamMetadata metadata; bool useMetadata = GetStreamMetadataCached(reader, streamId, out metadata); if (useMetadata && metadata.MaxCount.HasValue) { var minEventNumber = lastEventNumber - metadata.MaxCount.Value + 1; if (version < minEventNumber || version > lastEventNumber) { return(new ReadEventResult(SingleReadResult.NotFound)); } } EventRecord record; var success = GetStreamRecord(reader, streamId, version, out record); if (success) { if (useMetadata && metadata.MaxAge.HasValue && record.TimeStamp < DateTime.UtcNow - metadata.MaxAge.Value) { return(new ReadEventResult(SingleReadResult.NotFound)); } return(new ReadEventResult(SingleReadResult.Success, record)); } return(new ReadEventResult(SingleReadResult.NotFound)); }
private void TestMethodEnFile(ITransactionFileReader reader) { // Arrange const string resourceFile = "Inquiry_statements.csv"; // Act var transactions = reader.Read(GlobalSettings.GetResourceFilePath(resourceFile), new CultureInfo("en-US")); // Assert var firstTransaction = transactions[0]; Assert.IsTrue((firstTransaction.TransactionDate == new DateTime(2016, 4, 1)) && (firstTransaction.TransactionType == TransactionType.Debit) && (firstTransaction.TransactionDetails == "Foreign exchange Home'Bank") && (firstTransaction.Amount == 693.17M)); var lastTransaction = transactions[transactions.Count - 1]; Assert.IsTrue((lastTransaction.TransactionDate == new DateTime(2016, 2, 4)) && (lastTransaction.TransactionType == TransactionType.Credit) && (lastTransaction.TransactionDetails == "Incoming funds") && (lastTransaction.Amount == 2500m)); }
private EpochRecord ReadEpochAt(ITransactionFileReader reader, long epochPos) { var result = reader.TryReadAt(epochPos); if (!result.Success) { throw new Exception($"Could not find Epoch record at LogPosition {epochPos}."); } if (result.LogRecord.RecordType != LogRecordType.System) { throw new Exception($"LogRecord is not SystemLogRecord: {result.LogRecord}."); } var sysRec = (SystemLogRecord)result.LogRecord; if (sysRec.SystemRecordType != SystemRecordType.Epoch) { throw new Exception($"SystemLogRecord is not of Epoch sub-type: {result.LogRecord}."); } return(sysRec.GetEpochRecord()); }
private bool GetStreamMetadataCached(ITransactionFileReader reader, string streamId, out StreamMetadata metadata) { StreamCacheInfo streamInfo; if (_streamInfoCache.TryGet(streamId, out streamInfo) && streamInfo.Metadata.HasValue) { metadata = streamInfo.Metadata.Value; return(true); } if (GetStreamMetadataUncached(reader, streamId, out metadata)) { var meta = metadata; _streamInfoCache.Put(streamId, key => new StreamCacheInfo(null, meta), (key, oldValue) => new StreamCacheInfo(oldValue.LastEventNumber, meta)); return(true); } return(false); }
private int GetLastStreamEventNumberCached(ITransactionFileReader reader, string streamId) { Ensure.NotNull(streamId, "streamId"); StreamCacheInfo streamInfo; if (_streamInfoCache.TryGet(streamId, out streamInfo) && streamInfo.LastEventNumber.HasValue) { return(streamInfo.LastEventNumber.Value); } var lastEventNumber = GetLastStreamEventNumberUncached(reader, streamId); if (lastEventNumber != ExpectedVersion.NoStream) { // we should take Max on LastEventNumber because there could be a commit happening in parallel thread // so we should not overwrite the actual LastEventNumber updated by Commit method with our stale one _streamInfoCache.Put( streamId, key => new StreamCacheInfo(lastEventNumber, null), (key, old) => new StreamCacheInfo(Math.Max(lastEventNumber, old.LastEventNumber ?? -1), old.Metadata)); } return(lastEventNumber); }
private StreamMetadata GetStreamMetadataUncached(ITransactionFileReader reader, string streamId) { EventRecord record; if (!GetStreamRecord(reader, streamId, 0, out record)) throw new Exception("GetStreamMetadata couldn't find 0th event on stream. That should never happen."); if (record.Metadata == null || record.Metadata.Length == 0 || (record.Flags & PrepareFlags.IsJson) == 0) return new StreamMetadata(null, null); try { var json = Encoding.UTF8.GetString(record.Metadata); var jObj = JObject.Parse(json); int maxAge = -1; int maxCount = -1; JToken prop; if (jObj.TryGetValue(SystemMetadata.MaxAge, out prop) && prop.Type == JTokenType.Integer) maxAge = prop.Value<int>(); if (jObj.TryGetValue(SystemMetadata.MaxCount, out prop) && prop.Type == JTokenType.Integer) maxCount = prop.Value<int>(); return new StreamMetadata(maxCount > 0 ? maxCount : (int?) null, maxAge > 0 ? TimeSpan.FromSeconds(maxAge) : (TimeSpan?) null); } catch (Exception) { return new StreamMetadata(null, null); } }
private bool IsStreamDeletedInternal(ITransactionFileReader reader, string streamId) { EventRecord record; return(GetStreamRecord(reader, streamId, int.MaxValue, out record)); }
private StreamMetadata GetStreamMetadataUncached(ITransactionFileReader reader, string streamId) { Interlocked.Increment(ref _notCachedStreamInfo); var metastreamId = SystemStreams.MetastreamOf(streamId); var metaEventNumber = GetLastStreamEventNumberCached(reader, metastreamId); if (metaEventNumber == ExpectedVersion.NoStream || metaEventNumber == EventNumber.DeletedStream) return StreamMetadata.Empty; EventRecord record; if (!GetStreamRecord(reader, metastreamId, metaEventNumber, out record)) throw new Exception(string.Format("GetStreamRecord couldn't find metaevent #{0} on metastream '{1}'. That should never happen.", metaEventNumber, metastreamId)); if (record.Data.Length == 0 || (record.Flags & PrepareFlags.IsJson) == 0) return StreamMetadata.Empty; try { return StreamMetadata.FromJsonBytes(record.Data); } catch (Exception) { return StreamMetadata.Empty; } }
private IndexReadEventResult ReadEventInternal(ITransactionFileReader reader, string streamId, int eventNumber) { Ensure.NotNull(streamId, "streamId"); if (eventNumber < -1) throw new ArgumentOutOfRangeException("eventNumber"); var lastEventNumber = GetLastStreamEventNumberCached(reader, streamId); if (lastEventNumber == EventNumber.DeletedStream) return new IndexReadEventResult(ReadEventResult.StreamDeleted, null); if (lastEventNumber == ExpectedVersion.NoStream) return new IndexReadEventResult(ReadEventResult.NoStream, null); if (eventNumber == -1) eventNumber = lastEventNumber; var metadata = GetStreamMetadataCached(reader, streamId); if (metadata.MaxCount.HasValue) { var minEventNumber = lastEventNumber - metadata.MaxCount.Value + 1; if (eventNumber < minEventNumber || eventNumber > lastEventNumber) return new IndexReadEventResult(ReadEventResult.NotFound, metadata); } EventRecord record; var success = GetStreamRecord(reader, streamId, eventNumber, out record); if (success) { if (metadata.MaxAge.HasValue && record.TimeStamp < DateTime.UtcNow - metadata.MaxAge.Value) return new IndexReadEventResult(ReadEventResult.NotFound, metadata); return new IndexReadEventResult(ReadEventResult.Success, record, metadata); } return new IndexReadEventResult(ReadEventResult.NotFound, metadata); }
private int GetLastStreamEventNumberCached(ITransactionFileReader reader, string streamId) { Ensure.NotNull(streamId, "streamId"); // if this is metastream -- check if original stream was deleted, if yes -- metastream is deleted as well if (SystemStreams.IsMetastream(streamId) && GetLastStreamEventNumberCached(reader, SystemStreams.OriginalStreamOf(streamId)) == EventNumber.DeletedStream) return EventNumber.DeletedStream; StreamCacheInfo streamCacheInfo; if (_streamInfoCache.TryGet(streamId, out streamCacheInfo) && streamCacheInfo.LastEventNumber.HasValue) { Interlocked.Increment(ref _cachedStreamInfo); return streamCacheInfo.LastEventNumber.Value; } var lastEventNumber = GetLastStreamEventNumberUncached(reader, streamId); if (lastEventNumber != ExpectedVersion.NoStream) { // we should take Max on LastEventNumber because there could be a commit happening in parallel thread // so we should not overwrite the actual LastEventNumber updated by Commit method with our stale one _streamInfoCache.Put( streamId, key => new StreamCacheInfo(lastEventNumber, null), (key, old) => new StreamCacheInfo(Math.Max(lastEventNumber, old.LastEventNumber ?? -1), old.Metadata)); } return lastEventNumber; }
private IndexReadEventResult ReadEventInternal(ITransactionFileReader reader, string streamId, int version) { Ensure.NotNull(streamId, "streamId"); Ensure.Nonnegative(version, "eventNumber"); var lastEventNumber = GetLastStreamEventNumberCached(reader, streamId); if (lastEventNumber == EventNumber.DeletedStream) return new IndexReadEventResult(ReadEventResult.StreamDeleted); if (lastEventNumber == ExpectedVersion.NoStream) return new IndexReadEventResult(ReadEventResult.NoStream); var metadata = GetStreamMetadataCached(reader, streamId); if (metadata.MaxCount.HasValue) { var minEventNumber = lastEventNumber - metadata.MaxCount.Value + 1; if (version < minEventNumber || version > lastEventNumber) return new IndexReadEventResult(ReadEventResult.NotFound); } EventRecord record; var success = GetStreamRecord(reader, streamId, version, out record); if (success) { if (metadata.MaxAge.HasValue && record.TimeStamp < DateTime.UtcNow - metadata.MaxAge.Value) return new IndexReadEventResult(ReadEventResult.NotFound); return new IndexReadEventResult(ReadEventResult.Success, record); } return new IndexReadEventResult(ReadEventResult.NotFound); }
public TransactionsManager(IUnitOfWork unitOfWork, ITransactionFileReader fileReader) { _unitOfWork = unitOfWork; _fileReader = fileReader; }
public TFReaderLease(ObjectPool<ITransactionFileReader> pool) { _pool = pool; Reader = pool.Get(); }
public TFReaderLease(ITransactionFileReader reader) { _pool = null; Reader = reader; }
public TFReaderLease(ObjectPool <ITransactionFileReader> pool) { _pool = pool; Reader = pool.Get(); }
private bool GetStreamRecord(ITransactionFileReader reader, string streamId, int version, out EventRecord record) { // we assume that you already did check for stream deletion Ensure.NotNullOrEmpty(streamId, "streamId"); Ensure.Nonnegative(version, "eventNumber"); var streamHash = _hasher.Hash(streamId); long position; if (_tableIndex.TryGetOneValue(streamHash, version, out position)) { var res = GetEventRecord(reader, new IndexEntry(streamHash, version, position)); if (res.Success && res.Record.EventStreamId == streamId) { _succReadCount += 1; record = res.Record; return true; } _failedReadCount += 1; foreach (var indexEntry in _tableIndex.GetRange(streamHash, version, version)) { if (indexEntry.Position == position) // already checked that continue; res = GetEventRecord(reader, indexEntry); if (res.Success && res.Record.EventStreamId == streamId) { _succReadCount += 1; record = res.Record; return true; } _failedReadCount += 1; } } record = null; return false; }
private StreamAccessResult CheckStreamAccessInternal(ITransactionFileReader 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 StreamAccessResult.Denied; default: throw new ArgumentOutOfRangeException("streamAccessType"); } } if ((streamAccessType == StreamAccessType.Write || streamAccessType == StreamAccessType.Delete) && streamId == SystemStreams.AllStream) return StreamAccessResult.Denied; if (user != null && user.IsInRole(SystemUserGroups.Admins)) return StreamAccessResult.Granted; var meta = GetStreamMetadataCached(reader, streamId); var isSystemStream = SystemStreams.IsSystemStream(streamId); switch (streamAccessType) { case StreamAccessType.Read: return CheckRoleAccess(meta.Acl == null ? null : meta.Acl.ReadRole, user, isSystemStream); case StreamAccessType.Write: return CheckRoleAccess(meta.Acl == null ? null : meta.Acl.WriteRole, user, isSystemStream); case StreamAccessType.Delete: return CheckRoleAccess(meta.Acl == null ? null : meta.Acl.DeleteRole, user, isSystemStream); case StreamAccessType.MetaRead: return CheckRoleAccess(meta.Acl == null ? null : meta.Acl.MetaReadRole, user, isSystemStream); case StreamAccessType.MetaWrite: return CheckRoleAccess(meta.Acl == null ? null : meta.Acl.MetaWriteRole, user, isSystemStream); default: throw new ArgumentOutOfRangeException("streamAccessType"); } }
private static EventResult GetEventRecord(ITransactionFileReader reader, IndexEntry indexEntry) { var res = ReadPrepareInternal(reader, indexEntry.Position); if (!res.Success) return new EventResult(false, null); var eventRecord = new EventRecord(indexEntry.Version, res.Record); return new EventResult(true, eventRecord); }
private void ReturnReader(ITransactionFileReader reader) { _readers.Push(reader); }
private static PrepareResult ReadPrepareInternal(ITransactionFileReader reader, long pos) { RecordReadResult result = reader.TryReadAt(pos); if (!result.Success) return new PrepareResult(false, null); Debug.Assert(result.LogRecord.RecordType == LogRecordType.Prepare, "Incorrect type of log record, expected Prepare record."); return new PrepareResult(true, (PrepareLogRecord)result.LogRecord); }
private StreamMetadata GetStreamMetadataCached(ITransactionFileReader reader, string streamId) { if (SystemStreams.IsMetastream(streamId)) return _metastreamMetadata; StreamCacheInfo streamCacheInfo; if (_streamInfoCache.TryGet(streamId, out streamCacheInfo) && streamCacheInfo.Metadata != null) { Interlocked.Increment(ref _cachedStreamInfo); return streamCacheInfo.Metadata; } var metadata = GetStreamMetadataUncached(reader, streamId); _streamInfoCache.Put(streamId, key => new StreamCacheInfo(null, metadata), // we keep previous metadata, if present by this time, because it was added on commit and is more up to date (key, oldValue) => new StreamCacheInfo(oldValue.LastEventNumber, oldValue.Metadata ?? metadata)); return metadata; }
private int GetLastStreamEventNumberCached(ITransactionFileReader reader, string streamId) { Ensure.NotNull(streamId, "streamId"); StreamCacheInfo streamCacheInfo; if (_streamInfoCache.TryGet(streamId, out streamCacheInfo) && streamCacheInfo.LastEventNumber.HasValue) return streamCacheInfo.LastEventNumber.Value; var lastEventNumber = GetLastStreamEventNumberUncached(reader, streamId); if (lastEventNumber != ExpectedVersion.NoStream) { // we should take Max on LastEventNumber because there could be a commit happening in parallel thread // so we should not overwrite the actual LastEventNumber updated by Commit method with our stale one _streamInfoCache.Put( streamId, key => new StreamCacheInfo(lastEventNumber, null), (key, old) => new StreamCacheInfo(Math.Max(lastEventNumber, old.LastEventNumber ?? -1), old.Metadata)); } return lastEventNumber; }
private int GetLastStreamEventNumberUncached(ITransactionFileReader reader, string streamId) { var streamHash = _hasher.Hash(streamId); IndexEntry latestEntry; if (!_tableIndex.TryGetLatestEntry(streamHash, out latestEntry)) return ExpectedVersion.NoStream; var res = ReadPrepareInternal(reader, latestEntry.Position); if (!res.Success) throw new Exception("Couldn't read latest stream's prepare! That shouldn't happen EVER!"); if (res.Record.EventStreamId == streamId) // LUCKY!!! return latestEntry.Version; // TODO AN here lies the problem of out of memory if the stream has A LOT of events in them foreach (var indexEntry in _tableIndex.GetRange(streamHash, 0, int.MaxValue)) { var r = ReadPrepareInternal(reader, indexEntry.Position); if (r.Success && r.Record.EventStreamId == streamId) return indexEntry.Version; // AT LAST!!! } return ExpectedVersion.NoStream; // no such event stream }
private StreamMetadata GetStreamMetadataCached(ITransactionFileReader reader, string streamId) { StreamCacheInfo streamCacheInfo; if (_streamInfoCache.TryGet(streamId, out streamCacheInfo) && streamCacheInfo.Metadata.HasValue) return streamCacheInfo.Metadata.Value; var metadata = GetStreamMetadataUncached(reader, streamId); _streamInfoCache.Put(streamId, key => new StreamCacheInfo(null, metadata), (key, oldValue) => new StreamCacheInfo(oldValue.LastEventNumber, metadata)); return metadata; }