public int GetCurrentDataSize() { if (_disposed) { throw new ObjectDisposedException("TreeIterator " + _tree.Name); } return(NodeHeader.GetDataSize(_tx, Current)); }
public int GetDataSize(Slice key) { Lazy <Cursor> lazy; var p = FindPageFor(key, out lazy); var node = p.Search(key); if (node == null || new Slice(node).Compare(key) != 0) { return(-1); } return(NodeHeader.GetDataSize(_tx, node)); }
public int GetDataSize(Slice key) { Lazy <Cursor> lazy; NodeHeader * node; var p = FindPageFor(key, out node, out lazy); if (p == null || p.LastMatch != 0) { return(-1); } Debug.Assert(node != null); return(NodeHeader.GetDataSize(_tx, node)); }
private void EnsureNestedPagePointer(Page page, NodeHeader *currentItem, ref Page nestedPage, ref byte *nestedPagePtr) { var movedItem = page.GetNode(page.LastSearchPosition); if (movedItem == currentItem) { return; } // HasSpaceFor could called Defrag internally and read item has moved // need to ensure the nested page has a valid pointer nestedPagePtr = NodeHeader.DirectAccess(_tx, movedItem); nestedPage = new Page(nestedPagePtr, "multi tree", (ushort)NodeHeader.GetDataSize(_tx, movedItem)); }
public int GetDataSize(Slice key) { Lazy <Cursor> lazy; NodeHeader * node; var p = FindPageFor(key, out node, out lazy); if (p == null || p.LastMatch != 0) { return(-1); } if (node == null || p.GetNodeKey(node).Compare(key) != 0) { return(-1); } return(NodeHeader.GetDataSize(_tx, node)); }
public void MultiAdd(Slice key, Slice value, ushort?version = null) { if (value == null) { throw new ArgumentNullException("value"); } int maxNodeSize = AbstractPager.NodeMaxSize; if (value.Size > maxNodeSize) { throw new ArgumentException( "Cannot add a value to child tree that is over " + maxNodeSize + " bytes in size", "value"); } if (value.Size == 0) { throw new ArgumentException("Cannot add empty value to child tree"); } State.IsModified = true; Lazy <Cursor> lazy; NodeHeader * node; var page = FindPageFor(key, out node, out lazy); if ((page == null || page.LastMatch != 0)) { MultiAddOnNewValue(_tx, key, value, version, maxNodeSize); return; } page = _tx.ModifyPage(page.PageNumber, page); var item = page.GetNode(page.LastSearchPosition); // already was turned into a multi tree, not much to do here if (item->Flags == NodeFlags.MultiValuePageRef) { var existingTree = OpenMultiValueTree(_tx, key, item); existingTree.DirectAdd(value, 0, version: version); return; } byte *nestedPagePtr; if (item->Flags == NodeFlags.PageRef) { var overFlowPage = _tx.ModifyPage(item->PageNumber, null); nestedPagePtr = overFlowPage.Base + Constants.PageHeaderSize; } else { nestedPagePtr = NodeHeader.DirectAccess(_tx, item); } var nestedPage = new Page(nestedPagePtr, "multi tree", (ushort)NodeHeader.GetDataSize(_tx, item)); var existingItem = nestedPage.Search(value); if (nestedPage.LastMatch != 0) { existingItem = null; // not an actual match, just greater than } ushort previousNodeRevision = existingItem != null ? existingItem->Version : (ushort)0; CheckConcurrency(key, value, version, previousNodeRevision, TreeActionType.Add); if (existingItem != null) { // maybe same value added twice? var tmpKey = page.GetNodeKey(item); if (tmpKey.Compare(value) == 0) { return; // already there, turning into a no-op } nestedPage.RemoveNode(nestedPage.LastSearchPosition); } var valueToInsert = nestedPage.PrepareKeyToInsert(value, nestedPage.LastSearchPosition); if (nestedPage.HasSpaceFor(_tx, valueToInsert, 0)) { // we are now working on top of the modified root page, we can just modify the memory directly nestedPage.AddDataNode(nestedPage.LastSearchPosition, valueToInsert, 0, previousNodeRevision); return; } int pageSize = nestedPage.CalcSizeUsed() + Constants.PageHeaderSize; var newRequiredSize = pageSize + nestedPage.GetRequiredSpace(valueToInsert, 0); if (newRequiredSize <= maxNodeSize) { // we can just expand the current value... no need to create a nested tree yet var actualPageSize = (ushort)Math.Min(Utils.NearestPowerOfTwo(newRequiredSize), maxNodeSize); var currentDataSize = NodeHeader.GetDataSize(_tx, item); ExpandMultiTreeNestedPageSize(_tx, key, value, nestedPagePtr, actualPageSize, currentDataSize); return; } // we now have to convert this into a tree instance, instead of just a nested page var tree = Create(_tx, KeysPrefixing, TreeFlags.MultiValue); for (int i = 0; i < nestedPage.NumberOfEntries; i++) { var existingValue = nestedPage.GetNodeKey(i); tree.DirectAdd(existingValue, 0); } tree.DirectAdd(value, 0, version: version); _tx.AddMultiValueTree(this, key, tree); // we need to record that we switched to tree mode here, so the next call wouldn't also try to create the tree again DirectAdd(key, sizeof(TreeRootHeader), NodeFlags.MultiValuePageRef); }
public IIterator MultiRead(Slice key) { Lazy <Cursor> lazy; NodeHeader * node; var page = FindPageFor(key, out node, out lazy); if (page == null || page.LastMatch != 0) { return(new EmptyIterator()); } Debug.Assert(node != null); var fetchedNodeKey = page.GetNodeKey(node); if (fetchedNodeKey.Compare(key) != 0) { throw new InvalidDataException("Was unable to retrieve the correct node. Data corruption possible"); } if (node->Flags == NodeFlags.MultiValuePageRef) { var tree = OpenMultiValueTree(_tx, key, node); return(tree.Iterate()); } var nestedPage = new Page(NodeHeader.DirectAccess(_tx, node), "multi tree", (ushort)NodeHeader.GetDataSize(_tx, node)); return(new PageIterator(nestedPage)); }
public void MultiDelete(Slice key, Slice value, ushort?version = null) { State.IsModified = true; Lazy <Cursor> lazy; NodeHeader * node; var page = FindPageFor(key, out node, out lazy); if (page == null || page.LastMatch != 0) { return; //nothing to delete - key not found } page = _tx.ModifyPage(page.PageNumber, page); var item = page.GetNode(page.LastSearchPosition); if (item->Flags == NodeFlags.MultiValuePageRef) //multi-value tree exists { var tree = OpenMultiValueTree(_tx, key, item); tree.Delete(value, version); // previously, we would convert back to a simple model if we dropped to a single entry // however, it doesn't really make sense, once you got enough values to go to an actual nested // tree, you are probably going to remain that way, or be removed completely. if (tree.State.EntriesCount != 0) { return; } _tx.TryRemoveMultiValueTree(this, key); _tx.FreePage(tree.State.RootPageNumber); Delete(key); } else // we use a nested page here { var nestedPage = new Page(NodeHeader.DirectAccess(_tx, item), "multi tree", (ushort)NodeHeader.GetDataSize(_tx, item)); var nestedItem = nestedPage.Search(value); if (nestedItem == null) // value not found { return; } byte *nestedPagePtr; if (item->Flags == NodeFlags.PageRef) { var overFlowPage = _tx.ModifyPage(item->PageNumber, null); nestedPagePtr = overFlowPage.Base + Constants.PageHeaderSize; } else { nestedPagePtr = NodeHeader.DirectAccess(_tx, item); } nestedPage = new Page(nestedPagePtr, "multi tree", (ushort)NodeHeader.GetDataSize(_tx, item)) { LastSearchPosition = nestedPage.LastSearchPosition }; CheckConcurrency(key, value, version, nestedItem->Version, TreeActionType.Delete); nestedPage.RemoveNode(nestedPage.LastSearchPosition); if (nestedPage.NumberOfEntries == 0) { Delete(key); } } }
public int GetCurrentDataSize() { return(NodeHeader.GetDataSize(_tx, Current)); }