straw-queue 0.1.7__tar.gz → 0.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {straw_queue-0.1.7 → straw_queue-0.1.8}/CHANGELOG.md +34 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/CHANGELOG_zh.md +14 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/Cargo.lock +1 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/Cargo.toml +1 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/PKG-INFO +1 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/DESIGN.md +17 -2
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/DESIGN_zh.md +5 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/USAGE.md +19 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/USAGE_zh.md +16 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/pyproject.toml +1 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/coordinator.rs +44 -10
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc.rs +45 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_writer.rs +28 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/python.rs +40 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/store.rs +3 -5
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/writer_gate.rs +7 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/coordinator.py +24 -1
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/store.py +17 -2
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_gc_concurrency.py +46 -1
- straw_queue-0.1.8/tests/test_supervised_leases.py +82 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_writer_retirement.py +43 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/environment_contracts.json +4 -3
- {straw_queue-0.1.7 → straw_queue-0.1.8}/.agents/skills/straw-protocol-review/SKILL.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/.agents/skills/straw-protocol-review/agents/openai.yaml +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/.github/workflows/tests.yml +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/.github/workflows/wheels.yml +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/CONTRIBUTING.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/CONTRIBUTING_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/LICENSE +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/README_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/BENCHMARKS.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/BENCHMARKS_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/FILESYSTEM.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/FILESYSTEM_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/FORMAT.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/FORMAT_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/docs/README_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/examples/multiprocess.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/examples/records.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/examples/tensors.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/examples/work_queue.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/access.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/bounds.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_append.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_decode.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_event.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_frame.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_json.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_log.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_namespace.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_primitives.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_runtime.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_state.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_target.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/catalog_transaction.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/closure.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/closure_node.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/consumption.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/directory.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/directory_io.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/discovery.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/extent_retry.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/file_adapter.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/file_primitives.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/finalization.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/framing.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_batch.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_collection.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_io.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_mark.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_plan.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/gc_receipt.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/graph_proof_tests.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/holding.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/identities.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/incomplete.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_append.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_io.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_owner.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_primitives.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_recovery.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/journal_state.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/json_update.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/lib.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/namespace_identity.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/namespace_step.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/namespace_target.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/payload.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/pending.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/protocol.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_admin.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_application.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_commit.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_event.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_gc.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_gc_prepare.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_handoff.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_history.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_metadata.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_progress.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_reader.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_receipt.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_replay.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_retirement.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_roots.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_state.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_task.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/queue_transition.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/read_window.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/reclamation.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/record_index.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/record_manifest.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/reference_node.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/reference_validation.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/replay.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/request.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/selection.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/staging_consumption.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/stream.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/traversal.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/typed.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_append.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_device.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_file.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_recovery.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_sink.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/wal_source.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/writer_gate_flow.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/writer_ownership.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/writer_registry.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/rust/writer_retirement.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/__init__.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/backend.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/benchmark.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/errors.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/inspect.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/journal.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/protocol.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/reporting.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/rpc.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/tensor.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/src/straw/tracing.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/native.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_artifact_privacy.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_benchmark_profile.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_catalog_encoding.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_commit_consumption.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_commit_protocol.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_confined_open.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_consumer_rewind.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_dependency_traversal.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_durable_handoff.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_extent_bounds.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_extent_visibility.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_filesystem_queue.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_gc_batch.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_gc_extent_validation.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_gc_missing_parent.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_gc_receipts.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_graph_proof_operations.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_incomplete_publication.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_journal_contract.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_json_roundtrip.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_lease_selection.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_metadata_recovery.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_offline_aliases.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_offline_inspection.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_offline_recovery.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_online_gc.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_packed_store.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_parallel_validation.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_path_identity.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_pending_publication.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_provisional_holds.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_publication_handoff.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_publication_preparation.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_queue_gc_roots.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_read_session.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_ready_validation_scope.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_request_replay.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_resume_workflow.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_staging_consumption.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_streaming_write.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_task_recovery.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_tensor.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_tensor_batch_reads.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_tensor_granularity.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_tensor_preflight.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_unlimited_capacity.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_verification_runner.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_visibility_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_wal_recovery.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tests/test_writer_access.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tools/check_artifact_privacy.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tools/check_wheel.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/tools/release_build.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/README_zh.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/probes/runtime_performance.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentCatalog.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentGraph.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentInputs.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentNamespace.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentPersistence.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentProgress.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/common/tla/EnvironmentRead.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/catalog_discovery_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/catalog_discovery_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_cross_client.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_history_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_parent_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_parent_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_receipt_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_scale.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_stat_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/probes/gc_stat_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/EnvironmentParentRepair.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/EnvironmentWriter.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/EnvironmentWriterRetirement.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCBatchDeletion.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCBatchDeletion.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCConcurrentDeletion.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCConcurrentDeletion.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCDeletion.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCDeletion.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCDiscovery.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCDiscovery.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCParentRepair.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCParentRepair.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCReceipt.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/GCReceipt.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/WriterLifetime.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/WriterLifetime.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/WriterRetirement.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/gc/tla/WriterRetirement.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/measurements/20261026-release-100gb.json +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/measurements/20261026-release-comparison.json +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/measurements/20261026-release-visibility.json +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/probes/offline_alias_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/probes/offline_guard_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/probes/offline_guard_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/EnvironmentBindings.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/EnvironmentOffline.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineAliases.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineAliases.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineCleanup.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineCleanup.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineRoots.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/offline/tla/OfflineRoots.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/checks/ownership_model.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/commit_cleanup_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/consumption_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/handoff_extent_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/handoff_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/lease_selection_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/provisional_hold_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/queue_record_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/reactivation_peer_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/reactivation_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/probes/workflow_extent_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CommitApplication.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CommitApplication.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CommitCleanup.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CommitCleanup.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/Completion.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/Completion.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CrossLogComposition.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/CrossLogComposition.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/DurableHandoff.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/DurableHandoff.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentApplication.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentClock.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentCommitCleanup.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentConsumption.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentCrossComposition.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentCrossLog.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentHandoff.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentReaders.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentRequest.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/EnvironmentTraining.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/Ownership.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/Ownership.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ProvisionalHold.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ProvisionalHold.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/PublicationHandoff.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/PublicationHandoff.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/QueueRecordWorkflow.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/QueueRecordWorkflow.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ReactivationRace.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ReactivationRace.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ReactivationScan.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/ReactivationScan.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/RequestReplay.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/RequestReplay.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/SharedRecordWorkflow.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/SharedRecordWorkflow.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/StagingConsumption.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/StagingConsumption.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/TrainingResume.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/protocol/tla/TrainingResume.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/runners/check_mutations.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/runners/check_tla.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/runners/environment_manifest.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/catalog_encoding_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/dependency_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/directory_sync_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/directory_sync_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/extent_visibility_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/filesystem_bandwidth_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/incomplete_cleanup_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/incomplete_publication_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/large_extent_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/metadata_scaling.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/namespace_lookup_count.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/path_identity_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/pending_publication_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/positioned_extent_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/preparation_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/preparation_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/publication_finalize_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/publication_retry_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/publication_sync_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/read_latency_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/read_latency_trace.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/read_lookup_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/read_lookup_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/standalone_extent_probe.rs +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/tensor_granularity_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/typed_preflight_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/writer_access_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/probes/writer_lifetime_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/DependencyTraversal.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/DependencyTraversal.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/DirectoryDurability.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/DirectoryDurability.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentAuthentication.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentIncomplete.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentLocalAccess.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentLookup.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentPreparation.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentTyped.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/EnvironmentVisibility.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ExtentVisibility.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ExtentVisibility.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/IncompletePublication.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/IncompletePublication.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/NamespaceIdentity.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/NamespaceIdentity.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PendingPublication.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PendingPublication.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationFinalization.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationFinalization.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationPreparation.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationPreparation.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationRetry.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/PublicationRetry.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/RangeRead.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/RangeRead.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ReadAttempt.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ReadAttempt.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ReadLookup.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/ReadLookup.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/TypedRead.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/TypedRead.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/WriterAccess.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/storage/tla/WriterAccess.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/README.md +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/checks/crash_campaign.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/probes/catalog_fsync_fault.c +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/probes/catalog_history_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/probes/catalog_replay_probe.py +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogReadBuffer.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogReadBuffer.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogReplay.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogReplay.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogTransaction.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/CatalogTransaction.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/EnvironmentWal.tla +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/WalRecovery.cfg +0 -0
- {straw_queue-0.1.7 → straw_queue-0.1.8}/verification/wal/tla/WalRecovery.tla +0 -0
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
[中文版](CHANGELOG_zh.md)
|
|
4
4
|
|
|
5
|
+
## 0.1.8
|
|
6
|
+
|
|
7
|
+
### Supervised workers and reclamation
|
|
8
|
+
|
|
9
|
+
- Add `Coordinator(..., lease_seconds=None)` for externally supervised workers.
|
|
10
|
+
Leases do not expire with elapsed time; attempt/epoch fencing and explicit
|
|
11
|
+
worker retirement remain enforced. The default is still 300 seconds, and
|
|
12
|
+
recovery requires the queue's original lease configuration.
|
|
13
|
+
- Release both Python and native coordinator locks after GC commits root
|
|
14
|
+
retirement and tombstones, allowing heartbeats, acquisitions and completions
|
|
15
|
+
during physical deletion and directory synchronization. GC calls on the same
|
|
16
|
+
coordinator remain serialized. Return separate queue-lock wait, preparation
|
|
17
|
+
and detached-collection timings.
|
|
18
|
+
- Add opt-in `retire_writer(..., discard_staging=True)` to release only that
|
|
19
|
+
writer's registered transfer staging after retirement and sealing. Preserve
|
|
20
|
+
independent queue, checkpoint, reader and other writer owners. Retrying after
|
|
21
|
+
an uncertain retirement remains supported.
|
|
22
|
+
- Add `retention_summary()` for owner categories, retained and reclaimable
|
|
23
|
+
packs, pending deletions and open writers, with bounded examples and no
|
|
24
|
+
payload reads. Category pack counts can overlap.
|
|
25
|
+
|
|
26
|
+
### Compatibility and limits
|
|
27
|
+
|
|
28
|
+
- WAL and packed-record formats remain unchanged. The new lease and staging
|
|
29
|
+
options require 0.1.8; existing timed leases and staging retention remain the
|
|
30
|
+
defaults. Supervised mode requires external failure detection and confirmation
|
|
31
|
+
that a worker has exited before retirement. Before discarding staging, stop
|
|
32
|
+
its readers and preserve accepted results through independent durable owners;
|
|
33
|
+
returned references no longer have staging protection.
|
|
34
|
+
- Models retain their existing expiration, owner-release and deletion-plan
|
|
35
|
+
abstractions. Concrete regressions cover supervised fencing, concurrent queue
|
|
36
|
+
calls during GC and retirement/staging retries; they do not establish a
|
|
37
|
+
shared-filesystem latency bound or automatic failure detection.
|
|
38
|
+
|
|
5
39
|
## 0.1.7
|
|
6
40
|
|
|
7
41
|
### Batched reads and validation
|
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
[English](CHANGELOG.md)
|
|
4
4
|
|
|
5
|
+
## 0.1.8
|
|
6
|
+
|
|
7
|
+
### 受监督的 worker 与回收
|
|
8
|
+
|
|
9
|
+
- 新增 `Coordinator(..., lease_seconds=None)`,由外部监督器管理 worker 存活性。租约不会随时间自动过期,仍执行 attempt/epoch fencing 和显式 worker 退休;默认仍为 300 秒,恢复时必须沿用队列原有的 lease 配置。
|
|
10
|
+
- GC 持久化根退休和 tombstone 后,释放 Python 与原生 coordinator 锁,使 heartbeat、acquire 和 complete 可以与物理删除、目录同步并行。同一 coordinator 的 GC 调用仍串行;返回队列锁等待、准备和锁外回收的独立耗时。
|
|
11
|
+
- 新增显式选项 `retire_writer(..., discard_staging=True)`,在退休、封口完成后,仅释放该 writer 已登记的 transfer staging。保留独立的 queue、checkpoint、reader 和其他 writer owner;支持退休结果不确定后的重试。
|
|
12
|
+
- 新增 `retention_summary()`,报告 owner 类别、受保留/可回收 pack、待完成删除和未封口 writer,限制示例数量且不读取 payload。不同类别的 pack 计数可能重叠。
|
|
13
|
+
|
|
14
|
+
### 兼容与限制
|
|
15
|
+
|
|
16
|
+
- WAL 和 packed-record 格式不变。新的 lease 与 staging 选项需要 0.1.8;默认仍使用定时租约并保留 staging。受监督模式要求外部故障探测,并在退休前确认 worker 已退出。放弃 staging 前须停止相关 reader,以独立持久 owner 保留已接受结果;返回引用不再受 staging 保护。
|
|
17
|
+
- 模型沿用既有的过期、owner 释放与删除计划抽象;实际回归覆盖受监督 fencing、GC 期间的队列并发调用和退休/staging 重试,不据此承诺共享文件系统延迟上限或自动故障探测。
|
|
18
|
+
|
|
5
19
|
## 0.1.7
|
|
6
20
|
|
|
7
21
|
### 批量读取与校验
|
|
@@ -109,6 +109,9 @@ payload may already have been collected. Conflicting content is an error. A new
|
|
|
109
109
|
request must pass current task/attempt/epoch and expiry checks. Recovery revokes
|
|
110
110
|
old work authority but preserves outstanding reader roots. External fencing must
|
|
111
111
|
exclude concurrent coordinators; an `exclusive_owner` string is not enforcement.
|
|
112
|
+
With `lease_seconds=None`, time does not expire a lease: an external supervisor
|
|
113
|
+
must detect failure and confirm process exit before `retire_worker`. Attempt and
|
|
114
|
+
epoch checks remain mandatory, and recovery must preserve the lease mode.
|
|
112
115
|
|
|
113
116
|
<a id="c4"></a>
|
|
114
117
|
|
|
@@ -272,8 +275,11 @@ tombstone; late retain cannot revive that path. Live extents protect whole packs
|
|
|
272
275
|
Collectors may overlap: unlink is idempotent, and every collector completes its
|
|
273
276
|
own parent barriers. Never include targets added after this attempt's snapshot
|
|
274
277
|
in its receipt. A failed attempt leaves durable pending work for a later call.
|
|
275
|
-
The lower `LockedCatalog::collect` compatibility API retains its enclosing lock
|
|
276
|
-
|
|
278
|
+
The lower `LockedCatalog::collect` compatibility API retains its enclosing lock.
|
|
279
|
+
Python coordinator GC calls serialize with each other, but release both queue
|
|
280
|
+
locks after root retirement and tombstone preparation. Other queue calls may
|
|
281
|
+
proceed during physical deletion; receipt completion refreshes the catalog and
|
|
282
|
+
uses only the captured plan.
|
|
277
283
|
Offline cleanup requires stopped clients, no shared catalog/queue markers, a
|
|
278
284
|
complete accepted-root/path-binding trace and a fresh unchanged inspection.
|
|
279
285
|
|
|
@@ -288,6 +294,15 @@ persists the retirement receipt. Recover authenticates complete results and stag
|
|
|
288
294
|
them before release; abandon makes no readable-result claim. A retry may repeat
|
|
289
295
|
any already-effective step. PID, age and timeout never establish safe retirement.
|
|
290
296
|
|
|
297
|
+
Explicit `discard_staging=True` releases the exact staging owners of that
|
|
298
|
+
writer's registered results in a separate catalog transaction after retirement.
|
|
299
|
+
It does not recursively release dependency writers' staging. The caller must
|
|
300
|
+
first stop relevant readers and independently retain results still needed;
|
|
301
|
+
returned references have no staging protection. A retry must finish retirement
|
|
302
|
+
before releasing staging again and must preserve other owners. `WriterRetirement`
|
|
303
|
+
models through the retirement receipt; subsequent explicit abandonment uses the
|
|
304
|
+
owner-release rules, with concrete regressions checking the API composition.
|
|
305
|
+
|
|
291
306
|
Safety holds while owners remain and errors recur. Eventual reclamation concerns
|
|
292
307
|
sealed **permanently unowned** objects and additionally requires continued GC calls,
|
|
293
308
|
returning lock/I/O operations, eventual stabilization and fair scheduling. No
|
|
@@ -72,6 +72,8 @@ Catalog 与队列日志独立。步骤之间崩溃可以多保留保护,不能
|
|
|
72
72
|
|
|
73
73
|
**C2 — 身份与重试。** 稳定请求 ID 绑定内容和结果。先查询匹配的已记录回执,再考虑旧 payload 或 lease 校验;payload 可能已经回收。内容冲突必须报错。新请求必须校验当前 task/attempt/epoch 和过期状态。恢复撤销旧工作权限,但保留尚未退出的 reader 根。外部 fencing 必须排除并发协调器;`exclusive_owner` 字符串不执行 fencing。
|
|
74
74
|
|
|
75
|
+
`lease_seconds=None` 时,时间不会使 lease 过期:外部监督器必须探测故障,并在调用 `retire_worker` 前确认进程退出。Attempt/epoch 检查仍然必需,恢复时必须保留原有 lease 模式。
|
|
76
|
+
|
|
75
77
|
<a id="c4"></a>
|
|
76
78
|
|
|
77
79
|
**C4 — Checkpoint 回退。** 持久保存 model/optimizer/RNG checkpoint 及其匹配的 consumer 位置。该 checkpoint 之后已经处理的结果,需要在确认处理前有独立 replay owner。恢复 checkpoint 的位置,而非队列最新 cursor。回退 WAL 更新前先重新保留变为必需的 receipt/batch 根;保护缺失或数据损坏必须拒绝更新。替代版本持久化后才释放旧 checkpoint/replay owner。真实 checkpoint 提交和全部 rank 完成信号由应用提供。
|
|
@@ -172,12 +174,14 @@ unlink 本轮全部目标(包括 advisory stat 声称不存在的目标)
|
|
|
172
174
|
|
|
173
175
|
Unlink `NotFound` 是幂等缺失,不是持久删除。已经缺失的 pending 文件仍需父目录屏障。其他错误上报并保留待办。回执停止重复删除/计数,但保留永久 tombstone;迟到 retain 不得复活路径。存活 extent 保护整个 pack。离线清理要求客户端停止、无共享 catalog/queue 标记、完整接受根及路径绑定追踪,以及新的未变化检查结果。
|
|
174
176
|
|
|
175
|
-
多个 collector 可以重叠执行:unlink 幂等,各自完成自己目标的父目录屏障。回执不能包含本轮快照之后加入的目标。失败后持久 pending 留给后续调用处理。底层 `LockedCatalog::collect` 兼容 API
|
|
177
|
+
多个 collector 可以重叠执行:unlink 幂等,各自完成自己目标的父目录屏障。回执不能包含本轮快照之后加入的目标。失败后持久 pending 留给后续调用处理。底层 `LockedCatalog::collect` 兼容 API 仍持有外层锁。Python coordinator 的 GC 调用彼此串行,但在根退休和 tombstone 准备完成后释放两层队列锁;物理删除期间其他队列调用可以继续。回执阶段重新获取新鲜 catalog,只使用已捕获的计划。
|
|
176
178
|
|
|
177
179
|
<a id="g4"></a>
|
|
178
180
|
|
|
179
181
|
**G4 — Writer 退休与进展。** 每次 writer 修改持有准确 incarnation 的 gate 并检查持久 fence。产生效果前先登记操作身份、准备 owner 和依赖。退休获取相同 gate,持久化 fence,排空旧 I/O,对账已登记操作,然后释放准备 owner、记录结算、seal 预留文件、持久化退休回执。Recover 在释放前认证完整结果并 staging;abandon 不声称结果可读。重试可能重复任意已生效步骤。PID、年龄和超时都不能证明退休安全。
|
|
180
182
|
|
|
183
|
+
显式 `discard_staging=True` 在上述退休完成后,以独立 catalog 事务释放该 writer 已登记结果的准确 staging owner,不递归释放依赖 writer 的 staging。调用者必须先停止相关 reader,并以独立持久 owner 保留仍需使用的结果;此时返回引用不受 staging 保护。错误后的重试仍须完成退休后再释放,其他 owner 保持不变。`WriterRetirement` 模型覆盖到退休回执;后续显式放弃沿用 owner 释放规则,由实际回归检查接口组合。
|
|
184
|
+
|
|
181
185
|
Owner 持续存在或错误反复发生时,安全性仍须成立。最终回收只针对 sealed 且**永久无主**的对象,还要求持续调用 GC、锁/I/O 返回、故障最终稳定及公平调度。这不提供延迟上限,也不意味着存在自动后台回收器。
|
|
182
186
|
|
|
183
187
|
<details>
|
|
@@ -463,3 +463,22 @@ matching queue view, pending/buffered/prefetched dependencies and post-checkpoin
|
|
|
463
463
|
replay owners. A latest marker or queue acknowledgement cannot replace it. See
|
|
464
464
|
[restart APIs](#what-resumes-after-a-restart). Application tests cover real schemas,
|
|
465
465
|
abort/resume, shared tensors, multiple-reader completion and whole-job recovery.
|
|
466
|
+
|
|
467
|
+
### Externally supervised workers
|
|
468
|
+
|
|
469
|
+
`Coordinator(..., lease_seconds=None)` delegates liveness to an external supervisor;
|
|
470
|
+
attempt and epoch fences remain enforced. The supervisor must detect failures,
|
|
471
|
+
confirm the old process has exited, and call `retire_worker`. The default remains
|
|
472
|
+
300 seconds, and recovery cannot change this queue identity setting.
|
|
473
|
+
Queue GC serializes root retirement and durable tombstones, then releases queue
|
|
474
|
+
locks before deleting files and syncing directories. Its result includes
|
|
475
|
+
`queue_lock_wait_seconds`, `queue_prepare_seconds`, and `detached_collection_seconds`.
|
|
476
|
+
|
|
477
|
+
After readers and writers have exited and accepted results have durable owners,
|
|
478
|
+
`retire_writer(writer_id, policy="abandon", discard_staging=True)` also relinquishes
|
|
479
|
+
that writer's registered transfer staging after retirement and sealing. This is
|
|
480
|
+
opt-in; other queue, checkpoint, reader, and writer owners are preserved. Returned
|
|
481
|
+
references have no staging protection in this mode and are not recovery handles.
|
|
482
|
+
`retention_summary()` reports owner categories and open packs with bounded
|
|
483
|
+
examples, without reading tensor payloads. Category pack counts can overlap and
|
|
484
|
+
must not be added together.
|
|
@@ -272,3 +272,19 @@ receipt = peer.publication_receipt(
|
|
|
272
272
|
Rollout 的路由/分数采集必须完整、一致后才能发布 continuation,不能仅以 token 生成结束为准。所有必要消费者完成后才确认原始输出,全部训练 rank 读完后才确认 ready batch。应用监督进程应锁存并传播后台 GC 失败、停止接收新任务、保留不确定存储,并对远端在途工作实施 fencing。
|
|
273
273
|
|
|
274
274
|
联合 checkpoint 的提交与回退遵循 [C4](DESIGN_zh.md#c4):包含模型/优化器/RNG 和匹配队列视图,保留 pending/buffered/prefetched 依赖及 post-checkpoint replay owner;不能只用 latest 标记或队列确认代替。重启 API 见[恢复说明](#重启后分别续上什么)。应用集成测试应覆盖真实 schema、中断续跑、共享张量、多 reader 完成信号与整任务恢复。
|
|
275
|
+
|
|
276
|
+
### 由外部监督器管理的 worker
|
|
277
|
+
|
|
278
|
+
`Coordinator(..., lease_seconds=None)` 显式关闭墙钟租约过期,仍保留 attempt/epoch fencing。
|
|
279
|
+
只有外部监督器负责故障探测、确认旧进程退出并调用 `retire_worker` 时才使用此模式;
|
|
280
|
+
默认仍为 300 秒。已有队列恢复时不能改变该配置。
|
|
281
|
+
队列 GC 的持久化根/墓碑准备仍串行,物理删除和目录同步在队列锁外执行。
|
|
282
|
+
`collect_garbage()` 返回 `queue_lock_wait_seconds`、`queue_prepare_seconds` 和 `detached_collection_seconds`。
|
|
283
|
+
|
|
284
|
+
监督器确认 writer 的读写进程已退出、已接受结果由队列或其他 durable owner 接管后,
|
|
285
|
+
可调用 `retire_writer(writer_id, policy="abandon", discard_staging=True)`:
|
|
286
|
+
先完整退役、封口,再放弃这个 writer 已登记的 transfer staging;默认不放弃。
|
|
287
|
+
这不会释放队列、checkpoint、reader 或其他 writer 的 staging。
|
|
288
|
+
该模式返回的引用没有 staging 保护,不应当作待恢复的裸引用读取。
|
|
289
|
+
`retention_summary()` 提供 owner 类别和未封口 pack 的元数据摘要,限制示例数量且不读取 tensor payload。
|
|
290
|
+
不同类别的 pack 计数可能重叠,不能直接相加。
|
|
@@ -78,7 +78,7 @@ pub struct Coordinator {
|
|
|
78
78
|
owners: HashMap<String, String>,
|
|
79
79
|
queue_id: String,
|
|
80
80
|
storage_prefix: String,
|
|
81
|
-
lease_seconds: f64
|
|
81
|
+
lease_seconds: Option<f64>,
|
|
82
82
|
sealed: bool,
|
|
83
83
|
draining: bool,
|
|
84
84
|
storage_failed: bool,
|
|
@@ -391,8 +391,18 @@ impl Coordinator {
|
|
|
391
391
|
.as_str()
|
|
392
392
|
.unwrap_or("rollout")
|
|
393
393
|
.to_string();
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
// Null explicitly delegates failure detection to a process supervisor.
|
|
395
|
+
// Attempt/epoch fencing and reader lifetime checks still apply.
|
|
396
|
+
let lease_seconds = match options.get("lease_seconds") {
|
|
397
|
+
None => Some(300.),
|
|
398
|
+
Some(Value::Null) => None,
|
|
399
|
+
Some(value) => Some(value.as_f64().ok_or_else(|| {
|
|
400
|
+
Error::new("ValueError", "Lease duration must be a number or null")
|
|
401
|
+
})?),
|
|
402
|
+
};
|
|
403
|
+
if lease_seconds.is_some_and(|seconds| !seconds.is_finite() || seconds <= 0.)
|
|
404
|
+
|| queue_id.is_empty()
|
|
405
|
+
{
|
|
396
406
|
return fail("ValueError", "Invalid lease duration/queue ID");
|
|
397
407
|
}
|
|
398
408
|
let defaults = json!({"pending_tasks":10000,"inflight_tasks":256,"control_tasks":1,"accepted_records":100000,"accepted_bytes":68719476736u64,"accepted_tokens":100000000,"ready_bytes":68719476736u64,"max_result_bytes":4294967296u64,"max_result_tokens":100000000,"metadata_bytes":262144});
|
|
@@ -686,7 +696,7 @@ impl Coordinator {
|
|
|
686
696
|
self.count("stale_attempts");
|
|
687
697
|
return fail("StaleAttempt", "Lease is not current authorization");
|
|
688
698
|
}
|
|
689
|
-
if self.deadlines.get(id).copied().unwrap_or(0.) <= now {
|
|
699
|
+
if self.lease_seconds.is_some() && self.deadlines.get(id).copied().unwrap_or(0.) <= now {
|
|
690
700
|
return fail("LeaseExpired", "Lease expired");
|
|
691
701
|
};
|
|
692
702
|
Ok(task.clone())
|
|
@@ -1018,9 +1028,11 @@ impl Coordinator {
|
|
|
1018
1028
|
fault,
|
|
1019
1029
|
Some(graph),
|
|
1020
1030
|
)?;
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1031
|
+
if let Some(seconds) = self.lease_seconds {
|
|
1032
|
+
for lease in leases {
|
|
1033
|
+
self.deadlines
|
|
1034
|
+
.insert(field(&lease, "task_id")?.into(), now + seconds);
|
|
1035
|
+
}
|
|
1024
1036
|
}
|
|
1025
1037
|
Ok(json!({"status":"acquired","assignments":assignments}))
|
|
1026
1038
|
}
|
|
@@ -1126,8 +1138,10 @@ impl Coordinator {
|
|
|
1126
1138
|
for lease in leases {
|
|
1127
1139
|
match self.valid_lease(lease, now) {
|
|
1128
1140
|
Ok(_) => {
|
|
1129
|
-
self.
|
|
1130
|
-
|
|
1141
|
+
if let Some(seconds) = self.lease_seconds {
|
|
1142
|
+
self.deadlines
|
|
1143
|
+
.insert(field(lease, "task_id")?.into(), now + seconds);
|
|
1144
|
+
}
|
|
1131
1145
|
results.push(json!("extended"));
|
|
1132
1146
|
}
|
|
1133
1147
|
Err(e) if ["StaleAttempt", "LeaseExpired"].contains(&e.kind.as_str()) => {
|
|
@@ -1587,6 +1601,26 @@ impl Coordinator {
|
|
|
1587
1601
|
.map_err(root_error)
|
|
1588
1602
|
}
|
|
1589
1603
|
fn collect_garbage(&mut self, fault: &mut Fault<'_>) -> Result<Value> {
|
|
1604
|
+
let plan = self.prepare_garbage_collection(fault)?;
|
|
1605
|
+
plan.execute(&self.store.config, fault)
|
|
1606
|
+
}
|
|
1607
|
+
/// Only durable queue/root admission needs exclusive queue access. Once
|
|
1608
|
+
/// tombstones are committed, physical deletion can run without this owner.
|
|
1609
|
+
pub(crate) fn prepare_garbage_collection(
|
|
1610
|
+
&mut self,
|
|
1611
|
+
fault: &mut Fault<'_>,
|
|
1612
|
+
) -> Result<crate::gc::CollectionPlan> {
|
|
1613
|
+
if !crate::queue_application::permitted(
|
|
1614
|
+
&self.journal,
|
|
1615
|
+
self.journal.closed(),
|
|
1616
|
+
"collect_garbage",
|
|
1617
|
+
) {
|
|
1618
|
+
return fail(
|
|
1619
|
+
"UnsafeRecovery",
|
|
1620
|
+
"Coordinator unavailable; stop owner and recover",
|
|
1621
|
+
);
|
|
1622
|
+
}
|
|
1623
|
+
self.finish_consumption(fault)?;
|
|
1590
1624
|
if !self.store.config.gc_enabled()? {
|
|
1591
1625
|
return fail("ValueError", "Online GC is not enabled");
|
|
1592
1626
|
}
|
|
@@ -1610,7 +1644,7 @@ impl Coordinator {
|
|
|
1610
1644
|
.map_err(gc_prepare_error)?;
|
|
1611
1645
|
self.store
|
|
1612
1646
|
.config
|
|
1613
|
-
.
|
|
1647
|
+
.plan_queue_collection(prepared, fault)?
|
|
1614
1648
|
.ok_or_else(|| Error::new("ValueError", "Online GC is not enabled"))
|
|
1615
1649
|
}
|
|
1616
1650
|
pub fn close(&mut self) {
|
|
@@ -23,6 +23,7 @@ use std::path::{Path, PathBuf};
|
|
|
23
23
|
|
|
24
24
|
#[path = "gc_plan.rs"]
|
|
25
25
|
mod collection;
|
|
26
|
+
pub(crate) use collection::Plan as CollectionPlan;
|
|
26
27
|
|
|
27
28
|
fn catalog_append_error(error: crate::catalog_append::Error<Error, Error>) -> Error {
|
|
28
29
|
match error {
|
|
@@ -649,6 +650,10 @@ impl LockedCatalog<'_> {
|
|
|
649
650
|
pub fn collect(&mut self, config: &Config, fault: &mut Fault<'_>) -> Result<Value> {
|
|
650
651
|
self.catalog.collect(config, fault)
|
|
651
652
|
}
|
|
653
|
+
#[cfg(feature = "python")]
|
|
654
|
+
pub(crate) fn retention_summary(&self) -> Value {
|
|
655
|
+
self.catalog.retention_summary()
|
|
656
|
+
}
|
|
652
657
|
#[cfg(test)]
|
|
653
658
|
pub(crate) fn collect_queue(
|
|
654
659
|
&mut self,
|
|
@@ -1482,6 +1487,46 @@ impl Catalog {
|
|
|
1482
1487
|
"retained_packs":result.retained,"tombstones":self.log.indexes().deleted.len()})
|
|
1483
1488
|
}
|
|
1484
1489
|
|
|
1490
|
+
/// Metadata diagnostics with bounded examples; never reads payload files.
|
|
1491
|
+
#[cfg(feature = "python")]
|
|
1492
|
+
pub(crate) fn retention_summary(&self) -> Value {
|
|
1493
|
+
let indexes = self.log.indexes();
|
|
1494
|
+
let live = indexes.roots();
|
|
1495
|
+
let mut categories =
|
|
1496
|
+
std::collections::BTreeMap::<String, (usize, HashSet<String>, Vec<Value>)>::new();
|
|
1497
|
+
for (owner, paths) in &indexes.owners {
|
|
1498
|
+
let kind = owner.split(':').next().unwrap_or(owner).to_owned();
|
|
1499
|
+
let entry = categories.entry(kind).or_default();
|
|
1500
|
+
entry.0 += 1;
|
|
1501
|
+
entry.1.extend(paths.iter().cloned());
|
|
1502
|
+
if entry.2.len() < 4 {
|
|
1503
|
+
entry.2.push(json!({"owner":owner,"packs":paths.len(),"pack_examples":paths.iter().take(3).collect::<Vec<_>>()}));
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
let categories = categories
|
|
1507
|
+
.into_iter()
|
|
1508
|
+
.map(|(kind, (owners, packs, examples))| {
|
|
1509
|
+
(
|
|
1510
|
+
kind,
|
|
1511
|
+
json!({"owners":owners,"retained_packs":packs.len(),"examples":examples}),
|
|
1512
|
+
)
|
|
1513
|
+
})
|
|
1514
|
+
.collect::<serde_json::Map<_, _>>();
|
|
1515
|
+
let mut open = std::collections::BTreeMap::<String, usize>::new();
|
|
1516
|
+
for (path, sealed) in &indexes.packs {
|
|
1517
|
+
if !sealed && !indexes.deleted.contains(path) {
|
|
1518
|
+
let writer = path.split('/').nth(2).unwrap_or("unknown").to_owned();
|
|
1519
|
+
*open.entry(writer).or_default() += 1;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
json!({"owners":indexes.owners.len(),"retained_packs":live.len(),
|
|
1523
|
+
"unowned_sealed_packs":indexes.candidates(&live).len(),
|
|
1524
|
+
"pending_deletions":indexes.pending_deletions.len(),"tombstones":indexes.deleted.len(),
|
|
1525
|
+
"open_packs":open.values().sum::<usize>(),"open_writers":open.len(),
|
|
1526
|
+
"open_writer_examples":open.into_iter().take(64).collect::<std::collections::BTreeMap<_,_>>(),
|
|
1527
|
+
"categories":categories})
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1485
1530
|
#[cfg(test)]
|
|
1486
1531
|
fn collect_queue(
|
|
1487
1532
|
&mut self,
|
|
@@ -390,6 +390,18 @@ impl Config {
|
|
|
390
390
|
writer: &str,
|
|
391
391
|
policy: RetirementPolicy,
|
|
392
392
|
fault: &mut Fault<'_>,
|
|
393
|
+
) -> Result<Vec<Value>> {
|
|
394
|
+
self.retire_writer_with_staging(writer, policy, false, fault)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/// Explicitly relinquish this writer's transfer staging only after its
|
|
398
|
+
/// retirement has committed. Queue/checkpoint/reader owners are untouched.
|
|
399
|
+
pub(crate) fn retire_writer_with_staging(
|
|
400
|
+
&self,
|
|
401
|
+
writer: &str,
|
|
402
|
+
policy: RetirementPolicy,
|
|
403
|
+
discard_staging: bool,
|
|
404
|
+
fault: &mut Fault<'_>,
|
|
393
405
|
) -> Result<Vec<Value>> {
|
|
394
406
|
let mut permit = Permit::retire(&self.root, &self.run_id, writer)?;
|
|
395
407
|
let registry = permit.registry(None, fault)?;
|
|
@@ -406,6 +418,22 @@ impl Config {
|
|
|
406
418
|
pending,
|
|
407
419
|
};
|
|
408
420
|
crate::writer_retirement::execute(&mut retirement)?;
|
|
421
|
+
if discard_staging {
|
|
422
|
+
// Use exact durable result descriptors, not file age or path
|
|
423
|
+
// overlap. Do not recursively consume another writer's staging.
|
|
424
|
+
let owners = retirement
|
|
425
|
+
.registry
|
|
426
|
+
.described_publications()
|
|
427
|
+
.map(Catalog::staged)
|
|
428
|
+
.collect::<Result<BTreeSet<_>>>()?;
|
|
429
|
+
retirement.config.catalog(|c| {
|
|
430
|
+
let held = owners
|
|
431
|
+
.into_iter()
|
|
432
|
+
.filter(|owner| c.catalog.log.indexes().owners.contains_key(owner))
|
|
433
|
+
.collect::<Vec<_>>();
|
|
434
|
+
c.release(retirement.config, &held, retirement.fault)
|
|
435
|
+
})?;
|
|
436
|
+
}
|
|
409
437
|
Ok(retirement.recovered)
|
|
410
438
|
}
|
|
411
439
|
}
|
|
@@ -675,6 +675,7 @@ impl NativeStore {
|
|
|
675
675
|
return Ok(serde_json::to_string(&self.config.collect_garbage(fault)?)?);
|
|
676
676
|
}
|
|
677
677
|
let result = self.config.catalog(|c| match method {
|
|
678
|
+
"retention_summary" => Ok(c.retention_summary()),
|
|
678
679
|
"retain" => {
|
|
679
680
|
c.retain(
|
|
680
681
|
&self.config,
|
|
@@ -706,12 +707,14 @@ impl NativeStore {
|
|
|
706
707
|
py.allow_threads(|| Ok(self.writer_access()?.writer_id().to_owned()))
|
|
707
708
|
.map_err(|e| exception(py, e))
|
|
708
709
|
}
|
|
710
|
+
#[pyo3(signature = (writer_id, policy, fault, discard_staging=false))]
|
|
709
711
|
fn retire_writer(
|
|
710
712
|
&self,
|
|
711
713
|
py: Python<'_>,
|
|
712
714
|
writer_id: &str,
|
|
713
715
|
policy: &str,
|
|
714
716
|
fault: Py<PyAny>,
|
|
717
|
+
discard_staging: bool,
|
|
715
718
|
) -> PyResult<String> {
|
|
716
719
|
self.check_writer_process()?;
|
|
717
720
|
let policy = match policy {
|
|
@@ -729,7 +732,12 @@ impl NativeStore {
|
|
|
729
732
|
};
|
|
730
733
|
run(py, &fault, |fault| {
|
|
731
734
|
Ok(serde_json::to_string(
|
|
732
|
-
&self.config.
|
|
735
|
+
&self.config.retire_writer_with_staging(
|
|
736
|
+
writer_id,
|
|
737
|
+
policy,
|
|
738
|
+
discard_staging,
|
|
739
|
+
fault,
|
|
740
|
+
)?,
|
|
733
741
|
)?)
|
|
734
742
|
})
|
|
735
743
|
}
|
|
@@ -758,6 +766,23 @@ impl NativeStore {
|
|
|
758
766
|
}
|
|
759
767
|
}
|
|
760
768
|
#[pyclass]
|
|
769
|
+
struct NativeQueueCollection {
|
|
770
|
+
config: Config,
|
|
771
|
+
plan: Mutex<Option<crate::gc::CollectionPlan>>,
|
|
772
|
+
}
|
|
773
|
+
#[pymethods]
|
|
774
|
+
impl NativeQueueCollection {
|
|
775
|
+
fn execute(&self, py: Python<'_>, fault: Py<PyAny>) -> PyResult<String> {
|
|
776
|
+
run(py, &fault, |f| {
|
|
777
|
+
let plan =
|
|
778
|
+
self.plan.lock().unwrap().take().ok_or_else(|| {
|
|
779
|
+
Error::new("ValueError", "Collection plan was already executed")
|
|
780
|
+
})?;
|
|
781
|
+
Ok(serde_json::to_string(&plan.execute(&self.config, f)?)?)
|
|
782
|
+
})
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
#[pyclass]
|
|
761
786
|
struct NativeCoordinator {
|
|
762
787
|
owner: Mutex<Coordinator>,
|
|
763
788
|
}
|
|
@@ -809,6 +834,20 @@ impl NativeCoordinator {
|
|
|
809
834
|
fn diagnostics(&self, py: Python<'_>) -> String {
|
|
810
835
|
py.allow_threads(||{let q=self.owner.lock().unwrap();json!({"path":q.journal.path,"sequence":q.journal.sequence,"poisoned":q.journal.poisoned,"closed":q.journal.closed(),"recovery_seconds":q.recovery_seconds}).to_string()})
|
|
811
836
|
}
|
|
837
|
+
fn prepare_garbage_collection(
|
|
838
|
+
&self,
|
|
839
|
+
py: Python<'_>,
|
|
840
|
+
fault: Py<PyAny>,
|
|
841
|
+
) -> PyResult<NativeQueueCollection> {
|
|
842
|
+
run(py, &fault, |f| {
|
|
843
|
+
let mut owner = self.owner.lock().unwrap();
|
|
844
|
+
let plan = owner.prepare_garbage_collection(f)?;
|
|
845
|
+
Ok(NativeQueueCollection {
|
|
846
|
+
config: owner.store.config.clone(),
|
|
847
|
+
plan: Mutex::new(Some(plan)),
|
|
848
|
+
})
|
|
849
|
+
})
|
|
850
|
+
}
|
|
812
851
|
fn close(&self, py: Python<'_>) {
|
|
813
852
|
py.allow_threads(|| self.owner.lock().unwrap().close());
|
|
814
853
|
}
|
|
@@ -559,14 +559,12 @@ impl Config {
|
|
|
559
559
|
) -> Result<Option<T>> {
|
|
560
560
|
self.with_catalog(|catalog| catalog.transaction(self, call))
|
|
561
561
|
}
|
|
562
|
-
pub(crate) fn
|
|
562
|
+
pub(crate) fn plan_queue_collection(
|
|
563
563
|
&self,
|
|
564
564
|
prepared: crate::queue_gc::Prepared<'_>,
|
|
565
565
|
fault: &mut Fault<'_>,
|
|
566
|
-
) -> Result<Option<
|
|
567
|
-
self.catalog(|catalog| catalog.plan_collection(self, Some(prepared), fault))
|
|
568
|
-
.map(|plan| plan.execute(self, fault))
|
|
569
|
-
.transpose()
|
|
566
|
+
) -> Result<Option<crate::gc::CollectionPlan>> {
|
|
567
|
+
self.catalog(|catalog| catalog.plan_collection(self, Some(prepared), fault))
|
|
570
568
|
}
|
|
571
569
|
/// Collect with the physical deletion and directory barriers outside the
|
|
572
570
|
/// pool-wide catalog lock. Durable tombstones fence every selected name.
|
|
@@ -536,6 +536,13 @@ impl Registry {
|
|
|
536
536
|
.cloned()
|
|
537
537
|
.collect()
|
|
538
538
|
}
|
|
539
|
+
|
|
540
|
+
pub(crate) fn described_publications(&self) -> impl Iterator<Item = &Value> {
|
|
541
|
+
self.operations
|
|
542
|
+
.iter()
|
|
543
|
+
.filter_map(|op| op.results.as_ref())
|
|
544
|
+
.flat_map(|results| results.roots.iter().chain(results.intermediates.iter()))
|
|
545
|
+
}
|
|
539
546
|
}
|
|
540
547
|
|
|
541
548
|
#[cfg(test)]
|
|
@@ -30,6 +30,8 @@ class _JournalView:
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class Coordinator:
|
|
33
|
+
supports_supervised_leases = True
|
|
34
|
+
|
|
33
35
|
def __init__(
|
|
34
36
|
self,
|
|
35
37
|
store,
|
|
@@ -46,6 +48,7 @@ class Coordinator:
|
|
|
46
48
|
self.limits = limits or Limits()
|
|
47
49
|
self.lease_seconds, self.clock = lease_seconds, clock
|
|
48
50
|
self._call_lock = threading.RLock()
|
|
51
|
+
self._gc_lock = threading.Lock()
|
|
49
52
|
self._validation_context = threading.local()
|
|
50
53
|
self._cpu_started = time.process_time()
|
|
51
54
|
options = dict(
|
|
@@ -272,7 +275,27 @@ class Coordinator:
|
|
|
272
275
|
raw results. Its finished_batches acknowledge training reads on all ranks.
|
|
273
276
|
Other queues and explicit storage owners independently retain their roots.
|
|
274
277
|
"""
|
|
275
|
-
|
|
278
|
+
# Only GC passes serialize with each other. The queue lock protects
|
|
279
|
+
# root retirement and durable tombstones, never physical filesystem I/O.
|
|
280
|
+
with self._gc_lock:
|
|
281
|
+
started = time.monotonic()
|
|
282
|
+
try:
|
|
283
|
+
with self._call_lock:
|
|
284
|
+
acquired = time.monotonic()
|
|
285
|
+
plan = self._native.prepare_garbage_collection(self.store._fault)
|
|
286
|
+
prepared = time.monotonic()
|
|
287
|
+
result = json.loads(plan.execute(self.store._fault))
|
|
288
|
+
except BaseException:
|
|
289
|
+
scope = getattr(self._validation_context, "scope", None)
|
|
290
|
+
if scope is not None:
|
|
291
|
+
scope.close()
|
|
292
|
+
raise
|
|
293
|
+
result.update(
|
|
294
|
+
queue_lock_wait_seconds=acquired - started,
|
|
295
|
+
queue_prepare_seconds=prepared - acquired,
|
|
296
|
+
detached_collection_seconds=time.monotonic() - prepared,
|
|
297
|
+
)
|
|
298
|
+
return result
|
|
276
299
|
|
|
277
300
|
def snapshot(self):
|
|
278
301
|
result = self._call("snapshot", locals())
|
|
@@ -114,6 +114,8 @@ class SharedFilesystemStore(_RecordReader):
|
|
|
114
114
|
max_buffer_bytes controls temporary copy memory, never logical record size.
|
|
115
115
|
"""
|
|
116
116
|
|
|
117
|
+
supports_writer_staging_discard = True
|
|
118
|
+
|
|
117
119
|
def __init__(
|
|
118
120
|
self,
|
|
119
121
|
root,
|
|
@@ -215,14 +217,18 @@ class SharedFilesystemStore(_RecordReader):
|
|
|
215
217
|
"""Persistent incarnation used to explicitly retire this writer."""
|
|
216
218
|
return self._native.writer_id()
|
|
217
219
|
|
|
218
|
-
def retire_writer(self, writer_id, *, policy="recover"):
|
|
220
|
+
def retire_writer(self, writer_id, *, policy="recover", discard_staging=False):
|
|
219
221
|
"""Fence an exact incarnation and reconcile its unfinished publications.
|
|
220
222
|
|
|
221
223
|
A busy writer raises WriterBusy. Recovery returns staged results;
|
|
222
224
|
explicit abandonment preserves existing queue, reader and staging roots.
|
|
223
225
|
The same writer cannot resume after retirement. Create a fresh writer.
|
|
226
|
+
discard_staging=True explicitly relinquishes that writer's registered
|
|
227
|
+
transfer publications after retirement. The supervisor must first stop
|
|
228
|
+
its readers and adopt accepted results. Other durable owners survive;
|
|
229
|
+
returned references are not protected by staging in this mode.
|
|
224
230
|
"""
|
|
225
|
-
values = json.loads(self._native.retire_writer(writer_id, policy, self._fault))
|
|
231
|
+
values = json.loads(self._native.retire_writer(writer_id, policy, self._fault, discard_staging))
|
|
226
232
|
return [
|
|
227
233
|
RecordSetRef.from_dict(value) if "manifest" in value else RecordRef.from_dict(value) for value in values
|
|
228
234
|
]
|
|
@@ -277,6 +283,15 @@ class SharedFilesystemStore(_RecordReader):
|
|
|
277
283
|
"""Reclaim unowned sealed packs; retry deletions without a durable receipt."""
|
|
278
284
|
return self._storage("collect")
|
|
279
285
|
|
|
286
|
+
def retention_summary(self):
|
|
287
|
+
"""Report owner/pack metadata with bounded examples and no payload reads.
|
|
288
|
+
|
|
289
|
+
Category pack counts can overlap and must not be added together.
|
|
290
|
+
Open writers and retained ownership require lifecycle confirmation;
|
|
291
|
+
elapsed file age alone does not authorize reclamation.
|
|
292
|
+
"""
|
|
293
|
+
return self._storage("retention_summary")
|
|
294
|
+
|
|
280
295
|
def _inputs(self, records):
|
|
281
296
|
metadata, payloads = [], []
|
|
282
297
|
for record in records:
|