예제 #1
0
        public static List <DbItem> ReadFixedSizeItems(IPage page)
        {
            short[] itemLengths = ReadFixedSizeItemLengths(page);
            var     result      = new List <DbItem>(itemLengths.Length);

            short maxSize = DbItem.GetMaxSize(PageHeaderBase.GetSizeRange(page));
            int   offset  = page.Content.Length - maxSize;
            var   content = page.Content;
            int   cnt     = itemLengths.Length;

            for (int i = 0; i < cnt; i++)
            {
                var il = itemLengths[i];
                if (il != -1) // item is actualy present on page, read it
                {
                    var itemBytes = new byte[Math.Max(il, (short)0)];
                    Buffer.BlockCopy(content, offset, itemBytes, 0, itemBytes.Length);

                    result.Add(new DbItem(itemBytes));
                }

                offset -= maxSize;
            }

            return(result);
        }
예제 #2
0
        public static bool HasFreeSpaceForFixedSizeItem(IPage page)
        {
            PageHeaderBase header = GetPageHeader(page);

            if (header.SizeRange == SizeRange.NotApplicable ||
                header.SizeRange == SizeRange.MultiPage)
            {
                return(false);
            }

            short fixedSizeItemMarkersLength = ReadFixedSizeItemMarkersLength(page);

            short slotSize = DbItem.GetMaxSize(header.SizeRange);

            int remainingSpace =
                page.Length -                                                         // full page length
                header.Length -                                                       // subtract header length
                fixedSizeItemMarkersLength * OnPagePointerSize - OnPagePointerSize -  // subtract item length markers array and its length
                ReadFixedSizeItemsCount(page) * slotSize                              // subtract non-deleted items
                - OnPagePointerSize;                                                  // subtruct new item length marker needed to add a new item

            if (remainingSpace < slotSize)
            {
                return(false);
            }

            return(true);
        }
예제 #3
0
        public static short[] ReadFixedSizeItemLengths(IPage page)
        {
            SizeRange range = PageHeaderBase.GetSizeRange(page);

            if (range == SizeRange.MultiPage || range == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            short headerLength    = PageHeaderBase.GetHeaderLength(page);
            short itemSizesLength = BitConverter.ToInt16(page.Content, headerLength);

            var result = new short[itemSizesLength];

            int offset  = headerLength + OnPagePointerSize;
            var content = page.Content;

            for (int i = 0; i < itemSizesLength; i++)
            {
                result[i] = BitConverter.ToInt16(content, offset);
                offset   += OnPagePointerSize;
            }

            return(result);
        }
예제 #4
0
        public static List <byte[]> ReadVariableSizeItems(IPage page)
        {
            PageType pageType = PageHeaderBase.GetPageType(page);

            if (pageType != PageType.RadixTree)
            {
                throw new PageFormatException("Page is not dedicated to variable size items.");
            }

            short headerLength = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);

            var result = new List <byte[]>();

            var lengthMarkers = ReadMarkers(page, headerLength);

            int offset = 0;

            foreach (var length in lengthMarkers)
            {
                offset += Math.Abs(length);

                var bytes = new byte[length];
                Buffer.BlockCopy(page.Content, page.Content.Length - offset, bytes, 0, length);

                result.Add(bytes);
            }

            return(result);
        }
예제 #5
0
        public static void RewriteFixedSizeItem(IPage page, short itemIndex, DbItem item)
        {
            if (itemIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(itemIndex));
            }

            PageHeaderBase header = GetPageHeader(page);

            if (header.SizeRange == SizeRange.MultiPage ||
                header.SizeRange == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            if (ReadFixedSizeItemMarkersLength(page) - 1 < itemIndex)
            {
                throw new PageFormatException("Unable to rewrite fixed size item. Index is too large.");
            }

            // write the item length marker
            byte[] lengthBytes = BitConverter.GetBytes((short)item.RawData.Length);
            lengthBytes.CopyTo(page.Content,
                               header.Length +               // length of header
                               OnPagePointerSize +           // length of length marker array
                               itemIndex * OnPagePointerSize // offset in length marker array
                               );

            Buffer.BlockCopy(item.RawData,
                             0,
                             page.Content,
                             page.Length - DbItem.GetMaxSize(header.SizeRange) * (itemIndex + 1),
                             item.RawData.Length);
        }
예제 #6
0
        public static ushort GetFreeSpace(IPage page)
        {
            PageType pageType = PageHeaderBase.GetPageType(page);

            if (pageType != PageType.RadixTree)
            {
                throw new PageFormatException("Page is not dedicated to variable size items.");
            }

            return(RadixTreeNodesPageHeader.ReadFreeSpace(page));
        }
예제 #7
0
        private static MultipageItemPageHeader GetMultipageItemPageHeader(IPage page)
        {
            PageHeaderBase result = GetPageHeader(page);

            if (result.SizeRange != SizeRange.MultiPage)
            {
                throw new PageFormatException("Page is not dedicated to multipage items.");
            }

            return((MultipageItemPageHeader)result);
        }
예제 #8
0
        private static FreeSpaceMapPageHeader GetFsmPageHeader(IPage page)
        {
            PageHeaderBase result = GetPageHeader(page);

            if (result.SizeRange != SizeRange.MultiPage ||
                result.PageType != PageType.FreeSpaceMap)
            {
                throw new PageFormatException("Page is not dedicated to free-space-map.");
            }

            return((FreeSpaceMapPageHeader)result);
        }
예제 #9
0
        public static void FormatVariableSizeItemsPage(IPage page, PageHeaderBase header, List <byte[]> items)
        {
            header.WriteToPage(page);

            short itemsLength = items.Aggregate <byte[], short>(0, (current, item) => (short)(current + (short)(item.Length)));

            int remainingSpace =
                page.Length -                                           // full page length
                header.Length -                                         // subtract header length
                itemsLength -                                           // subtract items length
                items.Count * OnPagePointerSize + OnPagePointerSize;    // subtract markers array and its length

            if (remainingSpace < 0)
            {
                throw new ArgumentException("Page have no space to add specified items", nameof(items));
            }

            var content       = page.Content;
            int contentLength = page.Length;
            int cnt           = items.Count;
            int headerLength  = header.Length;

            short offset = 0;

            for (int index = 0; index < cnt; index++)
            {
                var item = items[index];

                byte[] bytes;
                if (item != null)
                {
                    bytes = BitConverter.GetBytes((short)item.Length);

                    offset += (short)item.Length;

                    // write the body of item
                    Buffer.BlockCopy(item, 0, content, contentLength - offset, item.Length);
                }
                else
                {
                    bytes = zeroBytesShort;
                }

                // write the length marker
                Buffer.BlockCopy(bytes, 0, content, headerLength + OnPagePointerSize * (index + 1), sizeof(short));
            }

            // write the length of length marker array
            byte[] lengthLengthMarkers = BitConverter.GetBytes((short)cnt);
            lengthLengthMarkers.CopyTo(content, headerLength);

            WriteFreeSpace(page, (ushort)remainingSpace);
        }
예제 #10
0
        public static void InitPage(IPage page, PageHeaderBase header)
        {
            if (header.Length > page.Length)
            {
                throw new PageFormatException("Unable to format page. Too large header.");
            }

            // fill whole page with zero
            Array.Clear(page.Content, 0, page.Length);

            header.WriteToPage(page);
        }
예제 #11
0
        public static short ReadItemMarkersLength(IPage page)
        {
            PageType pageType = PageHeaderBase.GetPageType(page);

            if (pageType != PageType.RadixTree)
            {
                throw new PageFormatException("Page is not dedicated to variable size items.");
            }

            short headerLength = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);

            return(BitConverter.ToInt16(page.Content, headerLength));
        }
예제 #12
0
        public static short ReadFixedSizeItemMarkersLength(IPage page)
        {
            SizeRange sc = PageHeaderBase.GetSizeRange(page);

            if (sc == SizeRange.MultiPage || sc == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            short headerLength = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);

            return(BitConverter.ToInt16(page.Content, headerLength));
        }
예제 #13
0
        private static int GetNewSlotCount(IPage page, PageHeaderBase header)
        {
            short fixedSizeItemMarkersLength = BitConverter.ToInt16(page.Content, FixedSizeItemsPageHeader.FixedSizeItemsHeaderLength);

            short slotSize = DbItem.GetMaxSize(header.SizeRange);

            int remainingSpace =
                page.Length -                                                        // full page length
                header.Length -                                                      // subtract header length
                fixedSizeItemMarkersLength * OnPagePointerSize - OnPagePointerSize - // subtract item length markers array and its length
                fixedSizeItemMarkersLength * slotSize;                               // subtract items

            return(remainingSpace / (slotSize + OnPagePointerSize));
        }
예제 #14
0
        public static void DeleteFixedSizeItems(IPage page)
        {
            PageHeaderBase header = GetPageHeader(page);

            if (header.SizeRange == SizeRange.MultiPage ||
                header.SizeRange == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            // set length of item markers to zero
            zeroBytesShort.CopyTo(page.Content, header.Length);

            // set empty slot count to zero
            zeroBytesShort.CopyTo(page.Content, OnPageOffsets.FixedSizeItem.EmptySlotCount);
        }
예제 #15
0
        public static void FormatFixedSizeItemsPage(IPage page, PageHeaderBase header, DbItem[] items)
        {
            var sizeRange = header.SizeRange;

            if (items.Any())
            {
                if (items.Any(item => item.SizeRange != sizeRange))
                {
                    throw new ArgumentException("Size ranges should be equal", nameof(items));
                }
            }

            header.WriteToPage(page);

            int remainingSpace =
                page.Length -                                                     // full page length
                header.Length -                                                   // subtract header length
                items.Length * OnPagePointerSize - OnPagePointerSize;             // subtract item length markers array and its length

            if (remainingSpace < 0)
            {
                throw new ArgumentException("Page have no space to add specified items", nameof(items));
            }

            var maxSize       = DbItem.GetMaxSize(sizeRange);
            var content       = page.Content;
            int contentLength = page.Length;
            int cnt           = items.Length;
            int headerLength  = header.Length;

            for (int index = 0; index < cnt; index++)
            {
                var rawData = items[index].RawData;

                // write the length marker
                Buffer.BlockCopy(BitConverter.GetBytes((short)rawData.Length), 0, content, headerLength + OnPagePointerSize * (index + 1), sizeof(short));

                // write the body of item
                Buffer.BlockCopy(rawData, 0, content, contentLength - maxSize * (index + 1), rawData.Length);
            }

            // write the length of length marker array
            byte[] lengthLengthMarkers = BitConverter.GetBytes((short)cnt);
            lengthLengthMarkers.CopyTo(content, headerLength);
        }
예제 #16
0
        public static DbItem ReadFixedSizeItem(IPage page, short itemIndex)
        {
            short itemLength = ReadFixedSizeItemLength(page, itemIndex);

            if (itemLength == -1)
            {
                throw new PageFormatException("Item has been deleted.");
            }

            var   itemBytes = new byte[itemLength];
            short slotSize  = DbItem.GetMaxSize(PageHeaderBase.GetSizeRange(page));
            int   offset    = page.Content.Length - slotSize * (itemIndex + 1);

            for (int j = 0; j < itemBytes.Length; j++)
            {
                itemBytes[j] = page.Content[j + offset];
            }

            return(new DbItem(itemBytes));
        }
예제 #17
0
        public static bool IsFixedSizeItemAllocated(IPage page, short itemIndex)
        {
            SizeRange sc = PageHeaderBase.GetSizeRange(page);

            if (sc == SizeRange.MultiPage || sc == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            short headerLength    = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);
            short itemSizesLength = BitConverter.ToInt16(page.Content, headerLength);

            if (itemIndex >= itemSizesLength)
            {
                return(false);
            }

            int offset = headerLength + OnPagePointerSize + itemIndex * OnPagePointerSize;

            return(BitConverter.ToInt16(page.Content, offset) != -1);
        }
예제 #18
0
        public static short ReadFixedSizeItemLength(IPage page, short itemIndex)
        {
            SizeRange range = PageHeaderBase.GetSizeRange(page);

            if (range == SizeRange.MultiPage || range == SizeRange.NotApplicable)
            {
                throw new PageFormatException("Page is not dedicated to fixed size items.");
            }

            short headerLength    = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);
            short itemSizesLength = BitConverter.ToInt16(page.Content, headerLength);

            if (itemIndex >= itemSizesLength)
            {
                throw new ArgumentOutOfRangeException(nameof(itemIndex));
            }

            int offset = headerLength + OnPagePointerSize + itemIndex * OnPagePointerSize;

            return(BitConverter.ToInt16(page.Content, offset));
        }
예제 #19
0
        public static byte[] ReadVariableSizeItem(IPage page, short itemIndex)
        {
            PageType pageType = PageHeaderBase.GetPageType(page);

            if (pageType != PageType.RadixTree)
            {
                throw new PageFormatException("Page is not dedicated to variable size items.");
            }


            short headerLength = BitConverter.ToInt16(page.Content, OnPageOffsets.HeaderLength);

            var lengthMarkers = ReadMarkers(page, headerLength);

            if (itemIndex >= lengthMarkers.Length)
            {
                throw new PageFormatException("Wrong item index.");
            }

            int offset = 0;
            int length = 0;

            for (int i = 0; i <= itemIndex; i++)
            {
                length  = lengthMarkers[i];
                offset += Math.Abs(length);
            }

            if (length <= 0)
            {
                throw new PageFormatException("Item has been deleted.");
            }

            var result = new byte[length];

            Buffer.BlockCopy(page.Content, page.Content.Length - offset, result, 0, length);

            return(result);
        }
예제 #20
0
        public static PageHeaderBase GetPageHeader(IPage page)
        {
            PageHeaderBase ph;
            PageType       pt = PageHeaderBase.GetPageType(page);

            switch (pt)
            {
            case PageType.FreeSpaceMap:
                ph = new FreeSpaceMapPageHeader();
                ph.Read(page);
                return(ph);

            case PageType.Heading:
                ph = new HeadingPageHeader();
                ph.Read(page);
                return(ph);

            case PageType.MultipageItem:
                ph = new MultipageItemPageHeader();
                ph.Read(page);
                return(ph);

            case PageType.FixedSizeItem:
                ph = new FixedSizeItemsPageHeader();
                ph.Read(page);
                return(ph);

            case PageType.BPlusTree:
                ph = new BPlusTreeNodePageHeader();
                ph.Read(page);
                return(ph);

            case PageType.RadixTree:
                ph = new RadixTreeNodesPageHeader();
                ph.Read(page);
                return(ph);
            }
            return(null);
        }