refactor(M03): extract ADT water load pipeline state

This commit is contained in:
2026-07-17 09:38:24 +04:00
parent 7973945582
commit b7c036f14d
9 changed files with 824 additions and 53 deletions
@@ -0,0 +1,167 @@
class_name AdtWaterLoadPipelineState
extends RefCounted
## Owns ADT water request, active-task and worker-result bookkeeping. The caller
## owns WorkerThreadPool operations, ADT parsing, permits and scene finalization.
var _pending_requests: Array[Dictionary] = []
var _queued_tile_keys: Dictionary = {}
var _active_task_ids_by_tile_key: Dictionary = {}
var _result_mutex := Mutex.new()
var _results: Array[Dictionary] = []
## Appends one tile/path request in FIFO order. Invalid, queued or active tile
## keys are rejected without mutation.
func enqueue_request(tile_key: String, adt_path: String) -> bool:
if tile_key.is_empty() or adt_path.is_empty():
return false
if _queued_tile_keys.has(tile_key) or _active_task_ids_by_tile_key.has(tile_key):
return false
_pending_requests.append({
"key": tile_key,
"path": adt_path,
})
_queued_tile_keys[tile_key] = true
return true
## Removes and returns the oldest request, also releasing its queued-key marker.
## An empty Dictionary means no pending request exists.
func take_next_request() -> Dictionary:
if _pending_requests.is_empty():
return {}
var request: Dictionary = _pending_requests.pop_front()
_queued_tile_keys.erase(String(request.get("key", "")))
return request
## Removes all pending requests for one tile without affecting active work.
## Returns the number of removed FIFO entries.
func cancel_pending_requests(tile_key: String) -> int:
if tile_key.is_empty():
return 0
_queued_tile_keys.erase(tile_key)
var removed_count := 0
for request_index in range(_pending_requests.size() - 1, -1, -1):
var request: Dictionary = _pending_requests[request_index]
if String(request.get("key", "")) != tile_key:
continue
_pending_requests.remove_at(request_index)
removed_count += 1
return removed_count
## Records one caller-started worker task. The opaque task ID is retained until
## the caller waits for and completes it.
func remember_active_task(tile_key: String, task_id: int) -> bool:
if tile_key.is_empty() or _active_task_ids_by_tile_key.has(tile_key):
return false
_active_task_ids_by_tile_key[tile_key] = task_id
return true
## Returns whether a worker task is active for the tile.
func has_active_task(tile_key: String) -> bool:
return not tile_key.is_empty() and _active_task_ids_by_tile_key.has(tile_key)
## Returns the opaque active task ID, or -1 for an unknown tile.
func active_task_id_for(tile_key: String) -> int:
return int(_active_task_ids_by_tile_key.get(tile_key, -1))
## Removes and returns one completed task ID, or -1 for an unknown tile.
func complete_active_task(tile_key: String) -> int:
if tile_key.is_empty() or not _active_task_ids_by_tile_key.has(tile_key):
return -1
var task_id := int(_active_task_ids_by_tile_key[tile_key])
_active_task_ids_by_tile_key.erase(tile_key)
return task_id
## Returns a detached snapshot of opaque task IDs for orderly shutdown waiting.
func active_task_ids_snapshot() -> Array:
return _active_task_ids_by_tile_key.values().duplicate()
## Publishes one parsed ADT result from a worker thread. Payload identity is
## retained; the caller must not mutate it after publication.
func publish_result(tile_key: String, adt_path: String, water_data: Dictionary) -> bool:
if tile_key.is_empty() or adt_path.is_empty():
return false
_result_mutex.lock()
_results.append({
"key": tile_key,
"path": adt_path,
"data": water_data,
})
_result_mutex.unlock()
return true
## Returns whether a worker result is currently ready.
func has_result() -> bool:
_result_mutex.lock()
var result_available := not _results.is_empty()
_result_mutex.unlock()
return result_available
## Removes and returns the oldest worker result. An empty Dictionary means no
## result was ready. Intended for the serialized renderer main thread.
func pop_result() -> Dictionary:
_result_mutex.lock()
var result: Dictionary = {}
if not _results.is_empty():
result = _results.pop_front()
_result_mutex.unlock()
return result
## Returns pending plus active load count for existing renderer metrics.
func total_load_count() -> int:
return _pending_requests.size() + _active_task_ids_by_tile_key.size()
## Returns the pending request count.
func pending_request_count() -> int:
return _pending_requests.size()
## Returns the active worker-task count.
func active_task_count() -> int:
return _active_task_ids_by_tile_key.size()
## Clears bookkeeping and queued results without interrupting worker tasks.
## Orderly shutdown must wait the task-ID snapshot before calling this method.
func clear() -> void:
_pending_requests.clear()
_queued_tile_keys.clear()
_active_task_ids_by_tile_key.clear()
_result_mutex.lock()
_results.clear()
_result_mutex.unlock()
## Returns detached FIFO/task/result scalar diagnostics without water payloads.
func diagnostic_snapshot() -> Dictionary:
var pending_requests: Array[Dictionary] = []
for request in _pending_requests:
pending_requests.append(request.duplicate())
var active_tile_keys: Array = _active_task_ids_by_tile_key.keys()
active_tile_keys.sort()
_result_mutex.lock()
var result_records: Array[Dictionary] = []
for result in _results:
result_records.append({
"key": String(result.get("key", "")),
"path": String(result.get("path", "")),
})
_result_mutex.unlock()
return {
"pending_requests": pending_requests,
"active_tile_keys": active_tile_keys.duplicate(),
"result_records": result_records,
}
@@ -0,0 +1 @@
uid://pwqm3n25pnn7