urbit/include/f/cash.h
2014-03-14 10:50:12 -07:00

272 lines
9.8 KiB
C

/* include/cash.h
**
** This file is in the public domain.
*/
/** Hash-table design:
***
*** The cash system is a 16-way hash tree designed to
*** scale smoothly, remaining small for small usage
*** and fast for big usage. It is also salted for use
*** of multiple associations in the same table.
***
*** A logical key is the combination of an opaque
*** function salt, any number < (1 << 31), and a
*** sample list. Matches are in every case within
*** the salt.
***
*** All the nouns in the sample list are equal, but
*** duplicate. Comparing duplicates is expensive, so
*** the hash-table stores every duplicate it finds.
***
*** The search key is the mug of the salt, XORed
*** with the mug of the sample. [XX - This sacrifices
*** efficiency to internal convenience and should
*** be replaced with direct salt.]
***
*** A single slot stores a single entry. If a new entry
*** is added, the slot expands to a 16-way table. If the
*** table is lightly filled, slots are collision-mapped.
*** If it is heavily filled, slots are radix-mapped.
***
*** Full key collisions, which are inevitable and not at
*** all improbable, revert to linear search. 16 collisions
*** on the same 31-bit key will produce storage failure.
***
*** Future revisions should add a reclamation mode based on
*** the "clock algorithm" (a variant on LRU). The clock
*** rotates around search-key space. Entries are reclaimed
*** if they are clocked out and either key or value has a
*** reference count of 1.
**/
/** Tunable constants.
**/
/* A 16-way subtable with remaining keyspace switches up to laminar
** mode when it exceeds `cash_hi` recursively counted entries, and
** reverts to collision mode when it falls back below `cash_lo`.
*/
# define u2_tune_cash_lo 6
# define u2_tune_cash_hi 10
/** Data types.
**/
/* Slot: a discriminated union.
*/
# define u2_slot_is_a(lot_r) (0 == (*u2_at_ray(lot_r) >> 31))
# define u2_slot_is_b(lot_r) (3 == (*u2_at_ray(lot_r) >> 30))
# define u2_slot_is_c(lot_r) (2 == (*u2_at_ray(lot_r) >> 30))
/* u2_cash_slot_a: cache slot, containing exactly one entry.
*/
typedef struct {
/* sel_m: opaque, unique function identity (0 for nock)
** sap: sample list
** pro: product
*/
c3_m sel_m;
u2_noun sap;
u2_noun pro;
} u2_cash_slot_a;
typedef u2_cash_slot_a u2_cash_slot;
# define u2_slot_a_sel(lot_r) *u2_at(lot_r, u2_cash_slot_a, sel_m)
# define u2_slot_a_sap(lot_r) *u2_at(lot_r, u2_cash_slot_a, sap)
# define u2_slot_a_pro(lot_r) *u2_at(lot_r, u2_cash_slot_a, pro)
# define u2_slot_gunk_coll (7 << 29)
# define u2_slot_gunk_radx (6 << 29)
# define u2_slot_gunk_is_coll(gun_w) (!!((gun_w) & (1 << 29)))
# define u2_slot_gunk_is_radx(gun_w) (!((gun_w) & (1 << 29)))
/* u2_cash_slot_b: cache slot, with 16-way table - if not empty.
*/
typedef struct {
/* gun_w: gunk word - (1 << 31) at present
** rag_w: recursive entry count
** sid_r: ray to 16-way slot array, or 0 if rag_w is 0
*/
c3_w gun_w;
c3_w rag_w;
u2_ray sid_r;
} u2_cash_slot_b;
# define u2_slot_b_gun(lot_r) *u2_at(lot_r, u2_cash_slot_b, gun_w)
# define u2_slot_b_rag(lot_r) *u2_at(lot_r, u2_cash_slot_b, rag_w)
# define u2_slot_b_sid(lot_r) *u2_at(lot_r, u2_cash_slot_b, sid_r)
# define u2_slot_b_sid_i(lot_r, i_w) \
(u2_slot_b_sid(lot_r) + ((i_w) * c3_wiseof(u2_cash_slot_a)))
/* u2_cash_slot_c: cache slot, empty
*/
typedef struct {
/* emt_w: (1 << 31)
*/
c3_w emt_w;
c3_w xxx_w; // unused
c3_w xxy_w; // unused
} u2_cash_slot_c;
# define u2_slot_emty (1 << 31)
# define u2_slot_c_emt(lot_r) *u2_at(lot_r, u2_cash_slot_c, emt_w)
/** Functions.
**/
/* u2_cs_free():
**
** Release an old hashtable.
*/
void
u2_cs_free(u2_ray ral_r,
u2_ray lot_r); // submit
/* u2_cs_mark():
**
** Mark traverse of slot. Return allocated words.
*/
c3_w
u2_cs_mark(u2_ray ral_r,
u2_ray lot_r);
/* u2_cs_init():
**
** Initialize slot to empty.
*/
void
u2_cs_init(u2_ray lot_r);
/* u2_cs_lose():
**
** Release all resources in and under slot (but not slot itself).
*/
void
u2_cs_lose(u2_ray ral_r,
u2_ray lot_r); // submit
/* u2_cs_make():
**
** Create a new hashtable.
*/
u2_ray // produce
u2_cs_make(u2_ray ral_r);
/* u2_cs_find():
**
** Find `sam` for `sel`, or return `u2_none`.
*/
u2_weak // discover
u2_cs_find(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun sam); // retain
/* u2_cs_find_cell():
**
** Find `[a b]` for `sel`, or return `u2_none`.
*/
u2_weak // retain
u2_cs_find_cell(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b); // retain
/* u2_cs_find_mixt():
**
** Find `[a b]` for `sel`, or return `u2_none`.
*/
u2_weak // retain
u2_cs_find_mixt(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
const c3_c* a_c, // retain
u2_noun b); // retain
/* u2_cs_find_trel():
**
** Find `[a b c]` for `sel`, or return `u2_none`.
*/
u2_weak // retain
u2_cs_find_trel(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b, // retain
u2_noun c); // retain
/* u2_cs_find_qual():
**
** Find `[a b c d]` for `sel`, or return `u2_none`.
*/
u2_weak // retain
u2_cs_find_qual(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b, // retain
u2_noun c, // retain
u2_noun d); // retain
/* u2_cs_save():
**
** Save `sam` as `pro` for `sel`. Replace existing `pro`, if any.
*/
u2_noun // produce
u2_cs_save(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun sam, // retain
u2_noun pro); // submit
/* u2_cs_save_cell():
**
** Save `[a b]` as `pro` for `sel`.
*/
u2_noun // transfer
u2_cs_save_cell(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b, // retain
u2_noun pro); // transfer
/* u2_cs_save_mixt():
**
** Save `[a b]` as `pro` for `sel`.
*/
u2_noun // transfer
u2_cs_save_mixt(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
const c3_c* a_c, // retain
u2_noun b, // retain
u2_noun pro); // transfer
/* u2_cs_save_trel():
**
** Save `[a b c]` as `pro` for `sel`.
*/
u2_noun // transfer
u2_cs_save_trel(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b, // retain
u2_noun c, // retain
u2_noun pro); // transfer
/* u2_cs_save_qual():
**
** Save `[a b c d]` as `pro` for `sel`.
*/
u2_noun // transfer
u2_cs_save_qual(u2_ray ral_r,
u2_ray lot_r,
c3_m sel_m,
u2_noun a, // retain
u2_noun b, // retain
u2_noun c, // retain
u2_noun d, // retain
u2_noun pro); // transfer