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 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); }
/// <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> /// 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); } }
internal void AddReference(Guid instanceId, object key, Guid referenceId) { BPlusTreeOperations.InsertEdge(provider, instanceId, new Edge <Guid, EdgeData>(referenceId, new EdgeData(EdgeType.ListItem, key)), BPlusTreeOrder); }
/// <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; } }
internal void AddReference(Guid instanceId, Guid referenceId) { var data = Guid.NewGuid(); BPlusTreeOperations.InsertEdge(provider, instanceId, new Edge <Guid, EdgeData>(referenceId, new EdgeData(EdgeType.ListItem, data)), BPlusTreeOrder); }
private void MergeRecursive(Guid nodeId, RecursiveResolutionParameters parameters) { if (parameters.VisitedNodes.ContainsKey(nodeId)) { return; } parameters.VisitedNodes.Add(nodeId, null); // Are we within the last snapshot affected sub tree if (parameters.SubTree.ContainsKey(nodeId)) { // Create node which we will change var node = parameters.DestinationProvider.GetNode(nodeId, NodeAccess.ReadWrite); // Perform the change depending on node type switch (node.NodeType) { case NodeType.Snapshot: foreach (var edge in node.Edges.Values) { MergeRecursive(edge.ToNodeId, parameters); } break; case NodeType.Scalar: throw new NotImplementedException("TODO"); case NodeType.Object: { // Is there a change in the changeset with conflicting change? // TODO (nsabo) Optimize searching by new ID value Guid changeNodeId = (Guid)parameters.SubTree[nodeId]; if (changeNodeId != Guid.Empty) { var changedNode = parameters.ChangeSet.Nodes.GetNode(changeNodeId, NodeAccess.Read); var originalNode = nodes.GetNode(changeNodeId, NodeAccess.Read); nodeMergeExecutor.MergeObjects(nodeId, originalNode, changedNode, node, new MergeRecursiveDelegate(MergeRecursive), new InsertRecursiveDelegate(InsertRecursive), parameters); } else { var changedNode = parameters.ChangeSet.Nodes.GetNode(nodeId, NodeAccess.Read); if (changedNode != null) { nodeMergeExecutor.ChangeObject(nodeId, changedNode, node, new MergeRecursiveDelegate(MergeRecursive), new InsertRecursiveDelegate(InsertRecursive), parameters); } else { // Follow edges foreach (var item in node.Edges.Values) { MergeRecursive(item.ToNodeId, parameters); } } } break; } case NodeType.Collection: case NodeType.Dictionary: { var treeOrder = node.NodeType == NodeType.Collection ? CollectionInstancesService.BPlusTreeOrder : DictionaryInstancesService.BPlusTreeOrder; // Search the changeset for new added elements Dictionary <EdgeData, Edge <Guid, EdgeData> > addedEdges = null; Dictionary <EdgeData, Edge <Guid, EdgeData> > removedEdges = null; FindTreeAddedElements(nodeId, parameters, out addedEdges, out removedEdges); foreach (var addedEdge in addedEdges.Values) { // Add node in the isolated provider InsertRecursive(addedEdge.ToNodeId, parameters); // Create edge from the current collection BPlusTreeOperations.InsertEdge(parameters.DestinationProvider, nodeId, addedEdge, treeOrder); } foreach (var removedEdge in removedEdges.Values) { BPlusTreeOperations.RemoveEdge(parameters.DestinationProvider, nodeId, removedEdge.Data, treeOrder); } // Enumerate through existing elements and look for their changes using (var enumerator = BPlusTreeOperations.GetEnumerator(nodes, nodeId, EdgeType.ListItem)) { while (enumerator.MoveNext()) { if (!addedEdges.ContainsKey(enumerator.Current.Data) && !removedEdges.ContainsKey(enumerator.Current.Data)) { MergeRecursive(enumerator.Current.ToNodeId, parameters); } } } break; } default: throw new ArgumentException("Unexpected node type in tree :" + node.NodeType); } parameters.DestinationProvider.SetNode(nodeId, node); } }