public void ChangeObject(Guid nodeId, Node<Guid, object, EdgeData> changedNode, Node<Guid, object, EdgeData> node, MergeRecursiveDelegate mergeRecursive, InsertRecursiveDelegate insertRecursive, RecursiveResolutionParameters parameters) { // Consolidate the values foreach (var item in changedNode.Values) { node.Values[item.Key] = item.Value; } // Consolidate the edges foreach (var edge in changedNode.Edges) { Guid newReference = edge.Value.ToNodeId; NodeState nodeState = NodeState.None; parameters.ChangeSet.NodeStates.TryGetValue(newReference, out nodeState); // If changed node is a new node go into the changed node recursion if (nodeState == NodeState.Created) { // Set the new reference node.SetEdgeToNode(edge.Value.Data, newReference); // Insert the new nodes insertRecursive(newReference, parameters); } else { // Set the new reference node.SetEdgeToNode(edge.Value.Data, newReference); // Follow the new reference and see changes mergeRecursive(newReference, parameters); } } }
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); } } } }
private void InsertRecursive(Guid nodeId, RecursiveResolutionParameters parameters) { if (parameters.VisitedNodes.ContainsKey(nodeId)) { return; } parameters.VisitedNodes.Add(nodeId, null); Node <Guid, object, EdgeData> node = null; // Get new node from changeset if (parameters.ChangeSet.Nodes.Contains(nodeId)) { node = parameters.ChangeSet.Nodes.GetNode(nodeId, NodeAccess.Read); } else { node = nodes.GetNode(nodeId, NodeAccess.Read); } // Process edges foreach (var item in node.Edges) { // Upgrade reference to existing object when changed Guid newReferenceId = Guid.Empty; if (!Utils.IsPermanentEdge(item.Value) && // Not permanent edge parameters.IntermediateChanges.TryGetValue(item.Value.ToNodeId, out newReferenceId)) // There is newer version { // Update new reference node.Edges[item.Key].ToNodeId = newReferenceId; } // Follow reference to new object NodeState referenceState = NodeState.None; if (parameters.ChangeSet.NodeStates.TryGetValue(item.Value.ToNodeId, out referenceState)) { if (referenceState == NodeState.Created) { InsertRecursive(item.Value.ToNodeId, parameters); } } } parameters.DestinationProvider.SetNode(nodeId, node); }
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); } }
private void InsertRecursive(Guid nodeId, RecursiveResolutionParameters parameters) { if (parameters.VisitedNodes.ContainsKey(nodeId)) { return; } parameters.VisitedNodes.Add(nodeId, null); Node<Guid, object, EdgeData> node = null; // Get new node from changeset if (parameters.ChangeSet.Nodes.Contains(nodeId)) { node = parameters.ChangeSet.Nodes.GetNode(nodeId, NodeAccess.Read); } else { node = nodes.GetNode(nodeId, NodeAccess.Read); } // Process edges foreach (var item in node.Edges) { // Upgrade reference to existing object when changed Guid newReferenceId = Guid.Empty; if (!Utils.IsPermanentEdge(item.Value) && // Not permanent edge parameters.IntermediateChanges.TryGetValue(item.Value.ToNodeId, out newReferenceId)) // There is newer version { // Update new reference node.Edges[item.Key].ToNodeId = newReferenceId; } // Follow reference to new object NodeState referenceState = NodeState.None; if (parameters.ChangeSet.NodeStates.TryGetValue(item.Value.ToNodeId, out referenceState)) { if (referenceState == NodeState.Created) { InsertRecursive(item.Value.ToNodeId, parameters); } } } parameters.DestinationProvider.SetNode(nodeId, node); }
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); } } } }
public void MergeObjects(Guid nodeId, Node<Guid, object, EdgeData> originalNode, Node<Guid, object, EdgeData> changedNode, Node<Guid, object, EdgeData> node, MergeRecursiveDelegate mergeRecursive, InsertRecursiveDelegate insertRecursive, RecursiveResolutionParameters parameters) { Guid typeId = typesService.GetInstanceTypeId(originalNode); if (!objectAttributeProvider.IsConcurrent(typeId)) { var instanceType = typesService.GetTypeFromId(typesService.GetInstanceTypeId(nodeId)); throw new ConcurrentModificationException("Concurrent modification not allowed for entity type:" + instanceType.ToString()); } if (objectAttributeProvider.IsStaticConcurrency(typeId)) { MergeObjectsStatic(nodeId, typeId, originalNode, changedNode, node, mergeRecursive, insertRecursive, parameters); } else { throw new NotImplementedException("Dynamic concurrency not implemented"); } }
private void MergeObjectsStatic(Guid nodeId, Guid typeId, Node<Guid, object, EdgeData> originalNode, Node<Guid, object, EdgeData> changedNode, Node<Guid, object, EdgeData> node, MergeRecursiveDelegate mergeRecursive, InsertRecursiveDelegate insertRecursive, RecursiveResolutionParameters parameters) { // Consolidate the values foreach (var item in originalNode.Values) { // Value was changed compared to previous version if (!changedNode.Values[item.Key].Equals(item.Value)) { // Try setting value in the node, if it is still the same if (node.Values[item.Key].Equals(item.Value)) { node.Values[item.Key] = changedNode.Values[item.Key]; } else { if (objectAttributeProvider.IsMemberOverride(typeId, item.Key)) { // Override with changed value node.Values[item.Key] = changedNode.Values[item.Key]; } else { throw new ConcurrentModificationException("Concurrent modification of scalar value not allowed in type:" + typesService.GetTypeFromId(typeId).ToString() + " for member " + typesService.GetMemberName(typeId, item.Key)); } } } } // Consolidate the edges foreach (var edge in originalNode.Edges) { // Value was changed compared to previous version if (!changedNode.Edges[edge.Key].ToNodeId.Equals(edge.Value.ToNodeId)) { // Was member set to override? bool isOverride = objectAttributeProvider.IsMemberOverride(typeId, (Guid)edge.Key.Data); // Try setting value in the node, if it is still the same or if override is set if (node.Edges[edge.Key].ToNodeId.Equals(edge.Value.ToNodeId) || isOverride) { Guid newReference = changedNode.Edges[edge.Key].ToNodeId; Guid newReferenceUpdated = Guid.Empty; // Is there an intermediate change? if (parameters.IntermediateChanges.TryGetValue(newReference, out newReferenceUpdated)) { // Set edge to node from the changed node node.SetEdgeToNode(edge.Value.Data, newReferenceUpdated); // See about the new object mergeRecursive(newReferenceUpdated, parameters); } else { NodeState nodeState = NodeState.None; parameters.ChangeSet.NodeStates.TryGetValue(newReference, out nodeState); // If changed node is a new node go into the changed node recursion if (nodeState == NodeState.Created) { // Set the new reference node.SetEdgeToNode(edge.Value.Data, newReference); // Insert the new nodes insertRecursive(newReference, parameters); } else { // Set the new reference node.SetEdgeToNode(edge.Value.Data, newReference); // Follow the new reference and see changes mergeRecursive(newReference, parameters); } } } else { throw new ConcurrentModificationException("Concurrent modification of referenced item not allowed in type:" + typesService.GetTypeFromId(typeId).ToString() + " for member " + typesService.GetMemberName(typeId, (Guid)edge.Key.Data)); } } else { mergeRecursive(node.Edges[edge.Key].ToNodeId, parameters); } } }
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); } }