public void Validate() { #if DEBUG using (RootLock root = LockRoot(LockType.Read, "Validate", true)) Validate(root.Pin, null, int.MinValue, int.MaxValue); #endif }
/// <inheritdoc /> public void Dispose() { //Inner most lock disposed first ChildLock?.Dispose(); //Then global root lock. RootLock?.Dispose(); }
public bool MoveNext() { if (_enumComplete) { return(false); } if (++_currentOffset < _currentLimit) { if (_fnContinue == null || _fnContinue(CurrentKey)) { return(true); } Array.Clear(_currentSet, 0, _currentSet.Length); _currentOffset = 0; _currentLimit = 0; _enumComplete = true; return(false); } bool success = false; using (RootLock root = _tree.LockRoot(LockType.Read, "Enumerator")) { int offset; NodePin next; if (_hasMore && SeekNext(root.Pin, _nextKey, out next, out offset, out _nextKey, out _hasMore)) { using (next) { FillFromNode(next.Ptr); _currentOffset = offset; } success = true; } } if (success) { if (_currentOffset >= _currentLimit) { return(MoveNext()); } if (_fnContinue == null || _fnContinue(CurrentKey)) { return(true); } } Array.Clear(_currentSet, 0, _currentSet.Length); _currentOffset = 0; _currentLimit = 0; _enumComplete = true; return(false); }
private RemoveResult RemoveEntry(TKey key, TValue removeValue) //where T : IRemoveValue<TKey, TValue> { RemoveResult result; using (RootLock root = LockRoot(LockType.Delete, "Remove")) result = Delete(root.Pin, key, removeValue, null, int.MinValue); DebugComplete("Removed({0}) = {1}", key, result); return(result); }
private InsertResult AddEntry(TKey key, TValue value) //where T : ICreateOrUpdateValue<TKey, TValue> { InsertResult result; using (RootLock root = LockRoot(LockType.Insert, "AddOrUpdate")) result = Insert(root.Pin, key, value, null, int.MinValue); DebugComplete("Added({0}) = {1}", key, result); return(result); }
//TODO: not sure about the functionality of this function after changes /// <summary> /// Updates an element with the provided key to the value if it exists. /// </summary> /// <returns>Returns true if the key provided was found and updated to the value.</returns> /// <param name="key">The object to use as the key of the element to update.</param> /// <param name="value">The new value for the key if found.</param> /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> public bool TryUpdate(TKey key, TValue value) { UpdateInfo ui = new UpdateInfo(value); bool result; using (RootLock root = LockRoot(LockType.Update, "Update")) result = Update(root.Pin, key, value, default(TValue)); //TODO: old value can be any value DebugComplete("Updated({0}) = {1}", key, result); return(ui.Updated); }
/// <summary> /// Gets the value associated with the specified key. /// </summary> public bool TryGetValue(TKey key, out IDictionary <TValue, byte> value) { bool result; value = null; using (RootLock root = LockRoot(LockType.Read, "TryGetValue")) result = Search(root.Pin, key, ref value); DebugComplete("Found({0}) = {1}", key, result); return(result); }
/// <summary> /// Gets the value associated with the specified key. /// </summary> public bool TryGetValue(TKey key, out TValue value) { bool result; value = default(TValue); using (RootLock root = LockRoot(LockType.Read, "TryGetValue")) result = Search(root.Pin, key, ref value); DebugComplete("Found({0}) = {1}", key, result); return(result); }
/// <summary> /// Modify the value associated with the result of the provided update method /// as an atomic operation, Allows for reading/writing a single record within /// the tree lock. Be cautious about the behavior and performance of the code /// provided as it can cause a dead-lock to occur. If the method returns an /// instance who .Equals the original, no update is applied. /// </summary> public bool TryUpdate(TKey key, KeyValueUpdate <TKey, TValue> fnUpdate) { UpdateInfo ui = new UpdateInfo(fnUpdate); bool result; using (RootLock root = LockRoot(LockType.Update, "Update")) result = Update(root.Pin, key, ref ui); DebugComplete("Updated({0}) = {1}", key, result); return(ui.Updated); }
/// <summary> /// Updates an element with the provided key to the value if it exists. /// </summary> /// <returns>Returns true if the key provided was found and updated to the value.</returns> /// <param name="key">The object to use as the key of the element to update.</param> /// <param name="value">The new value for the key if found.</param> /// <param name="comparisonValue">The value that is compared to the value of the element with key.</param> public bool TryUpdate(TKey key, TValue value, TValue comparisonValue) { UpdateIfValue ui = new UpdateIfValue(value, comparisonValue); bool result; using (RootLock root = LockRoot(LockType.Update, "Update")) result = Update(root.Pin, key, ref ui); DebugComplete("Updated({0}) = {1}", key, result); return(ui.Updated); }
/// <summary> /// Due to the cost of upkeep, this must be enable each time the object is created via a call to /// EnableCount() which itself must be done before any writer threads are active for it to be /// accurate. This requires that the entire tree be loaded (sequentially) in order to build /// the initial working count. Once completed, members like Add() and Remove() will keep the /// initial count accurate. /// </summary> public void EnableCount() { if (_hasCount) { return; } _keyCount = 0; using (RootLock root = LockRoot(LockType.Read, "EnableCount", true)) CountValues(root.Pin, out _keyCount, out _valueCount); _hasCount = true; }
/// <summary> /// Due to the cost of upkeep, this must be enable each time the object is created via a call to /// EnableCount() which itself must be done before any writer threads are active for it to be /// accurate. This requires that the entire tree be loaded (sequentially) in order to build /// the initial working count. Once completed, members like Add() and Remove() will keep the /// initial count accurate. /// </summary> public void EnableCount() { if (_hasCount) { return; } _count = 0; using (RootLock root = LockRoot(LockType.Read, "EnableCount", true)) _count = CountValues(root.Pin); _hasCount = true; }
private RemoveResult RemoveEntry <T>(TKey key, ref T removeValue) where T : IRemoveValue <TKey, TValue> { RemoveResult result; using (RootLock root = LockRoot(LockType.Delete, "Remove")) result = Delete(root.Pin, key, ref removeValue, null, int.MinValue); if (result == RemoveResult.Removed && _hasCount) { Interlocked.Decrement(ref _count); } DebugComplete("Removed({0}) = {1}", key, result); return(result); }
private InsertResult AddEntry <T>(TKey key, ref T info) where T : ICreateOrUpdateValue <TKey, TValue> { InsertResult result; using (RootLock root = LockRoot(LockType.Insert, "AddOrUpdate")) result = Insert(root.Pin, key, ref info, null, int.MinValue); if (result == InsertResult.Inserted && _hasCount) { Interlocked.Increment(ref _count); } DebugComplete("Added({0}) = {1}", key, result); return(result); }
/// <summary> /// Optimized insert of presorted key/value pairs. /// If the input is not presorted, please use AddRange() instead. /// </summary> /// <param name="items">The ordered list of items to insert</param> /// <param name="allowUpdates">True to overwrite any existing records</param> /// <returns>The total number of records inserted or updated</returns> public int AddRangeSorted(IEnumerable <KeyValuePair <TKey, TValue> > items, bool allowUpdates) { int result = 0; using (AddRangeInfo bulk = new AddRangeInfo(allowUpdates, items)) { while (!bulk.IsComplete) { KeyRange range = new KeyRange(_keyComparer); using (RootLock root = LockRoot(LockType.Insert, "BulkInsert")) result += AddRange(root.Pin, ref range, bulk, null, int.MinValue); } } DebugComplete("AddRange({0} records)", result); return(result); }
public void Reset() { if (_hasStart) { _enumComplete = false; _currentLimit = 0; _currentOffset = 0; _hasMore = true; _nextKey = _startKey; } else { using (RootLock root = _tree.LockRoot(LockType.Read, "Enumerator")) using (NodePin first = SeekFirst(root.Pin, out _nextKey, out _hasMore)) { FillFromNode(first.Ptr); _enumComplete = _currentLimit == 0; } } }
public void Print(TextWriter output, DebugFormat format) { using (RootLock root = LockRoot(LockType.Read, "Print", true)) Print(root.Pin, output, 0, format); }
/// <summary> /// Returns the first key and it's associated value. /// </summary> public bool TryGetFirst(out KeyValuePair <TKey, IDictionary <TValue, byte> > item) { using (RootLock root = LockRoot(LockType.Read, "TryGetFirst")) return(TryGetEdge(root.Pin, true, out item)); }
/// <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; } }
/// <summary> /// Returns the last key and it's associated value. /// </summary> public bool TryGetLast(out KeyValuePair <TKey, TValue> item) { using (RootLock root = LockRoot(LockType.Read, "TryGetLast")) return(TryGetEdge(root.Pin, false, out item)); }