nx_mvault_layout.nx source
↩ module page · 65 lines · 2794 B
1// nx_mvault_layout.nx -- DSM-native on-disk layout for vault blobs.
2//
3// GOAL (operator 2026-07-17): "structured on disk ... so it works with the
4// synology dsm os but still has all of our capabilities so i dont have a
5// million folders and files."
6//
7// LAYOUT: <root>/<class>/<type>/<shard>/<cid16>_<source>.<ext>
8// class = gen | real (the two major sections)
9// type = image|gif|video|audio|story|page|manga|model3d|audiobook
10// shard = 2 hex chars of the CID (<=256 dirs per type)
11// file = <cid16>_<source>.<ext> (real ext => DSM Photos/Video
12// index it; CID + source VISIBLE in File Station)
13//
14// FAN-OUT BOUND: classes(2) x types(<=10) x shards(256) = <=5120 leaf dirs,
15// NEVER per-item folders. Metadata does NOT live in per-item sidecars -- it
16// lives in the seg-store (nx_mvault_record), a few segment files. So on-disk
17// file count ~= media count, folder count ~= 5120. No million-folders trap.
18//
19// SELF-DESCRIBING: class/type/source/cid are all recoverable from the path
20// alone, so DSM-side browsing works even without the seg-store; the seg-store
21// is the rich classified+searchable index over the same blobs (ref = path).
22//
23// Composes nx_mvault_ingest (mv_class_str / mv_type_str). license_tier: ORIGINAL
24
25import "nx_syscalls.nx"
26import "nx_mvault_ingest.nx"
27
28func dp_cat(dst: *u8, off: i64, s: *u8) -> i64 {
29 var i: i64 = 0
30 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
31 return off + i
32}
33
34func dp_ch(dst: *u8, off: i64, ch: i64) -> i64 {
35 dst[off] = ch as u8
36 return off + 1
37}
38
39// Build the DSM on-disk path for an item into `out` (NUL-terminated); ret len.
40// cid is the "nxc1-<64hex>" string; shard + stem come from its hex prefix.
41func mv_disk_path(out: *u8, root: *u8, class_code: i64, type_code: i64,
42 cid: *u8, source: *u8, ext: *u8) -> i64 {
43 let cs: *u8 = mv_class_str(class_code)
44 let ts: *u8 = mv_type_str(type_code)
45 var o: i64 = 0
46 o = dp_cat(out, o, root) // /volume1/vault
47 o = dp_ch(out, o, 47) // /
48 o = dp_cat(out, o, cs) // gen | real
49 o = dp_ch(out, o, 47)
50 o = dp_cat(out, o, ts) // image | video | ...
51 o = dp_ch(out, o, 47)
52 // shard = first 2 hex chars after the "nxc1-" prefix (cid[5], cid[6])
53 out[o] = cid[5]; o = o + 1
54 out[o] = cid[6]; o = o + 1
55 o = dp_ch(out, o, 47)
56 // filename stem = 16 hex chars of the CID hash (unique enough; short)
57 var k: i64 = 0
58 while k < 16 { out[o] = cid[5 + k]; o = o + 1; k = k + 1 }
59 o = dp_ch(out, o, 95) // _
60 o = dp_cat(out, o, source) // tumblr
61 o = dp_ch(out, o, 46) // .
62 o = dp_cat(out, o, ext) // mp4
63 out[o] = 0 as u8
64 return o
65}