Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
16cf8e4
wip: blob 1
matthew-levan Mar 28, 2026
965aced
wip: blob 2
matthew-levan Mar 30, 2026
9657a77
wip: blob 3
matthew-levan Mar 31, 2026
89f6d15
wip: blob 4
matthew-levan Apr 2, 2026
87155ca
wip: blob 5
matthew-levan Apr 2, 2026
7d6cbf0
wip: blob 6
matthew-levan Apr 2, 2026
a2f950a
Merge branch 'ml/64' into ml/bob
matthew-levan Apr 13, 2026
53b30f5
wip: blob 7
matthew-levan Apr 14, 2026
2137f0d
wip: blob 8
matthew-levan Apr 14, 2026
77c91e0
wip: blob 9
matthew-levan Apr 14, 2026
f6f1cef
wip: blob 10
matthew-levan Apr 14, 2026
b8c2669
wip: blob 11
matthew-levan Apr 15, 2026
816d058
wip: blob 12
matthew-levan Apr 15, 2026
cf3d58d
wip: blob 13
matthew-levan Apr 15, 2026
e00de89
wip: blob 14
matthew-levan Apr 15, 2026
8a2cb3e
wip: fixed blob gc
matthew-levan Apr 16, 2026
9a7b409
noun: adds `jam_shax` jet
matthew-levan Apr 23, 2026
4b3b6d2
wip: blob refcounting redesign 1
matthew-levan Apr 23, 2026
41b2c8b
wip: blob refcounting redesign 2
matthew-levan Apr 27, 2026
afe7320
wip: blob refcounting redesign 3
matthew-levan Apr 27, 2026
bfe12ee
wip: blob refcounting redesign 4
matthew-levan Apr 27, 2026
6a284b2
Merge branch 'ml/64' into ml/bob
matthew-levan Apr 27, 2026
0888234
wip: refactors blob ids
matthew-levan Apr 28, 2026
0a90694
wip: ensures interned atom is correct post-canonicalization
matthew-levan Apr 28, 2026
9fb40a7
Merge branch 'ml/64' into ml/bob
matthew-levan Apr 28, 2026
c4c23e6
wip: use atom blob ids and cells for blobref count metadata in `blb_p`
matthew-levan Apr 29, 2026
5799d2a
wip: blob gc working in both 32 and 64 bit modes
matthew-levan Apr 29, 2026
36ee292
wip: cleanup and comment
matthew-levan Apr 30, 2026
da41817
wip: cleans up includes
matthew-levan Apr 30, 2026
074e156
wip: fixes blobs for windows
matthew-levan May 1, 2026
c3bd045
wip: fixes serial tests for 32-bit mode
matthew-levan May 1, 2026
f425672
blob: returns `u3a_blob` metadata struct
matthew-levan May 6, 2026
4903f96
Merge branch 'ml/64' into ml/bob
matthew-levan May 6, 2026
d45c1df
wip: catches old cell-based blob refcounting
matthew-levan May 7, 2026
3a426cd
wip: blob refcounting + `u3a_atom.len_w` stores `u3a_blob*`
matthew-levan May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,11 @@ fn buildBinary(
.file = "pkg/vere/newt_tests.c",
.deps = vere_test_deps,
},
.{
.name = "blob-test",
.file = "pkg/vere/blob_tests.c",
.deps = vere_test_deps,
},
.{
.name = "vere-noun-test",
.file = "pkg/vere/noun_tests.c",
Expand Down
12 changes: 12 additions & 0 deletions pkg/c3/platform/windows/mman.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,16 @@ int mprotect(void *addr, size_t len, int prot);
#define MS_SYNC 0 /* Synchronous memory sync. */
#define MS_INVALIDATE 2 /* Invalidate the caches. */

/* madvise: no-op on Windows. Advisory only — safe to skip.
*/
#define MADV_NORMAL 0
#define MADV_SEQUENTIAL 2
#define MADV_DONTNEED 4

static inline int madvise(void* addr, size_t len, int advice)
{
(void)addr; (void)len; (void)advice;
return 0;
}

#endif//_SYS_MMAN_H
105 changes: 101 additions & 4 deletions pkg/noun/allocate.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,10 @@ _me_gain_use(u3_noun dog)
static inline u3_atom
_ca_take_atom(u3a_atom* old_u)
{
c3_w* new_w = u3a_walloc(old_u->len_w + c3_wiseof(u3a_atom));
// use masked length; bob atoms carry u3a_blob_flag in len_w
//
c3_w dat_w = old_u->len_w & u3a_blob_mask;
c3_w* new_w = u3a_walloc(dat_w + c3_wiseof(u3a_atom));
u3a_atom* new_u = (u3a_atom*)(void *)new_w;
u3_noun new = u3a_to_pug(u3a_outa(new_u));

Expand All @@ -523,7 +526,7 @@ _ca_take_atom(u3a_atom* old_u)
{
c3_w i_w;

for ( i_w=0; i_w < old_u->len_w; i_w++ ) {
for ( i_w=0; i_w < dat_w; i_w++ ) {
new_u->buf_w[i_w] = old_u->buf_w[i_w];
}
}
Expand Down Expand Up @@ -842,6 +845,82 @@ _me_gain_south(u3_noun dog)
}
}

/* u3a_blob_get(): look up blb_p entry for (mug_h, seq_h). RETAINS.
*/
u3a_blob*
u3a_blob_get(c3_h mug_h, c3_h seq_h)
{
u3_noun bid = u3i_chub(((c3_d)mug_h << 32) | (c3_d)seq_h);
u3_weak bv = u3h_get(u3H->blb_p, bid);
u3z(bid);

if ( u3_none == bv ) return 0;

c3_d off_d = 0;
u3r_safe_chub(bv, &off_d);
u3z(bv);

return (u3a_blob*)u3a_into((u3_post)off_d);
}

/* u3a_blob_new(): allocate fresh u3a_blob and install it under (mug_h, seq_h).
*/
u3a_blob*
u3a_blob_new(c3_h mug_h, c3_h seq_h)
{
u3a_blob* blb_u = u3a_walloc(c3_wiseof(u3a_blob));
blb_u->use_w = 0;
blb_u->eve_w = 0;
blb_u->les_h = 0;
blb_u->mug_h = mug_h;
blb_u->seq_h = seq_h;

u3_post off_p = u3a_outa(blb_u);
u3_noun bid = u3i_chub(((c3_d)mug_h << 32) | (c3_d)seq_h);
u3h_put(u3H->blb_p, bid, u3i_chub((c3_d)off_p));
u3z(bid);

return blb_u;
}

/* u3a_blob_drop(): remove blb_p entry and free underlying u3a_blob.
*/
void
u3a_blob_drop(c3_h mug_h, c3_h seq_h)
{
u3a_blob* blb_u = u3a_blob_get(mug_h, seq_h);
if ( !blb_u ) return;

u3a_wfree(blb_u);

u3_noun bid = u3i_chub(((c3_d)mug_h << 32) | (c3_d)seq_h);
u3h_del(u3H->blb_p, bid);
u3z(bid);
}

/* _me_bob_dead(): bob atom's loom refcount just hit zero.
**
** Decrements u3a_blob.use_w (atom cardinality contribution). If
** use_w hits zero, calls blob_del_f to wipe the file and drop the
** blb_p entry.
*/
static void
_me_bob_dead(u3a_atom* atm_u)
{
if ( !u3C.blob_del_f ) return;

u3a_blob* blb_u = (u3a_blob*)u3a_into((u3_post)atm_u->buf_w[0]);
if ( !blb_u ) return;

if ( blb_u->use_w > 0 ) {
blb_u->use_w -= 1;
}

if ( 0 == blb_u->use_w ) {
u3C.blob_del_f(blb_u->mug_h, blb_u->seq_h);
}
}

/* _me_lose_north(): lose on a north road.
*/
static void
Expand Down Expand Up @@ -874,6 +953,10 @@ _me_lose_north(u3_noun dog)
}
}
else {
u3a_atom* atm_u = (u3a_atom*)box_u;
if ( atm_u->len_w & u3a_blob_flag ) {
_me_bob_dead(atm_u);
}
u3a_wfree(box_u);
}
}
Expand Down Expand Up @@ -913,6 +996,10 @@ _me_lose_south(u3_noun dog)
}
}
else {
u3a_atom* atm_u = (u3a_atom*)box_u;
if ( atm_u->len_w & u3a_blob_flag ) {
_me_bob_dead(atm_u);
}
u3a_wfree(box_u);
}
}
Expand Down Expand Up @@ -1152,8 +1239,18 @@ u3a_relocate_noun(u3_noun *som)
old_p = u3a_to_off(old);

if ( c3n == u3a_is_cell(old) ) {
new_p = _pack_relocate(old_p);
*som = u3a_to_pug(new_p);
// indirect atom: mark-tracked relocate so bob atoms can rewrite
// their u3a_blob pointer at old_p exactly once.
//
new_p = _pack_relocate_mark(old_p, &fir_t);
*som = u3a_to_pug(new_p);

if ( fir_t ) {
u3a_atom* atm_u = u3to(u3a_atom, old_p);
if ( atm_u->len_w & u3a_blob_flag ) {
u3a_relocate_post((u3_post*)&atm_u->buf_w[0]);
}
}
return;
}

Expand Down
100 changes: 100 additions & 0 deletions pkg/noun/allocate.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,31 @@
typedef u3a_64_cell u3a_cell;
#endif

/* u3a_blob: loom-resident metadata for a blob file.
**
** Stored in u3H->blb_p keyed by bid = (mug_h << 32) | seq_h, with one
** entry per (mug_h, seq_h). Each bob atom's buf_w[0] is the loom
** offset of its u3a_blob.
**
** Single-counter design: the blob file is deleted iff use_w == 0.
** use_w is the sum of three component sources:
** - eve_w: event-log refcount (rebuilt on chop)
** - les_h: active king-held lease count (transient; zeroed on boot)
** - implicit atom cardinality: number of live bob atoms whose
** buf_w[0] points here. Updated only on atom alloc/free; not
** affected by normal noun-refcount transitions.
**
** On boot we zero les_h (and subtract from use_w); eve_w and atom
** cardinality survive the snapshot.
*/
typedef struct __attribute__((aligned(4))) {
c3_w use_w; // total refs: eve_w + les_h + atom cardinality
c3_w eve_w; // event-log refcount (rebuildable from LMDB)
c3_h les_h; // active king-held leases (transient; zeroed on boot)
c3_h mug_h; // blob mug — identifies file in .urb/bob
c3_h seq_h; // blob seq — identifies file in .urb/bob
} u3a_blob;

STATIC_ASSERT( (((c3_w)1) << u3a_min_log) == u3a_minimum,
"log2 minimum allocation" );
STATIC_ASSERT( u3a_vits <= u3a_min_log,
Expand Down Expand Up @@ -475,6 +500,19 @@ STATIC_ASSERT( u3a_vits <= u3a_min_log,
/* u3a_is_cell: yes if noun [som] is cell.
*/
# define u3a_is_cell(som) u3a_is_pom(som)

/* u3a_blob_flag: MSB of u3a_atom.len_w marks an indirect atom as a bob
** (blob reference backed by an on-disk file rather than loom data).
** The remaining bits hold the actual data word count.
** In VERE64, len_w is uint64_t so we use bit 63; in 32-bit we use bit 31.
*/
# ifdef VERE64
# define u3a_blob_flag ((c3_w)0x8000000000000000ULL)
# define u3a_blob_mask ((c3_w)0x7FFFFFFFFFFFFFFFULL)
# else
# define u3a_blob_flag ((c3_w)0x80000000U)
# define u3a_blob_mask ((c3_w)0x7FFFFFFFU)
# endif
# define u3du(som) u3a_is_cell(som)

/* u3a_h(): get head of cell [som]. Bail if [som] is not cell.
Expand Down Expand Up @@ -777,6 +815,49 @@ typedef struct {
return (pil_u->top_p == u3R->cap_p) ? c3y : c3n;
}

/* u3a_is_bob(): yes if [som] is an indirect atom flagged as a bob (blob ref).
** Follows naming convention: u3a_is_cat, u3a_is_pug, u3a_is_pom, u3a_is_bob.
*/
static inline c3_o
u3a_is_bob(u3_atom som) {
if ( c3n == u3a_is_pug(som) ) return c3n;
u3a_atom* atm_u = u3a_to_ptr(som);
return (atm_u->len_w & u3a_blob_flag) ? c3y : c3n;
}

/* u3a_bob_blob(): u3a_blob* referenced by a bob atom (via buf_w[0]).
*/
static inline u3a_blob*
u3a_bob_blob(u3_atom som) {
u3a_atom* atm_u = u3a_to_ptr(som);
return (u3a_blob*)u3a_into((u3_post)atm_u->buf_w[0]);
}

/* u3a_bob_mug(): content mug of a bob atom (= blob directory name).
** Stored redundantly on the atom (mug_w) for fast u3r_mug.
*/
static inline c3_h
u3a_bob_mug(u3_atom som) {
return (c3_h)((u3a_atom*)u3a_to_ptr(som))->mug_w;
}

/* u3a_bob_seq(): sequence number within mug bucket.
*/
static inline c3_h
u3a_bob_seq(u3_atom som) {
return u3a_bob_blob(som)->seq_h;
}

/* u3a_bob_bid(): blob ID = (mug << 32) | seq.
** On VERE64 this is a direct atom (63 bits).
** On 32-bit this is a c3_d that must go through u3i_chub().
*/
static inline c3_d
u3a_bob_bid(u3_atom som) {
u3a_blob* blb_u = u3a_bob_blob(som);
return ((c3_d)blb_u->mug_h << 32) | (c3_d)blb_u->seq_h;
}

/** Functions.
**/

Expand Down Expand Up @@ -983,6 +1064,25 @@ u3a_post_info(u3_post);
c3_w
u3a_idle(u3a_road* rod_u);

/* u3a_blob_get(): look up blb_p entry by (mug_h, seq_h).
** Returns NULL if no entry exists. RETAINS.
*/
u3a_blob*
u3a_blob_get(c3_h mug_h, c3_h seq_h);

/* u3a_blob_new(): allocate a fresh u3a_blob and install it in
** blb_p under (mug_h, seq_h). Caller is responsible for
** ensuring no entry exists; struct is zero-initialized.
*/
u3a_blob*
u3a_blob_new(c3_h mug_h, c3_h seq_h);

/* u3a_blob_drop(): remove blb_p entry for (mug_h, seq_h) and
** free the underlying u3a_blob. No-op if no entry.
*/
void
u3a_blob_drop(c3_h mug_h, c3_h seq_h);

/* u3a_ream(): ream free-lists.
*/
void
Expand Down
1 change: 1 addition & 0 deletions pkg/noun/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ const c_source_files = [_][]const u8{
"jets/e/fynd_ob.c",
"jets/e/hmac.c",
"jets/e/jam.c",
"jets/e/jam_shax.c",
"jets/e/json_de.c",
"jets/e/json_en.c",
"jets/e/keccak.c",
Expand Down
11 changes: 3 additions & 8 deletions pkg/noun/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,20 @@
c3_i
u3e_image_open_any(c3_c* nam_c, c3_c* dir_c, c3_z* len_z, c3_i mod_i);

/* u3_{32,64}_load(): locate u3v_{32,64}_home in the mapped 32-bit /
** 64-bit image.
/* u3_{32,64}_load(): locate u3v_{32,64}_home in the mapped image.
*/
void
u3_32_load(c3_z wor_i);

void
u3_64_load(c3_z wor_i);

/* u3_migrate_32(): migrate the loaded 64-bit snapshot into the native
** 32-bit loom. Called from disk.c on a 32-bit vere reading a 64-bit
** snapshot.
/* u3_migrate_32(): migrate 64 -> 32.
*/
void
u3_migrate_32(c3_d eve_d);

/* u3_migrate_64(): migrate the loaded 32-bit snapshot into the native
** 64-bit loom. Called from disk.c on a 64-bit vere reading a 32-bit
** snapshot.
/* u3_migrate_64(): migrate 32 -> 64.
*/
void
u3_migrate_64(c3_d eve_d);
Expand Down
Loading