private byte *SplitPageInHalf(Page rightPage) { var currentIndex = _page.LastSearchPosition; var newPosition = true; var splitIndex = _page.NumberOfEntries / 2; if (currentIndex < splitIndex) { newPosition = false; } if (_page.IsLeaf) { splitIndex = AdjustSplitPosition(_newKey, _len, _page, currentIndex, splitIndex, ref newPosition); } // here we the current key is the separator key and can go either way, so // use newPosition to decide if it stays on the left node or moves to the right Slice seperatorKey; if (currentIndex == splitIndex && newPosition) { seperatorKey = _newKey; } else { var node = _page.GetNode(splitIndex); seperatorKey = new Slice(node); } AddSeperatorToParentPage(rightPage, seperatorKey); // move the actual entries from page to right page var nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { var node = _page.GetNode(i); var itemsMoved = 1; if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, Slice.Empty); itemsMoved = _tx.Pager.Get(_tx, node->PageNumber).ItemCount; } else { rightPage.CopyNodeDataToEndOfPage(node); } rightPage.ItemCount += itemsMoved; _page.ItemCount -= itemsMoved; } _page.Truncate(_tx, splitIndex); byte *dataPos; // actually insert the new key return((currentIndex > splitIndex || newPosition && currentIndex == splitIndex) ? InsertNewKey(rightPage) : InsertNewKey(_page)); }
private byte *SplitPageInHalf(Page rightPage) { int currentIndex = _page.LastSearchPosition; bool newPosition = true; int splitIndex = _page.NumberOfEntries / 2; if (currentIndex < splitIndex) { newPosition = false; } if (_page.IsLeaf) { splitIndex = AdjustSplitPosition(currentIndex, splitIndex, ref newPosition); } var currentKey = _page.GetNodeKey(splitIndex); // here the current key is the separator key and can go either way, so // use newPosition to decide if it stays on the left node or moves to the right MemorySlice seperatorKey; if (currentIndex == splitIndex && newPosition) { seperatorKey = currentKey.Compare(_newKey) < 0 ? currentKey : _newKey; } else { seperatorKey = currentKey; } AddSeparatorToParentPage(rightPage.PageNumber, seperatorKey); MemorySlice instance = _page.CreateNewEmptyKey(); // move the actual entries from page to right page ushort nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { NodeHeader *node = _page.GetNode(i); if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); } else { _page.SetNodeKey(node, ref instance); var key = rightPage.PrepareKeyToInsert(instance, rightPage.NumberOfEntries); rightPage.CopyNodeDataToEndOfPage(node, key); } } _page.Truncate(_tx, splitIndex); // actually insert the new key return((currentIndex > splitIndex || newPosition && currentIndex == splitIndex) ? InsertNewKey(rightPage) : InsertNewKey(_page)); }
private byte *SplitPageInHalf(Page rightPage) { int currentIndex = _page.LastSearchPosition; bool newPosition = true; int splitIndex = _page.NumberOfEntries / 2; if (currentIndex < splitIndex) { newPosition = false; } if (_page.IsLeaf) { splitIndex = AdjustSplitPosition(_newKey, _len, _page, currentIndex, splitIndex, ref newPosition); } NodeHeader *currentNode = _page.GetNode(splitIndex); var currentKey = new Slice(currentNode); // here we the current key is the separator key and can go either way, so // use newPosition to decide if it stays on the left node or moves to the right Slice seperatorKey; if (currentIndex == splitIndex && newPosition) { seperatorKey = currentKey.Compare(_newKey) < 0 ? currentKey : _newKey; } else { seperatorKey = currentKey; } AddSeparatorToParentPage(rightPage, seperatorKey); // move the actual entries from page to right page ushort nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { NodeHeader *node = _page.GetNode(i); if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, Slice.Empty); } else { rightPage.CopyNodeDataToEndOfPage(node); } } _page.Truncate(_tx, splitIndex); // actually insert the new key return((currentIndex > splitIndex || newPosition && currentIndex == splitIndex) ? InsertNewKey(rightPage) : InsertNewKey(_page)); }
private byte *SplitPageInHalf(Page rightPage) { bool toRight; var currentIndex = _page.LastSearchPosition; var splitIndex = _page.NumberOfEntries / 2; if (currentIndex <= splitIndex) { toRight = false; } else { toRight = true; var leftPageEntryCount = splitIndex; var rightPageEntryCount = _page.NumberOfEntries - leftPageEntryCount + 1; if (rightPageEntryCount > leftPageEntryCount) { splitIndex++; Debug.Assert(splitIndex < _page.NumberOfEntries); } } PrefixNode[] prefixes = null; if (_tree.KeysPrefixing && _page.HasPrefixes) { prefixes = _page.GetPrefixes(); } if (_page.IsLeaf || prefixes != null) { splitIndex = AdjustSplitPosition(currentIndex, splitIndex, prefixes, ref toRight); } var currentKey = _page.GetNodeKey(splitIndex); MemorySlice seperatorKey; if (toRight && splitIndex == currentIndex) { seperatorKey = currentKey.Compare(_newKey) < 0 ? currentKey : _newKey; } else { seperatorKey = currentKey; } Page parentOfRight; AddSeparatorToParentPage(rightPage.PageNumber, seperatorKey, out parentOfRight); var parentOfPage = _cursor.CurrentPage; MemorySlice instance = _page.CreateNewEmptyKey(); if (prefixes != null) { for (int i = 0; i < prefixes.Length; i++) { var prefix = prefixes[i]; rightPage.WritePrefix(new Slice(prefix.ValuePtr, prefix.PrefixLength), i); } } bool addedAsImplicitRef = false; if (_page.IsBranch && toRight && seperatorKey == _newKey) { // _newKey needs to be inserted as first key (BeforeAllKeys) to the right page, so we need to add it before we move entries from the current page AddNodeToPage(rightPage, 0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); addedAsImplicitRef = true; } // move the actual entries from page to right page ushort nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { NodeHeader *node = _page.GetNode(i); if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); } else { _page.SetNodeKey(node, ref instance); var key = rightPage.PrepareKeyToInsert(instance, rightPage.NumberOfEntries); rightPage.CopyNodeDataToEndOfPage(node, key); } } _page.Truncate(_tx, splitIndex); byte *pos; if (addedAsImplicitRef == false) { try { if (toRight && _cursor.CurrentPage.PageNumber != parentOfRight.PageNumber) { // modify the cursor if we are going to insert to the right page _cursor.Pop(); _cursor.Push(parentOfRight); } // actually insert the new key pos = toRight ? InsertNewKey(rightPage) : InsertNewKey(_page); } catch (InvalidOperationException e) { if (e.Message.StartsWith("The page is full and cannot add an entry") == false) { throw; } throw new InvalidOperationException(GatherDetailedDebugInfo(rightPage, currentKey, seperatorKey, currentIndex, splitIndex, toRight), e); } } else { pos = null; _cursor.Push(rightPage); } if (_page.IsBranch) // remove a branch that has only one entry, the page ref needs to be added to the parent of the current page { Debug.Assert(_page.NumberOfEntries > 0); Debug.Assert(rightPage.NumberOfEntries > 0); if (_page.NumberOfEntries == 1) { RemoveBranchWithOneEntry(_page, parentOfPage); } if (rightPage.NumberOfEntries == 1) { RemoveBranchWithOneEntry(rightPage, parentOfRight); } } return(pos); }
private byte *SplitPageInHalf(Page rightPage) { int currentIndex = _page.LastSearchPosition; bool newPosition = true; int splitIndex = _page.NumberOfEntries / 2; if (currentIndex < splitIndex) { newPosition = false; } PrefixNode[] prefixes = null; if (_tree.KeysPrefixing && _page.HasPrefixes) { prefixes = _page.GetPrefixes(); } if (_page.IsLeaf || prefixes != null) { splitIndex = AdjustSplitPosition(currentIndex, splitIndex, prefixes, ref newPosition); } var currentKey = _page.GetNodeKey(splitIndex); // here the current key is the separator key and can go either way, so // use newPosition to decide if it stays on the left node or moves to the right MemorySlice seperatorKey; if (currentIndex == splitIndex && newPosition) { seperatorKey = currentKey.Compare(_newKey) < 0 ? currentKey : _newKey; } else { seperatorKey = currentKey; } AddSeparatorToParentPage(rightPage.PageNumber, seperatorKey); MemorySlice instance = _page.CreateNewEmptyKey(); if (prefixes != null) { for (int i = 0; i < prefixes.Length; i++) { var prefix = prefixes[i]; rightPage.WritePrefix(new Slice(prefix.ValuePtr, prefix.PrefixLength), i); } } // move the actual entries from page to right page ushort nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { NodeHeader *node = _page.GetNode(i); if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); } else { _page.SetNodeKey(node, ref instance); var key = rightPage.PrepareKeyToInsert(instance, rightPage.NumberOfEntries); rightPage.CopyNodeDataToEndOfPage(node, key); } } _page.Truncate(_tx, splitIndex); // actually insert the new key try { return((currentIndex > splitIndex || newPosition && currentIndex == splitIndex) ? InsertNewKey(rightPage) : InsertNewKey(_page)); } catch (InvalidOperationException e) { if (e.Message.StartsWith("The page is full and cannot add an entry")) { var debugInfo = new StringBuilder(); debugInfo.AppendFormat("\r\n_tree.Name: {0}\r\n", _tree.Name); debugInfo.AppendFormat("_newKey: {0}, _len: {1}, needed space: {2}\r\n", _newKey, _len, _page.GetRequiredSpace(_newKey, _len)); debugInfo.AppendFormat("currentKey: {0}, seperatorKey: {1}\r\n", currentKey, seperatorKey); debugInfo.AppendFormat("currentIndex: {0}\r\n", currentIndex); debugInfo.AppendFormat("splitIndex: {0}\r\n", splitIndex); debugInfo.AppendFormat("newPosition: {0}\r\n", newPosition); debugInfo.AppendFormat("_page info: flags - {0}, # of entries {1}, size left: {2}, calculated size left: {3}\r\n", _page.Flags, _page.NumberOfEntries, _page.SizeLeft, _page.CalcSizeLeft()); for (int i = 0; i < _page.NumberOfEntries; i++) { var node = _page.GetNode(i); var key = _page.GetNodeKey(node); debugInfo.AppendFormat("{0} - {2} {1}\r\n", key, node->DataSize, node->Flags == NodeFlags.Data ? "Size" : "Page"); } debugInfo.AppendFormat("rightPage info: flags - {0}, # of entries {1}, size left: {2}, calculated size left: {3}\r\n", rightPage.Flags, rightPage.NumberOfEntries, rightPage.SizeLeft, rightPage.CalcSizeLeft()); for (int i = 0; i < rightPage.NumberOfEntries; i++) { var node = rightPage.GetNode(i); var key = rightPage.GetNodeKey(node); debugInfo.AppendFormat("{0} - {2} {1}\r\n", key, node->DataSize, node->Flags == NodeFlags.Data ? "Size" : "Page"); } throw new InvalidOperationException(debugInfo.ToString(), e); } throw; } }