public PageSplitter(Transaction tx, Tree tree, SliceComparer cmp, Slice newKey, int len, long pageNumber, NodeFlags nodeType, ushort nodeVersion, Cursor cursor, TreeMutableState treeState) { _tx = tx; _tree = tree; _cmp = cmp; _newKey = newKey; _len = len; _pageNumber = pageNumber; _nodeType = nodeType; _nodeVersion = nodeVersion; _cursor = cursor; _treeState = treeState; Page page = _cursor.Pages.First.Value; _page = tx.ModifyPage(page.PageNumber, page); _cursor.Pop(); }
public ParentPageAction(Page parentPage, Page currentPage, Tree tree, Cursor cursor, Transaction tx) { _parentPage = parentPage; _currentPage = currentPage; _tree = tree; _cursor = cursor; _tx = tx; }
public bool Seek(Slice key) { Lazy<Cursor> lazy; _currentPage = _tree.FindPageFor(_tx, key, out lazy); _cursor = lazy.Value; _cursor.Pop(); var node = _currentPage.Search(key, _cmp); if (node == null) { return false; } _currentKey.Set(node); return this.ValidateCurrentKey(Current, _cmp); }
public bool Seek(Slice key) { Lazy<Cursor> lazy; _currentPage = _tree.FindPageFor(key, out lazy); _cursor = lazy.Value; _cursor.Pop(); var node = _currentPage.Search(key); if (node != null) { _currentKey.Set(node); return this.ValidateCurrentKey(Current); } // The key is not found in the db, but we are Seek()ing for equals or starts with. // We know that the exact value isn't there, but it is possible that the next page has values // that is actually greater than the key, so we need to check it as well. _currentPage.LastSearchPosition = _currentPage.NumberOfEntries; // force next MoveNext to move to the next _page_. return MoveNext(); }
public TreeRebalancer(Transaction tx, Tree tree, Cursor cursor) { _tx = tx; _tree = tree; _cursor = cursor; }
private bool TryUseRecentTransactionPage(Transaction tx, Slice key, out Lazy<Cursor> cursor, out Page page) { page = null; cursor = null; var recentPages = tx.GetRecentlyFoundPages(this); if (recentPages == null) return false; var foundPage = recentPages.Find(key); if (foundPage == null) return false; var lastFoundPageNumber = foundPage.Number; page = tx.GetReadOnlyPage(lastFoundPageNumber); if (page.IsLeaf == false) throw new DataException("Index points to a non leaf page"); page.NodePositionFor(key, _cmp); // will set the LastSearchPosition var cursorPath = foundPage.CursorPath; var pageCopy = page; cursor = new Lazy<Cursor>(() => { var c = new Cursor(); foreach (var p in cursorPath) { if (p == lastFoundPageNumber) c.Push(pageCopy); else { var cursorPage = tx.GetReadOnlyPage(p); if (key.Options == SliceOptions.BeforeAllKeys) { cursorPage.LastSearchPosition = 0; } else if (key.Options == SliceOptions.AfterAllKeys) { cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1); } else if (cursorPage.Search(key, _cmp) != null) { if (cursorPage.LastMatch != 0) { cursorPage.LastSearchPosition--; } } c.Push(cursorPage); } } return c; }); return true; }
private void AddToRecentlyFoundPages(Transaction tx, Cursor c, Page p, bool? leftmostPage, bool? rightmostPage) { var foundPage = new RecentlyFoundPages.FoundPage(c.Pages.Count) { Number = p.PageNumber, FirstKey = leftmostPage == true ? Slice.BeforeAllKeys : p.GetNodeKey(0), LastKey = rightmostPage == true ? Slice.AfterAllKeys : p.GetNodeKey(p.NumberOfEntries - 1), }; var cur = c.Pages.First; int pos = foundPage.CursorPath.Length - 1; while (cur != null) { foundPage.CursorPath[pos--] = cur.Value.PageNumber; cur = cur.Next; } tx.AddRecentlyFoundPage(this, foundPage); }
private Page SearchForPage(Transaction tx, Slice key, ref Lazy<Cursor> cursor) { var p = tx.GetReadOnlyPage(State.RootPageNumber); var c = new Cursor(); c.Push(p); bool rightmostPage = true; bool leftmostPage = true; while (p.Flags == (PageFlags.Branch)) { int nodePos; if (key.Options == SliceOptions.BeforeAllKeys) { p.LastSearchPosition = nodePos = 0; rightmostPage = false; } else if (key.Options == SliceOptions.AfterAllKeys) { p.LastSearchPosition = nodePos = (ushort) (p.NumberOfEntries - 1); leftmostPage = false; } else { if (p.Search(key, _cmp) != null) { nodePos = p.LastSearchPosition; if (p.LastMatch != 0) { nodePos--; p.LastSearchPosition--; } if (nodePos != 0) leftmostPage = false; rightmostPage = false; } else { nodePos = (ushort) (p.LastSearchPosition - 1); leftmostPage = false; } } var node = p.GetNode(nodePos); p = tx.GetReadOnlyPage(node->PageNumber); Debug.Assert(node->PageNumber == p.PageNumber, string.Format("Requested Page: #{0}. Got Page: #{1}", node->PageNumber, p.PageNumber)); c.Push(p); } if (p.IsLeaf == false) throw new DataException("Index points to a non leaf page"); p.Search(key, _cmp); // will set the LastSearchPosition AddToRecentlyFoundPages(tx, c, p, leftmostPage, rightmostPage); cursor = new Lazy<Cursor>(() => c); return p; }
private void AddToRecentlyFoundPages(Cursor c, Page p, bool? leftmostPage, bool? rightmostPage) { var foundPage = new RecentlyFoundPages.FoundPage(c.Pages.Count) { Number = p.PageNumber }; if (leftmostPage == true) { if(p.KeysPrefixed) foundPage.FirstKey = PrefixedSlice.BeforeAllKeys; else foundPage.FirstKey = Slice.BeforeAllKeys; } else { foundPage.FirstKey = p.GetNodeKey(0); } if (rightmostPage == true) { if (p.KeysPrefixed) foundPage.LastKey = PrefixedSlice.AfterAllKeys; else foundPage.LastKey = Slice.AfterAllKeys; } else { foundPage.LastKey = p.GetNodeKey(p.NumberOfEntries - 1); } var cur = c.Pages.First; int pos = foundPage.CursorPath.Length - 1; while (cur != null) { foundPage.CursorPath[pos--] = cur.Value.PageNumber; cur = cur.Next; } _tx.AddRecentlyFoundPage(this, foundPage); }
private void RebalanceRoot(Cursor cursor, Page page) { if (page.NumberOfEntries == 0) return; // nothing to do if (!page.IsBranch || page.NumberOfEntries > 1) { return; // cannot do anything here } // in this case, we have a root pointer with just one pointer, we can just swap it out var node = page.GetNode(0); Debug.Assert(node->Flags == (NodeFlags.PageRef)); _tree.State.LeafPages = 1; _tree.State.BranchPages = 0; _tree.State.Depth = 1; _tree.State.PageCount = 1; var rootPage = _tx.ModifyPage(node->PageNumber, null); _tree.State.RootPageNumber = rootPage.PageNumber; Debug.Assert(rootPage.Dirty); cursor.Pop(); cursor.Push(rootPage); _tx.FreePage(page.PageNumber); }
public Page Execute(Cursor cursor, Page page) { _tx.ClearRecentFoundPages(_tree); if (cursor.PageCount <= 1) // the root page { RebalanceRoot(cursor, page); return null; } var parentPage = _tx.ModifyPage(cursor.ParentPage.PageNumber, cursor.ParentPage); cursor.Update(cursor.Pages.First.Next, parentPage); if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to delete the implicit left page, shift right if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.RemoveNode(0); parentPage.RemoveNode(0); parentPage.AddPageRefNode(0, Slice.Empty, newImplicit); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry); } _tx.FreePage(page.PageNumber); cursor.Pop(); return parentPage; } var minKeys = page.IsBranch ? 2 : 1; if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) && page.NumberOfEntries >= minKeys) return null; // above space/keys thresholds Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(cursor, page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) && sibling.NumberOfEntries > minKeys) { // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else MoveLeafNode(parentPage, sibling, page); cursor.Pop(); return parentPage; } if (page.LastSearchPosition == 0) // this is the right page, merge left { if (!HasEnoughSpaceToCopyNodes(sibling, page)) return null; MergePages(parentPage, sibling, page); } else // this is the left page, merge right { if (!HasEnoughSpaceToCopyNodes(page, sibling)) return null; MergePages(parentPage, page, sibling); } cursor.Pop(); return parentPage; }
private Page SetupMoveOrMerge(Cursor c, Page page, Page parentPage) { Page sibling; if (parentPage.LastSearchPosition == 0) // we are the left most item { parentPage.LastSearchPosition = 1; sibling = _tx.ModifyPage(parentPage.GetNode(1)->PageNumber, null); parentPage.LastSearchPosition = 0; sibling.LastSearchPosition = 0; page.LastSearchPosition = page.NumberOfEntries; parentPage.LastSearchPosition = 1; } else // there is at least 1 page to our left { var beyondLast = parentPage.LastSearchPosition == parentPage.NumberOfEntries; if (beyondLast) parentPage.LastSearchPosition--; parentPage.LastSearchPosition--; sibling = _tx.ModifyPage(parentPage.GetNode(parentPage.LastSearchPosition)->PageNumber, null); parentPage.LastSearchPosition++; if (beyondLast) parentPage.LastSearchPosition++; sibling.LastSearchPosition = sibling.NumberOfEntries - 1; page.LastSearchPosition = 0; } return sibling; }