Skip to content

Instantly share code, notes, and snippets.

@creationix
Last active December 21, 2018 03:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creationix/b2b0ff7f7546602b72b9c16023ab65e1 to your computer and use it in GitHub Desktop.
Save creationix/b2b0ff7f7546602b72b9c16023ab65e1 to your computer and use it in GitHub Desktop.
Browser Storage Proposal

Level DB Style

This is highly influenced by https://github.com/google/leveldb#features

  • Keys and values are arbitrary byte arrays.
  • Data is stored sorted by key.
  • Callers can provide a custom comparison function to override the sort order.
  • The basic operations are Put(key,value), Get(key), Delete(key).
  • Multiple changes can be made in one atomic batch.
  • Users can create a transient snapshot to get a consistent view of data.
  • Forward and backward iteration is supported over the data.
// Basic operations
db.put(key, value) -> Promise
db.get(key) -> Promise<value>
db.delete(key) -> Promise

// Atomic Batch Writes
db.batch() -> Batch
batch.put(key, value) -> Batch
batch.delete(key) -> Batch
batch.write() -> Promise

// Snapshot reads
db.snapshot() -> Promise<Snapshot>
snapshot.get(key) -> Promise<value>
snapshot.iterate() -> Iterator

// Iterator
db.iterate() -> Iterator
it.seekToFirst() -> Promise
it.seekToEnd() -> Promise
it.valid() -> Promise<isValid>
it.prev() -> Promise
it.next() -> Promise
it.key() -> key
it.value() -> Promise<value>

This is less well designed, but we'll need some globals for bootstrapping this process:

window.openStorage(name, options) -> Promise<DB> // create if not found
// options.compare(a, b) -> Number - custom comparator 
window.delStorage(name) -> Promise
window.listStorage() -> Promise<names>

MMAP Style

Some applications may prefer a different approach to storage. Consider if we wanted to compile sqlite3 using emscripten and wanted to persist the data somehow.

window.mmap(name) -> Promise<MMap>

mm.lock(start, end) -> Promise<ByteArray> // Ensure a range of bytes is in ram and get access as byte array
mm.unlock(start, end) // Free a range to be cleared from ram cache.
mm.msync() -> Promise // Flush all changes in memory to disk.
// If you try to access a bytearray that's not in ram cache, an exception will be thrown.

Append-only Store

Many databases can be implemented with simply an append-only stream.

window.logStore(name) -> Promise<LogStore>
log.write(value) -> Promise // Write to file, promise resolves when data in kernel space
log.fsync() -> Promise // Do a full sync (flush kernel buffers)
log.close() -> Promise // sync and close.
@creationix
Copy link
Author

I may be off on some places which functions need to be async (return a promise), but this is the general idea of the core interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment