Skip to content

cowsql/go-cowsql

Repository files navigation

go-cowsql CI tests Coverage Status Go Report Card GoDoc

This repository provides the go-cowsql Go package, containing bindings for the cowsql C library and a pure-Go client for the cowsql wire protocol.

Fork of Canonical go-dqlite

These bindings are a cowsql-oriented fork of Canonical's go-dqlite ones, which were originally written by cowsql's author himself while working at Canonical.

Usage

The best way to understand how to use the go-cowsql package is probably by looking at the source code of the demo program and use it as example.

In general your application will use code such as:

dir := "/path/to/data/directory"
address := "1.2.3.4:666" // Unique node address
cluster := []string{...} // Optional list of existing nodes, when starting a new node
app, err := app.New(dir, app.WithAddress(address), app.WithCluster(cluster))
if err != nil {
        // ...
}

db, err := app.Open(context.Background(), "my-database")
if err != nil {
        // ...
}

// db is a *sql.DB object
if _, err := db.Exec("CREATE TABLE my_table (n INT)"); err != nil
        // ...
}

Build

In order to use the go-cowsql package in your application, you'll need to have the cowsql C library installed on your system, along with its dependencies.

By default, go-cowsql's client module supports storing a cache of the cluster's state in a SQLite database, locally on each cluster member. (This is not to be confused with any SQLite databases that are managed by cowsql.) In order to do this, it imports https://github.com/mattn/go-sqlite3, and so you can use the libsqlite3 build tag to control whether go-sqlite3 links to a system libsqlite3 or builds its own. You can also disable support for SQLite node stores entirely with the nosqlite3 build tag (unique to go-cowsql). If you pass this tag, your application will not link directly to libsqlite3 (but it will still link it indirectly via libcowsql, unless you've dropped the sqlite3.c amalgamation into the cowsql build).

Documentation

The documentation for this package can be found on pkg.go.dev.

Demo

To see cowsql in action, either install the Debian package from the PPA:

sudo add-apt-repository -y ppa:cowsql/master
sudo apt install cowsql libcowsql-dev

or build the cowsql C library and its dependencies from source, as described here, and then run:

go install -tags libsqlite3 ./cmd/cowsql-demo

from the top-level directory of this repository.

This builds a demo cowsql application, which exposes a simple key/value store over an HTTP API.

Once the cowsql-demo binary is installed (normally under ~/go/bin or /usr/bin/), start three nodes of the demo application:

cowsql-demo --api 127.0.0.1:8001 --db 127.0.0.1:9001 &
cowsql-demo --api 127.0.0.1:8002 --db 127.0.0.1:9002 --join 127.0.0.1:9001 &
cowsql-demo --api 127.0.0.1:8003 --db 127.0.0.1:9003 --join 127.0.0.1:9001 &

The --api flag tells the demo program where to expose its HTTP API.

The --db flag tells the demo program to use the given address for internal database replication.

The --join flag is optional and should be used only for additional nodes after the first one. It informs them about the existing cluster, so they can automatically join it.

Now we can start using the cluster. Let's insert a key pair:

curl -X PUT -d my-value http://127.0.0.1:8001/my-key

and then retrieve it from the database:

curl http://127.0.0.1:8001/my-key

Currently the first node is the leader. If we stop it and then try to query the key again curl will fail, but we can simply change the endpoint to another node and things will work since an automatic failover has taken place:

kill -TERM %1; curl http://127.0.0.1:8002/my-key

Shell

A basic SQLite-like cowsql shell is available in the cowsql-tools package or can be built with:

go install -tags libsqlite3 ./cmd/cowsql
Usage:
  cowsql -s <servers> <database> [command] [flags]

Example usage in the case of the cowsql-demo example listed above:

cowsql -s 127.0.0.1:9001 demo

cowsql> SELECT * FROM model;
my-key|my-value

The shell supports normal SQL queries plus the special .cluster and .leader commands to inspect the cluster members and the current leader.