public void TestFillRemove() { INodeProvider <Guid, object, EdgeData> nodes = new DirectNodeProviderSafe <Guid, object, EdgeData>(new MemoryStorageUnsafe <Guid, object>(), false); Guid rootId = Guid.NewGuid(); Node <Guid, object, EdgeData> node = BPlusTreeOperations.CreateRootNode(NodeType.Collection, rootId); nodes.SetNode(rootId, node); Collection <Guid> references = new Collection <Guid>(); for (int i = 0; i < 1000; i++) { references.Add(Guid.NewGuid()); } int count = 0; foreach (var reference in references) { Assert.AreEqual(count, BPlusTreeOperations.Count(nodes, rootId, EdgeType.ListItem)); BPlusTreeOperations.InsertEdge(nodes, rootId, new Edge <Guid, EdgeData>(reference, new EdgeData(EdgeType.ListItem, reference)), TreeOrder); count++; } foreach (var reference in references) { Assert.AreEqual(count, BPlusTreeOperations.Count(nodes, rootId, EdgeType.ListItem)); BPlusTreeOperations.RemoveEdge(nodes, rootId, new EdgeData(EdgeType.ListItem, reference), TreeOrder); count--; } }
internal void SetReference(Guid instanceId, object key, Guid referenceId) { if (!BPlusTreeOperations.TrySetEdgeToNode(provider, instanceId, new EdgeData(EdgeType.ListItem, key), referenceId)) { throw new KeyNotFoundException("Item not found with the specified key"); } }
/// <summary> /// Initialize global root node if not found /// </summary> private void InitializeRoot() { if (!nodes.Contains(Constants.SnapshotsNodeId)) { var node = BPlusTreeOperations.CreateRootNode(NodeType.Collection, Constants.SnapshotsNodeId); nodes.SetNode(Constants.SnapshotsNodeId, node); } }
/// <summary> /// Determines if there is change set information for given snapshot /// </summary> /// <param name="snapshotId">Snapshot Id to query</param> /// <returns>True if data exists</returns> public bool ContainsSnapshot(Guid snapshotId) { lock (sync) { Edge <Guid, EdgeData> edge = null; return(BPlusTreeOperations.TryFindEdge(nodes, Constants.SnapshotsNodeId, new EdgeData(EdgeType.ListItem, snapshotId), out edge)); } }
/// <summary> /// Removes information for a snapshot /// </summary> /// <param name="snapshotId">Snapshot ID to remove</param> public void RemoveChangeSet(Guid snapshotId) { lock (sync) { // Remove from snapshots list if (BPlusTreeOperations.RemoveEdge(nodes, Constants.SnapshotsNodeId, new EdgeData(EdgeType.ListItem, snapshotId), TreeOrder)) { DeleteTree(snapshotId); } } }
internal void AddScalar(Guid instanceId, Guid itemTypeId, object key, object value) { Guid id = Guid.NewGuid(); // Create new value node var node = new Node <Guid, object, EdgeData>(NodeType.Scalar, value); provider.SetNode(id, node); BPlusTreeOperations.InsertEdge(provider, instanceId, new Edge <Guid, EdgeData>(id, new EdgeData(EdgeType.ListItem, key)), BPlusTreeOrder); }
internal long MaxOrderedIdentifier(Guid instanceId) { if (Count(instanceId) == 0) { return((long)0); } else { return((long)BPlusTreeOperations.RightEdge(provider, provider.GetNode(instanceId, NodeAccess.Read)).Data.Data); } }
private void FindTreeAddedElements(Guid nodeId, RecursiveResolutionParameters parameters, out Dictionary <EdgeData, Edge <Guid, EdgeData> > addedElements, out Dictionary <EdgeData, Edge <Guid, EdgeData> > removedElements) { addedElements = new Dictionary <EdgeData, Edge <Guid, EdgeData> >(); removedElements = new Dictionary <EdgeData, Edge <Guid, EdgeData> >(); // TODO (nsabo) Optimize searching by new ID value Guid originalNodeId = Guid.Empty; foreach (var item in parameters.IntermediateChanges) { if (item.Value.Equals(nodeId)) { originalNodeId = item.Key; break; } } if (originalNodeId == Guid.Empty) { originalNodeId = nodeId; } // Go through changed list and see if some item has not been included in the last version using (var enumerator = BPlusTreeOperations.GetEnumerator(parameters.SourceProvider, originalNodeId, EdgeType.ListItem)) { while (enumerator.MoveNext()) { var edge = enumerator.Current; Edge <Guid, EdgeData> foundEdge = null; // Try finding the element in last version if (!BPlusTreeOperations.TryFindEdge(nodes, originalNodeId, edge.Data, out foundEdge)) { addedElements.Add(edge.Data, edge); } } } // Go through last version and see if there are elements which are not found in changed list using (var enumerator = BPlusTreeOperations.GetEnumerator(nodes, originalNodeId, EdgeType.ListItem)) { while (enumerator.MoveNext()) { var edge = enumerator.Current; Edge <Guid, EdgeData> foundEdge = null; // Try finding the element in last version if (!BPlusTreeOperations.TryFindEdge(parameters.SourceProvider, originalNodeId, edge.Data, out foundEdge)) { removedElements.Add(edge.Data, edge); } } } }
internal Guid GetInstanceTypeId(Guid referenceId) { Edge <Guid, EdgeData> edge = null; if (BPlusTreeOperations.TryFindEdge(provider, referenceId, new EdgeData(EdgeType.OfType, null), out edge)) { return(edge.ToNodeId); } else { return(Guid.Empty); } }
internal void SetScalar(Guid instanceId, Guid itemTypeId, object key, object value) { Guid id = Guid.NewGuid(); // Create new value node var node = new Node <Guid, object, EdgeData>(NodeType.Scalar, value); provider.SetNode(id, node); if (!BPlusTreeOperations.TrySetEdgeToNode(provider, instanceId, new EdgeData(EdgeType.ListItem, key), id)) { throw new KeyNotFoundException("Item not found with the specified key"); } }
internal bool RemoveReference(Guid instanceId, Guid referenceId) { using (var enumerator = GetEnumerator(instanceId)) { while (enumerator.MoveNext()) { if (enumerator.Current.ToNodeId.Equals(referenceId)) { return(BPlusTreeOperations.RemoveEdge(provider, instanceId, enumerator.Current.Data, BPlusTreeOrder)); } } return(false); } }
internal bool TryGetReference(Guid instanceId, object key, out Guid referenceId) { Edge <Guid, EdgeData> edge = null; if (BPlusTreeOperations.TryFindEdge(provider, instanceId, new EdgeData(EdgeType.ListItem, key), out edge)) { referenceId = edge.ToNodeId; return(true); } else { referenceId = Guid.Empty; return(false); } }
internal bool TryGetScalar(Guid instanceId, object key, out object value) { Edge <Guid, EdgeData> edge = null; if (BPlusTreeOperations.TryFindEdge(provider, instanceId, new EdgeData(EdgeType.ListItem, key), out edge)) { value = provider.GetNode(edge.ToNodeId, NodeAccess.Read).Data; return(true); } else { value = null; return(false); } }
internal bool RemoveScalar(Guid instanceId, object value) { using (var enumerator = GetEnumerator(instanceId)) { while (enumerator.MoveNext()) { var node = provider.GetNode(enumerator.Current.ToNodeId, NodeAccess.Read); if (node.Data.Equals(value)) { return(BPlusTreeOperations.RemoveEdge(provider, instanceId, enumerator.Current.Data, BPlusTreeOrder)); } } return(false); } }
/// <summary> /// Initializes new dictionary instance /// </summary> /// <param name="typeId">Type ID of dictionary</param> /// <returns>Instance ID</returns> public Guid NewInstance(Guid typeId) { //Determine new id Guid id = Guid.NewGuid(); // Create node as root of B+ tree var node = BPlusTreeOperations.CreateRootNode(NodeType.Dictionary, id); // Add node in provider provider.SetNode(id, node); // Add edge from node to the type of node BPlusTreeOperations.InsertEdge(provider, id, new Edge <Guid, EdgeData>(typeId, new EdgeData(EdgeType.OfType, null)), BPlusTreeOrder); // Add node in provider provider.SetNode(id, node); // Return the instance id return(id); }
/// <summary> /// Provides change set edges for given snapshot /// </summary> /// <param name="snapshotId">Snapshot ID</param> /// <returns>Change set edge enumerator</returns> public IEnumerator <Edge <Guid, EdgeData> > GetChangeSetEdges(Guid snapshotId) { lock (sync) { Edge <Guid, EdgeData> edge = null; if (BPlusTreeOperations.TryFindEdge(nodes, Constants.SnapshotsNodeId, new EdgeData(EdgeType.ListItem, snapshotId), out edge)) { return(BPlusTreeOperations.GetEnumerator(nodes, snapshotId, EdgeType.ListItem)); } else { // Returtn empty enumerator return(new Collection <Edge <Guid, EdgeData> >().GetEnumerator()); } } }
internal void Clear(Guid instanceId) { var removalKeys = new Collection <EdgeData>(); using (var enumerator = GetEnumerator(instanceId)) { while (enumerator.MoveNext()) { removalKeys.Add(enumerator.Current.Data); } } foreach (var key in removalKeys) { BPlusTreeOperations.RemoveEdge(provider, instanceId, key, BPlusTreeOrder); } }
/// <summary> /// Stores collectable nodes for a change set /// </summary> /// <param name="changeSet">Change set</param> /// <param name="mutableParentMap">Parent map of mutable data</param> /// <param name="immutableParentMap">Parent map of immutable data</param> public void StoreChangeset(AppendableChangeSet <Guid, object, EdgeData> changeSet, IParentMapProvider <Guid, object, EdgeData> mutableParentMap, IParentMapProvider <Guid, object, EdgeData> immutableParentMap) { Guid snapshotId = changeSet.SourceSnapshotId; var snapshotRoot = BPlusTreeOperations.CreateRootNode(NodeType.Collection, snapshotId); nodes.SetNode(snapshotId, snapshotRoot); Hashtable collectedNodes = new Hashtable(); GetCollectedNodesRecursive(changeSet.SourceSnapshotId, changeSet, mutableParentMap, immutableParentMap, collectedNodes, new Hashtable()); foreach (Guid nodeId in collectedNodes.Keys) { BPlusTreeOperations.InsertEdge(nodes, snapshotId, new Edge <Guid, EdgeData>(nodeId, new EdgeData(EdgeType.ListItem, nodeId)), TreeOrder); } }
/// <summary> /// Stores the change set /// </summary> /// <param name="changeSet">Change set to store</param> public void SetChangeSet(AppendableChangeSet <Guid, object, EdgeData> changeSet) { lock (sync) { var snapshotNode = BPlusTreeOperations.CreateRootNode(NodeType.Dictionary, changeSet.DestinationSnapshotId); nodes.SetNode(changeSet.DestinationSnapshotId, snapshotNode); // Add all changes from changeset to snapshot tree. foreach (var item in changeSet.Mapping) { BPlusTreeOperations.InsertEdge(nodes, changeSet.DestinationSnapshotId, new Edge <Guid, EdgeData>(item.Value, new EdgeData(EdgeType.ListItem, item.Key)), TreeOrder); } // Add snapshot to collection BPlusTreeOperations.InsertEdge(nodes, Constants.SnapshotsNodeId, new Edge <Guid, EdgeData>(changeSet.DestinationSnapshotId, new EdgeData(EdgeType.ListItem, changeSet.DestinationSnapshotId)), TreeOrder); } }
/// <summary> /// Recursive breadth-first pass through node graph which generates parent information /// </summary> /// <param name="snapshotId">Snapshot to generate</param> /// <param name="nodeId">Visited node</param> /// <param name="visitedNodes">List of visited nodes</param> private void AddParentsRecursive(Guid nodeId, Hashtable visitedNodes, INodeProvider <Guid, object, EdgeData> nodes) { if (nodeId.Equals(Constants.NullReferenceNodeId)) { return; } if (visitedNodes.ContainsKey(nodeId)) { return; } else { visitedNodes.Add(nodeId, null); } // Add the node as parent of all child nodes foreach (var edge in dataNodeProvider.GetNode(nodeId, NodeAccess.Read).Edges.Values) { if (EdgeFilter(edge)) { if (!nodes.Contains(edge.ToNodeId)) { var holderNode = BPlusTreeOperations.CreateRootNode(NodeType.Collection, edge.ToNodeId); nodes.SetNode(edge.ToNodeId, holderNode); } var edgeData = new EdgeData(EdgeType.Contains, nodeId); Edge <Guid, EdgeData> existingEdge = null; if (!BPlusTreeOperations.TryFindEdge(nodes, edge.ToNodeId, edgeData, out existingEdge)) { BPlusTreeOperations.InsertEdge(nodes, edge.ToNodeId, new Edge <Guid, EdgeData>(nodeId, edgeData), ParentsTreeOrder); } } } foreach (var edge in dataNodeProvider.GetNode(nodeId, NodeAccess.Read).Edges.Values) { AddParentsRecursive(edge.ToNodeId, visitedNodes, nodes); } }
public void TestConsistency() { INodeProvider <Guid, object, EdgeData> nodes = new DirectNodeProviderSafe <Guid, object, EdgeData>(new MemoryStorageUnsafe <Guid, object>(), false); Guid rootId = Guid.NewGuid(); Node <Guid, object, EdgeData> node = BPlusTreeOperations.CreateRootNode(NodeType.Collection, rootId); nodes.SetNode(rootId, node); Collection <Guid> references = new Collection <Guid>(); Collection <Guid> referencesAdded = new Collection <Guid>(); for (int i = 0; i < 1000; i++) { references.Add(Guid.NewGuid()); } foreach (var reference in references) { var data = new EdgeData(EdgeType.ListItem, reference); BPlusTreeOperations.InsertEdge(nodes, rootId, new Edge <Guid, EdgeData>(reference, data), TreeOrder); referencesAdded.Add(reference); foreach (var addedReference in referencesAdded) { var dataAdded = new EdgeData(EdgeType.ListItem, addedReference); Edge <Guid, EdgeData> edge; Assert.IsTrue(BPlusTreeOperations.TryFindEdge(nodes, rootId, dataAdded, out edge)); Assert.AreEqual(addedReference, edge.Data.Data); } } foreach (var reference in references) { var data = new EdgeData(EdgeType.ListItem, reference); Edge <Guid, EdgeData> edge; Assert.IsTrue(BPlusTreeOperations.TryFindEdge(nodes, rootId, data, out edge)); Assert.AreEqual(reference, edge.Data.Data); Assert.AreEqual(reference, edge.ToNodeId); } }
/// <summary> /// Returns list of parents for given node witin a snapshot /// </summary> /// <param name="snapshotId">Snapshot within parents are requested</param> /// <param name="nodeId">Node which parents are returned</param> /// <returns>List of parent node identifiers for each node in dictionary format, or null if there are no parent edges</returns> public IEnumerator <Edge <Guid, EdgeData> > ParentEdges(Guid snapshotId, Guid nodeId) { lock (dataSync) { // Generate parents if they dont exist if (!createdNodes) { createdNodes = true; AddParentsRecursive(snapshotId, new Hashtable(), nodes); lastSnapshotId = snapshotId; } // Do we have the last snapshot in the memory if (snapshotId != lastSnapshotId) { // Try going for fallback provider if (fallbackParentMapProvider != null) { return(fallbackParentMapProvider.ParentEdges(snapshotId, nodeId)); } else { // If not, generate asked snapshot nodes.Clear(); AddParentsRecursive(snapshotId, new Hashtable(), nodes); lastSnapshotId = snapshotId; } } // Find edge leading to holder node for given ID if (nodes.Contains(nodeId)) { return(BPlusTreeOperations.GetEnumerator(nodes, nodeId, EdgeType.Contains)); } else { return(null); } } }
private static void LogCollection(Guid nodeId, Node <Guid, object, EdgeData> node, INodeProvider <Guid, object, EdgeData> nodes, INodeProvider <Guid, object, EdgeData> changes, int tabLevel, Hashtable visited, TypesService typesService) { Edge <Guid, EdgeData> typeEdge = null; BPlusTreeOperations.TryFindEdge(nodes, nodeId, new EdgeData(EdgeType.OfType, null), out typeEdge); var typeId = typeEdge.ToNodeId; var typeName = typesService.GetTypeFromId(typeId).Name; Debug.WriteLine(LogTabs(tabLevel) + nodeId + "(" + typeName + ")"); Debug.WriteLine(LogTabs(tabLevel) + "Previous=" + node.Previous); using (var enumeration = BPlusTreeOperations.GetEnumerator(nodes, nodeId, EdgeType.ListItem)) { while (enumeration.MoveNext()) { Debug.WriteLine(LogTabs(tabLevel) + enumeration.Current.Data + "="); LogNodesRecursive(enumeration.Current.ToNodeId, nodes, changes, tabLevel + 1, visited, typesService); } } }
internal bool Remove(Guid instanceId, object key) { return(BPlusTreeOperations.RemoveEdge(provider, instanceId, new EdgeData(EdgeType.ListItem, key), BPlusTreeOrder)); }
internal IEnumerator <Edge <Guid, EdgeData> > GetEnumerator(Guid instanceId) { return(BPlusTreeOperations.GetEnumerator(provider, instanceId, EdgeType.ListItem)); }
internal bool ContainsKey(Guid instanceId, object key) { Edge <Guid, EdgeData> edge = null; return(BPlusTreeOperations.TryFindEdge(provider, instanceId, new EdgeData(EdgeType.ListItem, key), out edge)); }
internal void AddReference(Guid instanceId, object key, Guid referenceId) { BPlusTreeOperations.InsertEdge(provider, instanceId, new Edge <Guid, EdgeData>(referenceId, new EdgeData(EdgeType.ListItem, key)), BPlusTreeOrder); }
internal int Count(Guid instanceId) { return(BPlusTreeOperations.Count(provider, instanceId, EdgeType.ListItem)); }
/// <summary> /// Returns edges to collectable nodes for a snapshot /// </summary> /// <param name="snapshotId">Snapshot identifier</param> /// <returns>Enumerator of edges towards collectable nodes</returns> public IEnumerator <Edge <Guid, EdgeData> > GetEdges(Guid snapshotId) { return(BPlusTreeOperations.GetEnumerator(nodes, snapshotId, EdgeType.ListItem)); }
/// <summary> /// Updates parent information based on change set /// </summary> /// <param name="changeSet">Data change description</param> public void UpdateParents(AppendableChangeSet <Guid, object, EdgeData> changeSet, ICollectedNodesProvider <Guid, object, EdgeData> collectedNodesProvider) { lock (dataSync) { if (changeSet.SourceSnapshotId != lastSnapshotId) { // If the last snapshot is not in the memory, clear and return nodes.Clear(); createdNodes = false; return; } using (var enumerator = collectedNodesProvider.GetEdges(changeSet.SourceSnapshotId)) { if (enumerator != null) { while (enumerator.MoveNext()) { if (nodes.Contains(enumerator.Current.ToNodeId)) { DeleteTree(enumerator.Current.ToNodeId); } // Get the old node var node = dataNodeProvider.GetNode(enumerator.Current.ToNodeId, NodeAccess.Read); // For every edge in old node foreach (var edge in node.Edges.Values) { if (EdgeFilter(edge)) { // Find holder in destination snapshot for referenced node if (nodes.Contains(edge.ToNodeId)) { BPlusTreeOperations.RemoveEdge(nodes, edge.ToNodeId, new EdgeData(EdgeType.Contains, enumerator.Current.ToNodeId), ParentsTreeOrder); } } } } } } // Add new node ids to map foreach (Guid nodeId in changeSet.Nodes.EnumerateNodes()) { var holderNode = BPlusTreeOperations.CreateRootNode(NodeType.Collection, nodeId); nodes.SetNode(nodeId, holderNode); } // Add reused nodes if needed foreach (Guid nodeId in changeSet.ReusedNodes.Keys) { if (!nodes.Contains(nodeId)) { var holderNode = BPlusTreeOperations.CreateRootNode(NodeType.Collection, nodeId); nodes.SetNode(nodeId, holderNode); } } // Add new node edges to map foreach (Guid nodeId in changeSet.Nodes.EnumerateNodes()) { var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.Read); // Add this id into all referenced nodes foreach (var edge in node.Edges.Values) { if (EdgeFilter(edge)) { var edgeData = new EdgeData(EdgeType.Contains, nodeId); Edge <Guid, EdgeData> existingEdge = null; if (!BPlusTreeOperations.TryFindEdge(nodes, edge.ToNodeId, edgeData, out existingEdge)) { BPlusTreeOperations.InsertEdge(nodes, edge.ToNodeId, new Edge <Guid, EdgeData>(nodeId, edgeData), ParentsTreeOrder); } } } } // Set last snapshot as the destination ID lastSnapshotId = changeSet.DestinationSnapshotId; } }