Esempio n. 1
0
        public static int WriteMultipageItemBlock(IPage page, DbItem item, long offset)
        {
            if (offset < 0 || offset >= item.RawData.LongLength)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            MultipageItemPageHeader header = GetMultipageItemPageHeader(page);

            if (item.GetAllocationType(page.Length) == AllocationType.SinglePage)
            {
                throw new PageFormatException("Unable to add item block on page. Item allocation type is single page.");
            }

            int last          = Math.Min(page.Length - header.Length, (int)(item.RawData.LongLength - offset)) - 1;
            int contentOffset = header.Length;

            if (offset == 0)
            {
                // we should write the length of the object
                var lengthBytes = BitConverter.GetBytes(item.RawData.LongLength);
                lengthBytes.CopyTo(page.Content, header.Length);

                last          -= 8;
                contentOffset += 8;
            }

            for (long i = 0; i <= last; i++)
            {
                page.Content[i + contentOffset] = item.RawData[i + offset];
            }

            return(last + 1);
        }
Esempio n. 2
0
        public static DbItemReference AddFixedSizeItem(IPage page, DbItem item, out bool hasRemainingSpace)
        {
            var header = (FixedSizeItemsPageHeader)GetPageHeader(page);

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

            if (item.GetAllocationType(page.Length) == AllocationType.MultiPage)
            {
                throw new PageFormatException("Unable to add item on page. Item is too large.");
            }

            if (header.SizeRange != item.SizeRange)
            {
                throw new PageFormatException("Unable to add item on page. Mismatch size ranges.");
            }

            hasRemainingSpace = false;

            byte[] lengthBytes;
            if (header.EmptySlotCount > 0)
            {
                // find an empty slot for a new item
                var slotIndex = GetFirstFixedSizeItemEmptySlotIndex(page, header.Length);
                if (slotIndex == -1)
                {
                    throw new DataTankerException($"Page is corrupt: empty slot counter is {header.EmptySlotCount}, but there is no empty slot found");
                }

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

                Buffer.BlockCopy(item.RawData,
                                 0,
                                 page.Content,
                                 page.Length - DbItem.GetMaxSize(header.SizeRange) * (slotIndex + 1),
                                 item.RawData.Length);

                if (header.EmptySlotCount > 1)
                {
                    hasRemainingSpace = true;
                }

                // decrease empty slot count
                BitConverter.GetBytes((short)(header.EmptySlotCount - 1)).CopyTo(page.Content, OnPageOffsets.FixedSizeItem.EmptySlotCount);
                return(new DbItemReference(page.Index, slotIndex));
            }

            // there are no empty slots on this page
            // check the page have the enough space to allocate a new slot
            var newSlotCount = GetNewSlotCount(page, header);

            if (newSlotCount == 0)
            {
                throw new PageFormatException("The page have no space to add an item.");
            }

            var itemLengthsLength = BitConverter.ToInt16(page.Content, header.Length);

            // write the length marker
            lengthBytes = BitConverter.GetBytes((short)item.RawData.Length);
            lengthBytes.CopyTo(page.Content,
                               header.Length +                       // length of header
                               OnPagePointerSize +                   // length of length marker array
                               itemLengthsLength * OnPagePointerSize // skip to the end of length marker array
                               );

            // write the increased length of length marker array
            byte[] lengthLengthMarkers = BitConverter.GetBytes((short)(itemLengthsLength + 1));
            lengthLengthMarkers.CopyTo(page.Content, header.Length);

            // write the item body
            Buffer.BlockCopy(item.RawData,
                             0,
                             page.Content,
                             page.Length - DbItem.GetMaxSize(header.SizeRange) * (itemLengthsLength + 1),
                             item.RawData.Length);

            if (newSlotCount > 1)
            {
                hasRemainingSpace = true;
            }

            return(new DbItemReference(page.Index, itemLengthsLength));
        }