diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 6b72a9cb..d3b4b195 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -42,7 +42,7 @@ { "ImportPath": "github.com/google/cayley", "Comment": "v0.4.1-160-gcdf0154", - "Rev": "cdf0154d1a34019651eb4f46ce666b31f4d8cae7" + "Rev": "6027e4c48b3385307bd4bea462149fd544577165" }, { "ImportPath": "github.com/julienschmidt/httprouter", diff --git a/database/database.go b/database/database.go index 75c3ac94..87f51d80 100644 --- a/database/database.go +++ b/database/database.go @@ -21,9 +21,9 @@ import ( "os" "github.com/barakmich/glog" - "github.com/coreos/pkg/capnslog" "github.com/coreos/clair/health" "github.com/coreos/clair/utils" + "github.com/coreos/pkg/capnslog" "github.com/google/cayley" "github.com/google/cayley/graph" "github.com/google/cayley/graph/path" @@ -70,23 +70,29 @@ func Open(dbType, dbPath string) error { } var err error + options := make(graph.Options) - // Try to create database if necessary - if dbType == "bolt" || dbType == "leveldb" { + switch dbType { + case "bolt", "leveldb": 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) - 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) return ErrCantOpen } } - } else if dbType == "sql" { - graph.InitQuadStore(dbType, dbPath, nil) + case "sql": + // 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 { log.Errorf("could not open database at %s : %s", dbPath, err) return ErrCantOpen diff --git a/vendor/github.com/google/cayley/graph/sql/quadstore.go b/vendor/github.com/google/cayley/graph/sql/quadstore.go index a24d48e5..d03e84ef 100644 --- a/vendor/github.com/google/cayley/graph/sql/quadstore.go +++ b/vendor/github.com/google/cayley/graph/sql/quadstore.go @@ -37,11 +37,12 @@ var ( ) type QuadStore struct { - db *sql.DB - sqlFlavor string - size int64 - lru *cache - noSizes bool + db *sql.DB + sqlFlavor string + size int64 + lru *cache + noSizes bool + useEstimates bool } 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.useEstimates, _, err = options.BoolKey("use_estimates") + if err != nil { + return nil, err + } + return &qs, nil } @@ -286,7 +292,18 @@ func (qs *QuadStore) Size() int64 { if qs.size != -1 { 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) if err != nil { glog.Errorf("Couldn't execute COUNT: %v", err)