#000061: cold list + total bytes in cold stats

New peers landing on a public bucket need to enumerate pack_hashes
before they can `arborist cold unpack <hash>`. `cold stats` only gives
a count; `cold list` returns the per-pack details:

  - pack_hash (taken from the key)
  - compressed_bytes (one HEAD round-trip via new object_size method)
  - chunk_count (parsed from the small manifest sidecar; skippable
                 via --no-manifest for huge-bucket fast listing)

`cold stats` also now reports total bucket footprint (sums HEAD sizes).

Backend ABC gains `object_size(key) -> int | None` so both subcommands
get sizes without paying egress for the body. S3 impl uses HEAD;
MemoryBackend reads from the dict.

Verified live against DO Spaces NYC3: list-empty → push tiny pack →
list-with-manifest (pack_hash, size=5311 B, chunk_count=5) → list
--no-manifest → cold stats → cleanup.

23 passed in tests/test_cold_object.py + tests/test_evict.py.
This commit is contained in:
russell@unturf.com 2026-05-25 20:40:07 -04:00
parent 6f0ceab033
commit 51f1736091
No known key found for this signature in database
4 changed files with 94 additions and 3 deletions

View file

@ -123,6 +123,15 @@ def test_memory_backend_put_get_head_list():
assert list(b.list_keys("packs/")) == [key]
def test_memory_backend_object_size_returns_content_length_or_none():
b = MemoryBackend()
key = "packs/abc.tar.zst"
assert b.object_size(key) is None # missing
b.put(key, b"x" * 1234)
assert b.object_size(key) == 1234
assert b.object_size("packs/nonexistent") is None
def test_memory_backend_identity_carries_no_credentials():
b = MemoryBackend(endpoint_url="memory://nyc3", bucket="arborist-test")
body = b.identity.to_audit_body()