2019-12-16 18:45:21 +00:00
|
|
|
// +build cgo
|
|
|
|
|
2019-08-22 05:12:46 +00:00
|
|
|
package sqlite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"os"
|
2019-12-12 01:27:03 +00:00
|
|
|
"time"
|
2019-08-22 05:12:46 +00:00
|
|
|
|
2020-11-30 23:45:22 +00:00
|
|
|
"github.com/k3s-io/kine/pkg/drivers/generic"
|
|
|
|
"github.com/k3s-io/kine/pkg/logstructured"
|
|
|
|
"github.com/k3s-io/kine/pkg/logstructured/sqllog"
|
|
|
|
"github.com/k3s-io/kine/pkg/server"
|
2019-11-13 06:05:20 +00:00
|
|
|
"github.com/mattn/go-sqlite3"
|
2019-12-12 01:27:03 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/sirupsen/logrus"
|
2019-08-22 05:12:46 +00:00
|
|
|
|
|
|
|
// sqlite db driver
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
schema = []string{
|
|
|
|
`CREATE TABLE IF NOT EXISTS kine
|
|
|
|
(
|
2020-10-28 07:38:43 +00:00
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
2019-08-22 05:12:46 +00:00
|
|
|
name INTEGER,
|
|
|
|
created INTEGER,
|
|
|
|
deleted INTEGER,
|
|
|
|
create_revision INTEGER,
|
|
|
|
prev_revision INTEGER,
|
|
|
|
lease INTEGER,
|
|
|
|
value BLOB,
|
|
|
|
old_value BLOB
|
|
|
|
)`,
|
|
|
|
`CREATE INDEX IF NOT EXISTS kine_name_index ON kine (name)`,
|
2020-10-28 07:38:43 +00:00
|
|
|
`CREATE INDEX IF NOT EXISTS kine_name_id_index ON kine (name,id)`,
|
|
|
|
`CREATE INDEX IF NOT EXISTS kine_id_deleted_index ON kine (id,deleted)`,
|
|
|
|
`CREATE INDEX IF NOT EXISTS kine_prev_revision_index ON kine (prev_revision)`,
|
2019-08-22 05:12:46 +00:00
|
|
|
`CREATE UNIQUE INDEX IF NOT EXISTS kine_name_prev_revision_uindex ON kine (name, prev_revision)`,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
func New(ctx context.Context, dataSourceName string, connPoolConfig generic.ConnectionPoolConfig) (server.Backend, error) {
|
|
|
|
backend, _, err := NewVariant(ctx, "sqlite3", dataSourceName, connPoolConfig)
|
2019-11-08 21:45:10 +00:00
|
|
|
return backend, err
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
func NewVariant(ctx context.Context, driverName, dataSourceName string, connPoolConfig generic.ConnectionPoolConfig) (server.Backend, *generic.Generic, error) {
|
2019-08-22 05:12:46 +00:00
|
|
|
if dataSourceName == "" {
|
|
|
|
if err := os.MkdirAll("./db", 0700); err != nil {
|
2019-11-08 21:45:10 +00:00
|
|
|
return nil, nil, err
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
dataSourceName = "./db/state.db?_journal=WAL&cache=shared"
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
dialect, err := generic.Open(ctx, driverName, dataSourceName, connPoolConfig, "?", false)
|
2019-08-22 05:12:46 +00:00
|
|
|
if err != nil {
|
2019-11-08 21:45:10 +00:00
|
|
|
return nil, nil, err
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
2020-10-28 07:38:43 +00:00
|
|
|
|
2019-08-22 05:12:46 +00:00
|
|
|
dialect.LastInsertID = true
|
2021-08-30 20:43:25 +00:00
|
|
|
dialect.GetSizeSQL = `SELECT SUM(pgsize) FROM dbstat`
|
2020-10-28 07:38:43 +00:00
|
|
|
dialect.CompactSQL = `
|
|
|
|
DELETE FROM kine AS kv
|
|
|
|
WHERE
|
|
|
|
kv.id IN (
|
|
|
|
SELECT kp.prev_revision AS id
|
|
|
|
FROM kine AS kp
|
|
|
|
WHERE
|
2020-11-13 03:14:07 +00:00
|
|
|
kp.name != 'compact_rev_key' AND
|
2020-10-28 07:38:43 +00:00
|
|
|
kp.prev_revision != 0 AND
|
|
|
|
kp.id <= ?
|
|
|
|
UNION
|
|
|
|
SELECT kd.id AS id
|
|
|
|
FROM kine AS kd
|
|
|
|
WHERE
|
|
|
|
kd.deleted != 0 AND
|
|
|
|
kd.id <= ?
|
|
|
|
)`
|
2019-11-13 06:05:20 +00:00
|
|
|
dialect.TranslateErr = func(err error) error {
|
|
|
|
if err, ok := err.(sqlite3.Error); ok && err.ExtendedCode == sqlite3.ErrConstraintUnique {
|
|
|
|
return server.ErrKeyExists
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2019-08-22 05:12:46 +00:00
|
|
|
|
2019-12-12 01:27:03 +00:00
|
|
|
// this is the first SQL that will be executed on a new DB conn so
|
|
|
|
// loop on failure here because in the case of dqlite it could still be initializing
|
|
|
|
for i := 0; i < 300; i++ {
|
|
|
|
err = setup(dialect.DB)
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
logrus.Errorf("failed to setup db: %v", err)
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil, nil, ctx.Err()
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
}
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, errors.Wrap(err, "setup db")
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dialect.Migrate(context.Background())
|
2019-11-08 21:45:10 +00:00
|
|
|
return logstructured.New(sqllog.New(dialect)), dialect, nil
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func setup(db *sql.DB) error {
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Infof("Configuring database table schema and indexes, this may take a moment...")
|
|
|
|
|
2019-08-22 05:12:46 +00:00
|
|
|
for _, stmt := range schema {
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Tracef("SETUP EXEC : %v", generic.Stripped(stmt))
|
2019-08-22 05:12:46 +00:00
|
|
|
_, err := db.Exec(stmt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Infof("Database tables and indexes are up to date")
|
2019-08-22 05:12:46 +00:00
|
|
|
return nil
|
|
|
|
}
|