mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Merge pull request #1192 from travisturner/inverse-slice-on-remote
make sure that slices is treated as inverseSlices on inverse calls
This commit is contained in:
commit
ea2921c192
2 changed files with 67 additions and 23 deletions
46
executor.go
46
executor.go
|
|
@ -84,29 +84,31 @@ func (e *Executor) Execute(ctx context.Context, index string, q *pql.Query, slic
|
|||
// to send queries to different slices based on orientation.
|
||||
var inverseSlices []uint64
|
||||
|
||||
// If slices aren't specified, then include all of them.
|
||||
if len(slices) == 0 {
|
||||
// Determine slices and inverseSlices for use in e.executeCall().
|
||||
if needsSlices {
|
||||
// Round up the number of slices.
|
||||
idx := e.Holder.Index(index)
|
||||
if idx == nil {
|
||||
return nil, ErrIndexNotFound
|
||||
}
|
||||
maxSlice := idx.MaxSlice()
|
||||
maxInverseSlice := idx.MaxInverseSlice()
|
||||
// If slices are specified, then use that value for slices or
|
||||
// inverseSlices. If slices aren't specified, then include all of them.
|
||||
if len(slices) > 0 {
|
||||
// For inverse queries, the values of `slices` provided to the Execute() method
|
||||
// on the remote node actually represents inverseSlices.
|
||||
inverseSlices = slices
|
||||
} else if needsSlices {
|
||||
// Round up the number of slices.
|
||||
idx := e.Holder.Index(index)
|
||||
if idx == nil {
|
||||
return nil, ErrIndexNotFound
|
||||
}
|
||||
maxSlice := idx.MaxSlice()
|
||||
maxInverseSlice := idx.MaxInverseSlice()
|
||||
|
||||
// Generate a slices of all slices.
|
||||
slices = make([]uint64, maxSlice+1)
|
||||
for i := range slices {
|
||||
slices[i] = uint64(i)
|
||||
}
|
||||
// Generate a slices of all slices.
|
||||
slices = make([]uint64, maxSlice+1)
|
||||
for i := range slices {
|
||||
slices[i] = uint64(i)
|
||||
}
|
||||
|
||||
// Generate a slices of all inverse slices.
|
||||
inverseSlices = make([]uint64, maxInverseSlice+1)
|
||||
for i := range inverseSlices {
|
||||
inverseSlices[i] = uint64(i)
|
||||
}
|
||||
// Generate a slices of all inverse slices.
|
||||
inverseSlices = make([]uint64, maxInverseSlice+1)
|
||||
for i := range inverseSlices {
|
||||
inverseSlices[i] = uint64(i)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +120,6 @@ func (e *Executor) Execute(ctx context.Context, index string, q *pql.Query, slic
|
|||
// Execute each call serially.
|
||||
results := make([]interface{}, 0, len(q.Calls))
|
||||
for _, call := range q.Calls {
|
||||
|
||||
if call.SupportsInverse() && needsSlices {
|
||||
// Fetch frame & row label based on argument.
|
||||
frame, _ := call.Args["frame"].(string)
|
||||
|
|
@ -147,7 +148,6 @@ func (e *Executor) Execute(ctx context.Context, index string, q *pql.Query, slic
|
|||
|
||||
// executeCall executes a call.
|
||||
func (e *Executor) executeCall(ctx context.Context, index string, c *pql.Call, slices []uint64, opt *ExecOptions) (interface{}, error) {
|
||||
|
||||
if err := e.validateCallArgs(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/pilosa/pilosa"
|
||||
|
|
@ -234,6 +235,49 @@ func TestMain_SetColumnAttrs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure inverse slices get handled correctly in a multi-node query.
|
||||
func TestMain_InverseSlices(t *testing.T) {
|
||||
mains := test.MustRunMainWithCluster(t, 2)
|
||||
|
||||
m0 := mains[0]
|
||||
m1 := mains[1]
|
||||
|
||||
// Make sure to use node0 in the cluster.
|
||||
var m *test.Main
|
||||
if m0.Server.NodeID < m1.Server.NodeID {
|
||||
m = m0
|
||||
} else {
|
||||
m = m1
|
||||
}
|
||||
|
||||
// Create frames.
|
||||
client := m.Client()
|
||||
if err := client.CreateIndex(context.Background(), "i", pilosa.IndexOptions{}); err != nil && err != pilosa.ErrIndexExists {
|
||||
t.Fatal("create index:", err)
|
||||
}
|
||||
if err := client.CreateFrame(context.Background(), "i", "f", pilosa.FrameOptions{InverseEnabled: true}); err != nil {
|
||||
t.Fatal("create frame:", err)
|
||||
}
|
||||
|
||||
// Write data on cluster.
|
||||
if _, err := m.Query("i", "", fmt.Sprintf(`
|
||||
SetBit(col=1, frame="f", row=1000)
|
||||
SetBit(col=1, frame="f", row=2000)
|
||||
SetBit(col=1, frame="f", row=%d)
|
||||
`, 1*pilosa.SliceWidth)); err != nil {
|
||||
t.Fatal("setting bits:", err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Query the cluster.
|
||||
if res, err := m.Query("i", "", `Bitmap(col=1, frame="f")`); err != nil {
|
||||
t.Fatal("another bitmap query:", err)
|
||||
} else if res != fmt.Sprintf(`{"results":[{"attrs":{},"bits":[1000,2000,%d]}]}`, 1*pilosa.SliceWidth)+"\n" {
|
||||
t.Fatalf("unexpected result: %s", res)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure program can set bits on one cluster and then restore to a second cluster.
|
||||
func TestMain_FrameRestore(t *testing.T) {
|
||||
mains1 := test.MustRunMainWithCluster(t, 2)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue