Beispiel #1
0
        /// <summary>
        /// Inserts or updates key value pair.
        /// </summary>
        /// <param name="key">The key</param>
        /// <param name="value">The value</param>
        public void Set(TKey key, TValue value)
        {
            var keyPath  = GetPathForKey(key);
            var leafNode = keyPath.Last();

            int index;

            var entry = FindSuitableEntry(leafNode.Entries, key, out index);

            if (entry.HasValue)
            {
                // update found value
                leafNode.Entries[index] =
                    new KeyValuePair <TKey, DbItemReference>(key, _valueStorage.Reallocate(entry.Value.Value, value));

                _nodeStorage.Update(leafNode);
                return;
            }

            var newEntry      = new KeyValuePair <TKey, DbItemReference>(key, _valueStorage.AllocateNew(value));
            var nodesToUpdate = new Dictionary <long, IBPlusTreeNode <TKey> >();

            leafNode.Entries.Insert(index, newEntry);

            // node could be in the inconsistent state while inserting new value
            // pin it to prevent writing of the corresponding page
            _nodeStorage.PinNode(leafNode.Index);

            AlignMaximalValues(key, keyPath, nodesToUpdate);

            if (IsOverflow(leafNode))
            {
                // the node is overflow, we should try to rotate it
                // or split if rotation is impossible
                if (!Rotate(leafNode, nodesToUpdate))
                {
                    Split(leafNode, nodesToUpdate);
                }
            }
            else
            {
                _nodeStorage.Update(leafNode);
            }

            foreach (var nodeToUpdate in nodesToUpdate)
            {
                _nodeStorage.Update(nodeToUpdate.Value);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Inserts or updates key value pair.
        /// </summary>
        /// <param name="key">The key</param>
        /// <param name="value">The value</param>
        public void Set(TKey key, TValue value)
        {
            var  binaryKey = _keySerializer.Serialize(key);
            int  keyOffset;
            int  nodePrefixOffset;
            bool isFullMatch;

            IRadixTreeNode targetNode = FindMostSuitableNode(binaryKey, out keyOffset, out nodePrefixOffset, out isFullMatch);

            if (isFullMatch)
            {
                // here we needn't any manipulation with key prefixes
                // simply update the existing or allocate a new value
                targetNode.ValueReference =
                    targetNode.ValueReference != null
                        ? _valueStorage.Reallocate(targetNode.ValueReference, value)
                        : _valueStorage.AllocateNew(value);

                UpdateOrFail(targetNode);
                return;
            }

            // we have a partial match
            var remainingKeyPart = new byte[binaryKey.Length - keyOffset];

            var nodeChain = new List <IRadixTreeNode>();

            if (remainingKeyPart.Length > 0)
            {
                Buffer.BlockCopy(binaryKey, keyOffset, remainingKeyPart, 0, remainingKeyPart.Length);

                // the remaining prefix may exceed the _maxPrefixLength
                // we must create a chain of nodes, where each node
                // contain part of the prefix remaining
                nodeChain = CreateNodeChain(remainingKeyPart);
            }

            if (targetNode.Prefix != null && nodePrefixOffset < targetNode.Prefix.Length)
            {
                // we got into splitting update:
                // the targetNode is split into newParentNode and targetNode itself
                // nodeChain (if has any items) is attached to newParentNode as a child

                // split prefix
                byte[] remainingPrefix;
                byte[] prefixForNewParent;

                SplitPrefix(targetNode.Prefix, nodePrefixOffset, out prefixForNewParent, out remainingPrefix);

                targetNode.Prefix = remainingPrefix;

                var newParentNode = _nodeStorage.Create(prefixForNewParent.Length, 2);

                newParentNode.Prefix = prefixForNewParent;
                newParentNode.ParentNodeReference = targetNode.ParentNodeReference;
                targetNode.ParentNodeReference    = newParentNode.Reference;

                var valueReference = _valueStorage.AllocateNew(value);
                if (nodeChain.Any())
                {
                    nodeChain.First().ParentNodeReference = newParentNode.Reference;
                    nodeChain.Last().ValueReference       = valueReference;
                }
                else
                {
                    newParentNode.ValueReference = valueReference;
                }

                // add links to child nodes
                foreach (var item in GetChildLinks(nodeChain.FirstOrDefault(), targetNode))
                {
                    newParentNode.Entries.Add(item);
                }

                if (nodeChain.Any())
                {
                    foreach (var node in nodeChain)
                    {
                        UpdateOrFail(node);
                    }
                }

                UpdateOrFail(newParentNode);
                UpdateOrFail(targetNode);

                // change link in parent node if needed
                if (!DbItemReference.IsNull(newParentNode.ParentNodeReference))
                {
                    AdjustParentNodeLink(newParentNode, true);
                }
            }
            else
            {
                // here is keeping update
                // all nodes above remain intact

                byte b = remainingKeyPart[0];
                int  index;
                FindSuitableEntry(targetNode.Entries, b, out index);

                targetNode.Entries.Insert(index, new KeyValuePair <byte, DbItemReference>(b, (DbItemReference)(nodeChain.First().Reference.Clone())));
                bool reallocated;
                targetNode = UpdateOrReallocateNode(targetNode, out reallocated);

                if (reallocated)
                {
                    AdjustParentNodeLink(targetNode, true);
                    AdjustLinksInChildNodes(targetNode, true);
                }

                nodeChain.First().ParentNodeReference = targetNode.Reference;
                nodeChain.Last().ValueReference       = _valueStorage.AllocateNew(value);

                foreach (var node in nodeChain)
                {
                    UpdateOrFail(node);
                }
            }
        }