| | | 1 | | //======================================================================= |
| | | 2 | | // NavigationAutomaticSeamRefreshWork.cs |
| | | 3 | | //======================================================================= |
| | | 4 | | // MIT License, Copyright (c) 2024-present David Oravsky (mrdav30) |
| | | 5 | | // See LICENSE file in the project root for full license information. |
| | | 6 | | //======================================================================= |
| | | 7 | | |
| | | 8 | | using System; |
| | | 9 | | using GridForge.Configuration; |
| | | 10 | | using GridForge.Grids; |
| | | 11 | | using GridForge.Grids.Topology; |
| | | 12 | | |
| | | 13 | | namespace Trailblazer.Pathing; |
| | | 14 | | |
| | | 15 | | /// <summary>Applies bounded incident automatic-seam changes to one unpublished graph candidate.</summary> |
| | | 16 | | internal sealed class NavigationAutomaticSeamRefreshWork |
| | | 17 | | { |
| | | 18 | | internal const long FixedRetainedBytes = 3_480L; |
| | | 19 | | |
| | | 20 | | private const int CursorHeight = 64; |
| | | 21 | | private const int PairDeltaNodeBytes = 104; |
| | | 22 | | private const int AddressDeltaNodeBytes = 80; |
| | | 23 | | private const int LinkDeltaNodeBytes = 72; |
| | | 24 | | private const long PairDeltaBytes = 40L; |
| | | 25 | | private const long AddressDeltaBytes = 56L; |
| | | 26 | | private const long LinkDeltaBytes = 24L; |
| | | 27 | | |
| | 1 | 28 | | private static readonly NavigationSeamEditTree<NavigationAutomaticSeamPairKey, PairDelta> |
| | 1 | 29 | | EmptyPairDeltas = new(PairDeltaNodeBytes); |
| | 1 | 30 | | private static readonly NavigationSeamEditTree<NavigationCellAddress, AddressDelta> |
| | 1 | 31 | | EmptyAddressDeltas = new(AddressDeltaNodeBytes); |
| | 1 | 32 | | private static readonly NavigationSeamEditTree<NavigationAutomaticSeamLinkKey, LinkDelta> |
| | 1 | 33 | | EmptyLinkDeltas = new(LinkDeltaNodeBytes); |
| | | 34 | | |
| | | 35 | | private readonly GridWorld _world; |
| | | 36 | | private readonly NavigationWorldGraph _sourceGraph; |
| | | 37 | | private readonly NavigationWorldGraph _preparedGraph; |
| | | 38 | | private readonly NavigationOperationFrameChange[] _changes; |
| | | 39 | | private readonly int _changeCount; |
| | | 40 | | private readonly GridEventInfo[] _gridEvents; |
| | | 41 | | private readonly int _gridEventCount; |
| | | 42 | | private readonly PersistentStringMap<bool> _discoveryMapIds; |
| | | 43 | | private readonly bool _fullRebuild; |
| | | 44 | | private NavigationSeamEditToken _ownershipToken; |
| | 3242 | 45 | | private GridBoundaryContactCursor _cursor = new(); |
| | 3242 | 46 | | private GridBoundaryContactCursor _validatorCursor = new(); |
| | 3242 | 47 | | private readonly GridBoundaryContact[] _contact = new GridBoundaryContact[1]; |
| | | 48 | | private NavigationAutomaticSeamIndex _working; |
| | 3242 | 49 | | private PersistentStringMap<bool> _changedMapIds = PersistentStringMap<bool>.Empty; |
| | 3242 | 50 | | private NavigationCellAddressSet _changedStructuralEndpoints = |
| | 3242 | 51 | | NavigationCellAddressSet.Empty; |
| | | 52 | | |
| | | 53 | | private NavigationSeamEditTree<NavigationAutomaticSeamPairKey, PairDelta>.Editor? _pairEditor; |
| | | 54 | | private NavigationSeamEditTree<NavigationAutomaticSeamPairKey, PairDelta>? _pairDeltas; |
| | | 55 | | private NavigationSeamEditTree<NavigationAutomaticSeamPairKey, PairDelta>.Cursor? _pairCursor; |
| | | 56 | | private NavigationSeamEditTree<NavigationCellAddress, AddressDelta>.Editor? _addressEditor; |
| | | 57 | | private NavigationSeamEditTree<NavigationCellAddress, AddressDelta>? _addressDeltas; |
| | | 58 | | private NavigationSeamEditTree<NavigationCellAddress, AddressDelta>.Cursor? _addressCursor; |
| | | 59 | | private NavigationSeamEditTree<NavigationAutomaticSeamLinkKey, LinkDelta>.Editor? _linkEditor; |
| | | 60 | | private NavigationSeamEditTree<NavigationAutomaticSeamLinkKey, LinkDelta>? _linkDeltas; |
| | | 61 | | private NavigationSeamEditTree<NavigationAutomaticSeamLinkKey, LinkDelta>.Cursor? _linkCursor; |
| | | 62 | | private NavigationAutomaticSeamIndex.EditSession? _indexEditor; |
| | | 63 | | |
| | | 64 | | private NavigationSeamEditTree<NavigationCellAddress, NavigationPagedSequence<NavigationAutomaticSeamPair>>.Cursor? |
| | | 65 | | _dependencyCursor; |
| | | 66 | | private NavigationAutomaticSeamIndex.EndpointEnumerator _dependencyRow; |
| | | 67 | | private NavigationCellAddress _dependencyAddress; |
| | | 68 | | private int _dependencyRowRemaining; |
| | | 69 | | |
| | | 70 | | private NavigationAutomaticSeamPair? _pendingPair; |
| | | 71 | | private MutationKind _pendingMutation; |
| | | 72 | | private int _mutationStage; |
| | | 73 | | private bool _pendingPairOwned; |
| | | 74 | | |
| | | 75 | | private PairDelta? _currentPairDelta; |
| | | 76 | | private NavigationAutomaticSeamPairKey _currentPairKey; |
| | | 77 | | private int _pairApplyStage; |
| | | 78 | | private bool _currentGeometryChanged; |
| | | 79 | | private bool _currentActiveChanged; |
| | | 80 | | private bool _currentActiveRowChanged; |
| | | 81 | | private bool _currentStructuralLinkChanged; |
| | | 82 | | |
| | | 83 | | private AddressDelta? _currentAddressDelta; |
| | | 84 | | private NavigationCellAddress _currentAddress; |
| | | 85 | | private int _addressApplyStage; |
| | | 86 | | private RowKind _rowKind; |
| | | 87 | | private NavigationPagedSequence<NavigationAutomaticSeamPair>.Enumerator _sourceRow; |
| | | 88 | | private NavigationPagedSequence<NavigationAutomaticSeamPair>.Enumerator _additionRow; |
| | | 89 | | private bool _sourceRowHasNext; |
| | | 90 | | private bool _sourceRowComplete; |
| | | 91 | | private bool _additionRowHasNext; |
| | | 92 | | private bool _additionRowComplete; |
| | | 93 | | private NavigationAutomaticSeamPair? _sourceRowPair; |
| | | 94 | | private NavigationAutomaticSeamPair? _additionRowPair; |
| | | 95 | | private NavigationAutomaticSeamPair? _pendingRowOutput; |
| | | 96 | | private NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder? _rowBuilder; |
| | | 97 | | |
| | | 98 | | private NavigationAutomaticSeamLinkKey _currentLinkKey; |
| | | 99 | | private LinkDelta? _currentLinkDelta; |
| | | 100 | | private bool _linkDeltaReady; |
| | | 101 | | private bool _linkDeltaComplete; |
| | | 102 | | private string? _linkSourceMapId; |
| | | 103 | | private NavigationPagedSequence<NavigationStructuralLink>.Enumerator _sourceLinks; |
| | | 104 | | private bool _sourceLinkReady; |
| | | 105 | | private bool _sourceLinksComplete; |
| | | 106 | | private NavigationStructuralLink _sourceLink; |
| | | 107 | | private NavigationStructuralLink? _pendingLinkOutput; |
| | | 108 | | private NavigationPagedSequence<NavigationStructuralLink>.Builder? _linkBuilder; |
| | | 109 | | |
| | | 110 | | private long _pairDeltaPayloadBytes; |
| | | 111 | | private int _pairDeltaPayloadPages; |
| | | 112 | | private long _addressDeltaPayloadBytes; |
| | | 113 | | private int _addressDeltaPayloadPages; |
| | | 114 | | private long _linkDeltaPayloadBytes; |
| | | 115 | | private int _linkDeltaPayloadPages; |
| | | 116 | | private long _sealedIndexBytes; |
| | | 117 | | private int _sealedIndexPages; |
| | | 118 | | |
| | | 119 | | private string? _modeMapId; |
| | | 120 | | private GridConfigurationKey _pendingDiscoveryKey; |
| | | 121 | | private int _changeIndex; |
| | | 122 | | private int _overlayMapIndex; |
| | | 123 | | private int _overlayCellIndex; |
| | | 124 | | private int _gridEventIndex; |
| | | 125 | | private int _discoveryMapIndex; |
| | | 126 | | private int _worldResetMapIndex; |
| | | 127 | | private int _fullRebuildRemoveMapIndex; |
| | | 128 | | private int _fullRebuildDiscoverMapIndex; |
| | | 129 | | private bool _worldResetPending; |
| | | 130 | | private bool _overlayMapInspected; |
| | | 131 | | private WorkMode _mode; |
| | | 132 | | private WorkPhase _phase; |
| | | 133 | | private GridBoundaryContactRunStamp _runStamp; |
| | | 134 | | private bool _hasRunStamp; |
| | | 135 | | private bool _cursorBegun; |
| | | 136 | | private bool _hasValidatorCursor; |
| | | 137 | | private bool _complete; |
| | | 138 | | |
| | 2151 | 139 | | internal NavigationAutomaticSeamRefreshWork( |
| | 2151 | 140 | | GridWorld world, |
| | 2151 | 141 | | NavigationWorldGraph sourceGraph, |
| | 2151 | 142 | | NavigationWorldGraph preparedGraph, |
| | 2151 | 143 | | NavigationOperationFrameChange[] changes, |
| | 2151 | 144 | | int changeCount) |
| | | 145 | | { |
| | 2151 | 146 | | _world = world; |
| | 2151 | 147 | | _sourceGraph = sourceGraph; |
| | 2151 | 148 | | _preparedGraph = preparedGraph; |
| | 2151 | 149 | | _changes = changes; |
| | 2151 | 150 | | _changeCount = changeCount; |
| | 2151 | 151 | | _gridEvents = Array.Empty<GridEventInfo>(); |
| | 2151 | 152 | | _gridEventCount = 0; |
| | 2151 | 153 | | _discoveryMapIds = PersistentStringMap<bool>.Empty; |
| | 2151 | 154 | | _fullRebuild = false; |
| | 2151 | 155 | | _working = sourceGraph.AutomaticSeams; |
| | 2151 | 156 | | _ownershipToken = NavigationSeamEditToken.Create(); |
| | 2151 | 157 | | } |
| | | 158 | | |
| | 1066 | 159 | | internal NavigationAutomaticSeamRefreshWork( |
| | 1066 | 160 | | GridWorld world, |
| | 1066 | 161 | | NavigationWorldGraph sourceGraph, |
| | 1066 | 162 | | NavigationWorldGraph preparedGraph, |
| | 1066 | 163 | | GridEventInfo[] gridEvents, |
| | 1066 | 164 | | int gridEventCount, |
| | 1066 | 165 | | bool fullRebuild = false) |
| | | 166 | | { |
| | 1066 | 167 | | _world = world; |
| | 1066 | 168 | | _sourceGraph = sourceGraph; |
| | 1066 | 169 | | _preparedGraph = preparedGraph; |
| | 1066 | 170 | | _changes = Array.Empty<NavigationOperationFrameChange>(); |
| | 1066 | 171 | | _changeCount = 0; |
| | 1066 | 172 | | _gridEvents = gridEvents; |
| | 1066 | 173 | | _gridEventCount = gridEventCount; |
| | 1066 | 174 | | _discoveryMapIds = PersistentStringMap<bool>.Empty; |
| | 1066 | 175 | | _fullRebuild = fullRebuild; |
| | 1066 | 176 | | _working = sourceGraph.AutomaticSeams; |
| | 1066 | 177 | | _ownershipToken = NavigationSeamEditToken.Create(); |
| | 1066 | 178 | | } |
| | | 179 | | |
| | 25 | 180 | | internal NavigationAutomaticSeamRefreshWork( |
| | 25 | 181 | | GridWorld world, |
| | 25 | 182 | | NavigationWorldGraph sourceGraph, |
| | 25 | 183 | | NavigationWorldGraph preparedGraph, |
| | 25 | 184 | | PersistentStringMap<bool> discoveryMapIds) |
| | | 185 | | { |
| | 25 | 186 | | _world = world; |
| | 25 | 187 | | _sourceGraph = sourceGraph; |
| | 25 | 188 | | _preparedGraph = preparedGraph; |
| | 25 | 189 | | _changes = Array.Empty<NavigationOperationFrameChange>(); |
| | 25 | 190 | | _changeCount = 0; |
| | 25 | 191 | | _gridEvents = Array.Empty<GridEventInfo>(); |
| | 25 | 192 | | _gridEventCount = 0; |
| | 25 | 193 | | _discoveryMapIds = discoveryMapIds; |
| | 25 | 194 | | _fullRebuild = false; |
| | 25 | 195 | | _working = sourceGraph.AutomaticSeams; |
| | 25 | 196 | | _ownershipToken = NavigationSeamEditToken.Create(); |
| | 25 | 197 | | } |
| | | 198 | | |
| | 1200 | 199 | | internal NavigationAutomaticSeamIndex Result => _working; |
| | | 200 | | |
| | 238499 | 201 | | internal bool IsComplete => _complete; |
| | | 202 | | |
| | | 203 | | internal bool GeometryChanged { get; private set; } |
| | | 204 | | |
| | | 205 | | internal bool StructuralLinksChanged { get; private set; } |
| | | 206 | | |
| | | 207 | | internal long Revision { get; private set; } |
| | | 208 | | |
| | 1524 | 209 | | internal int ChangedMapCount => _changedMapIds.Count; |
| | | 210 | | |
| | 352 | 211 | | internal string GetChangedMapIdAt(int ordinal) => _changedMapIds.GetKeyAt(ordinal); |
| | | 212 | | |
| | 3341 | 213 | | internal int ChangedStructuralEndpointCount => _changedStructuralEndpoints.Count; |
| | | 214 | | |
| | | 215 | | internal NavigationCellAddress GetChangedStructuralEndpointAt(int ordinal) => |
| | 463 | 216 | | _changedStructuralEndpoints.GetAt(ordinal); |
| | | 217 | | |
| | 540 | 218 | | internal bool RevalidateForPublication() => RevalidateCompletedCursor(); |
| | | 219 | | |
| | 265297 | 220 | | internal long RetainedBytes => checked( |
| | 265297 | 221 | | FixedRetainedBytes |
| | 265297 | 222 | | + (ReferenceEquals(_changedMapIds, PersistentStringMap<bool>.Empty) |
| | 265297 | 223 | | ? 0L |
| | 265297 | 224 | | : _changedMapIds.RetainedBytes) |
| | 265297 | 225 | | + (ReferenceEquals(_discoveryMapIds, PersistentStringMap<bool>.Empty) |
| | 265297 | 226 | | ? 0L |
| | 265297 | 227 | | : _discoveryMapIds.RetainedBytes) |
| | 265297 | 228 | | + (ReferenceEquals(_changedStructuralEndpoints, NavigationCellAddressSet.Empty) |
| | 265297 | 229 | | ? 0L |
| | 265297 | 230 | | : _changedStructuralEndpoints.RetainedBytes) |
| | 265297 | 231 | | + (_pendingPairOwned ? NavigationAutomaticSeamPair.RetainedSize : 0L) |
| | 265297 | 232 | | + GetPairJournalBytes() |
| | 265297 | 233 | | + GetAddressJournalBytes() |
| | 265297 | 234 | | + GetLinkJournalBytes() |
| | 265297 | 235 | | + (_dependencyCursor?.RetainedBytes ?? 0L) |
| | 265297 | 236 | | + (_indexEditor?.RetainedBytes ?? _sealedIndexBytes) |
| | 265297 | 237 | | + (_rowBuilder?.RetainedBytes ?? 0L) |
| | 265297 | 238 | | + (_linkBuilder?.RetainedBytes ?? 0L)); |
| | | 239 | | |
| | 265640 | 240 | | internal int PersistentPageCount => checked( |
| | 265640 | 241 | | 4 |
| | 265640 | 242 | | + (ReferenceEquals(_changedMapIds, PersistentStringMap<bool>.Empty) |
| | 265640 | 243 | | ? 0 |
| | 265640 | 244 | | : 1 + _changedMapIds.PersistentNodeCount) |
| | 265640 | 245 | | + (ReferenceEquals(_discoveryMapIds, PersistentStringMap<bool>.Empty) |
| | 265640 | 246 | | ? 0 |
| | 265640 | 247 | | : 1 + _discoveryMapIds.PersistentNodeCount) |
| | 265640 | 248 | | + (ReferenceEquals(_changedStructuralEndpoints, NavigationCellAddressSet.Empty) |
| | 265640 | 249 | | ? 0 |
| | 265640 | 250 | | : _changedStructuralEndpoints.PersistentPageCount) |
| | 265640 | 251 | | + (_pendingPairOwned ? 1 : 0) |
| | 265640 | 252 | | + GetPairJournalPages() |
| | 265640 | 253 | | + GetAddressJournalPages() |
| | 265640 | 254 | | + GetLinkJournalPages() |
| | 265640 | 255 | | + (_dependencyCursor?.PersistentPageCount ?? 0) |
| | 265640 | 256 | | + (_indexEditor?.PersistentPageCount ?? _sealedIndexPages) |
| | 265640 | 257 | | + (_rowBuilder?.PersistentPageCount ?? 0) |
| | 265640 | 258 | | + (_linkBuilder?.PersistentPageCount ?? 0)); |
| | | 259 | | |
| | | 260 | | internal SeamAdvanceStatus AdvanceOne(MaintenanceWorkMeter meter) |
| | | 261 | | { |
| | 234111 | 262 | | if (_complete) |
| | 2 | 263 | | return RevalidateCompletedCursor() |
| | 2 | 264 | | ? SeamAdvanceStatus.Complete |
| | 2 | 265 | | : SeamAdvanceStatus.Blocked; |
| | 234109 | 266 | | bool progressed = false; |
| | 234109 | 267 | | switch (_phase) |
| | | 268 | | { |
| | | 269 | | case WorkPhase.Gather: |
| | 125778 | 270 | | progressed = AdvanceGather(meter); |
| | 125778 | 271 | | break; |
| | | 272 | | case WorkPhase.ApplyPairs: |
| | 58209 | 273 | | progressed = AdvancePairApplication(meter); |
| | 58209 | 274 | | break; |
| | | 275 | | case WorkPhase.ApplyAddresses: |
| | 47598 | 276 | | progressed = AdvanceAddressApplication(meter); |
| | 47598 | 277 | | break; |
| | | 278 | | case WorkPhase.ApplyLinks: |
| | 2343 | 279 | | progressed = AdvanceLinkApplication(meter); |
| | 2343 | 280 | | break; |
| | | 281 | | case WorkPhase.Seal: |
| | 181 | 282 | | progressed = SealResult(); |
| | | 283 | | break; |
| | | 284 | | } |
| | 234109 | 285 | | if (_complete) |
| | 1183 | 286 | | return SeamAdvanceStatus.Complete; |
| | 232926 | 287 | | return progressed ? SeamAdvanceStatus.Progressed : SeamAdvanceStatus.Blocked; |
| | | 288 | | } |
| | | 289 | | |
| | | 290 | | private bool AdvanceGather(MaintenanceWorkMeter meter) |
| | | 291 | | { |
| | 125778 | 292 | | if (_pendingPair != null) |
| | 49758 | 293 | | return AdvanceQueuedMutation(meter); |
| | 76020 | 294 | | if (_mode != WorkMode.None) |
| | 56806 | 295 | | return AdvanceMode(meter); |
| | 19214 | 296 | | if (TrySetupNextMode(meter)) |
| | 17823 | 297 | | return true; |
| | 1391 | 298 | | if ((!_fullRebuild && _worldResetPending) |
| | 1391 | 299 | | || (_fullRebuild |
| | 1391 | 300 | | && (_fullRebuildRemoveMapIndex < _sourceGraph.MapCount |
| | 1391 | 301 | | || _fullRebuildDiscoverMapIndex < _preparedGraph.MapCount)) |
| | 1391 | 302 | | || (!_fullRebuild && _gridEventIndex < _gridEventCount) |
| | 1391 | 303 | | || _discoveryMapIndex < _discoveryMapIds.Count |
| | 1391 | 304 | | || _changeIndex < _changeCount) |
| | 204 | 305 | | return false; |
| | 1187 | 306 | | if (!RevalidateCompletedCursor()) |
| | 1 | 307 | | return false; |
| | 1186 | 308 | | BeginPairApplication(); |
| | 1186 | 309 | | return true; |
| | | 310 | | } |
| | | 311 | | |
| | | 312 | | private bool TrySetupNextMode(MaintenanceWorkMeter meter) |
| | | 313 | | { |
| | 19214 | 314 | | if (_fullRebuild) |
| | | 315 | | { |
| | 73 | 316 | | if (TrySetupFullRebuildMode(meter)) |
| | 48 | 317 | | return true; |
| | 25 | 318 | | if (_fullRebuildRemoveMapIndex < _sourceGraph.MapCount |
| | 25 | 319 | | || _fullRebuildDiscoverMapIndex < _preparedGraph.MapCount) |
| | | 320 | | { |
| | 10 | 321 | | return false; |
| | | 322 | | } |
| | | 323 | | } |
| | 19141 | 324 | | else if (TrySetupNextGridEventMode(meter)) |
| | | 325 | | { |
| | 30 | 326 | | return true; |
| | | 327 | | } |
| | 19126 | 328 | | while (_discoveryMapIndex < _discoveryMapIds.Count) |
| | | 329 | | { |
| | 38 | 330 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 11 | 331 | | return false; |
| | 27 | 332 | | string mapId = _discoveryMapIds.GetKeyAt(_discoveryMapIndex++); |
| | 27 | 333 | | if (_preparedGraph.TryGetMap(mapId, out NavigationMapInstance instance)) |
| | | 334 | | { |
| | 27 | 335 | | _pendingDiscoveryKey = instance.Map.GridBinding.Key; |
| | 27 | 336 | | BeginMapMode(mapId, WorkMode.RevalidateMap); |
| | 27 | 337 | | return true; |
| | | 338 | | } |
| | | 339 | | } |
| | 19278 | 340 | | while (_changeIndex < _changeCount) |
| | | 341 | | { |
| | 18088 | 342 | | NavigationOperationFrameChange change = _changes[_changeIndex]; |
| | 18088 | 343 | | if (change.Kind == NavigationOperationFrameChangeKind.MapCommit) |
| | | 344 | | { |
| | 1280 | 345 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 143 | 346 | | return false; |
| | 1137 | 347 | | _changeIndex++; |
| | 1137 | 348 | | string mapId = change.MapId!; |
| | 1137 | 349 | | _sourceGraph.TryGetMap(mapId, out NavigationMapInstance? prior); |
| | 1137 | 350 | | _preparedGraph.TryGetMap(mapId, out NavigationMapInstance? next); |
| | 1137 | 351 | | if (next == null) |
| | | 352 | | continue; |
| | 1136 | 353 | | if (prior == null) |
| | | 354 | | { |
| | 1096 | 355 | | BeginDiscovery(next.Map.GridBinding.Key); |
| | 1096 | 356 | | return true; |
| | | 357 | | } |
| | 40 | 358 | | if (!prior.Map.GridBinding.Key.Equals(next.Map.GridBinding.Key)) |
| | | 359 | | { |
| | 1 | 360 | | _pendingDiscoveryKey = next.Map.GridBinding.Key; |
| | 1 | 361 | | BeginMapMode(mapId, WorkMode.RemoveMap); |
| | 1 | 362 | | return true; |
| | | 363 | | } |
| | 39 | 364 | | BeginMapMode(mapId, WorkMode.RevalidateMap); |
| | 39 | 365 | | return true; |
| | | 366 | | } |
| | 16808 | 367 | | if (change.Kind == NavigationOperationFrameChangeKind.MapRemove) |
| | | 368 | | { |
| | 11 | 369 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 1 | 370 | | return false; |
| | 10 | 371 | | _changeIndex++; |
| | 10 | 372 | | BeginMapMode(change.MapId!, WorkMode.RemoveMap); |
| | 10 | 373 | | return true; |
| | | 374 | | } |
| | | 375 | | |
| | 16797 | 376 | | ReadOnlySpan<NavigationMapOverlayDelta> maps = |
| | 16797 | 377 | | change.PreparedOverlay!.Transaction.MapSpan; |
| | 17001 | 378 | | while (_overlayMapIndex < maps.Length) |
| | | 379 | | { |
| | 16812 | 380 | | if (!_overlayMapInspected) |
| | | 381 | | { |
| | 238 | 382 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 34 | 383 | | return false; |
| | 204 | 384 | | _overlayMapInspected = true; |
| | | 385 | | } |
| | 16778 | 386 | | ReadOnlySpan<NavigationCellOverlayOperation> cells = maps[_overlayMapIndex].CellSpan; |
| | 16778 | 387 | | if (_overlayCellIndex < cells.Length) |
| | | 388 | | { |
| | 16574 | 389 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 2 | 390 | | return false; |
| | 16572 | 391 | | NavigationCellAddress address = new( |
| | 16572 | 392 | | maps[_overlayMapIndex].MapId, |
| | 16572 | 393 | | cells[_overlayCellIndex++].Index); |
| | 16572 | 394 | | BeginAddressMode(address); |
| | 16572 | 395 | | return true; |
| | | 396 | | } |
| | 204 | 397 | | _overlayMapIndex++; |
| | 204 | 398 | | _overlayCellIndex = 0; |
| | 204 | 399 | | _overlayMapInspected = false; |
| | | 400 | | } |
| | 189 | 401 | | _overlayMapIndex = 0; |
| | 189 | 402 | | _overlayMapInspected = false; |
| | 189 | 403 | | _changeIndex++; |
| | | 404 | | } |
| | 1190 | 405 | | return false; |
| | | 406 | | } |
| | | 407 | | |
| | | 408 | | private bool TrySetupFullRebuildMode(MaintenanceWorkMeter meter) |
| | | 409 | | { |
| | 73 | 410 | | if (_fullRebuildRemoveMapIndex < _sourceGraph.MapCount) |
| | | 411 | | { |
| | 26 | 412 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 2 | 413 | | return false; |
| | 24 | 414 | | BeginMapMode( |
| | 24 | 415 | | _sourceGraph.GetInstance(_fullRebuildRemoveMapIndex++).MapId, |
| | 24 | 416 | | WorkMode.RemoveMap); |
| | 24 | 417 | | return true; |
| | | 418 | | } |
| | 47 | 419 | | if (_fullRebuildDiscoverMapIndex < _preparedGraph.MapCount) |
| | | 420 | | { |
| | 32 | 421 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 8 | 422 | | return false; |
| | 24 | 423 | | BeginDiscovery( |
| | 24 | 424 | | _preparedGraph.GetInstance(_fullRebuildDiscoverMapIndex++) |
| | 24 | 425 | | .Map.GridBinding.Key); |
| | 24 | 426 | | return true; |
| | | 427 | | } |
| | 15 | 428 | | return false; |
| | | 429 | | } |
| | | 430 | | |
| | | 431 | | private bool TrySetupNextGridEventMode(MaintenanceWorkMeter meter) |
| | | 432 | | { |
| | 19141 | 433 | | while (_worldResetPending || _gridEventIndex < _gridEventCount) |
| | | 434 | | { |
| | 33 | 435 | | if (_worldResetPending) |
| | | 436 | | { |
| | 3 | 437 | | if (_worldResetMapIndex < _sourceGraph.MapCount) |
| | | 438 | | { |
| | 2 | 439 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 1 | 440 | | return false; |
| | 1 | 441 | | BeginMapMode( |
| | 1 | 442 | | _sourceGraph.GetInstance(_worldResetMapIndex++).MapId, |
| | 1 | 443 | | WorkMode.RemoveMap); |
| | 1 | 444 | | return true; |
| | | 445 | | } |
| | 1 | 446 | | _worldResetPending = false; |
| | 1 | 447 | | _worldResetMapIndex = 0; |
| | 1 | 448 | | _gridEventIndex++; |
| | 1 | 449 | | return true; |
| | | 450 | | } |
| | | 451 | | |
| | 30 | 452 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 2 | 453 | | return false; |
| | 28 | 454 | | GridEventInfo eventInfo = _gridEvents[_gridEventIndex]; |
| | 28 | 455 | | GridConfigurationKey key = eventInfo.Configuration.ToGridKey(); |
| | 28 | 456 | | switch (eventInfo.ChangeKind) |
| | | 457 | | { |
| | | 458 | | case GridEventKind.GridRemoved: |
| | 11 | 459 | | _gridEventIndex++; |
| | 11 | 460 | | if (_sourceGraph.TryGetMapId(key, out string removedMapId)) |
| | | 461 | | { |
| | 10 | 462 | | BeginMapMode(removedMapId, WorkMode.RemoveMap); |
| | 10 | 463 | | return true; |
| | | 464 | | } |
| | | 465 | | break; |
| | | 466 | | case GridEventKind.GridAdded: |
| | 15 | 467 | | _gridEventIndex++; |
| | 15 | 468 | | if (_preparedGraph.TryGetMapId(key, out _)) |
| | | 469 | | { |
| | 14 | 470 | | BeginDiscovery(key); |
| | 14 | 471 | | return true; |
| | | 472 | | } |
| | | 473 | | break; |
| | | 474 | | case GridEventKind.WorldReset: |
| | 1 | 475 | | _worldResetPending = true; |
| | 1 | 476 | | _worldResetMapIndex = 0; |
| | 1 | 477 | | return true; |
| | | 478 | | default: |
| | 1 | 479 | | _gridEventIndex++; |
| | | 480 | | break; |
| | | 481 | | } |
| | 3 | 482 | | return true; |
| | | 483 | | } |
| | 19108 | 484 | | return false; |
| | | 485 | | } |
| | | 486 | | |
| | | 487 | | private bool AdvanceMode(MaintenanceWorkMeter meter) |
| | | 488 | | { |
| | 56806 | 489 | | if (_mode == WorkMode.Discover) |
| | 39892 | 490 | | return AdvanceDiscovery(meter); |
| | 16914 | 491 | | if (_dependencyRowRemaining > 0) |
| | | 492 | | { |
| | 155 | 493 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 1 | 494 | | return false; |
| | 154 | 495 | | _dependencyRow.MoveNext(); |
| | 154 | 496 | | NavigationAutomaticSeamPair pair = _dependencyRow.Current.Pair; |
| | 154 | 497 | | _dependencyRowRemaining--; |
| | 154 | 498 | | QueueMutation( |
| | 154 | 499 | | pair, |
| | 154 | 500 | | _mode == WorkMode.RemoveMap ? MutationKind.Remove : MutationKind.Revalidate); |
| | 154 | 501 | | return true; |
| | | 502 | | } |
| | 16759 | 503 | | if (_mode == WorkMode.RevalidateAddress) |
| | | 504 | | { |
| | 16572 | 505 | | FinishMode(); |
| | 16572 | 506 | | return true; |
| | | 507 | | } |
| | 187 | 508 | | if (!_dependencyCursor!.HasNext) |
| | 98 | 509 | | return CompleteMapMode(); |
| | 89 | 510 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 3 | 511 | | return false; |
| | 86 | 512 | | _dependencyCursor.MoveNext(); |
| | 86 | 513 | | NavigationCellAddress address = _dependencyCursor.CurrentKey; |
| | 86 | 514 | | if (!address.MapId.Equals(_modeMapId, StringComparison.Ordinal)) |
| | 14 | 515 | | return CompleteMapMode(); |
| | 72 | 516 | | _dependencyAddress = address; |
| | 72 | 517 | | NavigationPagedSequence<NavigationAutomaticSeamPair> row = |
| | 72 | 518 | | _sourceGraph.AutomaticSeams.GetDependencyRow(address); |
| | 72 | 519 | | _dependencyRow = new NavigationAutomaticSeamIndex.EndpointEnumerator(address, row); |
| | 72 | 520 | | _dependencyRowRemaining = row.Count; |
| | 72 | 521 | | return true; |
| | | 522 | | } |
| | | 523 | | |
| | | 524 | | private bool CompleteMapMode() |
| | | 525 | | { |
| | | 526 | | System.Diagnostics.Debug.Assert( |
| | | 527 | | _pendingDiscoveryKey.Equals(default(GridConfigurationKey)) |
| | | 528 | | || _mode is WorkMode.RemoveMap or WorkMode.RevalidateMap, |
| | | 529 | | "A queued discovery is owned by the map mode that must complete before it begins."); |
| | 112 | 530 | | FinishMode(); |
| | 112 | 531 | | if (!_pendingDiscoveryKey.Equals(default(GridConfigurationKey))) |
| | | 532 | | { |
| | 28 | 533 | | GridConfigurationKey key = _pendingDiscoveryKey; |
| | 28 | 534 | | _pendingDiscoveryKey = default; |
| | 28 | 535 | | BeginDiscovery(key); |
| | | 536 | | } |
| | 112 | 537 | | return true; |
| | | 538 | | } |
| | | 539 | | |
| | | 540 | | private bool AdvanceDiscovery(MaintenanceWorkMeter meter) |
| | | 541 | | { |
| | 39892 | 542 | | if (!_cursorBegun) |
| | | 543 | | { |
| | 1159 | 544 | | if (!RevalidateCompletedCursor()) |
| | 1 | 545 | | return false; |
| | 1158 | 546 | | bool began = _world.TryBeginBoundaryContacts(_pendingDiscoveryKey, _cursor); |
| | 1158 | 547 | | bool completedCursorCurrent = true; |
| | 1158 | 548 | | if (!began) |
| | 36 | 549 | | completedCursorCurrent = IsCompletedCursorCurrent(); |
| | 1158 | 550 | | return AdvanceDiscoveryAfterCursorStart( |
| | 1158 | 551 | | meter, |
| | 1158 | 552 | | began, |
| | 1158 | 553 | | completedCursorCurrent, |
| | 1158 | 554 | | _hasRunStamp, |
| | 1158 | 555 | | !(_cursor.RunStamp != _runStamp)); |
| | | 556 | | } |
| | | 557 | | |
| | 38733 | 558 | | return AdvanceBegunDiscovery(meter); |
| | | 559 | | } |
| | | 560 | | |
| | | 561 | | internal bool AdvanceDiscoveryAfterCursorStart( |
| | | 562 | | MaintenanceWorkMeter meter, |
| | | 563 | | bool began, |
| | | 564 | | bool completedCursorCurrent, |
| | | 565 | | bool hadRunStamp, |
| | | 566 | | bool runStampMatches) |
| | | 567 | | { |
| | 1161 | 568 | | if (!began) |
| | | 569 | | { |
| | 38 | 570 | | if (!completedCursorCurrent) |
| | 1 | 571 | | return RestartDiscoveryAfterInvalidation(); |
| | 37 | 572 | | _pendingDiscoveryKey = default; |
| | 37 | 573 | | FinishMode(); |
| | 37 | 574 | | return true; |
| | | 575 | | } |
| | 1123 | 576 | | if (hadRunStamp && !runStampMatches) |
| | 1 | 577 | | return RestartDiscoveryAfterInvalidation(); |
| | 1122 | 578 | | _runStamp = _cursor.RunStamp; |
| | 1122 | 579 | | _hasRunStamp = true; |
| | 1122 | 580 | | _cursorBegun = true; |
| | 1122 | 581 | | return AdvanceBegunDiscovery(meter); |
| | | 582 | | } |
| | | 583 | | |
| | | 584 | | private bool AdvanceBegunDiscovery(MaintenanceWorkMeter meter) |
| | | 585 | | { |
| | 39855 | 586 | | GridBoundaryContactCursorStatus status = _world.AdvanceBoundaryContacts( |
| | 39855 | 587 | | _cursor, |
| | 39855 | 588 | | _contact, |
| | 39855 | 589 | | meter.RemainingSeamCandidateProbes, |
| | 39855 | 590 | | outputLimit: 1, |
| | 39855 | 591 | | out int consumed, |
| | 39855 | 592 | | out int outputCount); |
| | 39855 | 593 | | meter.TryConsumeSeamCandidateProbes(consumed); |
| | 39855 | 594 | | if (status == GridBoundaryContactCursorStatus.Stale |
| | 39855 | 595 | | || _cursor.RunStamp != _runStamp) |
| | | 596 | | { |
| | 1 | 597 | | return RestartDiscoveryAfterInvalidation(); |
| | | 598 | | } |
| | 39854 | 599 | | if (outputCount != 0) |
| | 38293 | 600 | | PrepareDiscoveredPair(_contact[0]); |
| | | 601 | | System.Diagnostics.Debug.Assert( |
| | | 602 | | status != GridBoundaryContactCursorStatus.Complete || outputCount == 0, |
| | | 603 | | "A one-output boundary-contact advance returns More as soon as it emits that output."); |
| | 39854 | 604 | | if (status == GridBoundaryContactCursorStatus.Complete) |
| | | 605 | | { |
| | 1121 | 606 | | GridBoundaryContactCursor previousValidator = _validatorCursor; |
| | 1121 | 607 | | _validatorCursor = _cursor; |
| | 1121 | 608 | | _cursor = previousValidator; |
| | 1121 | 609 | | _hasValidatorCursor = true; |
| | 1121 | 610 | | _cursorBegun = false; |
| | 1121 | 611 | | _pendingDiscoveryKey = default; |
| | 1121 | 612 | | FinishMode(); |
| | | 613 | | } |
| | 39854 | 614 | | return outputCount != 0 || consumed != 0 |
| | 39854 | 615 | | || status == GridBoundaryContactCursorStatus.Complete; |
| | | 616 | | } |
| | | 617 | | |
| | | 618 | | private void PrepareDiscoveredPair(GridBoundaryContact contact) |
| | | 619 | | { |
| | 38293 | 620 | | if (!_preparedGraph.TryGetMapId(contact.SourceConfigurationKey, out string sourceMapId) |
| | 38293 | 621 | | || !_preparedGraph.TryGetMapId(contact.TargetConfigurationKey, out string targetMapId)) |
| | | 622 | | { |
| | 35 | 623 | | return; |
| | | 624 | | } |
| | 38258 | 625 | | NavigationCellAddress first = new(sourceMapId, contact.Contact.Source.VoxelIndex); |
| | 38258 | 626 | | NavigationCellAddress second = new(targetMapId, contact.Contact.Target.VoxelIndex); |
| | 38258 | 627 | | var key = new NavigationAutomaticSeamPairKey(first, second); |
| | 38258 | 628 | | if (TryGetCurrentPair(key, out NavigationAutomaticSeamPair existing)) |
| | | 629 | | { |
| | 5974 | 630 | | QueueMutation(existing, MutationKind.Revalidate); |
| | 5974 | 631 | | return; |
| | | 632 | | } |
| | 32284 | 633 | | bool foundFirstPrism = _preparedGraph.TryGetSeamPrism( |
| | 32284 | 634 | | key.First, |
| | 32284 | 635 | | out GridCellPrism firstPrism); |
| | 32284 | 636 | | bool foundSecondPrism = _preparedGraph.TryGetSeamPrism( |
| | 32284 | 637 | | key.Second, |
| | 32284 | 638 | | out GridCellPrism secondPrism); |
| | | 639 | | System.Diagnostics.Debug.Assert(foundFirstPrism && foundSecondPrism, |
| | | 640 | | "Boundary contacts resolved through the same normalized map bindings own both cell prisms."); |
| | 32284 | 641 | | if (!GridCellGeometry.TryCreateNavigationPortal( |
| | 32284 | 642 | | firstPrism, |
| | 32284 | 643 | | secondPrism, |
| | 32284 | 644 | | out GridNavigationPortal portal)) |
| | | 645 | | { |
| | 26268 | 646 | | return; |
| | | 647 | | } |
| | 6016 | 648 | | QueueMutation( |
| | 6016 | 649 | | new NavigationAutomaticSeamPair(key.First, key.Second, portal), |
| | 6016 | 650 | | MutationKind.Add, |
| | 6016 | 651 | | ownsPair: true); |
| | 6016 | 652 | | } |
| | | 653 | | |
| | | 654 | | private bool AdvanceQueuedMutation(MaintenanceWorkMeter meter) |
| | | 655 | | { |
| | 49758 | 656 | | if (_mutationStage < 2) |
| | | 657 | | { |
| | 24501 | 658 | | if (!meter.TryConsumeExplicitEdges(1)) |
| | 213 | 659 | | return false; |
| | 24288 | 660 | | _mutationStage++; |
| | 24288 | 661 | | return true; |
| | | 662 | | } |
| | 25257 | 663 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 969 | 664 | | return false; |
| | 24288 | 665 | | _mutationStage++; |
| | 24288 | 666 | | if (_mutationStage == 4) |
| | 12144 | 667 | | CoalescePendingMutation(); |
| | 24288 | 668 | | return true; |
| | | 669 | | } |
| | | 670 | | |
| | | 671 | | private void CoalescePendingMutation() |
| | | 672 | | { |
| | 12144 | 673 | | NavigationAutomaticSeamPair pair = _pendingPair!; |
| | 12144 | 674 | | var key = new NavigationAutomaticSeamPairKey(pair.First, pair.Second); |
| | 12144 | 675 | | EnsurePairEditor(); |
| | 12144 | 676 | | if (!_pairEditor!.TryGetValue(key, out PairDelta delta)) |
| | | 677 | | { |
| | 6148 | 678 | | _sourceGraph.AutomaticSeams.TryGetPairRecord(key, out NavigationAutomaticSeamPairRecord source); |
| | 6148 | 679 | | delta = new PairDelta(source); |
| | 6148 | 680 | | _pairEditor.Set(key, delta); |
| | 6148 | 681 | | _pairDeltaPayloadBytes = checked(_pairDeltaPayloadBytes + PairDeltaBytes); |
| | 6148 | 682 | | _pairDeltaPayloadPages++; |
| | | 683 | | } |
| | 12144 | 684 | | NavigationAutomaticSeamPair? prior = delta.FinalPair; |
| | 12144 | 685 | | if (_pendingMutation == MutationKind.Remove) |
| | 83 | 686 | | delta.FinalPair = null; |
| | 12061 | 687 | | else if (_pendingMutation == MutationKind.Add) |
| | | 688 | | { |
| | | 689 | | System.Diagnostics.Debug.Assert(_pendingPairOwned, |
| | | 690 | | "Only newly discovered seam geometry enters the add mutation."); |
| | | 691 | | System.Diagnostics.Debug.Assert(delta.FinalPair == null, |
| | | 692 | | "Discovery queues an add only after the current seam pair is absent."); |
| | | 693 | | System.Diagnostics.Debug.Assert(!ReferenceEquals(prior, pair)); |
| | 6016 | 694 | | delta.FinalPair = pair; |
| | 6016 | 695 | | _pairDeltaPayloadBytes = checked( |
| | 6016 | 696 | | _pairDeltaPayloadBytes + NavigationAutomaticSeamPair.RetainedSize); |
| | 6016 | 697 | | _pairDeltaPayloadPages++; |
| | 6016 | 698 | | delta.OwnsFinalPair = true; |
| | 6016 | 699 | | _pendingPairOwned = false; |
| | | 700 | | } |
| | | 701 | | else |
| | | 702 | | { |
| | | 703 | | System.Diagnostics.Debug.Assert(_pendingMutation == MutationKind.Revalidate); |
| | | 704 | | System.Diagnostics.Debug.Assert(!_pendingPairOwned); |
| | | 705 | | } |
| | 12144 | 706 | | delta.FinalActive = delta.FinalPair != null |
| | 12144 | 707 | | && _preparedGraph.HasEffectiveCell(delta.FinalPair.First) |
| | 12144 | 708 | | && _preparedGraph.HasEffectiveCell(delta.FinalPair.Second); |
| | 12144 | 709 | | _pendingPair = null; |
| | 12144 | 710 | | _pendingPairOwned = false; |
| | 12144 | 711 | | _pendingMutation = MutationKind.None; |
| | 12144 | 712 | | _mutationStage = 0; |
| | 12144 | 713 | | } |
| | | 714 | | |
| | | 715 | | private void BeginPairApplication() |
| | | 716 | | { |
| | 1186 | 717 | | if (_pairEditor == null) |
| | | 718 | | { |
| | 1005 | 719 | | _complete = true; |
| | 1005 | 720 | | return; |
| | | 721 | | } |
| | 181 | 722 | | _pairDeltas = _pairEditor.Seal(); |
| | 181 | 723 | | _pairEditor = null; |
| | 181 | 724 | | _pairCursor = _pairDeltas.CreateCursor( |
| | 181 | 725 | | CursorHeight, |
| | 181 | 726 | | NavigationAutomaticSeamIndex.PairCursorShellBytes); |
| | 181 | 727 | | _pairCursor.BeginAll(_pairDeltas); |
| | 181 | 728 | | _indexEditor = _sourceGraph.AutomaticSeams.Edit(_ownershipToken); |
| | 181 | 729 | | _phase = WorkPhase.ApplyPairs; |
| | 181 | 730 | | } |
| | | 731 | | |
| | | 732 | | private bool AdvancePairApplication(MaintenanceWorkMeter meter) |
| | | 733 | | { |
| | 58209 | 734 | | if (_currentPairDelta == null) |
| | | 735 | | { |
| | 6331 | 736 | | if (!_pairCursor!.HasNext) |
| | | 737 | | { |
| | 181 | 738 | | _pairCursor = null; |
| | 181 | 739 | | SealSecondaryJournals(); |
| | 181 | 740 | | return true; |
| | | 741 | | } |
| | 6150 | 742 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 3 | 743 | | return false; |
| | 6147 | 744 | | _pairCursor.MoveNext(); |
| | 6147 | 745 | | _currentPairKey = _pairCursor.CurrentKey; |
| | 6147 | 746 | | _currentPairDelta = _pairCursor.Current; |
| | 6147 | 747 | | NormalizeCurrentPairDelta(); |
| | 6147 | 748 | | _pairApplyStage = 0; |
| | 6147 | 749 | | return true; |
| | | 750 | | } |
| | | 751 | | |
| | 51878 | 752 | | PairDelta delta = _currentPairDelta; |
| | 63669 | 753 | | while (_pairApplyStage < 13) |
| | | 754 | | { |
| | 57522 | 755 | | switch (_pairApplyStage) |
| | | 756 | | { |
| | | 757 | | case 0: |
| | 6166 | 758 | | if (!_currentGeometryChanged && !_currentActiveChanged) |
| | | 759 | | { |
| | 46 | 760 | | _pairApplyStage = 13; |
| | 46 | 761 | | continue; |
| | | 762 | | } |
| | 6120 | 763 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 19 | 764 | | return false; |
| | 6101 | 765 | | NavigationAutomaticSeamPairRecord? record = delta.FinalPair == null |
| | 6101 | 766 | | ? null |
| | 6101 | 767 | | : new NavigationAutomaticSeamPairRecord(delta.FinalPair, delta.FinalActive); |
| | 6101 | 768 | | _indexEditor!.SetPair(_currentPairKey, record); |
| | 6101 | 769 | | if (delta.OwnsFinalPair) |
| | | 770 | | { |
| | 6016 | 771 | | _pairDeltaPayloadBytes -= NavigationAutomaticSeamPair.RetainedSize; |
| | 6016 | 772 | | _pairDeltaPayloadPages--; |
| | 6016 | 773 | | delta.OwnsFinalPair = false; |
| | | 774 | | } |
| | 6101 | 775 | | _pairApplyStage++; |
| | 6101 | 776 | | return true; |
| | | 777 | | case 1: |
| | | 778 | | case 3: |
| | 12193 | 779 | | if (!_currentGeometryChanged) |
| | | 780 | | { |
| | 23 | 781 | | _pairApplyStage = 5; |
| | 23 | 782 | | continue; |
| | | 783 | | } |
| | 12170 | 784 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 14 | 785 | | return false; |
| | 12156 | 786 | | TouchAddress( |
| | 12156 | 787 | | _pairApplyStage == 1 ? _currentPairKey.First : _currentPairKey.Second, |
| | 12156 | 788 | | dependency: true, |
| | 12156 | 789 | | active: false); |
| | 12156 | 790 | | _pairApplyStage++; |
| | 12156 | 791 | | return true; |
| | | 792 | | case 2: |
| | | 793 | | case 4: |
| | 12913 | 794 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 757 | 795 | | return false; |
| | 12156 | 796 | | if (delta.FinalPair != null) |
| | 12032 | 797 | | AppendAddressPair( |
| | 12032 | 798 | | _pairApplyStage == 2 ? _currentPairKey.First : _currentPairKey.Second, |
| | 12032 | 799 | | delta.FinalPair, |
| | 12032 | 800 | | active: false); |
| | 12156 | 801 | | _pairApplyStage++; |
| | 12156 | 802 | | return true; |
| | | 803 | | case 5: |
| | | 804 | | case 7: |
| | 6381 | 805 | | if (!_currentActiveRowChanged) |
| | | 806 | | { |
| | 5861 | 807 | | _pairApplyStage = 9; |
| | 5861 | 808 | | continue; |
| | | 809 | | } |
| | 520 | 810 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 40 | 811 | | return false; |
| | 480 | 812 | | TouchAddress( |
| | 480 | 813 | | _pairApplyStage == 5 ? _currentPairKey.First : _currentPairKey.Second, |
| | 480 | 814 | | dependency: false, |
| | 480 | 815 | | active: true); |
| | 480 | 816 | | _pairApplyStage++; |
| | 480 | 817 | | return true; |
| | | 818 | | case 6: |
| | | 819 | | case 8: |
| | 518 | 820 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 38 | 821 | | return false; |
| | 480 | 822 | | if (delta.FinalActive) |
| | 428 | 823 | | AppendAddressPair( |
| | 428 | 824 | | _pairApplyStage == 6 ? _currentPairKey.First : _currentPairKey.Second, |
| | 428 | 825 | | delta.FinalPair!, |
| | 428 | 826 | | active: true); |
| | 480 | 827 | | _pairApplyStage++; |
| | 480 | 828 | | return true; |
| | | 829 | | case 9: |
| | | 830 | | case 10: |
| | 6361 | 831 | | if (!_currentActiveRowChanged && !_currentStructuralLinkChanged) |
| | | 832 | | { |
| | 5861 | 833 | | _pairApplyStage = 11; |
| | 5861 | 834 | | continue; |
| | | 835 | | } |
| | 500 | 836 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 20 | 837 | | return false; |
| | 480 | 838 | | bool reverse = _pairApplyStage == 10; |
| | 480 | 839 | | NavigationCellAddress endpoint = reverse |
| | 480 | 840 | | ? _currentPairKey.Second |
| | 480 | 841 | | : _currentPairKey.First; |
| | 480 | 842 | | _changedStructuralEndpoints = |
| | 480 | 843 | | _changedStructuralEndpoints.Add(endpoint); |
| | 480 | 844 | | if (!_currentStructuralLinkChanged) |
| | | 845 | | { |
| | 18 | 846 | | _pairApplyStage++; |
| | 18 | 847 | | return true; |
| | | 848 | | } |
| | 462 | 849 | | string source = reverse ? _currentPairKey.Second.MapId : _currentPairKey.First.MapId; |
| | 462 | 850 | | string destination = reverse ? _currentPairKey.First.MapId : _currentPairKey.Second.MapId; |
| | 462 | 851 | | NavigationAutomaticSeamPair? sourcePair = delta.SourceRecord?.Pair; |
| | 462 | 852 | | bool sourceActive = delta.SourceRecord?.IsActive ?? false; |
| | 462 | 853 | | AddLinkDelta( |
| | 462 | 854 | | source, |
| | 462 | 855 | | destination, |
| | 462 | 856 | | (delta.FinalActive ? 1 : 0) - (sourceActive ? 1 : 0), |
| | 462 | 857 | | GetUncertifiedCount(delta.FinalPair, delta.FinalActive) |
| | 462 | 858 | | - GetUncertifiedCount(sourcePair, sourceActive)); |
| | 462 | 859 | | _pairApplyStage++; |
| | 462 | 860 | | return true; |
| | | 861 | | case 11: |
| | | 862 | | case 12: |
| | 12990 | 863 | | if (!meter.TryConsumeComponentNodes(1)) |
| | 788 | 864 | | return false; |
| | 12202 | 865 | | AddChangedMapId(_pairApplyStage == 11 |
| | 12202 | 866 | | ? _currentPairKey.First.MapId |
| | 12202 | 867 | | : _currentPairKey.Second.MapId); |
| | 12202 | 868 | | _pairApplyStage++; |
| | 12202 | 869 | | return true; |
| | | 870 | | } |
| | | 871 | | } |
| | 6147 | 872 | | _currentPairDelta = null; |
| | 6147 | 873 | | return true; |
| | | 874 | | } |
| | | 875 | | |
| | | 876 | | private void NormalizeCurrentPairDelta() |
| | | 877 | | { |
| | 6147 | 878 | | PairDelta delta = _currentPairDelta!; |
| | 6147 | 879 | | if (delta.FinalPair != null) |
| | | 880 | | { |
| | | 881 | | System.Diagnostics.Debug.Assert( |
| | | 882 | | _preparedGraph.TryGetMap(delta.FinalPair.First.MapId, out _) |
| | | 883 | | && _preparedGraph.TryGetMap(delta.FinalPair.Second.MapId, out _), |
| | | 884 | | "Removed-map modes clear every incident pair before journal normalization."); |
| | | 885 | | } |
| | 6147 | 886 | | NavigationAutomaticSeamPair? sourcePair = delta.SourceRecord?.Pair; |
| | 6147 | 887 | | _currentGeometryChanged = !ReferenceEquals(sourcePair, delta.FinalPair); |
| | 6147 | 888 | | bool sourceActive = delta.SourceRecord?.IsActive ?? false; |
| | 6147 | 889 | | _currentActiveChanged = sourceActive != delta.FinalActive; |
| | 6147 | 890 | | _currentActiveRowChanged = _currentActiveChanged |
| | 6147 | 891 | | || (_currentGeometryChanged && (sourceActive || delta.FinalActive)); |
| | 6147 | 892 | | _currentStructuralLinkChanged = _currentActiveChanged |
| | 6147 | 893 | | || GetUncertifiedCount(sourcePair, sourceActive) |
| | 6147 | 894 | | != GetUncertifiedCount(delta.FinalPair, delta.FinalActive); |
| | 6147 | 895 | | GeometryChanged |= _currentGeometryChanged; |
| | 6147 | 896 | | StructuralLinksChanged |= _currentStructuralLinkChanged; |
| | 6147 | 897 | | } |
| | | 898 | | |
| | | 899 | | private static int GetUncertifiedCount( |
| | | 900 | | NavigationAutomaticSeamPair? pair, |
| | 12758 | 901 | | bool active) => active |
| | 12758 | 902 | | && pair!.Portal.FaceKind != VoxelContactFaceKind.Vertical |
| | 12758 | 903 | | ? 1 |
| | 12758 | 904 | | : 0; |
| | | 905 | | |
| | | 906 | | private void TouchAddress(NavigationCellAddress address, bool dependency, bool active) |
| | | 907 | | { |
| | 12636 | 908 | | EnsureAddressEditor(); |
| | 12636 | 909 | | if (!_addressEditor!.TryGetValue(address, out AddressDelta delta)) |
| | | 910 | | { |
| | 1600 | 911 | | delta = new AddressDelta(); |
| | 1600 | 912 | | _addressEditor.Set(address, delta); |
| | 1600 | 913 | | _addressDeltaPayloadBytes = checked(_addressDeltaPayloadBytes + AddressDeltaBytes); |
| | 1600 | 914 | | _addressDeltaPayloadPages++; |
| | | 915 | | } |
| | 12636 | 916 | | delta.DependencyChanged |= dependency; |
| | 12636 | 917 | | delta.ActiveChanged |= active; |
| | 12636 | 918 | | } |
| | | 919 | | |
| | | 920 | | private void AppendAddressPair( |
| | | 921 | | NavigationCellAddress address, |
| | | 922 | | NavigationAutomaticSeamPair pair, |
| | | 923 | | bool active) |
| | | 924 | | { |
| | 12460 | 925 | | _addressEditor!.TryGetValue(address, out AddressDelta delta); |
| | 12460 | 926 | | long beforeBytes = delta.RetainedBytes; |
| | 12460 | 927 | | int beforePages = delta.PersistentPageCount; |
| | 12460 | 928 | | if (active) |
| | 428 | 929 | | delta.AppendActive(pair); |
| | | 930 | | else |
| | 12032 | 931 | | delta.AppendDependency(pair); |
| | 12460 | 932 | | RecordAddressPayloadChange(delta, beforeBytes, beforePages); |
| | 12460 | 933 | | } |
| | | 934 | | |
| | | 935 | | private void AddLinkDelta( |
| | | 936 | | string sourceMapId, |
| | | 937 | | string destinationMapId, |
| | | 938 | | int countChange, |
| | | 939 | | int uncertifiedCountChange) |
| | | 940 | | { |
| | 462 | 941 | | EnsureLinkEditor(); |
| | 462 | 942 | | var key = new NavigationAutomaticSeamLinkKey(sourceMapId, destinationMapId); |
| | 462 | 943 | | if (!_linkEditor!.TryGetValue(key, out LinkDelta delta)) |
| | | 944 | | { |
| | 418 | 945 | | delta = new LinkDelta(); |
| | 418 | 946 | | _linkEditor.Set(key, delta); |
| | 418 | 947 | | _linkDeltaPayloadBytes = checked(_linkDeltaPayloadBytes + LinkDeltaBytes); |
| | 418 | 948 | | _linkDeltaPayloadPages++; |
| | | 949 | | } |
| | 462 | 950 | | delta.Count = checked(delta.Count + countChange); |
| | 462 | 951 | | delta.UncertifiedCount = checked( |
| | 462 | 952 | | delta.UncertifiedCount + uncertifiedCountChange); |
| | 462 | 953 | | if (delta.Count != 0 || delta.UncertifiedCount != 0) |
| | 460 | 954 | | return; |
| | 2 | 955 | | _linkEditor.Remove(key); |
| | 2 | 956 | | _linkDeltaPayloadBytes -= LinkDeltaBytes; |
| | 2 | 957 | | _linkDeltaPayloadPages--; |
| | 2 | 958 | | } |
| | | 959 | | |
| | | 960 | | private void SealSecondaryJournals() |
| | | 961 | | { |
| | 181 | 962 | | if (_addressEditor != null) |
| | | 963 | | { |
| | 172 | 964 | | _addressDeltas = _addressEditor.Seal(); |
| | 172 | 965 | | _addressEditor = null; |
| | 172 | 966 | | _addressCursor = _addressDeltas.CreateCursor( |
| | 172 | 967 | | CursorHeight, |
| | 172 | 968 | | NavigationAutomaticSeamIndex.AddressCursorShellBytes); |
| | 172 | 969 | | _addressCursor.BeginAll(_addressDeltas); |
| | | 970 | | } |
| | 181 | 971 | | if (_linkEditor != null) |
| | | 972 | | { |
| | 159 | 973 | | _linkDeltas = _linkEditor.Seal(); |
| | 159 | 974 | | _linkEditor = null; |
| | 159 | 975 | | _linkCursor = _linkDeltas.CreateCursor( |
| | 159 | 976 | | CursorHeight, |
| | 159 | 977 | | NavigationAutomaticSeamIndex.LinkCursorShellBytes); |
| | 159 | 978 | | _linkCursor.BeginAll(_linkDeltas); |
| | | 979 | | } |
| | 181 | 980 | | _phase = WorkPhase.ApplyAddresses; |
| | 181 | 981 | | } |
| | | 982 | | |
| | | 983 | | private bool AdvanceAddressApplication(MaintenanceWorkMeter meter) |
| | | 984 | | { |
| | 47598 | 985 | | if (_addressCursor == null) |
| | | 986 | | { |
| | 9 | 987 | | _phase = WorkPhase.ApplyLinks; |
| | 9 | 988 | | return true; |
| | | 989 | | } |
| | 47589 | 990 | | if (_currentAddressDelta == null) |
| | | 991 | | { |
| | 1875 | 992 | | if (!_addressCursor.HasNext) |
| | | 993 | | { |
| | 172 | 994 | | _addressCursor = null; |
| | 172 | 995 | | _addressDeltas = null; |
| | 172 | 996 | | _addressDeltaPayloadBytes = 0; |
| | 172 | 997 | | _addressDeltaPayloadPages = 0; |
| | 172 | 998 | | _phase = WorkPhase.ApplyLinks; |
| | 172 | 999 | | return true; |
| | | 1000 | | } |
| | 1703 | 1001 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 103 | 1002 | | return false; |
| | 1600 | 1003 | | _addressCursor.MoveNext(); |
| | 1600 | 1004 | | _currentAddress = _addressCursor.CurrentKey; |
| | 1600 | 1005 | | _currentAddressDelta = _addressCursor.Current; |
| | 1600 | 1006 | | long beforeBytes = _currentAddressDelta.RetainedBytes; |
| | 1600 | 1007 | | int beforePages = _currentAddressDelta.PersistentPageCount; |
| | 1600 | 1008 | | _currentAddressDelta.SealAdditions(); |
| | 1600 | 1009 | | RecordAddressPayloadChange(_currentAddressDelta, beforeBytes, beforePages); |
| | 1600 | 1010 | | _addressApplyStage = 0; |
| | 1600 | 1011 | | return true; |
| | | 1012 | | } |
| | 45714 | 1013 | | if (_addressApplyStage == 0) |
| | | 1014 | | { |
| | 40592 | 1015 | | if (!_currentAddressDelta.DependencyChanged) |
| | | 1016 | | { |
| | 43 | 1017 | | _addressApplyStage = 1; |
| | 43 | 1018 | | return true; |
| | | 1019 | | } |
| | 40549 | 1020 | | if (_rowKind == RowKind.None) |
| | 1557 | 1021 | | BeginRow(RowKind.Dependency, _currentAddressDelta.DependencyAdditions); |
| | 40549 | 1022 | | if (!AdvanceRow(meter)) |
| | 1166 | 1023 | | return false; |
| | 39383 | 1024 | | if (_rowKind != RowKind.None) |
| | 37826 | 1025 | | return true; |
| | 1557 | 1026 | | _addressApplyStage = 1; |
| | 1557 | 1027 | | return true; |
| | | 1028 | | } |
| | 5122 | 1029 | | if (_addressApplyStage == 1) |
| | | 1030 | | { |
| | 3522 | 1031 | | if (!_currentAddressDelta.ActiveChanged) |
| | | 1032 | | { |
| | 1171 | 1033 | | _addressApplyStage = 2; |
| | 1171 | 1034 | | return true; |
| | | 1035 | | } |
| | 2351 | 1036 | | if (_rowKind == RowKind.None) |
| | 429 | 1037 | | BeginRow(RowKind.Active, _currentAddressDelta.ActiveAdditions); |
| | 2351 | 1038 | | if (!AdvanceRow(meter)) |
| | 108 | 1039 | | return false; |
| | 2243 | 1040 | | if (_rowKind != RowKind.None) |
| | 1814 | 1041 | | return true; |
| | 429 | 1042 | | _addressApplyStage = 2; |
| | 429 | 1043 | | return true; |
| | | 1044 | | } |
| | 1600 | 1045 | | long retained = _currentAddressDelta.RetainedBytes; |
| | 1600 | 1046 | | int pages = _currentAddressDelta.PersistentPageCount; |
| | 1600 | 1047 | | _currentAddressDelta.ReleaseAdditions(); |
| | 1600 | 1048 | | RecordAddressPayloadChange(_currentAddressDelta, retained, pages); |
| | 1600 | 1049 | | _currentAddressDelta = null; |
| | 1600 | 1050 | | return true; |
| | | 1051 | | } |
| | | 1052 | | |
| | | 1053 | | private void BeginRow( |
| | | 1054 | | RowKind kind, |
| | | 1055 | | NavigationPagedSequence<NavigationAutomaticSeamPair> additions) |
| | | 1056 | | { |
| | 1986 | 1057 | | ClearRowEnumeration(); |
| | 1986 | 1058 | | _rowKind = kind; |
| | 1986 | 1059 | | NavigationPagedSequence<NavigationAutomaticSeamPair> source = kind == RowKind.Dependency |
| | 1986 | 1060 | | ? _sourceGraph.AutomaticSeams.GetDependencyRow(_currentAddress) |
| | 1986 | 1061 | | : _sourceGraph.AutomaticSeams.GetActiveRow(_currentAddress); |
| | 1986 | 1062 | | _sourceRow = source.GetEnumerator(); |
| | 1986 | 1063 | | _additionRow = additions.GetEnumerator(); |
| | 1986 | 1064 | | _sourceRowComplete = source.Count == 0; |
| | 1986 | 1065 | | _additionRowComplete = additions.Count == 0; |
| | 1986 | 1066 | | _sourceRowHasNext = false; |
| | 1986 | 1067 | | _additionRowHasNext = false; |
| | 1986 | 1068 | | _pendingRowOutput = null; |
| | 1986 | 1069 | | } |
| | | 1070 | | |
| | | 1071 | | private bool AdvanceRow(MaintenanceWorkMeter meter) |
| | | 1072 | | { |
| | 42900 | 1073 | | if (_pendingRowOutput != null) |
| | | 1074 | | { |
| | 13012 | 1075 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 547 | 1076 | | return false; |
| | 12465 | 1077 | | _rowBuilder ??= new NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder(8); |
| | 12465 | 1078 | | _rowBuilder.Append(_pendingRowOutput); |
| | 12465 | 1079 | | _pendingRowOutput = null; |
| | 12465 | 1080 | | return true; |
| | | 1081 | | } |
| | 29888 | 1082 | | if (!_sourceRowHasNext && !_sourceRowComplete) |
| | | 1083 | | { |
| | 400 | 1084 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 20 | 1085 | | return false; |
| | 380 | 1086 | | if (!_sourceRow.MoveNext()) |
| | | 1087 | | { |
| | 157 | 1088 | | _sourceRowComplete = true; |
| | 157 | 1089 | | return true; |
| | | 1090 | | } |
| | 223 | 1091 | | NavigationAutomaticSeamPair pair = _sourceRow.Current; |
| | 223 | 1092 | | if (ShouldFilterSourcePair(pair, _rowKind)) |
| | 218 | 1093 | | return true; |
| | 5 | 1094 | | _sourceRowPair = pair; |
| | 5 | 1095 | | _sourceRowHasNext = true; |
| | 5 | 1096 | | return true; |
| | | 1097 | | } |
| | 29488 | 1098 | | if (!_additionRowHasNext && !_additionRowComplete) |
| | | 1099 | | { |
| | 14953 | 1100 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 623 | 1101 | | return false; |
| | 14330 | 1102 | | if (!_additionRow.MoveNext()) |
| | | 1103 | | { |
| | 1870 | 1104 | | _additionRowComplete = true; |
| | 1870 | 1105 | | return true; |
| | | 1106 | | } |
| | 12460 | 1107 | | _additionRowPair = _additionRow.Current; |
| | 12460 | 1108 | | _additionRowHasNext = true; |
| | 12460 | 1109 | | return true; |
| | | 1110 | | } |
| | 14535 | 1111 | | if (!_sourceRowHasNext && _sourceRowComplete |
| | 14535 | 1112 | | && !_additionRowHasNext && _additionRowComplete) |
| | | 1113 | | { |
| | 2070 | 1114 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 84 | 1115 | | return false; |
| | 1986 | 1116 | | NavigationPagedSequence<NavigationAutomaticSeamPair> result = |
| | 1986 | 1117 | | _rowBuilder?.Seal() ?? NavigationPagedSequence<NavigationAutomaticSeamPair>.Empty; |
| | 1986 | 1118 | | if (_rowKind == RowKind.Dependency) |
| | 1557 | 1119 | | _indexEditor!.SetDependencyRow(_currentAddress, result); |
| | | 1120 | | else |
| | 429 | 1121 | | _indexEditor!.SetActiveRow(_currentAddress, result); |
| | 1986 | 1122 | | _rowBuilder = null; |
| | 1986 | 1123 | | ClearRowEnumeration(); |
| | 1986 | 1124 | | _rowKind = RowKind.None; |
| | 1986 | 1125 | | return true; |
| | | 1126 | | } |
| | 12465 | 1127 | | if (!_sourceRowHasNext) |
| | | 1128 | | { |
| | 12458 | 1129 | | _pendingRowOutput = _additionRowPair; |
| | 12458 | 1130 | | _additionRowHasNext = false; |
| | 12458 | 1131 | | return true; |
| | | 1132 | | } |
| | 7 | 1133 | | if (!_additionRowHasNext) |
| | | 1134 | | { |
| | 3 | 1135 | | _pendingRowOutput = _sourceRowPair; |
| | 3 | 1136 | | _sourceRowHasNext = false; |
| | 3 | 1137 | | return true; |
| | | 1138 | | } |
| | 4 | 1139 | | int comparison = ComparePairs(_sourceRowPair!, _additionRowPair!); |
| | 4 | 1140 | | if (comparison <= 0) |
| | | 1141 | | { |
| | 2 | 1142 | | _pendingRowOutput = _sourceRowPair; |
| | 2 | 1143 | | _sourceRowHasNext = false; |
| | | 1144 | | } |
| | | 1145 | | else |
| | | 1146 | | { |
| | 2 | 1147 | | _pendingRowOutput = _additionRowPair; |
| | 2 | 1148 | | _additionRowHasNext = false; |
| | | 1149 | | } |
| | 4 | 1150 | | return true; |
| | | 1151 | | } |
| | | 1152 | | |
| | | 1153 | | private bool ShouldFilterSourcePair(NavigationAutomaticSeamPair pair, RowKind kind) |
| | | 1154 | | { |
| | 223 | 1155 | | if (!_pairDeltas!.TryGetValue( |
| | 223 | 1156 | | new NavigationAutomaticSeamPairKey(pair.First, pair.Second), |
| | 223 | 1157 | | out PairDelta delta)) |
| | | 1158 | | { |
| | 5 | 1159 | | return false; |
| | | 1160 | | } |
| | | 1161 | | System.Diagnostics.Debug.Assert(delta.SourceRecord != null, |
| | | 1162 | | "A delta reached through a source row retains that row's indexed pair record."); |
| | 218 | 1163 | | NavigationAutomaticSeamPairRecord source = delta.SourceRecord!; |
| | 218 | 1164 | | return ShouldFilterChangedPair( |
| | 218 | 1165 | | kind == RowKind.Dependency, |
| | 218 | 1166 | | !ReferenceEquals(source.Pair, delta.FinalPair), |
| | 218 | 1167 | | source.IsActive, |
| | 218 | 1168 | | delta.FinalActive); |
| | | 1169 | | } |
| | | 1170 | | |
| | | 1171 | | internal static bool ShouldFilterChangedPair( |
| | | 1172 | | bool dependencyRow, |
| | | 1173 | | bool geometryChanged, |
| | | 1174 | | bool sourceActive, |
| | 225 | 1175 | | bool finalActive) => dependencyRow |
| | 225 | 1176 | | ? geometryChanged |
| | 225 | 1177 | | : geometryChanged || sourceActive != finalActive; |
| | | 1178 | | |
| | | 1179 | | private bool AdvanceLinkApplication(MaintenanceWorkMeter meter) |
| | | 1180 | | { |
| | 2343 | 1181 | | if (_linkCursor == null) |
| | | 1182 | | { |
| | 22 | 1183 | | _phase = WorkPhase.Seal; |
| | 22 | 1184 | | return true; |
| | | 1185 | | } |
| | 2321 | 1186 | | if (!_linkDeltaReady && !_linkDeltaComplete) |
| | | 1187 | | { |
| | 616 | 1188 | | if (!_linkCursor.HasNext) |
| | | 1189 | | { |
| | 159 | 1190 | | _linkDeltaComplete = true; |
| | | 1191 | | } |
| | | 1192 | | else |
| | | 1193 | | { |
| | 457 | 1194 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 41 | 1195 | | return false; |
| | 416 | 1196 | | _linkCursor.MoveNext(); |
| | 416 | 1197 | | _currentLinkKey = _linkCursor.CurrentKey; |
| | 416 | 1198 | | _currentLinkDelta = _linkCursor.Current; |
| | 416 | 1199 | | _linkDeltaReady = true; |
| | 416 | 1200 | | return true; |
| | | 1201 | | } |
| | | 1202 | | } |
| | 1864 | 1203 | | if (_linkSourceMapId == null) |
| | | 1204 | | { |
| | 525 | 1205 | | if (_linkDeltaComplete) |
| | | 1206 | | { |
| | 159 | 1207 | | _linkCursor = null; |
| | 159 | 1208 | | _linkDeltas = null; |
| | 159 | 1209 | | _currentLinkDelta = null; |
| | 159 | 1210 | | _linkDeltaPayloadBytes = 0; |
| | 159 | 1211 | | _linkDeltaPayloadPages = 0; |
| | 159 | 1212 | | _phase = WorkPhase.Seal; |
| | 159 | 1213 | | return true; |
| | | 1214 | | } |
| | 366 | 1215 | | _linkSourceMapId = _currentLinkKey.SourceMapId; |
| | 366 | 1216 | | NavigationPagedSequence<NavigationStructuralLink> source = |
| | 366 | 1217 | | _sourceGraph.AutomaticSeams.GetStructuralLinks(_linkSourceMapId); |
| | 366 | 1218 | | _sourceLinks = source.GetEnumerator(); |
| | 366 | 1219 | | _sourceLinksComplete = source.Count == 0; |
| | 366 | 1220 | | return true; |
| | | 1221 | | } |
| | 1339 | 1222 | | if (_pendingLinkOutput.HasValue) |
| | | 1223 | | { |
| | 396 | 1224 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 17 | 1225 | | return false; |
| | 379 | 1226 | | _linkBuilder ??= new NavigationPagedSequence<NavigationStructuralLink>.Builder(16); |
| | 379 | 1227 | | _linkBuilder.Append(_pendingLinkOutput.Value); |
| | 379 | 1228 | | _pendingLinkOutput = null; |
| | 379 | 1229 | | return true; |
| | | 1230 | | } |
| | 943 | 1231 | | if (!_sourceLinkReady && !_sourceLinksComplete) |
| | | 1232 | | { |
| | 127 | 1233 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 17 | 1234 | | return false; |
| | 110 | 1235 | | if (!_sourceLinks.MoveNext()) |
| | | 1236 | | { |
| | 51 | 1237 | | _sourceLinksComplete = true; |
| | 51 | 1238 | | return true; |
| | | 1239 | | } |
| | 59 | 1240 | | _sourceLink = _sourceLinks.Current; |
| | 59 | 1241 | | _sourceLinkReady = true; |
| | 59 | 1242 | | return true; |
| | | 1243 | | } |
| | 816 | 1244 | | bool deltaInGroup = _linkDeltaReady |
| | 816 | 1245 | | && _currentLinkKey.SourceMapId.Equals(_linkSourceMapId, StringComparison.Ordinal); |
| | 816 | 1246 | | if (!_sourceLinkReady && _sourceLinksComplete && !deltaInGroup) |
| | | 1247 | | { |
| | 391 | 1248 | | if (!meter.TryConsumeDependencyEntries(1)) |
| | 25 | 1249 | | return false; |
| | 366 | 1250 | | NavigationPagedSequence<NavigationStructuralLink> result = |
| | 366 | 1251 | | _linkBuilder?.Seal() ?? NavigationPagedSequence<NavigationStructuralLink>.Empty; |
| | 366 | 1252 | | _indexEditor!.SetStructuralLinks(_linkSourceMapId, result); |
| | 366 | 1253 | | _linkBuilder = null; |
| | 366 | 1254 | | _linkSourceMapId = null; |
| | 366 | 1255 | | _sourceLinks = default; |
| | 366 | 1256 | | _sourceLink = default; |
| | 366 | 1257 | | return true; |
| | | 1258 | | } |
| | 425 | 1259 | | if (!_sourceLinkReady) |
| | | 1260 | | { |
| | | 1261 | | System.Diagnostics.Debug.Assert(_currentLinkDelta!.Count > 0, |
| | | 1262 | | "An unmatched negative link delta requires the source link it removes."); |
| | 365 | 1263 | | _pendingLinkOutput = new NavigationStructuralLink( |
| | 365 | 1264 | | _currentLinkKey.DestinationMapId, |
| | 365 | 1265 | | _currentLinkDelta.Count, |
| | 365 | 1266 | | _currentLinkDelta.UncertifiedCount); |
| | 365 | 1267 | | ConsumeCurrentLinkDelta(); |
| | 365 | 1268 | | return true; |
| | | 1269 | | } |
| | 60 | 1270 | | if (!deltaInGroup) |
| | | 1271 | | { |
| | 1 | 1272 | | _pendingLinkOutput = _sourceLink; |
| | 1 | 1273 | | _sourceLinkReady = false; |
| | 1 | 1274 | | _sourceLink = default; |
| | 1 | 1275 | | return true; |
| | | 1276 | | } |
| | 59 | 1277 | | int comparison = string.CompareOrdinal( |
| | 59 | 1278 | | _sourceLink.DestinationMapId, |
| | 59 | 1279 | | _currentLinkKey.DestinationMapId); |
| | 59 | 1280 | | if (comparison < 0) |
| | | 1281 | | { |
| | 8 | 1282 | | _pendingLinkOutput = _sourceLink; |
| | 8 | 1283 | | _sourceLinkReady = false; |
| | 8 | 1284 | | return true; |
| | | 1285 | | } |
| | 51 | 1286 | | if (comparison > 0) |
| | | 1287 | | { |
| | | 1288 | | System.Diagnostics.Debug.Assert(_currentLinkDelta!.Count > 0, |
| | | 1289 | | "A negative link delta must sort with the source link it removes."); |
| | 1 | 1290 | | _pendingLinkOutput = new NavigationStructuralLink( |
| | 1 | 1291 | | _currentLinkKey.DestinationMapId, |
| | 1 | 1292 | | _currentLinkDelta.Count, |
| | 1 | 1293 | | _currentLinkDelta.UncertifiedCount); |
| | 1 | 1294 | | ConsumeCurrentLinkDelta(); |
| | 1 | 1295 | | return true; |
| | | 1296 | | } |
| | 50 | 1297 | | int count = checked(_sourceLink.Count + _currentLinkDelta!.Count); |
| | 50 | 1298 | | int uncertifiedCount = checked( |
| | 50 | 1299 | | _sourceLink.UncertifiedCount + _currentLinkDelta.UncertifiedCount); |
| | 50 | 1300 | | if (count > 0) |
| | | 1301 | | { |
| | 4 | 1302 | | _pendingLinkOutput = new NavigationStructuralLink( |
| | 4 | 1303 | | _sourceLink.DestinationMapId, |
| | 4 | 1304 | | count, |
| | 4 | 1305 | | uncertifiedCount); |
| | | 1306 | | } |
| | 50 | 1307 | | _sourceLinkReady = false; |
| | 50 | 1308 | | _sourceLink = default; |
| | 50 | 1309 | | ConsumeCurrentLinkDelta(); |
| | 50 | 1310 | | return true; |
| | | 1311 | | } |
| | | 1312 | | |
| | | 1313 | | private void ConsumeCurrentLinkDelta() |
| | | 1314 | | { |
| | 416 | 1315 | | _currentLinkDelta = null; |
| | 416 | 1316 | | _linkDeltaReady = false; |
| | 416 | 1317 | | } |
| | | 1318 | | |
| | | 1319 | | private void ClearRowEnumeration() |
| | | 1320 | | { |
| | 3985 | 1321 | | _sourceRow = default; |
| | 3985 | 1322 | | _additionRow = default; |
| | 3985 | 1323 | | _sourceRowPair = null; |
| | 3985 | 1324 | | _additionRowPair = null; |
| | 3985 | 1325 | | _pendingRowOutput = null; |
| | 3985 | 1326 | | _sourceRowHasNext = false; |
| | 3985 | 1327 | | _sourceRowComplete = false; |
| | 3985 | 1328 | | _additionRowHasNext = false; |
| | 3985 | 1329 | | _additionRowComplete = false; |
| | 3985 | 1330 | | } |
| | | 1331 | | |
| | | 1332 | | private bool SealResult() |
| | | 1333 | | { |
| | 181 | 1334 | | if (!RevalidateCompletedCursor()) |
| | 3 | 1335 | | return false; |
| | 178 | 1336 | | _sealedIndexBytes = _indexEditor!.SealedAdditionalRetainedBytes; |
| | 178 | 1337 | | _sealedIndexPages = _indexEditor.SealedAdditionalPersistentPages; |
| | 178 | 1338 | | _working = _indexEditor.Seal(); |
| | 178 | 1339 | | _indexEditor = null; |
| | 178 | 1340 | | _pairDeltas = null; |
| | 178 | 1341 | | _pairDeltaPayloadBytes = 0; |
| | 178 | 1342 | | _pairDeltaPayloadPages = 0; |
| | 178 | 1343 | | _complete = true; |
| | 178 | 1344 | | return true; |
| | | 1345 | | } |
| | | 1346 | | |
| | | 1347 | | private bool RevalidateCompletedCursor() |
| | | 1348 | | { |
| | 3069 | 1349 | | if (IsCompletedCursorCurrent()) |
| | 3059 | 1350 | | return true; |
| | 10 | 1351 | | ResetToSource(); |
| | 10 | 1352 | | return false; |
| | | 1353 | | } |
| | | 1354 | | |
| | | 1355 | | private bool IsCompletedCursorCurrent() |
| | | 1356 | | { |
| | 3105 | 1357 | | if (!_hasValidatorCursor) |
| | 1474 | 1358 | | return true; |
| | 1631 | 1359 | | GridBoundaryContactCursorStatus status = _world.AdvanceBoundaryContacts( |
| | 1631 | 1360 | | _validatorCursor, |
| | 1631 | 1361 | | _contact.AsSpan(0, 0), |
| | 1631 | 1362 | | 0, |
| | 1631 | 1363 | | 0, |
| | 1631 | 1364 | | out _, |
| | 1631 | 1365 | | out _); |
| | 1631 | 1366 | | if (status != GridBoundaryContactCursorStatus.Stale |
| | 1631 | 1367 | | && _validatorCursor.RunStamp == _runStamp) |
| | | 1368 | | { |
| | 1621 | 1369 | | return true; |
| | | 1370 | | } |
| | 10 | 1371 | | return false; |
| | | 1372 | | } |
| | | 1373 | | |
| | | 1374 | | private bool RestartDiscoveryAfterInvalidation() |
| | | 1375 | | { |
| | 3 | 1376 | | ResetToSource(); |
| | 3 | 1377 | | return false; |
| | | 1378 | | } |
| | | 1379 | | |
| | | 1380 | | private void BeginMapMode(string mapId, WorkMode mode) |
| | | 1381 | | { |
| | 112 | 1382 | | _modeMapId = mapId; |
| | 112 | 1383 | | _dependencyCursor = _sourceGraph.AutomaticSeams.CreateDependencyCursor(CursorHeight); |
| | 112 | 1384 | | _sourceGraph.AutomaticSeams.BeginDependencyRange(_dependencyCursor, mapId); |
| | 112 | 1385 | | _dependencyRowRemaining = 0; |
| | 112 | 1386 | | _mode = mode; |
| | 112 | 1387 | | } |
| | | 1388 | | |
| | | 1389 | | private void BeginAddressMode(NavigationCellAddress address) |
| | | 1390 | | { |
| | 16572 | 1391 | | _modeMapId = address.MapId; |
| | 16572 | 1392 | | _dependencyAddress = address; |
| | 16572 | 1393 | | NavigationPagedSequence<NavigationAutomaticSeamPair> row = |
| | 16572 | 1394 | | _sourceGraph.AutomaticSeams.GetDependencyRow(address); |
| | 16572 | 1395 | | _dependencyRow = new NavigationAutomaticSeamIndex.EndpointEnumerator(address, row); |
| | 16572 | 1396 | | _dependencyRowRemaining = row.Count; |
| | 16572 | 1397 | | _mode = WorkMode.RevalidateAddress; |
| | 16572 | 1398 | | } |
| | | 1399 | | |
| | | 1400 | | private void BeginDiscovery(GridConfigurationKey key) |
| | | 1401 | | { |
| | 1162 | 1402 | | _pendingDiscoveryKey = key; |
| | 1162 | 1403 | | _cursorBegun = false; |
| | 1162 | 1404 | | _mode = WorkMode.Discover; |
| | 1162 | 1405 | | } |
| | | 1406 | | |
| | | 1407 | | private void QueueMutation( |
| | | 1408 | | NavigationAutomaticSeamPair pair, |
| | | 1409 | | MutationKind mutation, |
| | | 1410 | | bool ownsPair = false) |
| | | 1411 | | { |
| | 12144 | 1412 | | _pendingPair = pair; |
| | 12144 | 1413 | | _pendingMutation = mutation; |
| | 12144 | 1414 | | _pendingPairOwned = ownsPair; |
| | 12144 | 1415 | | _mutationStage = 0; |
| | 12144 | 1416 | | } |
| | | 1417 | | |
| | | 1418 | | private void FinishMode() |
| | | 1419 | | { |
| | 17842 | 1420 | | _mode = WorkMode.None; |
| | 17842 | 1421 | | _modeMapId = null; |
| | 17842 | 1422 | | _dependencyCursor = null; |
| | 17842 | 1423 | | _dependencyRow = default; |
| | 17842 | 1424 | | _dependencyRowRemaining = 0; |
| | 17842 | 1425 | | } |
| | | 1426 | | |
| | | 1427 | | private bool TryGetCurrentPair( |
| | | 1428 | | NavigationAutomaticSeamPairKey key, |
| | | 1429 | | out NavigationAutomaticSeamPair pair) |
| | | 1430 | | { |
| | 38258 | 1431 | | if (_pairEditor != null && _pairEditor.TryGetValue(key, out PairDelta delta)) |
| | | 1432 | | { |
| | 5985 | 1433 | | if (delta.FinalPair != null) |
| | | 1434 | | { |
| | 5974 | 1435 | | pair = delta.FinalPair; |
| | 5974 | 1436 | | return true; |
| | | 1437 | | } |
| | 11 | 1438 | | pair = null!; |
| | 11 | 1439 | | return false; |
| | | 1440 | | } |
| | 32273 | 1441 | | return _sourceGraph.AutomaticSeams.TryGetPair(key.First, key.Second, out pair); |
| | | 1442 | | } |
| | | 1443 | | |
| | | 1444 | | private void EnsurePairEditor() => |
| | 12144 | 1445 | | _pairEditor ??= EmptyPairDeltas.Edit(_ownershipToken); |
| | | 1446 | | |
| | | 1447 | | private void EnsureAddressEditor() => |
| | 12636 | 1448 | | _addressEditor ??= EmptyAddressDeltas.Edit(_ownershipToken); |
| | | 1449 | | |
| | | 1450 | | private void EnsureLinkEditor() => |
| | 462 | 1451 | | _linkEditor ??= EmptyLinkDeltas.Edit(_ownershipToken); |
| | | 1452 | | |
| | | 1453 | | private void AddChangedMapId(string mapId) |
| | | 1454 | | { |
| | 12202 | 1455 | | if (!_changedMapIds.ContainsKey(mapId)) |
| | 395 | 1456 | | _changedMapIds = _changedMapIds.Set(mapId, true); |
| | 12202 | 1457 | | } |
| | | 1458 | | |
| | | 1459 | | private void RecordAddressPayloadChange( |
| | | 1460 | | AddressDelta delta, |
| | | 1461 | | long beforeBytes, |
| | | 1462 | | int beforePages) |
| | | 1463 | | { |
| | 15660 | 1464 | | _addressDeltaPayloadBytes = checked( |
| | 15660 | 1465 | | _addressDeltaPayloadBytes - beforeBytes + delta.RetainedBytes); |
| | 15660 | 1466 | | _addressDeltaPayloadPages = checked( |
| | 15660 | 1467 | | _addressDeltaPayloadPages - beforePages + delta.PersistentPageCount); |
| | 15660 | 1468 | | } |
| | | 1469 | | |
| | 265297 | 1470 | | private long GetPairJournalBytes() => checked( |
| | 265297 | 1471 | | (_pairEditor?.RetainedBytes ?? _pairDeltas?.RetainedBytes ?? 0L) |
| | 265297 | 1472 | | + (_pairCursor?.RetainedBytes ?? 0L) |
| | 265297 | 1473 | | + _pairDeltaPayloadBytes); |
| | | 1474 | | |
| | 265640 | 1475 | | private int GetPairJournalPages() => checked( |
| | 265640 | 1476 | | (_pairEditor?.PersistentPageCount ?? _pairDeltas?.PersistentPageCount ?? 0) |
| | 265640 | 1477 | | + (_pairCursor?.PersistentPageCount ?? 0) |
| | 265640 | 1478 | | + _pairDeltaPayloadPages); |
| | | 1479 | | |
| | 265297 | 1480 | | private long GetAddressJournalBytes() => checked( |
| | 265297 | 1481 | | (_addressEditor?.RetainedBytes ?? _addressDeltas?.RetainedBytes ?? 0L) |
| | 265297 | 1482 | | + (_addressCursor?.RetainedBytes ?? 0L) |
| | 265297 | 1483 | | + _addressDeltaPayloadBytes); |
| | | 1484 | | |
| | 265640 | 1485 | | private int GetAddressJournalPages() => checked( |
| | 265640 | 1486 | | (_addressEditor?.PersistentPageCount ?? _addressDeltas?.PersistentPageCount ?? 0) |
| | 265640 | 1487 | | + (_addressCursor?.PersistentPageCount ?? 0) |
| | 265640 | 1488 | | + _addressDeltaPayloadPages); |
| | | 1489 | | |
| | 265297 | 1490 | | private long GetLinkJournalBytes() => checked( |
| | 265297 | 1491 | | (_linkEditor?.RetainedBytes ?? _linkDeltas?.RetainedBytes ?? 0L) |
| | 265297 | 1492 | | + (_linkCursor?.RetainedBytes ?? 0L) |
| | 265297 | 1493 | | + _linkDeltaPayloadBytes); |
| | | 1494 | | |
| | 265640 | 1495 | | private int GetLinkJournalPages() => checked( |
| | 265640 | 1496 | | (_linkEditor?.PersistentPageCount ?? _linkDeltas?.PersistentPageCount ?? 0) |
| | 265640 | 1497 | | + (_linkCursor?.PersistentPageCount ?? 0) |
| | 265640 | 1498 | | + _linkDeltaPayloadPages); |
| | | 1499 | | |
| | | 1500 | | private void ResetToSource() |
| | | 1501 | | { |
| | 13 | 1502 | | _working = _sourceGraph.AutomaticSeams; |
| | 13 | 1503 | | _changedMapIds = PersistentStringMap<bool>.Empty; |
| | 13 | 1504 | | _changedStructuralEndpoints = NavigationCellAddressSet.Empty; |
| | 13 | 1505 | | _pairEditor = null; |
| | 13 | 1506 | | _pairDeltas = null; |
| | 13 | 1507 | | _pairCursor = null; |
| | 13 | 1508 | | _addressEditor = null; |
| | 13 | 1509 | | _addressDeltas = null; |
| | 13 | 1510 | | _addressCursor = null; |
| | 13 | 1511 | | _linkEditor = null; |
| | 13 | 1512 | | _linkDeltas = null; |
| | 13 | 1513 | | _linkCursor = null; |
| | 13 | 1514 | | _indexEditor = null; |
| | 13 | 1515 | | _dependencyCursor = null; |
| | 13 | 1516 | | _dependencyRow = default; |
| | 13 | 1517 | | _pendingPair = null; |
| | 13 | 1518 | | _pendingPairOwned = false; |
| | 13 | 1519 | | _pendingMutation = MutationKind.None; |
| | 13 | 1520 | | _mutationStage = 0; |
| | 13 | 1521 | | _currentPairDelta = null; |
| | 13 | 1522 | | _currentStructuralLinkChanged = false; |
| | 13 | 1523 | | _currentAddressDelta = null; |
| | 13 | 1524 | | _rowBuilder = null; |
| | 13 | 1525 | | _linkBuilder = null; |
| | 13 | 1526 | | _rowKind = RowKind.None; |
| | 13 | 1527 | | ClearRowEnumeration(); |
| | 13 | 1528 | | _pendingLinkOutput = null; |
| | 13 | 1529 | | _linkSourceMapId = null; |
| | 13 | 1530 | | _currentLinkDelta = null; |
| | 13 | 1531 | | _linkDeltaReady = false; |
| | 13 | 1532 | | _linkDeltaComplete = false; |
| | 13 | 1533 | | _sourceLinks = default; |
| | 13 | 1534 | | _sourceLink = default; |
| | 13 | 1535 | | _sourceLinkReady = false; |
| | 13 | 1536 | | _sourceLinksComplete = false; |
| | 13 | 1537 | | _modeMapId = null; |
| | 13 | 1538 | | _pendingDiscoveryKey = default; |
| | 13 | 1539 | | _dependencyRowRemaining = 0; |
| | 13 | 1540 | | _changeIndex = 0; |
| | 13 | 1541 | | _overlayMapIndex = 0; |
| | 13 | 1542 | | _overlayCellIndex = 0; |
| | 13 | 1543 | | _overlayMapInspected = false; |
| | 13 | 1544 | | _gridEventIndex = 0; |
| | 13 | 1545 | | _discoveryMapIndex = 0; |
| | 13 | 1546 | | _worldResetMapIndex = 0; |
| | 13 | 1547 | | _fullRebuildRemoveMapIndex = 0; |
| | 13 | 1548 | | _fullRebuildDiscoverMapIndex = 0; |
| | 13 | 1549 | | _worldResetPending = false; |
| | 13 | 1550 | | _mode = WorkMode.None; |
| | 13 | 1551 | | _phase = WorkPhase.Gather; |
| | 13 | 1552 | | _runStamp = default; |
| | 13 | 1553 | | _hasRunStamp = false; |
| | 13 | 1554 | | _cursorBegun = false; |
| | 13 | 1555 | | _hasValidatorCursor = false; |
| | 13 | 1556 | | _complete = false; |
| | 13 | 1557 | | _pairDeltaPayloadBytes = 0; |
| | 13 | 1558 | | _pairDeltaPayloadPages = 0; |
| | 13 | 1559 | | _addressDeltaPayloadBytes = 0; |
| | 13 | 1560 | | _addressDeltaPayloadPages = 0; |
| | 13 | 1561 | | _linkDeltaPayloadBytes = 0; |
| | 13 | 1562 | | _linkDeltaPayloadPages = 0; |
| | 13 | 1563 | | _sealedIndexBytes = 0; |
| | 13 | 1564 | | _sealedIndexPages = 0; |
| | 13 | 1565 | | GeometryChanged = false; |
| | 13 | 1566 | | StructuralLinksChanged = false; |
| | 13 | 1567 | | Revision++; |
| | 13 | 1568 | | _ownershipToken = NavigationSeamEditToken.Create(); |
| | 13 | 1569 | | } |
| | | 1570 | | |
| | | 1571 | | private static int ComparePairs( |
| | | 1572 | | NavigationAutomaticSeamPair first, |
| | | 1573 | | NavigationAutomaticSeamPair second) => |
| | 4 | 1574 | | new NavigationAutomaticSeamPairKey(first.First, first.Second).CompareTo( |
| | 4 | 1575 | | new NavigationAutomaticSeamPairKey(second.First, second.Second)); |
| | | 1576 | | |
| | | 1577 | | private sealed class PairDelta |
| | | 1578 | | { |
| | 6148 | 1579 | | internal PairDelta(NavigationAutomaticSeamPairRecord? sourceRecord) |
| | | 1580 | | { |
| | 6148 | 1581 | | SourceRecord = sourceRecord; |
| | 6148 | 1582 | | FinalPair = sourceRecord?.Pair; |
| | 6148 | 1583 | | FinalActive = sourceRecord?.IsActive ?? false; |
| | 6148 | 1584 | | } |
| | | 1585 | | |
| | | 1586 | | internal NavigationAutomaticSeamPairRecord? SourceRecord; |
| | | 1587 | | internal NavigationAutomaticSeamPair? FinalPair; |
| | | 1588 | | internal bool FinalActive; |
| | | 1589 | | internal bool OwnsFinalPair; |
| | | 1590 | | } |
| | | 1591 | | |
| | | 1592 | | private sealed class AddressDelta |
| | | 1593 | | { |
| | | 1594 | | private NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder? _dependencyBuilder; |
| | | 1595 | | private NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder? _activeBuilder; |
| | | 1596 | | |
| | | 1597 | | internal bool DependencyChanged; |
| | | 1598 | | internal bool ActiveChanged; |
| | 1600 | 1599 | | internal NavigationPagedSequence<NavigationAutomaticSeamPair> DependencyAdditions = |
| | 1600 | 1600 | | NavigationPagedSequence<NavigationAutomaticSeamPair>.Empty; |
| | 1600 | 1601 | | internal NavigationPagedSequence<NavigationAutomaticSeamPair> ActiveAdditions = |
| | 1600 | 1602 | | NavigationPagedSequence<NavigationAutomaticSeamPair>.Empty; |
| | | 1603 | | |
| | 31320 | 1604 | | internal long RetainedBytes => checked( |
| | 31320 | 1605 | | AddressDeltaBytes |
| | 31320 | 1606 | | + (_dependencyBuilder?.RetainedBytes ?? DependencyAdditions.RetainedBytes) |
| | 31320 | 1607 | | + (_activeBuilder?.RetainedBytes ?? ActiveAdditions.RetainedBytes)); |
| | | 1608 | | |
| | 31320 | 1609 | | internal int PersistentPageCount => checked( |
| | 31320 | 1610 | | 1 |
| | 31320 | 1611 | | + (_dependencyBuilder?.PersistentPageCount ?? DependencyAdditions.PersistentPageCount) |
| | 31320 | 1612 | | + (_activeBuilder?.PersistentPageCount ?? ActiveAdditions.PersistentPageCount)); |
| | | 1613 | | |
| | | 1614 | | internal void AppendDependency(NavigationAutomaticSeamPair pair) |
| | | 1615 | | { |
| | 12032 | 1616 | | _dependencyBuilder ??= new NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder(8); |
| | 12032 | 1617 | | _dependencyBuilder.Append(pair); |
| | 12032 | 1618 | | } |
| | | 1619 | | |
| | | 1620 | | internal void AppendActive(NavigationAutomaticSeamPair pair) |
| | | 1621 | | { |
| | 428 | 1622 | | _activeBuilder ??= new NavigationPagedSequence<NavigationAutomaticSeamPair>.Builder(8); |
| | 428 | 1623 | | _activeBuilder.Append(pair); |
| | 428 | 1624 | | } |
| | | 1625 | | |
| | | 1626 | | internal void SealAdditions() |
| | | 1627 | | { |
| | 1600 | 1628 | | if (_dependencyBuilder != null) |
| | | 1629 | | { |
| | 1490 | 1630 | | DependencyAdditions = _dependencyBuilder.Seal(); |
| | 1490 | 1631 | | _dependencyBuilder = null; |
| | | 1632 | | } |
| | 1600 | 1633 | | if (_activeBuilder != null) |
| | | 1634 | | { |
| | 380 | 1635 | | ActiveAdditions = _activeBuilder.Seal(); |
| | 380 | 1636 | | _activeBuilder = null; |
| | | 1637 | | } |
| | 1600 | 1638 | | } |
| | | 1639 | | |
| | | 1640 | | internal void ReleaseAdditions() |
| | | 1641 | | { |
| | 1600 | 1642 | | DependencyAdditions = NavigationPagedSequence<NavigationAutomaticSeamPair>.Empty; |
| | 1600 | 1643 | | ActiveAdditions = NavigationPagedSequence<NavigationAutomaticSeamPair>.Empty; |
| | 1600 | 1644 | | } |
| | | 1645 | | } |
| | | 1646 | | |
| | | 1647 | | private sealed class LinkDelta |
| | | 1648 | | { |
| | | 1649 | | internal int Count; |
| | | 1650 | | internal int UncertifiedCount; |
| | | 1651 | | } |
| | | 1652 | | |
| | | 1653 | | private enum WorkPhase : byte |
| | | 1654 | | { |
| | | 1655 | | Gather, |
| | | 1656 | | ApplyPairs, |
| | | 1657 | | ApplyAddresses, |
| | | 1658 | | ApplyLinks, |
| | | 1659 | | Seal |
| | | 1660 | | } |
| | | 1661 | | |
| | | 1662 | | private enum WorkMode : byte |
| | | 1663 | | { |
| | | 1664 | | None, |
| | | 1665 | | RemoveMap, |
| | | 1666 | | RevalidateMap, |
| | | 1667 | | RevalidateAddress, |
| | | 1668 | | Discover |
| | | 1669 | | } |
| | | 1670 | | |
| | | 1671 | | private enum MutationKind : byte |
| | | 1672 | | { |
| | | 1673 | | None, |
| | | 1674 | | Add, |
| | | 1675 | | Remove, |
| | | 1676 | | Revalidate |
| | | 1677 | | } |
| | | 1678 | | |
| | | 1679 | | private enum RowKind : byte |
| | | 1680 | | { |
| | | 1681 | | None, |
| | | 1682 | | Dependency, |
| | | 1683 | | Active |
| | | 1684 | | } |
| | | 1685 | | |
| | | 1686 | | internal enum SeamAdvanceStatus : byte |
| | | 1687 | | { |
| | | 1688 | | Blocked, |
| | | 1689 | | Progressed, |
| | | 1690 | | Complete |
| | | 1691 | | } |
| | | 1692 | | } |