Esempio n. 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);
        }
Esempio n. 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);
        }
Esempio n. 3
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);
        }
Esempio n. 4
0
 private byte[] GenerateRandomSequence(SizeRange sizeRange)
 {
     return
         (GenerateRandomSequence(sizeRange == SizeRange.MultiPage
                                    ? _r.Next(327681)
                                    : DbItem.GetMaxSize(sizeRange)));
 }
Esempio n. 5
0
        public void FixedSizeItemsLength()
        {
            var manager = new FileSystemPageManager(4096);

            using (var storage = new Storage(manager))
            {
                storage.CreateNew(StoragePath);

                var fsm = new FreeSpaceMap(manager);

                var memoryManager = new MemoryManager(fsm, manager);

                int count = 1000;

                var items = new Dictionary <DbItemReference, byte[]>();

                var r = new Random();

                // allocate items
                for (int i = 0; i < count; i++)
                {
                    var sizeRange = GetRandomFixedSizeItemsSizeRange();
                    var content   = GenerateRandomSequence(DbItem.GetMaxSize(sizeRange) - r.Next(5));
                    var reference = memoryManager.Allocate(content);
                    items[reference] = content;
                }

                // check lengths
                foreach (var reference in items.Keys)
                {
                    Assert.AreEqual(items[reference].Length, memoryManager.GetLength(reference));
                }
            }
        }
Esempio n. 6
0
 protected void CheckSizeRange(int pageSize)
 {
     if (DbItem.GetMaxSize(SizeRange) > pageSize - Length - 4)
     {
         throw new PageFormatException("Unable to format page. The class size " + Enum.GetName(typeof(SizeRange), SizeRange) + " is too large for page " + pageSize + "bytes length.");
     }
 }
Esempio n. 7
0
        public void FixedSizeItemsAllocation()
        {
            var manager = new FileSystemPageManager(4096);

            using (var storage = new Storage(manager))
            {
                storage.CreateNew(StoragePath);

                var fsm = new FreeSpaceMap(manager);

                var memoryManager = new MemoryManager(fsm, manager);

                int count = 100000;

                var items = new Dictionary <DbItemReference, byte[]>();

                // allocate items
                for (int i = 0; i < count; i++)
                {
                    var sizeRange = GetRandomFixedSizeItemsSizeRange();
                    var content   = GenerateRandomSequence(DbItem.GetMaxSize(sizeRange));
                    var reference = memoryManager.Allocate(content);
                    items[reference] = content;
                }

                // check contents
                foreach (var reference in items.Keys)
                {
                    Assert.IsTrue(AreEqualByteArrays(items[reference], memoryManager.Get(reference).RawData));
                }

                // free half of the items
                var freedItems = new Dictionary <DbItemReference, byte[]>();

                foreach (var reference in items.Keys)
                {
                    if (_r.NextDouble() > 0.5)
                    {
                        memoryManager.Free(reference);
                        freedItems[reference] = items[reference];
                    }
                }

                // check that the items do not exist
                foreach (var reference in freedItems.Keys)
                {
                    Assert.IsNull(memoryManager.Get(reference));
                }

                // and the remaining items still available
                foreach (var reference in items.Keys.Where(item => !freedItems.ContainsKey(item)))
                {
                    Assert.IsTrue(AreEqualByteArrays(items[reference], memoryManager.Get(reference).RawData));
                }
            }
        }
Esempio n. 8
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));
        }
Esempio n. 9
0
        public void FixedSizeItemsPage()
        {
            int pageSize         = 32768;
            var dummyPageManager = new FileSystemPageManager(pageSize);
            var p = new Page(dummyPageManager, 0, new byte[pageSize]);

            var header = new FixedSizeItemsPageHeader();
            var r      = new Random();

            foreach (var sizeRange in EnumHelper.FixedSizeItemsSizeRanges())
            {
                header.SizeRange = sizeRange;

                PageFormatter.InitPage(p, header);

                var item = new DbItem(new byte[DbItem.GetMaxSize(header.SizeRange)]);
                r.NextBytes(item.RawData);

                // fill the page with the items
                short count        = 0;
                bool  spaceRemains = true;
                while (PageFormatter.HasFreeSpaceForFixedSizeItem(p))
                {
                    Assert.IsTrue(spaceRemains);
                    PageFormatter.AddFixedSizeItem(p, item, out spaceRemains);
                    count++;
                    Assert.AreEqual(count, PageFormatter.ReadFixedSizeItemsCount(p));
                }

                Assert.IsFalse(spaceRemains);

                // check if fetched objects are equal to originals
                for (short j = 0; j < PageFormatter.ReadFixedSizeItemsCount(p); j++)
                {
                    DbItem readItem = PageFormatter.ReadFixedSizeItem(p, j);
                    Assert.IsTrue(AreEqualByteArrays(item.RawData, readItem.RawData));
                }

                // delete all added items
                short itemindex = 0;
                while (PageFormatter.ReadFixedSizeItemsCount(p) > 0)
                {
                    PageFormatter.DeleteFixedSizeItem(p, itemindex);
                    count--;
                    itemindex++;
                    Assert.AreEqual(count, PageFormatter.ReadFixedSizeItemsCount(p));
                }
            }
        }
Esempio n. 10
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);
        }
Esempio n. 11
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));
        }
Esempio n. 12
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));
        }