Esempio n. 1
0
        public IRadixTreeNode Fetch(DbItemReference reference)
        {
            if (DbItemReference.IsNull(reference))
            {
                return(null);
            }

            var page = _pageManager.FetchPage(reference.PageIndex);

            if (page.BackingObject == null)
            {
                var obj1 = RadixTreePageBackingObject.FromPage(page);
                page = new Page(_pageManager, page.Index, () => Serialize(obj1), obj1);
            }

            var backingObject = (RadixTreePageBackingObject)page.BackingObject;

            var obj = backingObject.Items[reference.ItemIndex];

            var result = obj as IRadixTreeNode;

            if (result == null)
            {
                result           = NodeFromBytes((byte[])obj);
                result.Reference = (DbItemReference)reference.Clone();
                backingObject.Items[reference.ItemIndex] = result;
            }

            return(result);
        }
Esempio n. 2
0
        private IRadixTreeNode NodeFromBytes(byte[] nodeBytes)
        {
            var result = new RadixTreeNode(0);

            using (var ms = new MemoryStream(nodeBytes, false))
            {
                var buffer = new byte[PageFormatter.OnPagePointerSize];

                ms.Read(buffer, 0, PageFormatter.OnPagePointerSize); // overall size

                ms.Read(buffer, 0, PageFormatter.OnPagePointerSize); // prefix length
                short prefixLength = BitConverter.ToInt16(buffer, 0);
                var   prefix       = new byte[prefixLength];
                ms.Read(prefix, 0, prefixLength); // prefix itself
                result.Prefix              = prefix;
                result.ValueReference      = DbItemReference.Read(ms);
                result.ParentNodeReference = DbItemReference.Read(ms);

                if (DbItemReference.IsNull(result.ValueReference))
                {
                    result.ValueReference = null;
                }
                if (DbItemReference.IsNull(result.ParentNodeReference))
                {
                    result.ParentNodeReference = null;
                }

                ms.Read(buffer, 0, sizeof(short));
                var nodeCount = BitConverter.ToInt16(buffer, 0);
                for (int i = 0; i < nodeCount; i++)
                {
                    var key   = (byte)ms.ReadByte();
                    var value = DbItemReference.Read(ms);
                    result.Entries.Add(new KeyValuePair <byte, DbItemReference>(key, value));
                }

                return(result);
            }
        }
Esempio n. 3
0
        private TKey BuildKeyForNode(IRadixTreeNode node)
        {
            var prefixes = new List <byte[]>();

            while (!DbItemReference.IsNull(node.ParentNodeReference))
            {
                prefixes.Add(node.Prefix);
                node = _nodeStorage.Fetch(node.ParentNodeReference);
            }

            prefixes.Reverse();

            using (var ms = new MemoryStream())
            {
                foreach (var prefix in prefixes.Where(p => p != null))
                {
                    ms.Write(prefix, 0, prefix.Length);
                }

                return(_keySerializer.Deserialize(ms.ToArray()));
            }
        }
Esempio n. 4
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);
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Removes key-value pair by key.
        /// </summary>
        /// <param name="key">The key</param>
        public void Remove(TKey key)
        {
            var            binaryKey = _keySerializer.Serialize(key);
            int            keyOffset;
            int            nodePrefixOffset;
            bool           isFullMatch;
            IRadixTreeNode node = FindMostSuitableNode(binaryKey, out keyOffset, out nodePrefixOffset, out isFullMatch);

            if (isFullMatch)
            {
                _valueStorage.Free(node.ValueReference);
                node.ValueReference = null;

                if (node.Entries.Any())
                {
                    if (node.Prefix != null && node.Entries.Count == 1)
                    {
                        var child = _nodeStorage.Fetch(node.Entries[0].Value);

                        var newPrefixLength = node.Prefix.Length + child.Prefix.Length;
                        if (newPrefixLength <= MaxPrefixLength)
                        {
                            var newPrefix = new byte[newPrefixLength];

                            Buffer.BlockCopy(node.Prefix, 0, newPrefix, 0, node.Prefix.Length);
                            Buffer.BlockCopy(child.Prefix, 0, newPrefix, node.Prefix.Length, child.Prefix.Length);

                            child.Prefix = newPrefix;
                            child.ParentNodeReference = node.ParentNodeReference;

                            _nodeStorage.Remove(node.Reference);
                            bool reallocated;
                            child = UpdateOrReallocateNode(child, out reallocated);

                            var parent = _nodeStorage.Fetch(child.ParentNodeReference);
                            int index;
                            FindSuitableEntry(parent.Entries, child.Prefix[0], out index);
                            parent.Entries[index] = new KeyValuePair <byte, DbItemReference>(child.Prefix[0], child.Reference);

                            UpdateOrFail(parent);
                        }
                        else
                        {
                            UpdateOrFail(node);
                        }
                    }
                    else
                    {
                        UpdateOrFail(node);
                    }
                }
                else
                {
                    while (!DbItemReference.IsNull(node.ParentNodeReference))
                    {
                        var parentNode = _nodeStorage.Fetch(node.ParentNodeReference);
                        int index;
                        FindSuitableEntry(parentNode.Entries, node.Prefix[0], out index);
                        parentNode.Entries.RemoveAt(index);
                        _nodeStorage.Remove(node.Reference);

                        if (parentNode.Entries.Any() || parentNode.ValueReference != null ||
                            DbItemReference.IsNull(parentNode.ParentNodeReference))
                        {
                            UpdateOrFail(parentNode);
                            break;
                        }

                        node = parentNode;
                    }
                }
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Gets the key next to the specified key.
        /// The existence of the specified key is not required.
        /// </summary>
        /// <returns>The key next to specified key</returns>
        public TKey NextTo(TKey key)
        {
            var            binaryKey = _keySerializer.Serialize(key);
            int            keyOffset;
            int            nodePrefixOffset;
            bool           isFullMatch;
            IRadixTreeNode targetNode = FindMostSuitableNode(binaryKey, out keyOffset, out nodePrefixOffset, out isFullMatch);

            if (isFullMatch || keyOffset == binaryKey.Length)
            {
                if (targetNode.Entries.Any())
                {
                    targetNode = _nodeStorage.Fetch(targetNode.Entries.First().Value);
                }
                else
                {
                    while (!DbItemReference.IsNull(targetNode.ParentNodeReference))
                    {
                        var parent = _nodeStorage.Fetch(targetNode.ParentNodeReference);
                        targetNode = GetChildNextTo(parent, targetNode.Prefix[0]);
                        if (targetNode != null)
                        {
                            break;
                        }
                        targetNode = parent;
                    }
                }
            }
            else
            {
                byte b = binaryKey[keyOffset];
                while (true)
                {
                    var child = GetChildNextTo(targetNode, b);
                    if (child != null)
                    {
                        targetNode = child;
                        break;
                    }

                    if (DbItemReference.IsNull(targetNode.ParentNodeReference))
                    {
                        break;
                    }

                    b          = targetNode.Prefix[0];
                    targetNode = _nodeStorage.Fetch(targetNode.ParentNodeReference);
                }
            }

            if (DbItemReference.IsNull(targetNode.ParentNodeReference))
            {
                return(default(TKey));
            }

            while (DbItemReference.IsNull(targetNode.ValueReference) && targetNode.Entries.Any())
            {
                targetNode = _nodeStorage.Fetch(targetNode.Entries.First().Value);
            }

            return(BuildKeyForNode(targetNode));
        }