/// <summary> /// Creates the and enqueue operations. /// </summary> /// <param name="targetContainerContext">The target container context.</param> /// <param name="treeNode">The tree node.</param> /// <param name="sourceContainers">The source containers.</param> /// <param name="alwaysDefined">if set to <c>true</c> [always defined].</param> public void CreateAndEnqueueOperations(ITargetContainerContext targetContainerContext, MemoryIndexTreeNode treeNode, List <ContainerContext> sourceContainers, bool alwaysDefined) { // Creates and enques merge operations for all child nodes of given node foreach (var childNode in treeNode.ChildNodes) { string childName = childNode.Key; MemoryIndexTreeNode childTreeNode = childNode.Value; MergeOperation operation = new MergeOperation(); bool isChildDefined = collectIndexes(childName, sourceContainers, operation); if (isChildDefined) { // Child is defined at least in one collection - enqueue merge operation enqueueMergeOperation(childName, operation, targetContainerContext, childTreeNode, alwaysDefined); } else { // Child is not defined - enqueue delete operation enqueueDeleteOperation(childName, operation, targetContainerContext, childTreeNode); } } // Enqueue merge operation for unknown index if is defined if (treeNode.AnyChild != null) { enqueueMergeUnknownOperation(targetContainerContext, treeNode.AnyChild, sourceContainers); } }
/// <summary> /// Merges the object definitions. /// </summary> protected void mergeObjectDefinitions() { foreach (var objectDefinition in changeTree.ObjectTreeRoots) { ObjectValue objectValue = objectDefinition.Key; MemoryIndexTreeNode treeNode = objectDefinition.Value; IObjectDescriptor targetDescriptor; bool containsTargetDescriptor = targetStructure.TryGetDescriptor(objectValue, out targetDescriptor); bool alwaysDefined = true; List <ContainerContext> sourceContainers = new List <ContainerContext>(); // Iterate sources to collect object descriptors foreach (SnapshotContext context in snapshotContexts) { IObjectDescriptor descriptor; if (context.SourceStructure.TryGetDescriptor(objectValue, out descriptor)) { // Source contains object - add descriptor to sources sourceContainers.Add(new ContainerContext(context, descriptor)); if (targetDescriptor == null) { // Descriptor is not in the target structure - use current as target targetDescriptor = descriptor; } } else { // Object is at least once undefined - weak merge alwaysDefined = false; } } // Merge object descriptor and prepare operations of modified fields if (targetDescriptor != null) { ObjectTargetContainerContext objectContext = new ObjectTargetContainerContext(writeableTargetStructure, targetDescriptor); createAndEnqueueOperations(objectContext, treeNode, sourceContainers, alwaysDefined); // Save updated descriptor if instance changed or is not stored in target if (isStructureWriteable) { IObjectDescriptor currentDescriptor = objectContext.getCurrentDescriptor(); if (!containsTargetDescriptor || currentDescriptor != targetDescriptor) { writeableTargetStructure.SetDescriptor(objectValue, currentDescriptor); } } } } }
/// <summary> /// Enqueues the merge unknown operation. /// </summary> /// <param name="targetContainerContext">The target container context.</param> /// <param name="anyNode">Any node.</param> /// <param name="sourceContainers">The source containers.</param> private void enqueueMergeUnknownOperation(ITargetContainerContext targetContainerContext, MemoryIndexTreeNode anyNode, List <ContainerContext> sourceContainers) { MergeOperation unknownOperation = new MergeOperation(); foreach (ContainerContext containerContext in sourceContainers) { unknownOperation.Add(new MergeOperationContext( containerContext.IndexContainer.UnknownIndex, containerContext.SnapshotContext)); } IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer(); unknownOperation.TreeNode = anyNode; unknownOperation.SetTargetIndex(targetContainer.UnknownIndex); unknownOperation.SetUndefined(); operationQueue.AddLast(unknownOperation); }
/// <summary> /// Enqueues the delete operation. /// </summary> /// <param name="childName">Name of the child.</param> /// <param name="operation">The operation.</param> /// <param name="targetContainerContext">The target container context.</param> /// <param name="childTreeNode">The child tree node.</param> private void enqueueDeleteOperation(string childName, MergeOperation operation, ITargetContainerContext targetContainerContext, MemoryIndexTreeNode childTreeNode) { IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer(); MemoryIndex targetIndex; if (targetContainer.TryGetIndex(childName, out targetIndex)) { // Enque delete operation only if target index exists in paret snapshot operation.TreeNode = childTreeNode; operation.SetTargetIndex(targetIndex); operation.SetDeleteOperation(); operationQueue.AddLast(operation); // Delete child from parent container targetContainerContext.getWriteableSourceContainer().RemoveIndex(childName); } }
/// <summary> /// Enqueues the merge operation. /// </summary> /// <param name="childName">Name of the child.</param> /// <param name="operation">The operation.</param> /// <param name="targetContainerContext">The target container context.</param> /// <param name="childTreeNode">The child tree node.</param> /// <param name="alwaysDefined">if set to <c>true</c> [always defined].</param> private void enqueueMergeOperation(string childName, MergeOperation operation, ITargetContainerContext targetContainerContext, MemoryIndexTreeNode childTreeNode, bool alwaysDefined) { IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer(); MemoryIndex targetIndex; // Use index from target collection or crete and add it to the target collection if (!targetContainer.TryGetIndex(childName, out targetIndex)) { targetIndex = createNewTargetIndex(targetContainerContext, childName); if (targetIndex == null) { return; } } // Set parameters and add it to collection operation.TreeNode = childTreeNode; operation.SetTargetIndex(targetIndex); if (!alwaysDefined) { operation.SetUndefined(); } operationQueue.AddLast(operation); }
/// <summary> /// Creates the and enqueue operations. /// </summary> /// <param name="targetContainerContext">The target container context.</param> /// <param name="treeNode">The tree node.</param> /// <param name="sourceContainers">The source containers.</param> /// <param name="alwaysDefined">if set to <c>true</c> [always defined].</param> private void createAndEnqueueOperations( ITargetContainerContext targetContainerContext, MemoryIndexTreeNode treeNode, List <ContainerContext> sourceContainers, bool alwaysDefined) { IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer(); // Creates and enques merge operations for all child nodes of given node foreach (var childNode in treeNode.ChildNodes) { string childName = childNode.Key; MemoryIndexTreeNode childTreeNode = childNode.Value; MergeOperation operation = new MergeOperation(); bool isChildDefined = collectIndexes(childName, sourceContainers, operation); if (isChildDefined) { // Child is defined at least in one collection - enqueue merge operation MemoryIndex targetIndex; // Use index from target collection or crete and add it to the target collection if (!targetContainer.TryGetIndex(childName, out targetIndex)) { targetIndex = createNewTargetIndex(targetContainerContext, childName); if (targetIndex == null) { continue; } } // Set parameters and add it to collection operation.TreeNode = childTreeNode; operation.SetTargetIndex(targetIndex); if (!alwaysDefined) { operation.SetUndefined(); } operationQueue.AddLast(operation); } else { // Child is not defined - enqueue delete operation MemoryIndex targetIndex; if (targetContainer.TryGetIndex(childName, out targetIndex)) { // Enque delete operation only if target index exists in paret snapshot operation.TreeNode = childTreeNode; operation.SetTargetIndex(targetIndex); operation.SetDeleteOperation(); operationQueue.AddLast(operation); deleteChild(targetContainerContext, childName); } } } // Enqueue merge operation for unknown index if is defined if (treeNode.AnyChild != null) { MergeOperation unknownOperation = new MergeOperation(); foreach (ContainerContext containerContext in sourceContainers) { unknownOperation.Add(new MergeOperationContext( containerContext.IndexContainer.UnknownIndex, containerContext.SnapshotContext)); } unknownOperation.TreeNode = treeNode.AnyChild; unknownOperation.SetTargetIndex(targetContainer.UnknownIndex); unknownOperation.SetUndefined(); operationQueue.AddLast(unknownOperation); } }