public static void CopyToPage(CompressionResult compressed, TreePage dest) { // let us copy the compressed values at the end of the page // so we will handle additional, uncompressed values as usual var writePtr = dest.Base + dest.PageSize - Constants.Compression.HeaderSize; var header = (CompressedNodesHeader *)writePtr; *header = compressed.Header; writePtr -= header->SectionSize; Memory.Copy(writePtr, compressed.CompressionOutputPtr, compressed.Header.CompressedSize + header->NumberOfCompressedEntries * Constants.Tree.NodeOffsetSize); dest.Flags |= PageFlags.Compressed; dest.Lower = (ushort)Constants.Tree.PageHeaderSize; dest.Upper = (ushort)(writePtr - dest.Base); Debug.Assert((dest.Upper & 1) == 0); }
public static void CopyToPage(CompressionResult compressed, TreePage dest) { // let us copy the compressed values at the end of the page // so we will handle additional, uncompressed values as usual if (compressed.CompressionOutputPtr != null) { Debug.Assert(compressed.Header.CompressedSize > 0, "compressed.Header.CompressedSize > 0, value: " + compressed.Header.CompressedSize); var writePtr = dest.Base + dest.PageSize - Constants.Compression.HeaderSize; var header = (CompressedNodesHeader *)writePtr; * header = compressed.Header; writePtr -= header->SectionSize; Memory.Copy(writePtr, compressed.CompressionOutputPtr, compressed.Header.CompressedSize + header->NumberOfCompressedEntries * Constants.Tree.NodeOffsetSize); dest.Flags |= PageFlags.Compressed; dest.Lower = (ushort)Constants.Tree.PageHeaderSize; dest.Upper = (ushort)(writePtr - dest.Base); Debug.Assert((dest.Upper & 1) == 0); } else { Debug.Assert(compressed.Header.CompressedSize == 0, "compressed.Header.CompressedSize == 0, value: " + compressed.Header.CompressedSize); if (compressed.CompressedPage.NumberOfEntries != 0) { ThrowNullCompressionOutputButNonEmptyPage(compressed.CompressedPage); } dest.Lower = (ushort)Constants.Tree.PageHeaderSize; dest.Upper = (ushort)dest.PageSize; dest.Flags &= ~PageFlags.Compressed; } }
public static IDisposable TryGetCompressedTempPage(LowLevelTransaction tx, TreePage page, out CompressionResult result, bool defrag = true) { if (defrag) { if (page.CalcSizeUsed() != page.SizeUsed - Constants.Tree.PageHeaderSize) // check if the page really requires defrag { page.Defrag(tx); } } var valuesSize = page.PageSize - page.Upper; TemporaryPage temp; var returnTempPage = tx.Environment.GetTemporaryPage(tx, out temp); var tempPage = temp.GetTempPage(); var compressionInput = page.Base + page.Upper; var compressionResult = tempPage.Base + Constants.Tree.PageHeaderSize + Constants.Compression.HeaderSize; // temp compression result has compressed values at the beginning of the page var offsetsSize = page.NumberOfEntries * Constants.Tree.NodeOffsetSize; var compressionOutput = compressionResult + offsetsSize; var compressedSize = LZ4.Encode64( compressionInput, compressionOutput, valuesSize, tempPage.PageSize - (Constants.Tree.PageHeaderSize + Constants.Compression.HeaderSize) - offsetsSize); if (compressedSize == 0 || compressedSize > valuesSize) { // output buffer size not enough or compressed output size is greater than uncompressed input result = null; return(returnTempPage); } var compressedOffsets = (ushort *)compressionResult; var offsets = page.KeysOffsets; for (var i = 0; i < page.NumberOfEntries; i++) { compressedOffsets[i] = (ushort)(offsets[i] - page.Upper); } var compressionSectionSize = compressedSize + offsetsSize; var sizeLeftInDecompressedPage = Constants.Compression.MaxPageSize - page.SizeUsed; var sizeLeftForUncompressedEntries = tx.PageSize - (Constants.Tree.PageHeaderSize + Constants.Compression.HeaderSize + compressionSectionSize); if (sizeLeftForUncompressedEntries > sizeLeftInDecompressedPage) { // expand compression section to prevent from adding next uncompressed entries what would result in // exceeding MaxPageSize after the decompression compressionSectionSize += sizeLeftForUncompressedEntries - sizeLeftInDecompressedPage; } compressionSectionSize += compressionSectionSize & 1; // ensure 2-byte alignment // check that after decompression we won't exceed MaxPageSize Debug.Assert(page.SizeUsed + // page header, node offsets, existing entries (tx.PageSize - // space that can be still used to insert next uncompressed entries (Constants.Tree.PageHeaderSize + Constants.Compression.HeaderSize + compressionSectionSize)) <= Constants.Compression.MaxPageSize); Memory.Copy(tempPage.Base, page.Base, Constants.Tree.PageHeaderSize); tempPage.Lower = (ushort)(Constants.Tree.PageHeaderSize + Constants.Compression.HeaderSize + compressionSectionSize); tempPage.Upper = (ushort)tempPage.PageSize; Debug.Assert(tempPage.Lower <= tempPage.Upper); result = new CompressionResult { CompressedPage = tempPage, CompressionOutputPtr = compressionResult, Header = new CompressedNodesHeader { SectionSize = (ushort)compressionSectionSize, CompressedSize = (ushort)compressedSize, UncompressedSize = (ushort)valuesSize, NumberOfCompressedEntries = page.NumberOfEntries, } }; return(returnTempPage); }