Пример #1
0
        public void MetaTest_Test_MakeSubgridWith10240CellPassesAtOneSecondIntervals()
        {
            // Create a subgrid to hold the segment
            IServerLeafSubGrid subGrid = MakeSubgridWith10240CellPassesAtOneSecondIntervals();

            ISubGridCellPassesDataSegment segment = subGrid.Cells.PassesData[0];

            // Check all cells have exactly 10 passes
            VSS.TRex.SubGridTrees.Core.Utilities.SubGridUtilities.SubGridDimensionalIterator((x, y) =>
            {
                Assert.True(segment.PassesData.PassCount(x, y) == 10,
                            $"Cell in segment at {x},{y} does not have 10 cell passes");
            });

            //Check the total number of passes is 10240, and the maximum pass count is 10
            segment.PassesData.CalculateTotalPasses(out int totalPassCount, out _, out int maximumPassCount);

            Assert.True(10240 == totalPassCount, "Initial total pass count not 10240");
            Assert.True(10240 == segment.PassesData.SegmentPassCount,
                        $"segment.PassesData.SegmentPassCount does not equal 10240 (it is {segment.PassesData.SegmentPassCount})");
            Assert.True(10 == maximumPassCount, "Initial maximum pass count not 10");

            // Check the time range is as expected
            segment.PassesData.CalculateTimeRange(out DateTime startSegmentTime, out DateTime endSegmentTime);
            Assert.True(endSegmentTime > startSegmentTime, $"End time {endSegmentTime} not greater than startTime {startSegmentTime}");

            Assert.True(startSegmentTime == startTime, $"Start time {startSegmentTime} not equal to {startTime} as expected");
            Assert.True(endSegmentTime == startTime.AddSeconds(10239), $"End time {endSegmentTime} not equal to {startTime.AddSeconds(10239)} as expected");
        }
Пример #2
0
        private void IntegrateIntoLiveGrid(IServerLeafSubGrid sourceSubGrid,
                                           ISubGridSegmentIterator segmentIterator,
                                           Action <int, int> subGridChangeNotifier)
        {
            var targetSubGrid = LocateOrCreateSubGrid(_target, sourceSubGrid.OriginX, sourceSubGrid.OriginY);

            try
            {
                if (targetSubGrid == null)
                {
                    _log.LogError("Failed to locate or create sub grid in IntegrateIntoLiveGrid");
                    return;
                }

                if (!IntegrateIntoLiveDatabase(sourceSubGrid, targetSubGrid, segmentIterator, subGridChangeNotifier))
                {
                    _log.LogError("Integration into live database failed");
                }
            }
            finally
            {
                // At this point TargetSubGrid is of no further interest. The site model will be dropped in-toto once all
                // changes have been integrated into the live sub grids and releasing it's resources here alleviates memory
                // pressure that occurs if all sub grids are integrated before any resource freeing occurs
                // This is not mediated by a using block as we want the sub grid to remain in the sub grid tree (ie:
                // removing it is messy and not necessary here, it can be delegated to the DropSiteModel() phase.
                targetSubGrid?.DeAllocateLeafFullPassStacks();
                targetSubGrid?.DeAllocateLeafLatestPassGrid();
            }
        }
Пример #3
0
        public ISubGridCellPassesDataSegment AddNewSegment(IServerLeafSubGrid subGrid,
                                                           ISubGridCellPassesDataSegmentInfo segmentInfo)
        {
            if (segmentInfo == null)
            {
                throw new TRexSubGridProcessingException($"Null segment info passed to AddNewSegment for sub grid {subGrid.Moniker()}");
            }

            if (segmentInfo.Segment != null)
            {
                throw new TRexSubGridProcessingException($"Segment info passed to AddNewSegment for sub grid {subGrid.Moniker()} already contains an allocated segment");
            }

            var Result = new SubGridCellPassesDataSegment
            {
                Owner       = subGrid,
                SegmentInfo = segmentInfo
            };

            segmentInfo.Segment = Result;

            for (int I = 0; I < Count; I++)
            {
                if (segmentInfo.EndTime <= Items[I].SegmentInfo.StartTime)
                {
                    Items.Insert(I, Result);

                    if (_performSegmentAdditionIntegrityChecks)
                    {
                        for (int J = 0; J < Count - 1; J++)
                        {
                            if (Items[J].SegmentInfo.StartTime >= Items[J + 1].SegmentInfo.StartTime)
                            {
                                _log.LogError($"Segment passes list out of order {Items[J].SegmentInfo.StartTime} versus {Items[J + 1].SegmentInfo.StartTime}. Segment count = {Count}");
                                DumpSegmentsToLog();
                                throw new TRexSubGridProcessingException($"Segment passes list out of order {Items[J].SegmentInfo.StartTime} versus {Items[J + 1].SegmentInfo.StartTime}. Segment count = {Count}");
                            }
                        }
                    }

                    return(Result);
                }
            }

            // if we get to here, then the new segment is at the end of the list, so just add it to the end
            Add(Result);

            return(Result);
        }
Пример #4
0
        private bool IntegrateIntoLiveDatabase(IServerLeafSubGrid sourceSubGrid,
                                               IServerLeafSubGrid targetSubGrid,
                                               ISubGridSegmentIterator segmentIterator,
                                               Action <int, int> subGridChangeNotifier)
        {
            // Note the fact that this sub grid will be changed and become dirty as a result
            // of the cell pass integration
            targetSubGrid.SetDirty();
            targetSubGrid.Integrate(sourceSubGrid, segmentIterator, false);

            subGridChangeNotifier?.Invoke(targetSubGrid.OriginX, targetSubGrid.OriginY);

            // Save the integrated state of the sub grid segments to allow Ignite to store & socialize the update
            // within the cluster.

            // Failure to save a piece of data aborts the entire integration
            var result = false;

            if (_target.SaveLeafSubGrid(targetSubGrid, _storageProxySubGrids, _storageProxySubGridSegments, InvalidatedSpatialStreams))
            {
                // Successfully saving the sub grid directory information is the point at which this sub grid may be recognized to exist
                // in the site model. Note this by including it within the SiteModel existence map

                _siteModel.ExistenceMap.SetCell(targetSubGrid.OriginX >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                                                targetSubGrid.OriginY >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                                                true);
                result = true;
            }
            else
            {
                _log.LogError($"Sub grid leaf save failed for {targetSubGrid}, existence map not modified.");
            }

            // Finally, mark the source sub grid as not being dirty. We need to do this to allow
            // the sub grid to permit its destruction as all changes have been merged into the target.
            if (result)
            {
                sourceSubGrid.AllChangesMigrated();
            }

            return(result);
        }
Пример #5
0
        private void IntegrateSubGrid(IServerLeafSubGrid sourceSubGrid,
                                      SubGridTreeIntegrationMode integrationMode,
                                      Action <int, int> subGridChangeNotifier,
                                      ISubGridSegmentIterator segmentIterator)
        {
            // Locate a matching sub grid in this tree. If there is none, then create it
            // and assign the sub grid from the iterator to it. If there is one, process
            // the cell pass stacks merging the two together

            var integratingIntoIntermediaryGrid = integrationMode == SubGridTreeIntegrationMode.UsingInMemoryTarget;

            if (integratingIntoIntermediaryGrid)
            {
                IntegrateIntoIntermediaryGrid(sourceSubGrid, segmentIterator);
            }
            else
            {
                IntegrateIntoLiveGrid(sourceSubGrid, segmentIterator, subGridChangeNotifier);
            }
        }
Пример #6
0
        public void Test_SubgridSegment_Cleaver()
        {
            // Create a sub grid to hold the segment
            IServerLeafSubGrid subGrid = MakeSubgridWith10240CellPassesAtOneSecondIntervals();

            // Exercise the cleaver!
            // Instruct the segment container to cleave the segment
            // Set the segment to not dirty - it should be ignored
            subGrid.Cells.PassesData[0].Dirty = false;

            var cleaver = new SubGridSegmentCleaver();

            cleaver.PerformSegmentCleaving(StorageProxy.Instance(StorageMutability.Mutable), subGrid, 10000);

            Assert.True(1 == subGrid.Cells.PassesData.Count, $"After cleaving with no dirty segments there are {subGrid.Cells.PassesData.Count} segments instead of the expected one segments");

            // Set the segment to not dirty - it should be ignored
            subGrid.Cells.PassesData[0].Dirty = true;
            cleaver = new SubGridSegmentCleaver();
            cleaver.PerformSegmentCleaving(StorageProxy.Instance(StorageMutability.Mutable), subGrid, 10000);

            //Check there are now two segments in total
            Assert.True(2 == subGrid.Cells.PassesData.Count, $"After cleaving there are {subGrid.Cells.PassesData.Count} segments instead of the expected two segments");

            //Check the total number of passes across the two segments is 10240, and the maximum pass count is 5
            ISubGridCellPassesDataSegment segment1 = subGrid.Cells.PassesData[0];
            ISubGridCellPassesDataSegment segment2 = subGrid.Cells.PassesData[1];

            segment1.PassesData.CalculateTotalPasses(out int totalPassCount1, out _, out int maximumPassCount1);
            segment2.PassesData.CalculateTotalPasses(out int totalPassCount2, out _, out int maximumPassCount2);

            Assert.True(10240 == (totalPassCount1 + totalPassCount2), $"Totals ({totalPassCount1} and {totalPassCount2} don't add up to 10240 after cleaving");
            Assert.True(5 == maximumPassCount1, $"Maximum pass count 1 {maximumPassCount1}, is not 5");
            Assert.True(5 == maximumPassCount2, $"Maximum pass count 2 {maximumPassCount2}, is not 5");

            // Check the segment pass count in the segment is correct
            Assert.True(totalPassCount1 == segment1.PassesData.SegmentPassCount, $"Total passes for segment 1 {totalPassCount1} is not equal to segmentPassCount in that segment {segment1.PassesData.SegmentPassCount}");
            Assert.True(totalPassCount2 == segment2.PassesData.SegmentPassCount, $"Total passes for segment 2 {totalPassCount2} is not equal to segmentPassCount in that segment {segment2.PassesData.SegmentPassCount}");
        }
Пример #7
0
        private void IntegrateIntoIntermediaryGrid(IServerLeafSubGrid sourceSubGrid, ISubGridSegmentIterator segmentIterator)
        {
            var targetSubGrid = _target.ConstructPathToCell(sourceSubGrid.OriginX, sourceSubGrid.OriginY,
                                                            SubGridPathConstructionType.CreateLeaf) as IServerLeafSubGrid;

            targetSubGrid.AllocateLeafFullPassStacks();

            // If the node is brand new (ie: it does not have any cell passes committed to it yet)
            // then create and select the default segment
            if (targetSubGrid.Directory.SegmentDirectory.Count == 0)
            {
                targetSubGrid.Cells.SelectSegment(Consts.MIN_DATETIME_AS_UTC);
                targetSubGrid.Cells.PassesData[0].AllocateFullPassStacks();
            }

            if (targetSubGrid.Cells.PassesData[0].PassesData == null)
            {
                _log.LogCritical("No segment passes data in new segment");
                return;
            }

            targetSubGrid.Integrate(sourceSubGrid, segmentIterator, true);
        }
Пример #8
0
        public void Test_SubgridSegmentCleaving()
        {
            // Create a sub grid to hold the segment. the subGrid retains the limit in the subGrid constructor in MakeSubgridWith10240CellPassesAtOneSecondIntervals()
            IServerLeafSubGrid            subGrid = MakeSubgridWith10240CellPassesAtOneSecondIntervals();
            ISubGridCellPassesDataSegment segment = subGrid.Cells.PassesData[0];

            // Instruct the segment container to cleave the segment with a limit of 100000
            var newSegmentsFromCleaving = new List <ISubGridCellPassesDataSegment>();
            var persistedClovenSegments = new List <ISubGridSpatialAffinityKey>();

            Assert.False(subGrid.Cells.CleaveSegment(segment, newSegmentsFromCleaving, persistedClovenSegments, 100000), "Segment was cloven when cell pass count was below limit");

            // Set the cleaving limit to 10000 to force the segment TO BE cloven = the cleave result should be true
            subGrid = MakeSubgridWith10240CellPassesAtOneSecondIntervals();
            segment = subGrid.Cells.PassesData[0];
            newSegmentsFromCleaving = new List <ISubGridCellPassesDataSegment>();
            persistedClovenSegments = new List <ISubGridSpatialAffinityKey>();
            Assert.True(subGrid.Cells.CleaveSegment(segment, newSegmentsFromCleaving, persistedClovenSegments, 10000), "Segment failed to cleave with pass count above limit");

            //Check there are now two segments in total
            Assert.True(2 == subGrid.Cells.PassesData.Count, $"After cleaving there are {subGrid.Cells.PassesData.Count} segments instead of the expected two segments");

            //Check the total number of passes across the two segments is 10240, and the maximum pass count is 5
            ISubGridCellPassesDataSegment segment1 = subGrid.Cells.PassesData[0];
            ISubGridCellPassesDataSegment segment2 = subGrid.Cells.PassesData[1];

            segment1.PassesData.CalculateTotalPasses(out int totalPassCount1, out _, out int maximumPassCount1);
            segment2.PassesData.CalculateTotalPasses(out int totalPassCount2, out _, out int maximumPassCount2);

            Assert.True(10240 == totalPassCount1 + totalPassCount2, $"Totals ({totalPassCount1} and {totalPassCount2} don't add up to 10240 after cleaving");
            Assert.True(5 == maximumPassCount1, $"Maximum pass count 1 {maximumPassCount1}, is not 5");
            Assert.True(5 == maximumPassCount2, $"Maximum pass count 2 {maximumPassCount2}, is not 5");

            // Check the segment pass count in the segment is correct
            Assert.True(totalPassCount1 == segment1.PassesData.SegmentPassCount, $"Total passes for segment 1 {totalPassCount1} is not equal to segmentPassCount in that segment {segment1.PassesData.SegmentPassCount}");
            Assert.True(totalPassCount2 == segment2.PassesData.SegmentPassCount, $"Total passes for segment 2 {totalPassCount2} is not equal to segmentPassCount in that segment {segment2.PassesData.SegmentPassCount}");
        }
Пример #9
0
        public static void AddMultipleCellsWithPasses(ISiteModel siteModel, int cellX, int cellY,
                                                      List <CellPass[]> passesList, int expectedCellCount = -1, int expectedPassCount = -1)
        {
            // Construct the sub grid to hold the cell being tested
            IServerLeafSubGrid leaf = siteModel.Grid.ConstructPathToCell(cellX, cellY, SubGridPathConstructionType.CreateLeaf) as IServerLeafSubGrid;

            leaf.Should().NotBeNull();

            leaf.AllocateLeafFullPassStacks();
            leaf.CreateDefaultSegment();
            leaf.AllocateFullPassStacks(leaf.Directory.SegmentDirectory.First());
            leaf.AllocateLeafLatestPassGrid();

            // Add the leaf to the site model existence map
            siteModel.ExistenceMap[leaf.OriginX >> SubGridTreeConsts.SubGridIndexBitsPerLevel, leaf.OriginY >> SubGridTreeConsts.SubGridIndexBitsPerLevel] = true;

            long totalCells = 0;

            for (var i = 0; i < passesList.Count; i++)
            {
                //CellPass[] _passes = passes.ToArray();

                byte subGridX = (byte)(cellX & SubGridTreeConsts.SubGridLocalKeyMask);
                byte subGridY = (byte)(cellY & SubGridTreeConsts.SubGridLocalKeyMask);

                foreach (var pass in passesList[i])
                {
                    leaf.AddPass(subGridX, subGridY, pass);
                }

                var cellPasses = leaf.Cells.PassesData[i].PassesData.ExtractCellPasses(subGridX, subGridY);
                if (expectedPassCount > -1)
                {
                    ((int)cellPasses.PassCount).Should().Be(expectedPassCount);
                }

                // Assign global latest cell pass to the appropriate pass
                leaf.Directory.GlobalLatestCells[subGridX, subGridY] = cellPasses.Passes.Last();

                // Ensure the pass data existence map records the existence of a non null value in the cell
                leaf.Directory.GlobalLatestCells.PassDataExistenceMap[subGridX, subGridY] = true;

                if (expectedCellCount > -1)
                {
                    // Count the number of non-null elevation cells to verify a correct setup
                    siteModel.Grid.Root.ScanSubGrids(siteModel.Grid.FullCellExtent(), x =>
                    {
                        totalCells += leaf.Directory.GlobalLatestCells.PassDataExistenceMap.CountBits();
                        return(true);
                    });
                }

                siteModel.SiteModelExtent.Include(siteModel.Grid.GetCellExtents(cellX, cellY));
            }

            totalCells.Should().Be(expectedCellCount);

            // Save the leaf information just created
            siteModel.Grid.SaveLeafSubGrid(leaf, siteModel.PrimaryStorageProxy, siteModel.PrimaryStorageProxy, new List <ISubGridSpatialAffinityKey>());

            siteModel.SaveToPersistentStoreForTAGFileIngest(siteModel.PrimaryStorageProxy);
        }
Пример #10
0
        /// <summary>
        /// Cleaves all dirty segments requiring cleaving within the given sub grid
        /// </summary>
        public void PerformSegmentCleaving(IStorageProxy storageProxyForSubGridSegments, IServerLeafSubGrid subGrid, int subGridSegmentPassCountLimit = 0)
        {
            var iterator = new SubGridSegmentIterator(subGrid, storageProxyForSubGridSegments)
            {
                IterationDirection = IterationDirection.Forwards,
                ReturnDirtyOnly    = true,
                RetrieveAllPasses  = true
            };

            var origin = new SubGridCellAddress(subGrid.OriginX, subGrid.OriginY);

            if (!iterator.MoveToFirstSubGridSegment())
            {
                return;
            }

            do
            {
                var segment = iterator.CurrentSubGridSegment;

                var cleavedTimeRangeStart = segment.SegmentInfo.StartTime;
                var cleavedTimeRangeEnd   = segment.SegmentInfo.EndTime;

                if (!segment.RequiresCleaving(out var totalPassCount, out var maximumPassCount))
                {
                    continue;
                }

                if (subGrid.Cells.CleaveSegment(segment, NewSegmentsFromCleaving, PersistedClovenSegments, subGridSegmentPassCountLimit))
                {
                    iterator.SegmentListExtended();

                    if (_segmentCleavingOperationsToLog)
                    {
                        _log.LogInformation(
                            $"Info: Performed cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {ServerSubGridTree.GetLeafSubGridFullFileName(origin)}. TotalPassCount = {totalPassCount} MaximumPassCount = {maximumPassCount}");
                    }
                }
                else
                {
                    // The segment cleave failed. While this is not a serious problem (as the sub grid will be
                    // cleaved at some point in the future when it is modified again via tag file processing etc)
                    // it will be noted in the log.

                    _log.LogWarning(
                        $"Cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {ServerSubGridTree.GetLeafSubGridFullFileName(origin)} failed. TotalPassCount = {totalPassCount} MaximumPassCount = {maximumPassCount}");
                }

                if (_segmentCleavingOperationsToLog)
                {
                    if (segment.RequiresCleaving(out totalPassCount, out maximumPassCount))
                    {
                        _log.LogWarning(
                            $"Cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {subGrid.Moniker()} failed to reduce cell pass count below maximums (max passes = {totalPassCount}/{subGridSegmentPassCountLimit}, per cell = {maximumPassCount}/{_subGridMaxSegmentCellPassesLimit})");
                    }
                }
            } while (iterator.MoveToNextSubGridSegment());
        }
Пример #11
0
        /// <summary>
        /// Orchestrates all the activities relating to saving the state of a created or modified sub grid, including
        /// cleaving, saving updated elements, creating new elements and arranging for the retirement of
        /// elements that have been replaced in the persistent store as a result of this activity.
        /// </summary>
        public bool SaveLeafSubGrid(IServerLeafSubGrid subGrid,
                                    IStorageProxy storageProxyForSubGrids,
                                    IStorageProxy storageProxyForSubGridSegments,
                                    List <ISubGridSpatialAffinityKey> invalidatedSpatialStreams)
        {
            //Log.LogInformation($"Saving {subGrid.Moniker()} to persistent store");

            try
            {
                // Perform segment cleaving as the first activity in the action of saving a leaf sub grid
                // to disk. This reduces the number of segment cleaving actions that would otherwise
                // be performed in the context of the aggregated integrator.

                if (_segmentCleavingOperationsToLog)
                {
                    _log.LogDebug($"About to perform segment cleaving on {subGrid.Moniker()}");
                }

                var cleaver = new SubGridSegmentCleaver();

                cleaver.PerformSegmentCleaving(storageProxyForSubGridSegments, subGrid);

                // Calculate the cell last pass information here, immediately before it is
                // committed to the persistent store. The reason for this is to remove this
                // compute intensive operation from the critical path in TAG file processing
                // (which is the only writer of this information in the Raptor system).
                // The computer is instructed to do a partial recompute, which will recompute
                // all segments from the first segment marked as dirty.
                subGrid.ComputeLatestPassInformation(false, storageProxyForSubGridSegments);

                if (_segmentCleavingOperationsToLog)
                {
                    _log.LogInformation($"SaveLeafSubGrid: {subGrid.Moniker()} ({subGrid.Cells.PassesData.Count} segments)");
                }

                var modifiedOriginalSegments = new List <ISubGridCellPassesDataSegment>(100);
                var originAddress            = new SubGridCellAddress(subGrid.OriginX, subGrid.OriginY);

                // The following used to be an assert/exception. However, this is may readily
                // happen if there are no modified segments resulting from processing a
                // process TAG file where the Dirty flag for the sub grid is set but no cell
                // passes are added to segments in that sub grid. As this is not an integrity
                // issue the persistence of the modified sub grid is allowed, but noted in
                // the log for posterity.
                if (subGrid.Cells.PassesData.Count == 0)
                {
                    _log.LogInformation(
                        $"Note: Saving a sub grid, {subGrid.Moniker()}, (Segments = {subGrid.Cells.PassesData.Count}, Dirty = {subGrid.Dirty}) with no cached sub grid segments to the persistent store in SaveLeafSubGrid (possible reprocessing of TAG file with no cell pass changes). " +
                        $"SubGrid.Directory.PersistedClovenSegments.Count={cleaver.PersistedClovenSegments?.Count}, ModifiedOriginalFiles.Count={modifiedOriginalSegments.Count}, NewSegmentsFromCleaving.Count={cleaver.NewSegmentsFromCleaving.Count}");
                }

                var iterator = new SubGridSegmentIterator(subGrid, storageProxyForSubGridSegments)
                {
                    IterationDirection = IterationDirection.Forwards,
                    ReturnDirtyOnly    = true,
                };

                //**********************************************************************
                //***Construct list of original segment files that have been modified***
                //*** These files may be updated in-situ with no sub grid/segment    ***
                //*** integrity issues wrt the segment directory in the sub grid     ***
                //**********************************************************************

                iterator.MoveToFirstSubGridSegment();
                while (iterator.CurrentSubGridSegment != null)
                {
                    if (iterator.CurrentSubGridSegment.SegmentInfo.ExistsInPersistentStore && iterator.CurrentSubGridSegment.Dirty)
                    {
                        modifiedOriginalSegments.Add(iterator.CurrentSubGridSegment);
                    }
                    iterator.MoveToNextSubGridSegment();
                }

                //**********************************************************************
                //*** Construct list of spatial streams that will be deleted or replaced
                //*** in the FS file. These will be passed to the call that saves the
                //*** sub grid directory file as an instruction to place them into the
                //*** deferred deletion list
                //**********************************************************************

                lock (invalidatedSpatialStreams)
                {
                    if (cleaver.PersistedClovenSegments != null)
                    {
                        invalidatedSpatialStreams.AddRange(cleaver.PersistedClovenSegments);
                    }

                    invalidatedSpatialStreams.AddRange(modifiedOriginalSegments.Select(x => x.SegmentInfo.AffinityKey(ID)));
                }

                if (cleaver.NewSegmentsFromCleaving.Count > 0)
                {
                    //**********************************************************************
                    //***    Write new segment files generated by cleaving               ***
                    //*** File system integrity failures here will have no effect on the ***
                    //*** sub grid/segment directory as they are not referenced by it.   ***
                    //*** At worst they become orphans they may be cleaned by in the FS  ***
                    //*** recovery phase                                                 ***
                    //**********************************************************************

                    if (_segmentCleavingOperationsToLog)
                    {
                        _log.LogInformation($"Sub grid has {cleaver.NewSegmentsFromCleaving.Count} new segments from cleaving");
                    }

                    foreach (var segment in cleaver.NewSegmentsFromCleaving)
                    {
                        // Update the version of the segment as it is about to be written
                        segment.SegmentInfo.Touch();

                        segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError);
                        segment.Dirty = false;

                        if (fsError == FileSystemErrorStatus.OK)
                        {
                            if (_segmentCleavingOperationsToLog)
                            {
                                _log.LogInformation($"Saved new cloven grid segment file: {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}");
                            }
                        }
                        else
                        {
                            _log.LogWarning($"Failed to save cloven grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}");
                            return(false);
                        }
                    }
                }

                if (modifiedOriginalSegments.Count > 0)
                {
                    //**********************************************************************
                    //***    Write modified segment files                                ***
                    //*** File system integrity failures here will have no effect on the ***
                    //*** sub grid/segment directory as the previous version of the      ***
                    //*** modified file being written will be recovered.                 ***
                    //**********************************************************************

                    if (_log.IsTraceEnabled())
                    {
                        _log.LogTrace($"Sub grid has {modifiedOriginalSegments.Count} modified segments");
                    }

                    foreach (var segment in modifiedOriginalSegments)
                    {
                        // Update the version of the segment as it is about to be written
                        segment.SegmentInfo.Touch();
                        segment.Dirty = false;

                        if (segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError))
                        {
                            segment.Dirty = false;
                            if (_log.IsTraceEnabled())
                            {
                                _log.LogTrace($"Saved modified grid segment file: {segment}");
                            }
                        }
                        else
                        {
                            _log.LogError($"Failed to save modified original grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}");
                            return(false);
                        }
                    }
                }

                // Any remaining dirty segments in the sub grid will be due to previously empty sub grids with newly
                // created segments from ingest processing that have not required cleaving. These segments do not require any
                // special treatment are jsut saved to persistent store

                foreach (var segment in subGrid.Directory.SegmentDirectory.Select(x => x.Segment).Where(x => (x?.Dirty ?? false)))
                {
                    if (segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError))
                    {
                        segment.Dirty = false;
                        if (_log.IsTraceEnabled())
                        {
                            _log.LogTrace($"Saved new sub grid segment file: {segment}");
                        }
                    }
                    else
                    {
                        _log.LogError($"Failed to save new sub grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}");
                        return(false);
                    }
                }

                //**********************************************************************
                //***                 Write the sub grid directory file              ***
                //**********************************************************************

                /*
                 * There is no need to add the sub grid directory stream to the segment retirement
                 * queue as this will be automatically replaced when the new version of the
                 * sub grid directory is written to persistent store.
                 *
                 * // Add the stream representing the sub grid directory file to the list of
                 * // invalidated streams as this stream will be replaced with the stream
                 * // containing the updated directory information. Note: This only needs to
                 * // be done if the sub grid has previously been read from the FS file (if not
                 * // it has been created and not yet persisted to the store.
                 *
                 * if (subGrid.Directory.ExistsInPersistentStore)
                 * {
                 * // Include an additional invalidated spatial stream for the sub grid directory stream
                 * lock (invalidatedSpatialStreams)
                 * {
                 *  invalidatedSpatialStreams.Add(subGrid.AffinityKey());
                 * }
                 * }
                 */

                if (subGrid.SaveDirectoryToFile(storageProxyForSubGrids, GetLeafSubGridFullFileName(originAddress)))
                {
                    if (_log.IsTraceEnabled())
                    {
                        _log.LogTrace($"Saved grid directory file: {GetLeafSubGridFullFileName(originAddress)}");
                    }
                }
                else
                {
                    if (_log.IsTraceEnabled())
                    {
                        _log.LogTrace($"Failed to save grid: {GetLeafSubGridFullFileName(originAddress)}");
                    }
                    return(false);
                }

                //**********************************************************************
                //***                   Reset segment dirty flags                    ***
                //**********************************************************************

                iterator.MoveToFirstSubGridSegment();
                while (iterator.CurrentSubGridSegment != null)
                {
                    iterator.CurrentSubGridSegment.Dirty = false;
                    iterator.CurrentSubGridSegment.SegmentInfo.ExistsInPersistentStore = true;

                    iterator.MoveToNextSubGridSegment();
                }

                //Log.LogInformation($"Completed saving {subGrid.Moniker()} to persistent store");

                return(true);
            }
            catch (Exception e)
            {
                _log.LogError(e, "Exception raised in SaveLeafSubGrid");
            }

            return(false);
        }
Пример #12
0
        public bool LoadLeafSubGrid(IStorageProxy storageProxy,
                                    SubGridCellAddress cellAddress,
                                    bool loadAllPasses, bool loadLatestPasses,
                                    IServerLeafSubGrid subGrid)
        {
            var fullFileName = string.Empty;
            var result       = false;

            try
            {
                // Loading contents into a dirty sub grid (which should happen only on the mutable nodes), or
                // when there is already content in the segment directory are strictly forbidden and break immutability
                // rules for sub grids
                if (subGrid.Dirty)
                {
                    throw new TRexSubGridIOException("Leaf sub grid directory loads may not be performed while the sub grid is dirty. The information should be taken from the cache instead.");
                }

                // Load the cells into it from its file
                // Briefly lock this sub grid just for the period required to read its contents
                lock (subGrid)
                {
                    // If more than thread wants this sub grid then they may concurrently attempt to load it.
                    // Make a check to see if this has happened and another thread has already loaded this sub grid directory.
                    // If so, just return success. Previously the commented out assert was enforced causing exceptions
                    // Debug.Assert(SubGrid.Directory?.SegmentDirectory?.Count == 0, "Loading a leaf sub grid directory when there are already segments present within it.");

                    // Check this thread is the winner of the lock to be able to load the contents
                    if (subGrid.Directory?.SegmentDirectory?.Count == 0)
                    {
                        // Ensure the appropriate storage is allocated
                        if (loadAllPasses)
                        {
                            subGrid.AllocateLeafFullPassStacks();
                        }

                        if (loadLatestPasses)
                        {
                            subGrid.AllocateLeafLatestPassGrid();
                        }

                        fullFileName = GetLeafSubGridFullFileName(cellAddress);

                        // Briefly lock this sub grid just for the period required to read its contents
                        result = subGrid.LoadDirectoryFromFile(storageProxy, fullFileName);
                    }
                    else
                    {
                        // A previous thread has already read the directory so there is nothing more to do, return a true result.
                        return(true);
                    }
                }
            }
            finally
            {
                if (result && RecordSubGridFileReadingToLog)
                {
                    _log.LogDebug($"Sub grid file {fullFileName} read from persistent store containing {subGrid.Directory.SegmentDirectory.Count} segments (Moniker: {subGrid.Moniker()}");
                }
            }

            return(result);
        }
Пример #13
0
        public FileSystemErrorStatus LoadLeafSubGridSegment(IStorageProxy storageProxy,
                                                            SubGridCellAddress cellAddress,
                                                            bool loadLatestData,
                                                            bool loadAllPasses,
                                                            IServerLeafSubGrid subGrid,
                                                            ISubGridCellPassesDataSegment segment)
        {
            //Log.LogInformation($"Segment load on {cellAddress}:{Segment.SegmentInfo.StartTime}-{Segment.SegmentInfo.EndTime} beginning, loadLatestData = {loadLatestData}, loadAllPasses = {loadAllPasses}");

            var needToLoadLatestData = loadLatestData && !segment.HasLatestData;
            var needToLoadAllPasses  = loadAllPasses && !segment.HasAllPasses;

            if (!needToLoadLatestData && !needToLoadAllPasses)
            {
                //Log.LogInformation($"Segment load on {cellAddress} exiting as neither latest nor all passes required");
                return(FileSystemErrorStatus.OK); // Nothing more to do here
            }

            // Lock the segment briefly while its contents is being loaded
            lock (segment)
            {
                if (!(needToLoadLatestData ^ segment.HasLatestData) && !(needToLoadAllPasses ^ segment.HasAllPasses))
                {
                    //Log.LogInformation($"Segment load on {cellAddress} leaving quietly as a previous thread has performed the load");
                    return(FileSystemErrorStatus.OK); // The load operation was performed on another thread. Leave quietly
                }

                // Ensure the appropriate storage is allocated
                if (needToLoadLatestData)
                {
                    segment.AllocateLatestPassGrid();
                }

                if (needToLoadAllPasses)
                {
                    segment.AllocateFullPassStacks();
                }

                if (!segment.SegmentInfo.ExistsInPersistentStore)
                {
                    //Log.LogInformation($"Segment load on {cellAddress} exiting as segment does not exist in persistent store");
                    return(FileSystemErrorStatus.OK); // Nothing more to do here
                }

                // Locate the segment file and load the data from it
                var fullFileName = GetLeafSubGridSegmentFullFileName(cellAddress, segment.SegmentInfo);

                // Load the cells into it from its file
                var fsError = subGrid.LoadSegmentFromStorage(storageProxy, fullFileName, segment, needToLoadLatestData, needToLoadAllPasses);

                if (fsError != FileSystemErrorStatus.OK)
                {
                    //Log.LogInformation($"Segment load on {cellAddress} failed, performing allocation cleanup activities");

                    // Something bad happened. Remove the segment from the list. Return failure to the caller.
                    if (loadAllPasses)
                    {
                        segment.DeAllocateFullPassStacks();
                    }

                    if (loadLatestData)
                    {
                        segment.DeAllocateLatestPassGrid();
                    }

                    return(fsError);
                }
            }

            //Log.LogInformation($"Segment load on {cellAddress} succeeded, AllPasses?={Segment.HasAllPasses}, Segment.PassesData?Null={Segment.PassesData==null} ");

            return(FileSystemErrorStatus.OK);
        }
Пример #14
0
        /// <summary>
        /// Orchestrates the mainline work of analyzing cell and cell pass information to create a client sub grid (heights, CMV, MDP etc)
        /// based on filter and other information established in the class
        /// </summary>
        /// <param name="clientGrid"></param>
        /// <param name="cellOverrideMask"></param>
        /// <returns></returns>
        public virtual ServerRequestResult RetrieveSubGrid(IClientLeafSubGrid clientGrid,
                                                           SubGridTreeBitmapSubGridBits cellOverrideMask,
                                                           out bool sieveFilterInUse,
                                                           Func <ServerRequestResult> computeSpatialFilterMaskAndClientProdDataMap)
        {
            sieveFilterInUse = false;

            if (!Utilities.DerivedGridDataTypesAreCompatible(_gridDataType, clientGrid.GridDataType))
            {
                throw new TRexSubGridProcessingException($"Grid data type of client leaf sub grid [{clientGrid.GridDataType}] is not compatible with the grid data type of retriever [{_gridDataType}]");
            }

            var result = ServerRequestResult.UnknownError;

            //  SIGLogMessage.PublishNoODS(Nil, Format('In RetrieveSubGrid: Active pass filters = %s, Active cell filters = %s', [PassFilter.ActiveFiltersText, CellFilter.ActiveFiltersText]));

            // Set up class local state for other methods to access
            _clientGrid       = clientGrid;
            _clientGridAsLeaf = clientGrid as ClientLeafSubGrid;

            _canUseGlobalLatestCells &=
                !(_gridDataType == GridDataType.CCV ||
                  _gridDataType == GridDataType.CCVPercent) &&
                _liftParams.CCVSummaryTypes != CCVSummaryTypes.None &&
                !(_gridDataType == GridDataType.MDP ||
                  _gridDataType == GridDataType.MDPPercent) &&
                _liftParams.MDPSummaryTypes != MDPSummaryTypes.None &&
                !(_gridDataType == GridDataType.CCA || _gridDataType == GridDataType.CCAPercent) &&
                !(_gridDataType == GridDataType.CellProfile ||
                  _gridDataType == GridDataType.PassCount ||
                  _gridDataType == GridDataType.CellPasses ||
                  _gridDataType == GridDataType.MachineSpeed ||
                  _gridDataType == GridDataType.CCVPercentChange ||
                  _gridDataType == GridDataType.MachineSpeedTarget ||
                  _gridDataType == GridDataType.CCVPercentChangeIgnoredTopNullValue);

            // Support for lazy construction of any required profiling infrastructure
            if (_clientGrid.WantsLiftProcessingResults() && _profiler == null)
            {
                // Some display types require lift processing to be able to select the
                // appropriate cell pass containing the filtered value required.

                _profiler = DIContext.Obtain <IProfilerBuilder <ProfileCell> >();

                //TODO: should referenceDesignWrapper be null here or be passed through from args?
                _profiler.Configure(ProfileStyle.CellPasses, _siteModel, _pdExistenceMap, _gridDataType, new FilterSet(_filter),
                                    null, _populationControl, new CellPassFastEventLookerUpper(_siteModel), VolumeComputationType.None, _overrides, _liftParams);

                _cellProfile = new ProfileCell();

                // Create and configure the assignment context which is used to contain
                // a filtered pass and its attendant machine events and target values
                // prior to assignment to the client sub grid.
                _assignmentContext.CellProfile = _cellProfile;
            }

            try
            {
                // Ensure pass type filter is set correctly
                if (_filter.AttributeFilter.HasPassTypeFilter)
                {
                    if ((_filter.AttributeFilter.PassTypeSet & (PassTypeSet.Front | PassTypeSet.Rear)) == PassTypeSet.Front)
                    {
                        _filter.AttributeFilter.PassTypeSet |= PassTypeSet.Rear; // these two types go together as half passes
                    }
                }
                // ... unless we can use the last pass grid to satisfy the query
                if (_canUseGlobalLatestCells &&
                    !_filter.AttributeFilter.HasElevationRangeFilter &&
                    !_clientGrid.WantsLiftProcessingResults() &&
                    !_filter.AttributeFilter.HasElevationMappingModeFilter &&
                    !(_filter.AttributeFilter.HasElevationTypeFilter &&
                      (_filter.AttributeFilter.ElevationType == ElevationType.Highest ||
                       _filter.AttributeFilter.ElevationType == ElevationType.Lowest)) &&
                    !(_gridDataType == GridDataType.PassCount || _gridDataType == GridDataType.Temperature ||
                      _gridDataType == GridDataType.CellProfile || _gridDataType == GridDataType.CellPasses ||
                      _gridDataType == GridDataType.MachineSpeed))
                {
                    _useLastPassGrid = true;
                }

                // First get the sub grid we are interested in
                // SIGLogMessage.PublishNoODS(Nil, Format('Begin LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.OriginY]));

                _subGrid = SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining(_storageProxy, _siteModel.Grid, clientGrid.OriginX, clientGrid.OriginY, _siteModel.Grid.NumLevels, false, false);

                //  SIGLogMessage.PublishNoODS(Nil, Format('End LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.Origin]));

                if (_subGrid == null) // This should never really happen, but we'll be polite about it
                {
                    Log.LogWarning(
                        $"Sub grid address (CellX={clientGrid.OriginX}, CellY={clientGrid.OriginY}) passed to LocateSubGridContaining() from RetrieveSubGrid() did not match an existing sub grid in the data model. Returning SubGridNotFound as response with a null sub grid reference.");
                    return(ServerRequestResult.SubGridNotFound);
                }

                // Now process the contents of that sub grid into the sub grid to be returned to the client.

                if (!_subGrid.IsLeafSubGrid())
                {
                    Log.LogInformation("Requests of node sub grids in the server sub grid are not yet supported");
                    return(result);
                }

                if (!(_subGrid is IServerLeafSubGrid))
                {
                    Log.LogError($"_SubGrid {_subGrid.Moniker()} is not a server grid leaf node");
                    return(result);
                }

                // SIGLogMessage.PublishNoODS(Nil, Format('Getting sub grid leaf at %dx%d', [clientGrid.OriginX, clientGrid.OriginY]));

                _subGridAsLeaf     = (IServerLeafSubGrid)_subGrid;
                _globalLatestCells = _subGridAsLeaf.Directory.GlobalLatestCells;

                if (PruneSubGridRetrievalHere())
                {
                    return(ServerRequestResult.NoError);
                }

                // SIGLogMessage.PublishNoODS(Nil, Format('Setup for stripe iteration at %dx%d', [clientGrid.OriginX, clientGrid.OriginY]));

                SetupForCellPassStackExamination();

                // Determine if a sieve filter is required for the sub grid where the sieve matches
                // the X and Y pixel world size (used for WMS tile computation)
                _subGrid.CalculateWorldOrigin(out var subGridWorldOriginX, out var subGridWorldOriginY);

                sieveFilterInUse = _areaControlSet.UseIntegerAlgorithm
          ? GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, _subGrid.Moniker(), _areaControlSet, _siteModel.CellSize, out _sieveBitmask)
          : GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, _areaControlSet, _siteModel.CellSize, _assignmentContext, out _sieveBitmask);

                //if (Debug_ExtremeLogSwitchC) Log.LogDebug($"Performing stripe iteration at {clientGrid.OriginX}x{clientGrid.OriginY}");

                if (computeSpatialFilterMaskAndClientProdDataMap != null)
                {
                    _clientGrid.ProdDataMap.Assign(_subGridAsLeaf.Directory.GlobalLatestCells.PassDataExistenceMap);
                    var innerResult = computeSpatialFilterMaskAndClientProdDataMap();
                    if (innerResult != ServerRequestResult.NoError)
                    {
                        return(innerResult);
                    }
                }

                // Before iterating over stripes of this sub grid, compute a scan map detailing to the best of our current
                // knowledge, which cells need to be visited so that only cells the filter wants and which are actually
                // present in the data set are requested. If the intent is to store the result in a cache then ensure the
                // entire content is requested for the sub grid.
                if (_prepareGridForCacheStorageIfNoSieving)
                {
                    _aggregatedCellScanMap.Fill();
                }
                else
                {
                    _aggregatedCellScanMap.OrWith(_globalLatestCells.PassDataExistenceMap);

                    if (sieveFilterInUse)
                    {
                        _aggregatedCellScanMap.AndWith(_sieveBitmask);             // ... and which are required by any sieve mask
                    }
                    _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.ProdDataMap); // ... and which are in the required production data map
                    _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.FilterMap);   // ... and which are in the required filter map
                }

                // Iterate over the stripes in the sub grid processing each one in turn.
                for (byte i = 0; i < SubGridTreeConsts.SubGridTreeDimension; i++)
                {
                    RetrieveSubGridStripe(i);
                }

                //if Debug_ExtremeLogSwitchC then Log.LogDebug($"Stripe iteration complete at {clientGrid.OriginX}x{clientGrid.OriginY}");

                result = ServerRequestResult.NoError;
            }
            catch (Exception e)
            {
                Log.LogError(e, $"Exception occurred in {nameof(RetrieveSubGrid)}");
                throw;
            }

            return(result);
        }
Пример #15
0
        /// <summary>
        /// Locates the sub grid in the sub grid tree that contains the cell identified by CellX and CellY in the global
        /// sub grid tree cell address space. The tree level for the sub grid returned is specified in Level.
        /// </summary>
        public static ISubGrid LocateSubGridContaining(IStorageProxy storageProxyForSubGrids,
                                                       IServerSubGridTree forSubGridTree,
                                                       //const GridDataCache : TICDataStoreCache;
                                                       int cellX,
                                                       int cellY,
                                                       byte level,
                                                       bool lookInCacheOnly,
                                                       bool acceptSpeculativeReadFailure)
        {
            IServerLeafSubGrid leafSubGrid = null;
            var createdANewSubGrid         = false;

            ISubGrid result = null;

            if (forSubGridTree == null)
            {
                throw new TRexSubGridProcessingException($"Sub grid tree null in {nameof(LocateSubGridContaining)}");
            }

            // Note: Sub grid tree specific interlocks are no longer used. The tree now internally
            // manages fine grained locks across structurally mutating activities such as node/leaf
            // sub grid addition and reading content from the persistent store.

            // First check to see if the requested cell is present in a leaf sub grid
            var subGrid = forSubGridTree.LocateClosestSubGridContaining(cellX, cellY, level);

            if (subGrid == null) // Something bad happened
            {
                _log.LogWarning($"Failed to locate sub grid at {cellX}:{cellY}, level {level}, data model ID:{forSubGridTree.ID}");
                return(null);
            }

            if (!subGrid.IsLeafSubGrid() && !lookInCacheOnly && level == forSubGridTree.NumLevels)
            {
                if (forSubGridTree.CachingStrategy == ServerSubGridTreeCachingStrategy.CacheSubGridsInTree)
                {
                    // Create the leaf sub grid that will be used to read in the sub grid from the disk.
                    // In the case where the sub grid isn't present on the disk this reference will be destroyed
                    subGrid = forSubGridTree.ConstructPathToCell(cellX, cellY, Types.SubGridPathConstructionType.CreateLeaf);
                }
                else if (forSubGridTree.CachingStrategy == ServerSubGridTreeCachingStrategy.CacheSubGridsInIgniteGridCache)
                {
                    // Create the leaf sub grid without constructing elements in the grid to represent it other than the
                    // path in the tree to the parent of the sub grid.
                    // Note: Setting owner and parent relationship from the sub grid to the tree in this fashion permits
                    // business logic in th sub grid that require knowledge of it parent and owner relationships to function
                    // correctly while not including a reference to the sub grid from the tree.
                    subGrid = forSubGridTree.CreateNewSubGrid(forSubGridTree.NumLevels);
                    subGrid.SetAbsoluteOriginPosition(cellX & ~SubGridTreeConsts.SubGridLocalKeyMask, cellY & ~SubGridTreeConsts.SubGridLocalKeyMask);
                    subGrid.Owner  = forSubGridTree;
                    subGrid.Parent = forSubGridTree.ConstructPathToCell(cellX, cellY, Types.SubGridPathConstructionType.CreatePathToLeaf);
                }

                if (subGrid != null)
                {
                    createdANewSubGrid = true;
                }
                else
                {
                    _log.LogError($"Failed to create leaf sub grid in LocateSubGridContaining for sub grid at {cellX}x{cellY}");
                    return(null);
                }
            }

            if (subGrid.IsLeafSubGrid())
            {
                leafSubGrid = subGrid as IServerLeafSubGrid;
            }

            if (leafSubGrid == null) // Something bad happened
            {
                _log.LogError($"Sub grid request result for {cellX}:{cellY} is not a leaf sub grid, it is a {subGrid.GetType().Name}.");
                return(null);
            }

            if (!createdANewSubGrid)
            {
                if (lookInCacheOnly)
                {
                    if (subGrid.Level == level)
                    {
                        return(subGrid);
                    }

                    // If the returned sub grid is a leaf sub grid then it was already present in the
                    // cache. If the level of the returned sub grid matches the request level parameter
                    // then there is nothing more to do here.
                    if (subGrid.IsLeafSubGrid() &&
                        ((leafSubGrid.HasSubGridDirectoryDetails || leafSubGrid.Dirty) &&
                         leafSubGrid.HasAllCellPasses() && leafSubGrid.HasLatestData()) ||
                        (!subGrid.IsLeafSubGrid() && subGrid.Level == level))
                    {
                        return(subGrid);
                    }
                }
            }

            if ((!leafSubGrid.HasSubGridDirectoryDetails && !leafSubGrid.Dirty) ||
                !(leafSubGrid.HasAllCellPasses() && leafSubGrid.HasLatestData()))
            {
                // The requested cell is either not present in the sub grid tree (cache),
                // or it is residing on disk, and a newly created sub grid has been constructed
                // to contain the data read from disk.

                // The underlying assumption is that this method is only called if the caller knows
                // that the sub grid exists in the sub grid tree (this is known via the sub grid existence
                // map available to the caller). In cases where eventual consistency
                // may mean that a sub grid was removed from the sub grid tree since the caller retrieved
                // its copy of the sub grid existence map this function will fail gracefully with a null sub grid.
                // The exception to this rule is the tag file processor service which may speculatively
                // attempt to read a sub grid that doesn't exist.
                // This is a different approach to desktop systems where the individual node sub grids
                // contain mini existence maps for the sub grids below them.

                if (forSubGridTree.LoadLeafSubGrid(storageProxyForSubGrids,
                                                   new SubGridCellAddress(cellX, cellY),
                                                   true, true,
                                                   leafSubGrid))
                {
                    // We've loaded it - get the reference to the new sub grid and return it
                    result = leafSubGrid;
                }
                else
                {
                    // The sub grid could not be loaded. This is likely due to it not ever existing
                    // in the model, or it may have been deleted. Failure here does not necessarily
                    // constitute evidence of corruption in the data model. Examination of the
                    // spatial existence map in conjunction with the requested sub grid index is
                    // required to determine that. Advise the caller nothing was read by sending back
                    // a null sub grid reference.
                    // The failed sub grid is not proactively deleted and will remain so the normal cache
                    // expiry mechanism can remove it in its normal operations

                    if (acceptSpeculativeReadFailure)
                    {
                        // Return the otherwise empty sub grid back to the caller and integrate it into the cache
                        if (_log.IsTraceEnabled())
                        {
                            _log.LogTrace($"Speculative read failure accepted for sub grid {leafSubGrid.Moniker()}. Blank sub grid returned to caller.");
                        }

                        result = leafSubGrid;
                    }
                    else
                    {
                        _log.LogWarning($"Failed to read leaf sub grid {leafSubGrid.Moniker()} in model {forSubGridTree.ID}. Failed sub grid is NOT removed from the tree");

                        // Empty the sub grid leaf based data to encourage it to be read on a secondary attempt
                        leafSubGrid.DeAllocateLeafFullPassStacks();
                        leafSubGrid.DeAllocateLeafLatestPassGrid();
                    }
                }
            }

            // Ignite special case - allow Dirty leaf sub grids to be returned
            if (result == null)
            {
                if (leafSubGrid.HasSubGridDirectoryDetails && leafSubGrid.Dirty && leafSubGrid.HasAllCellPasses() && leafSubGrid.HasLatestData())
                {
                    result = leafSubGrid;
                }
            }

            // IGNITE: Last gasp - if the sub grid is in memory and has directory details then just return it
            if (result == null && leafSubGrid.HasSubGridDirectoryDetails)
            {
                result = leafSubGrid;
            }

            return(result);
        }
Пример #16
0
        ///  <summary>
        ///  Builds a fully analyzed vector of profiled cells from the list of cell passed to it
        ///  </summary>
        public override bool Analyze(List <SummaryVolumeProfileCell> profileCells, ISubGridSegmentCellPassIterator cellPassIterator)
        {
            Log.LogDebug($"Analyze Summary Volume ProfileCells. Processing {profileCells.Count}");

            var                CurrentSubgridOrigin = new SubGridCellAddress(int.MaxValue, int.MaxValue);
            ISubGrid           SubGrid        = null;
            IServerLeafSubGrid _SubGridAsLeaf = null;

            profileCell = null;

            // Construct the set of requestors to query elevation sub grids needed for the summary volume calculations.
            var filterSet = FilterUtilities.ConstructFilters(FilterSet, VolumeType);

            IntermediaryFilterRequired = filterSet.Filters.Length == 3;
            var utilities = DIContext.Obtain <IRequestorUtilities>();

            Requestors = utilities.ConstructRequestors(null, SiteModel, Overrides, LiftParams,
                                                       utilities.ConstructRequestorIntermediaries(SiteModel, filterSet, true, GridDataType.HeightAndTime),
                                                       AreaControlSet.CreateAreaControlSet(), PDExistenceMap);

            var cellOverrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled);

            for (int I = 0; I < profileCells.Count; I++)
            {
                profileCell = profileCells[I];

                // get sub grid origin for cell address
                var thisSubgridOrigin = new SubGridCellAddress(profileCell.OTGCellX >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                                                               profileCell.OTGCellY >> SubGridTreeConsts.SubGridIndexBitsPerLevel);

                if (!CurrentSubgridOrigin.Equals(thisSubgridOrigin)) // if we have a new sub grid to fetch
                {
                    // if we have an existing sub grid and a change in sub grid detected process the current sub grid profile cell list
                    if (SubGrid != null)
                    {
                        ProcessSubGroup(new SubGridCellAddress(CurrentSubgridOrigin.X << SubGridTreeConsts.SubGridIndexBitsPerLevel, CurrentSubgridOrigin.Y << SubGridTreeConsts.SubGridIndexBitsPerLevel),
                                        PDExistenceMap[CurrentSubgridOrigin.X, CurrentSubgridOrigin.Y], cellOverrideMask);
                        cellOverrideMask.Clear();
                    }

                    SubGrid     = null;
                    cellCounter = 0;

                    // Does the sub grid tree contain this node in it's existence map? if so get sub grid
                    if (PDExistenceMap[thisSubgridOrigin.X, thisSubgridOrigin.Y])
                    {
                        SubGrid = SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining
                                      (SiteModel.PrimaryStorageProxy, SiteModel.Grid, profileCell.OTGCellX, profileCell.OTGCellY, SiteModel.Grid.NumLevels, false, false);
                    }

                    _SubGridAsLeaf = SubGrid as ServerSubGridTreeLeaf;
                    if (_SubGridAsLeaf == null)
                    {
                        continue;
                    }

                    CurrentSubgridOrigin = thisSubgridOrigin; // all good to proceed with this sub grid
                }

                profileCellList[cellCounter++] = profileCell; // add cell to list to process for this sub grid
                cellOverrideMask.SetBit(profileCell.OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask, profileCell.OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask);
            }

            if (cellCounter > 0 && SubGrid != null) // Make sure we process last list
            {
                ProcessSubGroup(new SubGridCellAddress(CurrentSubgridOrigin.X << SubGridTreeConsts.SubGridIndexBitsPerLevel, CurrentSubgridOrigin.Y << SubGridTreeConsts.SubGridIndexBitsPerLevel),
                                PDExistenceMap[CurrentSubgridOrigin.X, CurrentSubgridOrigin.Y], cellOverrideMask);
            }

            return(true);
        }
Пример #17
0
        /// <summary>
        /// Set up a model with a single sub grid with a single cell containing 3 cell passes
        /// </summary>
        /// <returns></returns>
        private ISiteModel CreateSiteModelWithSingleCellForTesting()
        {
            var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(DITagFileFixture.NewSiteModelGuid, true);

            // Switch to mutable storage representation to allow creation of content in the site model
            siteModel.StorageRepresentationToSupply.Should().Be(StorageMutability.Immutable);
            siteModel.SetStorageRepresentationToSupply(StorageMutability.Mutable);

            siteModel.Machines.CreateNew("Test Machine", "", MachineType.Dozer, DeviceTypeEnum.SNM940, false, Guid.NewGuid());

            // vibrationState is needed to get cmv values
            siteModel.MachinesTargetValues[0].VibrationStateEvents.PutValueAtDate(BASE_TIME, VibrationState.On);
            siteModel.MachinesTargetValues[0].AutoVibrationStateEvents.PutValueAtDate(BASE_TIME, AutoVibrationState.Manual);

            // Construct the sub grid to hold the cell being tested
            IServerLeafSubGrid leaf = siteModel.Grid.ConstructPathToCell(SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridPathConstructionType.CreateLeaf) as IServerLeafSubGrid;

            leaf.Should().NotBeNull();

            leaf.AllocateLeafFullPassStacks();
            leaf.CreateDefaultSegment();
            leaf.AllocateFullPassStacks(leaf.Directory.SegmentDirectory.First());
            leaf.AllocateLeafLatestPassGrid();

            // Add the leaf to the site model existence map
            siteModel.ExistenceMap[leaf.OriginX >> SubGridTreeConsts.SubGridIndexBitsPerLevel, leaf.OriginY >> SubGridTreeConsts.SubGridIndexBitsPerLevel] = true;
            siteModel.Grid.CountLeafSubGridsInMemory().Should().Be(1);

            // Add three passes, each separated by 10 seconds and descending by 100mm each pass
            for (int i = 0; i < PASSES_IN_DECREMENTING_ELEVATION_LIST; i++)
            {
                leaf.AddPass(0, 0, new CellPass
                {
                    InternalSiteModelMachineIndex = 0,
                    Time                = BASE_TIME.AddSeconds(i * TIME_INCREMENT_SECONDS),
                    Height              = BASE_HEIGHT + i * HEIGHT_DECREMENT,
                    PassType            = PassType.Front,
                    CCV                 = CCV_Test,
                    MDP                 = MDP_Test,
                    MaterialTemperature = Temperature_Test
                });
            }

            var cellPasses = leaf.Cells.PassesData[0].PassesData.ExtractCellPasses(0, 0);

            cellPasses.Passes.Count.Should().Be(PASSES_IN_DECREMENTING_ELEVATION_LIST);

            // Assign global latest cell pass to the appropriate pass
            leaf.Directory.GlobalLatestCells[0, 0] = cellPasses.Passes.Last();

            // Ensure the pass data existence map records the existence of a non null value in the cell
            leaf.Directory.GlobalLatestCells.PassDataExistenceMap[0, 0] = true;

            // Count the number of non-null elevation cells to verify a correct setup
            long totalCells = 0;

            siteModel.Grid.Root.ScanSubGrids(siteModel.Grid.FullCellExtent(), x => {
                totalCells += leaf.Directory.GlobalLatestCells.PassDataExistenceMap.CountBits();
                return(true);
            });
            totalCells.Should().Be(1);

            return(siteModel);
        }