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);
        }
Пример #4
0
            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();
            }
Пример #6
0
        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;
            }
        }
Пример #7
0
            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();
                }
            }
Пример #8
0
        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));
        }
Пример #9
0
        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));
        }
Пример #10
0
        /// <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;
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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));
        }