mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-05 16:15:56 +00:00
Merge remote-tracking branch 'upstream/enterprise' into clearvalue
This commit is contained in:
commit
75e017cf4f
33 changed files with 2422 additions and 955 deletions
|
|
@ -5,7 +5,7 @@ ARG MAKE_FLAGS
|
|||
|
||||
COPY . pilosa
|
||||
|
||||
RUN cd pilosa && CGO_ENABLED=0 make install FLAGS="-a ${BUILD_FLAGS}" ${MAKE_FLAGS}
|
||||
RUN cd pilosa && CGO_ENABLED=0 make install FLAGS="-a -mod=vendor ${BUILD_FLAGS}" ${MAKE_FLAGS}
|
||||
|
||||
FROM alpine:3.9.4
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
# This Dockerfile is used for cluster testing - it produces a much larger image
|
||||
# and includes all of Go as well as some utilities.
|
||||
|
||||
FROM golang:1.11
|
||||
FROM golang:1.13
|
||||
|
||||
LABEL maintainer "dev@pilosa.com"
|
||||
|
||||
COPY . /go/src/github.com/pilosa/pilosa/
|
||||
|
||||
RUN cd /go/src/github.com/pilosa/pilosa \
|
||||
&& GO111MODULE=on make vendor
|
||||
|
||||
RUN cd /go/src/github.com/pilosa/pilosa \
|
||||
&& CGO_ENABLED=0 make install FLAGS="-a"
|
||||
&& CGO_ENABLED=0 make install FLAGS="-a -mod=vendor"
|
||||
|
||||
# download pumba for fault injection
|
||||
ADD https://github.com/alexei-led/pumba/releases/download/0.6.0/pumba_linux_amd64 /pumba
|
||||
|
|
|
|||
12
Makefile
12
Makefile
|
|
@ -16,12 +16,16 @@ RELEASE_ENABLED = $(subst 0,,$(RELEASE))
|
|||
BUILD_TAGS += $(if $(ENTERPRISE_ENABLED),enterprise)
|
||||
BUILD_TAGS += $(if $(RELEASE_ENABLED),release)
|
||||
BUILD_TAGS += shardwidth$(SHARD_WIDTH)
|
||||
BUILD_TAGS += $(foreach p,$(PLUGINS),plugin$(p))
|
||||
define LICENSE_HASH_CODE
|
||||
head -13 $1 | sed -e 's/Copyright 20[0-9][0-9]/Copyright 20XX/g' | shasum | cut -f 1 -d " "
|
||||
endef
|
||||
LICENSE_HASH=$(shell $(call LICENSE_HASH_CODE, pilosa.go))
|
||||
|
||||
PLUGINS=distinct
|
||||
export GO111MODULE=on
|
||||
export GOPRIVATE=github.com/molecula
|
||||
export PLUGINS
|
||||
|
||||
# Run tests and compile Pilosa
|
||||
default: test build
|
||||
|
|
@ -85,14 +89,14 @@ DOCKER_COMPOSE=internal/clustertests/docker-compose.yml
|
|||
# running. This will catch changes to internal/clustertests/*.go, but if you
|
||||
# make changes to Pilosa, you'll want to run clustertests-build to rebuild the
|
||||
# pilosa image.
|
||||
clustertests:
|
||||
clustertests: vendor
|
||||
docker-compose -f $(DOCKER_COMPOSE) down
|
||||
docker-compose -f $(DOCKER_COMPOSE) build client1
|
||||
docker-compose -f $(DOCKER_COMPOSE) up --exit-code-from=client1
|
||||
|
||||
|
||||
# Like clustertests, but rebuilds all images.
|
||||
clustertests-build:
|
||||
clustertests-build: vendor
|
||||
docker-compose -f $(DOCKER_COMPOSE) down
|
||||
docker-compose -f $(DOCKER_COMPOSE) up --exit-code-from=client1 --build
|
||||
|
||||
|
|
@ -127,12 +131,12 @@ generate-proto-grpc: require-protoc require-protoc-gen-gofast
|
|||
generate: generate-protoc generate-stringer generate-pql
|
||||
|
||||
# Create Docker image from Dockerfile
|
||||
docker:
|
||||
docker: vendor
|
||||
docker build --build-arg BUILD_FLAGS="${FLAGS}" -t "pilosa:$(VERSION)" .
|
||||
@echo Created docker image: pilosa:$(VERSION)
|
||||
|
||||
# Create Docker image from Dockerfile (enterprise)
|
||||
docker-enterprise:
|
||||
docker-enterprise: vendor
|
||||
docker build --build-arg MAKE_FLAGS="ENTERPRISE=1" -t "pilosa-enterprise:$(VERSION)" .
|
||||
@echo Created docker image: pilosa-enterprise:$(VERSION)
|
||||
|
||||
|
|
|
|||
7
api.go
7
api.go
|
|
@ -1188,13 +1188,10 @@ func (api *API) ImportColumnAttrs(ctx context.Context, req *ImportColumnAttrsReq
|
|||
bulkAttrs[uint64(req.ColumnIDs[n])] = map[string]interface{}{req.AttrKey: req.AttrVals[n]}
|
||||
}
|
||||
if err := index.ColumnAttrStore().SetBulkAttrs(bulkAttrs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
api.server.logger.Printf("import error: index=%s, shard=%d, len(columns)=%d, err=%s", req.Index, req.Shard, len(req.ColumnIDs), err)
|
||||
return errors.Wrap(err, "importing column attrs")
|
||||
}
|
||||
return errors.Wrap(err, "importing column attrs")
|
||||
return nil
|
||||
}
|
||||
|
||||
func importExistenceColumns(index *Index, columnIDs []uint64) error {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func (c *GRPCClient) Query(ctx context.Context, index string, pql string) (pb.St
|
|||
|
||||
// Inspect returns a stream of RowResponse for the given index, columns, and filters.
|
||||
// It is intended to mimic something like "select [fields] from table where recordID IN (...)".
|
||||
func (c *GRPCClient) Inspect(ctx context.Context, index string, columnIDs []uint64, columnKeys []string, fieldFilters []string) (pb.StreamClient, error) {
|
||||
func (c *GRPCClient) Inspect(ctx context.Context, index string, columnIDs []uint64, columnKeys []string, fieldFilters []string, limit, offset uint64) (pb.StreamClient, error) {
|
||||
if c.conn == nil {
|
||||
return nil, errors.New("client has not established a grpc connection")
|
||||
}
|
||||
|
|
@ -103,7 +103,10 @@ func (c *GRPCClient) Inspect(ctx context.Context, index string, columnIDs []uint
|
|||
Index: index,
|
||||
Columns: idsOrKeys,
|
||||
FilterFields: fieldFilters,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting stream")
|
||||
} else if stream == nil {
|
||||
|
|
|
|||
25
cache.go
25
cache.go
|
|
@ -16,6 +16,7 @@ package pilosa
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
|
@ -322,6 +323,18 @@ type Pair struct {
|
|||
Count uint64 `json:"count"`
|
||||
}
|
||||
|
||||
// PairField
|
||||
type PairField struct {
|
||||
Pair Pair
|
||||
Field string
|
||||
}
|
||||
|
||||
// MarshalJSON marshals PairField into a JSON-encoded byte slice,
|
||||
// excluding `Field`.
|
||||
func (p PairField) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(p.Pair)
|
||||
}
|
||||
|
||||
// Pairs is a sortable slice of Pair objects.
|
||||
type Pairs []Pair
|
||||
|
||||
|
|
@ -397,6 +410,18 @@ func (p Pairs) String() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// PairsField
|
||||
type PairsField struct {
|
||||
Pairs []Pair
|
||||
Field string
|
||||
}
|
||||
|
||||
// MarshalJSON marshals PairsField into a JSON-encoded byte slice,
|
||||
// excluding `Field`.
|
||||
func (p PairsField) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(p.Pairs)
|
||||
}
|
||||
|
||||
// uint64Slice represents a sortable slice of uint64 numbers.
|
||||
type uint64Slice []uint64
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,9 @@ func encodeQueryResponse(m *pilosa.QueryResponse) *internal.QueryResponse {
|
|||
case []pilosa.Pair:
|
||||
pb.Results[i].Type = queryResultTypePairs
|
||||
pb.Results[i].Pairs = encodePairs(result)
|
||||
case *pilosa.PairsField:
|
||||
pb.Results[i].Type = queryResultTypePairsField
|
||||
pb.Results[i].PairsField = encodePairsField(result)
|
||||
case pilosa.ValCount:
|
||||
pb.Results[i].Type = queryResultTypeValCount
|
||||
pb.Results[i].ValCount = encodeValCount(result)
|
||||
|
|
@ -471,6 +474,9 @@ func encodeQueryResponse(m *pilosa.QueryResponse) *internal.QueryResponse {
|
|||
case pilosa.Pair:
|
||||
pb.Results[i].Type = queryResultTypePair
|
||||
pb.Results[i].Pairs = []*internal.Pair{encodePair(result)}
|
||||
case pilosa.PairField:
|
||||
pb.Results[i].Type = queryResultTypePairField
|
||||
pb.Results[i].Pairs = []*internal.Pair{encodePairField(result)}
|
||||
case nil:
|
||||
pb.Results[i].Type = queryResultTypeNil
|
||||
default:
|
||||
|
|
@ -1101,6 +1107,7 @@ const (
|
|||
queryResultTypeNil uint32 = iota
|
||||
queryResultTypeRow
|
||||
queryResultTypePairs
|
||||
queryResultTypePairsField
|
||||
queryResultTypeValCount
|
||||
queryResultTypeUint64
|
||||
queryResultTypeBool
|
||||
|
|
@ -1108,6 +1115,7 @@ const (
|
|||
queryResultTypeGroupCounts
|
||||
queryResultTypeRowIdentifiers
|
||||
queryResultTypePair
|
||||
queryResultTypePairField
|
||||
queryResultTypeSignedRow
|
||||
)
|
||||
|
||||
|
|
@ -1119,6 +1127,8 @@ func decodeQueryResult(pb *internal.QueryResult) interface{} {
|
|||
return decodeRow(pb.Row)
|
||||
case queryResultTypePairs:
|
||||
return decodePairs(pb.Pairs)
|
||||
case queryResultTypePairsField:
|
||||
return decodePairsField(pb.PairsField)
|
||||
case queryResultTypeValCount:
|
||||
return decodeValCount(pb.ValCount)
|
||||
case queryResultTypeUint64:
|
||||
|
|
@ -1135,6 +1145,8 @@ func decodeQueryResult(pb *internal.QueryResult) interface{} {
|
|||
return decodeGroupCounts(pb.GroupCounts)
|
||||
case queryResultTypePair:
|
||||
return decodePair(pb.Pairs[0])
|
||||
case queryResultTypePairField:
|
||||
return decodePairField(pb.Pairs[0])
|
||||
}
|
||||
panic(fmt.Sprintf("unknown type: %d", pb.Type))
|
||||
}
|
||||
|
|
@ -1243,6 +1255,17 @@ func decodePairs(a []*internal.Pair) []pilosa.Pair {
|
|||
return other
|
||||
}
|
||||
|
||||
func decodePairsField(a *internal.PairsField) *pilosa.PairsField {
|
||||
other := &pilosa.PairsField{
|
||||
Pairs: make([]pilosa.Pair, len(a.Pairs)),
|
||||
}
|
||||
for i := range a.Pairs {
|
||||
other.Pairs[i] = decodePair(a.Pairs[i])
|
||||
}
|
||||
other.Field = a.Field
|
||||
return other
|
||||
}
|
||||
|
||||
func decodePair(pb *internal.Pair) pilosa.Pair {
|
||||
return pilosa.Pair{
|
||||
ID: pb.ID,
|
||||
|
|
@ -1251,6 +1274,17 @@ func decodePair(pb *internal.Pair) pilosa.Pair {
|
|||
}
|
||||
}
|
||||
|
||||
func decodePairField(pb *internal.Pair) pilosa.PairField {
|
||||
return pilosa.PairField{
|
||||
Pair: pilosa.Pair{
|
||||
ID: pb.ID,
|
||||
Key: pb.Key,
|
||||
Count: pb.Count,
|
||||
},
|
||||
//Field: pb.Field, // TODO: in order to have this, we need PairField in QueryResponse.
|
||||
}
|
||||
}
|
||||
|
||||
func decodeValCount(pb *internal.ValCount) pilosa.ValCount {
|
||||
return pilosa.ValCount{
|
||||
Val: pb.Val,
|
||||
|
|
@ -1346,6 +1380,17 @@ func encodePairs(a pilosa.Pairs) []*internal.Pair {
|
|||
return other
|
||||
}
|
||||
|
||||
func encodePairsField(a *pilosa.PairsField) *internal.PairsField {
|
||||
other := &internal.PairsField{
|
||||
Pairs: make([]*internal.Pair, len(a.Pairs)),
|
||||
}
|
||||
for i := range a.Pairs {
|
||||
other.Pairs[i] = encodePair(a.Pairs[i])
|
||||
}
|
||||
other.Field = a.Field
|
||||
return other
|
||||
}
|
||||
|
||||
func encodePair(p pilosa.Pair) *internal.Pair {
|
||||
return &internal.Pair{
|
||||
ID: p.ID,
|
||||
|
|
@ -1354,6 +1399,17 @@ func encodePair(p pilosa.Pair) *internal.Pair {
|
|||
}
|
||||
}
|
||||
|
||||
func encodePairField(p pilosa.PairField) *internal.Pair {
|
||||
/*
|
||||
// TODO: in order to have this, we need PairField in QueryResponse.
|
||||
return &internal.Pair{
|
||||
Pair: encodePair(p.Pair),
|
||||
Field: p.Field,
|
||||
}
|
||||
*/
|
||||
return encodePair(p.Pair)
|
||||
}
|
||||
|
||||
func encodeValCount(vc pilosa.ValCount) *internal.ValCount {
|
||||
return &internal.ValCount{
|
||||
Val: vc.Val,
|
||||
|
|
|
|||
331
executor.go
331
executor.go
|
|
@ -23,7 +23,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
"github.com/molecula/ext"
|
||||
"github.com/pilosa/pilosa/v2/pql"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
"github.com/pilosa/pilosa/v2/shardwidth"
|
||||
|
|
@ -527,6 +527,8 @@ func (e *executor) executeCall(ctx context.Context, index string, c *pql.Call, s
|
|||
return e.executeOptionsCall(ctx, index, c, shards, opt)
|
||||
case "IncludesColumn":
|
||||
return e.executeIncludesColumnCall(ctx, index, c, shards, opt)
|
||||
case "All":
|
||||
return e.executeAllCall(ctx, index, c, shards, opt)
|
||||
case "Precomputed":
|
||||
return e.executePrecomputedCall(ctx, index, c, shards, opt)
|
||||
default:
|
||||
|
|
@ -635,6 +637,112 @@ func (e *executor) executeIncludesColumnCall(ctx context.Context, index string,
|
|||
return result.(bool), nil
|
||||
}
|
||||
|
||||
// executeAllCall executes an All() call.
|
||||
func (e *executor) executeAllCall(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) (*Row, error) {
|
||||
rslt := NewRow()
|
||||
|
||||
var limit uint64
|
||||
var offset uint64
|
||||
|
||||
if lim, hasLimit, err := c.UintArg("limit"); err != nil {
|
||||
return nil, errors.Wrap(err, "getting limit")
|
||||
} else if hasLimit && lim > 0 {
|
||||
limit = uint64(lim)
|
||||
}
|
||||
if off, hasOffset, err := c.UintArg("offset"); err != nil {
|
||||
return nil, errors.Wrap(err, "getting offset")
|
||||
} else if hasOffset && off > 0 {
|
||||
offset = uint64(off)
|
||||
}
|
||||
|
||||
if limit == 0 {
|
||||
limit = math.MaxUint64
|
||||
}
|
||||
|
||||
// skip tracks the number of records left to be skipped
|
||||
// in support of getting to the offset.
|
||||
var skip uint64 = offset
|
||||
|
||||
// got tracks the number of records gotten to that point.
|
||||
var got uint64
|
||||
|
||||
for _, shard := range shards {
|
||||
row, err := e.executeAllCallMapReduce(ctx, index, c, shard, opt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "executing map reduce on shard")
|
||||
}
|
||||
|
||||
segCnt := row.Count()
|
||||
|
||||
// If this segment doesn't reach the offset, skip it.
|
||||
if segCnt <= skip {
|
||||
skip -= segCnt
|
||||
continue
|
||||
}
|
||||
|
||||
// This segment doesn't have enough to finish fulfilling the limit
|
||||
// (or it has exactly enough).
|
||||
if segCnt-skip <= limit-got {
|
||||
if skip == 0 {
|
||||
rslt.Merge(row)
|
||||
} else {
|
||||
cols := row.Columns()
|
||||
partialRow := NewRow()
|
||||
for _, bit := range cols[skip:] {
|
||||
partialRow.SetBit(bit)
|
||||
}
|
||||
rslt.Merge(partialRow)
|
||||
}
|
||||
got += segCnt - skip
|
||||
// In the case where this segment exactly fulfills the limit, break.
|
||||
if got == limit {
|
||||
break
|
||||
}
|
||||
skip = 0
|
||||
continue
|
||||
}
|
||||
|
||||
// This segment has more records than the remaining limit requires.
|
||||
cols := row.Columns()
|
||||
partialRow := NewRow()
|
||||
for _, bit := range cols[skip : skip+limit-got] {
|
||||
partialRow.SetBit(bit)
|
||||
}
|
||||
rslt.Merge(partialRow)
|
||||
break
|
||||
}
|
||||
|
||||
return rslt, nil
|
||||
}
|
||||
|
||||
// executeAllCallMapReduce executes a single shard of the All() call
|
||||
// using the executor.mapReduce() method.
|
||||
func (e *executor) executeAllCallMapReduce(ctx context.Context, index string, c *pql.Call, shard uint64, opt *execOptions) (*Row, error) {
|
||||
// Execute calls in bulk on each remote node and merge.
|
||||
mapFn := func(shard uint64) (interface{}, error) {
|
||||
return e.executeAllCallShard(ctx, index, c, shard)
|
||||
}
|
||||
|
||||
// Merge returned results at coordinating node.
|
||||
reduceFn := func(prev, v interface{}) interface{} {
|
||||
other, _ := prev.(*Row)
|
||||
if other == nil {
|
||||
other = NewRow()
|
||||
}
|
||||
other.Merge(v.(*Row))
|
||||
return other
|
||||
}
|
||||
|
||||
result, err := e.mapReduce(ctx, index, []uint64{shard}, c, opt, mapFn, reduceFn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "map reduce")
|
||||
}
|
||||
|
||||
row, _ := result.(*Row)
|
||||
|
||||
return row, nil
|
||||
}
|
||||
|
||||
// executeIncludesColumnCallShard
|
||||
func (e *executor) executeIncludesColumnCallShard(ctx context.Context, index string, c *pql.Call, shard uint64, column uint64) (bool, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeIncludesColumnCallShard")
|
||||
|
|
@ -694,7 +802,8 @@ func (e *executor) executeGenericField(ctx context.Context, index string, c *pql
|
|||
span.LogKV("name", c.Name)
|
||||
defer span.Finish()
|
||||
|
||||
if field := c.Args["field"]; field == "" {
|
||||
field := c.Args["field"]
|
||||
if field == "" {
|
||||
return SignedRow{}, fmt.Errorf("plugin operation %s(): field required", c.Name)
|
||||
}
|
||||
|
||||
|
|
@ -714,6 +823,7 @@ func (e *executor) executeGenericField(ctx context.Context, index string, c *pql
|
|||
return SignedRow{}, err
|
||||
}
|
||||
other, _ := result.(SignedRow)
|
||||
other.field = field.(string)
|
||||
|
||||
return other, nil
|
||||
}
|
||||
|
|
@ -808,14 +918,19 @@ func (e *executor) executeMinRow(ctx context.Context, index string, c *pql.Call,
|
|||
reduceFn := func(prev, v interface{}) interface{} {
|
||||
// if minRowID exists, and if it is smaller than the other one return it.
|
||||
// otherwise return the minRowID of the one which exists.
|
||||
prevp, _ := prev.(Pair)
|
||||
vp, _ := v.(Pair)
|
||||
if prevp.Count > 0 && vp.Count > 0 {
|
||||
if prevp.ID < vp.ID {
|
||||
if prev == nil {
|
||||
return v
|
||||
} else if v == nil {
|
||||
return prev
|
||||
}
|
||||
prevp, _ := prev.(PairField)
|
||||
vp, _ := v.(PairField)
|
||||
if prevp.Pair.Count > 0 && vp.Pair.Count > 0 {
|
||||
if prevp.Pair.ID < vp.Pair.ID {
|
||||
return prevp
|
||||
}
|
||||
return vp
|
||||
} else if prevp.Count > 0 {
|
||||
} else if prevp.Pair.Count > 0 {
|
||||
return prevp
|
||||
}
|
||||
return vp
|
||||
|
|
@ -824,7 +939,7 @@ func (e *executor) executeMinRow(ctx context.Context, index string, c *pql.Call,
|
|||
return e.mapReduce(ctx, index, shards, c, opt, mapFn, reduceFn)
|
||||
}
|
||||
|
||||
// executeMinRow executes a MaxRow() call.
|
||||
// executeMaxRow executes a MaxRow() call.
|
||||
func (e *executor) executeMaxRow(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) (interface{}, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeMaxRow")
|
||||
defer span.Finish()
|
||||
|
|
@ -842,14 +957,19 @@ func (e *executor) executeMaxRow(ctx context.Context, index string, c *pql.Call,
|
|||
reduceFn := func(prev, v interface{}) interface{} {
|
||||
// if minRowID exists, and if it is smaller than the other one return it.
|
||||
// otherwise return the minRowID of the one which exists.
|
||||
prevp, _ := prev.(Pair)
|
||||
vp, _ := v.(Pair)
|
||||
if prevp.Count > 0 && vp.Count > 0 {
|
||||
if prevp.ID > vp.ID {
|
||||
if prev == nil {
|
||||
return v
|
||||
} else if v == nil {
|
||||
return prev
|
||||
}
|
||||
prevp, _ := prev.(PairField)
|
||||
vp, _ := v.(PairField)
|
||||
if prevp.Pair.Count > 0 && vp.Pair.Count > 0 {
|
||||
if prevp.Pair.ID > vp.Pair.ID {
|
||||
return prevp
|
||||
}
|
||||
return vp
|
||||
} else if prevp.Count > 0 {
|
||||
} else if prevp.Pair.Count > 0 {
|
||||
return prevp
|
||||
}
|
||||
return vp
|
||||
|
|
@ -993,6 +1113,8 @@ func (e *executor) executeBitmapCallShard(ctx context.Context, index string, c *
|
|||
return e.executeNotShard(ctx, index, c, shard)
|
||||
case "Shift":
|
||||
return e.executeShiftShard(ctx, index, c, shard)
|
||||
case "All": // Allow a shard computation to use All() (note, limit/offset not applied)
|
||||
return e.executeAllCallShard(ctx, index, c, shard)
|
||||
case "Precomputed":
|
||||
return e.executePrecomputedCallShard(ctx, index, c, shard)
|
||||
default:
|
||||
|
|
@ -1175,12 +1297,12 @@ func (e *executor) executeMaxShard(ctx context.Context, index string, c *pql.Cal
|
|||
}
|
||||
|
||||
// executeMinRowShard returns the minimum row ID for a shard.
|
||||
func (e *executor) executeMinRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (Pair, error) {
|
||||
func (e *executor) executeMinRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (PairField, error) {
|
||||
var filter *Row
|
||||
if len(c.Children) == 1 {
|
||||
row, err := e.executeBitmapCallShard(ctx, index, c.Children[0], shard)
|
||||
if err != nil {
|
||||
return Pair{}, err
|
||||
return PairField{}, err
|
||||
}
|
||||
filter = row
|
||||
}
|
||||
|
|
@ -1188,28 +1310,31 @@ func (e *executor) executeMinRowShard(ctx context.Context, index string, c *pql.
|
|||
fieldName, _ := c.Args["field"].(string)
|
||||
field := e.Holder.Field(index, fieldName)
|
||||
if field == nil {
|
||||
return Pair{}, nil
|
||||
return PairField{}, nil
|
||||
}
|
||||
|
||||
fragment := e.Holder.fragment(index, fieldName, viewStandard, shard)
|
||||
if fragment == nil {
|
||||
return Pair{}, nil
|
||||
return PairField{}, nil
|
||||
}
|
||||
|
||||
minRowID, count := fragment.minRow(filter)
|
||||
return Pair{
|
||||
ID: minRowID,
|
||||
Count: count,
|
||||
return PairField{
|
||||
Pair: Pair{
|
||||
ID: minRowID,
|
||||
Count: count,
|
||||
},
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// executeMaxRowShard returns the maximum row ID for a shard.
|
||||
func (e *executor) executeMaxRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (Pair, error) {
|
||||
func (e *executor) executeMaxRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (PairField, error) {
|
||||
var filter *Row
|
||||
if len(c.Children) == 1 {
|
||||
row, err := e.executeBitmapCallShard(ctx, index, c.Children[0], shard)
|
||||
if err != nil {
|
||||
return Pair{}, err
|
||||
return PairField{}, err
|
||||
}
|
||||
filter = row
|
||||
}
|
||||
|
|
@ -1217,25 +1342,28 @@ func (e *executor) executeMaxRowShard(ctx context.Context, index string, c *pql.
|
|||
fieldName, _ := c.Args["field"].(string)
|
||||
field := e.Holder.Field(index, fieldName)
|
||||
if field == nil {
|
||||
return Pair{}, nil
|
||||
return PairField{}, nil
|
||||
}
|
||||
|
||||
fragment := e.Holder.fragment(index, fieldName, viewStandard, shard)
|
||||
if fragment == nil {
|
||||
return Pair{}, nil
|
||||
return PairField{}, nil
|
||||
}
|
||||
|
||||
maxRowID, count := fragment.maxRow(filter)
|
||||
return Pair{
|
||||
ID: maxRowID,
|
||||
Count: count,
|
||||
return PairField{
|
||||
Pair: Pair{
|
||||
ID: maxRowID,
|
||||
Count: count,
|
||||
},
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// executeTopN executes a TopN() call.
|
||||
// This first performs the TopN() to determine the top results and then
|
||||
// requeries to retrieve the full counts for each of the top results.
|
||||
func (e *executor) executeTopN(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) ([]Pair, error) {
|
||||
func (e *executor) executeTopN(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) (*PairsField, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeTopN")
|
||||
defer span.Finish()
|
||||
|
||||
|
|
@ -1243,6 +1371,8 @@ func (e *executor) executeTopN(ctx context.Context, index string, c *pql.Call, s
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("executeTopN: %v", err)
|
||||
}
|
||||
|
||||
fieldName, _ := c.Args["_field"].(string)
|
||||
n, _, err := c.UintArg("n")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("executeTopN: %v", err)
|
||||
|
|
@ -1256,13 +1386,16 @@ func (e *executor) executeTopN(ctx context.Context, index string, c *pql.Call, s
|
|||
|
||||
// If this call is against specific ids, or we didn't get results,
|
||||
// or we are part of a larger distributed query then don't refetch.
|
||||
if len(pairs) == 0 || len(idsArg) > 0 || opt.Remote {
|
||||
return pairs, nil
|
||||
if len(pairs.Pairs) == 0 || len(idsArg) > 0 || opt.Remote {
|
||||
return &PairsField{
|
||||
Pairs: pairs.Pairs,
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
// Only the original caller should refetch the full counts.
|
||||
other := c.Clone()
|
||||
|
||||
ids := Pairs(pairs).Keys()
|
||||
ids := Pairs(pairs.Pairs).Keys()
|
||||
sort.Sort(uint64Slice(ids))
|
||||
other.Args["ids"] = ids
|
||||
|
||||
|
|
@ -1271,13 +1404,17 @@ func (e *executor) executeTopN(ctx context.Context, index string, c *pql.Call, s
|
|||
return nil, errors.Wrap(err, "retrieving full counts")
|
||||
}
|
||||
|
||||
if n != 0 && int(n) < len(trimmedList) {
|
||||
trimmedList = trimmedList[0:n]
|
||||
if n != 0 && int(n) < len(trimmedList.Pairs) {
|
||||
trimmedList.Pairs = trimmedList.Pairs[0:n]
|
||||
}
|
||||
return trimmedList, nil
|
||||
|
||||
return &PairsField{
|
||||
Pairs: trimmedList.Pairs,
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *executor) executeTopNShards(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) ([]Pair, error) {
|
||||
func (e *executor) executeTopNShards(ctx context.Context, index string, c *pql.Call, shards []uint64, opt *execOptions) (*PairsField, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeTopNShards")
|
||||
defer span.Finish()
|
||||
|
||||
|
|
@ -1288,24 +1425,31 @@ func (e *executor) executeTopNShards(ctx context.Context, index string, c *pql.C
|
|||
|
||||
// Merge returned results at coordinating node.
|
||||
reduceFn := func(prev, v interface{}) interface{} {
|
||||
other, _ := prev.([]Pair)
|
||||
return Pairs(other).Add(v.([]Pair))
|
||||
other, _ := prev.(*PairsField)
|
||||
vpf, _ := v.(*PairsField)
|
||||
if other == nil {
|
||||
return vpf
|
||||
} else if vpf == nil {
|
||||
return other
|
||||
}
|
||||
other.Pairs = Pairs(other.Pairs).Add(vpf.Pairs)
|
||||
return other
|
||||
}
|
||||
|
||||
other, err := e.mapReduce(ctx, index, shards, c, opt, mapFn, reduceFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results, _ := other.([]Pair)
|
||||
results, _ := other.(*PairsField)
|
||||
|
||||
// Sort final merged results.
|
||||
sort.Sort(Pairs(results))
|
||||
sort.Sort(Pairs(results.Pairs))
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// executeTopNShard executes a TopN call for a single shard.
|
||||
func (e *executor) executeTopNShard(ctx context.Context, index string, c *pql.Call, shard uint64) ([]Pair, error) {
|
||||
func (e *executor) executeTopNShard(ctx context.Context, index string, c *pql.Call, shard uint64) (*PairsField, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeTopNShard")
|
||||
defer span.Finish()
|
||||
|
||||
|
|
@ -1351,7 +1495,7 @@ func (e *executor) executeTopNShard(ctx context.Context, index string, c *pql.Ca
|
|||
|
||||
f := e.Holder.fragment(index, fieldName, viewStandard, shard)
|
||||
if f == nil {
|
||||
return nil, nil
|
||||
return &PairsField{}, nil
|
||||
} else if f.CacheType == CacheTypeNone {
|
||||
return nil, fmt.Errorf("cannot compute TopN(), field has no cache: %q", fieldName)
|
||||
}
|
||||
|
|
@ -1363,7 +1507,7 @@ func (e *executor) executeTopNShard(ctx context.Context, index string, c *pql.Ca
|
|||
if tanimotoThreshold > 100 {
|
||||
return nil, errors.New("Tanimoto Threshold is from 1 to 100 only")
|
||||
}
|
||||
return f.top(topOptions{
|
||||
pairs, err := f.top(topOptions{
|
||||
N: int(n),
|
||||
Src: src,
|
||||
RowIDs: rowIDs,
|
||||
|
|
@ -1372,6 +1516,13 @@ func (e *executor) executeTopNShard(ctx context.Context, index string, c *pql.Ca
|
|||
MinThreshold: minThreshold,
|
||||
TanimotoThreshold: tanimotoThreshold,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting top")
|
||||
}
|
||||
|
||||
return &PairsField{
|
||||
Pairs: pairs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// executeDifferenceShard executes a difference() call for a local shard.
|
||||
|
|
@ -1405,8 +1556,14 @@ func (e *executor) executeDifferenceShard(ctx context.Context, index string, c *
|
|||
// Row query which returns `Columns` and `Keys`.
|
||||
// TODO: Rename this to something better. Anything.
|
||||
type RowIdentifiers struct {
|
||||
Rows []uint64 `json:"rows"`
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
Rows []uint64 `json:"rows"`
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
field string
|
||||
}
|
||||
|
||||
// Field returns the field name associated to the row.
|
||||
func (r *RowIdentifiers) Field() string {
|
||||
return r.field
|
||||
}
|
||||
|
||||
// RowIDs is a query return type for just uint64 row ids.
|
||||
|
|
@ -2334,7 +2491,7 @@ func (e *executor) executePrecomputedCallShard(ctx context.Context, index string
|
|||
return nil, fmt.Errorf("per-shard: missing precomputed values for shard %d", shard)
|
||||
}
|
||||
|
||||
// executeNotShard executes a not() call for a local shard.
|
||||
// executeNotShard executes a Not() call for a local shard.
|
||||
func (e *executor) executeNotShard(ctx context.Context, index string, c *pql.Call, shard uint64) (*Row, error) {
|
||||
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeNotShard")
|
||||
defer span.Finish()
|
||||
|
|
@ -2369,6 +2526,34 @@ func (e *executor) executeNotShard(ctx context.Context, index string, c *pql.Cal
|
|||
return existenceRow.Difference(row), nil
|
||||
}
|
||||
|
||||
// executeAllCallShard executes an All() call for a local shard.
|
||||
func (e *executor) executeAllCallShard(ctx context.Context, index string, c *pql.Call, shard uint64) (*Row, error) {
|
||||
span, _ := tracing.StartSpanFromContext(ctx, "Executor.executeAllCallShard")
|
||||
defer span.Finish()
|
||||
|
||||
if len(c.Children) > 0 {
|
||||
return nil, errors.New("All() does not accept an input row")
|
||||
}
|
||||
|
||||
// Make sure the index supports existence tracking.
|
||||
idx := e.Holder.Index(index)
|
||||
if idx == nil {
|
||||
return nil, ErrIndexNotFound
|
||||
} else if idx.existenceField() == nil {
|
||||
return nil, errors.Errorf("index does not support existence tracking: %s", index)
|
||||
}
|
||||
|
||||
var existenceRow *Row
|
||||
existenceFrag := e.Holder.fragment(index, existenceFieldName, viewStandard, shard)
|
||||
if existenceFrag == nil {
|
||||
existenceRow = NewRow()
|
||||
} else {
|
||||
existenceRow = existenceFrag.row(0)
|
||||
}
|
||||
|
||||
return existenceRow, nil
|
||||
}
|
||||
|
||||
// executeShiftShard executes a shift() call for a local shard.
|
||||
func (e *executor) executeShiftShard(ctx context.Context, index string, c *pql.Call, shard uint64) (*Row, error) {
|
||||
n, _, err := c.IntArg("n")
|
||||
|
|
@ -3574,41 +3759,47 @@ func (e *executor) translateResult(index string, idx *Index, call *pql.Call, res
|
|||
return other, nil
|
||||
}
|
||||
|
||||
case Pair:
|
||||
case PairField:
|
||||
if fieldName := callArgString(call, "field"); fieldName != "" {
|
||||
field := idx.Field(fieldName)
|
||||
if field == nil {
|
||||
return nil, fmt.Errorf("field %q not found", fieldName)
|
||||
}
|
||||
if field.keys() {
|
||||
key, err := field.translateStore.TranslateID(result.ID)
|
||||
key, err := field.translateStore.TranslateID(result.Pair.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if call.Name == "MinRow" || call.Name == "MaxRow" {
|
||||
result.Key = key
|
||||
result.Pair.Key = key
|
||||
return result, nil
|
||||
}
|
||||
return Pair{Key: key, Count: result.Count}, nil
|
||||
return PairField{
|
||||
Pair: Pair{Key: key, Count: result.Pair.Count},
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
case []Pair:
|
||||
case *PairsField:
|
||||
if fieldName := callArgString(call, "_field"); fieldName != "" {
|
||||
field := idx.Field(fieldName)
|
||||
if field == nil {
|
||||
return nil, fmt.Errorf("field %q not found", fieldName)
|
||||
}
|
||||
if field.keys() {
|
||||
other := make([]Pair, len(result))
|
||||
for i := range result {
|
||||
key, err := field.translateStore.TranslateID(result[i].ID)
|
||||
other := make([]Pair, len(result.Pairs))
|
||||
for i := range result.Pairs {
|
||||
key, err := field.translateStore.TranslateID(result.Pairs[i].ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
other[i] = Pair{Key: key, Count: result[i].Count}
|
||||
other[i] = Pair{Key: key, Count: result.Pairs[i].Count}
|
||||
}
|
||||
return other, nil
|
||||
return &PairsField{
|
||||
Pairs: other,
|
||||
Field: fieldName,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3643,13 +3834,15 @@ func (e *executor) translateResult(index string, idx *Index, call *pql.Call, res
|
|||
return other, nil
|
||||
|
||||
case RowIDs:
|
||||
other := RowIdentifiers{}
|
||||
|
||||
fieldName := callArgString(call, "_field")
|
||||
if fieldName == "" {
|
||||
return nil, ErrFieldNotFound
|
||||
}
|
||||
|
||||
other := RowIdentifiers{
|
||||
field: fieldName,
|
||||
}
|
||||
|
||||
if field := idx.Field(fieldName); field == nil {
|
||||
return nil, ErrFieldNotFound
|
||||
} else if field.keys() {
|
||||
|
|
@ -3762,12 +3955,18 @@ func needsShards(calls []*pql.Call) bool {
|
|||
|
||||
// SignedRow represents a signed *Row with two (neg/pos) *Rows.
|
||||
type SignedRow struct {
|
||||
Neg *Row `json:"neg"`
|
||||
Pos *Row `json:"pos"`
|
||||
Neg *Row `json:"neg"`
|
||||
Pos *Row `json:"pos"`
|
||||
field string
|
||||
}
|
||||
|
||||
// Field returns the field name associated to the signed row.
|
||||
func (s *SignedRow) Field() string {
|
||||
return s.field
|
||||
}
|
||||
|
||||
func (sr *SignedRow) union(other SignedRow) SignedRow {
|
||||
ret := SignedRow{&Row{}, &Row{}}
|
||||
ret := SignedRow{&Row{}, &Row{}, ""}
|
||||
|
||||
// merge in sr
|
||||
if sr != nil {
|
||||
|
|
@ -3808,9 +4007,13 @@ func (vc *ValCount) smaller(other ValCount) ValCount {
|
|||
if vc.Count == 0 || (other.Val < vc.Val && other.Count > 0) {
|
||||
return other
|
||||
}
|
||||
extra := int64(0)
|
||||
if vc.Val == other.Val {
|
||||
extra += other.Count
|
||||
}
|
||||
return ValCount{
|
||||
Val: vc.Val,
|
||||
Count: vc.Count,
|
||||
Count: vc.Count + extra,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3819,9 +4022,13 @@ func (vc *ValCount) larger(other ValCount) ValCount {
|
|||
if vc.Count == 0 || (other.Val > vc.Val && other.Count > 0) {
|
||||
return other
|
||||
}
|
||||
extra := int64(0)
|
||||
if vc.Val == other.Val {
|
||||
extra += other.Count
|
||||
}
|
||||
return ValCount{
|
||||
Val: vc.Val,
|
||||
Count: vc.Count,
|
||||
Count: vc.Count + extra,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
431
executor_test.go
431
executor_test.go
|
|
@ -945,9 +945,12 @@ func TestExecutor_Execute_TopN(t *testing.T) {
|
|||
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=2)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results[0], []pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
{ID: 10, Count: 2},
|
||||
} else if !reflect.DeepEqual(result.Results[0], &pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
{ID: 10, Count: 2},
|
||||
},
|
||||
Field: "f",
|
||||
}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -986,9 +989,12 @@ func TestExecutor_Execute_TopN(t *testing.T) {
|
|||
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=2)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results[0], []pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
{ID: 10, Count: 2},
|
||||
} else if !reflect.DeepEqual(result.Results[0], &pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
{ID: 10, Count: 2},
|
||||
},
|
||||
Field: "f",
|
||||
}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1027,11 +1033,16 @@ func TestExecutor_Execute_TopN(t *testing.T) {
|
|||
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=2)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results[0], []pilosa.Pair{
|
||||
{Key: "zero", Count: 5},
|
||||
{Key: "ten", Count: 2},
|
||||
}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
} else {
|
||||
if !reflect.DeepEqual(result.Results[0], &pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{Key: "zero", Count: 5},
|
||||
{Key: "ten", Count: 2},
|
||||
},
|
||||
Field: "f",
|
||||
}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -1069,9 +1080,12 @@ func TestExecutor_Execute_TopN(t *testing.T) {
|
|||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=2)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if diff := cmp.Diff(result.Results, []interface{}{
|
||||
[]pilosa.Pair{
|
||||
{Key: "foo", Count: 5},
|
||||
{Key: "bar", Count: 2},
|
||||
&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{Key: "foo", Count: 5},
|
||||
{Key: "bar", Count: 2},
|
||||
},
|
||||
Field: "f",
|
||||
},
|
||||
}); diff != "" {
|
||||
t.Fatal(diff)
|
||||
|
|
@ -1154,8 +1168,11 @@ func TestExecutor_Execute_TopN_fill(t *testing.T) {
|
|||
// Execute query.
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 0, Count: 4},
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 0, Count: 4},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1188,8 +1205,11 @@ func TestExecutor_Execute_TopN_fill_small(t *testing.T) {
|
|||
// Execute query.
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 0, Count: 5},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1224,10 +1244,13 @@ func TestExecutor_Execute_TopN_Src(t *testing.T) {
|
|||
// Execute query.
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, Row(other=100), n=3)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 20, Count: 3},
|
||||
{ID: 10, Count: 2},
|
||||
{ID: 0, Count: 1},
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 20, Count: 3},
|
||||
{ID: 10, Count: 2},
|
||||
{ID: 0, Count: 1},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1247,8 +1270,11 @@ func TestExecutor_Execute_TopN_Attr(t *testing.T) {
|
|||
}
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=1, attrName="category", attrValues=[123])`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 10, Count: 1},
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 10, Count: 1},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1270,8 +1296,11 @@ func TestExecutor_Execute_TopN_Attr_Src(t *testing.T) {
|
|||
}
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, Row(f=10), n=1, attrName="category", attrValues=[123])`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 10, Count: 1},
|
||||
} else if !reflect.DeepEqual(result.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 10, Count: 1},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("unexpected result: %s", spew.Sdump(result))
|
||||
}
|
||||
|
|
@ -1465,7 +1494,10 @@ func TestExecutor_Execute_MinMaxRow(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
target := pilosa.Pair{ID: 1, Count: 1}
|
||||
target := pilosa.PairField{
|
||||
Pair: pilosa.Pair{ID: 1, Count: 1},
|
||||
Field: "f",
|
||||
}
|
||||
if !reflect.DeepEqual(target, result.Results[0]) {
|
||||
t.Fatalf("unexpected result %v != %v", target, result.Results[0])
|
||||
}
|
||||
|
|
@ -1476,7 +1508,10 @@ func TestExecutor_Execute_MinMaxRow(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
target := pilosa.Pair{ID: 10000, Count: 1}
|
||||
target := pilosa.PairField{
|
||||
Pair: pilosa.Pair{ID: 10000, Count: 1},
|
||||
Field: "f",
|
||||
}
|
||||
if !reflect.DeepEqual(target, result.Results[0]) {
|
||||
t.Fatalf("unexpected result %v != %v", target, result.Results[0])
|
||||
}
|
||||
|
|
@ -1512,7 +1547,10 @@ func TestExecutor_Execute_MinMaxRow(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
target := pilosa.Pair{Key: "seven-thousand", ID: 1, Count: 1}
|
||||
target := pilosa.PairField{
|
||||
Pair: pilosa.Pair{Key: "seven-thousand", ID: 1, Count: 1},
|
||||
Field: "f",
|
||||
}
|
||||
if !reflect.DeepEqual(target, result.Results[0]) {
|
||||
t.Fatalf("unexpected result %v != %v", target, result.Results[0])
|
||||
}
|
||||
|
|
@ -1523,7 +1561,10 @@ func TestExecutor_Execute_MinMaxRow(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
target := pilosa.Pair{Key: "five-thousand", ID: 5, Count: 1}
|
||||
target := pilosa.PairField{
|
||||
Pair: pilosa.Pair{Key: "five-thousand", ID: 5, Count: 1},
|
||||
Field: "f",
|
||||
}
|
||||
if !reflect.DeepEqual(target, result.Results[0]) {
|
||||
t.Fatalf("unexpected result %v != %v", target, result.Results[0])
|
||||
}
|
||||
|
|
@ -2420,7 +2461,6 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("creating field: %v", err)
|
||||
}
|
||||
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `
|
||||
Set(500001, fn=5)
|
||||
Set(1500001, fn=5)
|
||||
|
|
@ -2432,11 +2472,11 @@ Set(3500003, fn=3)
|
|||
Set(500001, fn=4)
|
||||
Set(4500001, fn=4)
|
||||
`}); err != nil {
|
||||
t.Fatalf("quuerying remote: %v", err)
|
||||
t.Fatalf("querying remote: %v", err)
|
||||
}
|
||||
err := c[0].API.RecalculateCaches(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("recalcing caches: %v", err)
|
||||
t.Fatalf("recalculating caches: %v", err)
|
||||
}
|
||||
|
||||
if res, err := c[1].API.Query(context.Background(), &pilosa.QueryRequest{
|
||||
|
|
@ -2444,10 +2484,13 @@ Set(4500001, fn=4)
|
|||
Query: `TopN(fn, n=3)`,
|
||||
}); err != nil {
|
||||
t.Fatalf("topn querying: %v", err)
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 5, Count: 4},
|
||||
{ID: 3, Count: 3},
|
||||
{ID: 4, Count: 2},
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 5, Count: 4},
|
||||
{ID: 3, Count: 3},
|
||||
{ID: 4, Count: 2},
|
||||
},
|
||||
Field: "fn",
|
||||
}}) {
|
||||
t.Fatalf("topn wrong results: %v", res.Results)
|
||||
}
|
||||
|
|
@ -2855,6 +2898,175 @@ func TestExecutor_Execute_Not(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure an all query can be executed.
|
||||
func TestExecutor_Execute_All(t *testing.T) {
|
||||
t.Run("ColumnID", func(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 1)
|
||||
defer c.Close()
|
||||
hldr := test.Holder{Holder: c[0].Server.Holder()}
|
||||
index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{TrackExistence: true})
|
||||
fld, err := index.CreateField("f", pilosa.OptFieldTypeDefault())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create an import request that sets a full shard,
|
||||
// plus a couple bits set on either side of it, and
|
||||
// a final bit set in a fourth shard.
|
||||
//
|
||||
// shard0 shard1 shard2 shard3
|
||||
// |----------|----------|----------|----------|
|
||||
// | **|**********|** | *
|
||||
//
|
||||
bitCount := ShardWidth + 5
|
||||
req := &pilosa.ImportRequest{
|
||||
Index: index.Name(),
|
||||
Field: fld.Name(),
|
||||
Shard: 0,
|
||||
RowIDs: make([]uint64, bitCount),
|
||||
ColumnIDs: make([]uint64, bitCount),
|
||||
}
|
||||
for i := 0; i < bitCount-1; i++ {
|
||||
req.RowIDs[i] = 10
|
||||
req.ColumnIDs[i] = uint64(i + ShardWidth - 2)
|
||||
}
|
||||
req.RowIDs[bitCount-1] = 10
|
||||
req.ColumnIDs[bitCount-1] = uint64((3 * ShardWidth) + 2)
|
||||
|
||||
if err := c[0].API.Import(context.Background(), req); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
qry string
|
||||
expCols []uint64
|
||||
expCnt uint64
|
||||
}{
|
||||
{qry: "All()", expCols: req.ColumnIDs, expCnt: uint64(bitCount)},
|
||||
{qry: "All(limit=1)", expCols: req.ColumnIDs[:1], expCnt: 1},
|
||||
{qry: "All(limit=4)", expCols: req.ColumnIDs[:4], expCnt: 4},
|
||||
{qry: "All(limit=4, offset=4)", expCols: req.ColumnIDs[4:8], expCnt: 4},
|
||||
{qry: fmt.Sprintf("All(limit=4, offset=%d)", bitCount-5), expCols: req.ColumnIDs[bitCount-5 : bitCount-1], expCnt: 4},
|
||||
{qry: fmt.Sprintf("All(limit=1, offset=%d)", bitCount-2), expCols: req.ColumnIDs[bitCount-2 : bitCount-1], expCnt: 1},
|
||||
{qry: fmt.Sprintf("All(limit=1, offset=%d)", bitCount-2), expCols: req.ColumnIDs[bitCount-2 : bitCount-1], expCnt: 1},
|
||||
{qry: fmt.Sprintf("All(limit=4, offset=%d)", bitCount-2), expCols: req.ColumnIDs[bitCount-2:], expCnt: 2},
|
||||
{qry: fmt.Sprintf("All(limit=4, offset=%d)", bitCount+1), expCols: []uint64{}, expCnt: 0},
|
||||
{qry: fmt.Sprintf("All(limit=2, offset=%d)", bitCount-3), expCols: req.ColumnIDs[bitCount-3 : bitCount-1], expCnt: 2},
|
||||
{qry: fmt.Sprintf("All(limit=2, offset=%d)", bitCount-5), expCols: req.ColumnIDs[bitCount-5 : bitCount-3], expCnt: 2},
|
||||
{qry: "All(limit=2, offset=2)", expCols: req.ColumnIDs[2:4], expCnt: 2},
|
||||
{qry: "All(limit=1, offset=1)", expCols: req.ColumnIDs[1:2], expCnt: 1},
|
||||
{qry: fmt.Sprintf("All(limit=%d, offset=2)", ShardWidth), expCols: req.ColumnIDs[2 : bitCount-3], expCnt: ShardWidth},
|
||||
}
|
||||
for i, test := range tests {
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: test.qry}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cnt := res.Results[0].(*pilosa.Row).Count(); cnt != test.expCnt {
|
||||
t.Fatalf("test %d, unexpected count, got: %d, but expected: %d", i, cnt, test.expCnt)
|
||||
} else if cols := res.Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(cols, test.expCols) {
|
||||
// If the error results are too large, just show the count.
|
||||
if len(cols) > 1000 || len(test.expCols) > 1000 {
|
||||
t.Fatalf("test %d, unexpected columns, got: len(%d), but expected: len(%d)", i, len(cols), len(test.expCols))
|
||||
} else {
|
||||
t.Fatalf("test %d, unexpected columns, got: %v, but expected: %v", i, cols, test.expCols)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ColumnKey", func(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 1, []server.CommandOption{
|
||||
server.OptCommandServerOptions(
|
||||
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
|
||||
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
|
||||
),
|
||||
})
|
||||
defer c.Close()
|
||||
hldr := test.Holder{Holder: c[0].Server.Holder()}
|
||||
index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{TrackExistence: true, Keys: true})
|
||||
fld, err := index.CreateField("f", pilosa.OptFieldTypeDefault())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create an import request that sets key columns
|
||||
//
|
||||
// shard0
|
||||
// |----------|
|
||||
// |**** |
|
||||
//
|
||||
bitCount := 4
|
||||
req := &pilosa.ImportRequest{
|
||||
Index: index.Name(),
|
||||
Field: fld.Name(),
|
||||
Shard: 0,
|
||||
RowIDs: make([]uint64, bitCount),
|
||||
ColumnKeys: make([]string, bitCount),
|
||||
}
|
||||
for i := 0; i < bitCount; i++ {
|
||||
req.RowIDs[i] = 10
|
||||
req.ColumnKeys[i] = fmt.Sprintf("c%d", i)
|
||||
}
|
||||
|
||||
if err := c[0].API.Import(context.Background(), req); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
qry string
|
||||
expCols []string
|
||||
expCnt uint64
|
||||
}{
|
||||
{qry: "All()", expCols: req.ColumnKeys, expCnt: uint64(bitCount)},
|
||||
{qry: "All(limit=1)", expCols: req.ColumnKeys[:1], expCnt: 1},
|
||||
{qry: "All(limit=4)", expCols: req.ColumnKeys, expCnt: 4},
|
||||
{qry: "All(limit=5)", expCols: req.ColumnKeys, expCnt: 4},
|
||||
{qry: "All(limit=1, offset=1)", expCols: req.ColumnKeys[1:2], expCnt: 1},
|
||||
{qry: "All(limit=4, offset=1)", expCols: req.ColumnKeys[1:], expCnt: 3},
|
||||
{qry: "All(limit=4, offset=5)", expCols: nil, expCnt: 0},
|
||||
}
|
||||
for i, test := range tests {
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: test.qry}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cnt := len(res.Results[0].(*pilosa.Row).Keys); uint64(cnt) != test.expCnt {
|
||||
t.Fatalf("test %d, unexpected count, got: %d, but expected: %d", i, cnt, test.expCnt)
|
||||
} else if cols := res.Results[0].(*pilosa.Row).Keys; !reflect.DeepEqual(cols, test.expCols) {
|
||||
// If the error results are too large, just show the count.
|
||||
if len(cols) > 1000 || len(test.expCols) > 1000 {
|
||||
t.Fatalf("test %d, unexpected columns, got: len(%d), but expected: len(%d)", i, len(cols), len(test.expCols))
|
||||
} else {
|
||||
t.Fatalf("test %d, unexpected columns, got: %T, but expected: %T", i, cols, test.expCols)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Ensure that a query which uses All() at the shard level can call it.
|
||||
t.Run("AllShard", func(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 1)
|
||||
defer c.Close()
|
||||
hldr := test.Holder{Holder: c[0].Server.Holder()}
|
||||
index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{TrackExistence: true})
|
||||
_, err := index.CreateField("f", pilosa.OptFieldTypeDefault())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `
|
||||
Set(3001, f=3)
|
||||
Set(5001, f=5)
|
||||
Set(5002, f=5)
|
||||
`}); err != nil {
|
||||
t.Fatalf("querying remote: %v", err)
|
||||
}
|
||||
|
||||
expCols := []uint64{5001, 5002}
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: "Intersect(All(), Row(f=5))"}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cols := res.Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(cols, expCols) {
|
||||
t.Fatalf("unexpected columns, got: %v, but expected: %v", cols, expCols)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a row can be cleared.
|
||||
func TestExecutor_Execute_ClearRow(t *testing.T) {
|
||||
// Set and Mutex tests use the same data and queries
|
||||
|
|
@ -3039,10 +3251,13 @@ func TestExecutor_Execute_ClearRow(t *testing.T) {
|
|||
// Check the TopN results.
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=5)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 1, Count: 7},
|
||||
{ID: 2, Count: 6},
|
||||
{ID: 3, Count: 5},
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 1, Count: 7},
|
||||
{ID: 2, Count: 6},
|
||||
{ID: 3, Count: 5},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("topn wrong results: %v", res.Results)
|
||||
}
|
||||
|
|
@ -3057,9 +3272,12 @@ func TestExecutor_Execute_ClearRow(t *testing.T) {
|
|||
// Ensure that the cleared row doesn't show up in TopN (i.e. it was removed from the cache).
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `TopN(f, n=5)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{[]pilosa.Pair{
|
||||
{ID: 1, Count: 7},
|
||||
{ID: 3, Count: 5},
|
||||
} else if !reflect.DeepEqual(res.Results, []interface{}{&pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{ID: 1, Count: 7},
|
||||
{ID: 3, Count: 5},
|
||||
},
|
||||
Field: "f",
|
||||
}}) {
|
||||
t.Fatalf("topn wrong results: %v", res.Results)
|
||||
}
|
||||
|
|
@ -3280,30 +3498,40 @@ func TestExecutor_Execute_Rows(t *testing.T) {
|
|||
})
|
||||
|
||||
rows := c.Query(t, "i", `Rows(general)`).Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows, pilosa.RowIdentifiers{Rows: []uint64{10, 11, 12, 13}}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows)
|
||||
if !reflect.DeepEqual(rows.Rows, []uint64{10, 11, 12, 13}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows.Rows)
|
||||
} else if rows.Keys != nil {
|
||||
t.Fatalf("unexpected keys: %+v", rows.Keys)
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
// TODO: remove at Pilosa 2.0
|
||||
rows = c.Query(t, "i", `Rows(field=general)`).Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows, pilosa.RowIdentifiers{Rows: []uint64{10, 11, 12, 13}}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows)
|
||||
if !reflect.DeepEqual(rows.Rows, []uint64{10, 11, 12, 13}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows.Rows)
|
||||
} else if rows.Keys != nil {
|
||||
t.Fatalf("unexpected keys: %+v", rows.Keys)
|
||||
}
|
||||
|
||||
rows = c.Query(t, "i", `Rows(general, limit=2)`).Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows, pilosa.RowIdentifiers{Rows: []uint64{10, 11}}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows)
|
||||
if !reflect.DeepEqual(rows.Rows, []uint64{10, 11}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows.Rows)
|
||||
} else if rows.Keys != nil {
|
||||
t.Fatalf("unexpected keys: %+v", rows.Keys)
|
||||
}
|
||||
|
||||
rows = c.Query(t, "i", `Rows(general, previous=10,limit=2)`).Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows, pilosa.RowIdentifiers{Rows: []uint64{11, 12}}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows)
|
||||
if !reflect.DeepEqual(rows.Rows, []uint64{11, 12}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows.Rows)
|
||||
} else if rows.Keys != nil {
|
||||
t.Fatalf("unexpected keys: %+v", rows.Keys)
|
||||
}
|
||||
|
||||
rows = c.Query(t, "i", `Rows(general, column=2)`).Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows, pilosa.RowIdentifiers{Rows: []uint64{11, 12}}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows)
|
||||
if !reflect.DeepEqual(rows.Rows, []uint64{11, 12}) {
|
||||
t.Fatalf("unexpected rows: %+v", rows.Rows)
|
||||
} else if rows.Keys != nil {
|
||||
t.Fatalf("unexpected keys: %+v", rows.Keys)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3613,9 +3841,13 @@ func TestExecutor_Execute_Rows_Keys(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("#%d_%s", i, test.q), func(t *testing.T) {
|
||||
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: test.q}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if rows := res.Results[0].(pilosa.RowIdentifiers); !reflect.DeepEqual(
|
||||
rows, pilosa.RowIdentifiers{Keys: test.exp}) {
|
||||
t.Fatalf("\ngot: %+v\nexp: %+v", rows, pilosa.RowIdentifiers{Keys: test.exp})
|
||||
} else {
|
||||
rows := res.Results[0].(pilosa.RowIdentifiers)
|
||||
if !reflect.DeepEqual(rows.Keys, test.exp) {
|
||||
t.Fatalf("\ngot: %+v\nexp: %+v", rows.Keys, test.exp)
|
||||
} else if rows.Rows != nil {
|
||||
t.Fatalf("\ngot: %+v\nexp: nil", rows.Rows)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -4254,3 +4486,88 @@ func TestExecutor_Execute_IncludesColumn(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestExecutor_Execute_MinMaxCountEqual(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 1)
|
||||
defer c.Close()
|
||||
hldr := test.Holder{Holder: c[0].Server.Holder()}
|
||||
|
||||
idx, err := hldr.CreateIndex("i", pilosa.IndexOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := idx.CreateField("x", pilosa.OptFieldTypeDefault()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := idx.CreateField("f", pilosa.OptFieldTypeInt(-1100, 1000)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `
|
||||
Set(0, f=3)
|
||||
Set(1, f=3)
|
||||
Set(2, f=4)
|
||||
Set(3, f=5)
|
||||
Set(4, f=5)
|
||||
Set(` + strconv.Itoa(ShardWidth+1) + `, f=3)
|
||||
Set(` + strconv.Itoa(ShardWidth+2) + `, f=5)
|
||||
Set(` + strconv.Itoa(ShardWidth+3) + `, f=5)
|
||||
Set(` + strconv.Itoa(ShardWidth+4) + `, f=5)
|
||||
Set(` + strconv.Itoa(ShardWidth+5) + `, f=4)
|
||||
Set(` + strconv.Itoa(2*ShardWidth+1) + `, f=3)
|
||||
Set(0, x=3)
|
||||
Set(1, x=3)
|
||||
|
||||
`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("Min", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
filter string
|
||||
exp int64
|
||||
cnt int64
|
||||
}{
|
||||
{filter: ``, exp: 3, cnt: 4},
|
||||
{filter: `Row(x=3)`, exp: 3, cnt: 2},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var pql string
|
||||
if tt.filter == "" {
|
||||
pql = `Min(field=f)`
|
||||
} else {
|
||||
pql = fmt.Sprintf(`Min(%s, field=f)`, tt.filter)
|
||||
}
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: pql}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{Val: tt.exp, Count: tt.cnt}) {
|
||||
t.Fatalf("unexpected result, test %d: %s", i, spew.Sdump(result))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Max", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
filter string
|
||||
exp int64
|
||||
cnt int64
|
||||
}{
|
||||
{filter: ``, exp: 5, cnt: 5},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var pql string
|
||||
if tt.filter == "" {
|
||||
pql = `Max(field=f)`
|
||||
} else {
|
||||
pql = fmt.Sprintf(`Max(%s, field=f)`, tt.filter)
|
||||
}
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: pql}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{Val: tt.exp, Count: tt.cnt}) {
|
||||
t.Fatalf("unexpected result, test %d: %s", i, spew.Sdump(result))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
238
ext/ext.go
238
ext/ext.go
|
|
@ -1,238 +0,0 @@
|
|||
// Copyright 2019 Pilosa Corp.
|
||||
//
|
||||
// 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 ext provides an EXPERIMENTAL AND TEMPORARY interface to use for
|
||||
// plugin extensions to Pilosa. DO NOT DEVELOP NEW PLUGINS WITH THIS. The
|
||||
// replacement design is already in process, but it needs more refinement
|
||||
// to address issues. This one has those issues, and more.
|
||||
//
|
||||
// In the current design, plugins will be loaded at runtime using the
|
||||
// go `plugin` package, so they should be built as a main package using
|
||||
// the plugin build mode.
|
||||
//
|
||||
// Plugins should not import other packages from Pilosa.
|
||||
//
|
||||
// To advertise their functionality, plugins define one or more of a
|
||||
// handful of symbols which will be checked for at plugin load and used
|
||||
// to register their functionality.
|
||||
//
|
||||
// The plugin interface will check for the following function(s). If the
|
||||
// functions exist, they must have the given signatures. If they return
|
||||
// a non-nil error, no ops are registered, and the error message will
|
||||
// be reported in the Pilosa server's logs.
|
||||
//
|
||||
// BitmapOps() ([]BitmapOp, error)
|
||||
//
|
||||
// These functions may be absent, and may return nil slices; in either
|
||||
// case, no ops are registered.
|
||||
package ext
|
||||
|
||||
// The Bitmap type represents a Pilosa bitmap, and is used for bitmap
|
||||
// operations.
|
||||
type Bitmap interface {
|
||||
// AddN and RemoveN can be used to add or remove values from a bitmap.
|
||||
AddN(a ...uint64) (int, error)
|
||||
RemoveN(a ...uint64) (int, error)
|
||||
|
||||
// Lookups
|
||||
Max() uint64
|
||||
Min() (uint64, bool)
|
||||
Count() uint64
|
||||
Any() bool
|
||||
Contains(uint64) bool
|
||||
Slice() []uint64
|
||||
SliceRange(uint64, uint64) []uint64
|
||||
// ContainerBits stores the next 1<<16 bits, starting at the provided
|
||||
// bit index. It may use a provided []uint64 to store them, or may
|
||||
// provide its own. Don't write to those bits. Offset must be a multiple
|
||||
// of 1<<16.
|
||||
ContainerBits(uint64, []uint64) []uint64
|
||||
|
||||
// These operators provide existing implemented binary ops.
|
||||
Intersect(Bitmap) Bitmap
|
||||
Union(Bitmap) Bitmap
|
||||
IntersectionCount(Bitmap) uint64
|
||||
Difference(Bitmap) Bitmap
|
||||
Xor(Bitmap) Bitmap
|
||||
Shift(int) (Bitmap, error)
|
||||
Flip(uint64, uint64) Bitmap
|
||||
|
||||
// New() is an atrocity: it creates a new bitmap, unrelated to the
|
||||
// existing bitmap. This lets you create a new bitmap without having
|
||||
// imported any of the packages that have bitmap creation tools, because
|
||||
// the bitmap wrapper type has to give you one.
|
||||
New() Bitmap
|
||||
}
|
||||
|
||||
// SignedBitmap represents a bitmap that can contain both positive and negative
|
||||
// values.
|
||||
type SignedBitmap struct {
|
||||
Pos, Neg Bitmap
|
||||
}
|
||||
|
||||
// A BitmapOp represents a new bitmap operation that should be exposed
|
||||
// in PQL.
|
||||
|
||||
type BitmapOpInput byte
|
||||
type BitmapOpOutput byte
|
||||
type BitmapOpArity byte
|
||||
type BitmapOpPrecall byte
|
||||
type BitmapOpType struct {
|
||||
Input BitmapOpInput
|
||||
Arity BitmapOpArity
|
||||
Output BitmapOpOutput
|
||||
Precall BitmapOpPrecall
|
||||
}
|
||||
|
||||
const (
|
||||
OpArityUnary = BitmapOpArity(iota)
|
||||
OpArityBinary
|
||||
OpArityNary
|
||||
)
|
||||
|
||||
const (
|
||||
// Unary: Exactly one bitmap.
|
||||
OpInputBitmap = BitmapOpInput(iota)
|
||||
// The really weird special case used for BSI, where we end up
|
||||
// needing to do BSI computations. Arguments will be a
|
||||
// single BitmapBSI, and a []Bitmap for other operands if any.
|
||||
OpInputNaryBSI
|
||||
)
|
||||
|
||||
const (
|
||||
OpOutputCount = BitmapOpOutput(iota)
|
||||
OpOutputBitmap
|
||||
OpOutputSignedBitmap
|
||||
)
|
||||
|
||||
const (
|
||||
OpPrecallNone = BitmapOpPrecall(iota)
|
||||
OpPrecallGlobal
|
||||
OpPrecallLocal // unimplemented
|
||||
)
|
||||
|
||||
// Regardless of arity, non-BSI functions should always take []Bitmap.
|
||||
type BitmapOpFunc interface {
|
||||
BitmapOpType() BitmapOpType
|
||||
}
|
||||
|
||||
// BitmapOpBitmap should actually always be func([]Bitmap) Bitmap, but
|
||||
// might be different kinds.
|
||||
type BitmapOpBitmap interface {
|
||||
BitmapOpArity() BitmapOpArity
|
||||
BitmapOpFunc() GenericBitmapOpBitmap
|
||||
}
|
||||
|
||||
// the common underlying type of the other BitmapOpBitmap functions
|
||||
type GenericBitmapOpBitmap func([]Bitmap, map[string]interface{}) Bitmap
|
||||
|
||||
// BitmapBSI represents the way a single BSI field is passed into a function
|
||||
// which takes a BSI field.
|
||||
type BitmapBSI struct {
|
||||
FieldData Bitmap
|
||||
ShardWidth uint64
|
||||
Offset int64
|
||||
Depth uint
|
||||
}
|
||||
|
||||
type BitmapOpBSIBitmap func(BitmapBSI, []Bitmap, map[string]interface{}) SignedBitmap
|
||||
|
||||
func (b BitmapOpBSIBitmap) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputNaryBSI, Arity: OpArityNary, Output: OpOutputSignedBitmap}
|
||||
}
|
||||
|
||||
type BitmapOpBSIBitmapPrecall func(BitmapBSI, []Bitmap, map[string]interface{}) SignedBitmap
|
||||
|
||||
func (b BitmapOpBSIBitmapPrecall) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputNaryBSI, Arity: OpArityNary, Precall: OpPrecallGlobal, Output: OpOutputSignedBitmap}
|
||||
}
|
||||
|
||||
type BitmapOpUnaryCount func([]Bitmap, map[string]interface{}) int64
|
||||
|
||||
func (b BitmapOpUnaryCount) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputBitmap, Arity: OpArityUnary, Output: OpOutputCount}
|
||||
}
|
||||
|
||||
type BitmapOpUnaryBitmap func([]Bitmap, map[string]interface{}) Bitmap
|
||||
|
||||
func (b BitmapOpUnaryBitmap) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputBitmap, Arity: OpArityUnary, Output: OpOutputBitmap}
|
||||
}
|
||||
|
||||
func (b BitmapOpUnaryBitmap) BitmapOpArity() BitmapOpArity {
|
||||
return OpArityUnary
|
||||
}
|
||||
|
||||
func (b BitmapOpUnaryBitmap) BitmapOpFunc() GenericBitmapOpBitmap {
|
||||
return GenericBitmapOpBitmap(b)
|
||||
}
|
||||
|
||||
type BitmapOpBinaryBitmap func([]Bitmap, map[string]interface{}) Bitmap
|
||||
|
||||
func (b BitmapOpBinaryBitmap) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputBitmap, Arity: OpArityBinary, Output: OpOutputBitmap}
|
||||
}
|
||||
|
||||
func (b BitmapOpBinaryBitmap) BitmapOpArity() BitmapOpArity {
|
||||
return OpArityBinary
|
||||
}
|
||||
|
||||
func (b BitmapOpBinaryBitmap) BitmapOpFunc() GenericBitmapOpBitmap {
|
||||
return GenericBitmapOpBitmap(b)
|
||||
}
|
||||
|
||||
type BitmapOpNaryBitmap func([]Bitmap, map[string]interface{}) Bitmap
|
||||
|
||||
func (b BitmapOpNaryBitmap) BitmapOpType() BitmapOpType {
|
||||
return BitmapOpType{Input: OpInputBitmap, Arity: OpArityNary, Output: OpOutputBitmap}
|
||||
}
|
||||
|
||||
func (b BitmapOpNaryBitmap) BitmapOpArity() BitmapOpArity {
|
||||
return OpArityNary
|
||||
}
|
||||
|
||||
func (b BitmapOpNaryBitmap) BitmapOpFunc() GenericBitmapOpBitmap {
|
||||
return GenericBitmapOpBitmap(b)
|
||||
}
|
||||
|
||||
// BitmapOp represents an operation to be supported in PQL. Operations
|
||||
// on bitmaps should always take []Bitmap. Operations on InputNaryBSI should
|
||||
// take a []Bitmap, plus a Bitmap/shard-width/offset/depth.
|
||||
//
|
||||
// Reserved is a list of words to treat as reserved words in a prototype.
|
||||
// This is not currently used but might be later, and I want to have the
|
||||
// concept handy now.
|
||||
type BitmapOp struct {
|
||||
Name string
|
||||
Func BitmapOpFunc
|
||||
Reserved []string
|
||||
}
|
||||
|
||||
// ExtensionInfo tells us about the extension. The ExtensionAPI string
|
||||
// should be "v0". The version is a human-readable version, use something
|
||||
// that seems meaningful. Name and Description are reasonably self-explanatory,
|
||||
// I hope.
|
||||
//
|
||||
// Extensions should define a function:
|
||||
// func ExtensionInfo(extensionAPI string) (*ExtensionInfo, error)
|
||||
// which reports their extension info if they think they can coexist with that
|
||||
// API string.
|
||||
type ExtensionInfo struct {
|
||||
Name string // Extension name.
|
||||
Description string // Short description.
|
||||
Version string // Human-readable version info for extension.
|
||||
ExtensionAPI string // Extension API version. Should be v0 for now.
|
||||
License string // License info.
|
||||
BitmapOps []BitmapOp // List of provided ops.
|
||||
}
|
||||
1
ext/samples/.gitignore
vendored
1
ext/samples/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
*/*.so
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
// Copyright 2019 Pilosa Corp.
|
||||
//
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
|
||||
"github.com/molecula/apophenia"
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
)
|
||||
|
||||
// This could be dynamically generated, but for now it's not.
|
||||
// nolint:unused,deadcode
|
||||
var extInfoTemplate = &ext.ExtensionInfo{
|
||||
Name: "some",
|
||||
Description: "some of the bits/all of the bits/none of the bits",
|
||||
Version: "0.01",
|
||||
ExtensionAPI: "v0",
|
||||
License: "unreleased",
|
||||
BitmapOps: []ext.BitmapOp{
|
||||
{Name: "Some", Func: ext.BitmapOpUnaryBitmap(Some), Reserved: []string{"p", "seed"}},
|
||||
},
|
||||
}
|
||||
|
||||
// ExtensionInfo is the entry point used by the plugin code.
|
||||
func ExtensionInfo(api string) (*ext.ExtensionInfo, error) { // nolint:unused,deadcode
|
||||
return extInfoTemplate, nil
|
||||
}
|
||||
|
||||
const batchSize = 1024
|
||||
|
||||
// Some returns some of the bits from its first input bitmap. Takes seed (int)
|
||||
// and p (float) values. Seed defaults to 0.
|
||||
func Some(inputs []ext.Bitmap, args map[string]interface{}) ext.Bitmap {
|
||||
if len(inputs) == 0 || inputs[0] == nil {
|
||||
return nil
|
||||
}
|
||||
input := inputs[0]
|
||||
min, ok := input.Min()
|
||||
// no bits found?
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
// start at multiple of 128 not greater than min.
|
||||
min &^= 127
|
||||
max := input.Max()
|
||||
p, ok := args["p"].(float64)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
// no bits or impossible probability range
|
||||
if p <= 0 || p > 1 {
|
||||
return nil
|
||||
}
|
||||
// every bit
|
||||
if p == 1 {
|
||||
return inputs[0]
|
||||
}
|
||||
// On failure, we default to 0.
|
||||
seed, _ := args["seed"].(int64)
|
||||
densityScale := uint64(256)
|
||||
density := uint64(p * float64(densityScale))
|
||||
for density == 0 {
|
||||
densityScale <<= 1
|
||||
density = uint64(p * float64(densityScale))
|
||||
// too small
|
||||
if densityScale > (1 << 32) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
w, err := apophenia.NewWeighted(apophenia.NewSequence(seed))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
someBits := input.New()
|
||||
toAdd := make([]uint64, batchSize)
|
||||
toAddN := 0
|
||||
offset := apophenia.OffsetFor(apophenia.SequenceWeighted, 0, 0, 0)
|
||||
for i := min; i < max; i += 128 {
|
||||
offset.Lo = i
|
||||
randomBits := w.Bits(offset, density, densityScale)
|
||||
bit := uint64(0)
|
||||
for randomBits.Lo != 0 {
|
||||
next := uint64(bits.TrailingZeros64(randomBits.Lo) + 1)
|
||||
randomBits.Lo >>= next
|
||||
toAdd[toAddN] = next + bit + i
|
||||
toAddN++
|
||||
bit += next
|
||||
}
|
||||
bit = 64
|
||||
for randomBits.Hi != 0 {
|
||||
next := uint64(bits.TrailingZeros64(randomBits.Hi) + 1)
|
||||
randomBits.Hi >>= next
|
||||
toAdd[toAddN] = next + bit + i
|
||||
toAddN++
|
||||
bit += next
|
||||
}
|
||||
if toAddN > (batchSize - 128) {
|
||||
// ignore error
|
||||
_, _ = someBits.AddN(toAdd[:toAddN]...)
|
||||
toAddN = 0
|
||||
}
|
||||
}
|
||||
if toAddN > 0 {
|
||||
_, _ = someBits.AddN(toAdd[:toAddN]...)
|
||||
}
|
||||
return input.Intersect(someBits)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Printf("this is a plugin module only.\n")
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ package pilosa
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
"github.com/molecula/ext"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
)
|
||||
|
||||
|
|
|
|||
21
extensions/distinct.go
Normal file
21
extensions/distinct.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2019 Pilosa Corp.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build plugindistinct
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
_ "github.com/molecula/extensions/distinct"
|
||||
)
|
||||
18
extensions/dummy.go
Normal file
18
extensions/dummy.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2019 Pilosa Corp.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This package contains only things which are conditional on build
|
||||
// tags.
|
||||
|
||||
package extensions
|
||||
7
go.mod
7
go.mod
|
|
@ -18,7 +18,8 @@ require (
|
|||
github.com/gorilla/mux v1.7.0
|
||||
github.com/hashicorp/memberlist v0.1.3
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/molecula/apophenia v0.0.0-20190827192002-68b7a14a478b
|
||||
github.com/molecula/ext v0.0.0-20191202195653-240f38a75171
|
||||
github.com/molecula/extensions v0.0.0-20191218165536-562244600fd4
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/pelletier/go-toml v1.2.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
|
|
@ -34,15 +35,17 @@ require (
|
|||
github.com/uber-go/atomic v1.4.0 // indirect
|
||||
github.com/uber/jaeger-client-go v2.16.0+incompatible
|
||||
github.com/uber/jaeger-lib v2.2.0+incompatible // indirect
|
||||
github.com/youtube/vitess v2.1.1+incompatible // indirect
|
||||
go.uber.org/atomic v1.4.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 // indirect
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
google.golang.org/grpc v1.24.0
|
||||
modernc.org/mathutil v1.0.0
|
||||
modernc.org/strutil v1.0.0
|
||||
vitess.io/vitess v2.1.1+incompatible // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
|
|
|||
8
go.sum
8
go.sum
|
|
@ -89,6 +89,10 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
|
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/molecula/apophenia v0.0.0-20190827192002-68b7a14a478b h1:cZADDaNYM7xn/nklO3g198JerGQjadFuA0ofxBJgK0Y=
|
||||
github.com/molecula/apophenia v0.0.0-20190827192002-68b7a14a478b/go.mod h1:uXd1BiH7xLmgkhVmspdJLENv6uGWrTL/MQX2TN7Yz9s=
|
||||
github.com/molecula/ext v0.0.0-20191202195653-240f38a75171 h1:4VK7u/RM+54Yaz8aRB9vIaDSnbKi3M0NQYg5tsZvOT4=
|
||||
github.com/molecula/ext v0.0.0-20191202195653-240f38a75171/go.mod h1:r6EIj0GH8dx5xxFLW6Voi1/mX3wXOUkJu6AoEE/xvGQ=
|
||||
github.com/molecula/extensions v0.0.0-20191218165536-562244600fd4 h1:mDB/dicofRVFuRYcCVPk+JBiVKXlfbzMahuqHvrYqu4=
|
||||
github.com/molecula/extensions v0.0.0-20191218165536-562244600fd4/go.mod h1:QQgN5OFjuBAi4Q2UYVMzfvi4k9yvg/qqC+MNFB4I9JI=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
|
|
@ -153,6 +157,8 @@ github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/
|
|||
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/youtube/vitess v2.1.1+incompatible h1:SE+P7DNX/jw5RHFs5CHRhZQjq402EJFCD33JhzQMdDw=
|
||||
github.com/youtube/vitess v2.1.1+incompatible/go.mod h1:hpMim5/30F1r+0P8GGtB29d0gWHr0IZ5unS+CG0zMx8=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
|
@ -210,3 +216,5 @@ modernc.org/mathutil v1.0.0 h1:93vKjrJopTPrtTNpZ8XIovER7iCIH1QU7wNbOQXC60I=
|
|||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0 h1:XVFtQwFVwc02Wk+0L/Z/zDDXO81r5Lhe6iMKmGX3KhE=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
vitess.io/vitess v2.1.1+incompatible h1:nuuGHiWYWpudD3gOCLeGzol2EJ25e/u5Wer2wV1O130=
|
||||
vitess.io/vitess v2.1.1+incompatible/go.mod h1:h4qvkyNYTOC0xI+vcidSWoka0gQAZc9ZPHbkHo48gP0=
|
||||
|
|
|
|||
|
|
@ -148,7 +148,8 @@ func TestClient_MultiNode(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test must return exactly N results.
|
||||
if len(result.Results[0].([]pilosa.Pair)) != topN {
|
||||
pairsField := result.Results[0].(*pilosa.PairsField)
|
||||
if len(pairsField.Pairs) != topN {
|
||||
t.Fatalf("unexpected number of TopN results: %s", spew.Sdump(result))
|
||||
}
|
||||
p := []pilosa.Pair{
|
||||
|
|
@ -158,7 +159,7 @@ func TestClient_MultiNode(t *testing.T) {
|
|||
{ID: 99, Count: 7}}
|
||||
|
||||
// Valdidate the Top 4 result counts.
|
||||
if !reflect.DeepEqual(result.Results[0].([]pilosa.Pair), p) {
|
||||
if !reflect.DeepEqual(pairsField.Pairs, p) {
|
||||
t.Fatalf("Invalid TopN result set: %s", spew.Sdump(result))
|
||||
}
|
||||
|
||||
|
|
@ -605,14 +606,14 @@ func TestClient_ImportKeys(t *testing.T) {
|
|||
Index: "keyed",
|
||||
Query: "TopN(keyedf)",
|
||||
})
|
||||
if pairs, ok := resp.Results[0].([]pilosa.Pair); !ok {
|
||||
if pairs, ok := resp.Results[0].(*pilosa.PairsField); !ok {
|
||||
t.Fatalf("unexpected response type %T", resp.Results[0])
|
||||
} else if !reflect.DeepEqual(pairs, []pilosa.Pair{
|
||||
} else if !reflect.DeepEqual(pairs.Pairs, []pilosa.Pair{
|
||||
{Key: "green", Count: 3},
|
||||
{Key: "blue", Count: 2},
|
||||
{Key: "purple", Count: 1},
|
||||
}) {
|
||||
t.Fatalf("unexpected topn result: %v", pairs)
|
||||
t.Fatalf("unexpected topn result: %v", pairs.Pairs)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -632,14 +633,14 @@ func TestClient_ImportKeys(t *testing.T) {
|
|||
Index: "keyed",
|
||||
Query: "TopN(unkeyedf)",
|
||||
})
|
||||
if pairs, ok := resp.Results[0].([]pilosa.Pair); !ok {
|
||||
if pairs, ok := resp.Results[0].(*pilosa.PairsField); !ok {
|
||||
t.Fatalf("unexpected response type %T", resp.Results[0])
|
||||
} else if !reflect.DeepEqual(pairs, []pilosa.Pair{
|
||||
} else if !reflect.DeepEqual(pairs.Pairs, []pilosa.Pair{
|
||||
{ID: 1, Count: 3},
|
||||
{ID: 2, Count: 2},
|
||||
{ID: 3, Count: 1},
|
||||
}) {
|
||||
t.Fatalf("unexpected topn result: %v", pairs)
|
||||
t.Fatalf("unexpected topn result: %v", pairs.Pairs)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -659,14 +660,14 @@ func TestClient_ImportKeys(t *testing.T) {
|
|||
Index: "unkeyed",
|
||||
Query: "TopN(keyedf)",
|
||||
})
|
||||
if pairs, ok := resp.Results[0].([]pilosa.Pair); !ok {
|
||||
if pairs, ok := resp.Results[0].(*pilosa.PairsField); !ok {
|
||||
t.Fatalf("unexpected response type %T", resp.Results[0])
|
||||
} else if !reflect.DeepEqual(pairs, []pilosa.Pair{
|
||||
} else if !reflect.DeepEqual(pairs.Pairs, []pilosa.Pair{
|
||||
{Key: "green", Count: 3},
|
||||
{Key: "blue", Count: 2},
|
||||
{Key: "purple", Count: 1},
|
||||
}) {
|
||||
t.Fatalf("unexpected topn result: %v", pairs)
|
||||
t.Fatalf("unexpected topn result: %v", pairs.Pairs)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -704,14 +705,14 @@ func TestClient_ImportKeys(t *testing.T) {
|
|||
Index: "keyed",
|
||||
Query: "TopN(keyedf0)",
|
||||
})
|
||||
if pairs, ok := resp.Results[0].([]pilosa.Pair); !ok {
|
||||
if pairs, ok := resp.Results[0].(*pilosa.PairsField); !ok {
|
||||
t.Fatalf("unexpected response type %T", resp.Results[0])
|
||||
} else if !reflect.DeepEqual(pairs, []pilosa.Pair{
|
||||
} else if !reflect.DeepEqual(pairs.Pairs, []pilosa.Pair{
|
||||
{Key: "green", Count: 3},
|
||||
{Key: "blue", Count: 2},
|
||||
{Key: "purple", Count: 1},
|
||||
}) {
|
||||
t.Fatalf("unexpected topn result: %v", pairs)
|
||||
t.Fatalf("unexpected topn result: %v", pairs.Pairs)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -736,14 +737,14 @@ func TestClient_ImportKeys(t *testing.T) {
|
|||
Index: "keyed",
|
||||
Query: "TopN(keyedf1)",
|
||||
})
|
||||
if pairs, ok := resp.Results[0].([]pilosa.Pair); !ok {
|
||||
if pairs, ok := resp.Results[0].(*pilosa.PairsField); !ok {
|
||||
t.Fatalf("unexpected response type %T", resp.Results[0])
|
||||
} else if !reflect.DeepEqual(pairs, []pilosa.Pair{
|
||||
} else if !reflect.DeepEqual(pairs.Pairs, []pilosa.Pair{
|
||||
{Key: "green", Count: 3},
|
||||
{Key: "blue", Count: 2},
|
||||
{Key: "purple", Count: 1},
|
||||
}) {
|
||||
t.Fatalf("unexpected topn result: %#v", pairs)
|
||||
t.Fatalf("unexpected topn result: %#v", pairs.Pairs)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -51,6 +51,6 @@ services:
|
|||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command:
|
||||
- "cd /go/src/github.com/pilosa/pilosa/ && go test -v -count=1 github.com/pilosa/pilosa/internal/clustertests"
|
||||
- "cd /go/src/github.com/pilosa/pilosa/ && go test -mod=vendor -v -count=1 github.com/pilosa/pilosa/v2/internal/clustertests"
|
||||
networks:
|
||||
pilosanet:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func (m *IndexMeta) Reset() { *m = IndexMeta{} }
|
|||
func (m *IndexMeta) String() string { return proto.CompactTextString(m) }
|
||||
func (*IndexMeta) ProtoMessage() {}
|
||||
func (*IndexMeta) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{0}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{0}
|
||||
}
|
||||
func (m *IndexMeta) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -96,7 +96,7 @@ func (m *FieldOptions) Reset() { *m = FieldOptions{} }
|
|||
func (m *FieldOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*FieldOptions) ProtoMessage() {}
|
||||
func (*FieldOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{1}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{1}
|
||||
}
|
||||
func (m *FieldOptions) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -213,7 +213,7 @@ func (m *ImportResponse) Reset() { *m = ImportResponse{} }
|
|||
func (m *ImportResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ImportResponse) ProtoMessage() {}
|
||||
func (*ImportResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{2}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{2}
|
||||
}
|
||||
func (m *ImportResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -264,7 +264,7 @@ func (m *BlockDataRequest) Reset() { *m = BlockDataRequest{} }
|
|||
func (m *BlockDataRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*BlockDataRequest) ProtoMessage() {}
|
||||
func (*BlockDataRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{3}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{3}
|
||||
}
|
||||
func (m *BlockDataRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -340,7 +340,7 @@ func (m *BlockDataResponse) Reset() { *m = BlockDataResponse{} }
|
|||
func (m *BlockDataResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*BlockDataResponse) ProtoMessage() {}
|
||||
func (*BlockDataResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{4}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{4}
|
||||
}
|
||||
func (m *BlockDataResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -394,7 +394,7 @@ func (m *Cache) Reset() { *m = Cache{} }
|
|||
func (m *Cache) String() string { return proto.CompactTextString(m) }
|
||||
func (*Cache) ProtoMessage() {}
|
||||
func (*Cache) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{5}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{5}
|
||||
}
|
||||
func (m *Cache) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -441,7 +441,7 @@ func (m *MaxShards) Reset() { *m = MaxShards{} }
|
|||
func (m *MaxShards) String() string { return proto.CompactTextString(m) }
|
||||
func (*MaxShards) ProtoMessage() {}
|
||||
func (*MaxShards) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{6}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{6}
|
||||
}
|
||||
func (m *MaxShards) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -490,7 +490,7 @@ func (m *CreateShardMessage) Reset() { *m = CreateShardMessage{} }
|
|||
func (m *CreateShardMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateShardMessage) ProtoMessage() {}
|
||||
func (*CreateShardMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{7}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{7}
|
||||
}
|
||||
func (m *CreateShardMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -551,7 +551,7 @@ func (m *DeleteIndexMessage) Reset() { *m = DeleteIndexMessage{} }
|
|||
func (m *DeleteIndexMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteIndexMessage) ProtoMessage() {}
|
||||
func (*DeleteIndexMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{8}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{8}
|
||||
}
|
||||
func (m *DeleteIndexMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -599,7 +599,7 @@ func (m *CreateIndexMessage) Reset() { *m = CreateIndexMessage{} }
|
|||
func (m *CreateIndexMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateIndexMessage) ProtoMessage() {}
|
||||
func (*CreateIndexMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{9}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{9}
|
||||
}
|
||||
func (m *CreateIndexMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -655,7 +655,7 @@ func (m *CreateFieldMessage) Reset() { *m = CreateFieldMessage{} }
|
|||
func (m *CreateFieldMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateFieldMessage) ProtoMessage() {}
|
||||
func (*CreateFieldMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{10}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{10}
|
||||
}
|
||||
func (m *CreateFieldMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -717,7 +717,7 @@ func (m *DeleteFieldMessage) Reset() { *m = DeleteFieldMessage{} }
|
|||
func (m *DeleteFieldMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteFieldMessage) ProtoMessage() {}
|
||||
func (*DeleteFieldMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{11}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{11}
|
||||
}
|
||||
func (m *DeleteFieldMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -773,7 +773,7 @@ func (m *DeleteAvailableShardMessage) Reset() { *m = DeleteAvailableShar
|
|||
func (m *DeleteAvailableShardMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteAvailableShardMessage) ProtoMessage() {}
|
||||
func (*DeleteAvailableShardMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{12}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{12}
|
||||
}
|
||||
func (m *DeleteAvailableShardMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -836,7 +836,7 @@ func (m *Field) Reset() { *m = Field{} }
|
|||
func (m *Field) String() string { return proto.CompactTextString(m) }
|
||||
func (*Field) ProtoMessage() {}
|
||||
func (*Field) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{13}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{13}
|
||||
}
|
||||
func (m *Field) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -897,7 +897,7 @@ func (m *Schema) Reset() { *m = Schema{} }
|
|||
func (m *Schema) String() string { return proto.CompactTextString(m) }
|
||||
func (*Schema) ProtoMessage() {}
|
||||
func (*Schema) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{14}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{14}
|
||||
}
|
||||
func (m *Schema) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -945,7 +945,7 @@ func (m *Index) Reset() { *m = Index{} }
|
|||
func (m *Index) String() string { return proto.CompactTextString(m) }
|
||||
func (*Index) ProtoMessage() {}
|
||||
func (*Index) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{15}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{15}
|
||||
}
|
||||
func (m *Index) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1001,7 +1001,7 @@ func (m *URI) Reset() { *m = URI{} }
|
|||
func (m *URI) String() string { return proto.CompactTextString(m) }
|
||||
func (*URI) ProtoMessage() {}
|
||||
func (*URI) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{16}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{16}
|
||||
}
|
||||
func (m *URI) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1065,7 +1065,7 @@ func (m *Node) Reset() { *m = Node{} }
|
|||
func (m *Node) String() string { return proto.CompactTextString(m) }
|
||||
func (*Node) ProtoMessage() {}
|
||||
func (*Node) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{17}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{17}
|
||||
}
|
||||
func (m *Node) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1134,7 +1134,7 @@ func (m *NodeStateMessage) Reset() { *m = NodeStateMessage{} }
|
|||
func (m *NodeStateMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*NodeStateMessage) ProtoMessage() {}
|
||||
func (*NodeStateMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{18}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{18}
|
||||
}
|
||||
func (m *NodeStateMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1189,7 +1189,7 @@ func (m *NodeEventMessage) Reset() { *m = NodeEventMessage{} }
|
|||
func (m *NodeEventMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*NodeEventMessage) ProtoMessage() {}
|
||||
func (*NodeEventMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{19}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{19}
|
||||
}
|
||||
func (m *NodeEventMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1245,7 +1245,7 @@ func (m *NodeStatus) Reset() { *m = NodeStatus{} }
|
|||
func (m *NodeStatus) String() string { return proto.CompactTextString(m) }
|
||||
func (*NodeStatus) ProtoMessage() {}
|
||||
func (*NodeStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{20}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{20}
|
||||
}
|
||||
func (m *NodeStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1307,7 +1307,7 @@ func (m *IndexStatus) Reset() { *m = IndexStatus{} }
|
|||
func (m *IndexStatus) String() string { return proto.CompactTextString(m) }
|
||||
func (*IndexStatus) ProtoMessage() {}
|
||||
func (*IndexStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{21}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{21}
|
||||
}
|
||||
func (m *IndexStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1362,7 +1362,7 @@ func (m *FieldStatus) Reset() { *m = FieldStatus{} }
|
|||
func (m *FieldStatus) String() string { return proto.CompactTextString(m) }
|
||||
func (*FieldStatus) ProtoMessage() {}
|
||||
func (*FieldStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{22}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{22}
|
||||
}
|
||||
func (m *FieldStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1418,7 +1418,7 @@ func (m *ClusterStatus) Reset() { *m = ClusterStatus{} }
|
|||
func (m *ClusterStatus) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClusterStatus) ProtoMessage() {}
|
||||
func (*ClusterStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{23}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{23}
|
||||
}
|
||||
func (m *ClusterStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1482,7 +1482,7 @@ func (m *BSIGroup) Reset() { *m = BSIGroup{} }
|
|||
func (m *BSIGroup) String() string { return proto.CompactTextString(m) }
|
||||
func (*BSIGroup) ProtoMessage() {}
|
||||
func (*BSIGroup) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{24}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{24}
|
||||
}
|
||||
func (m *BSIGroup) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1552,7 +1552,7 @@ func (m *CreateViewMessage) Reset() { *m = CreateViewMessage{} }
|
|||
func (m *CreateViewMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateViewMessage) ProtoMessage() {}
|
||||
func (*CreateViewMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{25}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{25}
|
||||
}
|
||||
func (m *CreateViewMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1615,7 +1615,7 @@ func (m *DeleteViewMessage) Reset() { *m = DeleteViewMessage{} }
|
|||
func (m *DeleteViewMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteViewMessage) ProtoMessage() {}
|
||||
func (*DeleteViewMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{26}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{26}
|
||||
}
|
||||
func (m *DeleteViewMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1681,7 +1681,7 @@ func (m *ResizeInstruction) Reset() { *m = ResizeInstruction{} }
|
|||
func (m *ResizeInstruction) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResizeInstruction) ProtoMessage() {}
|
||||
func (*ResizeInstruction) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{27}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{27}
|
||||
}
|
||||
func (m *ResizeInstruction) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1767,7 +1767,7 @@ func (m *ResizeSource) Reset() { *m = ResizeSource{} }
|
|||
func (m *ResizeSource) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResizeSource) ProtoMessage() {}
|
||||
func (*ResizeSource) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{28}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{28}
|
||||
}
|
||||
func (m *ResizeSource) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1844,7 +1844,7 @@ func (m *ResizeInstructionComplete) Reset() { *m = ResizeInstructionComp
|
|||
func (m *ResizeInstructionComplete) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResizeInstructionComplete) ProtoMessage() {}
|
||||
func (*ResizeInstructionComplete) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{29}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{29}
|
||||
}
|
||||
func (m *ResizeInstructionComplete) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1905,7 +1905,7 @@ func (m *SetCoordinatorMessage) Reset() { *m = SetCoordinatorMessage{} }
|
|||
func (m *SetCoordinatorMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*SetCoordinatorMessage) ProtoMessage() {}
|
||||
func (*SetCoordinatorMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{30}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{30}
|
||||
}
|
||||
func (m *SetCoordinatorMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -1952,7 +1952,7 @@ func (m *UpdateCoordinatorMessage) Reset() { *m = UpdateCoordinatorMessa
|
|||
func (m *UpdateCoordinatorMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateCoordinatorMessage) ProtoMessage() {}
|
||||
func (*UpdateCoordinatorMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{31}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{31}
|
||||
}
|
||||
func (m *UpdateCoordinatorMessage) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -2000,7 +2000,7 @@ func (m *Topology) Reset() { *m = Topology{} }
|
|||
func (m *Topology) String() string { return proto.CompactTextString(m) }
|
||||
func (*Topology) ProtoMessage() {}
|
||||
func (*Topology) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{32}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{32}
|
||||
}
|
||||
func (m *Topology) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -2053,7 +2053,7 @@ func (m *RecalculateCaches) Reset() { *m = RecalculateCaches{} }
|
|||
func (m *RecalculateCaches) String() string { return proto.CompactTextString(m) }
|
||||
func (*RecalculateCaches) ProtoMessage() {}
|
||||
func (*RecalculateCaches) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_private_b229d027a4642df7, []int{33}
|
||||
return fileDescriptor_private_e6d12fddb5948a73, []int{33}
|
||||
}
|
||||
func (m *RecalculateCaches) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
|
|
@ -8982,9 +8982,9 @@ var (
|
|||
ErrIntOverflowPrivate = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() { proto.RegisterFile("private.proto", fileDescriptor_private_b229d027a4642df7) }
|
||||
func init() { proto.RegisterFile("private.proto", fileDescriptor_private_e6d12fddb5948a73) }
|
||||
|
||||
var fileDescriptor_private_b229d027a4642df7 = []byte{
|
||||
var fileDescriptor_private_e6d12fddb5948a73 = []byte{
|
||||
// 1174 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xdb, 0x6e, 0x1b, 0x45,
|
||||
0x18, 0x66, 0x0f, 0x71, 0xec, 0xdf, 0x71, 0x0e, 0xdb, 0x36, 0x6c, 0x0b, 0x0a, 0x66, 0x54, 0x51,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,6 +25,16 @@ message Pair {
|
|||
uint64 Count = 2;
|
||||
}
|
||||
|
||||
message PairField {
|
||||
Pair Pair = 1;
|
||||
string Field = 2;
|
||||
}
|
||||
|
||||
message PairsField {
|
||||
repeated Pair Pairs = 1;
|
||||
string Field = 2;
|
||||
}
|
||||
|
||||
message FieldRow{
|
||||
string Field = 1;
|
||||
uint64 RowID = 2;
|
||||
|
|
@ -88,6 +98,7 @@ message QueryResult {
|
|||
repeated GroupCount GroupCounts = 8;
|
||||
RowIdentifiers RowIdentifiers = 9;
|
||||
SignedRow SignedRow = 10;
|
||||
PairsField PairsField = 11;
|
||||
}
|
||||
|
||||
message ImportRequest {
|
||||
|
|
@ -137,4 +148,4 @@ message ImportColumnAttrsRequest {
|
|||
string AttrKey = 3;
|
||||
repeated string AttrVals = 4;
|
||||
repeated uint64 ColumnIDs = 5;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
pql/ast.go
17
pql/ast.go
|
|
@ -23,7 +23,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
"github.com/molecula/ext"
|
||||
)
|
||||
|
||||
// Query represents a PQL query.
|
||||
|
|
@ -347,10 +347,17 @@ var callInfoByFunc = map[string]callInfo{
|
|||
"Difference": {allowUnknown: false},
|
||||
"Intersect": {allowUnknown: false},
|
||||
"Not": {allowUnknown: false},
|
||||
"ClearRow": {allowUnknown: true},
|
||||
"Store": {allowUnknown: true},
|
||||
"MinRow": allowField,
|
||||
"MaxRow": allowField,
|
||||
"All": {
|
||||
allowUnknown: false,
|
||||
prototypes: map[string]interface{}{
|
||||
"limit": int64(0),
|
||||
"offset": int64(0),
|
||||
},
|
||||
},
|
||||
"ClearRow": {allowUnknown: true},
|
||||
"Store": {allowUnknown: true},
|
||||
"MinRow": allowField,
|
||||
"MaxRow": allowField,
|
||||
"Rows": {
|
||||
allowUnknown: false,
|
||||
prototypes: map[string]interface{}{
|
||||
|
|
|
|||
|
|
@ -14,10 +14,254 @@
|
|||
|
||||
package pilosa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// StreamClient is an interface for a stream
|
||||
// which can return a RowResponse sent to a
|
||||
// stream via Send().
|
||||
type StreamClient interface {
|
||||
Recv() (*RowResponse, error)
|
||||
}
|
||||
|
||||
// StreamServer is an interface for a stream
|
||||
// which can accept a RowResponse to be later
|
||||
// returned by the stream via Recv().
|
||||
type StreamServer interface {
|
||||
Send(*RowResponse) error
|
||||
}
|
||||
|
||||
// EOF acts as an io.EOF encoded into a RowResponse.
|
||||
var EOF *RowResponse = &RowResponse{
|
||||
StatusError: &StatusError{
|
||||
Code: 0,
|
||||
Message: "EOF",
|
||||
},
|
||||
}
|
||||
|
||||
// Error is a helper function to create a RowResponse
|
||||
// based on an error message. If the error is a grpc
|
||||
// Status, then the status code is passed through.
|
||||
func Error(err error) *RowResponse {
|
||||
status, _ := status.FromError(err)
|
||||
return &RowResponse{
|
||||
StatusError: &StatusError{
|
||||
Code: uint32(status.Code()),
|
||||
Message: status.Err().Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorWrap prepends a message to the existing status
|
||||
// error message.
|
||||
func ErrorWrap(err error, message string) *RowResponse {
|
||||
status, _ := status.FromError(err)
|
||||
return &RowResponse{
|
||||
StatusError: &StatusError{
|
||||
Code: uint32(status.Code()),
|
||||
Message: message + ": " + status.Err().Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorWrapf prepends a message to the existing status
|
||||
// error message with the format specifier.
|
||||
func ErrorWrapf(err error, format string, args ...interface{}) *RowResponse {
|
||||
status, _ := status.FromError(err)
|
||||
return &RowResponse{
|
||||
StatusError: &StatusError{
|
||||
Code: uint32(status.Code()),
|
||||
Message: fmt.Sprintf(format, args...) + ": " + status.Err().Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorCode is a helper function to create a RowResponse
|
||||
// based on a grpc status code and an error message.
|
||||
func ErrorCode(err error, c codes.Code) *RowResponse {
|
||||
return &RowResponse{
|
||||
StatusError: &StatusError{
|
||||
Code: uint32(c),
|
||||
Message: err.Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RowResponseSorter implements the sort interface for a
|
||||
// provided []RowResponse based on the column index, type,
|
||||
// and sort direction.
|
||||
type RowResponseSorter struct {
|
||||
colIdx []int
|
||||
colDescending []bool
|
||||
colType []string
|
||||
|
||||
rrs []*RowResponse
|
||||
}
|
||||
|
||||
// NewRowResponseSorter return a new RowResponseSorter. It
|
||||
// does input validation and returns an error if the inputs
|
||||
// aren't compatible.
|
||||
func NewRowResponseSorter(idxs []int, dirs []bool, typs []string, rrs []*RowResponse) (*RowResponseSorter, error) {
|
||||
// Ensure the input slices are non-empty and equal size.
|
||||
if len(idxs) == 0 {
|
||||
return nil, errors.New("index list cannot be empty")
|
||||
}
|
||||
if len(dirs) != len(idxs) || len(typs) != len(idxs) {
|
||||
return nil, errors.New("index, direction, and type lists must be the same size")
|
||||
}
|
||||
|
||||
// Ensure the provided data types are supported by the sorter.
|
||||
for i := range typs {
|
||||
switch typs[i] {
|
||||
case "[]uint64", "[]string", "bool", "float64", "int64", "string", "uint64":
|
||||
// pass
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported data type: %s", typs[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure max(colIdx) is within size of rr.Columns.
|
||||
if len(rrs) > 0 {
|
||||
var maxColIdx int
|
||||
for i := range idxs {
|
||||
if idxs[i] > maxColIdx {
|
||||
maxColIdx = idxs[i]
|
||||
}
|
||||
}
|
||||
if maxColIdx >= len(rrs[0].Columns) {
|
||||
return nil, fmt.Errorf("column index is out of range: %d", maxColIdx)
|
||||
}
|
||||
}
|
||||
|
||||
return &RowResponseSorter{
|
||||
colIdx: idxs,
|
||||
colDescending: dirs,
|
||||
colType: typs,
|
||||
rrs: rrs,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (r RowResponseSorter) Len() int { return len(r.rrs) }
|
||||
func (r RowResponseSorter) Swap(i, j int) { r.rrs[i], r.rrs[j] = r.rrs[j], r.rrs[i] }
|
||||
func (r RowResponseSorter) Less(i, j int) bool {
|
||||
ri := r.rrs[i]
|
||||
rj := r.rrs[j]
|
||||
|
||||
for i, idx := range r.colIdx {
|
||||
coli := ri.Columns[idx]
|
||||
colj := rj.Columns[idx]
|
||||
var comp int
|
||||
switch r.colType[i] {
|
||||
case "[]uint64":
|
||||
ai := coli.GetUint64ArrayVal().Vals
|
||||
aj := colj.GetUint64ArrayVal().Vals
|
||||
comp = func() int {
|
||||
for ii := 0; ii < len(ai); ii++ {
|
||||
if len(aj) == ii {
|
||||
return 1
|
||||
}
|
||||
piv := ai[ii]
|
||||
pjv := aj[ii]
|
||||
if piv == pjv {
|
||||
continue
|
||||
} else if piv < pjv {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
if len(aj) > len(ai) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}()
|
||||
case "[]string":
|
||||
ai := coli.GetStringArrayVal().Vals
|
||||
aj := colj.GetStringArrayVal().Vals
|
||||
comp = func() int {
|
||||
for ii := 0; ii < len(ai); ii++ {
|
||||
if len(aj) == ii {
|
||||
return 1
|
||||
}
|
||||
sComp := strings.Compare(ai[ii], aj[ii])
|
||||
if sComp == 0 {
|
||||
continue
|
||||
} else {
|
||||
return sComp
|
||||
}
|
||||
}
|
||||
if len(aj) > len(ai) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}()
|
||||
case "bool":
|
||||
bi := coli.GetBoolVal()
|
||||
bj := colj.GetBoolVal()
|
||||
if bi == bj {
|
||||
comp = 0
|
||||
} else if !bi && bj {
|
||||
comp = -1
|
||||
} else {
|
||||
comp = 1
|
||||
}
|
||||
case "float64":
|
||||
fi := coli.GetFloat64Val()
|
||||
fj := colj.GetFloat64Val()
|
||||
if fi == fj {
|
||||
comp = 0
|
||||
} else if fi < fj {
|
||||
comp = -1
|
||||
} else {
|
||||
comp = 1
|
||||
}
|
||||
case "int64":
|
||||
ni := coli.GetInt64Val()
|
||||
nj := colj.GetInt64Val()
|
||||
if ni == nj {
|
||||
comp = 0
|
||||
} else if ni < nj {
|
||||
comp = -1
|
||||
} else {
|
||||
comp = 1
|
||||
}
|
||||
case "string":
|
||||
comp = strings.Compare(coli.GetStringVal(), colj.GetStringVal())
|
||||
case "uint64":
|
||||
ni := coli.GetUint64Val()
|
||||
nj := colj.GetUint64Val()
|
||||
if ni == nj {
|
||||
comp = 0
|
||||
} else if ni < nj {
|
||||
comp = -1
|
||||
} else {
|
||||
comp = 1
|
||||
}
|
||||
}
|
||||
|
||||
isDescending := r.colDescending[i]
|
||||
|
||||
switch comp {
|
||||
case 0:
|
||||
continue
|
||||
case -1:
|
||||
if isDescending {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
case 1:
|
||||
if isDescending {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@
|
|||
package pilosa
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
|
|
@ -22,7 +23,7 @@ var _ = math.Inf
|
|||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type QueryPQLRequest struct {
|
||||
Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"`
|
||||
|
|
@ -71,9 +72,57 @@ func (m *QueryPQLRequest) GetPql() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
type StatusError struct {
|
||||
Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *StatusError) Reset() { *m = StatusError{} }
|
||||
func (m *StatusError) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatusError) ProtoMessage() {}
|
||||
func (*StatusError) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{1}
|
||||
}
|
||||
|
||||
func (m *StatusError) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatusError.Unmarshal(m, b)
|
||||
}
|
||||
func (m *StatusError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_StatusError.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *StatusError) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StatusError.Merge(m, src)
|
||||
}
|
||||
func (m *StatusError) XXX_Size() int {
|
||||
return xxx_messageInfo_StatusError.Size(m)
|
||||
}
|
||||
func (m *StatusError) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StatusError.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StatusError proto.InternalMessageInfo
|
||||
|
||||
func (m *StatusError) GetCode() uint32 {
|
||||
if m != nil {
|
||||
return m.Code
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatusError) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RowResponse struct {
|
||||
Headers []*ColumnInfo `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"`
|
||||
Columns []*ColumnResponse `protobuf:"bytes,2,rep,name=columns,proto3" json:"columns,omitempty"`
|
||||
StatusError *StatusError `protobuf:"bytes,3,opt,name=StatusError,proto3" json:"StatusError,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -83,7 +132,7 @@ func (m *RowResponse) Reset() { *m = RowResponse{} }
|
|||
func (m *RowResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RowResponse) ProtoMessage() {}
|
||||
func (*RowResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{1}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{2}
|
||||
}
|
||||
|
||||
func (m *RowResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -118,6 +167,13 @@ func (m *RowResponse) GetColumns() []*ColumnResponse {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *RowResponse) GetStatusError() *StatusError {
|
||||
if m != nil {
|
||||
return m.StatusError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ColumnInfo struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Datatype string `protobuf:"bytes,2,opt,name=datatype,proto3" json:"datatype,omitempty"`
|
||||
|
|
@ -130,7 +186,7 @@ func (m *ColumnInfo) Reset() { *m = ColumnInfo{} }
|
|||
func (m *ColumnInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*ColumnInfo) ProtoMessage() {}
|
||||
func (*ColumnInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{2}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{3}
|
||||
}
|
||||
|
||||
func (m *ColumnInfo) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -185,7 +241,7 @@ func (m *ColumnResponse) Reset() { *m = ColumnResponse{} }
|
|||
func (m *ColumnResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ColumnResponse) ProtoMessage() {}
|
||||
func (*ColumnResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{3}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{4}
|
||||
}
|
||||
|
||||
func (m *ColumnResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -321,9 +377,9 @@ func (m *ColumnResponse) GetFloat64Val() float64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*ColumnResponse) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
// XXX_OneofFuncs is for the internal use of the proto package.
|
||||
func (*ColumnResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
|
||||
return _ColumnResponse_OneofMarshaler, _ColumnResponse_OneofUnmarshaler, _ColumnResponse_OneofSizer, []interface{}{
|
||||
(*ColumnResponse_StringVal)(nil),
|
||||
(*ColumnResponse_Uint64Val)(nil),
|
||||
(*ColumnResponse_Int64Val)(nil),
|
||||
|
|
@ -335,10 +391,162 @@ func (*ColumnResponse) XXX_OneofWrappers() []interface{} {
|
|||
}
|
||||
}
|
||||
|
||||
func _ColumnResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
||||
m := msg.(*ColumnResponse)
|
||||
// columnVal
|
||||
switch x := m.ColumnVal.(type) {
|
||||
case *ColumnResponse_StringVal:
|
||||
b.EncodeVarint(1<<3 | proto.WireBytes)
|
||||
b.EncodeStringBytes(x.StringVal)
|
||||
case *ColumnResponse_Uint64Val:
|
||||
b.EncodeVarint(2<<3 | proto.WireVarint)
|
||||
b.EncodeVarint(uint64(x.Uint64Val))
|
||||
case *ColumnResponse_Int64Val:
|
||||
b.EncodeVarint(3<<3 | proto.WireVarint)
|
||||
b.EncodeVarint(uint64(x.Int64Val))
|
||||
case *ColumnResponse_BoolVal:
|
||||
t := uint64(0)
|
||||
if x.BoolVal {
|
||||
t = 1
|
||||
}
|
||||
b.EncodeVarint(4<<3 | proto.WireVarint)
|
||||
b.EncodeVarint(t)
|
||||
case *ColumnResponse_BlobVal:
|
||||
b.EncodeVarint(5<<3 | proto.WireBytes)
|
||||
b.EncodeRawBytes(x.BlobVal)
|
||||
case *ColumnResponse_Uint64ArrayVal:
|
||||
b.EncodeVarint(6<<3 | proto.WireBytes)
|
||||
if err := b.EncodeMessage(x.Uint64ArrayVal); err != nil {
|
||||
return err
|
||||
}
|
||||
case *ColumnResponse_StringArrayVal:
|
||||
b.EncodeVarint(7<<3 | proto.WireBytes)
|
||||
if err := b.EncodeMessage(x.StringArrayVal); err != nil {
|
||||
return err
|
||||
}
|
||||
case *ColumnResponse_Float64Val:
|
||||
b.EncodeVarint(8<<3 | proto.WireFixed64)
|
||||
b.EncodeFixed64(math.Float64bits(x.Float64Val))
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("ColumnResponse.ColumnVal has unexpected type %T", x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _ColumnResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
||||
m := msg.(*ColumnResponse)
|
||||
switch tag {
|
||||
case 1: // columnVal.stringVal
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeStringBytes()
|
||||
m.ColumnVal = &ColumnResponse_StringVal{x}
|
||||
return true, err
|
||||
case 2: // columnVal.uint64Val
|
||||
if wire != proto.WireVarint {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeVarint()
|
||||
m.ColumnVal = &ColumnResponse_Uint64Val{x}
|
||||
return true, err
|
||||
case 3: // columnVal.int64Val
|
||||
if wire != proto.WireVarint {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeVarint()
|
||||
m.ColumnVal = &ColumnResponse_Int64Val{int64(x)}
|
||||
return true, err
|
||||
case 4: // columnVal.boolVal
|
||||
if wire != proto.WireVarint {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeVarint()
|
||||
m.ColumnVal = &ColumnResponse_BoolVal{x != 0}
|
||||
return true, err
|
||||
case 5: // columnVal.blobVal
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeRawBytes(true)
|
||||
m.ColumnVal = &ColumnResponse_BlobVal{x}
|
||||
return true, err
|
||||
case 6: // columnVal.uint64ArrayVal
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
msg := new(Uint64Array)
|
||||
err := b.DecodeMessage(msg)
|
||||
m.ColumnVal = &ColumnResponse_Uint64ArrayVal{msg}
|
||||
return true, err
|
||||
case 7: // columnVal.stringArrayVal
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
msg := new(StringArray)
|
||||
err := b.DecodeMessage(msg)
|
||||
m.ColumnVal = &ColumnResponse_StringArrayVal{msg}
|
||||
return true, err
|
||||
case 8: // columnVal.float64Val
|
||||
if wire != proto.WireFixed64 {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeFixed64()
|
||||
m.ColumnVal = &ColumnResponse_Float64Val{math.Float64frombits(x)}
|
||||
return true, err
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func _ColumnResponse_OneofSizer(msg proto.Message) (n int) {
|
||||
m := msg.(*ColumnResponse)
|
||||
// columnVal
|
||||
switch x := m.ColumnVal.(type) {
|
||||
case *ColumnResponse_StringVal:
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(len(x.StringVal)))
|
||||
n += len(x.StringVal)
|
||||
case *ColumnResponse_Uint64Val:
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(x.Uint64Val))
|
||||
case *ColumnResponse_Int64Val:
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(x.Int64Val))
|
||||
case *ColumnResponse_BoolVal:
|
||||
n += 1 // tag and wire
|
||||
n += 1
|
||||
case *ColumnResponse_BlobVal:
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(len(x.BlobVal)))
|
||||
n += len(x.BlobVal)
|
||||
case *ColumnResponse_Uint64ArrayVal:
|
||||
s := proto.Size(x.Uint64ArrayVal)
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(s))
|
||||
n += s
|
||||
case *ColumnResponse_StringArrayVal:
|
||||
s := proto.Size(x.StringArrayVal)
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(s))
|
||||
n += s
|
||||
case *ColumnResponse_Float64Val:
|
||||
n += 1 // tag and wire
|
||||
n += 8
|
||||
case nil:
|
||||
default:
|
||||
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
type InspectRequest struct {
|
||||
Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"`
|
||||
Columns *IdsOrKeys `protobuf:"bytes,2,opt,name=columns,proto3" json:"columns,omitempty"`
|
||||
FilterFields []string `protobuf:"bytes,3,rep,name=filterFields,proto3" json:"filterFields,omitempty"`
|
||||
Limit uint64 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"`
|
||||
Offset uint64 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -348,7 +556,7 @@ func (m *InspectRequest) Reset() { *m = InspectRequest{} }
|
|||
func (m *InspectRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*InspectRequest) ProtoMessage() {}
|
||||
func (*InspectRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{4}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{5}
|
||||
}
|
||||
|
||||
func (m *InspectRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -390,6 +598,20 @@ func (m *InspectRequest) GetFilterFields() []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *InspectRequest) GetLimit() uint64 {
|
||||
if m != nil {
|
||||
return m.Limit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *InspectRequest) GetOffset() uint64 {
|
||||
if m != nil {
|
||||
return m.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Uint64Array struct {
|
||||
Vals []uint64 `protobuf:"varint,1,rep,packed,name=vals,proto3" json:"vals,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
|
|
@ -401,7 +623,7 @@ func (m *Uint64Array) Reset() { *m = Uint64Array{} }
|
|||
func (m *Uint64Array) String() string { return proto.CompactTextString(m) }
|
||||
func (*Uint64Array) ProtoMessage() {}
|
||||
func (*Uint64Array) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{5}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{6}
|
||||
}
|
||||
|
||||
func (m *Uint64Array) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -440,7 +662,7 @@ func (m *StringArray) Reset() { *m = StringArray{} }
|
|||
func (m *StringArray) String() string { return proto.CompactTextString(m) }
|
||||
func (*StringArray) ProtoMessage() {}
|
||||
func (*StringArray) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{6}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{7}
|
||||
}
|
||||
|
||||
func (m *StringArray) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -482,7 +704,7 @@ func (m *IdsOrKeys) Reset() { *m = IdsOrKeys{} }
|
|||
func (m *IdsOrKeys) String() string { return proto.CompactTextString(m) }
|
||||
func (*IdsOrKeys) ProtoMessage() {}
|
||||
func (*IdsOrKeys) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{7}
|
||||
return fileDescriptor_ef0691a44d1e275c, []int{8}
|
||||
}
|
||||
|
||||
func (m *IdsOrKeys) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -540,16 +762,83 @@ func (m *IdsOrKeys) GetKeys() *StringArray {
|
|||
return nil
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*IdsOrKeys) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
// XXX_OneofFuncs is for the internal use of the proto package.
|
||||
func (*IdsOrKeys) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
|
||||
return _IdsOrKeys_OneofMarshaler, _IdsOrKeys_OneofUnmarshaler, _IdsOrKeys_OneofSizer, []interface{}{
|
||||
(*IdsOrKeys_Ids)(nil),
|
||||
(*IdsOrKeys_Keys)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
func _IdsOrKeys_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
||||
m := msg.(*IdsOrKeys)
|
||||
// type
|
||||
switch x := m.Type.(type) {
|
||||
case *IdsOrKeys_Ids:
|
||||
b.EncodeVarint(1<<3 | proto.WireBytes)
|
||||
if err := b.EncodeMessage(x.Ids); err != nil {
|
||||
return err
|
||||
}
|
||||
case *IdsOrKeys_Keys:
|
||||
b.EncodeVarint(2<<3 | proto.WireBytes)
|
||||
if err := b.EncodeMessage(x.Keys); err != nil {
|
||||
return err
|
||||
}
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("IdsOrKeys.Type has unexpected type %T", x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _IdsOrKeys_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
||||
m := msg.(*IdsOrKeys)
|
||||
switch tag {
|
||||
case 1: // type.ids
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
msg := new(Uint64Array)
|
||||
err := b.DecodeMessage(msg)
|
||||
m.Type = &IdsOrKeys_Ids{msg}
|
||||
return true, err
|
||||
case 2: // type.keys
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
msg := new(StringArray)
|
||||
err := b.DecodeMessage(msg)
|
||||
m.Type = &IdsOrKeys_Keys{msg}
|
||||
return true, err
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func _IdsOrKeys_OneofSizer(msg proto.Message) (n int) {
|
||||
m := msg.(*IdsOrKeys)
|
||||
// type
|
||||
switch x := m.Type.(type) {
|
||||
case *IdsOrKeys_Ids:
|
||||
s := proto.Size(x.Ids)
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(s))
|
||||
n += s
|
||||
case *IdsOrKeys_Keys:
|
||||
s := proto.Size(x.Keys)
|
||||
n += 1 // tag and wire
|
||||
n += proto.SizeVarint(uint64(s))
|
||||
n += s
|
||||
case nil:
|
||||
default:
|
||||
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*QueryPQLRequest)(nil), "pilosa.QueryPQLRequest")
|
||||
proto.RegisterType((*StatusError)(nil), "pilosa.StatusError")
|
||||
proto.RegisterType((*RowResponse)(nil), "pilosa.RowResponse")
|
||||
proto.RegisterType((*ColumnInfo)(nil), "pilosa.ColumnInfo")
|
||||
proto.RegisterType((*ColumnResponse)(nil), "pilosa.ColumnResponse")
|
||||
|
|
@ -559,44 +848,6 @@ func init() {
|
|||
proto.RegisterType((*IdsOrKeys)(nil), "pilosa.IdsOrKeys")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("pilosa.proto", fileDescriptor_ef0691a44d1e275c) }
|
||||
|
||||
var fileDescriptor_ef0691a44d1e275c = []byte{
|
||||
// 497 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0x5d, 0x6b, 0xd4, 0x40,
|
||||
0x14, 0xcd, 0x34, 0xe9, 0xee, 0xe6, 0x66, 0x59, 0xf5, 0x2a, 0x1a, 0x16, 0x91, 0x98, 0x17, 0x23,
|
||||
0x4a, 0x29, 0xab, 0x08, 0x4a, 0x7d, 0xb0, 0x82, 0x64, 0x51, 0xb0, 0x1d, 0xb1, 0xef, 0xb3, 0xcd,
|
||||
0x6c, 0x0d, 0xce, 0x66, 0xd2, 0x4c, 0xd6, 0x9a, 0x57, 0xff, 0xa2, 0x7f, 0x48, 0x66, 0xf2, 0xb1,
|
||||
0x49, 0x61, 0x7d, 0x9b, 0x39, 0xe7, 0xdc, 0xef, 0x7b, 0x61, 0x9a, 0xa7, 0x42, 0x2a, 0x76, 0x94,
|
||||
0x17, 0xb2, 0x94, 0x38, 0xaa, 0x7f, 0xe1, 0x5b, 0xb8, 0x73, 0xbe, 0xe5, 0x45, 0x75, 0x76, 0xfe,
|
||||
0x85, 0xf2, 0xeb, 0x2d, 0x57, 0x25, 0x3e, 0x80, 0xc3, 0x34, 0x4b, 0xf8, 0x6f, 0x9f, 0x04, 0x24,
|
||||
0x72, 0x69, 0xfd, 0xc1, 0xbb, 0x60, 0xe7, 0xd7, 0xc2, 0x3f, 0x30, 0x98, 0x7e, 0x86, 0x1b, 0xf0,
|
||||
0xa8, 0xbc, 0xa1, 0x5c, 0xe5, 0x32, 0x53, 0x1c, 0x5f, 0xc2, 0xf8, 0x07, 0x67, 0x09, 0x2f, 0x94,
|
||||
0x4f, 0x02, 0x3b, 0xf2, 0x16, 0x78, 0xd4, 0x44, 0xfc, 0x28, 0xc5, 0x76, 0x93, 0x2d, 0xb3, 0xb5,
|
||||
0xa4, 0xad, 0x04, 0x8f, 0x61, 0x7c, 0x69, 0x60, 0xe5, 0x1f, 0x18, 0xf5, 0xc3, 0xa1, 0xba, 0x75,
|
||||
0x4b, 0x5b, 0x59, 0x78, 0x02, 0xb0, 0x73, 0x84, 0x08, 0x4e, 0xc6, 0x36, 0xbc, 0xc9, 0xd1, 0xbc,
|
||||
0x71, 0x0e, 0x93, 0x84, 0x95, 0xac, 0xac, 0x72, 0xde, 0xe4, 0xd9, 0xfd, 0xc3, 0xbf, 0x07, 0x30,
|
||||
0x1b, 0x7a, 0xc6, 0x27, 0xe0, 0xaa, 0xb2, 0x48, 0xb3, 0xab, 0x0b, 0x26, 0x6a, 0x3f, 0xb1, 0x45,
|
||||
0x77, 0x90, 0xe6, 0xb7, 0x69, 0x56, 0xbe, 0x79, 0xad, 0x79, 0xed, 0xcf, 0xd1, 0x7c, 0x07, 0xe1,
|
||||
0x63, 0x98, 0x74, 0xb4, 0x1d, 0x90, 0xc8, 0x8e, 0x2d, 0xda, 0x21, 0x38, 0x87, 0xf1, 0x4a, 0x4a,
|
||||
0xa1, 0x49, 0x27, 0x20, 0xd1, 0x24, 0xb6, 0x68, 0x0b, 0x18, 0x4e, 0xc8, 0x95, 0xe6, 0x0e, 0x03,
|
||||
0x12, 0x4d, 0x0d, 0x57, 0x03, 0xf8, 0x1e, 0x66, 0x75, 0x88, 0x0f, 0x45, 0xc1, 0x2a, 0x2d, 0x19,
|
||||
0x05, 0x24, 0xf2, 0x16, 0xf7, 0xdb, 0xfe, 0x7c, 0xdf, 0xb1, 0xb1, 0x45, 0x6f, 0x89, 0xb5, 0x79,
|
||||
0x5d, 0x41, 0x67, 0x3e, 0x1e, 0x9a, 0x7f, 0xdb, 0xb1, 0xda, 0x7c, 0x28, 0xc6, 0x00, 0x60, 0x2d,
|
||||
0x24, 0x6b, 0xaa, 0x9a, 0x04, 0x24, 0x22, 0xb1, 0x45, 0x7b, 0xd8, 0xa9, 0x07, 0x6e, 0x3d, 0x91,
|
||||
0x0b, 0x26, 0xc2, 0x1b, 0x98, 0x2d, 0x33, 0x95, 0xf3, 0xcb, 0xf2, 0xff, 0xcb, 0xf3, 0xa2, 0x3f,
|
||||
0x6d, 0x9d, 0xce, 0xbd, 0x36, 0x9d, 0x65, 0xa2, 0xbe, 0x16, 0x9f, 0x79, 0xa5, 0xba, 0x41, 0x63,
|
||||
0x08, 0xd3, 0x75, 0x2a, 0x4a, 0x5e, 0x7c, 0x4a, 0xb9, 0x48, 0x94, 0x6f, 0x07, 0x76, 0xe4, 0xd2,
|
||||
0x01, 0x16, 0x3e, 0x05, 0xaf, 0xd7, 0x07, 0xbd, 0x0d, 0xbf, 0x98, 0xa8, 0x17, 0xcf, 0xa1, 0xe6,
|
||||
0xad, 0x25, 0xbd, 0x5a, 0x07, 0x12, 0xb7, 0x91, 0x5c, 0x81, 0xdb, 0xc5, 0xc7, 0x67, 0x60, 0xa7,
|
||||
0x89, 0x32, 0x79, 0xef, 0xed, 0xb6, 0x56, 0xe0, 0x73, 0x70, 0x7e, 0xf2, 0xaa, 0xad, 0x64, 0x4f,
|
||||
0x63, 0x8d, 0xe4, 0x74, 0x04, 0x8e, 0xde, 0xbe, 0xc5, 0x1f, 0x02, 0xa3, 0x33, 0x23, 0xc3, 0x13,
|
||||
0x98, 0xb4, 0x07, 0x87, 0x8f, 0x5a, 0xdb, 0x5b, 0x27, 0x38, 0xef, 0x9c, 0xf6, 0x0e, 0x2c, 0xb4,
|
||||
0x8e, 0x09, 0xbe, 0x83, 0x71, 0xd3, 0x70, 0xec, 0x0e, 0x66, 0x38, 0x81, 0xbd, 0xb6, 0xab, 0x91,
|
||||
0xb9, 0xfc, 0x57, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xca, 0x68, 0x70, 0x08, 0x09, 0x04, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
|
@ -691,17 +942,6 @@ type PilosaServer interface {
|
|||
Inspect(*InspectRequest, Pilosa_InspectServer) error
|
||||
}
|
||||
|
||||
// UnimplementedPilosaServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedPilosaServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedPilosaServer) QueryPQL(req *QueryPQLRequest, srv Pilosa_QueryPQLServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method QueryPQL not implemented")
|
||||
}
|
||||
func (*UnimplementedPilosaServer) Inspect(req *InspectRequest, srv Pilosa_InspectServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Inspect not implemented")
|
||||
}
|
||||
|
||||
func RegisterPilosaServer(s *grpc.Server, srv PilosaServer) {
|
||||
s.RegisterService(&_Pilosa_serviceDesc, srv)
|
||||
}
|
||||
|
|
@ -766,3 +1006,45 @@ var _Pilosa_serviceDesc = grpc.ServiceDesc{
|
|||
},
|
||||
Metadata: "pilosa.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("pilosa.proto", fileDescriptor_ef0691a44d1e275c) }
|
||||
|
||||
var fileDescriptor_ef0691a44d1e275c = []byte{
|
||||
// 568 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xdd, 0x6e, 0xd3, 0x30,
|
||||
0x14, 0x8e, 0x97, 0x2c, 0x69, 0x4e, 0xc6, 0x00, 0x83, 0x46, 0x54, 0x21, 0x14, 0x72, 0x43, 0x10,
|
||||
0x68, 0x9a, 0xca, 0x8f, 0x04, 0x8c, 0x0b, 0x36, 0x81, 0x5a, 0x01, 0x62, 0x33, 0x62, 0xf7, 0xee,
|
||||
0xe2, 0x96, 0x08, 0x37, 0xce, 0x62, 0x17, 0xe8, 0x2d, 0xcf, 0x02, 0x4f, 0xc4, 0x0b, 0x21, 0x3b,
|
||||
0x3f, 0x4d, 0x2a, 0x95, 0x3b, 0x9f, 0xef, 0xfb, 0xce, 0xf1, 0xf9, 0xb3, 0x61, 0xaf, 0xc8, 0xb8,
|
||||
0x90, 0xf4, 0xb0, 0x28, 0x85, 0x12, 0xd8, 0xad, 0xac, 0xf8, 0x05, 0x5c, 0x3f, 0x5f, 0xb2, 0x72,
|
||||
0x75, 0x76, 0xfe, 0x81, 0xb0, 0xab, 0x25, 0x93, 0x0a, 0xdf, 0x86, 0xdd, 0x2c, 0x4f, 0xd9, 0xcf,
|
||||
0x10, 0x45, 0x28, 0xf1, 0x49, 0x65, 0xe0, 0x1b, 0x60, 0x17, 0x57, 0x3c, 0xdc, 0x31, 0x98, 0x3e,
|
||||
0xc6, 0xaf, 0x20, 0xf8, 0xac, 0xa8, 0x5a, 0xca, 0xb7, 0x65, 0x29, 0x4a, 0x8c, 0xc1, 0x39, 0x15,
|
||||
0x29, 0x33, 0x5e, 0xd7, 0x88, 0x39, 0xe3, 0x10, 0xbc, 0x8f, 0x4c, 0x4a, 0x3a, 0x67, 0xb5, 0x63,
|
||||
0x63, 0xc6, 0xbf, 0x11, 0x04, 0x44, 0xfc, 0x20, 0x4c, 0x16, 0x22, 0x97, 0x0c, 0x3f, 0x06, 0xef,
|
||||
0x2b, 0xa3, 0x29, 0x2b, 0x65, 0x88, 0x22, 0x3b, 0x09, 0x46, 0xf8, 0xb0, 0xce, 0xf7, 0x54, 0xf0,
|
||||
0xe5, 0x22, 0x9f, 0xe4, 0x33, 0x41, 0x1a, 0x09, 0x3e, 0x02, 0xef, 0xd2, 0xc0, 0x32, 0xdc, 0x31,
|
||||
0xea, 0x83, 0xbe, 0xba, 0x09, 0x4b, 0x1a, 0x19, 0x7e, 0xd6, 0x4b, 0x36, 0xb4, 0x23, 0x94, 0x04,
|
||||
0xa3, 0x5b, 0x8d, 0x57, 0x87, 0x22, 0x5d, 0x5d, 0x7c, 0x0c, 0xb0, 0xbe, 0x5f, 0x97, 0x98, 0xd3,
|
||||
0x05, 0xab, 0x1b, 0x63, 0xce, 0x78, 0x08, 0x83, 0x94, 0x2a, 0xaa, 0x56, 0x45, 0x53, 0x63, 0x6b,
|
||||
0xc7, 0x7f, 0x77, 0x60, 0xbf, 0x9f, 0x10, 0xbe, 0x07, 0xbe, 0x54, 0x65, 0x96, 0xcf, 0x2f, 0x28,
|
||||
0xaf, 0xe2, 0x8c, 0x2d, 0xb2, 0x86, 0x34, 0xbf, 0xcc, 0x72, 0xf5, 0xfc, 0xa9, 0xe6, 0x75, 0x3c,
|
||||
0x47, 0xf3, 0x2d, 0x84, 0xef, 0xc2, 0xa0, 0xa5, 0x75, 0x11, 0xf6, 0xd8, 0x22, 0x2d, 0x82, 0x87,
|
||||
0xe0, 0x4d, 0x85, 0xe0, 0x9a, 0x74, 0x22, 0x94, 0x0c, 0xc6, 0x16, 0x69, 0x00, 0xc3, 0x71, 0x31,
|
||||
0xd5, 0xdc, 0x6e, 0x84, 0x92, 0x3d, 0xc3, 0x55, 0x00, 0x7e, 0x0d, 0xfb, 0xd5, 0x15, 0x6f, 0xca,
|
||||
0x92, 0xae, 0xb4, 0xc4, 0xed, 0x37, 0xe8, 0xcb, 0x9a, 0x1d, 0x5b, 0x64, 0x43, 0xac, 0xdd, 0xab,
|
||||
0x0a, 0x5a, 0x77, 0x6f, 0xb3, 0xbf, 0x2d, 0xab, 0xdd, 0xfb, 0x62, 0x1c, 0x01, 0xcc, 0xb8, 0xa0,
|
||||
0x75, 0x55, 0x83, 0x08, 0x25, 0x68, 0x6c, 0x91, 0x0e, 0x76, 0x12, 0x80, 0x5f, 0x0d, 0xf2, 0x82,
|
||||
0xf2, 0xf8, 0x0f, 0x82, 0xfd, 0x49, 0x2e, 0x0b, 0x76, 0xa9, 0xfe, 0xbf, 0xb2, 0x8f, 0xba, 0x5b,
|
||||
0xa2, 0xf3, 0xb9, 0xd9, 0xe4, 0x33, 0x49, 0xe5, 0xa7, 0xf2, 0x3d, 0x5b, 0xc9, 0xf5, 0x82, 0xc4,
|
||||
0xb0, 0x37, 0xcb, 0xb8, 0x62, 0xe5, 0xbb, 0x8c, 0xf1, 0x54, 0x86, 0x76, 0x64, 0x27, 0x3e, 0xe9,
|
||||
0x61, 0xfa, 0x1a, 0x9e, 0x2d, 0x32, 0x65, 0x9a, 0xeb, 0x90, 0xca, 0xc0, 0x07, 0xe0, 0x8a, 0xd9,
|
||||
0x4c, 0x32, 0x65, 0xfa, 0xea, 0x90, 0xda, 0x8a, 0xef, 0x43, 0xd0, 0x69, 0x9b, 0x5e, 0x9e, 0xef,
|
||||
0x94, 0x57, 0xeb, 0xed, 0x10, 0x73, 0xd6, 0x92, 0x4e, 0x6b, 0x7a, 0x12, 0xbf, 0x96, 0xcc, 0xc1,
|
||||
0x6f, 0xb3, 0xc5, 0x0f, 0xc0, 0xce, 0x52, 0x69, 0xaa, 0xdc, 0x3a, 0x1c, 0xad, 0xc0, 0x0f, 0xc1,
|
||||
0xf9, 0xc6, 0x56, 0x4d, 0xdd, 0x5b, 0xe6, 0x60, 0x24, 0x27, 0x2e, 0x38, 0x7a, 0x59, 0x47, 0xbf,
|
||||
0x10, 0xb8, 0x67, 0x46, 0x86, 0x8f, 0x61, 0xd0, 0x7c, 0x0a, 0xf8, 0x4e, 0xe3, 0xbb, 0xf1, 0x4d,
|
||||
0x0c, 0xdb, 0xa0, 0x9d, 0x67, 0x1c, 0x5b, 0x47, 0x08, 0xbf, 0x04, 0xaf, 0x1e, 0x0f, 0x6e, 0x9f,
|
||||
0x65, 0x7f, 0x5e, 0x5b, 0x7d, 0xa7, 0xae, 0xf9, 0x9d, 0x9e, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff,
|
||||
0x9e, 0xd3, 0x7d, 0xab, 0xad, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@ message QueryPQLRequest {
|
|||
string pql = 2;
|
||||
}
|
||||
|
||||
message StatusError{
|
||||
uint32 Code = 1;
|
||||
string Message = 2;
|
||||
}
|
||||
|
||||
message RowResponse{
|
||||
repeated ColumnInfo headers = 1;
|
||||
repeated ColumnResponse columns = 2;
|
||||
StatusError StatusError = 3;
|
||||
}
|
||||
|
||||
message ColumnInfo {
|
||||
|
|
@ -34,6 +39,8 @@ message InspectRequest {
|
|||
string index = 1;
|
||||
IdsOrKeys columns = 2;
|
||||
repeated string filterFields = 3;
|
||||
uint64 limit = 4;
|
||||
uint64 offset = 5;
|
||||
}
|
||||
|
||||
message Uint64Array {
|
||||
|
|
|
|||
|
|
@ -3688,41 +3688,43 @@ func union(a, b *Container) *Container {
|
|||
|
||||
func unionArrayArray(a, b *Container) *Container {
|
||||
statsHit("union/ArrayArray")
|
||||
aa, ab := a.array(), b.array()
|
||||
na, nb := len(aa), len(ab)
|
||||
output := make([]uint16, na+nb)
|
||||
n := 0
|
||||
for i, j := 0, 0; ; {
|
||||
if i >= na && j >= nb {
|
||||
break
|
||||
} else if i < na && j >= nb {
|
||||
output[n] = aa[i]
|
||||
n++
|
||||
i++
|
||||
continue
|
||||
} else if i >= na && j < nb {
|
||||
output[n] = ab[j]
|
||||
n++
|
||||
j++
|
||||
continue
|
||||
}
|
||||
|
||||
va, vb := aa[i], ab[j]
|
||||
if a.N() == 0 {
|
||||
return b
|
||||
}
|
||||
if b.N() == 0 {
|
||||
return a
|
||||
}
|
||||
s1, s2 := a.array(), b.array()
|
||||
n1, n2 := len(s1), len(s2)
|
||||
output := make([]uint16, 0, n1+n2)
|
||||
i, j := 0, 0
|
||||
for {
|
||||
va, vb := s1[i], s2[j]
|
||||
if va < vb {
|
||||
output[n] = va
|
||||
n++
|
||||
output = append(output, va)
|
||||
i++
|
||||
} else if va > vb {
|
||||
output[n] = vb
|
||||
n++
|
||||
output = append(output, vb)
|
||||
j++
|
||||
} else {
|
||||
output[n] = va
|
||||
n++
|
||||
i, j = i+1, j+1
|
||||
output = append(output, va)
|
||||
i++
|
||||
j++
|
||||
}
|
||||
// It's possible we hit the ends at the same time,
|
||||
// in which case the append will copy 0 items. This
|
||||
// is cheaper than performing a separate conditional
|
||||
// check every time...
|
||||
if j >= n2 {
|
||||
output = append(output, s1[i:]...)
|
||||
break
|
||||
}
|
||||
if i >= n1 {
|
||||
output = append(output, s2[j:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
return NewContainerArray(output[:n])
|
||||
return NewContainerArray(output)
|
||||
}
|
||||
|
||||
// unionArrayArrayInPlace does what it sounds like -- tries to combine
|
||||
|
|
@ -3730,47 +3732,56 @@ func unionArrayArray(a, b *Container) *Container {
|
|||
// of a good array size, so it could be up to twice that size, temporarily.
|
||||
func unionArrayArrayInPlace(a, b *Container) *Container {
|
||||
statsHit("union/ArrayArrayInPlace")
|
||||
aa, ab := a.array(), b.array()
|
||||
na, nb := len(aa), len(ab)
|
||||
output := make([]uint16, na+nb)
|
||||
outN := 0
|
||||
for i, j := 0, 0; ; {
|
||||
if i >= na && j >= nb {
|
||||
break
|
||||
} else if i < na && j >= nb {
|
||||
copy(output[outN:], aa[i:])
|
||||
outN += na - i
|
||||
break
|
||||
} else if i >= na && j < nb {
|
||||
copy(output[outN:], ab[j:])
|
||||
outN += nb - j
|
||||
break
|
||||
if a.N() == 0 {
|
||||
if b.N() != 0 {
|
||||
// for InPlace, we actually want to ensure that
|
||||
// we update a, as long as it's not frozen.
|
||||
a = a.Thaw()
|
||||
a.setArray(b.array())
|
||||
return a.optimize()
|
||||
}
|
||||
|
||||
va, vb := aa[i], ab[j]
|
||||
return a
|
||||
}
|
||||
if b.N() == 0 {
|
||||
return a
|
||||
}
|
||||
s1, s2 := a.array(), b.array()
|
||||
n1, n2 := len(s1), len(s2)
|
||||
output := make([]uint16, 0, n1+n2)
|
||||
i, j := 0, 0
|
||||
for {
|
||||
va, vb := s1[i], s2[j]
|
||||
if va < vb {
|
||||
output[outN] = va
|
||||
outN++
|
||||
output = append(output, va)
|
||||
i++
|
||||
} else if va > vb {
|
||||
output[outN] = vb
|
||||
outN++
|
||||
output = append(output, vb)
|
||||
j++
|
||||
} else {
|
||||
output[outN] = va
|
||||
outN++
|
||||
output = append(output, va)
|
||||
i++
|
||||
j++
|
||||
}
|
||||
// It's possible we hit the ends at the same time,
|
||||
// in which case the append will copy 0 items. This
|
||||
// is cheaper than performing a separate conditional
|
||||
// check every time...
|
||||
if j >= n2 {
|
||||
output = append(output, s1[i:]...)
|
||||
break
|
||||
}
|
||||
if i >= n1 {
|
||||
output = append(output, s2[j:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
// a union can't omit anything that was previously in a, so if
|
||||
// the output is the same length, nothing changed.
|
||||
if len(output) != int(a.N()) {
|
||||
a = a.Thaw()
|
||||
a.setArray(output[:outN])
|
||||
a = a.optimize()
|
||||
a.setArray(output)
|
||||
}
|
||||
return a
|
||||
return a.optimize()
|
||||
}
|
||||
|
||||
// unionArrayRun optimistically assumes that the result will be a run container,
|
||||
|
|
|
|||
2
row.go
2
row.go
|
|
@ -18,7 +18,7 @@ import (
|
|||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
"github.com/molecula/ext"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
|
|||
78
server.go
78
server.go
|
|
@ -17,19 +17,19 @@ package pilosa
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/ext"
|
||||
"github.com/molecula/ext"
|
||||
// extensions pulls in some extensions depending on build tags
|
||||
_ "github.com/pilosa/pilosa/v2/extensions"
|
||||
"github.com/pilosa/pilosa/v2/logger"
|
||||
"github.com/pilosa/pilosa/v2/pql"
|
||||
"github.com/pilosa/pilosa/v2/roaring"
|
||||
|
|
@ -61,7 +61,6 @@ type Server struct { // nolint: maligned
|
|||
hosts []string
|
||||
clusterDisabled bool
|
||||
serializer Serializer
|
||||
extensionPath string
|
||||
extensions []*ext.ExtensionInfo
|
||||
|
||||
// External
|
||||
|
|
@ -341,8 +340,6 @@ func NewServer(opts ...ServerOption) (*Server, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.extensionPath = filepath.Join(path, ".extensions")
|
||||
|
||||
s.holder.Path = path
|
||||
// s.holder.translateFile.Path = filepath.Join(path, ".keys")
|
||||
s.holder.Logger = s.logger
|
||||
|
|
@ -383,7 +380,7 @@ func NewServer(opts ...ServerOption) (*Server, error) {
|
|||
s.cluster.broadcaster = s
|
||||
s.cluster.maxWritesPerRequest = s.maxWritesPerRequest
|
||||
s.holder.broadcaster = s
|
||||
err = s.loadPlugins()
|
||||
err = s.loadExtensions()
|
||||
if err != nil {
|
||||
s.logger.Printf("not all plugins loaded successfully")
|
||||
}
|
||||
|
|
@ -420,67 +417,20 @@ func (s *Server) InternalClient() InternalClient {
|
|||
return s.defaultClient
|
||||
}
|
||||
|
||||
func (s *Server) loadPlugins() error {
|
||||
var anyError error
|
||||
dir, err := os.Open(s.extensionPath)
|
||||
if err != nil {
|
||||
// don't complain about it not existing, that's fine.
|
||||
if os.IsNotExist(err) {
|
||||
s.logger.Printf("extension interface v0: no extensions directory.")
|
||||
return nil
|
||||
}
|
||||
return errors.Wrap(err, "opening extension path:")
|
||||
}
|
||||
defer dir.Close()
|
||||
for files, err := dir.Readdir(64); err != io.EOF; files, err = dir.Readdir(64) {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "searching extension directory:")
|
||||
}
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
// only .so files are likely plugins.
|
||||
if !strings.HasSuffix(name, ".so") {
|
||||
continue
|
||||
}
|
||||
// only regular files are candidates for loading.
|
||||
mode := file.Mode()
|
||||
if !mode.IsRegular() {
|
||||
s.logger.Printf("extension file '%s' is not a regular file", name)
|
||||
continue
|
||||
}
|
||||
err = s.loadPlugin(name)
|
||||
if err != nil {
|
||||
s.logger.Printf("loading extension %s: %v", name, err)
|
||||
anyError = err
|
||||
}
|
||||
func (s *Server) loadExtensions() error {
|
||||
exts := ext.NewExtensions()
|
||||
var lastError error
|
||||
for _, extension := range exts {
|
||||
if err := s.loadExtension(extension); err != nil {
|
||||
lastError = err
|
||||
}
|
||||
}
|
||||
return anyError
|
||||
return lastError
|
||||
}
|
||||
|
||||
func (s *Server) loadPlugin(name string) error {
|
||||
path := filepath.Join(s.extensionPath, name)
|
||||
p, err := plugin.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pluginExtInfo, err := p.Lookup("ExtensionInfo")
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: no ExtensionInfo found", name)
|
||||
}
|
||||
extInfoFunc, ok := pluginExtInfo.(func(string) (*ext.ExtensionInfo, error))
|
||||
if !ok {
|
||||
return fmt.Errorf("%s: unexpected %T instead of ExtensionInfo object", name, pluginExtInfo)
|
||||
}
|
||||
extInfo, err := extInfoFunc("v0")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, name)
|
||||
}
|
||||
if extInfo == nil {
|
||||
return fmt.Errorf("%s: nil ExtensionInfo", name)
|
||||
}
|
||||
func (s *Server) loadExtension(extInfo *ext.ExtensionInfo) error {
|
||||
if extInfo.ExtensionAPI != "v0" {
|
||||
return fmt.Errorf("%s: unsupported extension API %s", name, extInfo.ExtensionAPI)
|
||||
return fmt.Errorf("%s: unsupported extension API %s", extInfo.Name, extInfo.ExtensionAPI)
|
||||
}
|
||||
s.extensions = append(s.extensions, extInfo)
|
||||
bitmapOps := extInfo.BitmapOps
|
||||
|
|
@ -500,7 +450,7 @@ func (s *Server) loadPlugin(name string) error {
|
|||
unknownOps++
|
||||
}
|
||||
}
|
||||
err = s.executor.registerOps(bitmapOps)
|
||||
err := s.executor.registerOps(bitmapOps)
|
||||
if err != nil {
|
||||
s.logger.Printf("warning: extension registration failed: %v", err)
|
||||
} else {
|
||||
|
|
|
|||
194
server/grpc.go
194
server/grpc.go
|
|
@ -42,10 +42,16 @@ type grpcHandler struct {
|
|||
// to the error (returning it as a status.Error). It is
|
||||
// assumed that the input err is non-nil.
|
||||
func errToStatusError(err error) error {
|
||||
// Check error string.
|
||||
switch errors.Cause(err) {
|
||||
case pilosa.ErrIndexNotFound, pilosa.ErrFieldNotFound:
|
||||
return status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
// Check error type.
|
||||
switch errors.Cause(err).(type) {
|
||||
case pilosa.NotFoundError:
|
||||
return status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
return status.Error(codes.Unknown, err.Error())
|
||||
}
|
||||
|
||||
|
|
@ -69,11 +75,36 @@ func (h grpcHandler) QueryPQL(req *pb.QueryPQLRequest, stream pb.Pilosa_QueryPQL
|
|||
return nil
|
||||
}
|
||||
|
||||
// fieldDataType returns a useful data type (string,
|
||||
// uint64, bool, etc.) based on the Pilosa field type.
|
||||
func fieldDataType(f *pilosa.Field) string {
|
||||
switch f.Type() {
|
||||
case "set", "mutex":
|
||||
if f.Options().Keys {
|
||||
return "[]string"
|
||||
} else {
|
||||
return "[]uint64"
|
||||
}
|
||||
case "int":
|
||||
return "int64"
|
||||
case "decimal":
|
||||
return "float64"
|
||||
case "bool":
|
||||
return "bool"
|
||||
case "time":
|
||||
return "int64" // TODO: this is a placeholder
|
||||
default:
|
||||
panic(fmt.Sprintf("unimplemented fieldDataType: %s", f.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect handles the inspect request and sends an InspectResponse to the stream.
|
||||
func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectServer) error {
|
||||
const defaultLimit = 100000
|
||||
|
||||
index, err := h.api.Index(context.Background(), req.Index)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting index")
|
||||
return errToStatusError(err)
|
||||
}
|
||||
|
||||
var fields []*pilosa.Field
|
||||
|
|
@ -91,20 +122,64 @@ func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSer
|
|||
}
|
||||
}
|
||||
|
||||
// If there are no matching fields, then don't return any records.
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
limit := req.Limit
|
||||
if limit == 0 {
|
||||
limit = defaultLimit
|
||||
}
|
||||
offset := req.Offset
|
||||
|
||||
if ints, ok := req.Columns.Type.(*pb.IdsOrKeys_Ids); ok {
|
||||
if !index.Options().Keys {
|
||||
ints, ok := req.Columns.Type.(*pb.IdsOrKeys_Ids)
|
||||
if !ok {
|
||||
return errors.New("invalid int columns")
|
||||
}
|
||||
ci := []*pb.ColumnInfo{
|
||||
{Name: "_id", Datatype: "uint64"},
|
||||
}
|
||||
for _, field := range fields {
|
||||
ci = append(ci, &pb.ColumnInfo{Name: field.Name(), Datatype: field.Type()}) // TODO: field.Type likely doesn't align with supported datatypes
|
||||
ci = append(ci, &pb.ColumnInfo{Name: field.Name(), Datatype: fieldDataType(field)})
|
||||
}
|
||||
|
||||
for _, col := range ints.Ids.Vals {
|
||||
// If Columns is empty, then get the _exists list (via All()),
|
||||
// from the index and loop over that instead.
|
||||
cols := ints.Ids.Vals
|
||||
if len(cols) > 0 {
|
||||
// Apply limit/offset to the provided columns.
|
||||
if int(offset) >= len(cols) {
|
||||
return nil
|
||||
}
|
||||
end := limit + offset
|
||||
if int(end) > len(cols) {
|
||||
end = uint64(len(cols))
|
||||
}
|
||||
cols = cols[offset:end]
|
||||
} else {
|
||||
// Prevent getting too many records by forcing a limit.
|
||||
pql := fmt.Sprintf("All(limit=%d, offset=%d)", limit, offset)
|
||||
query := pilosa.QueryRequest{
|
||||
Index: req.Index,
|
||||
Query: pql,
|
||||
}
|
||||
resp, err := h.api.Query(context.Background(), &query)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "querying for all: %s", pql)
|
||||
}
|
||||
|
||||
ids, ok := resp.Results[0].(*pilosa.Row)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "getting results as a row")
|
||||
}
|
||||
|
||||
limitedCols := ids.Columns()
|
||||
if len(limitedCols) == 0 {
|
||||
// If cols is still empty after the limit/offset, then
|
||||
// return with no results.
|
||||
return nil
|
||||
}
|
||||
cols = limitedCols
|
||||
}
|
||||
|
||||
for _, col := range cols {
|
||||
rowResp := &pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
|
|
@ -178,6 +253,7 @@ func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSer
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "decimal":
|
||||
value, exists, err := field.FloatValue(col)
|
||||
if err != nil {
|
||||
|
|
@ -189,6 +265,7 @@ func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSer
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "bool":
|
||||
pql := fmt.Sprintf("Rows(%s, column=%d)", field.Name(), col)
|
||||
query := pilosa.QueryRequest{
|
||||
|
|
@ -216,6 +293,7 @@ func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSer
|
|||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
}
|
||||
|
||||
case "time":
|
||||
rowResp.Columns = append(rowResp.Columns,
|
||||
&pb.ColumnResponse{ColumnVal: nil})
|
||||
|
|
@ -227,15 +305,58 @@ func (h grpcHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSer
|
|||
}
|
||||
}
|
||||
|
||||
} else if keys, ok := req.Columns.Type.(*pb.IdsOrKeys_Keys); ok {
|
||||
} else {
|
||||
keys, ok := req.Columns.Type.(*pb.IdsOrKeys_Keys)
|
||||
if !ok {
|
||||
return errToStatusError(errors.New("invalid key columns"))
|
||||
}
|
||||
ci := []*pb.ColumnInfo{
|
||||
{Name: "_id", Datatype: "string"},
|
||||
}
|
||||
for _, field := range fields {
|
||||
ci = append(ci, &pb.ColumnInfo{Name: field.Name(), Datatype: field.Type()}) // TODO: field.Type likely doesn't align with supported datatypes
|
||||
ci = append(ci, &pb.ColumnInfo{Name: field.Name(), Datatype: fieldDataType(field)})
|
||||
}
|
||||
|
||||
for _, col := range keys.Keys.Vals {
|
||||
// If Columns is empty, then get the _exists list (via All()),
|
||||
// from the index and loop over that instead.
|
||||
cols := keys.Keys.Vals
|
||||
if len(cols) > 0 {
|
||||
// Apply limit/offset to the provided columns.
|
||||
if int(offset) >= len(cols) {
|
||||
return nil
|
||||
}
|
||||
end := limit + offset
|
||||
if int(end) > len(cols) {
|
||||
end = uint64(len(cols))
|
||||
}
|
||||
cols = cols[offset:end]
|
||||
} else {
|
||||
// Prevent getting too many records by forcing a limit.
|
||||
pql := fmt.Sprintf("All(limit=%d, offset=%d)", limit, offset)
|
||||
query := pilosa.QueryRequest{
|
||||
Index: req.Index,
|
||||
Query: pql,
|
||||
}
|
||||
resp, err := h.api.Query(context.Background(), &query)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "querying for all: %s", pql)
|
||||
}
|
||||
|
||||
ids, ok := resp.Results[0].(*pilosa.Row)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "getting results as a row")
|
||||
}
|
||||
|
||||
limitedCols := ids.Keys
|
||||
if len(limitedCols) == 0 {
|
||||
// If cols is still empty after the limit/offset, then
|
||||
// return with no results.
|
||||
return nil
|
||||
}
|
||||
cols = limitedCols
|
||||
}
|
||||
|
||||
for _, col := range cols {
|
||||
rowResp := &pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
|
|
@ -433,35 +554,35 @@ func makeRows(resp pilosa.QueryResponse, logger logger.Logger) chan *pb.RowRespo
|
|||
}
|
||||
*/
|
||||
}
|
||||
case pilosa.Pair:
|
||||
if r.Key != "" {
|
||||
case pilosa.PairField:
|
||||
if r.Pair.Key != "" {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: []*pb.ColumnInfo{
|
||||
{Name: "_id", Datatype: "string"},
|
||||
{Name: r.Field, Datatype: "string"},
|
||||
{Name: "count", Datatype: "uint64"},
|
||||
},
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: r.Key}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.Count}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: r.Pair.Key}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.Pair.Count}},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: []*pb.ColumnInfo{
|
||||
{Name: "_id", Datatype: "uint64"},
|
||||
{Name: r.Field, Datatype: "uint64"},
|
||||
{Name: "count", Datatype: "uint64"},
|
||||
},
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.ID}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.Count}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.Pair.ID}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: r.Pair.Count}},
|
||||
},
|
||||
}
|
||||
}
|
||||
case []pilosa.Pair:
|
||||
case *pilosa.PairsField:
|
||||
// Determine if the ID has string keys.
|
||||
var stringKeys bool
|
||||
if len(r) > 0 {
|
||||
if r[0].Key != "" {
|
||||
if len(r.Pairs) > 0 {
|
||||
if r.Pairs[0].Key != "" {
|
||||
stringKeys = true
|
||||
}
|
||||
}
|
||||
|
|
@ -471,10 +592,10 @@ func makeRows(resp pilosa.QueryResponse, logger logger.Logger) chan *pb.RowRespo
|
|||
dtype = "string"
|
||||
}
|
||||
ci := []*pb.ColumnInfo{
|
||||
{Name: "_id", Datatype: dtype},
|
||||
{Name: r.Field, Datatype: dtype},
|
||||
{Name: "count", Datatype: "uint64"},
|
||||
}
|
||||
for _, pair := range r {
|
||||
for _, pair := range r.Pairs {
|
||||
if stringKeys {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: ci,
|
||||
|
|
@ -528,7 +649,7 @@ func makeRows(resp pilosa.QueryResponse, logger logger.Logger) chan *pb.RowRespo
|
|||
}
|
||||
case pilosa.RowIdentifiers:
|
||||
if len(r.Keys) > 0 {
|
||||
ci := []*pb.ColumnInfo{{Name: "_id", Datatype: "string"}}
|
||||
ci := []*pb.ColumnInfo{{Name: r.Field(), Datatype: "string"}}
|
||||
for _, key := range r.Keys {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: ci,
|
||||
|
|
@ -538,7 +659,7 @@ func makeRows(resp pilosa.QueryResponse, logger logger.Logger) chan *pb.RowRespo
|
|||
ci = nil
|
||||
}
|
||||
} else {
|
||||
ci := []*pb.ColumnInfo{{Name: "_id", Datatype: "uint64"}}
|
||||
ci := []*pb.ColumnInfo{{Name: r.Field(), Datatype: "uint64"}}
|
||||
for _, id := range r.Rows {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: ci,
|
||||
|
|
@ -573,6 +694,27 @@ func makeRows(resp pilosa.QueryResponse, logger logger.Logger) chan *pb.RowRespo
|
|||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: r.Val}},
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: r.Count}},
|
||||
}}
|
||||
case pilosa.SignedRow:
|
||||
// TODO: address the overflow issue with values outside the int64 range
|
||||
ci := []*pb.ColumnInfo{{Name: r.Field(), Datatype: "int64"}}
|
||||
negs := r.Neg.Columns()
|
||||
for i := len(negs) - 1; i >= 0; i-- {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: -1 * int64(negs[i])}},
|
||||
}}
|
||||
ci = nil
|
||||
}
|
||||
for _, id := range r.Pos.Columns() {
|
||||
results <- &pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: int64(id)}},
|
||||
}}
|
||||
ci = nil
|
||||
}
|
||||
|
||||
default:
|
||||
logger.Printf("unhandled %T\n", r)
|
||||
breakLoop = true
|
||||
|
|
@ -621,7 +763,7 @@ func (s *grpcServer) Serve(tlsConfig *tls.Config) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "creating listener")
|
||||
}
|
||||
s.logger.Printf("enabled grpc listening on %s", s.hostPort)
|
||||
s.logger.Printf("enabled grpc listening on %s", lis.Addr())
|
||||
|
||||
opts := make([]grpc.ServerOption, 0)
|
||||
if tlsConfig != nil {
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ func TestGRPC(t *testing.T) {
|
|||
Rows: []uint64{10, 11, 12},
|
||||
},
|
||||
[]expHeader{
|
||||
{"_id", "uint64"},
|
||||
{"", "uint64"}, // This is blank because we don't expose RowIdentifiers.field, so we have no way to set it for tests.
|
||||
},
|
||||
[][]expColumn{
|
||||
{uint64(10)},
|
||||
|
|
@ -189,7 +189,7 @@ func TestGRPC(t *testing.T) {
|
|||
Keys: []string{"ten", "eleven", "twelve"},
|
||||
},
|
||||
[]expHeader{
|
||||
{"_id", "string"},
|
||||
{"", "string"}, // This is blank because we don't expose RowIdentifiers.field, so we have no way to set it for tests.
|
||||
},
|
||||
[][]expColumn{
|
||||
{"ten"},
|
||||
|
|
|
|||
|
|
@ -224,7 +224,12 @@ func TestHandler_Endpoints(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("querying: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Results[0], []pilosa.Pair{{Count: 12, ID: 0}}) {
|
||||
if !reflect.DeepEqual(resp.Results[0], &pilosa.PairsField{
|
||||
Pairs: []pilosa.Pair{
|
||||
{Count: 12, ID: 0},
|
||||
},
|
||||
Field: "f1",
|
||||
}) {
|
||||
t.Fatalf("Unexpected result %v", resp.Results[0])
|
||||
}
|
||||
|
||||
|
|
@ -504,8 +509,8 @@ func TestHandler_Endpoints(t *testing.T) {
|
|||
var resp pilosa.QueryResponse
|
||||
if err := cmd.API.Serializer.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if a := resp.Results[0].([]pilosa.Pair); len(a) != 2 {
|
||||
t.Fatalf("unexpected pair length: %d", len(a))
|
||||
} else if a := resp.Results[0].(*pilosa.PairsField); len(a.Pairs) != 2 {
|
||||
t.Fatalf("unexpected pair length: %d", len(a.Pairs))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
)
|
||||
|
||||
// Expvar global expvar map.
|
||||
var Expvar = expvar.NewMap("index")
|
||||
var Expvar *expvar.Map
|
||||
|
||||
// StatsClient represents a client to a stats server.
|
||||
type StatsClient interface {
|
||||
|
|
@ -90,6 +90,9 @@ type expvarStatsClient struct {
|
|||
// NewExpvarStatsClient returns a new instance of ExpvarStatsClient.
|
||||
// This client points at the root of the expvar index map.
|
||||
func NewExpvarStatsClient() *expvarStatsClient {
|
||||
if Expvar == nil {
|
||||
Expvar = expvar.NewMap("index")
|
||||
}
|
||||
return &expvarStatsClient{
|
||||
m: Expvar,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue