Skip to content

Storage driver

Generated from crates/niso-storage/include/storage-driver.h when the site was built at 7aa23e2.

This is the storage-driver section of niso_runtime.h, owned by niso-storage and kept in crates/niso-storage/include/storage-driver.h. The build composes it with the other sections in the order crates/niso-compose/sections.txt gives.

A storage driver: where IndexedDB databases and localStorage areas keep their data (docs/storage.md). It stores, per origin and endpoint, named databases with a version, object stores and indexes (named in UTF-16 code units), and records ordered by key. Keys arrive encoded so that comparing their bytes (memcmp, then length) orders them as IndexedDB orders keys; values and key paths are opaque bytes. All calls come from the DOM’s thread. Each function returns 0, NISO_QUOTA_EXCEEDED_ERROR when the storage is full, or another nonzero status for any other failure.

endpoint: 0 IndexedDB, 1 localStorage, 2 sessionStorage. mode: 0 “readonly”, 1 “readwrite”, 2 “versionchange”. durability: 0 “default”, 1 “strict”, 2 “relaxed”.

A database has at most one “readwrite” or “versionchange” transaction at a time, and a “readonly” one that runs beside it uses other object stores, so a driver can run all of a database’s transactions on one underlying connection.

typedef struct niso_storage_range_end {
const uint8_t* key;
size_t key_len;
/* For an index, bounds the (key, primary key) pair; otherwise the key
* alone, so all of the key's entries are in or out. */
const uint8_t* primary;
size_t primary_len;
bool has_primary;
bool open;
} niso_storage_range_end;
typedef struct niso_storage_range {
niso_storage_range_end lower;
niso_storage_range_end upper;
bool has_lower;
bool has_upper;
} niso_storage_range;
typedef struct niso_storage_store_info {
uint64_t id;
const uint16_t* name;
size_t name_len;
const uint8_t* key_path;
size_t key_path_len;
bool has_key_path;
bool auto_increment;
} niso_storage_store_info;
typedef struct niso_storage_index_info {
uint64_t id;
const uint16_t* name;
size_t name_len;
const uint8_t* key_path;
size_t key_path_len;
bool unique;
bool multi_entry;
} niso_storage_index_info;

How open reports a database’s schema: store once per object store, then index once per index. The pointers need only live for the call.

typedef struct niso_storage_schema {
void* ctx;
void (*store)(void* ctx, const niso_storage_store_info* store);
void (*index)(void* ctx, uint64_t store, const niso_storage_index_info* index);
} niso_storage_schema;

One entry of a scan: an object store record (primary is its key again) or an index entry and the primary key of its record; value is the record’s value when the scan asked for values. Returns false to stop the scan.

typedef bool (*niso_storage_visit_fn)(void* ctx, const uint8_t* key, size_t key_len, const uint8_t* primary,
size_t primary_len, const uint8_t* value, size_t value_len, bool has_value);
typedef struct niso_storage_driver {
void* userdata;
/* Calls each with every database the origin has for the endpoint. */
int32_t (*databases)(void* userdata, const char* origin, size_t len, uint8_t endpoint, void* ctx,
void (*each)(void* ctx, const uint16_t* name, size_t name_len, uint64_t version));
/* Opens a database, creating it at version 0 with no object stores if
* it does not exist, and reports its version and schema. */
int32_t (*open)(void* userdata, const char* origin, size_t len, uint8_t endpoint, const uint16_t* name,
size_t name_len, uint64_t* db, uint64_t* version, const niso_storage_schema* schema);
void (*close)(void* userdata, uint64_t db);
/* Deletes a database that is not open. */
int32_t (*delete_database)(void* userdata, const char* origin, size_t len, uint8_t endpoint,
const uint16_t* name, size_t name_len);
int32_t (*begin)(void* userdata, uint64_t db, uint8_t mode, uint8_t durability, uint64_t* txn);
/* Writes everything the transaction did, atomically. */
int32_t (*commit)(void* userdata, uint64_t txn);
/* Undoes everything the transaction did, version and schema included. */
void (*abort)(void* userdata, uint64_t txn);
/* Schema changes, only in a "versionchange" transaction. The core picks
* the ids: unique among a database's object stores (or indexes), and
* reused only after the transaction that used them aborted. */
int32_t (*set_version)(void* userdata, uint64_t txn, uint64_t version);
int32_t (*create_store)(void* userdata, uint64_t txn, const niso_storage_store_info* store);
/* Deletes an object store, its records, its indexes and their entries. */
int32_t (*delete_store)(void* userdata, uint64_t txn, uint64_t store);
int32_t (*rename_store)(void* userdata, uint64_t txn, uint64_t store, const uint16_t* name, size_t len);
int32_t (*create_index)(void* userdata, uint64_t txn, uint64_t store, const niso_storage_index_info* index);
int32_t (*delete_index)(void* userdata, uint64_t txn, uint64_t index);
int32_t (*rename_index)(void* userdata, uint64_t txn, uint64_t index, const uint16_t* name, size_t len);
/* Stores a record, replacing the one with the same key after deleting
* that one's index entries. */
int32_t (*put)(void* userdata, uint64_t txn, uint64_t store, const uint8_t* key, size_t key_len,
const uint8_t* value, size_t value_len);
/* Adds the entry (key, primary) to an index. */
int32_t (*put_index)(void* userdata, uint64_t txn, uint64_t index, const uint8_t* key, size_t key_len,
const uint8_t* primary, size_t primary_len);
/* Deletes the records in the range, and their index entries. */
int32_t (*delete_range)(void* userdata, uint64_t txn, uint64_t store, const niso_storage_range* range);
int32_t (*clear)(void* userdata, uint64_t txn, uint64_t store);
/* Visits the entries of an object store (index false) or an index in the
* range, in key order (then primary key order), or in reverse. */
int32_t (*scan)(void* userdata, uint64_t txn, bool index, uint64_t source, const niso_storage_range* range,
bool reverse, bool values, void* ctx, niso_storage_visit_fn visit);
int32_t (*count)(void* userdata, uint64_t txn, bool index, uint64_t source, const niso_storage_range* range,
uint64_t* out);
/* An object store's key generator's current number: 1 when created. */
int32_t (*generator)(void* userdata, uint64_t txn, uint64_t store, uint64_t* out);
int32_t (*set_generator)(void* userdata, uint64_t txn, uint64_t store, uint64_t current);
/* Called once with userdata when the DOM lets go of the driver; may be NULL. */
niso_drop_fn drop;
} niso_storage_driver;