Example #1
0
        /// <summary>
        /// Updates the parent nodes list.
        /// If the node state is None, Created or Modified new node is added to the parent nodes list of all the child nodes (child nodes are nodes which are referenced by the new node as properties).
        /// If the node state is Removed new node is removed from the parent nodes list of all the child nodes.
        /// </summary>
        /// <param name="newId"></param>
        /// <param name="nodeState"></param>
        /// <param name="delta"></param>
        /// <param name="edge"></param>
        /// <param name="childNode"></param>
        /// <param name="parentNode"></param>
        private static void UpdateParentNode(Guid newId, NodeState nodeState, DirectNodeProviderUnsafe <Guid, object, EdgeData> delta, Edge <Guid, EdgeData> edge, Node <Guid, object, EdgeData> childNode, Node <Guid, object, EdgeData> parentNode)
        {
            switch (nodeState)
            {
            case NodeState.None:
            case NodeState.Created:
                AddParentToChildNode(newId, childNode);
                break;

            case NodeState.Modified:
                if (!parentNode.Previous.Equals(Guid.Empty) && childNode.ParentNodes.Contains(parentNode.Previous))
                {
                    childNode.ParentNodes.Remove(parentNode.Previous);
                }
                AddParentToChildNode(newId, childNode);
                break;

            case NodeState.Removed:
                childNode.ParentNodes.Remove(newId);
                break;

            default:
                break;
            }
        }
Example #2
0
        /// <summary>
        /// Creates new instance of Workspace type
        /// </summary>
        internal Workspace(Guid snapshotId, TimeSpan timeout, INodeProvider <Guid, object, EdgeData> nodeProvider, IWorkspaceFacade commitTarget, ProxyCreatorService proxyCreatorService, TypesService typesService, IsolationLevel isolationLevel, IProxyMap immutableProxyMap)
        {
            this.workspaceId = Guid.NewGuid();
            this.thread      = Thread.CurrentThread;

            if (!typeof(TDataType).IsInterface)
            {
                throw new ArgumentException("Interface type expected: " + typeof(TDataType).AssemblyQualifiedName);
            }

            this.snapshotId          = snapshotId;
            this.nodeProvider        = nodeProvider;
            this.proxyCreatorService = proxyCreatorService;
            this.typesService        = typesService;
            this.isolationLevel      = isolationLevel;
            this.workspaceFacade     = commitTarget;
            this.immutableProxyMap   = immutableProxyMap;

            workspaceFacade.OpenWorkspace(workspaceId, snapshotId, isolationLevel, timeout);

            if (isolationLevel == IsolationLevel.ReadOnly)
            {
                // Rely directly on parent provider if read only
                this.objectInstancesService     = new ObjectInstancesService(nodeProvider, typesService);
                this.immutableInstancesService  = new ObjectInstancesService(nodeProvider, typesService);
                this.collectionInstancesService = new CollectionInstancesService(nodeProvider, typesService);
                this.dictionaryInstancesService = new DictionaryInstancesService(nodeProvider, typesService);
            }
            else
            {
                // Construct isolated provider for local changes
                var isolatedStorage = new DirectNodeProviderUnsafe <Guid, object, EdgeData>(new MemoryStorageUnsafe <Guid, object>(), false);
                isolatedProvider                = new IsolatedNodeProvider(nodeProvider, isolatedStorage, thread);
                this.objectInstancesService     = new ObjectInstancesService(isolatedProvider, typesService);
                this.immutableInstancesService  = new ObjectInstancesService(nodeProvider, typesService);
                this.collectionInstancesService = new CollectionInstancesService(isolatedProvider, typesService);
                this.dictionaryInstancesService = new DictionaryInstancesService(isolatedProvider, typesService);
            }

            this.runtimeProxyFacade = new RuntimeProxyFacade(typesService, objectInstancesService, immutableInstancesService, collectionInstancesService, new CollectionInstancesService(nodeProvider, typesService), dictionaryInstancesService, new DictionaryInstancesService(nodeProvider, typesService), mutableProxyMap, immutableProxyMap, proxyCreatorService);

            // Initialize root data proxy
            var rootObjectId = commitTarget.GetRootObjectId(snapshotId);

            rootProxy = proxyCreatorService.NewObject <TDataType>(runtimeProxyFacade, rootObjectId, isolationLevel == IsolationLevel.ReadOnly);

            if (isolationLevel == IsolationLevel.ReadOnly)
            {
                immutableProxyMap.AddProxy(rootObjectId, rootProxy);
            }
            else
            {
                mutableProxyMap.AddProxy(rootObjectId, rootProxy);
            }
        }
Example #3
0
        /// <summary>
        /// Open an workspace over an archive. Archive must have the same schema as the main context.
        /// </summary>
        /// <typeparam name="TDataType">Data type of root archive object.</typeparam>
        /// <param name="storage">Storage which contains the archive.</param>
        /// <returns>A read-only workspace which allows data reading from an archive.</returns>
        public Workspace <TDataType> OpenArchive <TDataType>(IKeyValueStorage <Guid, object> storage)
        {
            INodeProvider <Guid, object, EdgeData> archiveProvider = new DirectNodeProviderUnsafe <Guid, object, EdgeData>(storage, false);

            if (storage is ISerializingStorage)
            {
                // Inject the serializer
                ((ISerializingStorage)storage).Serializer = objectSerializationService;
            }

            return(new Workspace <TDataType>(Guid.Empty, TimeSpan.Zero, archiveProvider, new ArchiveWorkspaceFacade(archiveProvider), proxyCreatorService, typesService, IsolationLevel.ReadOnly, new LimitedProxyMap(Properties.Settings.Default.ObjectCacheMinimumCount, Properties.Settings.Default.ObjectCacheMaximumCount)));
        }
Example #4
0
        private AppendableChangeSet <Guid, object, EdgeData> CreateMergedChangeSet(Guid latestSnapshot, Hashtable subTree, IsolatedChangeSet <Guid, object, EdgeData> changeSet, Dictionary <Guid, Guid> intermediateChanges)
        {
#if DEBUG
            Debug.WriteLine("Merging over intermediate changes");
#endif
            // We create node provider which will host changes to the last snapshot made by the merge process
            var isolatedNodes = new DirectNodeProviderUnsafe <Guid, object, EdgeData>(new MemoryStorageUnsafe <Guid, object>(), false);
            // Perform merging on the current thread
            IsolatedNodeProvider destinationProvider = new IsolatedNodeProvider(nodes, isolatedNodes, Thread.CurrentThread);
            IsolatedNodeProvider sourceProvider      = new IsolatedNodeProvider(nodes, changeSet.Nodes, Thread.CurrentThread);

            // Make changes from incoming changes within a subtree
            MergeRecursive(latestSnapshot, new RecursiveResolutionParameters(subTree, destinationProvider, sourceProvider, changeSet, intermediateChanges, new Hashtable()));

            // We create an appendable change set from changes made to last snapshot, defining a new snapshot
            return(CreateAppendableChangeSet(latestSnapshot, Guid.NewGuid(), destinationProvider.GetChanges(latestSnapshot)));
        }
Example #5
0
 /// <summary>
 /// For the given nod, goes through all the child nodes and adds that node to the parent node list of the child nodes.
 /// </summary>
 /// <param name="newId"></param>
 /// <param name="parentNode"></param>
 /// <param name="nodeState"></param>
 /// <param name="delta">Node provider which contains nodes which will be saved at the end of the commit process</param>
 private void UpdateParentNodes(Guid newId, Node<Guid, object, EdgeData> parentNode, NodeState nodeState, DirectNodeProviderUnsafe<Guid, object, EdgeData> delta, IsolatedChangeSet<Guid, object, EdgeData> changeSet)
 {
     foreach (Edge<Guid, EdgeData> edge in parentNode.Edges.Values)
     {
         if ((edge.Data as EdgeData).Semantic == EdgeType.Property && (edge.Data.Flags & EdgeFlags.StoreParentNodes) == EdgeFlags.StoreParentNodes)
         {
             var childNode = GetNode(edge.ToNodeId, changeSet);
             if (childNode != null)
             {
                 switch (childNode.NodeType)
                 {
                     case NodeType.Object:
                         UpdateParentNode(newId, nodeState, delta, edge, childNode, parentNode);
                         break;
                     case NodeType.Collection:
                     case NodeType.Dictionary:
                         foreach (Edge<Guid, EdgeData> collectionEdge in childNode.Edges.Values)
                         {
                             if (collectionEdge.Data.Semantic.Equals(EdgeType.ListItem))
                             {
                                 UpdateParentNode(newId, nodeState, delta, collectionEdge, GetNode(collectionEdge.ToNodeId, changeSet), parentNode);
                             }
                         }
                         break;
                     default:
                         throw new NotImplementedException("NodeType=" + childNode.NodeType);
                 }
             }
         }
     }
 }
Example #6
0
        private AppendableChangeSet<Guid, object, EdgeData> CreateMergedChangeSet(Guid latestSnapshot, Hashtable subTree, IsolatedChangeSet<Guid, object, EdgeData> changeSet, Dictionary<Guid, Guid> intermediateChanges)
        {
            #if DEBUG
            Debug.WriteLine("Merging over intermediate changes");
            #endif
            // We create node provider which will host changes to the last snapshot made by the merge process
            var isolatedNodes = new DirectNodeProviderUnsafe<Guid,object, EdgeData>(new MemoryStorageUnsafe<Guid, object>(), false);
            // Perform merging on the current thread
            IsolatedNodeProvider destinationProvider = new IsolatedNodeProvider(nodes, isolatedNodes, Thread.CurrentThread);
            IsolatedNodeProvider sourceProvider = new IsolatedNodeProvider(nodes, changeSet.Nodes, Thread.CurrentThread);

            // Make changes from incoming changes within a subtree
            MergeRecursive(latestSnapshot, new RecursiveResolutionParameters(subTree, destinationProvider, sourceProvider, changeSet, intermediateChanges, new Hashtable()));

            // We create an appendable change set from changes made to last snapshot, defining a new snapshot
            return CreateAppendableChangeSet(latestSnapshot, Guid.NewGuid(), destinationProvider.GetChanges(latestSnapshot));
        }
Example #7
0
        /// <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;
        }
Example #8
0
        /// <summary>
        /// Adds node to delta with recursive pass through node parents
        /// </summary>
        /// <param name="delta">Provider which will accept new nodes</param>
        /// <param name="nodeId">Node ID to add</param>
        /// <param name="nodeMapping">Mapping between (old ID)->(new ID)</param>
        private void AddNodeToAppendableTreeRecursive(DirectNodeProviderUnsafe<Guid, object, EdgeData> delta, Guid nodeId, Dictionary<Guid, Guid> nodeMapping, Dictionary<Guid, NodeState> nodeStates, IsolatedChangeSet<Guid, object, EdgeData> changeSet)
        {
            // Skip already added nodes
            if (!nodeMapping.ContainsKey(nodeId))
            {
                // Generate new ID
                Guid newId = Guid.NewGuid();
                // Check node state
                NodeState nodeState = NodeState.None;

                changeSet.NodeStates.TryGetValue(nodeId, out nodeState);

                switch (nodeState)
                {
                    case NodeState.None:
                        {
                            // Register in the mapping
                            nodeMapping.Add(nodeId, newId);
                            // Get undelrying node
                            var node = nodes.GetNode(nodeId, NodeAccess.Read);

                            var newNode = CloneNode(node);

                            // Set node to commited
                            newNode.Commited = true;

                            // Create edge to previous node
                            newNode.Previous = nodeId;

                            // New node is created which is copied from underlying provider
                            delta.SetNode(newId, newNode);

                            // This change is defined as modification
                            nodeStates.Add(newId, NodeState.Modified);

                            // Add node parents from the current snapshot
                            using (var enumerator = mutableParentProvider.ParentEdges(changeSet.SourceSnapshotId, nodeId))
                            {
                                if (enumerator != null)
                                {
                                    while (enumerator.MoveNext())
                                    {
                                        AddNodeToAppendableTreeRecursive(delta, enumerator.Current.ToNodeId, nodeMapping, nodeStates, changeSet);
                                    }
                                }
                            }

                            // Update parent nodes
                            UpdateParentNodes(newId, newNode, nodeState, delta, changeSet);
                        }
                        break;
                    case NodeState.Created:
                        {
                            // Read the node
                            var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.ReadWrite);
                            // Set node to commited
                            node.Commited = true;
                            // There is no previous
                            node.Previous = Guid.Empty;
                            // Store to delta
                            delta.SetNode(nodeId, node);
                            // This change is defined as creation
                            nodeStates.Add(nodeId, NodeState.Created);

                            // Update parent nodes
                            UpdateParentNodes(nodeId, node, nodeState, delta, changeSet);
                        }
                        break;
                    case NodeState.Modified:
                        {
                            // Register in the mapping
                            nodeMapping.Add(nodeId, newId);
                            // Read the node
                            var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.ReadWrite);
                            // Set node to commited
                            node.Commited = true;
                            // Set the previous
                            node.Previous = nodeId;
                            // Store to delta
                            delta.SetNode(newId, node);
                            // This change is defined as modification
                            nodeStates.Add(newId, NodeState.Modified);

                            // Add node parents from the current snapshot
                            using (var enumerator = mutableParentProvider.ParentEdges(changeSet.SourceSnapshotId, nodeId))
                            {
                                while (enumerator.MoveNext())
                                {
                                    AddNodeToAppendableTreeRecursive(delta, enumerator.Current.ToNodeId, nodeMapping, nodeStates, changeSet);
                                }
                            }

                            // Update parent nodes
                            UpdateParentNodes(newId, node, nodeState, delta, changeSet);
                        }
                        break;

                    case NodeState.Removed:
                        {
                            // Update parent nodes
                            var node = GetNode(nodeId, changeSet);
                            UpdateParentNodes(nodeId, node, nodeState, delta, changeSet);
                        }
                        break;
                    default:
                        throw new ArgumentException(nodeState.ToString());
                }
            }
        }
Example #9
0
 /// <summary>
 /// Updates the parent nodes list.
 /// If the node state is None, Created or Modified new node is added to the parent nodes list of all the child nodes (child nodes are nodes which are referenced by the new node as properties).
 /// If the node state is Removed new node is removed from the parent nodes list of all the child nodes.
 /// </summary>
 /// <param name="newId"></param>
 /// <param name="nodeState"></param>
 /// <param name="delta"></param>
 /// <param name="edge"></param>
 /// <param name="childNode"></param>
 /// <param name="parentNode"></param>
 private static void UpdateParentNode(Guid newId, NodeState nodeState, DirectNodeProviderUnsafe<Guid, object, EdgeData> delta, Edge<Guid, EdgeData> edge, Node<Guid, object, EdgeData> childNode, Node<Guid, object, EdgeData> parentNode)
 {
     switch (nodeState)
     {
         case NodeState.None:
         case NodeState.Created:
             AddParentToChildNode(newId, childNode);
             break;
         case NodeState.Modified:
             if (!parentNode.Previous.Equals(Guid.Empty) && childNode.ParentNodes.Contains(parentNode.Previous))
             {
                 childNode.ParentNodes.Remove(parentNode.Previous);
             }
             AddParentToChildNode(newId, childNode);
             break;
         case NodeState.Removed:
             childNode.ParentNodes.Remove(newId);
             break;
         default:
             break;
     }
 }
Example #10
0
        /// <summary>
        /// For the given nod, goes through all the child nodes and adds that node to the parent node list of the child nodes.
        /// </summary>
        /// <param name="newId"></param>
        /// <param name="parentNode"></param>
        /// <param name="nodeState"></param>
        /// <param name="delta">Node provider which contains nodes which will be saved at the end of the commit process</param>
        private void UpdateParentNodes(Guid newId, Node <Guid, object, EdgeData> parentNode, NodeState nodeState, DirectNodeProviderUnsafe <Guid, object, EdgeData> delta, IsolatedChangeSet <Guid, object, EdgeData> changeSet)
        {
            foreach (Edge <Guid, EdgeData> edge in parentNode.Edges.Values)
            {
                if ((edge.Data as EdgeData).Semantic == EdgeType.Property && (edge.Data.Flags & EdgeFlags.StoreParentNodes) == EdgeFlags.StoreParentNodes)
                {
                    var childNode = GetNode(edge.ToNodeId, changeSet);
                    if (childNode != null)
                    {
                        switch (childNode.NodeType)
                        {
                        case NodeType.Object:
                            UpdateParentNode(newId, nodeState, delta, edge, childNode, parentNode);
                            break;

                        case NodeType.Collection:
                        case NodeType.Dictionary:
                            foreach (Edge <Guid, EdgeData> collectionEdge in childNode.Edges.Values)
                            {
                                if (collectionEdge.Data.Semantic.Equals(EdgeType.ListItem))
                                {
                                    UpdateParentNode(newId, nodeState, delta, collectionEdge, GetNode(collectionEdge.ToNodeId, changeSet), parentNode);
                                }
                            }
                            break;

                        default:
                            throw new NotImplementedException("NodeType=" + childNode.NodeType);
                        }
                    }
                }
            }
        }
Example #11
0
        /// <summary>
        /// Adds node to delta with recursive pass through node parents
        /// </summary>
        /// <param name="delta">Provider which will accept new nodes</param>
        /// <param name="nodeId">Node ID to add</param>
        /// <param name="nodeMapping">Mapping between (old ID)->(new ID)</param>
        private void AddNodeToAppendableTreeRecursive(DirectNodeProviderUnsafe <Guid, object, EdgeData> delta, Guid nodeId, Dictionary <Guid, Guid> nodeMapping, Dictionary <Guid, NodeState> nodeStates, IsolatedChangeSet <Guid, object, EdgeData> changeSet)
        {
            // Skip already added nodes
            if (!nodeMapping.ContainsKey(nodeId))
            {
                // Generate new ID
                Guid newId = Guid.NewGuid();
                // Check node state
                NodeState nodeState = NodeState.None;

                changeSet.NodeStates.TryGetValue(nodeId, out nodeState);

                switch (nodeState)
                {
                case NodeState.None:
                {
                    // Register in the mapping
                    nodeMapping.Add(nodeId, newId);
                    // Get undelrying node
                    var node = nodes.GetNode(nodeId, NodeAccess.Read);

                    var newNode = CloneNode(node);

                    // Set node to commited
                    newNode.Commited = true;

                    // Create edge to previous node
                    newNode.Previous = nodeId;

                    // New node is created which is copied from underlying provider
                    delta.SetNode(newId, newNode);

                    // This change is defined as modification
                    nodeStates.Add(newId, NodeState.Modified);

                    // Add node parents from the current snapshot
                    using (var enumerator = mutableParentProvider.ParentEdges(changeSet.SourceSnapshotId, nodeId))
                    {
                        if (enumerator != null)
                        {
                            while (enumerator.MoveNext())
                            {
                                AddNodeToAppendableTreeRecursive(delta, enumerator.Current.ToNodeId, nodeMapping, nodeStates, changeSet);
                            }
                        }
                    }

                    // Update parent nodes
                    UpdateParentNodes(newId, newNode, nodeState, delta, changeSet);
                }
                break;

                case NodeState.Created:
                {
                    // Read the node
                    var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.ReadWrite);
                    // Set node to commited
                    node.Commited = true;
                    // There is no previous
                    node.Previous = Guid.Empty;
                    // Store to delta
                    delta.SetNode(nodeId, node);
                    // This change is defined as creation
                    nodeStates.Add(nodeId, NodeState.Created);

                    // Update parent nodes
                    UpdateParentNodes(nodeId, node, nodeState, delta, changeSet);
                }
                break;

                case NodeState.Modified:
                {
                    // Register in the mapping
                    nodeMapping.Add(nodeId, newId);
                    // Read the node
                    var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.ReadWrite);
                    // Set node to commited
                    node.Commited = true;
                    // Set the previous
                    node.Previous = nodeId;
                    // Store to delta
                    delta.SetNode(newId, node);
                    // This change is defined as modification
                    nodeStates.Add(newId, NodeState.Modified);

                    // Add node parents from the current snapshot
                    using (var enumerator = mutableParentProvider.ParentEdges(changeSet.SourceSnapshotId, nodeId))
                    {
                        while (enumerator.MoveNext())
                        {
                            AddNodeToAppendableTreeRecursive(delta, enumerator.Current.ToNodeId, nodeMapping, nodeStates, changeSet);
                        }
                    }

                    // Update parent nodes
                    UpdateParentNodes(newId, node, nodeState, delta, changeSet);
                }
                break;

                case NodeState.Removed:
                {
                    // Update parent nodes
                    var node = GetNode(nodeId, changeSet);
                    UpdateParentNodes(nodeId, node, nodeState, delta, changeSet);
                }
                break;

                default:
                    throw new ArgumentException(nodeState.ToString());
                }
            }
        }
Example #12
0
        /// <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);
        }