Exemple #1
0
        /// <summary>
        /// Get a new page segment for this length content using fixed index
        /// </summary>
        private BufferSlice InternalInsert(ushort bytesLength, ref byte index)
        {
            var isNewInsert = index == byte.MaxValue;

            ENSURE(_buffer.ShareCounter == BUFFER_WRITABLE, "page must be writable to support changes");
            ENSURE(bytesLength > 0, "must insert more than 0 bytes");
            ENSURE(this.FreeBytes >= bytesLength + (isNewInsert ? SLOT_SIZE : 0), "length must be always lower than current free space");
            ENSURE(this.ItemsCount < byte.MaxValue, "page full");
            ENSURE(this.FreeBytes >= this.FragmentedBytes, "fragmented bytes must be at most free bytes");

            if (!(this.FreeBytes >= bytesLength + (isNewInsert ? SLOT_SIZE : 0)))
            {
                throw LiteException.InvalidFreeSpacePage(this.PageID, this.FreeBytes, bytesLength + (isNewInsert ? SLOT_SIZE : 0));
            }

            // calculate how many continuous bytes are avaiable in this page
            var continuousBlocks = this.FreeBytes - this.FragmentedBytes - (isNewInsert ? SLOT_SIZE : 0);

            ENSURE(continuousBlocks == PAGE_SIZE - this.NextFreePosition - this.FooterSize - (isNewInsert ? SLOT_SIZE : 0), "continuousBlock must be same as from NextFreePosition");

            // if continuous blocks are not enough for this data, must run page defrag
            if (bytesLength > continuousBlocks)
            {
                this.Defrag();
            }

            // if index is new insert segment, must request for new Index
            if (index == byte.MaxValue)
            {
                // get new free index must run after defrag
                index = this.GetFreeIndex();
            }

            if (index > this.HighestIndex || this.HighestIndex == byte.MaxValue)
            {
                ENSURE(index == (byte)(this.HighestIndex + 1), "new index must be next highest index");

                this.HighestIndex = index;
            }

            // get segment addresses
            var positionAddr = CalcPositionAddr(index);
            var lengthAddr   = CalcLengthAddr(index);

            ENSURE(_buffer.ReadUInt16(positionAddr) == 0, "slot position must be empty before use");
            ENSURE(_buffer.ReadUInt16(lengthAddr) == 0, "slot length must be empty before use");

            // get next free position in page
            var position = this.NextFreePosition;

            // write this page position in my position address
            _buffer.Write(position, positionAddr);

            // write page segment length in my length address
            _buffer.Write(bytesLength, lengthAddr);

            // update next free position and counters
            this.ItemsCount++;
            this.UsedBytes        += bytesLength;
            this.NextFreePosition += bytesLength;

            this.IsDirty = true;

            ENSURE(position + bytesLength <= (PAGE_SIZE - (this.HighestIndex + 1) * SLOT_SIZE), "new buffer slice could not override footer area");

            // create page segment based new inserted segment
            return(_buffer.Slice(position, bytesLength));
        }