/// <summary> /// Create a new table builder. /// - storageOptions define the options for the table buildup. /// - dataStream is where the data for the table will be written to. /// REQUIRES: Being able to read dataStream.Position /// - tempStream is where temporary data is written to avoid holding too much in memory /// REQUIRES: Being able to read tempStream.Position AND change tempStream.Position /// </summary> public TableBuilder(StorageState storageState, Stream dataStream, TemporaryFiles temporaryFiles) { _temporaryFiles = temporaryFiles; try { _storageState = storageState; _dataStream = dataStream; _indexStream = temporaryFiles.Create(); _originalIndexStreamPosition = _indexStream.Position; _lastKeyBuffer = _storageState.Options.BufferPool.Take(storageState.Options.MaximumExpectedKeySize); _scratchBuffer = _storageState.Options.BufferPool.Take(storageState.Options.MaximumExpectedKeySize); if (storageState.Options.FilterPolicy != null) { var filterBuilder = storageState.Options.FilterPolicy.CreateBuilder(); _filterBlockStream = temporaryFiles.Create(); _filterBuilder = new FilterBlockBuilder(_filterBlockStream, filterBuilder); _filterBuilder.StartBlock(0); } _indexBlock = new BlockBuilder(_indexStream, storageState, _storageState.InternalKeyComparator, blockRestartInterval: 1); _dataBlock = new BlockBuilder(_dataStream, storageState, _storageState.InternalKeyComparator, _storageState.Options.BlockRestartInterval); } catch (Exception) { Dispose(); throw; } }
public void Finish() { Flush(); _closed = true; BlockHandle filterBlockHandle = null; //write filter block if (_filterBuilder != null) filterBlockHandle = _filterBuilder.Finish(_dataStream); // write metadata block var metaIndexBlock = new BlockBuilder(_dataStream, _storageState, _storageState.InternalKeyComparator, _storageState.Options.BlockRestartInterval); if (filterBlockHandle != null) { metaIndexBlock.Add(("filter." + _storageState.Options.FilterPolicy.Name), filterBlockHandle.AsStream()); } var metadIndexBlockHandle = WriteBlock(metaIndexBlock); // write index block if (_pendingIndexEntry) { var newKey = _storageState.InternalKeyComparator.FindShortestSuccessor(_lastKey, ref _scratchBuffer); _indexBlock.Add(newKey, _pendingHandle.AsStream()); _pendingIndexEntry = false; } var indexBlockSize = _indexBlock.Finish(); _indexBlock.Stream.WriteByte(0);//write type, uncompressed _indexBlock.Stream.WriteInt32(Crc.Mask(_indexBlock.Stream.WriteCrc)); _indexBlock.Stream.Position = _originalIndexStreamPosition; var indexBlockHandler = new BlockHandle { Position = _dataStream.Position, Count = indexBlockSize }; _indexBlock.Stream.Stream.CopyTo(_dataStream); // write footer var footer = new Footer { IndexHandle = indexBlockHandler, MetaIndexHandle = metadIndexBlockHandle }; footer.EncodeTo(_dataStream); }
private BlockHandle WriteBlock(BlockBuilder block) { // File format contains a sequence of blocks where each block has: // block_data: uint8[n] // type: uint8 - right now always uncompressed // crc: uint32 var size = block.Finish(); var originalPosition = block.OriginalPosition; var handle = new BlockHandle { Count = size, Position = originalPosition }; // write trailer block.Stream.WriteByte(0); // type - uncompressed _dataStream.WriteInt32(Crc.Mask(block.Stream.WriteCrc)); block.Dispose(); return handle; }
/// <summary> /// Advance: Forces the creation of a new block. /// Client code should probably not call this method /// </summary> public void Flush() { if (_dataBlock.IsEmpty) return; if (_closed) throw new InvalidOperationException("Cannot add after the table builder was closed"); if (_pendingIndexEntry) throw new InvalidOperationException("Cannot call Flush when pending for an index entry"); _pendingHandle = WriteBlock(_dataBlock); _dataBlock = new BlockBuilder(_dataStream, _storageState, _storageState.InternalKeyComparator, _storageState.Options.BlockRestartInterval); _pendingIndexEntry = true; _dataStream.Flush(); if (_filterBuilder != null) _filterBuilder.StartBlock(_dataStream.Position); }