Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        private TFChunk LoadChunk(string chunkFileName)
        {
            var chunk = TFChunk.FromCompletedFile(chunkFileName);

            return(chunk);
        }
Esempio n. 3
0
        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);
            }
        }
Esempio n. 4
0
        private TFChunk LoadChunk(string chunkFileName, bool verifyHash)
        {
            var chunk = TFChunk.FromCompletedFile(chunkFileName, verifyHash);

            return(chunk);
        }