database: Use an estimator in Cayley's Size() w/ PostgreSQL

pull/11/head
Quentin Machu 9 years ago
parent f229083e1e
commit 3a1d0602fb

2
Godeps/Godeps.json generated

@ -42,7 +42,7 @@
{ {
"ImportPath": "github.com/google/cayley", "ImportPath": "github.com/google/cayley",
"Comment": "v0.4.1-160-gcdf0154", "Comment": "v0.4.1-160-gcdf0154",
"Rev": "cdf0154d1a34019651eb4f46ce666b31f4d8cae7" "Rev": "6027e4c48b3385307bd4bea462149fd544577165"
}, },
{ {
"ImportPath": "github.com/julienschmidt/httprouter", "ImportPath": "github.com/julienschmidt/httprouter",

@ -21,9 +21,9 @@ import (
"os" "os"
"github.com/barakmich/glog" "github.com/barakmich/glog"
"github.com/coreos/pkg/capnslog"
"github.com/coreos/clair/health" "github.com/coreos/clair/health"
"github.com/coreos/clair/utils" "github.com/coreos/clair/utils"
"github.com/coreos/pkg/capnslog"
"github.com/google/cayley" "github.com/google/cayley"
"github.com/google/cayley/graph" "github.com/google/cayley/graph"
"github.com/google/cayley/graph/path" "github.com/google/cayley/graph/path"
@ -70,23 +70,29 @@ func Open(dbType, dbPath string) error {
} }
var err error var err error
options := make(graph.Options)
// Try to create database if necessary switch dbType {
if dbType == "bolt" || dbType == "leveldb" { case "bolt", "leveldb":
if _, err := os.Stat(dbPath); os.IsNotExist(err) { if _, err := os.Stat(dbPath); os.IsNotExist(err) {
// No, initialize it if possible
log.Infof("database at %s does not exist yet, creating it", dbPath) log.Infof("database at %s does not exist yet, creating it", dbPath)
if err = graph.InitQuadStore(dbType, dbPath, nil); err != nil { err = graph.InitQuadStore(dbType, dbPath, options)
if err != nil {
log.Errorf("could not create database at %s : %s", dbPath, err) log.Errorf("could not create database at %s : %s", dbPath, err)
return ErrCantOpen return ErrCantOpen
} }
} }
} else if dbType == "sql" { case "sql":
graph.InitQuadStore(dbType, dbPath, nil) // Replaces the PostgreSQL's slow COUNT query with a fast estimator.
// See:
// Ref: https://wiki.postgresql.org/wiki/Count_estimate
options["use_estimates"] = true
graph.InitQuadStore(dbType, dbPath, options)
} }
store, err = cayley.NewGraph(dbType, dbPath, nil) store, err = cayley.NewGraph(dbType, dbPath, options)
if err != nil { if err != nil {
log.Errorf("could not open database at %s : %s", dbPath, err) log.Errorf("could not open database at %s : %s", dbPath, err)
return ErrCantOpen return ErrCantOpen

@ -37,11 +37,12 @@ var (
) )
type QuadStore struct { type QuadStore struct {
db *sql.DB db *sql.DB
sqlFlavor string sqlFlavor string
size int64 size int64
lru *cache lru *cache
noSizes bool noSizes bool
useEstimates bool
} }
func connectSQLTables(addr string, _ graph.Options) (*sql.DB, error) { func connectSQLTables(addr string, _ graph.Options) (*sql.DB, error) {
@ -132,6 +133,11 @@ func newQuadStore(addr string, options graph.Options) (graph.QuadStore, error) {
qs.noSizes = false qs.noSizes = false
} }
} }
qs.useEstimates, _, err = options.BoolKey("use_estimates")
if err != nil {
return nil, err
}
return &qs, nil return &qs, nil
} }
@ -286,7 +292,18 @@ func (qs *QuadStore) Size() int64 {
if qs.size != -1 { if qs.size != -1 {
return qs.size return qs.size
} }
c := qs.db.QueryRow("SELECT COUNT(*) FROM quads;")
query := "SELECT COUNT(*) FROM quads;"
if qs.useEstimates {
switch qs.sqlFlavor {
case "postgres":
query = "SELECT reltuples::BIGINT AS estimate FROM pg_class WHERE relname='quads';"
default:
panic("no estimate support for flavor: " + qs.sqlFlavor)
}
}
c := qs.db.QueryRow(query)
err := c.Scan(&qs.size) err := c.Scan(&qs.size)
if err != nil { if err != nil {
glog.Errorf("Couldn't execute COUNT: %v", err) glog.Errorf("Couldn't execute COUNT: %v", err)

Loading…
Cancel
Save