Exemplo n.º 1
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);
        }