/// <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)); }