mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 17:15:56 +00:00
Merge branch 'master' into limit-cluster
This commit is contained in:
commit
e0f25f1d20
12 changed files with 265 additions and 76 deletions
2
api.go
2
api.go
|
|
@ -1827,7 +1827,7 @@ func (api *API) TranslateIDs(ctx context.Context, r io.Reader) (_ []byte, err er
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if keys, err = field.TranslateStore().TranslateIDs(req.IDs); err != nil {
|
||||
} else if keys, err = api.cluster.translateFieldListIDs(field, req.IDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
badger "github.com/dgraph-io/badger/v2"
|
||||
badgeroptions "github.com/dgraph-io/badger/v2/options"
|
||||
"github.com/pilosa/pilosa/v2/hash"
|
||||
"github.com/pilosa/pilosa/v2/rbf"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
"github.com/pilosa/pilosa/v2/testhook"
|
||||
"github.com/pilosa/pilosa/v2/txkey"
|
||||
|
|
@ -660,7 +661,7 @@ func (tx *BadgerTx) Type() string {
|
|||
|
||||
func (tx *BadgerTx) UseRowCache() bool {
|
||||
//the row cache speeds up queries.
|
||||
return false
|
||||
return rbf.EnableRowCache
|
||||
}
|
||||
|
||||
// overWriteOurAllocs provides detection of memory
|
||||
|
|
|
|||
40
cluster.go
40
cluster.go
|
|
@ -2377,6 +2377,46 @@ func (c *cluster) translateFieldKeys(ctx context.Context, field *Field, keys []s
|
|||
return ids, nil
|
||||
}
|
||||
|
||||
func (c *cluster) translateFieldIDs(field *Field, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
idList := make([]uint64, len(ids))
|
||||
{
|
||||
i := 0
|
||||
for id := range ids {
|
||||
idList[i] = id
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
keyList, err := c.translateFieldListIDs(field, idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mapped := make(map[uint64]string, len(idList))
|
||||
for i, key := range keyList {
|
||||
mapped[idList[i]] = key
|
||||
}
|
||||
return mapped, nil
|
||||
}
|
||||
|
||||
func (c *cluster) translateFieldListIDs(field *Field, ids []uint64) (keys []string, err error) {
|
||||
coordinator := c.coordinatorNode()
|
||||
if coordinator == nil {
|
||||
return nil, errors.Errorf("translating field(%s/%s) ids(%v) - cannot find coordinator node", field.Index(), field.Name(), ids)
|
||||
}
|
||||
|
||||
if c.Node.ID == coordinator.ID {
|
||||
keys, err = field.TranslateStore().TranslateIDs(ids)
|
||||
} else {
|
||||
keys, err = c.InternalClient.TranslateIDsNode(context.Background(), &coordinator.URI, field.Index(), field.Name(), ids)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "translating field(%s/%s) ids(%v)", field.Index(), field.Name(), ids)
|
||||
}
|
||||
|
||||
return keys, err
|
||||
}
|
||||
|
||||
func (c *cluster) translateIndexKey(ctx context.Context, indexName string, key string, writable bool) (uint64, error) {
|
||||
keyMap, err := c.translateIndexKeySet(ctx, indexName, map[string]struct{}{key: struct{}{}}, writable)
|
||||
if err != nil {
|
||||
|
|
|
|||
28
executor.go
28
executor.go
|
|
@ -5090,26 +5090,6 @@ func (e *executor) collectResultIDs(index string, idx *Index, call *pql.Call, re
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *executor) translateFieldIDs(field *Field, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
idList := make([]uint64, len(ids))
|
||||
{
|
||||
i := 0
|
||||
for id := range ids {
|
||||
idList[i] = id
|
||||
i++
|
||||
}
|
||||
}
|
||||
keyList, err := field.TranslateStore().TranslateIDs(idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mapped := make(map[uint64]string, len(idList))
|
||||
for i, key := range keyList {
|
||||
mapped[idList[i]] = key
|
||||
}
|
||||
return mapped, nil
|
||||
}
|
||||
|
||||
// preTranslateMatrixSet translates the IDs of a set field in an extracted matrix.
|
||||
func (e *executor) preTranslateMatrixSet(mat ExtractedIDMatrix, fieldIdx uint, field *Field) (map[uint64]string, error) {
|
||||
ids := make(map[uint64]struct{}, len(mat.Columns))
|
||||
|
|
@ -5119,7 +5099,7 @@ func (e *executor) preTranslateMatrixSet(mat ExtractedIDMatrix, fieldIdx uint, f
|
|||
}
|
||||
}
|
||||
|
||||
return e.translateFieldIDs(field, ids)
|
||||
return e.Cluster.translateFieldIDs(field, ids)
|
||||
}
|
||||
|
||||
func (e *executor) translateResult(ctx context.Context, index string, idx *Index, call *pql.Call, result interface{}, idSet map[uint64]string) (_ interface{}, err error) {
|
||||
|
|
@ -5205,7 +5185,7 @@ func (e *executor) translateResult(ctx context.Context, index string, idx *Index
|
|||
for i := range result.Pairs {
|
||||
ids[i] = result.Pairs[i].ID
|
||||
}
|
||||
keys, err := field.TranslateStore().TranslateIDs(ids)
|
||||
keys, err := e.Cluster.translateFieldListIDs(field, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -5256,7 +5236,7 @@ func (e *executor) translateResult(ctx context.Context, index string, idx *Index
|
|||
|
||||
fieldTranslations := make(map[string]map[uint64]string)
|
||||
for field, ids := range fieldIDs {
|
||||
trans, err := e.translateFieldIDs(field, ids)
|
||||
trans, err := e.Cluster.translateFieldIDs(field, ids)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "translating IDs in field %q", field.Name())
|
||||
}
|
||||
|
|
@ -5308,7 +5288,7 @@ func (e *executor) translateResult(ctx context.Context, index string, idx *Index
|
|||
if field := idx.Field(fieldName); field == nil {
|
||||
return nil, newNotFoundError(ErrFieldNotFound, fieldName)
|
||||
} else if field.Keys() {
|
||||
keys, err := field.TranslateStore().TranslateIDs(result)
|
||||
keys, err := e.Cluster.translateFieldListIDs(field, result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "translating row IDs")
|
||||
}
|
||||
|
|
|
|||
82
lmdb.go
82
lmdb.go
|
|
@ -33,6 +33,7 @@ import (
|
|||
|
||||
"github.com/glycerine/lmdb-go/lmdb"
|
||||
"github.com/pilosa/pilosa/v2/hash"
|
||||
"github.com/pilosa/pilosa/v2/rbf"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
"github.com/pilosa/pilosa/v2/txkey"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -274,10 +275,7 @@ func (w *LMDBWrapper) CleanupTx(tx Tx) {
|
|||
}
|
||||
|
||||
func (tx *LMDBTx) IsDone() (done bool) {
|
||||
tx.mu.Lock()
|
||||
done = tx.unlocked
|
||||
tx.mu.Unlock()
|
||||
return
|
||||
return atomic.LoadInt64(&tx.unlocked) == 1
|
||||
}
|
||||
|
||||
func (w *LMDBWrapper) OpenListString() (r string) {
|
||||
|
|
@ -434,9 +432,11 @@ func (w *LMDBWrapper) NewTx(write bool, initialIndexName string, o Txo) (tx Tx,
|
|||
}
|
||||
tx = ltx
|
||||
|
||||
w.muDb.Lock()
|
||||
w.openTx[ltx] = true
|
||||
w.muDb.Unlock()
|
||||
if isDebugRun {
|
||||
w.muDb.Lock()
|
||||
w.openTx[ltx] = true
|
||||
w.muDb.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -445,13 +445,14 @@ func (w *LMDBWrapper) Close() (err error) {
|
|||
w.muDb.Lock()
|
||||
defer w.muDb.Unlock()
|
||||
if !w.closed {
|
||||
// complain if there are still Tx in flight, b/c otherwise we will see
|
||||
// the somewhat mysterious 'panic: should not be in ReadSlot.free() with slot still owned by gid=107043; refCount=1'
|
||||
if len(w.openTx) > 0 {
|
||||
AlwaysPrintf("error: cannot close LMDBWrapper with Tx still in flight.")
|
||||
return
|
||||
if isDebugRun {
|
||||
// complain if there are still Tx in flight, b/c otherwise we will see
|
||||
// the somewhat mysterious 'panic: should not be in ReadSlot.free() with slot still owned by gid=107043; refCount=1'
|
||||
if len(w.openTx) > 0 {
|
||||
AlwaysPrintf("error: cannot close LMDBWrapper with Tx still in flight.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.reg.unregister(w)
|
||||
w.closed = true
|
||||
w.env.CloseDBI(w.dbi)
|
||||
|
|
@ -494,7 +495,7 @@ type LMDBTx struct {
|
|||
|
||||
DeleteEmptyContainer bool
|
||||
|
||||
unlocked bool // runtime.UnlockOSThread has been done.
|
||||
unlocked int64 // runtime.UnlockOSThread has been done if > 0
|
||||
|
||||
o Txo
|
||||
|
||||
|
|
@ -535,7 +536,7 @@ func (tx *LMDBTx) Type() string {
|
|||
}
|
||||
|
||||
func (tx *LMDBTx) UseRowCache() bool {
|
||||
return false
|
||||
return rbf.EnableRowCache
|
||||
}
|
||||
|
||||
// Pointer gives us a memory address for the underlying transaction for debugging.
|
||||
|
|
@ -545,15 +546,21 @@ func (tx *LMDBTx) Pointer() string {
|
|||
return fmt.Sprintf("%p", tx)
|
||||
}
|
||||
|
||||
const isDebugRun = false
|
||||
|
||||
// Rollback rolls back the transaction.
|
||||
func (tx *LMDBTx) Rollback() {
|
||||
tx.sanity()
|
||||
|
||||
alreadyDone := atomic.CompareAndSwapInt64(&tx.unlocked, 0, 1)
|
||||
if !alreadyDone {
|
||||
return
|
||||
}
|
||||
//vv("lmdb rollback tx _sn_ %v; stack \n%v", tx.sn) // , stack())
|
||||
|
||||
tx.Db.muDb.Lock()
|
||||
delete(tx.Db.openTx, tx)
|
||||
tx.Db.muDb.Unlock()
|
||||
if isDebugRun {
|
||||
tx.sanity()
|
||||
tx.Db.muDb.Lock()
|
||||
delete(tx.Db.openTx, tx)
|
||||
tx.Db.muDb.Unlock()
|
||||
}
|
||||
|
||||
tx.mu.Lock()
|
||||
defer tx.mu.Unlock()
|
||||
|
|
@ -561,25 +568,26 @@ func (tx *LMDBTx) Rollback() {
|
|||
//tx.debugOnlyGidcheck()
|
||||
tx.tx.Abort() // must hold tx.mu mutex lock
|
||||
|
||||
if !tx.unlocked {
|
||||
runtime.UnlockOSThread()
|
||||
tx.unlocked = true
|
||||
tx.o.dbs.Cleanup(tx)
|
||||
}
|
||||
// use CAS above instead of testing a bool unlocked.
|
||||
runtime.UnlockOSThread()
|
||||
tx.o.dbs.Cleanup(tx)
|
||||
}
|
||||
|
||||
// Commit commits the transaction to permanent storage.
|
||||
// Commits can handle up to 100k updates to fragments
|
||||
// at once, but not more. This is a LMDBDB imposed limit.
|
||||
func (tx *LMDBTx) Commit() error {
|
||||
tx.sanity()
|
||||
|
||||
alreadyDone := atomic.CompareAndSwapInt64(&tx.unlocked, 0, 1)
|
||||
if !alreadyDone {
|
||||
return nil
|
||||
}
|
||||
//vv("lmdb commit tx _sn_ %v; stack \n%v", tx.sn, stack())
|
||||
|
||||
tx.Db.muDb.Lock()
|
||||
delete(tx.Db.openTx, tx)
|
||||
tx.Db.muDb.Unlock()
|
||||
|
||||
if isDebugRun {
|
||||
tx.sanity()
|
||||
tx.Db.muDb.Lock()
|
||||
delete(tx.Db.openTx, tx)
|
||||
tx.Db.muDb.Unlock()
|
||||
}
|
||||
tx.mu.Lock()
|
||||
defer tx.mu.Unlock()
|
||||
|
||||
|
|
@ -587,11 +595,9 @@ func (tx *LMDBTx) Commit() error {
|
|||
err := tx.tx.Commit() // must hold tx.mu mutex lock
|
||||
panicOn(err)
|
||||
|
||||
if !tx.unlocked {
|
||||
runtime.UnlockOSThread()
|
||||
tx.unlocked = true
|
||||
tx.o.dbs.Cleanup(tx)
|
||||
}
|
||||
// replace the if !tx.unlocked with the CAS on tx.unlocked above.
|
||||
runtime.UnlockOSThread()
|
||||
tx.o.dbs.Cleanup(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
37
pprof.go
37
pprof.go
|
|
@ -29,7 +29,7 @@ func CPUProfileForDur(dur time.Duration, outpath string) {
|
|||
// per-query pprof output:
|
||||
txsrc := os.Getenv("PILOSA_TXSRC")
|
||||
if txsrc == "" {
|
||||
txsrc = "roaring"
|
||||
txsrc = DefaultTxsrc
|
||||
}
|
||||
path := outpath + "." + txsrc
|
||||
f, err := os.Create(path)
|
||||
|
|
@ -53,7 +53,7 @@ func MemProfileForDur(dur time.Duration, outpath string) {
|
|||
// per-query pprof output:
|
||||
txsrc := os.Getenv("PILOSA_TXSRC")
|
||||
if txsrc == "" {
|
||||
txsrc = "roaring"
|
||||
txsrc = DefaultTxsrc
|
||||
}
|
||||
path := outpath + "." + txsrc
|
||||
f, err := os.Create(path)
|
||||
|
|
@ -73,3 +73,36 @@ func MemProfileForDur(dur time.Duration, outpath string) {
|
|||
AlwaysPrintf("wrote memory profile after dur '%v', output: '%v'", dur, path)
|
||||
}()
|
||||
}
|
||||
|
||||
type pprofProfile struct {
|
||||
fdCpu *os.File
|
||||
}
|
||||
|
||||
var _ = newPprof
|
||||
var _ = pprofProfile{}
|
||||
|
||||
// for manually calling Close() to stop profiling.
|
||||
func newPprof() (pp *pprofProfile) {
|
||||
pp = &pprofProfile{}
|
||||
f, err := os.Create("cpu.manual.pprof")
|
||||
panicOn(err)
|
||||
pp.fdCpu = f
|
||||
|
||||
_ = pprof.StartCPUProfile(pp.fdCpu)
|
||||
return
|
||||
}
|
||||
|
||||
func (pp *pprofProfile) Close() {
|
||||
|
||||
pprof.StopCPUProfile()
|
||||
pp.fdCpu.Close()
|
||||
|
||||
f, err := os.Create("mem.manual.pprof")
|
||||
panicOn(err)
|
||||
|
||||
runtime.GC() // get up-to-date statistics
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
panic(fmt.Sprintf("could not write memory profile: %v", err))
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
|
|
|||
2
rbf.go
2
rbf.go
|
|
@ -68,7 +68,7 @@ func (w *RbfDBWrapper) CleanupTx(tx Tx) {
|
|||
r.done = true
|
||||
r.mu.Unlock()
|
||||
|
||||
// try not to old r.mu while locking w.muDb
|
||||
// try not to hold r.mu while locking w.muDb
|
||||
w.muDb.Lock()
|
||||
|
||||
delete(w.openTx, r)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
// if enableRowCache, then we must not return mmap-ed memory
|
||||
// directly, but only a copy.
|
||||
const EnableRowCache = false
|
||||
const EnableRowCache = true
|
||||
|
||||
// DoAllocZero means we copy mmap read data and
|
||||
// wipe it afterwards to catch retention of data
|
||||
|
|
|
|||
3
rrtx.go
3
rrtx.go
|
|
@ -25,6 +25,7 @@ import (
|
|||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/rbf"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -62,7 +63,7 @@ func (tx *RoaringTx) Dump(short bool, shard uint64) {
|
|||
}
|
||||
|
||||
func (tx *RoaringTx) UseRowCache() bool {
|
||||
return false
|
||||
return rbf.EnableRowCache
|
||||
}
|
||||
|
||||
func (tx *RoaringTx) SliceOfShards(index, field, view, optionalViewPath string) (sliceOfShards []uint64, err error) {
|
||||
|
|
|
|||
|
|
@ -557,7 +557,13 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64ArrayVal{Uint64ArrayVal: &pb.Uint64Array{Vals: ids.Rows}}})
|
||||
colAdded++
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "mutex":
|
||||
|
|
@ -589,6 +595,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "int":
|
||||
|
|
@ -656,6 +665,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -680,6 +692,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "bool":
|
||||
|
|
@ -711,6 +726,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
} else {
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "time":
|
||||
|
|
|
|||
|
|
@ -432,6 +432,32 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
},
|
||||
eq: equal,
|
||||
},
|
||||
{
|
||||
// Extract(Limit(ConstRow(columns=[2]), limit=100, offset=0),Rows(age),Rows(color),Rows(height),Rows(score))
|
||||
sql: "select * from grouper",
|
||||
exp: tableResponse{
|
||||
headers: []columnInfo{
|
||||
{"_id", "uint64"},
|
||||
{"age", "int64"},
|
||||
{"color", "[]string"},
|
||||
{"height", "int64"},
|
||||
{"score", "int64"},
|
||||
},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(1), int64(27), []string{"blue"}, int64(20), int64(-10)}},
|
||||
{[]columnResponse{uint64(2), int64(16), []string{"blue"}, int64(30), int64(-8)}},
|
||||
{[]columnResponse{uint64(3), int64(19), []string{"red"}, int64(40), int64(6)}},
|
||||
{[]columnResponse{uint64(4), int64(27), []string{"green"}, int64(50), int64(0)}},
|
||||
{[]columnResponse{uint64(5), int64(16), []string{"blue"}, int64(60), int64(-2)}},
|
||||
{[]columnResponse{uint64(6), int64(34), []string{"blue"}, int64(70), int64(100)}},
|
||||
{[]columnResponse{uint64(7), int64(27), []string{"blue"}, int64(80), int64(0)}},
|
||||
{[]columnResponse{uint64(8), int64(16), []string{}, int64(90), int64(-13)}},
|
||||
{[]columnResponse{uint64(9), int64(16), []string{"red"}, int64(100), int64(80)}},
|
||||
{[]columnResponse{uint64(10), int64(31), []string{"red"}, int64(110), int64(-2)}},
|
||||
},
|
||||
},
|
||||
eq: equal,
|
||||
},
|
||||
// join
|
||||
{
|
||||
// Count(Intersect(All(),Distinct(Row(grouperid!=null),index='joiner',field='grouperid')))
|
||||
|
|
@ -471,7 +497,6 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
headers: []columnInfo{{"_id", "uint64"}},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(3)}},
|
||||
{[]columnResponse{uint64(8)}},
|
||||
{[]columnResponse{uint64(9)}},
|
||||
},
|
||||
},
|
||||
|
|
@ -484,7 +509,6 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
headers: []columnInfo{{"_id", "uint64"}},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(3)}},
|
||||
{[]columnResponse{uint64(8)}},
|
||||
{[]columnResponse{uint64(9)}},
|
||||
},
|
||||
},
|
||||
|
|
@ -630,7 +654,7 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
},
|
||||
rows: []row{
|
||||
{[]columnResponse{int64(16), "blue", uint64(2)}},
|
||||
{[]columnResponse{int64(16), "red", uint64(2)}},
|
||||
{[]columnResponse{int64(16), "red", uint64(1)}},
|
||||
{[]columnResponse{int64(19), "red", uint64(1)}},
|
||||
{[]columnResponse{int64(27), "blue", uint64(2)}},
|
||||
{[]columnResponse{int64(27), "green", uint64(1)}},
|
||||
|
|
@ -764,7 +788,6 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
exp: tableResponse{
|
||||
headers: []columnInfo{{"_id", "uint64"}},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(8)}},
|
||||
{[]columnResponse{uint64(9)}},
|
||||
},
|
||||
},
|
||||
|
|
@ -777,7 +800,6 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
exp: tableResponse{
|
||||
headers: []columnInfo{{"_id", "uint64"}},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(8)}},
|
||||
{[]columnResponse{uint64(9)}},
|
||||
},
|
||||
},
|
||||
|
|
@ -789,7 +811,6 @@ func TestQuerySQLUnary(t *testing.T) {
|
|||
exp: tableResponse{
|
||||
headers: []columnInfo{{"_id", "uint64"}},
|
||||
rows: []row{
|
||||
{[]columnResponse{uint64(8)}},
|
||||
{[]columnResponse{uint64(9)}},
|
||||
},
|
||||
},
|
||||
|
|
@ -872,7 +893,6 @@ func setUpTestQuerySQLUnary(ctx context.Context, t *testing.T) (gh *server.GRPCH
|
|||
6: "blue",
|
||||
7: "blue",
|
||||
3: "red",
|
||||
8: "red",
|
||||
9: "red",
|
||||
10: "red",
|
||||
4: "green",
|
||||
|
|
|
|||
|
|
@ -605,3 +605,93 @@ func TestTranslation_Coordinator(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestTranslation_TranslateIDsOnCluster(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 4,
|
||||
[]server.CommandOption{
|
||||
server.OptCommandServerOptions(
|
||||
pilosa.OptServerIsCoordinator(true),
|
||||
pilosa.OptServerNodeID("node0"),
|
||||
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
|
||||
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
|
||||
)},
|
||||
[]server.CommandOption{
|
||||
server.OptCommandServerOptions(
|
||||
pilosa.OptServerIsCoordinator(false),
|
||||
pilosa.OptServerNodeID("node1"),
|
||||
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
|
||||
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
|
||||
)},
|
||||
[]server.CommandOption{
|
||||
server.OptCommandServerOptions(
|
||||
pilosa.OptServerIsCoordinator(false),
|
||||
pilosa.OptServerNodeID("node2"),
|
||||
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
|
||||
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
|
||||
)},
|
||||
[]server.CommandOption{
|
||||
server.OptCommandServerOptions(
|
||||
pilosa.OptServerIsCoordinator(false),
|
||||
pilosa.OptServerNodeID("node3"),
|
||||
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
|
||||
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
|
||||
)},
|
||||
)
|
||||
defer c.Close()
|
||||
|
||||
node0 := c.GetNode(0)
|
||||
node3 := c.GetNode(3)
|
||||
|
||||
ctx := context.Background()
|
||||
idx, fld := "i", "f"
|
||||
// Create an index with keys.
|
||||
if _, err := node0.API.CreateIndex(ctx, idx, pilosa.IndexOptions{Keys: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Create an index with keys.
|
||||
if _, err := node0.API.CreateField(ctx, idx, fld, pilosa.OptFieldKeys()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
keys := []string{"k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9"}
|
||||
// write a new key and get id
|
||||
req, err := node0.API.Serializer.Marshal(&pilosa.TranslateKeysRequest{
|
||||
Index: idx,
|
||||
Field: fld,
|
||||
Keys: keys,
|
||||
NotWritable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if buf, err := node0.API.TranslateKeys(ctx, bytes.NewReader(req)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
var (
|
||||
respKeys pilosa.TranslateKeysResponse
|
||||
respIDs pilosa.TranslateIDsResponse
|
||||
)
|
||||
if err = node0.API.Serializer.Unmarshal(buf, &respKeys); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ids := respKeys.IDs
|
||||
|
||||
// translate ids
|
||||
req, err = node3.API.Serializer.Marshal(&pilosa.TranslateIDsRequest{
|
||||
Index: idx,
|
||||
Field: fld,
|
||||
IDs: ids,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if buf, err = node3.API.TranslateIDs(ctx, bytes.NewReader(req)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = node3.API.Serializer.Unmarshal(buf, &respIDs); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(respIDs.Keys, keys) {
|
||||
t.Fatalf("TranslateIDs(%+v): expected: %+v, got: %+v", ids, keys, respIDs.Keys)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue