Tevere
Decentralized eventually-consistent key-value store over IPFS for the browser. Exposes a Leveldown-compatible API.
Install
$ npm install tevere --save
Use
Here we're using Memdown as a log database, but you can use any database that conforms to the Leveldown interface (Level-js on the browser or Leveldown on Node.js):
const Tevere = const Memdown = const db = db
Custom merge function
By default, when a conflict exists (two nodes have concucrently performed a change on the same key), Tevere will determinstically choose one of the values for you. Instead, you can provide a synchronous merge function like this:
const db = // custom merge function that merges two records { return a: v1a b: v2b c: v1c d: Math }
Custom merge and determinism
If you define a custom merge function, the result must be deterministic. For every node involved in the same conflict, Tevere guarantees that the order of the values passed into the merge function is the same. In return, you must guarantee that, given the same two values, you always return the same merged value.
This means that you cannot generate data that is not deterministic, like random values or even time stamps.
Invalid merge function:
{ return timestamp: Date }
This is valid, though:
{ return timestamp: Math }
Tevere's compromise: Given a specific conflict, the order of the two values passed into the merge function is always the same. This means that, if two nodes have conflicting changes, both nodes custom merge functions will be called with the exact same arguments in the exact same order.
Your compromise: Determinism, purely funcional merge function: given a sets of two conflicting values, you always return the same merged value, no matter at which node and at which time the merging occurs.
Tevere API
Tevere (partition, options)
Creates a Tevere instance.
- partition (string, mandatory): identifies the partition this node will participate in.
- options (object, mandatory): some options:
ipfsOptions
(object, optional). IPFS options object.log
(LevelDown-compatible database): this is where the node keeps the log entries (which only have a vector clock and a hash — all the actual data is kept in IPFS).ipfs
(IPFS object, optional): an IPFS object instance. If you already can provide an IPFS object, pass it in here.merge
(function, optional): a synchronous function that will receive two values and return a new value.
A Tevere instance respects the Leveldown API. Here are the main methods:
Example:
const Leveljs = const db =
db.put (key, value, callback)
Save a value to key.
db.get (key, callback)
Get the value stored in key
.
db.iterator (options)
Returns an iterator over the database. Supports the same options described in the Leveldown API.
Events
A Tevere instance emits these event types:
"change" (change)
Every time there is a change (either local or remote), a Tevere instance emits a change
event, which is an object that has these properties:
type
(string, either "del" or "put")key
(string)value
(any, relevant forput
type operations)
Examples
Check the tests dir for some examples.
Internals
Internal workings are documented here.
License
MIT
Why the name "Tevere"?
Tevere is the italian name for the river that goes through Rome. At the time the repo for this project was created, I was hanging out in Rome with some of the IPFS crew, so I guess it made sense at the time...
Contribute
Feel free to join in. All welcome. Open an issue!
This repository falls under the IPFS Code of Conduct.