tensorfs 0.3.64__tar.gz → 0.3.65__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.
- {tensorfs-0.3.64 → tensorfs-0.3.65}/Cargo.lock +2 -2
- {tensorfs-0.3.64 → tensorfs-0.3.65}/Cargo.toml +1 -1
- {tensorfs-0.3.64 → tensorfs-0.3.65}/PKG-INFO +1 -1
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/part_rows_tests.rs +157 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/progress.rs +10 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/resume_tests.rs +13 -3
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived.rs +166 -10
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/durability.rs +67 -27
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/meta.rs +11 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/src/store.rs +7 -1
- {tensorfs-0.3.64 → tensorfs-0.3.65}/pyproject.toml +1 -1
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/Cargo.toml +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/build.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/examples/h3-swiglu-layout.md +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/examples/optional-cache-backfill.md +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/examples/resident-conversion.md +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/examples/resident_conversion_profile.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/asset_update.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/b64.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/fetch.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/ingest.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/main.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/rd.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/cache_roots.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/canon.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/capability.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/catalog.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/cbor.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/checkpoint.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/checkpoint_root.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/corpus.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/adoption.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/companion_tests.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/estimate.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/graft_tests.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/retention.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/derived/roots.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/descriptors.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/dtype.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/err.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/fetch.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/fill.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/fit.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/gc.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/header.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/home.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ids.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/convert.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/custody.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/fingerprint.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/h3_lora.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/journal.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/mod.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/preflight.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/source.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/ingest/transaction.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/jcs.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/lib.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/limits.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/machine.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/manifest.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/project.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/providers.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/read.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/receipt.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/reclaim.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/registry.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/relation.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/repo_cache/identity.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/repo_cache.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/repository.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/sha256.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/source_artifact.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/spec.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/staging.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/stats.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/storage.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/store.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/api.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/http.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/http_reuse_tests.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/hub.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/ledger.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/memory.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/mod.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/pace.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/policy.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/prefix.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/pull.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/push.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/ranged.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/speculate.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/transport/tests.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/src/vectors.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/additive_fields.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/anima_hf_profile.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/checkpoint_roots.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fd_budget.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fd_headroom.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fetch_url_progress.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fit.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/foreign_json.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/h3_lora.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/h3_swiglu.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/home.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/import_tree.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/instrument_profiles.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/liveness.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/qwen_image21_profile.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/read_plan.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/reclaim.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/reclaim_run.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/repo_cache.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/repo_store.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/resident_admission.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/sha256_backends.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/sharded_cas.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/source_artifacts.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/source_download.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/source_plan.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/source_prefixes.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/source_preflight.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/staging.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/store_boundaries.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/tensor_schema.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/transfer_memory.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/trust_index.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/version.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/tests/write_through.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/Cargo.toml +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/src/docs.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/src/errors.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/src/ingest.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-py/src/lib.rs +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/__init__.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/_derived_channel.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/_ext.pyi +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/_source_channel.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/_tensors.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/derived.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/errors.py +0 -0
- {tensorfs-0.3.64 → tensorfs-0.3.65}/python/tensorfs/py.typed +0 -0
|
@@ -439,7 +439,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
439
439
|
|
|
440
440
|
[[package]]
|
|
441
441
|
name = "tensorfs-core"
|
|
442
|
-
version = "0.3.
|
|
442
|
+
version = "0.3.65"
|
|
443
443
|
dependencies = [
|
|
444
444
|
"fs2",
|
|
445
445
|
"libc",
|
|
@@ -454,7 +454,7 @@ dependencies = [
|
|
|
454
454
|
|
|
455
455
|
[[package]]
|
|
456
456
|
name = "tensorfs-py"
|
|
457
|
-
version = "0.3.
|
|
457
|
+
version = "0.3.65"
|
|
458
458
|
dependencies = [
|
|
459
459
|
"pyo3",
|
|
460
460
|
"tensorfs-core",
|
|
@@ -44,6 +44,7 @@ fn add(store: &Store, meta: &Meta, id: &str, writer: &Begin, key: &str, byte: u8
|
|
|
44
44
|
id,
|
|
45
45
|
1,
|
|
46
46
|
&writer.additions,
|
|
47
|
+
None,
|
|
47
48
|
("model", key, "value"),
|
|
48
49
|
&mut [byte; 512].as_slice(),
|
|
49
50
|
)
|
|
@@ -112,6 +113,7 @@ fn parts_are_rows_that_resume_refuse_conflicts_and_stay_retained() {
|
|
|
112
113
|
&id,
|
|
113
114
|
2,
|
|
114
115
|
&resumed.additions,
|
|
116
|
+
None,
|
|
115
117
|
("model", "weight_2", "value"),
|
|
116
118
|
&mut [3u8; 512].as_slice(),
|
|
117
119
|
)
|
|
@@ -167,3 +169,158 @@ fn an_older_builds_inline_row_and_a_torn_journal_line_are_read() {
|
|
|
167
169
|
assert!(!journal.exists());
|
|
168
170
|
std::fs::remove_dir_all(store.root()).unwrap();
|
|
169
171
|
}
|
|
172
|
+
|
|
173
|
+
#[test]
|
|
174
|
+
fn indexed_checkpoints_write_the_chain_full_checkpoints_write() {
|
|
175
|
+
const COUNT: usize = 40;
|
|
176
|
+
let mut stores = Vec::new();
|
|
177
|
+
for label in ["full", "indexed"] {
|
|
178
|
+
let (store, meta, id, mut declaration) = fixture(label);
|
|
179
|
+
let prototype = declaration.components[0].add[0].clone();
|
|
180
|
+
declaration.components[0].add = (0..COUNT)
|
|
181
|
+
.map(|index| {
|
|
182
|
+
let mut tensor = prototype.clone();
|
|
183
|
+
tensor.key = format!("weight_{index:03}");
|
|
184
|
+
tensor
|
|
185
|
+
})
|
|
186
|
+
.collect();
|
|
187
|
+
declaration.order = (0..COUNT)
|
|
188
|
+
.map(|index| ("model".into(), format!("weight_{index:03}")))
|
|
189
|
+
.collect();
|
|
190
|
+
declaration.configs = vec![ConfigDeclaration::Add {
|
|
191
|
+
target: "model.json".into(),
|
|
192
|
+
}];
|
|
193
|
+
declaration.max_new_bytes = (COUNT * 512 + 64) as u64;
|
|
194
|
+
let writer = begin(&store, &meta, &id, 1, declaration.clone(), None).unwrap();
|
|
195
|
+
stores.push((store, meta, id, declaration, writer));
|
|
196
|
+
}
|
|
197
|
+
let mut cursor = None;
|
|
198
|
+
let (mut full_prior, mut indexed_prior) = (None, None);
|
|
199
|
+
let mut heads: Vec<ObjectRef> = Vec::new();
|
|
200
|
+
for index in 0..COUNT {
|
|
201
|
+
let key = format!("weight_{index:03}");
|
|
202
|
+
let payload = [index as u8; 512];
|
|
203
|
+
let (store, meta, id, _, writer) = &stores[0];
|
|
204
|
+
add_indexed_part(
|
|
205
|
+
store,
|
|
206
|
+
meta,
|
|
207
|
+
id,
|
|
208
|
+
1,
|
|
209
|
+
&writer.additions,
|
|
210
|
+
None,
|
|
211
|
+
("model", &key, "value"),
|
|
212
|
+
&mut payload.as_slice(),
|
|
213
|
+
)
|
|
214
|
+
.unwrap();
|
|
215
|
+
let full = checkpoint_progress(store, meta, id, 1, "request", "model", full_prior.as_ref())
|
|
216
|
+
.unwrap();
|
|
217
|
+
let (store, meta, id, _, writer) = &stores[1];
|
|
218
|
+
add_indexed_part(
|
|
219
|
+
store,
|
|
220
|
+
meta,
|
|
221
|
+
id,
|
|
222
|
+
1,
|
|
223
|
+
&writer.additions,
|
|
224
|
+
cursor.as_mut(),
|
|
225
|
+
("model", &key, "value"),
|
|
226
|
+
&mut payload.as_slice(),
|
|
227
|
+
)
|
|
228
|
+
.unwrap();
|
|
229
|
+
// An older acknowledged head sends the writer down the full path, which re-seeds it.
|
|
230
|
+
let previous = if index == 25 {
|
|
231
|
+
heads.get(heads.len() - 3).cloned()
|
|
232
|
+
} else {
|
|
233
|
+
indexed_prior.clone()
|
|
234
|
+
};
|
|
235
|
+
let indexed = checkpoint_indexed(
|
|
236
|
+
store,
|
|
237
|
+
meta,
|
|
238
|
+
id,
|
|
239
|
+
1,
|
|
240
|
+
"request",
|
|
241
|
+
"model",
|
|
242
|
+
previous.as_ref(),
|
|
243
|
+
&mut cursor,
|
|
244
|
+
)
|
|
245
|
+
.unwrap();
|
|
246
|
+
assert_eq!(full, indexed, "checkpoint {index} diverged");
|
|
247
|
+
assert_eq!(cursor.as_ref().unwrap().tip.head, indexed.1);
|
|
248
|
+
full_prior = full.1.head;
|
|
249
|
+
indexed_prior = indexed.1.head;
|
|
250
|
+
heads.push(indexed_prior.clone().unwrap());
|
|
251
|
+
if index == 20 {
|
|
252
|
+
for (store, meta, id, _, _) in &stores {
|
|
253
|
+
add_config(meta, id, 1, "model.json", &mut b"{}".as_slice()).unwrap();
|
|
254
|
+
let _ = store;
|
|
255
|
+
}
|
|
256
|
+
cursor = None;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
let (store, meta, id, declaration, writer) = stores.pop().unwrap();
|
|
260
|
+
let head = indexed_prior.unwrap();
|
|
261
|
+
let canonical = String::from_utf8(declaration.clone().canonical_work_bytes().unwrap()).unwrap();
|
|
262
|
+
let restored = read_progress(&store, &head, &id, &canonical, &[]).unwrap();
|
|
263
|
+
assert_eq!(restored.added_parts.len(), COUNT);
|
|
264
|
+
assert_eq!(restored.added_configs.len(), 1);
|
|
265
|
+
fence(&meta, &id, 1).unwrap();
|
|
266
|
+
release_guards(&meta, Some(writer.writer_hold), writer.source_leases);
|
|
267
|
+
let resumed = begin(&store, &meta, &id, 2, declaration, Some(&head)).unwrap();
|
|
268
|
+
assert_eq!(completed(&meta, &id, 2).unwrap().0.len(), COUNT);
|
|
269
|
+
fence(&meta, &id, 2).unwrap();
|
|
270
|
+
release_guards(&meta, Some(resumed.writer_hold), resumed.source_leases);
|
|
271
|
+
std::fs::remove_dir_all(store.root()).unwrap();
|
|
272
|
+
for (store, meta, id, _, writer) in stores {
|
|
273
|
+
fence(&meta, &id, 1).unwrap();
|
|
274
|
+
release_guards(&meta, Some(writer.writer_hold), writer.source_leases);
|
|
275
|
+
std::fs::remove_dir_all(store.root()).unwrap();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[test]
|
|
280
|
+
fn an_indexed_checkpoint_does_not_reread_its_chain() {
|
|
281
|
+
let (store, meta, id, declaration) = fixture("no-reread");
|
|
282
|
+
let writer = begin(&store, &meta, &id, 1, declaration, None).unwrap();
|
|
283
|
+
let mut cursor = None;
|
|
284
|
+
let mut prior: Option<ObjectRef> = None;
|
|
285
|
+
let mut first = None;
|
|
286
|
+
for (index, key) in ["weight_0", "weight_1", "weight_2"].into_iter().enumerate() {
|
|
287
|
+
add_indexed_part(
|
|
288
|
+
&store,
|
|
289
|
+
&meta,
|
|
290
|
+
&id,
|
|
291
|
+
1,
|
|
292
|
+
&writer.additions,
|
|
293
|
+
cursor.as_mut(),
|
|
294
|
+
("model", key, "value"),
|
|
295
|
+
&mut [index as u8 + 1; 512].as_slice(),
|
|
296
|
+
)
|
|
297
|
+
.unwrap();
|
|
298
|
+
let (_, head) = checkpoint_indexed(
|
|
299
|
+
&store,
|
|
300
|
+
&meta,
|
|
301
|
+
&id,
|
|
302
|
+
1,
|
|
303
|
+
"request",
|
|
304
|
+
"model",
|
|
305
|
+
prior.as_ref(),
|
|
306
|
+
&mut cursor,
|
|
307
|
+
)
|
|
308
|
+
.unwrap();
|
|
309
|
+
prior = head.head;
|
|
310
|
+
first.get_or_insert(prior.clone().unwrap());
|
|
311
|
+
if index == 0 {
|
|
312
|
+
// The chain's root link is gone: a checkpoint that walked the chain now fails.
|
|
313
|
+
let root = first.clone().unwrap();
|
|
314
|
+
std::fs::remove_file(store.object_path(root.sha256.trim_start_matches("sha256:")))
|
|
315
|
+
.unwrap();
|
|
316
|
+
assert!(
|
|
317
|
+
checkpoint_progress(&store, &meta, &id, 1, "request", "model", prior.as_ref())
|
|
318
|
+
.is_err()
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
assert_eq!(cursor.as_ref().unwrap().parts, 3);
|
|
323
|
+
fence(&meta, &id, 1).unwrap();
|
|
324
|
+
release_guards(&meta, Some(writer.writer_hold), writer.source_leases);
|
|
325
|
+
std::fs::remove_dir_all(store.root()).unwrap();
|
|
326
|
+
}
|
|
@@ -21,6 +21,16 @@ fn part_key(part: &AddedPart) -> (&str, &str, &str) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
impl Delta {
|
|
24
|
+
/// The parts a writer accepted since its last checkpoint, sorted as a delta stores them.
|
|
25
|
+
pub(super) fn accepted(work: ObjectRef, mut parts: Vec<AddedPart>) -> Self {
|
|
26
|
+
parts.sort_by(|left, right| part_key(left).cmp(&part_key(right)));
|
|
27
|
+
Self {
|
|
28
|
+
work,
|
|
29
|
+
parts,
|
|
30
|
+
configs: Vec::new(),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
pub(super) fn between(
|
|
25
35
|
row: &TransactionRow,
|
|
26
36
|
prior: Option<&TransactionRow>,
|
|
@@ -981,6 +981,7 @@ fn profile_derived_transaction_scaling() {
|
|
|
981
981
|
let mut part_ms = 0.0;
|
|
982
982
|
let mut checkpoint_ms = 0.0;
|
|
983
983
|
let mut prior = None;
|
|
984
|
+
let mut cursor = None;
|
|
984
985
|
for index in 0..writes {
|
|
985
986
|
let key = format!("weight_{index:04}");
|
|
986
987
|
let started = Instant::now();
|
|
@@ -990,15 +991,24 @@ fn profile_derived_transaction_scaling() {
|
|
|
990
991
|
&id,
|
|
991
992
|
1,
|
|
992
993
|
&writer.additions,
|
|
994
|
+
cursor.as_mut(),
|
|
993
995
|
("model", &key, "value"),
|
|
994
996
|
&mut [index as u8; 16].as_slice(),
|
|
995
997
|
)
|
|
996
998
|
.unwrap();
|
|
997
999
|
part_ms += started.elapsed().as_secs_f64() * 1000.0;
|
|
998
1000
|
let started = Instant::now();
|
|
999
|
-
let (_, head) =
|
|
1000
|
-
|
|
1001
|
-
|
|
1001
|
+
let (_, head) = checkpoint_indexed(
|
|
1002
|
+
&store,
|
|
1003
|
+
&meta,
|
|
1004
|
+
&id,
|
|
1005
|
+
1,
|
|
1006
|
+
"profile",
|
|
1007
|
+
"model",
|
|
1008
|
+
prior.as_ref(),
|
|
1009
|
+
&mut cursor,
|
|
1010
|
+
)
|
|
1011
|
+
.unwrap();
|
|
1002
1012
|
prior = head.head;
|
|
1003
1013
|
checkpoint_ms += started.elapsed().as_secs_f64() * 1000.0;
|
|
1004
1014
|
}
|
|
@@ -2711,6 +2711,158 @@ pub fn completed(
|
|
|
2711
2711
|
))
|
|
2712
2712
|
}
|
|
2713
2713
|
|
|
2714
|
+
/// A writer's position in its checkpoint chain: the chain's tip and held blobs, its fixed
|
|
2715
|
+
/// plan and work context, and the parts it accepted since. With it a checkpoint writes and
|
|
2716
|
+
/// verifies only those parts instead of re-reading the chain it extends.
|
|
2717
|
+
#[derive(Debug, Clone)]
|
|
2718
|
+
pub struct CheckpointCursor {
|
|
2719
|
+
chain: String,
|
|
2720
|
+
plan: String,
|
|
2721
|
+
work: ObjectRef,
|
|
2722
|
+
tip: crate::durability::Tip,
|
|
2723
|
+
parts: usize,
|
|
2724
|
+
pending: Vec<AddedPart>,
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
impl CheckpointCursor {
|
|
2728
|
+
/// Seed from a checkpoint the full path just wrote or confirmed. `None` when there is
|
|
2729
|
+
/// no head yet to extend.
|
|
2730
|
+
fn at(
|
|
2731
|
+
store: &Store,
|
|
2732
|
+
meta: &Meta,
|
|
2733
|
+
transaction: &str,
|
|
2734
|
+
writer_session: u64,
|
|
2735
|
+
chain: String,
|
|
2736
|
+
plan: &str,
|
|
2737
|
+
head: &crate::durability::Head,
|
|
2738
|
+
) -> Result<Option<Self>> {
|
|
2739
|
+
let Some(tip) = head.head.as_ref() else {
|
|
2740
|
+
return Ok(None);
|
|
2741
|
+
};
|
|
2742
|
+
let mut rows: Vec<_> = meta.derived_row(transaction)?.into_iter().collect();
|
|
2743
|
+
let row = open_row(&mut rows, transaction, writer_session)?;
|
|
2744
|
+
let context = progress::context(row);
|
|
2745
|
+
let held = crate::durability::local_chain(store, tip, plan)?
|
|
2746
|
+
.blobs
|
|
2747
|
+
.into_iter()
|
|
2748
|
+
.map(|object| object.sha256)
|
|
2749
|
+
.collect();
|
|
2750
|
+
Ok(Some(Self {
|
|
2751
|
+
chain,
|
|
2752
|
+
plan: plan.to_string(),
|
|
2753
|
+
work: ObjectRef::of(&crate::canon::write(&context.to_value())),
|
|
2754
|
+
tip: crate::durability::Tip {
|
|
2755
|
+
head: head.clone(),
|
|
2756
|
+
held,
|
|
2757
|
+
},
|
|
2758
|
+
parts: row.added_parts.len(),
|
|
2759
|
+
pending: Vec::new(),
|
|
2760
|
+
}))
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
/// Extend the chain by the pending parts, or `None` when anything but this writer's own
|
|
2764
|
+
/// accepted parts moved since the cursor was taken.
|
|
2765
|
+
fn advance(
|
|
2766
|
+
&mut self,
|
|
2767
|
+
store: &Store,
|
|
2768
|
+
meta: &Meta,
|
|
2769
|
+
transaction: &str,
|
|
2770
|
+
writer_session: u64,
|
|
2771
|
+
chain: &str,
|
|
2772
|
+
previous: Option<&ObjectRef>,
|
|
2773
|
+
) -> Result<Option<(String, crate::durability::Head)>> {
|
|
2774
|
+
let tip = self.tip.head.head.clone();
|
|
2775
|
+
let root = roots::read(store, transaction)?;
|
|
2776
|
+
if self.chain != chain
|
|
2777
|
+
|| previous.is_some_and(|previous| Some(previous) != tip.as_ref())
|
|
2778
|
+
|| root.as_ref().and_then(|root| root.checkpoint.as_ref()) != tip.as_ref()
|
|
2779
|
+
{
|
|
2780
|
+
return Ok(None);
|
|
2781
|
+
}
|
|
2782
|
+
meta.check_session(transaction, writer_session)?;
|
|
2783
|
+
if meta.part_count(transaction)? != self.parts + self.pending.len() {
|
|
2784
|
+
return Ok(None);
|
|
2785
|
+
}
|
|
2786
|
+
if self.pending.is_empty() {
|
|
2787
|
+
return Ok(Some((self.plan.clone(), self.tip.head.clone())));
|
|
2788
|
+
}
|
|
2789
|
+
let parts = std::mem::take(&mut self.pending);
|
|
2790
|
+
let objects = parts
|
|
2791
|
+
.iter()
|
|
2792
|
+
.flat_map(|added| added.part.segments().iter().cloned())
|
|
2793
|
+
.collect();
|
|
2794
|
+
let count = parts.len();
|
|
2795
|
+
let delta = progress::Delta::accepted(self.work.clone(), parts);
|
|
2796
|
+
let policy = crate::durability::Policy {
|
|
2797
|
+
chain,
|
|
2798
|
+
operation: transaction,
|
|
2799
|
+
plan: &self.plan,
|
|
2800
|
+
interval: crate::durability::INTERVAL_BYTES,
|
|
2801
|
+
};
|
|
2802
|
+
let extended = crate::durability::extend(
|
|
2803
|
+
store,
|
|
2804
|
+
&policy,
|
|
2805
|
+
&self.tip,
|
|
2806
|
+
&crate::canon::write(&delta.to_value()),
|
|
2807
|
+
objects,
|
|
2808
|
+
None,
|
|
2809
|
+
)?;
|
|
2810
|
+
let Some(mut root) = root else {
|
|
2811
|
+
return Ok(None);
|
|
2812
|
+
};
|
|
2813
|
+
root.checkpoint = extended.head.head.clone();
|
|
2814
|
+
roots::write(store, &root)?;
|
|
2815
|
+
self.tip
|
|
2816
|
+
.held
|
|
2817
|
+
.extend(extended.named.into_iter().map(|object| object.sha256));
|
|
2818
|
+
self.tip.head = extended.head;
|
|
2819
|
+
self.parts += count;
|
|
2820
|
+
Ok(Some((self.plan.clone(), self.tip.head.clone())))
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
/// Checkpoint through the writer's cursor, which each full checkpoint re-seeds.
|
|
2825
|
+
#[allow(clippy::too_many_arguments)]
|
|
2826
|
+
pub fn checkpoint_indexed(
|
|
2827
|
+
store: &Store,
|
|
2828
|
+
meta: &Meta,
|
|
2829
|
+
transaction: &str,
|
|
2830
|
+
writer_session: u64,
|
|
2831
|
+
operation: &str,
|
|
2832
|
+
slot: &str,
|
|
2833
|
+
previous: Option<&ObjectRef>,
|
|
2834
|
+
cursor: &mut Option<CheckpointCursor>,
|
|
2835
|
+
) -> Result<(String, crate::durability::Head)> {
|
|
2836
|
+
let chain = format!("{operation}/{slot}");
|
|
2837
|
+
if let Some(current) = cursor.as_mut() {
|
|
2838
|
+
if let Some(advanced) =
|
|
2839
|
+
current.advance(store, meta, transaction, writer_session, &chain, previous)?
|
|
2840
|
+
{
|
|
2841
|
+
return Ok(advanced);
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
*cursor = None;
|
|
2845
|
+
let (plan, head) = checkpoint_progress(
|
|
2846
|
+
store,
|
|
2847
|
+
meta,
|
|
2848
|
+
transaction,
|
|
2849
|
+
writer_session,
|
|
2850
|
+
operation,
|
|
2851
|
+
slot,
|
|
2852
|
+
previous,
|
|
2853
|
+
)?;
|
|
2854
|
+
*cursor = CheckpointCursor::at(
|
|
2855
|
+
store,
|
|
2856
|
+
meta,
|
|
2857
|
+
transaction,
|
|
2858
|
+
writer_session,
|
|
2859
|
+
chain,
|
|
2860
|
+
&plan,
|
|
2861
|
+
&head,
|
|
2862
|
+
)?;
|
|
2863
|
+
Ok((plan, head))
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2714
2866
|
pub fn checkpoint_progress(
|
|
2715
2867
|
store: &Store,
|
|
2716
2868
|
meta: &Meta,
|
|
@@ -3115,6 +3267,7 @@ pub fn add_part<R: Read>(
|
|
|
3115
3267
|
transaction,
|
|
3116
3268
|
writer_session,
|
|
3117
3269
|
&additions,
|
|
3270
|
+
None,
|
|
3118
3271
|
value,
|
|
3119
3272
|
reader,
|
|
3120
3273
|
)
|
|
@@ -3122,12 +3275,14 @@ pub fn add_part<R: Read>(
|
|
|
3122
3275
|
|
|
3123
3276
|
/// Accept one part. The cost is this part's bytes plus one indexed SQL row: the
|
|
3124
3277
|
/// declaration is not re-read and earlier accepted parts are neither read nor rewritten.
|
|
3278
|
+
#[allow(clippy::too_many_arguments)]
|
|
3125
3279
|
pub fn add_indexed_part<R: Read>(
|
|
3126
3280
|
store: &Store,
|
|
3127
3281
|
meta: &Meta,
|
|
3128
3282
|
transaction: &str,
|
|
3129
3283
|
writer_session: u64,
|
|
3130
3284
|
additions: &Additions,
|
|
3285
|
+
cursor: Option<&mut CheckpointCursor>,
|
|
3131
3286
|
value: (&str, &str, &str),
|
|
3132
3287
|
reader: &mut R,
|
|
3133
3288
|
) -> Result<crate::checkpoint::Written> {
|
|
@@ -3168,16 +3323,17 @@ pub fn add_indexed_part<R: Read>(
|
|
|
3168
3323
|
// The private root names the objects before SQL accepts the part, so GC never
|
|
3169
3324
|
// observes an accepted part whose bytes it may reclaim.
|
|
3170
3325
|
roots::append_parts(store, &transaction, written.part.segments())?;
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3326
|
+
let added = AddedPart {
|
|
3327
|
+
component: component.to_string(),
|
|
3328
|
+
key: tensor_key.to_string(),
|
|
3329
|
+
role: role.to_string(),
|
|
3330
|
+
part: written.part.clone(),
|
|
3331
|
+
};
|
|
3332
|
+
if meta.accept_part(&transaction, writer_session, &added)? {
|
|
3333
|
+
if let Some(cursor) = cursor {
|
|
3334
|
+
cursor.pending.push(added);
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3181
3337
|
Ok(written)
|
|
3182
3338
|
}
|
|
3183
3339
|
|
|
@@ -429,7 +429,7 @@ pub(crate) fn checkpoint_bytes(
|
|
|
429
429
|
policy: &Policy<'_>,
|
|
430
430
|
previous: Option<&ObjectRef>,
|
|
431
431
|
bytes: &[u8],
|
|
432
|
-
|
|
432
|
+
objects: Vec<ObjectRef>,
|
|
433
433
|
hold: Option<&str>,
|
|
434
434
|
) -> Result<CheckpointExport> {
|
|
435
435
|
let prior = previous
|
|
@@ -444,18 +444,68 @@ pub(crate) fn checkpoint_bytes(
|
|
|
444
444
|
"checkpoint belongs to another operation slot",
|
|
445
445
|
);
|
|
446
446
|
}
|
|
447
|
-
if bytes.len() > limits::DOC_MAX_BYTES {
|
|
448
|
-
return refuse(
|
|
449
|
-
Code::COUNT_CAP,
|
|
450
|
-
"checkpoint progress exceeds the document byte cap",
|
|
451
|
-
);
|
|
452
|
-
}
|
|
453
447
|
if bytes.is_empty() {
|
|
454
448
|
return Ok(CheckpointExport {
|
|
455
449
|
head: Head::default(),
|
|
456
450
|
roots: Vec::new(),
|
|
457
451
|
});
|
|
458
452
|
}
|
|
453
|
+
let tip = Tip {
|
|
454
|
+
head: Head {
|
|
455
|
+
head: previous.cloned(),
|
|
456
|
+
links: prior.as_ref().map_or(0, |set| set.links),
|
|
457
|
+
bytes: prior.as_ref().map_or(0, |set| set.bytes),
|
|
458
|
+
},
|
|
459
|
+
held: prior
|
|
460
|
+
.iter()
|
|
461
|
+
.flat_map(|set| set.blobs.iter().map(|object| object.sha256.clone()))
|
|
462
|
+
.collect(),
|
|
463
|
+
};
|
|
464
|
+
let mut roots = previous
|
|
465
|
+
.map(|head| local_documents(store, head))
|
|
466
|
+
.transpose()?
|
|
467
|
+
.unwrap_or_default();
|
|
468
|
+
let extended = extend(store, policy, &tip, bytes, objects, hold)?;
|
|
469
|
+
roots.push(extended.progress);
|
|
470
|
+
roots.extend(extended.links);
|
|
471
|
+
Ok(CheckpointExport {
|
|
472
|
+
head: extended.head,
|
|
473
|
+
roots,
|
|
474
|
+
})
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/// A chain's tip and every blob digest the chain already names: all a writer needs to
|
|
478
|
+
/// extend it without walking it.
|
|
479
|
+
#[derive(Debug, Clone, Default)]
|
|
480
|
+
pub(crate) struct Tip {
|
|
481
|
+
pub head: Head,
|
|
482
|
+
pub held: std::collections::HashSet<String>,
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
pub(crate) struct Extended {
|
|
486
|
+
pub head: Head,
|
|
487
|
+
pub progress: ObjectRef,
|
|
488
|
+
/// The progress document and every object the new links name, now held by the chain.
|
|
489
|
+
pub named: Vec<ObjectRef>,
|
|
490
|
+
pub links: Vec<ObjectRef>,
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/// Write one progress document and the links naming only the objects `tip` does not yet
|
|
494
|
+
/// hold. Only the supplied objects are verified, so the cost is this checkpoint's own.
|
|
495
|
+
pub(crate) fn extend(
|
|
496
|
+
store: &Store,
|
|
497
|
+
policy: &Policy<'_>,
|
|
498
|
+
tip: &Tip,
|
|
499
|
+
bytes: &[u8],
|
|
500
|
+
mut objects: Vec<ObjectRef>,
|
|
501
|
+
hold: Option<&str>,
|
|
502
|
+
) -> Result<Extended> {
|
|
503
|
+
if bytes.len() > limits::DOC_MAX_BYTES {
|
|
504
|
+
return refuse(
|
|
505
|
+
Code::COUNT_CAP,
|
|
506
|
+
"checkpoint progress exceeds the document byte cap",
|
|
507
|
+
);
|
|
508
|
+
}
|
|
459
509
|
let progress = store
|
|
460
510
|
.put_stream_held(
|
|
461
511
|
&mut &*bytes,
|
|
@@ -486,24 +536,9 @@ pub(crate) fn checkpoint_bytes(
|
|
|
486
536
|
}
|
|
487
537
|
objects.push(progress.clone());
|
|
488
538
|
objects = canonical_refs(objects);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
.collect();
|
|
493
|
-
objects.retain(|object| !held.contains(object.sha256.as_str()));
|
|
494
|
-
let mut head = Head {
|
|
495
|
-
head: previous.cloned(),
|
|
496
|
-
links: prior.as_ref().map_or(0, |set| set.links),
|
|
497
|
-
bytes: prior.as_ref().map_or(0, |set| set.bytes),
|
|
498
|
-
};
|
|
499
|
-
let mut roots = previous
|
|
500
|
-
.map(|head| local_documents(store, head))
|
|
501
|
-
.transpose()?
|
|
502
|
-
.unwrap_or_default();
|
|
503
|
-
roots.push(progress.clone());
|
|
504
|
-
if objects.is_empty() {
|
|
505
|
-
return Ok(CheckpointExport { head, roots });
|
|
506
|
-
}
|
|
539
|
+
objects.retain(|object| !tip.held.contains(&object.sha256));
|
|
540
|
+
let mut head = tip.head.clone();
|
|
541
|
+
let mut links = Vec::new();
|
|
507
542
|
let pages = objects.chunks(CHECKPOINT_REFS);
|
|
508
543
|
let page_count = pages.len();
|
|
509
544
|
for (index, page) in pages.enumerate() {
|
|
@@ -540,11 +575,16 @@ pub(crate) fn checkpoint_bytes(
|
|
|
540
575
|
hold,
|
|
541
576
|
)?
|
|
542
577
|
.obj;
|
|
543
|
-
|
|
578
|
+
links.push(object.clone());
|
|
544
579
|
head.head = Some(object);
|
|
545
580
|
head.links += 1;
|
|
546
581
|
}
|
|
547
|
-
Ok(
|
|
582
|
+
Ok(Extended {
|
|
583
|
+
head,
|
|
584
|
+
progress,
|
|
585
|
+
named: objects,
|
|
586
|
+
links,
|
|
587
|
+
})
|
|
548
588
|
}
|
|
549
589
|
|
|
550
590
|
/// Pin restored chain documents before their journal is installed. Tensor segments are
|
|
@@ -131,6 +131,17 @@ impl Meta {
|
|
|
131
131
|
crate::derived::open_row(&mut rows, id, writer_session).map(|_| ())
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
pub(crate) fn part_count(&self, id: &str) -> Result<usize> {
|
|
135
|
+
self.connection()?
|
|
136
|
+
.query_row(
|
|
137
|
+
"SELECT count(*) FROM tensorfs_derived_parts WHERE id=?1",
|
|
138
|
+
[id],
|
|
139
|
+
|row| row.get::<_, i64>(0),
|
|
140
|
+
)
|
|
141
|
+
.map(|count| count as usize)
|
|
142
|
+
.map_err(|error| sql("count derived parts", error))
|
|
143
|
+
}
|
|
144
|
+
|
|
134
145
|
/// Record one accepted part for the current writer: one indexed read of the writer's
|
|
135
146
|
/// session and of that part. `Ok(false)` is the same part accepted before.
|
|
136
147
|
pub(crate) fn accept_part(
|
|
@@ -2221,6 +2221,7 @@ impl PyStore {
|
|
|
2221
2221
|
writer_session_id,
|
|
2222
2222
|
source_views: begin.source_views,
|
|
2223
2223
|
additions: begin.additions,
|
|
2224
|
+
cursor: Mutex::new(None),
|
|
2224
2225
|
guards: Mutex::new(Some(DerivedGuards {
|
|
2225
2226
|
writer_hold: begin.writer_hold,
|
|
2226
2227
|
source_leases: begin.source_leases,
|
|
@@ -2510,6 +2511,7 @@ pub struct PyDerivedWriter {
|
|
|
2510
2511
|
writer_session_id: u64,
|
|
2511
2512
|
source_views: Vec<derived::SourceView>,
|
|
2512
2513
|
additions: derived::Additions,
|
|
2514
|
+
cursor: Mutex<Option<derived::CheckpointCursor>>,
|
|
2513
2515
|
guards: Mutex<Option<DerivedGuards>>,
|
|
2514
2516
|
}
|
|
2515
2517
|
|
|
@@ -2613,7 +2615,7 @@ impl PyDerivedWriter {
|
|
|
2613
2615
|
.transpose()?;
|
|
2614
2616
|
let (plan, head) = py
|
|
2615
2617
|
.detach(|| {
|
|
2616
|
-
derived::
|
|
2618
|
+
derived::checkpoint_indexed(
|
|
2617
2619
|
&self.store,
|
|
2618
2620
|
&self.meta,
|
|
2619
2621
|
&self.transaction_id,
|
|
@@ -2621,6 +2623,7 @@ impl PyDerivedWriter {
|
|
|
2621
2623
|
operation_id,
|
|
2622
2624
|
slot,
|
|
2623
2625
|
previous.as_ref(),
|
|
2626
|
+
&mut self.cursor.lock().unwrap(),
|
|
2624
2627
|
)
|
|
2625
2628
|
})
|
|
2626
2629
|
.or_refuse(py)?;
|
|
@@ -2745,6 +2748,7 @@ impl PyDerivedWriter {
|
|
|
2745
2748
|
&self.transaction_id,
|
|
2746
2749
|
self.writer_session_id,
|
|
2747
2750
|
&self.additions,
|
|
2751
|
+
self.cursor.lock().unwrap().as_mut(),
|
|
2748
2752
|
(component, key, role),
|
|
2749
2753
|
&mut source,
|
|
2750
2754
|
)
|
|
@@ -2779,6 +2783,8 @@ impl PyDerivedWriter {
|
|
|
2779
2783
|
err: None,
|
|
2780
2784
|
};
|
|
2781
2785
|
let result = py.detach(|| {
|
|
2786
|
+
// A config is not a part: the next checkpoint takes the full path.
|
|
2787
|
+
*self.cursor.lock().unwrap() = None;
|
|
2782
2788
|
derived::add_config(
|
|
2783
2789
|
&self.meta,
|
|
2784
2790
|
&self.transaction_id,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.64 → tensorfs-0.3.65}/crates/tensorfs-core/examples/optional-cache-backfill.md
RENAMED
|
File without changes
|