Skip to content

How to

Choose a backend

How each driver stores a tuple, how to select a backend in the config, and the contract for a new driver.

storestore/xdbmemorystore/xdbfsstore/xdbredisstore/xdbsqlite

Read this when
  • You select a backend for a new deployment
  • You write a driver for another database

A driver writes tuples to one backend. XDB has drivers for memory, the filesystem, Redis, and SQLite. The store applies schema validation and versioning above the driver, so each backend gets the same rules.

backend storage layouts

Storage layouts

Each driver stores the tuple xdb://com.example/posts/p-1#title = "Hello" in a different form:

BackendStorage
Memorym["com.example/posts/p-1"]["title"] = "Hello"
Filesystemcom.example/posts/p-1.json contains { "title": "Hello" }
RedisHSET xdb:com.example:posts:p-1 title "Hello"
SQLiteINSERT INTO "t:com.example/posts" (_id, title) VALUES ('p-1', 'Hello')

Each backend maps the XDB types to its own format. SQLite uses these column types:

TypeGoSQLite
stringstringTEXT
integerint64INTEGER
unsigneduint64INTEGER
floatfloat64REAL
booleanboolINTEGER
timetime.TimeINTEGER
jsonjson.RawMessageTEXT
bytes[]byteBLOB
array[]*ValueTEXT

Select a backend

Set store.backend in ~/.xdb/config.json to sqlite, memory, fs, or redis. Put the options for that backend in the same object:

{
"store": {
"backend": "sqlite",
"sqlite": { "path": "/var/lib/xdb/xdb.db" }
}
}

Then restart the daemon:

Terminal window
xdb daemon restart

CAUTION: A change of backend does not copy the data from the old backend. To keep the data, export it before the change. See Read and write records.

BackendOptions
sqlitestore.sqlite.path (default <datadir>/xdb.db), journal, sync, cache_size, busy_timeout
redisstore.redis.addr (required), password, db
fsstore.fs.dir (default <datadir>)
memoryNo options. The data stays in the memory of the daemon.

Config describes each option.

Use a driver in Go

store.New puts the validation and versioning middleware around a driver:

// Memory
st := store.New(xdbmemory.NewDriver())
// Filesystem
d, err := xdbfs.NewDriver("/path/to/data", xdbfs.Options{})
st := store.New(d)
// Redis
st := store.New(xdbredis.NewDriver(client))
// SQLite
d, err := xdbsqlite.NewDriver(db)
st := store.New(d)

Write a driver

A driver implements TupleReader, TupleWriter, SchemaReader, and SchemaWriter. The store builds records from the tuples, converts each write to mutations, and applies validation and versioning.

driver interfaces

Optional interfaces add capabilities. store.New finds them on the driver:

  • TxDriver makes a batch atomic. Without it, the store applies the operations of a batch one at a time, and a CLI batch needs --non-atomic.
  • QueryDriver evaluates filters in the database through QueryTuples. Without it, the store scans the tuples and filters them.

To test a new driver, register storetest.NewDriverSuite, storetest.NewQuerySuite, and the store suites. Drivers gives the contract.