/// <summary> /// Direct commit of data is appended on the existing nodes /// </summary> /// <param name="changeSet">Changes</param> private void CommitDirect(AppendableChangeSet <Guid, object, EdgeData> changeSet) { // Add all nodes to the provider foreach (Guid nodeId in changeSet.Nodes.EnumerateNodes()) { var node = changeSet.Nodes.GetNode(nodeId, NodeAccess.Read); nodes.SetNode(nodeId, node); } // Store the change set in the change set provider changeSetProvider.SetChangeSet(changeSet); // Calculate collected nodes in the source changeset collectedNodesProvider.StoreChangeset(changeSet, mutableParentProvider, immutableParentProvider); // Update parent information in the parent map provider mutableParentProvider.UpdateParents(changeSet, collectedNodesProvider); // Update parent information in the immutable parent map provider immutableParentProvider.UpdateParents(changeSet, collectedNodesProvider); // Add new snapshot making it visible snapshotsService.AddSnapshot(changeSet.DestinationSnapshotId); #if DEBUG Debug.WriteLine("Created snapshot " + changeSet.DestinationSnapshotId); Utils.LogNodesRecursive(changeSet.DestinationSnapshotId, nodes, changeSet.Nodes, 0, new Hashtable(), typesService); Debug.WriteLine("---------------------------------------------"); Debug.WriteLine("Collected nodes are:"); var enumerator = collectedNodesProvider.GetEdges(changeSet.SourceSnapshotId); if (enumerator != null) { using (enumerator) { while (enumerator.MoveNext()) { Debug.WriteLine(enumerator.Current.ToNodeId); } } } Debug.WriteLine("---------------------------------------------"); #endif }
/// <summary> /// Performs cleanup of historic data which is not used /// </summary> public void Cleanup() { lock (cleanupSync) { // Clean expired workspaces trackingWorkspaceStateProvider.Cleanup(); // Determine which snapshots are used var usedSnapshots = trackingWorkspaceStateProvider.UsedSnapshotIds(); // Ensure that last is always used var lastSnapshot = snapshotsService.GetLatestSnapshotId(); if (!usedSnapshots.Contains(lastSnapshot)) { usedSnapshots.Add(lastSnapshot); } // Determine which snapshots are not used, remove them from shapshots list var unusedSnapshots = snapshotsService.RemoveUnusedSnapshots(usedSnapshots); // Process removed snapshots foreach (var snapshotId in unusedSnapshots) { // Garbage collect nodes which are not used var collectedNodesEnumerator = collectedNodesProvider.GetEdges(snapshotId); if (collectedNodesEnumerator != null) { using (collectedNodesEnumerator) { while (collectedNodesEnumerator.MoveNext()) { provider.Remove(collectedNodesEnumerator.Current.ToNodeId); } } } // Remove change set history information changeSetProvider.RemoveChangeSet(snapshotId); // Remove information about collected nodes in the snapshot collectedNodesProvider.Cleanup(snapshotId); // Remove the snapshot node provider.Remove(snapshotId); } } }
/// <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; } }