Example #1
0
        /// <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);
        }
Example #2
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);
        }