tensorfs 0.3.9__tar.gz → 0.3.10__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.
Potentially problematic release.
This version of tensorfs might be problematic. Click here for more details.
- {tensorfs-0.3.9 → tensorfs-0.3.10}/Cargo.lock +2 -2
- {tensorfs-0.3.9 → tensorfs-0.3.10}/Cargo.toml +1 -1
- {tensorfs-0.3.9 → tensorfs-0.3.10}/PKG-INFO +1 -1
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/derived.rs +273 -11
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/gc.rs +26 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/meta.rs +1 -14
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/storage.rs +1 -1
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-py/src/store.rs +6 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/pyproject.toml +1 -1
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/Cargo.toml +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/b64.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/fetch.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/ingest.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/main.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/rd.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/canon.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/capability.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/catalog.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/cbor.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/checkpoint.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/corpus.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/derived/roots.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/dtype.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/durability.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/err.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/fetch.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/fill.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/fit.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/header.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/home.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ids.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/convert.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/fingerprint.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/journal.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/mod.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/preflight.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/source.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/ingest/transaction.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/jcs.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/lib.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/limits.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/machine.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/manifest.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/project.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/providers.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/read.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/receipt.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/reclaim.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/registry.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/relation.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/repo_cache.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/repository.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/sha256.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/spec.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/staging.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/store.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/api.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/http.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/hub.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/ledger.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/mod.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/policy.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/pull.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/push.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/ranged.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/transport/tests.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/src/vectors.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fetch_url_progress.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fit.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/home.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/liveness.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/reclaim.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/reclaim_run.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/repo_cache.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/repo_store.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/sha256_backends.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/sharded_cas.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/source_plan.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/source_preflight.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/staging.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/store_boundaries.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/tensor_schema.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/version.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/write_through.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-py/Cargo.toml +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-py/src/docs.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-py/src/errors.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-py/src/lib.rs +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/python/tensorfs/__init__.py +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/python/tensorfs/_ext.pyi +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/python/tensorfs/errors.py +0 -0
- {tensorfs-0.3.9 → tensorfs-0.3.10}/python/tensorfs/py.typed +0 -0
|
@@ -392,7 +392,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
392
392
|
|
|
393
393
|
[[package]]
|
|
394
394
|
name = "tensorfs-core"
|
|
395
|
-
version = "0.3.
|
|
395
|
+
version = "0.3.10"
|
|
396
396
|
dependencies = [
|
|
397
397
|
"fs2",
|
|
398
398
|
"minicbor",
|
|
@@ -404,7 +404,7 @@ dependencies = [
|
|
|
404
404
|
|
|
405
405
|
[[package]]
|
|
406
406
|
name = "tensorfs-py"
|
|
407
|
-
version = "0.3.
|
|
407
|
+
version = "0.3.10"
|
|
408
408
|
dependencies = [
|
|
409
409
|
"pyo3",
|
|
410
410
|
"tensorfs-core",
|
|
@@ -1338,22 +1338,28 @@ fn require_payload_record(store: &Store, object: &ObjectRef, what: &str) -> Resu
|
|
|
1338
1338
|
}
|
|
1339
1339
|
}
|
|
1340
1340
|
|
|
1341
|
-
fn
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
let mut out = Vec::new();
|
|
1341
|
+
fn require_source_roots(store: &Store, declaration: &Declaration) -> Result<()> {
|
|
1342
|
+
if declaration.sources.is_empty() {
|
|
1343
|
+
return Ok(());
|
|
1344
|
+
}
|
|
1345
|
+
let retained = crate::gc::retained_manifests(store)?;
|
|
1347
1346
|
for declared in &declaration.sources {
|
|
1348
|
-
if !
|
|
1347
|
+
if !retained.contains(&declared.manifest) {
|
|
1349
1348
|
return refuse(
|
|
1350
1349
|
Code::ROOT_ABSENT,
|
|
1351
1350
|
format!(
|
|
1352
|
-
"source {}
|
|
1351
|
+
"source {} has no exact retained filesystem root",
|
|
1353
1352
|
declared.manifest.id()
|
|
1354
1353
|
),
|
|
1355
1354
|
);
|
|
1356
1355
|
}
|
|
1356
|
+
}
|
|
1357
|
+
Ok(())
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
fn load_sources(store: &Store, declaration: &Declaration) -> Result<Vec<SourceData>> {
|
|
1361
|
+
let mut out = Vec::new();
|
|
1362
|
+
for declared in &declaration.sources {
|
|
1357
1363
|
let manifest = checkpoint::load_manifest(store, &declared.manifest)?;
|
|
1358
1364
|
if manifest.manifest_id() != declared.manifest.id() {
|
|
1359
1365
|
return refuse(
|
|
@@ -1791,6 +1797,18 @@ pub fn inspect_source(
|
|
|
1791
1797
|
manifest: ObjectRef,
|
|
1792
1798
|
component_names: Vec<String>,
|
|
1793
1799
|
config_names: Vec<String>,
|
|
1800
|
+
) -> Result<SourceInspection> {
|
|
1801
|
+
let hold = meta.acquire_hold("derived-source-inspect")?;
|
|
1802
|
+
let result = inspect_retained_source(store, manifest, component_names, config_names);
|
|
1803
|
+
let released = hold.release(meta);
|
|
1804
|
+
result.and_then(|inspection| released.map(|()| inspection))
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
fn inspect_retained_source(
|
|
1808
|
+
store: &Store,
|
|
1809
|
+
manifest: ObjectRef,
|
|
1810
|
+
component_names: Vec<String>,
|
|
1811
|
+
config_names: Vec<String>,
|
|
1794
1812
|
) -> Result<SourceInspection> {
|
|
1795
1813
|
let alias = "source".to_string();
|
|
1796
1814
|
let mut declaration = Declaration {
|
|
@@ -1820,7 +1838,8 @@ pub fn inspect_source(
|
|
|
1820
1838
|
max_new_bytes: 0,
|
|
1821
1839
|
};
|
|
1822
1840
|
declaration.normalize_and_validate()?;
|
|
1823
|
-
|
|
1841
|
+
require_source_roots(store, &declaration)?;
|
|
1842
|
+
let mut sources = load_sources(store, &declaration)?;
|
|
1824
1843
|
let source = sources.pop().ok_or_else(|| Refusal {
|
|
1825
1844
|
code: Code::ROOT_ABSENT,
|
|
1826
1845
|
detail: "source inspection resolved no source".into(),
|
|
@@ -1882,7 +1901,9 @@ pub fn begin(
|
|
|
1882
1901
|
// The writer hold is registered before source metadata is touched. It is the live
|
|
1883
1902
|
// process proof that keeps exclusive GC out even for a source-free create.
|
|
1884
1903
|
let writer_hold = meta.acquire_hold("derived-writer")?;
|
|
1885
|
-
let sources = match
|
|
1904
|
+
let sources = match require_source_roots(store, &declaration)
|
|
1905
|
+
.and_then(|()| load_sources(store, &declaration))
|
|
1906
|
+
{
|
|
1886
1907
|
Ok(sources) => sources,
|
|
1887
1908
|
Err(error) => {
|
|
1888
1909
|
release_guards(meta, Some(writer_hold), Vec::new());
|
|
@@ -2330,6 +2351,9 @@ fn receipt_from(_store: &Store, row: &TransactionRow) -> Result<ReceiptFacts> {
|
|
|
2330
2351
|
})
|
|
2331
2352
|
}
|
|
2332
2353
|
|
|
2354
|
+
/// The caller retains Begin's writer hold and source leases through this call.
|
|
2355
|
+
/// Root membership was admitted at begin; the live hold now protects those exact
|
|
2356
|
+
/// bytes even if their original repository/session/private root is released.
|
|
2333
2357
|
pub fn commit(
|
|
2334
2358
|
store: &Store,
|
|
2335
2359
|
meta: &Meta,
|
|
@@ -2342,7 +2366,7 @@ pub fn commit(
|
|
|
2342
2366
|
open_row(&mut txn.rows, &transaction, writer_session)?.clone()
|
|
2343
2367
|
};
|
|
2344
2368
|
let declaration = declaration(&row_before)?;
|
|
2345
|
-
let sources =
|
|
2369
|
+
let sources = load_sources(store, &declaration)?;
|
|
2346
2370
|
let (header, closure, registry_adoptions) = build_header(
|
|
2347
2371
|
&declaration,
|
|
2348
2372
|
&sources,
|
|
@@ -2700,6 +2724,235 @@ mod tests {
|
|
|
2700
2724
|
}
|
|
2701
2725
|
}
|
|
2702
2726
|
|
|
2727
|
+
fn inherited_declaration(manifest: ObjectRef) -> Declaration {
|
|
2728
|
+
Declaration {
|
|
2729
|
+
sources: vec![Source {
|
|
2730
|
+
alias: "source".into(),
|
|
2731
|
+
manifest,
|
|
2732
|
+
}],
|
|
2733
|
+
components: vec![ComponentDeclaration {
|
|
2734
|
+
target: "inherited".into(),
|
|
2735
|
+
source: Some("source".into()),
|
|
2736
|
+
source_component: Some("model".into()),
|
|
2737
|
+
drop: Vec::new(),
|
|
2738
|
+
add: Vec::new(),
|
|
2739
|
+
}],
|
|
2740
|
+
configs: Vec::new(),
|
|
2741
|
+
order: vec![("inherited".into(), "weight".into())],
|
|
2742
|
+
max_new_bytes: 0,
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
#[test]
|
|
2747
|
+
fn retained_source_admission_and_writer_hold_share_the_gc_roots() {
|
|
2748
|
+
let root = std::env::temp_dir().join(format!(
|
|
2749
|
+
"tensorfs-retained-source-{}",
|
|
2750
|
+
crate::meta::now_nanos_unique()
|
|
2751
|
+
));
|
|
2752
|
+
let store = Store::init(&root).unwrap();
|
|
2753
|
+
let meta = Meta::open(&store).unwrap();
|
|
2754
|
+
let source_id = format!("sha256:{}", "81".repeat(32));
|
|
2755
|
+
let source_writer = begin(&store, &meta, &source_id, 1, created_declaration()).unwrap();
|
|
2756
|
+
let bytes = vec![0x21; 2048];
|
|
2757
|
+
add_part(
|
|
2758
|
+
&store,
|
|
2759
|
+
&meta,
|
|
2760
|
+
&source_id,
|
|
2761
|
+
1,
|
|
2762
|
+
("model", "weight", "value"),
|
|
2763
|
+
&mut bytes.as_slice(),
|
|
2764
|
+
)
|
|
2765
|
+
.unwrap();
|
|
2766
|
+
let source = commit(&store, &meta, &source_id, 1).unwrap();
|
|
2767
|
+
release_guards(
|
|
2768
|
+
&meta,
|
|
2769
|
+
Some(source_writer.writer_hold),
|
|
2770
|
+
source_writer.source_leases,
|
|
2771
|
+
);
|
|
2772
|
+
let preview = || {
|
|
2773
|
+
inspect_source(
|
|
2774
|
+
&store,
|
|
2775
|
+
&meta,
|
|
2776
|
+
source.manifest.clone(),
|
|
2777
|
+
vec!["model".into()],
|
|
2778
|
+
Vec::new(),
|
|
2779
|
+
)
|
|
2780
|
+
};
|
|
2781
|
+
|
|
2782
|
+
// Committed pending output and owner-adopted output have real filesystem roots.
|
|
2783
|
+
preview().unwrap();
|
|
2784
|
+
adopt(&store, &meta, &source_id, "source-private").unwrap();
|
|
2785
|
+
preview().unwrap();
|
|
2786
|
+
dispose(&store, &meta, &source_id).unwrap();
|
|
2787
|
+
assert_eq!(preview().unwrap_err().code, Code::ROOT_ABSENT);
|
|
2788
|
+
let target_id = format!("sha256:{}", "82".repeat(32));
|
|
2789
|
+
assert_eq!(
|
|
2790
|
+
begin(
|
|
2791
|
+
&store,
|
|
2792
|
+
&meta,
|
|
2793
|
+
&target_id,
|
|
2794
|
+
1,
|
|
2795
|
+
inherited_declaration(source.manifest.clone())
|
|
2796
|
+
)
|
|
2797
|
+
.err()
|
|
2798
|
+
.unwrap()
|
|
2799
|
+
.code,
|
|
2800
|
+
Code::ROOT_ABSENT
|
|
2801
|
+
);
|
|
2802
|
+
assert!(matches!(
|
|
2803
|
+
lookup(&store, &meta, &target_id).unwrap(),
|
|
2804
|
+
Lookup::Absent
|
|
2805
|
+
));
|
|
2806
|
+
|
|
2807
|
+
// The coordinator's actual prepared-source lifecycle names a private candidate.
|
|
2808
|
+
let operation = "prepared-source";
|
|
2809
|
+
let request_digest = format!("sha256:{}", "83".repeat(32));
|
|
2810
|
+
let catalog = crate::catalog::Catalog::open(&root).unwrap();
|
|
2811
|
+
let crate::catalog::SourcePreparation::Open(source_guard) = catalog
|
|
2812
|
+
.begin_source_preparation(operation, &request_digest)
|
|
2813
|
+
.unwrap()
|
|
2814
|
+
else {
|
|
2815
|
+
panic!("source operation already prepared")
|
|
2816
|
+
};
|
|
2817
|
+
crate::ingest::transaction::ensure_session_root(&root, operation, "_tensorfs").unwrap();
|
|
2818
|
+
crate::ingest::transaction::name_candidates(
|
|
2819
|
+
&root,
|
|
2820
|
+
operation,
|
|
2821
|
+
std::slice::from_ref(&source.manifest),
|
|
2822
|
+
)
|
|
2823
|
+
.unwrap();
|
|
2824
|
+
// An actual candidate is retained even before the rebuildable result row is written.
|
|
2825
|
+
preview().unwrap();
|
|
2826
|
+
catalog
|
|
2827
|
+
.commit_source_preparation(
|
|
2828
|
+
operation,
|
|
2829
|
+
&request_digest,
|
|
2830
|
+
&[crate::catalog::SourcePreparationResult {
|
|
2831
|
+
slot: "source".into(),
|
|
2832
|
+
profile: "proof".into(),
|
|
2833
|
+
manifest_sha256: source.manifest.sha256.clone(),
|
|
2834
|
+
manifest_length: source.manifest.length,
|
|
2835
|
+
}],
|
|
2836
|
+
)
|
|
2837
|
+
.unwrap();
|
|
2838
|
+
drop(source_guard);
|
|
2839
|
+
crate::gc::collect(&root, false).unwrap();
|
|
2840
|
+
preview().unwrap();
|
|
2841
|
+
let mut wrong = inherited_declaration(source.manifest.clone());
|
|
2842
|
+
wrong.sources[0].manifest.length += 1;
|
|
2843
|
+
assert_eq!(
|
|
2844
|
+
begin(&store, &meta, &target_id, 1, wrong)
|
|
2845
|
+
.err()
|
|
2846
|
+
.unwrap()
|
|
2847
|
+
.code,
|
|
2848
|
+
Code::ROOT_ABSENT
|
|
2849
|
+
);
|
|
2850
|
+
|
|
2851
|
+
let writer = begin(
|
|
2852
|
+
&store,
|
|
2853
|
+
&meta,
|
|
2854
|
+
&target_id,
|
|
2855
|
+
1,
|
|
2856
|
+
inherited_declaration(source.manifest.clone()),
|
|
2857
|
+
)
|
|
2858
|
+
.unwrap();
|
|
2859
|
+
crate::ingest::source::release_model_source(&store, operation).unwrap();
|
|
2860
|
+
assert_eq!(preview().unwrap_err().code, Code::ROOT_ABSENT);
|
|
2861
|
+
writer.writer_hold.still_registered(&meta).unwrap();
|
|
2862
|
+
assert_eq!(
|
|
2863
|
+
crate::gc::collect(&root, false).unwrap_err().code,
|
|
2864
|
+
Code::STORE_BUSY
|
|
2865
|
+
);
|
|
2866
|
+
let inherited = commit(&store, &meta, &target_id, 1).unwrap();
|
|
2867
|
+
assert_eq!(inherited.inherited_payload_bytes, 2048);
|
|
2868
|
+
assert!(inherited.added_objects.is_empty());
|
|
2869
|
+
release_guards(&meta, Some(writer.writer_hold), writer.source_leases);
|
|
2870
|
+
crate::gc::collect(&root, false).unwrap();
|
|
2871
|
+
store.read_manifest(&inherited.manifest).unwrap();
|
|
2872
|
+
inspect_source(
|
|
2873
|
+
&store,
|
|
2874
|
+
&meta,
|
|
2875
|
+
inherited.manifest.clone(),
|
|
2876
|
+
vec!["inherited".into()],
|
|
2877
|
+
Vec::new(),
|
|
2878
|
+
)
|
|
2879
|
+
.unwrap();
|
|
2880
|
+
dispose(&store, &meta, &target_id).unwrap();
|
|
2881
|
+
assert_eq!(
|
|
2882
|
+
inspect_source(
|
|
2883
|
+
&store,
|
|
2884
|
+
&meta,
|
|
2885
|
+
inherited.manifest,
|
|
2886
|
+
vec!["inherited".into()],
|
|
2887
|
+
Vec::new()
|
|
2888
|
+
)
|
|
2889
|
+
.unwrap_err()
|
|
2890
|
+
.code,
|
|
2891
|
+
Code::ROOT_ABSENT
|
|
2892
|
+
);
|
|
2893
|
+
let _ = std::fs::remove_dir_all(root);
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
#[test]
|
|
2897
|
+
fn retained_source_still_refuses_corrupt_payload_and_abandoned_writer() {
|
|
2898
|
+
let root = std::env::temp_dir().join(format!(
|
|
2899
|
+
"tensorfs-retained-source-refusal-{}",
|
|
2900
|
+
crate::meta::now_nanos_unique()
|
|
2901
|
+
));
|
|
2902
|
+
let store = Store::init(&root).unwrap();
|
|
2903
|
+
let meta = Meta::open(&store).unwrap();
|
|
2904
|
+
let source_id = format!("sha256:{}", "84".repeat(32));
|
|
2905
|
+
let source_writer = begin(&store, &meta, &source_id, 1, created_declaration()).unwrap();
|
|
2906
|
+
let bytes = vec![0x31; 2048];
|
|
2907
|
+
let part = add_part(
|
|
2908
|
+
&store,
|
|
2909
|
+
&meta,
|
|
2910
|
+
&source_id,
|
|
2911
|
+
1,
|
|
2912
|
+
("model", "weight", "value"),
|
|
2913
|
+
&mut bytes.as_slice(),
|
|
2914
|
+
)
|
|
2915
|
+
.unwrap();
|
|
2916
|
+
let source = commit(&store, &meta, &source_id, 1).unwrap();
|
|
2917
|
+
release_guards(
|
|
2918
|
+
&meta,
|
|
2919
|
+
Some(source_writer.writer_hold),
|
|
2920
|
+
source_writer.source_leases,
|
|
2921
|
+
);
|
|
2922
|
+
let target_id = format!("sha256:{}", "85".repeat(32));
|
|
2923
|
+
let writer = begin(
|
|
2924
|
+
&store,
|
|
2925
|
+
&meta,
|
|
2926
|
+
&target_id,
|
|
2927
|
+
1,
|
|
2928
|
+
inherited_declaration(source.manifest.clone()),
|
|
2929
|
+
)
|
|
2930
|
+
.unwrap();
|
|
2931
|
+
assert!(fence(&meta, &target_id, 1).unwrap());
|
|
2932
|
+
abandon(&store, &meta, &target_id).unwrap();
|
|
2933
|
+
assert_eq!(
|
|
2934
|
+
commit(&store, &meta, &target_id, 1).unwrap_err().code,
|
|
2935
|
+
Code::TRANSACTION_CLOSED
|
|
2936
|
+
);
|
|
2937
|
+
release_guards(&meta, Some(writer.writer_hold), writer.source_leases);
|
|
2938
|
+
let path = store.blob_path(&part.part.segments()[0].sha256);
|
|
2939
|
+
std::fs::remove_file(&path).unwrap();
|
|
2940
|
+
std::fs::write(path, vec![0x32; 2048]).unwrap();
|
|
2941
|
+
assert_eq!(
|
|
2942
|
+
inspect_source(
|
|
2943
|
+
&store,
|
|
2944
|
+
&meta,
|
|
2945
|
+
source.manifest,
|
|
2946
|
+
vec!["model".into()],
|
|
2947
|
+
Vec::new()
|
|
2948
|
+
)
|
|
2949
|
+
.unwrap_err()
|
|
2950
|
+
.code,
|
|
2951
|
+
Code::OBJECT_CORRUPT
|
|
2952
|
+
);
|
|
2953
|
+
let _ = std::fs::remove_dir_all(root);
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2703
2956
|
#[test]
|
|
2704
2957
|
fn private_adoption_retains_real_payload_until_dispose_without_a_repository() {
|
|
2705
2958
|
let root = std::env::temp_dir().join(format!(
|
|
@@ -2946,6 +3199,15 @@ mod tests {
|
|
|
2946
3199
|
)
|
|
2947
3200
|
.unwrap()
|
|
2948
3201
|
.unwrap();
|
|
3202
|
+
// An owner-retained checkpoint is a GC root before any public release exists.
|
|
3203
|
+
inspect_source(
|
|
3204
|
+
&store,
|
|
3205
|
+
&meta,
|
|
3206
|
+
manifest_ref.clone(),
|
|
3207
|
+
vec!["model".into()],
|
|
3208
|
+
Vec::new(),
|
|
3209
|
+
)
|
|
3210
|
+
.unwrap();
|
|
2949
3211
|
store
|
|
2950
3212
|
.apply_repository(
|
|
2951
3213
|
Some(&checkpointed.canonical_bytes()),
|
|
@@ -154,6 +154,32 @@ pub fn session_holds(store: &Store) -> Result<(Vec<HeldKey>, Vec<String>)> {
|
|
|
154
154
|
Ok((holds, sessions))
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/// The same exact manifest roots used by reclamation, without a payload census.
|
|
158
|
+
/// Membership is retention, not caller authorization. A consumer must acquire its
|
|
159
|
+
/// live hold before checking roots so GC cannot remove bytes during admission.
|
|
160
|
+
pub(crate) fn retained_manifests(store: &Store) -> Result<Vec<crate::ids::ObjectRef>> {
|
|
161
|
+
let mut roots = Vec::new();
|
|
162
|
+
for (repository, _) in storage::read_repositories(store.root())? {
|
|
163
|
+
roots.extend(
|
|
164
|
+
repository
|
|
165
|
+
.checkpoints
|
|
166
|
+
.into_iter()
|
|
167
|
+
.map(|checkpoint| checkpoint.manifest),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
let (holds, _) = session_holds(store)?;
|
|
171
|
+
roots.extend(
|
|
172
|
+
holds
|
|
173
|
+
.into_iter()
|
|
174
|
+
.filter(|hold| hold.kind == "manifest")
|
|
175
|
+
.map(|hold| crate::ids::ObjectRef {
|
|
176
|
+
sha256: hold.sha256,
|
|
177
|
+
length: hold.length,
|
|
178
|
+
}),
|
|
179
|
+
);
|
|
180
|
+
Ok(roots)
|
|
181
|
+
}
|
|
182
|
+
|
|
157
183
|
/// One complete pass: exclusivity, orphan temps, census, plan, delete, catalog repair.
|
|
158
184
|
pub fn collect(root: &Path, dry_run: bool) -> Result<Report> {
|
|
159
185
|
let store = Store::open(root)?;
|
|
@@ -11,7 +11,7 @@ use fs2::FileExt;
|
|
|
11
11
|
use rusqlite::{params, Connection};
|
|
12
12
|
|
|
13
13
|
use crate::err::{refuse, Code, Refusal, Result};
|
|
14
|
-
use crate::ids::
|
|
14
|
+
use crate::ids::ascii_name;
|
|
15
15
|
use crate::limits;
|
|
16
16
|
use crate::store::Store;
|
|
17
17
|
|
|
@@ -82,19 +82,6 @@ impl Meta {
|
|
|
82
82
|
self.lease_dir.join(format!("{id}.lease"))
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
pub fn manifest_is_released(&self, digest: &str) -> Result<bool> {
|
|
86
|
-
hex64("manifest", digest)?;
|
|
87
|
-
let count: u64 = self
|
|
88
|
-
.connection()?
|
|
89
|
-
.query_row(
|
|
90
|
-
"SELECT count(*) FROM tensorfs_released_manifests WHERE manifest_sha256=?1",
|
|
91
|
-
[digest],
|
|
92
|
-
|row| row.get(0),
|
|
93
|
-
)
|
|
94
|
-
.map_err(|error| sql("query released manifest", error))?;
|
|
95
|
-
Ok(count != 0)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
85
|
pub(crate) fn txn(&self) -> Result<Txn> {
|
|
99
86
|
let connection = self.connection()?;
|
|
100
87
|
connection
|
|
@@ -1223,7 +1223,7 @@ impl GcDelete {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
}
|
|
1225
1225
|
|
|
1226
|
-
fn read_repositories(root: &Path) -> Result<Vec<(Repository, Vec<u8>)>> {
|
|
1226
|
+
pub(crate) fn read_repositories(root: &Path) -> Result<Vec<(Repository, Vec<u8>)>> {
|
|
1227
1227
|
let mut result = Vec::new();
|
|
1228
1228
|
for org_path in read_dir(&root.join("repos"))? {
|
|
1229
1229
|
if !org_path.is_dir() {
|
|
@@ -1892,6 +1892,12 @@ impl PyDerivedWriter {
|
|
|
1892
1892
|
fn commit<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>> {
|
|
1893
1893
|
let value = py
|
|
1894
1894
|
.detach(|| {
|
|
1895
|
+
let guards = self.guards.lock().expect("writer hold mutex poisoned");
|
|
1896
|
+
let guards = guards.as_ref().ok_or_else(|| Refusal {
|
|
1897
|
+
code: Code::LEASE_REVOKED,
|
|
1898
|
+
detail: "derived writer holds were released".into(),
|
|
1899
|
+
})?;
|
|
1900
|
+
guards.writer_hold.still_registered(&self.meta)?;
|
|
1895
1901
|
derived::commit(
|
|
1896
1902
|
&self.store,
|
|
1897
1903
|
&self.meta,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor
RENAMED
|
File without changes
|
{tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json
RENAMED
|
File without changes
|
{tensorfs-0.3.9 → tensorfs-0.3.10}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|