private bool TryUseRecentTransactionPage(Slice key, out TreeCursorConstructor cursor, out TreePage page, out TreeNodeHeader *node) { var foundPage = _recentlyFoundPages?.Find(key); if (foundPage == null) { page = null; node = null; cursor = default(TreeCursorConstructor); return(false); } var lastFoundPageNumber = foundPage.Number; if (foundPage.Page != null) { // we can't share the same instance, Page instance may be modified by // concurrently run iterators page = new TreePage(foundPage.Page.Base, foundPage.Page.PageSize); } else { page = GetReadOnlyTreePage(lastFoundPageNumber); } if (page.IsLeaf == false) { VoronUnrecoverableErrorException.Raise(_llt.Environment, "Index points to a non leaf page"); } node = page.Search(_llt, key); // will set the LastSearchPosition cursor = new TreeCursorConstructor(_llt, this, page, foundPage.CursorPath, lastFoundPageNumber); return(true); }
private void DeleteOnCompressedPage(TreePage page, Slice keyToDelete, ref TreeCursorConstructor cursorConstructor) { var tombstoneNodeSize = page.GetRequiredSpace(keyToDelete, 0); page = ModifyPage(page); if (page.HasSpaceFor(_llt, tombstoneNodeSize)) { if (page.LastMatch == 0) { RemoveLeafNode(page); } page.AddCompressionTombstoneNode(page.LastSearchPosition, keyToDelete); return; } var decompressed = DecompressPage(page, usage: DecompressionUsage.Write); try { decompressed.Search(_llt, keyToDelete); if (decompressed.LastMatch != 0) { return; } State.NumberOfEntries--; RemoveLeafNode(decompressed); using (var cursor = cursorConstructor.Build(keyToDelete)) { var treeRebalancer = new TreeRebalancer(_llt, this, cursor); var changedPage = (TreePage)decompressed; while (changedPage != null) { changedPage = treeRebalancer.Execute(changedPage); } } page.DebugValidate(this, State.RootPageNumber); } finally { decompressed.CopyToOriginal(_llt, defragRequired: true, wasModified: true, this); } }
internal TreePage FindPageFor(Slice key, out TreeNodeHeader *node, out TreeCursorConstructor cursor, bool allowCompressed = false) { TreePage p; if (TryUseRecentTransactionPage(key, out cursor, out p, out node)) { if (allowCompressed == false && p.IsCompressed) { ThrowOnCompressedPage(p); } return(p); } return(SearchForPage(key, allowCompressed, out cursor, out node)); }
private TreePage SearchForPage(Slice key, bool allowCompressed, out TreeCursorConstructor cursorConstructor, out TreeNodeHeader *node, bool addToRecentlyFoundPages = true) { var p = GetReadOnlyTreePage(State.RootPageNumber); var cursor = new TreeCursor(); cursor.Push(p); bool rightmostPage = true; bool leftmostPage = true; while ((p.TreeFlags & TreePageFlags.Branch) == TreePageFlags.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(_llt, key) != 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 pageNode = p.GetNode(nodePos); p = GetReadOnlyTreePage(pageNode->PageNumber); Debug.Assert(pageNode->PageNumber == p.PageNumber, string.Format("Requested Page: #{0}. Got Page: #{1}", pageNode->PageNumber, p.PageNumber)); cursor.Push(p); } cursorConstructor = new TreeCursorConstructor(cursor); if (p.IsLeaf == false) { VoronUnrecoverableErrorException.Raise(_llt.Environment, "Index points to a non leaf page"); } if (allowCompressed == false && p.IsCompressed) { ThrowOnCompressedPage(p); } node = p.Search(_llt, key); // will set the LastSearchPosition if (p.NumberOfEntries > 0 && addToRecentlyFoundPages) // compressed page can have no ordinary entries { AddToRecentlyFoundPages(cursor, p, leftmostPage, rightmostPage); } return(p); }