public bool IsStreamDeleted(TStreamId streamId) => _readIndex.IsStreamDeleted(streamId);
private void ScavengeChunk(TFChunk oldChunk) { var sw = Stopwatch.StartNew(); var chunkNumber = oldChunk.ChunkHeader.ChunkStartNumber; var newScavengeVersion = oldChunk.ChunkHeader.ChunkScavengeVersion + 1; var chunkSize = oldChunk.ChunkHeader.ChunkSize; var tmpChunkPath = Path.Combine(_db.Config.Path, Guid.NewGuid() + ".scavenge.tmp"); var newChunkPath = _db.Config.FileNamingStrategy.GetFilenameFor(chunkNumber, newScavengeVersion); Log.Trace("Scavenging chunk #{0} ({1}) started. Scavenged chunk: {2} --> {3}.", chunkNumber, Path.GetFileName(oldChunk.FileName), Path.GetFileName(tmpChunkPath), Path.GetFileName(newChunkPath)); TFChunk newChunk; try { newChunk = TFChunk.CreateNew(tmpChunkPath, chunkSize, chunkNumber, newScavengeVersion); } catch (IOException exc) { Log.ErrorException(exc, "IOException during creating new chunk for scavenging purposes. Ignoring..."); return; } var positionMapping = new List <PosMap>(); var positioningNeeded = false; var result = oldChunk.TryReadFirst(); int cnt = 0; while (result.Success) { cnt += 1; var record = result.LogRecord; switch (record.RecordType) { case LogRecordType.Prepare: { var prepare = (PrepareLogRecord)record; if (!_readIndex.IsStreamDeleted(prepare.EventStreamId) || (prepare.Flags & PrepareFlags.StreamDelete) != 0) // delete tombstone should be left { var posMap = WriteRecord(newChunk, record); positionMapping.Add(posMap); positioningNeeded = posMap.LogPos != posMap.ActualPos; } break; } case LogRecordType.Commit: { var posMap = WriteRecord(newChunk, record); positionMapping.Add(posMap); positioningNeeded = posMap.LogPos != posMap.ActualPos; break; } default: throw new ArgumentOutOfRangeException(); } if (result.NextPosition == -1) { break; } result = oldChunk.TryReadSameOrClosest((int)result.NextPosition); } var oldSize = oldChunk.ChunkFooter.ActualChunkSize + oldChunk.ChunkFooter.MapSize + ChunkHeader.Size + ChunkFooter.Size; var newSize = newChunk.ActualDataSize + (positioningNeeded ? sizeof(ulong) * positionMapping.Count : 0) + ChunkHeader.Size + ChunkFooter.Size; if (false && oldSize <= newSize) { Log.Trace("Scavenging of chunk #{0} ({1}) completed in {2}.\n" + "Old version is kept as it is smaller.\n" + "Old chunk size: {3}, scavenged size: {4}.\n" + "Scavenged chunk removed.", chunkNumber, oldChunk.FileName, sw.Elapsed, oldSize, newSize); newChunk.Dispose(); File.Delete(newChunk.FileName); } else { newChunk.CompleteScavenge(positioningNeeded ? positionMapping : null); newChunk.Dispose(); File.Move(tmpChunkPath, newChunkPath); newChunk = TFChunk.FromCompletedFile(newChunkPath); var removedChunk = _db.Manager.SwapChunk(chunkNumber, newChunk); Debug.Assert(ReferenceEquals(removedChunk, oldChunk)); // only scavenging could switch, so old should be always same oldChunk.MarkForDeletion(); Log.Trace("Scavenging of chunk #{0} ({1}) completed in {2} into ({3} --> {4}).\n" + "Old size: {5}, new size: {6}, new scavenge version: {7}.", chunkNumber, Path.GetFileName(oldChunk.FileName), sw.Elapsed, Path.GetFileName(tmpChunkPath), Path.GetFileName(newChunkPath), oldSize, newSize, newScavengeVersion); } }
public static bool IsStreamDeleted <TStreamId>(this IReadIndex <TStreamId> self, string streamName) { var streamId = self.GetStreamId(streamName); return(self.IsStreamDeleted(streamId)); }