public void AddReplicatedChunk(TFChunk replicatedChunk, bool verifyHash) { Ensure.NotNull(replicatedChunk, "replicatedChunk"); if (!replicatedChunk.IsReadOnly) { throw new ArgumentException(string.Format("Passed TFChunk is not completed: {0}.", replicatedChunk.FileName)); } var chunkHeader = replicatedChunk.ChunkHeader; var oldFileName = replicatedChunk.FileName; var newFileName = _config.FileNamingStrategy.GetFilenameFor(chunkHeader.ChunkStartNumber, chunkHeader.ChunkScavengeVersion); replicatedChunk.Dispose(); try { replicatedChunk.WaitForDestroy(0); // should happen immediately } catch (TimeoutException exc) { throw new Exception(string.Format("Replicated chunk '{0}' ({1}-{2}) is used by someone else.", replicatedChunk.FileName, replicatedChunk.ChunkHeader.ChunkStartNumber, replicatedChunk.ChunkHeader.ChunkEndNumber), exc); } //TODO AN: temporary workaround for (int i = chunkHeader.ChunkStartNumber; i <= chunkHeader.ChunkEndNumber; ++i) { var oldChunk = _chunks[i]; if (oldChunk != null) { oldChunk.MarkForDeletion(); oldChunk.WaitForDestroy(500); } } // TODO AN it is possible that chunk with the newFileName already exists, need to work around that // TODO AN this could be caused by scavenging... no scavenge -- no cry :( File.Move(oldFileName, newFileName); var newChunk = TFChunk.FromCompletedFile(newFileName, verifyHash); for (int i = chunkHeader.ChunkStartNumber; i <= chunkHeader.ChunkEndNumber; ++i) { var oldChunk = Interlocked.Exchange(ref _chunks[i], newChunk); if (oldChunk != null) { oldChunk.MarkForDeletion(); } } _chunksCount = newChunk.ChunkHeader.ChunkEndNumber + 1; Debug.Assert(_chunks[_chunksCount] == null); TryCacheChunk(newChunk); }
private TFChunk LoadChunk(string chunkFileName) { var chunk = TFChunk.FromCompletedFile(chunkFileName); return(chunk); }
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); } }
private TFChunk LoadChunk(string chunkFileName, bool verifyHash) { var chunk = TFChunk.FromCompletedFile(chunkFileName, verifyHash); return(chunk); }