OXYGENHUB

Opening a bucket store sends no request per pack (refs #116) 7e0e8e5ad882

The split counters showed it: after the pack listing was kept, most
LISTs were stats. Opening a store loaded each pack's index with a stat
of the pack, for its size, and a bucket store had no stat of its own,
so each one was a LIST of the key. The size now comes from the listing
that found the pack, and a bucket store's stat is a HEAD of the key, not
a listing of its directory.

Refs #116
Author
Andy McCall @andymccall <[email protected]>
via
agent agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 762679541835
When
· 2026-10-18 02:16 UTC
Signature
◈ sealed by agent:claude@andymccall
Hash
7e0e8e5ad882474ba197e3c5b2a527370b346b6cda8fa1d3d71b3713b61027c6
Depends on
2ddd471651cd 648189388f1a 8d80356371c5 d02e545dc265 ff0af1ee299d
Depended on by
767ac6cd0545
In bookmarks
carried-not-removed doctor-trust identical-sides keyless-tags main merge-remote-bookmark paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state
In tags
v0.10.0 v0.11.0 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
5 atoms, 0 tree operations, 2 files

Browse the tree at this change

modified crates/oxy-core/src/store.rs +5 −8
…
196 unchanged lines
197 197
}
198 198
199 199
impl PackIndex {
200 -
    fn load(backend: &Backend, idx_key: &str, pack_key: &str) -> Result<PackIndex> {
200 +
    /// Load a pack's index; `pack_len` is the pack's size, from the listing
201 +
    /// that found it (a stat of it would be a request of its own).
202 +
    fn load(backend: &Backend, idx_key: &str, pack_key: &str, pack_len: u64) -> Result<PackIndex> {
201 203
        let data = backend.get(idx_key).map_err(backend_err)?;
202 204
        let bad = |m: &str| StoreError::Corrupt(ObjectRef::ZERO, format!("{idx_key}: {m}"));
203 205
        if data.len() < 12 || &data[..8] != IDX_MAGIC {
…
3 unchanged lines
207 209
        if data.len() != 12 + count * IDX_ENTRY {
208 210
            return Err(bad("index length mismatch"));
209 211
        }
210 -
        let pack_len = backend
211 -
            .stat(pack_key)
212 -
            .map_err(backend_err)?
213 -
            .ok_or_else(|| bad("the index names a pack that is not there"))?
214 -
            .size;
215 212
        let mut refs = Vec::with_capacity(count);
216 213
        let mut entries = Vec::with_capacity(count);
217 214
        for i in 0..count {
…
310 unchanged lines
528 525
        let mut packs = Vec::new();
529 526
        for idx in idx_keys {
530 527
            let pack = format!("{}.pack", idx.trim_end_matches(".idx"));
531 -
            if listed.iter().any(|e| e.key == pack) {
532 -
                packs.push(PackIndex::load(self.backend.as_ref(), idx, &pack)?);
528 +
            if let Some(p) = listed.iter().find(|e| e.key == pack) {
529 +
                packs.push(PackIndex::load(self.backend.as_ref(), idx, &pack, p.size)?);
533 530
            }
534 531
        }
535 532
        *self.packs.borrow_mut() = packs;
…
1960 unchanged lines
modified crates/oxy-strata/src/lib.rs +18 −0
…
91 unchanged lines
92 92
    fn list(&self, prefix: &str) -> Result<Vec<Entry>> {
93 93
        self.0.list(prefix)
94 94
    }
95 +
    fn stat(&self, key: &str) -> Result<Option<Entry>> {
96 +
        self.0.stat(key)
97 +
    }
95 98
    fn delete(&self, key: &str) -> Result<()> {
96 99
        self.0.delete(key)
97 100
    }
…
532 unchanged lines
630 633
            .collect();
631 634
        out.sort_by(|a, b| a.key.cmp(&b.key));
632 635
        Ok(out)
636 +
    }
637 +
638 +
    /// A HEAD of the key, not a listing of its directory (oxygen#116).
639 +
    fn stat(&self, key: &str) -> Result<Option<Entry>> {
640 +
        let path = self.path(key)?;
641 +
        counted(Op::Has);
642 +
        match self.block(self.inner.head(&path)) {
643 +
            Ok(m) => Ok(Some(Entry {
644 +
                key: key.to_string(),
645 +
                size: m.size,
646 +
                modified_ms: u64::try_from(m.last_modified.timestamp_millis()).ok(),
647 +
            })),
648 +
            Err(object_store::Error::NotFound { .. }) => Ok(None),
649 +
            Err(e) => Err(self.map(e, key)),
650 +
        }
633 651
    }
634 652
635 653
    fn delete(&self, key: &str) -> Result<()> {
…
164 unchanged lines