Remove mysql kvs storage backend
This commit is contained in:
parent
2932bac73e
commit
48df950be5
11 changed files with 1 additions and 912 deletions
|
@ -58,7 +58,7 @@ func setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.DB.Path != "memory" {
|
if opts.DB.Path != "memory" {
|
||||||
if ok, _ := regexp.MatchString(`^(s3|gcs|logr|file|mysql|dendrodb)://(.+)$`, opts.DB.Path); !ok {
|
if ok, _ := regexp.MatchString(`^(s3|gcs|logr|file|dendrodb)://(.+)$`, opts.DB.Path); !ok {
|
||||||
log.Fatalf("Invalid path %s. Specify a valid data store configuration path", opts.DB.Path)
|
log.Fatalf("Invalid path %s. Specify a valid data store configuration path", opts.DB.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
db/db.go
1
db/db.go
|
@ -31,7 +31,6 @@ import (
|
||||||
"github.com/abcum/surreal/util/data"
|
"github.com/abcum/surreal/util/data"
|
||||||
"github.com/abcum/surreal/util/uuid"
|
"github.com/abcum/surreal/util/uuid"
|
||||||
|
|
||||||
_ "github.com/abcum/surreal/kvs/mysql"
|
|
||||||
_ "github.com/abcum/surreal/kvs/rixxdb"
|
_ "github.com/abcum/surreal/kvs/rixxdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ import:
|
||||||
version: ^3.2.0
|
version: ^3.2.0
|
||||||
- package: github.com/elithrar/simple-scrypt
|
- package: github.com/elithrar/simple-scrypt
|
||||||
version: ^1.3.0
|
version: ^1.3.0
|
||||||
- package: github.com/go-sql-driver/mysql
|
|
||||||
version: ^1.3.0
|
|
||||||
- package: github.com/gorilla/websocket
|
- package: github.com/gorilla/websocket
|
||||||
version: ^1.2.0
|
version: ^1.2.0
|
||||||
- package: github.com/hashicorp/serf
|
- package: github.com/hashicorp/serf
|
||||||
|
|
|
@ -45,8 +45,6 @@ func New(opts *cnf.Options) (ds *DS, err error) {
|
||||||
db, err = stores["rixxdb"](opts)
|
db, err = stores["rixxdb"](opts)
|
||||||
case strings.HasPrefix(opts.DB.Path, "file://"):
|
case strings.HasPrefix(opts.DB.Path, "file://"):
|
||||||
db, err = stores["rixxdb"](opts)
|
db, err = stores["rixxdb"](opts)
|
||||||
case strings.HasPrefix(opts.DB.Path, "mysql://"):
|
|
||||||
db, err = stores["mysql"](opts)
|
|
||||||
case strings.HasPrefix(opts.DB.Path, "rixxdb://"):
|
case strings.HasPrefix(opts.DB.Path, "rixxdb://"):
|
||||||
db, err = stores["rixxdb"](opts)
|
db, err = stores["rixxdb"](opts)
|
||||||
case strings.HasPrefix(opts.DB.Path, "dendrodb://"):
|
case strings.HasPrefix(opts.DB.Path, "dendrodb://"):
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/abcum/surreal/kvs"
|
|
||||||
"github.com/abcum/surreal/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DB struct {
|
|
||||||
pntr *sql.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Begin(ctx context.Context, writable bool) (txn kvs.TX, err error) {
|
|
||||||
var pntr *sql.Tx
|
|
||||||
if pntr, err = db.pntr.BeginTx(ctx, &sql.TxOptions{}); err != nil {
|
|
||||||
log.WithPrefix("kvs").Errorln(err)
|
|
||||||
err = &kvs.DBError{Err: err}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return &TX{pntr: pntr}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Import(r io.Reader) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Export(w io.Writer) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Close() (err error) {
|
|
||||||
return db.pntr.Close()
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrKvNotExpectedValue occurs when conditionally putting or deleting a key-value item.
|
|
||||||
var ErrTxNotExpectedValue = errors.New("KV val is not expected value")
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
// KV represents a row stored in the database.
|
|
||||||
type KV struct {
|
|
||||||
ver uint64
|
|
||||||
key []byte
|
|
||||||
val []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exi returns whether this key-value item actually exists.
|
|
||||||
func (kv *KV) Exi() bool {
|
|
||||||
return kv.val != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the key for the underlying key-value item.
|
|
||||||
func (kv *KV) Key() []byte {
|
|
||||||
return kv.key
|
|
||||||
}
|
|
||||||
|
|
||||||
// Val returns the value for the underlying key-value item.
|
|
||||||
func (kv *KV) Val() []byte {
|
|
||||||
return kv.val
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ver returns the version for the underlying key-value item.
|
|
||||||
func (kv *KV) Ver() uint64 {
|
|
||||||
return kv.ver
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/abcum/surreal/cnf"
|
|
||||||
"github.com/abcum/surreal/kvs"
|
|
||||||
"github.com/abcum/surreal/log"
|
|
||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
kvs.Register("mysql", func(opts *cnf.Options) (db kvs.DB, err error) {
|
|
||||||
|
|
||||||
var pntr *sql.DB
|
|
||||||
|
|
||||||
path := strings.TrimPrefix(opts.DB.Path, "mysql://")
|
|
||||||
|
|
||||||
if cnf.Settings.DB.Cert.SSL {
|
|
||||||
|
|
||||||
cas := x509.NewCertPool()
|
|
||||||
all := make([]tls.Certificate, 0, 1)
|
|
||||||
car := []byte(cnf.Settings.DB.Cert.CA)
|
|
||||||
crt := []byte(cnf.Settings.DB.Cert.Crt)
|
|
||||||
key := []byte(cnf.Settings.DB.Cert.Key)
|
|
||||||
|
|
||||||
if ok := cas.AppendCertsFromPEM(car); !ok {
|
|
||||||
log.WithPrefix("kvs").Errorln("Failed to append CA file.")
|
|
||||||
}
|
|
||||||
|
|
||||||
par, err := tls.X509KeyPair(crt, key)
|
|
||||||
if err != nil {
|
|
||||||
log.WithPrefix("kvs").Errorln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql.RegisterTLSConfig("default", &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
RootCAs: cas,
|
|
||||||
Certificates: append(all, par),
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pntr, err = sql.Open("mysql", path)
|
|
||||||
if err != nil {
|
|
||||||
log.WithPrefix("kvs").Errorln(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the maximum connection lifetime
|
|
||||||
|
|
||||||
pntr.SetConnMaxLifetime(1 * time.Hour)
|
|
||||||
|
|
||||||
// Output logs to the default logger
|
|
||||||
|
|
||||||
mysql.SetLogger(log.Instance())
|
|
||||||
|
|
||||||
// Set the max number of idle connections
|
|
||||||
|
|
||||||
pntr.SetMaxIdleConns(350)
|
|
||||||
|
|
||||||
// Set the max number of open connections
|
|
||||||
|
|
||||||
pntr.SetMaxOpenConns(350)
|
|
||||||
|
|
||||||
// Return the database pointer
|
|
||||||
|
|
||||||
return &DB{pntr: pntr}, err
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
115
kvs/mysql/sql.go
115
kvs/mysql/sql.go
|
@ -1,115 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
const sqlClr = `
|
|
||||||
DELETE FROM kv
|
|
||||||
WHERE k=?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlClrP = `
|
|
||||||
DELETE FROM kv
|
|
||||||
WHERE k LIKE CONCAT(?, '%')
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlClrR = `
|
|
||||||
DELETE FROM kv
|
|
||||||
WHERE k>=? AND k<?
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlGet = `
|
|
||||||
SELECT * FROM kv
|
|
||||||
WHERE t<=? AND k=?
|
|
||||||
ORDER BY t DESC
|
|
||||||
LIMIT 1
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlGetP = `
|
|
||||||
SELECT q1.t, q1.k, v
|
|
||||||
FROM kv q1
|
|
||||||
JOIN (
|
|
||||||
SELECT k, MAX(t) AS t
|
|
||||||
FROM kv
|
|
||||||
WHERE t<=? AND k LIKE CONCAT(?, '%')
|
|
||||||
GROUP BY k
|
|
||||||
) AS q2
|
|
||||||
ON q1.t = q2.t AND q1.k = q2.k
|
|
||||||
ORDER BY q1.k
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlGetR = `
|
|
||||||
SELECT q1.t, q1.k, v
|
|
||||||
FROM kv q1
|
|
||||||
JOIN (
|
|
||||||
SELECT k, MAX(t) AS t
|
|
||||||
FROM kv
|
|
||||||
WHERE t<=? AND k>=? AND k<?
|
|
||||||
GROUP BY k
|
|
||||||
) AS q2
|
|
||||||
ON q1.t = q2.t AND q1.k = q2.k
|
|
||||||
ORDER BY q1.k
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlDel = `
|
|
||||||
DELETE FROM kv
|
|
||||||
WHERE t<=? AND k=?
|
|
||||||
ORDER BY t DESC
|
|
||||||
LIMIT 1
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlDelP = `
|
|
||||||
DELETE q1 FROM kv
|
|
||||||
JOIN (
|
|
||||||
SELECT k, MAX(t) AS t
|
|
||||||
FROM kv
|
|
||||||
WHERE t<=? AND k LIKE CONCAT(?, '%')
|
|
||||||
GROUP BY k
|
|
||||||
) AS q2
|
|
||||||
ON q1.t = q2.t AND q1.k = q2.k
|
|
||||||
ORDER BY q1.k
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlDelR = `
|
|
||||||
DELETE q1 FROM kv
|
|
||||||
JOIN (
|
|
||||||
SELECT k, MAX(t) AS t
|
|
||||||
FROM kv
|
|
||||||
WHERE t<=? AND k>=? AND k<?
|
|
||||||
GROUP BY k
|
|
||||||
) AS q2
|
|
||||||
ON q1.t = q2.t AND q1.k = q2.k
|
|
||||||
ORDER BY q1.k
|
|
||||||
LIMIT ?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlPut = `
|
|
||||||
INSERT INTO kv
|
|
||||||
(t, k, v)
|
|
||||||
VALUES
|
|
||||||
(?, ?, ?)
|
|
||||||
ON DUPLICATE KEY UPDATE v=?
|
|
||||||
`
|
|
||||||
|
|
||||||
const sqlPutN = `
|
|
||||||
INSERT INTO kv
|
|
||||||
(t, k, v)
|
|
||||||
VALUES
|
|
||||||
(?, ?, ?)
|
|
||||||
`
|
|
457
kvs/mysql/tx.go
457
kvs/mysql/tx.go
|
@ -1,457 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/abcum/surreal/cnf"
|
|
||||||
"github.com/abcum/surreal/kvs"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TX struct {
|
|
||||||
done bool
|
|
||||||
pntr *sql.Tx
|
|
||||||
lock sync.Mutex
|
|
||||||
stmt struct {
|
|
||||||
clr *sql.Stmt
|
|
||||||
clrP *sql.Stmt
|
|
||||||
clrR *sql.Stmt
|
|
||||||
get *sql.Stmt
|
|
||||||
getP *sql.Stmt
|
|
||||||
getR *sql.Stmt
|
|
||||||
del *sql.Stmt
|
|
||||||
delP *sql.Stmt
|
|
||||||
delR *sql.Stmt
|
|
||||||
put *sql.Stmt
|
|
||||||
putN *sql.Stmt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const maximum = math.MaxUint64
|
|
||||||
|
|
||||||
func dec(src []byte) (dst []byte, err error) {
|
|
||||||
if dst, err = decrypt(cnf.Settings.DB.Key, src); err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func enc(src []byte) (dst []byte, err error) {
|
|
||||||
if dst, err = encrypt(cnf.Settings.DB.Key, src); err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func one(res *sql.Rows, err error) (kvs.KV, error) {
|
|
||||||
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Close()
|
|
||||||
|
|
||||||
var out = &KV{}
|
|
||||||
|
|
||||||
for res.Next() {
|
|
||||||
err = res.Scan(&out.ver, &out.key, &out.val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
out.val, err = dec(out.val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = res.Err(); err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func many(res *sql.Rows, err error) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Close()
|
|
||||||
|
|
||||||
var out []kvs.KV
|
|
||||||
|
|
||||||
for res.Next() {
|
|
||||||
kv := &KV{}
|
|
||||||
err = res.Scan(&kv.ver, &kv.key, &kv.val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
kv.val, err = dec(kv.val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
if kv.val != nil {
|
|
||||||
out = append(out, kv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = res.Err(); err != nil {
|
|
||||||
return nil, &kvs.DBError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Closed() bool {
|
|
||||||
return tx.done
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Cancel() error {
|
|
||||||
tx.done = true
|
|
||||||
return tx.pntr.Rollback()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Commit() error {
|
|
||||||
tx.done = true
|
|
||||||
return tx.pntr.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Clr(ctx context.Context, key []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.clr == nil {
|
|
||||||
tx.stmt.clr, _ = tx.pntr.PrepareContext(ctx, sqlClr)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.clr.QueryContext(ctx, key)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) ClrP(ctx context.Context, key []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.clrP == nil {
|
|
||||||
tx.stmt.clrP, _ = tx.pntr.PrepareContext(ctx, sqlClrP)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.clrP.QueryContext(ctx, key, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) ClrR(ctx context.Context, beg []byte, end []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.clrR == nil {
|
|
||||||
tx.stmt.clrR, _ = tx.pntr.PrepareContext(ctx, sqlClrR)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.clrR.QueryContext(ctx, beg, end, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Get(ctx context.Context, ver int64, key []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.get == nil {
|
|
||||||
tx.stmt.get, _ = tx.pntr.PrepareContext(ctx, sqlGet)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.get.QueryContext(ctx, ver, key)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) GetP(ctx context.Context, ver int64, key []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.getP == nil {
|
|
||||||
tx.stmt.getP, _ = tx.pntr.PrepareContext(ctx, sqlGetP)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.getP.QueryContext(ctx, ver, key, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) GetR(ctx context.Context, ver int64, beg []byte, end []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.getR == nil {
|
|
||||||
tx.stmt.getR, _ = tx.pntr.PrepareContext(ctx, sqlGetR)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.getR.QueryContext(ctx, ver, beg, end, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Del(ctx context.Context, ver int64, key []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.del == nil {
|
|
||||||
tx.stmt.del, _ = tx.pntr.PrepareContext(ctx, sqlDel)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.del.QueryContext(ctx, ver, key)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) DelC(ctx context.Context, ver int64, key []byte, exp []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var now kvs.KV
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
// Get the item at the key
|
|
||||||
|
|
||||||
if tx.stmt.get == nil {
|
|
||||||
tx.stmt.get, _ = tx.pntr.PrepareContext(ctx, sqlGet)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.get.QueryContext(ctx, ver, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
now, err = one(res, err)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the values match
|
|
||||||
|
|
||||||
if !alter(now.Val(), exp) {
|
|
||||||
return nil, ErrTxNotExpectedValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If they match then delete
|
|
||||||
|
|
||||||
if tx.stmt.del == nil {
|
|
||||||
tx.stmt.del, _ = tx.pntr.PrepareContext(ctx, sqlDel)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.del.QueryContext(ctx, ver, key)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) DelP(ctx context.Context, ver int64, key []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.delP == nil {
|
|
||||||
tx.stmt.delP, _ = tx.pntr.PrepareContext(ctx, sqlDelP)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.delP.QueryContext(ctx, ver, key, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) DelR(ctx context.Context, ver int64, beg []byte, end []byte, max uint64) ([]kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
if max == 0 {
|
|
||||||
max = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.delR == nil {
|
|
||||||
tx.stmt.delR, _ = tx.pntr.PrepareContext(ctx, sqlDelR)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.delR.QueryContext(ctx, ver, beg, end, max)
|
|
||||||
|
|
||||||
return many(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) Put(ctx context.Context, ver int64, key []byte, val []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
val, err = enc(val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.lock.Lock()
|
|
||||||
defer tx.lock.Unlock()
|
|
||||||
|
|
||||||
if tx.stmt.put == nil {
|
|
||||||
tx.stmt.put, _ = tx.pntr.PrepareContext(ctx, sqlPut)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.put.QueryContext(ctx, ver, key, val, val)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *TX) PutC(ctx context.Context, ver int64, key []byte, val []byte, exp []byte) (kvs.KV, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var now kvs.KV
|
|
||||||
var res *sql.Rows
|
|
||||||
|
|
||||||
val, err = enc(val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch exp {
|
|
||||||
|
|
||||||
case nil:
|
|
||||||
|
|
||||||
if tx.stmt.putN == nil {
|
|
||||||
tx.stmt.putN, _ = tx.pntr.PrepareContext(ctx, sqlPutN)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.putN.QueryContext(ctx, ver, key, val)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
default:
|
|
||||||
|
|
||||||
// Get the item at the key
|
|
||||||
|
|
||||||
if tx.stmt.get == nil {
|
|
||||||
tx.stmt.get, _ = tx.pntr.PrepareContext(ctx, sqlGet)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.get.QueryContext(ctx, ver, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
now, err = one(res, err)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the values match
|
|
||||||
|
|
||||||
if !check(now.Val(), exp) {
|
|
||||||
return nil, ErrTxNotExpectedValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If they match then delete
|
|
||||||
|
|
||||||
if tx.stmt.del == nil {
|
|
||||||
tx.stmt.put, _ = tx.pntr.PrepareContext(ctx, sqlPut)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err = tx.stmt.put.QueryContext(ctx, ver, key, val, val)
|
|
||||||
|
|
||||||
return one(res, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
// Copyright © 2016 Abcum Ltd
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
|
|
||||||
|
|
||||||
// Used to see if we can conditionally put a value. We can only put
|
|
||||||
// a value if the value is the same, or if both items are nil.
|
|
||||||
func check(a, b []byte) bool {
|
|
||||||
if a != nil && b != nil {
|
|
||||||
return bytes.Equal(a, b)
|
|
||||||
} else if a == nil && b == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to see if we can conditionally del a value. We can only del
|
|
||||||
// a value if the value is the same, and neither item is nil.
|
|
||||||
func alter(a, b []byte) bool {
|
|
||||||
if a != nil && b != nil {
|
|
||||||
return bytes.Equal(a, b)
|
|
||||||
} else if a == nil && b == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encrypt(key []byte, src []byte) (dst []byte, err error) {
|
|
||||||
|
|
||||||
if key == nil || len(key) == 0 || len(src) == 0 {
|
|
||||||
return src, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initiate AES
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
|
|
||||||
// Initiate cipher
|
|
||||||
cipher, _ := cipher.NewGCM(block)
|
|
||||||
|
|
||||||
// Initiate nonce
|
|
||||||
nonce := random(12)
|
|
||||||
|
|
||||||
dst = cipher.Seal(nil, nonce, src, nil)
|
|
||||||
|
|
||||||
dst = append(nonce[:], dst[:]...)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func decrypt(key []byte, src []byte) (dst []byte, err error) {
|
|
||||||
|
|
||||||
if key == nil || len(key) == 0 || len(src) == 0 {
|
|
||||||
return src, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Corrupt
|
|
||||||
if len(src) < 12 {
|
|
||||||
return src, errors.New("Invalid data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initiate AES
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
|
|
||||||
// Initiate cipher
|
|
||||||
cipher, _ := cipher.NewGCM(block)
|
|
||||||
|
|
||||||
return cipher.Open(nil, src[:12], src[12:], nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func random(l int) []byte {
|
|
||||||
|
|
||||||
if l == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
t := len(chars)
|
|
||||||
m := 255 - (256 % t)
|
|
||||||
b := make([]byte, l)
|
|
||||||
r := make([]byte, l+(l/4))
|
|
||||||
|
|
||||||
for {
|
|
||||||
|
|
||||||
rand.Read(r)
|
|
||||||
|
|
||||||
for _, rb := range r {
|
|
||||||
c := int(rb)
|
|
||||||
if c > m {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
b[i] = chars[c%t]
|
|
||||||
i++
|
|
||||||
if i == l {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue