private IRadixTreeNode NewNode(DbItemReference parentReference) { return(new RadixTreeNode(0) { ParentNodeReference = parentReference, }); }
/// <summary> /// Allocates a new value and produces reference to it. /// </summary> /// <param name="value">Value to allocate</param> /// <returns>Reference to allocated value</returns> public DbItemReference AllocateNew(TValue value) { var reference = new DbItemReference(_index++, 0); _dictionary.Add(reference.ToString(), value); return(reference); }
/// <summary> /// Reallocates already allocated value and produces reference to it. /// </summary> /// <param name="reference">Reference to the already allocated value</param> /// <param name="newValue">New value to allocate</param> /// <returns>Reference to reallocated value</returns> public DbItemReference Reallocate(DbItemReference reference, TValue newValue) { var str = reference.ToString(); _dictionary.Remove(str); return(AllocateNew(newValue)); }
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); }
public byte[] GetItemSegment(DbItemReference reference, long startIndex, long endIndex) { var item = _items[reference.PageIndex]; var result = new byte[endIndex - startIndex]; Array.Copy(item, startIndex, result, 0, result.Length); return(result); }
public RadixTreeNodeMemoryStorage() { // initialize and add root node var root = NewNode(DbItemReference.Null); _rootNodeReference = root.Reference; _nodes.Add(root.Reference.ToString(), root); }
public DbItemReference Allocate(byte[] content) { _items[_lastNumber] = content; var reference = new DbItemReference(_lastNumber, 0); _lastNumber++; return(reference); }
public void Remove(DbItemReference reference) { if (_rootNodeReference.Equals(reference)) { throw new ArgumentOutOfRangeException(nameof(reference), "Unable to delete the root node"); } _nodes.Remove(reference.ToString()); }
private IRadixTreeNode NewNode(DbItemReference parentReference) { _index++; return(new RadixTreeNode(0) { Reference = new DbItemReference(_index, 0), ParentNodeReference = parentReference, }); }
/// <summary> /// Release allocated value. /// </summary> /// <param name="reference">Reference to allocated value</param> public void Free(DbItemReference reference) { //if (IsVersioningEnabled) //{ // var record = new VersionedRecord(_memoryManager.Get(reference).RawData, _memoryManager, SnapshotData); // record.Expire(DataTankerTransaction.Current.Id); //} //else _memoryManager.Free(reference); }
public static VersionInfo Read(Stream stream) { var result = new VersionInfo(); var buffer = new byte[sizeof(int)]; stream.Read(buffer, 0, sizeof(int)); result.CreateChangeNumber = BitConverter.ToInt32(buffer, 0); stream.Read(buffer, 0, sizeof(int)); result.ExpireChangeNumber = BitConverter.ToInt32(buffer, 0); result.VersionReference = DbItemReference.Read(stream); return(result); }
private DbItemReference GetVersionReferenceByRecordReference(DbItemReference reference) { if (IsVersioningEnabled) { var record = new VersionedRecord(_memoryManager.Get(reference).RawData, _memoryManager, SnapshotData); if (record.HasVisibleVersionTo(DataTankerTransaction.Current.Id)) { reference = record.GetMatchingVersionReference(DataTankerTransaction.Current.Id); } } return(reference); }
/// <summary> /// Fetches value by its reference. /// </summary> /// <param name="reference">Reference to the value</param> /// <returns>The instance of value</returns> public TValue Fetch(DbItemReference reference) { var item = _memoryManager.Get(reference); if (IsVersioningEnabled) { var record = new VersionedRecord(item.RawData, _memoryManager, SnapshotData); if (record.HasVisibleVersionTo(DataTankerTransaction.Current.Id)) { item = record.GetMatchingVersion(DataTankerTransaction.Current.Id); } } return(_valueSerializer.Deserialize(item.RawData)); }
public void MultipageItemSegments() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); var memoryManager = new MemoryManager(fsm, manager); var content = GenerateRandomSequence(4096 * 5 + 100); DbItemReference reference = memoryManager.Allocate(content); // check full content Assert.IsTrue(AreEqualByteArrays(content, memoryManager.GetItemSegment(reference, 0, content.Length - 1))); var bytes = new byte[2]; // check first two bytes Array.Copy(content, 0, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 0, 1))); // check next two bytes Array.Copy(content, 2, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 2, 3))); // check last two bytes Array.Copy(content, content.Length - 2, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, content.Length - 2, content.Length - 1))); //last but two bytes Array.Copy(content, content.Length - 4, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, content.Length - 4, content.Length - 3))); //all except first two bytes and last two bytes bytes = new byte[content.Length - 4]; Array.Copy(content, 2, bytes, 0, content.Length - 4); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 2, content.Length - 3))); } }
public void Remove(DbItemReference reference) { if (_rootNodeReference.Equals(reference)) { throw new ArgumentOutOfRangeException(nameof(reference), "Unable to delete the root node"); } var page = _pageManager.FetchPage(reference.PageIndex); if (page.BackingObject == null) { var obj = RadixTreePageBackingObject.FromPage(page); page = new Page(_pageManager, reference.PageIndex, () => Serialize(obj), obj); } var backingObject = (RadixTreePageBackingObject)page.BackingObject; if (backingObject.Items.Count == reference.ItemIndex + 1) { backingObject.Items.RemoveAt(reference.ItemIndex); } else { backingObject.Items[reference.ItemIndex] = null; } if (backingObject.Items.Any(item => item != null)) { _pageManager.UpdatePage(page); } else { _pageManager.RemovePage(page.Index); if (_recentPages.Contains(page.Index)) { _recentPages.Remove(page.Index); } } }
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); } }
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())); } }
private void CheckRoot() { if (_rootNodeReference == null) { var headerPage = _pageManager.FetchPage(0); _rootPageIndex = ((HeadingPageHeader)PageFormatter.GetPageHeader(headerPage)).AccessMethodPageIndex; var page = _pageManager.FetchPage(_rootPageIndex); var items = PageFormatter.ReadVariableSizeItems(page); if (items.Any()) { // root page already has an item _rootNodeReference = new DbItemReference(_rootPageIndex, 0); } else { var node = new RadixTreeNode(256); PageFormatter.AddVariableSizeItem(page, GetNodeBytes(node, GetNodeSize(0, 256))); _rootNodeReference = new DbItemReference(_rootPageIndex, 0); _pageManager.UpdatePage(page); } } }
/// <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; } } } }
/// <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); } } }
public IRadixTreeNode Fetch(DbItemReference reference) { var str = reference.ToString(); return(_nodes.ContainsKey(str) ? _nodes[str] : null); }
public void Free(DbItemReference reference) { _items.Remove(reference.PageIndex); }
public DbItemReference Reallocate(DbItemReference reference, byte[] newContent) { _items[reference.PageIndex] = newContent; return(new DbItemReference(reference.PageIndex, 0)); }
private KeyValuePair <TKey, DbItemReference> IndexEntryFromBytes(byte[] bytes) { short keyLength = BitConverter.ToInt16(bytes, 0); var keyBytes = new byte[keyLength]; Buffer.BlockCopy(bytes, sizeof(Int16), keyBytes, 0, keyLength); return(new KeyValuePair <TKey, DbItemReference>(_keySerializer.Deserialize(keyBytes), DbItemReference.FromBytes(bytes, _maxKeySize + _keyLengthSize))); }
public DbItem Get(DbItemReference reference) { return(new DbItem(_items[reference.PageIndex])); }
/// <summary> /// Gets the segment of binary representation of value. /// </summary> /// <param name="reference">Reference to the value</param> /// <param name="startIndex">The start index of binary representation</param> /// <param name="endIndex">The end index of binary representation</param> /// <returns>The array of bytes containing specified segment of value</returns> public byte[] GetRawDataSegment(DbItemReference reference, long startIndex, long endIndex) { reference = GetVersionReferenceByRecordReference(reference); return(_memoryManager.GetItemSegment(reference, startIndex, endIndex)); }
/// <summary> /// Retreives the length of value (in bytes) by its reference. /// </summary> /// <param name="reference">Reference to the value</param> /// <returns>The length of referenced value</returns> public long GetRawDataLength(DbItemReference reference) { reference = GetVersionReferenceByRecordReference(reference); return(_memoryManager.GetLength(reference)); }
public long GetLength(DbItemReference reference) { return(_items[reference.PageIndex].Length); }
/// <summary> /// Reallocates already allocated value and produces reference to it. /// </summary> /// <param name="reference">Reference to the already allocated value</param> /// <param name="newValue">New value to allocate</param> /// <returns>Reference to reallocated value</returns> public DbItemReference Reallocate(DbItemReference reference, TValue newValue) { return(_memoryManager.Reallocate(reference, _valueSerializer.Serialize(newValue))); }
/// <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)); }