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 |