/// <summary> /// Collects the source array. /// </summary> /// <param name="targetIndex">Index of the target.</param> /// <param name="operation">The operation.</param> /// <param name="operationContext">The operation context.</param> /// <param name="sourceArray">The source array.</param> public void collectSourceArray(MemoryIndex targetIndex, MergeOperation operation, MergeOperationContext operationContext, AssociativeArray sourceArray) { // Source array if (sourceArray != null) { // Becomes target array when not set if (targetArray == null && operationContext.Index.Equals(targetIndex)) { targetArray = sourceArray; } hasArray = true; // Save source array to merge descriptors IArrayDescriptor descriptor = operationContext.SnapshotContext.SourceStructure.GetDescriptor(sourceArray); sourceArrays.Add(new ContainerContext(operationContext.SnapshotContext, descriptor, operationContext.OperationType)); // Equeue all array indexes when whole subtree should be merged if (operationContext.OperationType == MergeOperationType.WholeSubtree) { foreach (var index in descriptor.Indexes) { operation.TreeNode.GetOrCreateChild(index.Key); } operation.TreeNode.GetOrCreateAny(); } } else { // Source do not contain array - at least one source is empty arrayAlwaysDefined = false; } }
public OperationAccessor(MergeOperation operation, Snapshot targetSnapshot, IWriteableSnapshotData writeableTargetData, IReadOnlySnapshotStructure targetStructure) { this.operation = operation; this.targetSnapshot = targetSnapshot; this.writeableTargetData = writeableTargetData; this.targetStructure = targetStructure; }
/// <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> /// Deletes the array. /// </summary> /// <param name="targetIndex">Index of the target.</param> /// <param name="targetArray">The target array.</param> public void DeleteArray(MemoryIndex targetIndex, AssociativeArray targetArray) { IArrayDescriptor targetArrayDescriptor = targetStructure.GetDescriptor(targetArray); foreach (var index in targetArrayDescriptor.Indexes) { // Enqueue delete operation for every child index MemoryIndex childIndex = index.Value; MergeOperation childOperation = new MergeOperation(); childOperation.SetTargetIndex(childIndex); childOperation.SetDeleteOperation(); operationQueue.AddLast(childOperation); } // Enqueue delete operation for unknown index MergeOperation unknownOperation = new MergeOperation(); unknownOperation.SetTargetIndex(targetArrayDescriptor.UnknownIndex); unknownOperation.SetUndefined(); unknownOperation.SetDeleteOperation(); operationQueue.AddLast(unknownOperation); // Deletes array from structure writeableTargetStructure.RemoveArray(targetIndex, targetArray); }
/// <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); } }
public OperationAccessor(MergeOperation operation, Snapshot targetSnapshot, IWriteableSnapshotStructure writeableTargetStructure, TrackingCallMergeStructureWorker mergeWorker) { this.operation = operation; this.targetSnapshot = targetSnapshot; this.writeableTargetStructure = writeableTargetStructure; this.mergeWorker = mergeWorker; this.references = new ReferenceCollector(writeableTargetStructure); }
/// <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 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> /// Processes the merge operations. /// </summary> private void processMergeOperations() { // Process operations while queue is not empty while (operationQueue.Count > 0) { // Dequeue next operation MergeOperation operation = operationQueue.First.Value; operationQueue.RemoveFirst(); if (operation.IsDeleteOperation) { processDeleteOperation(operation); } else { processMergeOperation(operation); } } }
/// <summary> /// Processes the merge operation. /// </summary> /// <param name="operation">The operation.</param> private void processMergeOperation(MergeOperation operation) { MemoryIndex targetIndex = operation.TargetIndex; var targetIndexDatasources = targetSnapshot.MergeInfo.GetOrCreateDatasourcesContaier(targetIndex); // Iterate sources foreach (MergeOperationContext operationContext in operation.Indexes) { // Retreive source context and definition MemoryIndex sourceIndex = operationContext.Index; SnapshotContext context = operationContext.SnapshotContext; IIndexDefinition sourceDefinition = context.SourceStructure.GetIndexDefinition(sourceIndex); // Collect array and aliases data arrayWorker.collectSourceArray(targetIndex, operation, operationContext, sourceDefinition.Array); aliasWorker.collectSourceAliases(sourceDefinition.Aliases); objectWorker.collectSourceObjects(sourceDefinition.Objects); // Store datasource for data and info merging targetIndexDatasources.SetDatasource(context.SourceSnapshot, sourceIndex); } IIndexDefinition targetDefinition; if (targetStructure.TryGetIndexDefinition(targetIndex, out targetDefinition)) { // Index is set in target snapshot if (targetDefinition.Array != null) { arrayWorker.SetTargetArray(targetDefinition.Array); } } else { // Index is not set in target snapshot - create it writeableTargetStructure.NewIndex(targetIndex); } aliasWorker.MergeAliasesAndClear(targetIndex, operation); arrayWorker.MergeArraysAndClear(targetSnapshot, targetIndex, operation); objectWorker.MergeObjectsAndClear(targetIndex); }
/// <summary> /// Merges the aliases to target and clear inner container. /// </summary> /// <param name="targetIndex">Index of the target.</param> /// <param name="operation">The operation.</param> /// <exception cref="System.Exception">Alias merge - memory index was not included into collection of aliases</exception> public void MergeAliasesAndClear(MemoryIndex targetIndex, MergeOperation operation) { if (hasAliases && references.HasAliases) { references.SetAliases(targetIndex, worker, aliasesAlwaysDefined && !operation.IsUndefined); MemoryAliasInfo aliasInfo; if (worker.MemoryAliases.TryGetValue(targetIndex, out aliasInfo)) { aliasInfo.IsTargetOfMerge = true; } else { throw new Exception("Alias merge - memory index was not included into collection of aliases"); } references.Clear(); hasAliases = false; } aliasesAlwaysDefined = true; }
/// <summary> /// Processes the delete operation. /// </summary> /// <param name="operation">The operation.</param> private void processDeleteOperation(MergeOperation operation) { MemoryIndex targetIndex = operation.TargetIndex; IIndexDefinition targetDefinition; // Index is set in target snapshot if (targetStructure.TryGetIndexDefinition(targetIndex, out targetDefinition)) { // Delete array and enqueue deletein operations if exists if (targetDefinition.Array != null) { DeleteArray(targetIndex, targetDefinition.Array); } // Delete aliases if any if (targetDefinition.Aliases != null && targetDefinition.Aliases.HasAliases) { deleteAliases(targetIndex, targetDefinition.Aliases); } // Removes index from target structure writeableTargetStructure.RemoveIndex(targetIndex); } }
/// <summary> /// Creates the new operation accessor. /// </summary> /// <param name="operation">The operation.</param> /// <returns>Operation accesor</returns> protected override TrackingMergeWorkerOperationAccessor createNewOperationAccessor(MergeOperation operation) { return(new OperationAccessor(operation, targetSnapshot, writeableTargetData, targetStructure)); }
/// <summary> /// Merges the arrays into the target index and clear inner collection. /// </summary> /// <param name="targetSnapshot">The target snapshot.</param> /// <param name="targetIndex">Index of the target.</param> /// <param name="operation">The operation.</param> public void MergeArraysAndClear(Snapshot targetSnapshot, MemoryIndex targetIndex, MergeOperation operation) { if (hasArray) { if (targetArray == null) { targetArray = targetSnapshot.CreateArray(); } IArrayDescriptor targetArrayDescriptor; if (!writeableTargetStructure.TryGetDescriptor(targetArray, out targetArrayDescriptor)) { // Target does not contain array - create and add new in target snapshot targetArrayDescriptor = worker.Factories.StructuralContainersFactories.ArrayDescriptorFactory.CreateArrayDescriptor(writeableTargetStructure, targetArray, targetIndex); writeableTargetStructure.SetDescriptor(targetArray, targetArrayDescriptor); writeableTargetStructure.NewIndex(targetArrayDescriptor.UnknownIndex); writeableTargetStructure.SetArray(targetIndex, targetArray); } // Create context and merge descriptors var arrayContext = new ArrayTargetContainerContext(writeableTargetStructure, targetArrayDescriptor); worker.CreateAndEnqueueOperations(arrayContext, operation.TreeNode, sourceArrays, arrayAlwaysDefined && !operation.IsUndefined); // Update current descriptor when changed IArrayDescriptor currentDescriptor = arrayContext.getCurrentDescriptor(); if (currentDescriptor != targetArrayDescriptor) { writeableTargetStructure.SetDescriptor(targetArray, currentDescriptor); } sourceArrays.Clear(); hasArray = false; targetArray = null; } else if (targetArray != null) { worker.DeleteArray(targetIndex, targetArray); targetArray = null; } arrayAlwaysDefined = true; }
/// <summary> /// Collects the indexes. /// </summary> /// <param name="childName">Name of the child.</param> /// <param name="sourceContainers">The source containers.</param> /// <param name="operation">The operation.</param> /// <returns>True if there is some defined child; otherwise false</returns> private bool collectIndexes(string childName, List <ContainerContext> sourceContainers, MergeOperation operation) { bool childDefined = false; // Collect source indexes from source collection foreach (ContainerContext containerContext in sourceContainers) { MemoryIndex sourceIndex; if (containerContext.IndexContainer.TryGetIndex(childName, out sourceIndex)) { // Collection contains field - use it operation.Add(new MergeOperationContext(sourceIndex, containerContext.SnapshotContext)); childDefined = true; } else { // Collection do not contain - use unknown index as source // When unknown index is the source - all subtree has to be merged into operation.Add( new MergeOperationContext( containerContext.IndexContainer.UnknownIndex, containerContext.SnapshotContext, MergeOperationType.WholeSubtree) ); operation.SetUndefined(); } } return(childDefined); }