/// <summary> /// Creates new delta tree describing the new snapshot /// </summary> /// <param name="baseSnapshotId">Base snapshot of the change set</param> /// <param name="newSnapshotId">New snapshot of the change set</param> /// <returns>Delta tree nodes</returns> private INodeProvider<Guid, object, EdgeData> CreateAppendableChangeSetTree(Guid baseSnapshotId, Guid newSnapshotId, IKeyValueStorage<Guid, object> storage, Dictionary<Guid, Guid> nodeMapping, Dictionary<Guid, NodeState> nodeStates, IsolatedChangeSet<Guid, object, EdgeData> changeSet, Hashtable reusedNodes) { DirectNodeProviderUnsafe<Guid, object, EdgeData> delta = new DirectNodeProviderUnsafe<Guid, object, EdgeData>(storage, storage is IForceUpdateStorage); // Create snapshot in delta nodeMapping.Add(baseSnapshotId, newSnapshotId); var snapshotNode = new Node<Guid, object, EdgeData>(NodeType.Snapshot, null); snapshotNode.Previous = baseSnapshotId; // Link to root object snapshotNode.AddEdge(new Edge<Guid, EdgeData>(snapshotsService.GetRootObjectId(baseSnapshotId), new EdgeData(EdgeType.RootObject, null))); // Set node to provider delta.SetNode(newSnapshotId, snapshotNode); // Add all changes and parent nodes foreach (Guid nodeId in changeSet.Nodes.EnumerateNodes()) { AddNodeToAppendableTreeRecursive(delta, nodeId, nodeMapping, nodeStates, changeSet); } // Prepare list of unreferenced node IDs Dictionary<Guid, Collection<Guid>> references = new Dictionary<Guid, Collection<Guid>>(); // Resolve edges based on mapping foreach (Guid nodeId in delta.EnumerateNodes()) { references.Add(nodeId, new Collection<Guid>()); } // Resolve edges based on mapping foreach (Guid nodeId in delta.EnumerateNodes()) { var node = delta.GetNode(nodeId, NodeAccess.ReadWrite); foreach (var edge in node.Edges.Values) { // Permanent edges should not be touched if (!Utils.IsPermanentEdge(edge)) { // Reroute based on node mapping if (nodeMapping.ContainsKey(edge.ToNodeId)) { edge.ToNodeId = nodeMapping[edge.ToNodeId]; } else { if (!reusedNodes.ContainsKey(edge.ToNodeId)) { reusedNodes.Add(edge.ToNodeId, null); } } // Change edge data if it points to changed node if (edge.Data.Data != null && edge.Data.Data is Guid) { if (nodeMapping.ContainsKey((Guid)edge.Data.Data)) { edge.Data = new EdgeData(edge.Data.Semantic, nodeMapping[(Guid)edge.Data.Data]); } } } else { if (!reusedNodes.ContainsKey(edge.ToNodeId)) { reusedNodes.Add(edge.ToNodeId, null); } } if (references.ContainsKey(edge.ToNodeId)) { references[edge.ToNodeId].Add(nodeId); } } } // Remove remaining unreferenced nodes bool removed = false; do { removed = false; foreach (Guid key in delta.EnumerateNodes()) { // There are no references to the key if ((key!=newSnapshotId) && (references[key].Count == 0)) { #if DEBUG Debug.WriteLine("Removed unreferenced key " + key); #endif delta.Remove(key); reusedNodes.Remove(key); nodeStates.Remove(key); foreach (Guid otherKey in references.Keys) { references[otherKey].Remove(key); } foreach (var mappingKey in nodeMapping.Keys) { if (nodeMapping[mappingKey] == key) { nodeMapping.Remove(mappingKey); break; } } removed = true; break; } } } while (removed); // Isolated provider nodes have been corrupted, perform clear changeSet.Nodes.Clear(); changeSet.NodeStates.Clear(); return delta; }
/// <summary> /// Creates new delta tree describing the new snapshot /// </summary> /// <param name="baseSnapshotId">Base snapshot of the change set</param> /// <param name="newSnapshotId">New snapshot of the change set</param> /// <returns>Delta tree nodes</returns> private INodeProvider <Guid, object, EdgeData> CreateAppendableChangeSetTree(Guid baseSnapshotId, Guid newSnapshotId, IKeyValueStorage <Guid, object> storage, Dictionary <Guid, Guid> nodeMapping, Dictionary <Guid, NodeState> nodeStates, IsolatedChangeSet <Guid, object, EdgeData> changeSet, Hashtable reusedNodes) { DirectNodeProviderUnsafe <Guid, object, EdgeData> delta = new DirectNodeProviderUnsafe <Guid, object, EdgeData>(storage, storage is IForceUpdateStorage); // Create snapshot in delta nodeMapping.Add(baseSnapshotId, newSnapshotId); var snapshotNode = new Node <Guid, object, EdgeData>(NodeType.Snapshot, null); snapshotNode.Previous = baseSnapshotId; // Link to root object snapshotNode.AddEdge(new Edge <Guid, EdgeData>(snapshotsService.GetRootObjectId(baseSnapshotId), new EdgeData(EdgeType.RootObject, null))); // Set node to provider delta.SetNode(newSnapshotId, snapshotNode); // Add all changes and parent nodes foreach (Guid nodeId in changeSet.Nodes.EnumerateNodes()) { AddNodeToAppendableTreeRecursive(delta, nodeId, nodeMapping, nodeStates, changeSet); } // Prepare list of unreferenced node IDs Dictionary <Guid, Collection <Guid> > references = new Dictionary <Guid, Collection <Guid> >(); // Resolve edges based on mapping foreach (Guid nodeId in delta.EnumerateNodes()) { references.Add(nodeId, new Collection <Guid>()); } // Resolve edges based on mapping foreach (Guid nodeId in delta.EnumerateNodes()) { var node = delta.GetNode(nodeId, NodeAccess.ReadWrite); foreach (var edge in node.Edges.Values) { // Permanent edges should not be touched if (!Utils.IsPermanentEdge(edge)) { // Reroute based on node mapping if (nodeMapping.ContainsKey(edge.ToNodeId)) { edge.ToNodeId = nodeMapping[edge.ToNodeId]; } else { if (!reusedNodes.ContainsKey(edge.ToNodeId)) { reusedNodes.Add(edge.ToNodeId, null); } } // Change edge data if it points to changed node if (edge.Data.Data != null && edge.Data.Data is Guid) { if (nodeMapping.ContainsKey((Guid)edge.Data.Data)) { edge.Data = new EdgeData(edge.Data.Semantic, nodeMapping[(Guid)edge.Data.Data]); } } } else { if (!reusedNodes.ContainsKey(edge.ToNodeId)) { reusedNodes.Add(edge.ToNodeId, null); } } if (references.ContainsKey(edge.ToNodeId)) { references[edge.ToNodeId].Add(nodeId); } } } // Remove remaining unreferenced nodes bool removed = false; do { removed = false; foreach (Guid key in delta.EnumerateNodes()) { // There are no references to the key if ((key != newSnapshotId) && (references[key].Count == 0)) { #if DEBUG Debug.WriteLine("Removed unreferenced key " + key); #endif delta.Remove(key); reusedNodes.Remove(key); nodeStates.Remove(key); foreach (Guid otherKey in references.Keys) { references[otherKey].Remove(key); } foreach (var mappingKey in nodeMapping.Keys) { if (nodeMapping[mappingKey] == key) { nodeMapping.Remove(mappingKey); break; } } removed = true; break; } } }while (removed); // Isolated provider nodes have been corrupted, perform clear changeSet.Nodes.Clear(); changeSet.NodeStates.Clear(); return(delta); }