Esempio n. 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

            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);
        }
Esempio n. 2
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;
            }
        }
Esempio n. 3
0
        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);
        }