private bool SeekNext(NodePin thisLock, TKey key, out NodePin pin, out int offset, out TKey nextKey, out bool hasMore) { pin = null; offset = -1; nextKey = default(TKey); hasMore = false; Element find = new Element(key); NodePin next = null; NodePin current = thisLock; try { int ordinal; while (true) { Node me = current.Ptr; me.BinarySearch(_tree._itemComparer, find, out ordinal); if (me.IsLeaf) { pin = current; offset = ordinal; current = null; return(true); } if (me.Count > ordinal + 1) { nextKey = current.Ptr[ordinal + 1].Key; hasMore = true; } next = _tree._storage.Lock(current, me[ordinal].ChildNode); current.Dispose(); current = next; next = null; } } finally { if (current != null) { current.Dispose(); } if (next != null) { next.Dispose(); } } }
private bool Seek(NodePin thisLock, TKey key, out NodePin pin, out int offset) { NodePin myPin = thisLock, nextPin = null; try { while (myPin != null) { Node me = myPin.Ptr; bool isValueNode = me.IsLeaf; int ordinal; if (me.BinarySearch(_itemComparer, new Element(key), out ordinal) && isValueNode) { pin = myPin; myPin = null; offset = ordinal; return(true); } if (isValueNode) { break; // not found. } nextPin = _storage.Lock(myPin, me[ordinal].ChildNode); myPin.Dispose(); myPin = nextPin; nextPin = null; } } finally { if (myPin != null) { myPin.Dispose(); } if (nextPin != null) { nextPin.Dispose(); } } pin = null; offset = -1; return(false); }
private bool SeekToEdge(NodePin thisLock, bool first, out NodePin pin, out int offset) { NodePin myPin = thisLock, nextPin = null; try { while (myPin != null) { Node me = myPin.Ptr; int ordinal = first ? 0 : me.Count - 1; if (me.IsLeaf) { if (ordinal < 0 || ordinal >= me.Count) { break; } pin = myPin; myPin = null; offset = ordinal; return(true); } nextPin = _storage.Lock(myPin, me[ordinal].ChildNode); myPin.Dispose(); myPin = nextPin; nextPin = null; } } finally { if (myPin != null) { myPin.Dispose(); } if (nextPin != null) { nextPin.Dispose(); } } pin = null; offset = -1; return(false); }
public void Rollback() { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (_reverted) { return; } _reverted = true; if (_parentItem != null) { _parentItem.CancelChanges(); _cache.UpdateNode(_parentItem); _parentItem.Dispose(); } NodePin pin = _created; while (pin != null) { pin.CancelChanges(); _cache.UpdateNode(pin); _cache.Storage.Destroy(pin.Handle.StoreHandle); pin.Dispose(); pin = (NodePin)pin.Next; } pin = _deleted; while (pin != null) { pin.CancelChanges(); _cache.UpdateNode(pin); pin.Dispose(); pin = (NodePin)pin.Next; } if (_hasLogToken) { _hasLogToken = false; _cache.Options.LogFile.RollbackTransaction(ref _logToken); } }
private NodePin SeekFirst(NodePin thisLock, out TKey nextKey, out bool hasMore) { nextKey = default(TKey); hasMore = false; NodePin myPin = thisLock, nextPin = null; try { while (myPin != null) { Node me = myPin.Ptr; if (me.IsLeaf) { NodePin pin = myPin; myPin = null; return(pin); } if (me.Count > 1) { nextKey = me[1].Key; hasMore = true; } nextPin = _tree._storage.Lock(myPin, me[0].ChildNode); myPin.Dispose(); myPin = nextPin; nextPin = null; } } finally { if (myPin != null) { myPin.Dispose(); } if (nextPin != null) { nextPin.Dispose(); } } throw new InvalidOperationException(); }
private NodePin Split(NodeTransaction trans, ref NodePin thisLock, NodePin parentLock, int parentIx, out TKey splitKey, bool leftHeavy) { Node me = thisLock.Ptr; NodePin prev = trans.Create(parentLock, thisLock.Ptr.IsLeaf); NodePin next = trans.Create(parentLock, thisLock.Ptr.IsLeaf); try { int ix; int count = me.Count >> 1; if (leftHeavy) { int minSize = thisLock.Ptr.IsLeaf ? _options.MinimumValueNodes : _options.MinimumChildNodes; count = me.Count - minSize; } for (ix = 0; ix < count; ix++) { prev.Ptr.Insert(prev.Ptr.Count, me[ix]); } splitKey = me[count].Key; if (!thisLock.Ptr.IsLeaf) { next.Ptr.Insert(next.Ptr.Count, new Element(default(TKey), me[ix++].ChildNode)); } for (; ix < me.Count; ix++) { next.Ptr.Insert(next.Ptr.Count, me[ix]); } parentLock.Ptr.ReplaceChild(parentIx, thisLock.Handle, prev.Handle); parentLock.Ptr.Insert(parentIx + 1, new Element(splitKey, next.Handle)); trans.Destroy(thisLock); thisLock = prev; return(next); } catch { prev.Dispose(); next.Dispose(); throw; } }
void IDisposable.Dispose() { Pin.Dispose(); if (_locked && _exclusive) { _tree._selfLock.ReleaseWrite(); } else if (_locked && !_exclusive) { _tree._selfLock.ReleaseRead(); } _locked = false; _tree._storage.ReturnVersion(ref _version); if (_type != LockType.Read) { _tree.OnChanged(); } }
private RemoveResult Delete <T>(NodePin thisLock, TKey key, ref T condition, NodePin parent, int parentIx) where T : IRemoveValue <TKey, TValue> { Node me = thisLock.Ptr; if (me.Count == 0) { return(RemoveResult.NotFound); } int minimumKeys = me.IsLeaf ? _options.MinimumValueNodes : _options.MinimumChildNodes; if (me.Count <= minimumKeys && parent != null && !parent.Ptr.IsRoot) { if (parentIx < parent.Ptr.Count - 1) { using (NodePin bigger = _storage.Lock(parent, parent.Ptr[parentIx + 1].ChildNode)) Join(thisLock, bigger, false, parent, parentIx); thisLock.Dispose(); return(Delete(parent, key, ref condition, null, int.MinValue)); } if (parentIx > 0) { using (NodePin smaller = _storage.Lock(parent, parent.Ptr[parentIx - 1].ChildNode)) Join(smaller, thisLock, true, parent, parentIx - 1); thisLock.Dispose(); return(Delete(parent, key, ref condition, null, int.MinValue)); } Assert(false, "Failed to join node before delete."); } else if (parent != null && parent.Ptr.IsRoot && me.Count == 1 && !me.IsLeaf) { using (NodePin onlyChild = _storage.Lock(thisLock, me[0].ChildNode)) { using (NodeTransaction t = _storage.BeginTransaction()) { RootNode rootNode = (RootNode)t.BeginUpdate(parent); rootNode.ReplaceChild(0, thisLock.Handle, onlyChild.Handle); t.Destroy(thisLock); t.Commit(); } return(Delete(onlyChild, key, ref condition, null, int.MinValue)); } } if (parent != null) { parent.Dispose();//done with the parent lock. } bool isValueNode = me.IsLeaf; int ordinal; if (me.BinarySearch(_itemComparer, new Element(key), out ordinal) && isValueNode) { if (condition.RemoveValue(key, me[ordinal].Payload)) { using (NodeTransaction t = _storage.BeginTransaction()) { me = t.BeginUpdate(thisLock); me.Remove(ordinal, new Element(key), _keyComparer); t.RemoveValue(key); t.Commit(); return(RemoveResult.Removed); } } return(RemoveResult.Ignored); } if (isValueNode) { return(RemoveResult.NotFound); } if (ordinal >= me.Count) { ordinal = me.Count - 1; } using (NodePin child = _storage.Lock(thisLock, me[ordinal].ChildNode)) return(Delete(child, key, ref condition, thisLock, ordinal)); }
private InsertResult Insert <T>(NodePin thisLock, TKey key, ref T value, NodePin parent, int parentIx) where T : ICreateOrUpdateValue <TKey, TValue> { Node me = thisLock.Ptr; if (me.Count == me.Size && parent != null) { using (NodeTransaction trans = _storage.BeginTransaction()) { TKey splitAt; if (parent.Ptr.IsRoot) //Is root node { Node rootNode = trans.BeginUpdate(parent); using (NodePin newRoot = trans.Create(parent, false)) { rootNode.ReplaceChild(0, thisLock.Handle, newRoot.Handle); newRoot.Ptr.Insert(0, new Element(default(TKey), thisLock.Handle)); using (NodePin next = Split(trans, ref thisLock, newRoot, 0, out splitAt, false)) using (thisLock) { trans.Commit(); GC.KeepAlive(thisLock); GC.KeepAlive(next); } return(Insert(newRoot, key, ref value, parent, parentIx)); } } trans.BeginUpdate(parent); using (NodePin next = Split(trans, ref thisLock, parent, parentIx, out splitAt, false)) using (thisLock) { trans.Commit(); if (_keyComparer.Compare(key, splitAt) >= 0) { thisLock.Dispose(); return(Insert(next, key, ref value, parent, parentIx + 1)); } next.Dispose(); return(Insert(thisLock, key, ref value, parent, parentIx)); } } } if (parent != null) { parent.Dispose();//done with the parent lock. } int ordinal; if (me.BinarySearch(_itemComparer, new Element(key), out ordinal) && me.IsLeaf) { TValue updatedValue = me[ordinal].Payload; if (value.UpdateValue(key, ref updatedValue)) { using (NodeTransaction trans = _storage.BeginTransaction()) { me = trans.BeginUpdate(thisLock); me.SetValue(ordinal, key, updatedValue, _keyComparer); trans.UpdateValue(key, updatedValue); trans.Commit(); return(InsertResult.Updated); } } return(InsertResult.Exists); } if (me.IsLeaf) { TValue newValue; if (value.CreateValue(key, out newValue)) { using (NodeTransaction trans = _storage.BeginTransaction()) { me = trans.BeginUpdate(thisLock); me.Insert(ordinal, new Element(key, newValue)); trans.AddValue(key, newValue); trans.Commit(); return(InsertResult.Inserted); } } return(InsertResult.NotFound); } if (ordinal >= me.Count) { ordinal = me.Count - 1; } using (NodePin child = _storage.Lock(thisLock, me[ordinal].ChildNode)) return(Insert(child, key, ref value, thisLock, ordinal)); }
/// <summary> /// Rewrite the entire BTree as a transaction to include the provided items. This method is Thread safe. /// If the input is already sorted, use BulkInsertOptions overload to specify InputIsSorted = true. /// </summary> public int BulkInsert(IEnumerable <KeyValuePair <TKey, TValue> > items, BulkInsertOptions bulkOptions) { NodePin oldRoot = null; if (bulkOptions.InputIsSorted == false) { KeyValueSerializer <TKey, TValue> kvserializer = new KeyValueSerializer <TKey, TValue>(_options.KeySerializer, _options.ValueSerializer); items = new OrderedKeyValuePairs <TKey, TValue>(_options.KeyComparer, items, kvserializer) { DuplicateHandling = bulkOptions.DuplicateHandling }; } List <IStorageHandle> handles = new List <IStorageHandle>(); try { int counter = 0; using (RootLock root = LockRoot(LockType.Insert, "Merge", false)) { if (root.Pin.Ptr.Count != 1) { throw new InvalidDataException(); } NodeHandle oldRootHandle = root.Pin.Ptr[0].ChildNode; oldRoot = _storage.Lock(root.Pin, oldRootHandle); if (oldRoot.Ptr.Count == 0 || bulkOptions.ReplaceContents) { // Currently empty, so just enforce duplicate keys... items = OrderedKeyValuePairs <TKey, TValue> .WithDuplicateHandling(items, new KeyValueComparer <TKey, TValue>(_options.KeyComparer), bulkOptions.DuplicateHandling); } else { // Merging with existing data and enforce duplicate keys... items = OrderedKeyValuePairs <TKey, TValue> .Merge(_options.KeyComparer, bulkOptions.DuplicateHandling, EnumerateNodeContents(oldRoot), items); } Node newtree = BulkWrite(handles, ref counter, items); if (newtree == null) // null when enumeration was empty { return(0); } using (NodeTransaction trans = _storage.BeginTransaction()) { Node rootNode = trans.BeginUpdate(root.Pin); rootNode.ReplaceChild(0, oldRootHandle, new NodeHandle(newtree.StorageHandle)); trans.Commit(); } _count = counter; } //point of no return... handles.Clear(); DeleteTree(oldRoot); oldRoot = null; if (bulkOptions.CommitOnCompletion) { //Since transaction logs do not deal with bulk-insert, we need to commit our current state Commit(); } return(counter); } catch { if (oldRoot != null) { oldRoot.Dispose(); } foreach (IStorageHandle sh in handles) { try { _storage.Storage.Destroy(sh); } catch (ThreadAbortException) { throw; } catch { continue; } } throw; } }
private int AddRange(NodePin thisLock, ref KeyRange range, AddRangeInfo value, NodePin parent, int parentIx) { int counter = 0; Node me = thisLock.Ptr; if (me.Count == me.Size && parent != null) { using (NodeTransaction trans = _storage.BeginTransaction()) { TKey splitAt; if (parent.Ptr.IsRoot) //Is root node { Node rootNode = trans.BeginUpdate(parent); using (NodePin newRoot = trans.Create(parent, false)) { rootNode.ReplaceChild(0, thisLock.Handle, newRoot.Handle); newRoot.Ptr.Insert(0, new Element(default(TKey), thisLock.Handle)); using (NodePin next = Split(trans, ref thisLock, newRoot, 0, out splitAt, true)) using (thisLock) { trans.Commit(); GC.KeepAlive(thisLock); GC.KeepAlive(next); } return(AddRange(newRoot, ref range, value, parent, parentIx)); } } trans.BeginUpdate(parent); using (NodePin next = Split(trans, ref thisLock, parent, parentIx, out splitAt, true)) using (thisLock) { trans.Commit(); if (_keyComparer.Compare(value.Current.Key, splitAt) >= 0) { thisLock.Dispose(); range.SetMinKey(splitAt); return(AddRange(next, ref range, value, parent, parentIx + 1)); } next.Dispose(); range.SetMaxKey(splitAt); return(AddRange(thisLock, ref range, value, parent, parentIx)); } } } if (parent != null) { parent.Dispose(); } if (me.IsLeaf) { using (NodeTransaction trans = _storage.BeginTransaction()) { me = trans.BeginUpdate(thisLock); int inserted = 0; while (me.Count < me.Size && !value.IsComplete && range.IsKeyInRange(value.Current.Key)) { int ordinal; bool exists = me.BinarySearch(_itemComparer, new Element(value.Current.Key), out ordinal); DuplicateKeyException.Assert(!exists || value.AllowUpdate); if (exists) { me.SetValue(ordinal, value.Current.Key, value.Current.Value, _keyComparer); trans.UpdateValue(value.Current.Key, value.Current.Value); } else { me.Insert(ordinal, new Element(value.Current.Key, value.Current.Value)); trans.AddValue(value.Current.Key, value.Current.Value); inserted++; } counter++; value.MoveNext(); } trans.Commit(); if (_hasCount && inserted > 0) { int count = _count, test; while (count != (test = Interlocked.CompareExchange(ref _count, count + inserted, count))) { count = test; } } } } else { int ordinal; me.BinarySearch(_itemComparer, new Element(value.Current.Key), out ordinal); if (ordinal >= me.Count) { ordinal = me.Count - 1; } if (ordinal > 0) { range.SetMinKey(me[ordinal - 1].Key); } if (ordinal < (me.Count - 1)) { range.SetMaxKey(me[ordinal + 1].Key); } using (NodePin child = _storage.Lock(thisLock, me[ordinal].ChildNode)) counter += AddRange(child, ref range, value, thisLock, ordinal); } return(counter); }
private InsertResult Insert(NodePin thisLock, TKey key, TValue value, NodePin parent, int parentIx) // where T : ICreateOrUpdateValue<TKey, TValue> { Node me = thisLock.Ptr; if (me.Count == me.Size && parent != null) { using (NodeTransaction trans = _storage.BeginTransaction()) { TKey splitAt; if (parent.Ptr.IsRoot) //Is root node { Node rootNode = trans.BeginUpdate(parent); using (NodePin newRoot = trans.Create(parent, false)) { rootNode.ReplaceChild(0, thisLock.Handle, newRoot.Handle); newRoot.Ptr.Insert(0, new Element(default(TKey), thisLock.Handle)); using (NodePin next = Split(trans, ref thisLock, newRoot, 0, out splitAt, false)) using (thisLock) { var watch = new Stopwatch(); trans.Commit(); watch.Start(); GC.KeepAlive(thisLock); GC.KeepAlive(next); watch.Stop(); if (watch.ElapsedMilliseconds > 10000 && LoggerManager.Instance.IndexLogger != null) { LoggerManager.Instance.IndexLogger.Debug("BPlusTree.Insert", "KeepAlive calls take: " + watch.ElapsedMilliseconds + " (ms)"); } } return(Insert(newRoot, key, value, parent, parentIx)); } } trans.BeginUpdate(parent); using (NodePin next = Split(trans, ref thisLock, parent, parentIx, out splitAt, false)) using (thisLock) { trans.Commit(); if (_keyComparer.Compare(key, splitAt) >= 0) { thisLock.Dispose(); return(Insert(next, key, value, parent, parentIx + 1)); } next.Dispose(); return(Insert(thisLock, key, value, parent, parentIx)); } } } if (parent != null) { parent.Dispose();//done with the parent lock. } int ordinal; if (me.BinarySearch(_itemComparer, new Element(key), out ordinal) && me.IsLeaf) { //TValue updatedValue = me[ordinal].Payload; //if (value.UpdateValue(key, ref updatedValue)) { using (NodeTransaction trans = _storage.BeginTransaction()) { me = trans.BeginUpdate(thisLock); InternalResult result = me.SetValue(ordinal, key, value, _keyComparer); if (_hasCount) { if (result == InternalResult.Added) { _keyCount++; _valueCount++; } else if (result == InternalResult.Updated) { _valueCount++; } } trans.UpdateValue(key, value); trans.Commit(); return(InsertResult.Updated); } } //return InsertResult.Exists; } if (me.IsLeaf) { //TValue newValue; //if (value.CreateValue(key, out newValue)) //{ using (NodeTransaction trans = _storage.BeginTransaction()) { me = trans.BeginUpdate(thisLock); me.Insert(ordinal, new Element(key, value)); _keyCount++; _valueCount++; trans.AddValue(key, value); trans.Commit(); return(InsertResult.Inserted); } //} //return InsertResult.NotFound; } if (ordinal >= me.Count) { ordinal = me.Count - 1; } using (NodePin child = _storage.Lock(thisLock, me[ordinal].ChildNode)) return(Insert(child, key, value, thisLock, ordinal)); }