private void SetNodeKey(NodeHeader *node, ref PrefixedSlice slice) { if (node->KeySize == 0) { slice = PrefixedSlice.Empty; return; } if (slice != null && slice != PrefixedSlice.Empty) { slice.Set(node); } else { slice = new PrefixedSlice(node); } if (slice.Header.PrefixId == PrefixedSlice.NonPrefixedId) { Debug.Assert(slice.Header.PrefixUsage == 0); return; } Debug.Assert(slice.Header.PrefixId < PrefixCount); if (slice.Prefix == null) { slice.Prefix = new PrefixNode(); } AssertPrefixNode(slice.Header.PrefixId); slice.Prefix.Set(_base + _prefixSection->PrefixOffsets[slice.Header.PrefixId], PageNumber); }
public static int NewPrefix(PrefixedSlice key) { var size = Constants.PrefixNodeHeaderSize + key.NewPrefix.Size; size += size & 1; return size; }
public static int NewPrefix(PrefixedSlice key) { var size = Constants.PrefixNodeHeaderSize + key.NewPrefix.Size; size += size & 1; return(size); }
private bool TryUseExistingPrefix(MemorySlice key, out PrefixedSlice prefixedSlice) { if (_prefixSection->NextPrefixId < 1) { prefixedSlice = null; return(false); } var prefix = new PrefixNode(); BestPrefixMatch bestMatch = null; for (byte prefixId = 0; prefixId < _prefixSection->NextPrefixId; prefixId++) { AssertPrefixNode(prefixId); prefix.Set(_base + _prefixSection->PrefixOffsets[prefixId], PageNumber); var length = key.FindPrefixSize(new Slice(prefix.ValuePtr, prefix.PrefixLength)); if (length == 0) { continue; } if (length == prefix.PrefixLength) // full prefix usage { prefixedSlice = new PrefixedSlice(prefixId, length, key.Skip(length)); return(true); } // keep on looking for a better prefix if (bestMatch == null) { bestMatch = new BestPrefixMatch { PrefixId = prefixId, PrefixUsage = length }; } else if (length > bestMatch.PrefixUsage) { bestMatch.PrefixId = prefixId; bestMatch.PrefixUsage = length; } } if (bestMatch != null && bestMatch.PrefixUsage > MinPrefixLength(key)) { prefixedSlice = new PrefixedSlice(bestMatch.PrefixId, bestMatch.PrefixUsage, key.Skip(bestMatch.PrefixUsage)); return(true); } prefixedSlice = null; return(false); }
public MemorySlice GetNodeKey(NodeHeader *node) { if (KeysPrefixed == false) { var keySize = node->KeySize; var key = new byte[keySize]; fixed(byte *ptr = key) MemoryUtils.CopyInline(ptr, (byte *)node + Constants.NodeHeaderSize, keySize); return(new Slice(key)); } if (node->KeySize == 0) { return(new PrefixedSlice(Slice.Empty)); } var prefixHeader = (PrefixedSliceHeader *)((byte *)node + Constants.NodeHeaderSize); var nonPrefixedSize = prefixHeader->NonPrefixedDataSize; var nonPrefixedData = new byte[nonPrefixedSize]; fixed(byte *ptr = nonPrefixedData) MemoryUtils.CopyInline(ptr, (byte *)prefixHeader + Constants.PrefixedSliceHeaderSize, nonPrefixedSize); var prefixedSlice = new PrefixedSlice(prefixHeader->PrefixId, prefixHeader->PrefixUsage, new Slice(nonPrefixedData)); if (prefixHeader->PrefixId == PrefixedSlice.NonPrefixedId) { return(prefixedSlice); } AssertPrefixNode(prefixedSlice.Header.PrefixId); var prefixNodePtr = (PrefixNodeHeader *)(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId]); var prefixLength = prefixNodePtr->PrefixLength; var prefixData = new byte[prefixLength]; fixed(byte *ptr = prefixData) MemoryUtils.CopyInline(ptr, (byte *)prefixNodePtr + Constants.PrefixNodeHeaderSize, prefixLength); prefixedSlice.Prefix = new PrefixNode(new PrefixNodeHeader { PrefixLength = prefixLength }, prefixData, PageNumber); return(prefixedSlice); }
private void MultiAddOnNewValue(Transaction tx, Slice key, Slice value, ushort?version, int maxNodeSize) { MemorySlice valueToInsert; if (KeysPrefixing) { valueToInsert = new PrefixedSlice(value); // first item is never prefixed } else { valueToInsert = value; } var requiredPageSize = Constants.PageHeaderSize + // header of a nested page Constants.NodeOffsetSize + // one node in a nested page SizeOf.LeafEntry(-1, value, 0); // node header and its value if (requiredPageSize + Constants.NodeHeaderSize > maxNodeSize) { // no choice, very big value, we might as well just put it in its own tree from the get go... // otherwise, we would have to put this in overflow page, and that won't save us any space anyway var tree = Create(tx, KeysPrefixing, TreeFlags.MultiValue); tree.DirectAdd(value, 0); tx.AddMultiValueTree(this, key, tree); DirectAdd(key, sizeof(TreeRootHeader), NodeFlags.MultiValuePageRef); return; } var actualPageSize = (ushort)Math.Min(Utils.NearestPowerOfTwo(requiredPageSize), maxNodeSize - Constants.NodeHeaderSize); var ptr = DirectAdd(key, actualPageSize); var nestedPage = new Page(ptr, "multi tree", actualPageSize) { PageNumber = -1L,// hint that this is an inner page Lower = (ushort)Constants.PageHeaderSize, Upper = KeysPrefixing ? (ushort)(actualPageSize - Constants.PrefixInfoSectionSize) : actualPageSize, Flags = KeysPrefixing ? PageFlags.Leaf | PageFlags.KeysPrefixed : PageFlags.Leaf, }; nestedPage.ClearPrefixInfo(); CheckConcurrency(key, value, version, 0, TreeActionType.Add); nestedPage.AddDataNode(0, valueToInsert, 0, 0); }
public void SetNodeKey(NodeHeader *node, ref MemorySlice sliceInstance) { if (KeysPrefixed == false) { sliceInstance.Set(node); return; } if (node->KeySize == 0) { sliceInstance = PrefixedSlice.Empty; return; } PrefixedSlice prefixedSlice; if (sliceInstance != null && sliceInstance != PrefixedSlice.Empty) { sliceInstance.Set(node); prefixedSlice = (PrefixedSlice)sliceInstance; } else { sliceInstance = prefixedSlice = new PrefixedSlice(node); } if (prefixedSlice.Header.PrefixId == PrefixedSlice.NonPrefixedId) { Debug.Assert(prefixedSlice.Header.PrefixUsage == 0); return; } Debug.Assert(prefixedSlice.Header.PrefixId < PrefixCount); if (prefixedSlice.Prefix == null) { prefixedSlice.Prefix = new PrefixNode(); } AssertPrefixNode(prefixedSlice.Header.PrefixId); prefixedSlice.Prefix.Set(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId], PageNumber); }
private void MultiAddOnNewValue(Transaction tx, Slice key, Slice value, ushort? version, int maxNodeSize) { MemorySlice valueToInsert; if(KeysPrefixing) valueToInsert = new PrefixedSlice(value); // first item is never prefixed else valueToInsert = value; var requiredPageSize = Constants.PageHeaderSize + SizeOf.LeafEntry(-1, valueToInsert, 0) + Constants.NodeOffsetSize; if (requiredPageSize > maxNodeSize) { // no choice, very big value, we might as well just put it in its own tree from the get go... // otherwise, we would have to put this in overflow page, and that won't save us any space anyway var tree = Create(tx, KeysPrefixing, TreeFlags.MultiValue); tree.DirectAdd(value, 0); tx.AddMultiValueTree(this, key, tree); DirectAdd(key, sizeof (TreeRootHeader), NodeFlags.MultiValuePageRef); return; } var actualPageSize = (ushort) Math.Min(Utils.NearestPowerOfTwo(requiredPageSize), maxNodeSize); var ptr = DirectAdd(key, actualPageSize); var nestedPage = new Page(ptr, "multi tree", actualPageSize) { PageNumber = -1L,// hint that this is an inner page Lower = (ushort) Constants.PageHeaderSize, Upper = KeysPrefixing ? (ushort)(actualPageSize - Constants.PrefixInfoSectionSize) : actualPageSize, Flags = KeysPrefixing ? PageFlags.Leaf | PageFlags.KeysPrefixed : PageFlags.Leaf, }; nestedPage.ClearPrefixInfo(); CheckConcurrency(key, value, version, 0, TreeActionType.Add); nestedPage.AddDataNode(0, valueToInsert, 0, 0); }
private bool TryCreateNewPrefix(MemorySlice key, int nodeIndex, out PrefixedSlice prefixedSlice) { if (_prefixSection->NextPrefixId >= PrefixCount || NumberOfEntries == 0) { prefixedSlice = null; return(false); } MemorySlice left; MemorySlice right; if (nodeIndex > 0 && nodeIndex < NumberOfEntries) // middle { left = GetNodeKey(nodeIndex - 1); right = GetNodeKey(nodeIndex); } else if (nodeIndex == 0) // first { left = null; right = GetNodeKey(0); } else if (nodeIndex == NumberOfEntries) // last { left = GetNodeKey(nodeIndex - 1); right = null; } else { throw new NotSupportedException("Invalid node index prefix: " + nodeIndex + ". Number of entries: " + NumberOfEntries); } ushort leftLength = 0; ushort rightLength = 0; if (left != null && left.Size > 0) // not before all keys { leftLength = key.FindPrefixSize(left); } if (right != null) { rightLength = key.FindPrefixSize(right); } var minPrefixLength = MinPrefixLength(key); if (left != null && leftLength > minPrefixLength && leftLength > rightLength) { prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, leftLength, key.Skip(leftLength)) { NewPrefix = new Slice(left.ToSlice(), leftLength) }; return(true); } if (right != null && rightLength > minPrefixLength && rightLength > leftLength) { prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, rightLength, key.Skip(rightLength)) { NewPrefix = new Slice(right.ToSlice(), rightLength) }; return(true); } prefixedSlice = null; return(false); }
public MemorySlice GetNodeKey(NodeHeader* node) { if (KeysPrefixed == false) { var keySize = node->KeySize; var key = new byte[keySize]; fixed (byte* ptr = key) Memory.CopyInline(ptr, (byte*)node + Constants.NodeHeaderSize, keySize); return new Slice(key); } if (node->KeySize == 0) return new PrefixedSlice(Slice.Empty); var prefixHeader = (PrefixedSliceHeader*)((byte*)node + Constants.NodeHeaderSize); var nonPrefixedSize = prefixHeader->NonPrefixedDataSize; var nonPrefixedData = new byte[nonPrefixedSize]; fixed (byte* ptr = nonPrefixedData) Memory.CopyInline(ptr, (byte*)prefixHeader + Constants.PrefixedSliceHeaderSize, nonPrefixedSize); var prefixedSlice = new PrefixedSlice(prefixHeader->PrefixId, prefixHeader->PrefixUsage, new Slice(nonPrefixedData)); if (prefixHeader->PrefixId == PrefixedSlice.NonPrefixedId) return prefixedSlice; AssertPrefixNode(prefixedSlice.Header.PrefixId); var prefixNodePtr = (PrefixNodeHeader*) (_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId]); var prefixLength = prefixNodePtr->PrefixLength; var prefixData = new byte[prefixLength]; fixed (byte* ptr = prefixData) Memory.CopyInline(ptr, (byte*)prefixNodePtr + Constants.PrefixNodeHeaderSize, prefixLength); prefixedSlice.Prefix = new PrefixNode(new PrefixNodeHeader{ PrefixLength = prefixLength }, prefixData, PageNumber); return prefixedSlice; }
private bool TryCreateNewPrefix(MemorySlice key, int nodeIndex, out PrefixedSlice prefixedSlice) { if (_prefixSection->NextPrefixId >= PrefixCount || NumberOfEntries == 0) { prefixedSlice = null; return false; } MemorySlice left; MemorySlice right; if (nodeIndex > 0 && nodeIndex < NumberOfEntries) // middle { left = GetNodeKey(nodeIndex - 1); right = GetNodeKey(nodeIndex); } else if (nodeIndex == 0) // first { left = null; right = GetNodeKey(0); } else if (nodeIndex == NumberOfEntries) // last { left = GetNodeKey(nodeIndex - 1); right = null; } else throw new NotSupportedException("Invalid node index prefix: " + nodeIndex + ". Number of entries: " + NumberOfEntries); ushort leftLength = 0; ushort rightLength = 0; if (left != null && left.Size > 0) // not before all keys leftLength = key.FindPrefixSize(left); if (right != null) rightLength = key.FindPrefixSize(right); var minPrefixLength = MinPrefixLength(key); if (left != null && leftLength > minPrefixLength && leftLength > rightLength) { prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, leftLength, key.Skip(leftLength)) { NewPrefix = new Slice(left.ToSlice(), leftLength) }; return true; } if (right != null && rightLength > minPrefixLength && rightLength > leftLength) { prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, rightLength, key.Skip(rightLength)) { NewPrefix = new Slice(right.ToSlice(), rightLength) }; return true; } prefixedSlice = null; return false; }
private int AdjustSplitPosition(int currentIndex, int splitIndex, ref bool newPosition) { MemorySlice keyToInsert; if (_tree.KeysPrefixing) keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space else keyToInsert = _newKey; var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize; if(_tree.KeysPrefixing) pageSize += (Constants.PrefixNodeHeaderSize + 1); // let's assume that prefix will be created to ensure the destination page will have enough space, + 1 because prefix node might require 2-byte alignment if (currentIndex <= splitIndex) { newPosition = false; for (int i = 0; i < splitIndex; i++) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) newPosition = true; return currentIndex; } return (ushort) i; } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { newPosition = false; return currentIndex; } return (ushort) (i + 1); } } } return splitIndex; }
/// <summary> /// For leaf pages, check the split point based on what /// fits where, since otherwise adding the node can fail. /// This check is only needed when the data items are /// relatively large, such that being off by one will /// make the difference between success or failure. /// It's also relevant if a page happens to be laid out /// such that one half of its nodes are all "small" and /// the other half of its nodes are "large." If the new /// item is also "large" and falls on the half with /// "large" nodes, it also may not fit. /// </summary> private int AdjustSplitPosition(int currentIndex, int splitIndex, ref bool newPosition) { MemorySlice keyToInsert; if (_tree.KeysPrefixing) { keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space } else { keyToInsert = _newKey; } int nodeSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize; if (_page.NumberOfEntries >= 20 && nodeSize <= AbstractPager.PageMaxSpace / 16) { return(splitIndex); } int pageSize = nodeSize; if (_tree.KeysPrefixing) { pageSize += (Constants.PrefixNodeHeaderSize + 1); // let's assume that prefix will be created to ensure the destination page will have enough space, + 1 because prefix node might require 2-byte alignment } if (currentIndex <= splitIndex) { newPosition = false; for (int i = 0; i < splitIndex; i++) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) { newPosition = true; } return(currentIndex); } return((ushort)i); } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { newPosition = false; return(currentIndex); } return((ushort)(i + 1)); } } } return(splitIndex); }
private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool toRight) { MemorySlice keyToInsert; int pageSize = 0; if (_tree.KeysPrefixing) { keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't match any of the existing prefixes pageSize += Constants.PrefixInfoSectionSize; pageSize += Constants.PrefixNodeHeaderSize + 1; // possible new prefix, + 1 because of possible 2-byte alignment } else keyToInsert = _newKey; pageSize += SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize; if (prefixes != null) { // we are going to copy all existing prefixes so we need to take into account their sizes for (var i = 0; i < prefixes.Length; i++) { var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength; pageSize += prefixNodeSize + (prefixNodeSize & 1); // & 1 because we need 2-byte alignment } } if (toRight == false) { for (int i = 0; i < splitIndex; i++) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) toRight = true; return currentIndex; } return i; } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { toRight = false; return currentIndex; } return i + 1; } } } return splitIndex; }
public void SetNodeKey(NodeHeader* node, ref MemorySlice sliceInstance) { if (KeysPrefixed == false) { sliceInstance.Set(node); return; } if (node->KeySize == 0) { sliceInstance = PrefixedSlice.Empty; return; } PrefixedSlice prefixedSlice; if (sliceInstance != null && sliceInstance != PrefixedSlice.Empty) { sliceInstance.Set(node); prefixedSlice = (PrefixedSlice)sliceInstance; } else sliceInstance = prefixedSlice = new PrefixedSlice(node); if (prefixedSlice.Header.PrefixId == PrefixedSlice.NonPrefixedId) { Debug.Assert(prefixedSlice.Header.PrefixUsage == 0); return; } Debug.Assert(prefixedSlice.Header.PrefixId < PrefixCount); if (prefixedSlice.Prefix == null) prefixedSlice.Prefix = new PrefixNode(); AssertPrefixNode(prefixedSlice.Header.PrefixId); prefixedSlice.Prefix.Set(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId], PageNumber); }
private void MoveBranchNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch); var originalFromKey = to.PrepareKeyToInsert(GetActualKey(from, from.LastSearchPositionOrLastEntry), to.LastSearchPosition); to.EnsureHasSpaceFor(_tx, originalFromKey, -1); var fromNode = from.GetNode(from.LastSearchPosition); long pageNum = fromNode->PageNumber; if (to.LastSearchPosition == 0) { // cannot add to left implicit side, adjust by moving the left node // to the right by one, then adding the new one as the left NodeHeader* actualKeyNode; var implicitLeftKey = GetActualKey(to, 0, out actualKeyNode); var implicitLeftNode = to.GetNode(0); var leftPageNumber = implicitLeftNode->PageNumber; MemorySlice implicitLeftKeyToInsert; if (implicitLeftNode == actualKeyNode) { // no need to create a prefix, just use the existing prefixed key from the node // this also prevents from creating a prefix which is the full key given in 'implicitLeftKey' if (_tree.KeysPrefixing) implicitLeftKeyToInsert = new PrefixedSlice(actualKeyNode); else implicitLeftKeyToInsert = new Slice(actualKeyNode); } else implicitLeftKeyToInsert = to.PrepareKeyToInsert(implicitLeftKey, 1); to.EnsureHasSpaceFor(_tx, implicitLeftKeyToInsert, -1); to.AddPageRefNode(1, implicitLeftKeyToInsert, leftPageNumber); to.ChangeImplicitRefPageNode(pageNum); // setup the new implicit node } else { to.AddPageRefNode(to.LastSearchPosition, originalFromKey, pageNum); } if (from.LastSearchPositionOrLastEntry == 0) { var rightPageNumber = from.GetNode(1)->PageNumber; from.RemoveNode(0); // remove the original implicit node from.ChangeImplicitRefPageNode(rightPageNumber); // setup the new implicit node Debug.Assert(from.NumberOfEntries >= 2); } else { from.RemoveNode(from.LastSearchPositionOrLastEntry); } var pos = parentPage.LastSearchPositionOrLastEntry; parentPage.RemoveNode(pos); var newSeparatorKey = GetActualKey(to, 0); // get the next smallest key it has now var pageNumber = to.PageNumber; if (parentPage.GetNode(0)->PageNumber == to.PageNumber) { pageNumber = from.PageNumber; newSeparatorKey = GetActualKey(from, 0); } AddSeparatorToParentPage(parentPage, pageNumber, newSeparatorKey, pos); }
private bool TryUseExistingPrefix(MemorySlice key, out PrefixedSlice prefixedSlice) { if (_prefixSection->NextPrefixId < 1) { prefixedSlice = null; return false; } BestPrefixMatch bestMatch = null; for (byte prefixId = 0; prefixId < _prefixSection->NextPrefixId; prefixId++) { AssertPrefixNode(prefixId); var prefix = new PrefixNode(); prefix.Set(_base + _prefixSection->PrefixOffsets[prefixId], PageNumber); var length = key.FindPrefixSize(new Slice(prefix.ValuePtr, prefix.PrefixLength)); if (length == 0) continue; if (length == prefix.PrefixLength) // full prefix usage { prefixedSlice = new PrefixedSlice(prefixId, length, key.Skip(length)) { Prefix = prefix }; return true; } // keep on looking for a better prefix if (bestMatch == null) { bestMatch = new BestPrefixMatch { PrefixId = prefixId, PrefixUsage = length, PrefixNode = prefix }; } else if (length > bestMatch.PrefixUsage) { bestMatch.PrefixId = prefixId; bestMatch.PrefixUsage = length; bestMatch.PrefixNode = prefix; } } if (bestMatch != null && bestMatch.PrefixUsage > MinPrefixLength(key)) { prefixedSlice = new PrefixedSlice(bestMatch.PrefixId, bestMatch.PrefixUsage, key.Skip(bestMatch.PrefixUsage)) { Prefix = bestMatch.PrefixNode }; return true; } prefixedSlice = null; return false; }
private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool newPosition) { MemorySlice keyToInsert; if (_tree.KeysPrefixing) keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space else keyToInsert = _newKey; var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize; if (prefixes != null) { // we are going to copy all existing prefixes so we need to take into account their sizes for (var i = 0; i < prefixes.Length; i++) { pageSize += (Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength) & 1; // & 1 because we need 2-byte alignment } } if (currentIndex <= splitIndex) { newPosition = false; for (int i = 0; i < splitIndex; i++) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) newPosition = true; return currentIndex; } return (ushort) i; } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader* node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { newPosition = false; return currentIndex; } return (ushort) (i + 1); } } } return splitIndex; }
private void SetNodeKey(NodeHeader* node, ref PrefixedSlice slice) { if (node->KeySize == 0) { slice = PrefixedSlice.Empty; return; } if (slice != null && slice != PrefixedSlice.Empty) { slice.Set(node); } else { slice = new PrefixedSlice(node); } if (slice.Header.PrefixId == PrefixedSlice.NonPrefixedId) { Debug.Assert(slice.Header.PrefixUsage == 0); return; } Debug.Assert(slice.Header.PrefixId < PrefixCount); if (slice.Prefix == null) slice.Prefix = new PrefixNode(); AssertPrefixNode(slice.Header.PrefixId); slice.Prefix.Set(_base + _prefixSection->PrefixOffsets[slice.Header.PrefixId], PageNumber); }
private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool toRight) { MemorySlice keyToInsert; int pageSize = 0; if (_tree.KeysPrefixing) { keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't match any of the existing prefixes pageSize += Constants.PrefixInfoSectionSize; pageSize += Constants.PrefixNodeHeaderSize + 1; // possible new prefix, + 1 because of possible 2-byte alignment } else { keyToInsert = _newKey; } pageSize += SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize; if (prefixes != null) { // we are going to copy all existing prefixes so we need to take into account their sizes for (var i = 0; i < prefixes.Length; i++) { var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength; pageSize += prefixNodeSize + (prefixNodeSize & 1); // & 1 because we need 2-byte alignment } } if (toRight == false) { for (int i = 0; i < splitIndex; i++) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) { toRight = true; } return(currentIndex); } return(i); } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { toRight = false; return(currentIndex); } return(i + 1); } } } return(splitIndex); }
private void MoveBranchNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch); var originalFromKey = to.PrepareKeyToInsert(GetActualKey(from, from.LastSearchPositionOrLastEntry), to.LastSearchPosition); to.EnsureHasSpaceFor(_tx, originalFromKey, -1); var fromNode = from.GetNode(from.LastSearchPosition); long pageNum = fromNode->PageNumber; if (to.LastSearchPosition == 0) { // cannot add to left implicit side, adjust by moving the left node // to the right by one, then adding the new one as the left NodeHeader *actualKeyNode; var implicitLeftKey = GetActualKey(to, 0, out actualKeyNode); var implicitLeftNode = to.GetNode(0); var leftPageNumber = implicitLeftNode->PageNumber; MemorySlice implicitLeftKeyToInsert; if (implicitLeftNode == actualKeyNode) { // no need to create a prefix, just use the existing prefixed key from the node // this also prevents from creating a prefix which is the full key given in 'implicitLeftKey' if (_tree.KeysPrefixing) { implicitLeftKeyToInsert = new PrefixedSlice(actualKeyNode); } else { implicitLeftKeyToInsert = new Slice(actualKeyNode); } } else { implicitLeftKeyToInsert = to.PrepareKeyToInsert(implicitLeftKey, 1); } to.EnsureHasSpaceFor(_tx, implicitLeftKeyToInsert, -1); to.AddPageRefNode(1, implicitLeftKeyToInsert, leftPageNumber); to.ChangeImplicitRefPageNode(pageNum); // setup the new implicit node } else { to.AddPageRefNode(to.LastSearchPosition, originalFromKey, pageNum); } if (from.LastSearchPositionOrLastEntry == 0) { var rightPageNumber = from.GetNode(1)->PageNumber; from.RemoveNode(0); // remove the original implicit node from.ChangeImplicitRefPageNode(rightPageNumber); // setup the new implicit node Debug.Assert(from.NumberOfEntries >= 2); } else { from.RemoveNode(from.LastSearchPositionOrLastEntry); } var pos = parentPage.LastSearchPositionOrLastEntry; parentPage.RemoveNode(pos); var newSeparatorKey = GetActualKey(to, 0); // get the next smallest key it has now var pageNumber = to.PageNumber; if (parentPage.GetNode(0)->PageNumber == to.PageNumber) { pageNumber = from.PageNumber; newSeparatorKey = GetActualKey(from, 0); } AddSeparatorToParentPage(parentPage, pageNumber, newSeparatorKey, pos); }
private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool newPosition) { MemorySlice keyToInsert; if (_tree.KeysPrefixing) { keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space } else { keyToInsert = _newKey; } var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize; if (prefixes != null) { // we are going to copy all existing prefixes so we need to take into account their sizes for (var i = 0; i < prefixes.Length; i++) { pageSize += (Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength) & 1; // & 1 because we need 2-byte alignment } } if (currentIndex <= splitIndex) { newPosition = false; for (int i = 0; i < splitIndex; i++) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) { newPosition = true; } return(currentIndex); } return((ushort)i); } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { NodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > AbstractPager.PageMaxSpace) { if (i >= currentIndex) { newPosition = false; return(currentIndex); } return((ushort)(i + 1)); } } } return(splitIndex); }