Documentation and tests
This commit is contained in:
parent
e2debf5f04
commit
d0fcdf4299
6 changed files with 59 additions and 15 deletions
|
|
@ -27,8 +27,9 @@ Its goal is to be a part of the developer's toolbox where [Linked Data](http://l
|
||||||
* JavaScript, with a [Gremlin](http://gremlindocs.com/)-inspired\* graph object.
|
* JavaScript, with a [Gremlin](http://gremlindocs.com/)-inspired\* graph object.
|
||||||
* (simplified) [MQL](https://developers.google.com/freebase/v1/mql-overview), for Freebase fans
|
* (simplified) [MQL](https://developers.google.com/freebase/v1/mql-overview), for Freebase fans
|
||||||
* Plays well with multiple backend stores:
|
* Plays well with multiple backend stores:
|
||||||
* [LevelDB](http://code.google.com/p/leveldb/) for single-machine storage
|
* [LevelDB](http://code.google.com/p/leveldb/)
|
||||||
* [MongoDB](http://mongodb.org)
|
* [Bolt](http://github.com/boltdb/bolt)
|
||||||
|
* [MongoDB](http://mongodb.org) for distributed stores
|
||||||
* In-memory, ephemeral
|
* In-memory, ephemeral
|
||||||
* Modular design; easy to extend with new languages and backends
|
* Modular design; easy to extend with new languages and backends
|
||||||
* Good test coverage
|
* Good test coverage
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -33,6 +35,8 @@ import (
|
||||||
"github.com/google/cayley/query/gremlin"
|
"github.com/google/cayley/query/gremlin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var backend = flag.String("backend", "memstore", "Which backend to test. Loads test data to /tmp if not present.")
|
||||||
|
|
||||||
var benchmarkQueries = []struct {
|
var benchmarkQueries = []struct {
|
||||||
message string
|
message string
|
||||||
long bool
|
long bool
|
||||||
|
|
@ -378,15 +382,42 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func prepare(t testing.TB) {
|
func prepare(t testing.TB) {
|
||||||
|
switch *backend {
|
||||||
|
case "memstore":
|
||||||
|
break
|
||||||
|
case "leveldb":
|
||||||
|
fallthrough
|
||||||
|
case "bolt":
|
||||||
|
cfg.DatabaseType = *backend
|
||||||
|
cfg.DatabasePath = fmt.Sprint("/tmp/cayley_test_", *backend)
|
||||||
|
cfg.DatabaseOptions = map[string]interface{}{
|
||||||
|
"nosync": true, // It's a test. If we need to load, do it fast.
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatalf("Untestable backend store %s", *backend)
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
create.Do(func() {
|
create.Do(func() {
|
||||||
|
needsLoad := true
|
||||||
|
if graph.IsPersistent(cfg.DatabaseType) {
|
||||||
|
if _, err := os.Stat(cfg.DatabasePath); os.IsNotExist(err) {
|
||||||
|
err = db.Init(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not initialize database: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
needsLoad = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle, err = db.Open(cfg)
|
handle, err = db.Open(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to open %q: %v", cfg.DatabasePath, err)
|
t.Fatalf("Failed to open %q: %v", cfg.DatabasePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !graph.IsPersistent(cfg.DatabaseType) {
|
if needsLoad {
|
||||||
err = load(handle.QuadWriter, cfg, "", "cquad")
|
err = load(handle.QuadWriter, cfg, "30kmoviedata.nq.gz", "cquad")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to load %q: %v", cfg.DatabasePath, err)
|
t.Fatalf("Failed to load %q: %v", cfg.DatabasePath, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ All command line flags take precedence over the configuration file.
|
||||||
|
|
||||||
* `mem`: An in-memory store, based on an initial N-Quads file. Loses all changes when the process exits.
|
* `mem`: An in-memory store, based on an initial N-Quads file. Loses all changes when the process exits.
|
||||||
* `leveldb`: A persistent on-disk store backed by [LevelDB](http://code.google.com/p/leveldb/).
|
* `leveldb`: A persistent on-disk store backed by [LevelDB](http://code.google.com/p/leveldb/).
|
||||||
* `mongodb`: Stores the graph data and indices in a [MongoDB](http://mongodb.org) instance. Slower, as it incurs network traffic, but multiple Cayley instances can disappear and reconnect at will, across a potentially horizontally-scaled store.
|
* `bolt`: Stores the graph data on-disk in a [Bolt](http://github.com/boltdb/bolt) file. Uses more disk space and memory than LevelDB for smaller stores, but is often faster to write to and comparable for large ones, with faster average query times.
|
||||||
|
* `mongo`: Stores the graph data and indices in a [MongoDB](http://mongodb.org) instance. Slower, as it incurs network traffic, but multiple Cayley instances can disappear and reconnect at will, across a potentially horizontally-scaled store.
|
||||||
|
|
||||||
#### **`db_path`**
|
#### **`db_path`**
|
||||||
|
|
||||||
|
|
@ -32,9 +33,10 @@ All command line flags take precedence over the configuration file.
|
||||||
|
|
||||||
Where does the database actually live? Dependent on the type of database. For each datastore:
|
Where does the database actually live? Dependent on the type of database. For each datastore:
|
||||||
|
|
||||||
* `mem`: Path to a triple file to automatically load
|
* `mem`: Path to a triple file to automatically load.
|
||||||
* `leveldb`: Directory to hold the LevelDB database files
|
* `leveldb`: Directory to hold the LevelDB database files.
|
||||||
* `mongodb`: "hostname:port" of the desired MongoDB server.
|
* `bolt`: Path to the persistent single Bolt database file.
|
||||||
|
* `mongo`: "hostname:port" of the desired MongoDB server.
|
||||||
|
|
||||||
#### **`listen_host`**
|
#### **`listen_host`**
|
||||||
|
|
||||||
|
|
@ -103,8 +105,16 @@ The size in MiB of the LevelDB write cache. Increasing this number allows for mo
|
||||||
|
|
||||||
The size in MiB of the LevelDB block cache. Increasing this number uses more memory to maintain a bigger cache of triple blocks for better performance.
|
The size in MiB of the LevelDB block cache. Increasing this number uses more memory to maintain a bigger cache of triple blocks for better performance.
|
||||||
|
|
||||||
|
### Bolt
|
||||||
|
|
||||||
### MongoDB
|
#### **`nosync`**
|
||||||
|
|
||||||
|
* Type: Boolean
|
||||||
|
* Default: false
|
||||||
|
|
||||||
|
Optionally disable syncing to disk per transaction. Nosync being true means much faster load times, but without consistency guarantees.
|
||||||
|
|
||||||
|
### Mongo
|
||||||
|
|
||||||
|
|
||||||
#### **`database_name`**
|
#### **`database_name`**
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ You can set up a full [configuration file](/docs/Configuration) if you'd prefer,
|
||||||
Examples for each backend:
|
Examples for each backend:
|
||||||
|
|
||||||
* `leveldb`: `./cayley init --db=leveldb --dbpath=/tmp/moviedb` -- where /tmp/moviedb is the path you'd like to store your data.
|
* `leveldb`: `./cayley init --db=leveldb --dbpath=/tmp/moviedb` -- where /tmp/moviedb is the path you'd like to store your data.
|
||||||
* `mongodb`: `./cayley init --db=mongodb --dbpath="<HOSTNAME>:<PORT>"` -- where HOSTNAME and PORT point to your Mongo instance.
|
* `bolt`: `./cayley init --db=bolt --dbpath=/tmp/moviedb` -- where /tmp/moviedb is the filename where you'd like to store your data.
|
||||||
|
* `mongo`: `./cayley init --db=mongo --dbpath="<HOSTNAME>:<PORT>"` -- where HOSTNAME and PORT point to your Mongo instance.
|
||||||
|
|
||||||
Those two options (db and dbpath) are always going to be present. If you feel like not repeating yourself, setting up a configuration file for your backend might be something to do now. There's an example file, `cayley.cfg.example` in the root directory.
|
Those two options (db and dbpath) are always going to be present. If you feel like not repeating yourself, setting up a configuration file for your backend might be something to do now. There's an example file, `cayley.cfg.example` in the root directory.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ package bolt
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -29,8 +30,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
boltType graph.Type
|
boltType graph.Type
|
||||||
bufferSize = 50
|
bufferSize = 50
|
||||||
|
errNotExist = errors.New("Quad does not exist")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -141,7 +143,7 @@ func (it *Iterator) Next() bool {
|
||||||
i++
|
i++
|
||||||
} else {
|
} else {
|
||||||
it.buffer = append(it.buffer, nil)
|
it.buffer = append(it.buffer, nil)
|
||||||
return quad.ErrNotExist
|
return errNotExist
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
k, _ := cur.Seek(last)
|
k, _ := cur.Seek(last)
|
||||||
|
|
@ -167,7 +169,7 @@ func (it *Iterator) Next() bool {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != quad.ErrNotExist {
|
if err != errNotExist {
|
||||||
glog.Error("Error nexting in database: ", err)
|
glog.Error("Error nexting in database: ", err)
|
||||||
}
|
}
|
||||||
it.done = true
|
it.done = true
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import (
|
||||||
var (
|
var (
|
||||||
ErrInvalid = errors.New("invalid N-Quad")
|
ErrInvalid = errors.New("invalid N-Quad")
|
||||||
ErrIncomplete = errors.New("incomplete N-Quad")
|
ErrIncomplete = errors.New("incomplete N-Quad")
|
||||||
ErrNotExist = errors.New("Quad does not exist")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Our triple struct, used throughout.
|
// Our triple struct, used throughout.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue