Merge branch 'master' into percentile

This commit is contained in:
Maxton Huff 2021-03-30 08:20:45 -05:00 committed by GitHub
commit ff82447647
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
113 changed files with 13387 additions and 2878 deletions

View file

@ -63,7 +63,7 @@ testv-race: topt-race testvsub-race
# find which test is hung/deadlocked.
#
testvsub:
set -e; for i in boltdb ctl http pg pql rbf roaring server sql txkey; do \
set -e; for i in boltdb client ctl http pg pql rbf roaring server sql txkey; do \
echo; echo "___ testing subpkg $$i"; \
cd $$i; pwd; \
$(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -timeout 60m || break; \
@ -72,7 +72,7 @@ testvsub:
done
testvsub-race:
set -e; for i in boltdb ctl http pg pql rbf roaring server sql txkey; do \
set -e; for i in boltdb client ctl http pg pql rbf roaring server sql txkey; do \
echo; echo "___ testing subpkg $$i -race"; \
cd $$i; pwd; \
CGO_ENABLED=1 $(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -race -timeout 60m || break; \
@ -163,7 +163,7 @@ upgrade-lattice: lattice
# `go generate` protocol buffers
generate-protoc: require-protoc require-protoc-gen-gofast
$(GO) generate github.com/pilosa/pilosa/v2/internal
$(GO) generate github.com/pilosa/pilosa/v2/pb
# `go generate` statik assets (lattice UI)
generate-statik: build-lattice require-statik

2
api.go
View file

@ -1893,7 +1893,7 @@ func (api *API) GetTranslateEntryReader(ctx context.Context, offsets TranslateOf
defer func() {
if err != nil {
for i := range a {
a[i].Close()
a[i].Close() // nolint: errcheck
}
}
}()

View file

@ -30,6 +30,7 @@ import (
"github.com/pilosa/pilosa/v2/http"
"github.com/pilosa/pilosa/v2/server"
"github.com/pilosa/pilosa/v2/test"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// attrFun defines a mapping from columnID -> attr value
@ -46,7 +47,7 @@ func TestAPI_ImportColumnAttrs(t *testing.T) {
10000 5.156
100000 38.179
*/
c := test.MustRunCluster(t, 2,
c := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node0"),
@ -57,11 +58,17 @@ func TestAPI_ImportColumnAttrs(t *testing.T) {
pilosa.OptServerNodeID("node1"),
pilosa.OptServerClusterHasher(&offsetModHasher{}),
)},
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node2"),
pilosa.OptServerClusterHasher(&offsetModHasher{}),
)},
)
defer c.Close()
m0 := c.GetNode(0)
m1 := c.GetNode(1)
t.Run("ImportColumnAttrs", func(t *testing.T) {
ctx := context.Background()
indexName := "i"
@ -111,7 +118,7 @@ func TestAPI_ImportColumnAttrs(t *testing.T) {
IndexCreatedAt: index.CreatedAt(),
}
if err := m1.API.ImportColumnAttrs(ctx, req); err != nil {
if err := m0.API.ImportColumnAttrs(ctx, req); err != nil {
t.Fatal(err)
}
@ -125,7 +132,7 @@ func TestAPI_ImportColumnAttrs(t *testing.T) {
IndexCreatedAt: index.CreatedAt(),
}
if err := m0.API.ImportColumnAttrs(ctx, req); err != nil {
if err := m1.API.ImportColumnAttrs(ctx, req); err != nil {
t.Fatal(err)
}
@ -166,7 +173,7 @@ func TestAPI_ImportColumnAttrs(t *testing.T) {
}
func TestAPI_Import(t *testing.T) {
c := test.MustRunCluster(t, 2,
c := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node0"),
@ -181,6 +188,13 @@ func TestAPI_Import(t *testing.T) {
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
)},
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node2"),
pilosa.OptServerClusterHasher(&offsetModHasher{}),
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
)},
)
defer c.Close()
@ -243,7 +257,7 @@ func TestAPI_Import(t *testing.T) {
if err := m0.API.Import(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
pql := fmt.Sprintf("Row(%s=%d)", fieldName, rowID)
@ -287,7 +301,7 @@ func TestAPI_Import(t *testing.T) {
}
func TestAPI_ImportValue(t *testing.T) {
c := test.MustRunCluster(t, 2,
c := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node0"),
@ -300,12 +314,19 @@ func TestAPI_ImportValue(t *testing.T) {
pilosa.OptServerClusterHasher(&offsetModHasher{}),
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
)},
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("node2"),
pilosa.OptServerClusterHasher(&offsetModHasher{}),
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderFunc(nil)),
)},
)
defer c.Close()
coord := c.GetPrimary()
m0 := c.GetNode(0)
m1 := c.GetNode(1)
m2 := c.GetNode(2)
t.Run("ValColumnKey", func(t *testing.T) {
ctx := context.Background()
@ -343,7 +364,7 @@ func TestAPI_ImportValue(t *testing.T) {
if err := coord.API.ImportValue(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
pql := fmt.Sprintf("Row(%s>0)", field)
@ -371,16 +392,14 @@ func TestAPI_ImportValue(t *testing.T) {
ctx := context.Background()
index := "valdec"
field := "fdec"
_, err := m1.API.CreateIndex(ctx, index, pilosa.IndexOptions{})
_, err := m2.API.CreateIndex(ctx, index, pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = m1.API.CreateField(ctx, index, field, pilosa.OptFieldTypeDecimal(1))
_, err = m2.API.CreateField(ctx, index, field, pilosa.OptFieldTypeDecimal(1))
if err != nil {
t.Fatalf("creating field: %v", err)
}
// Generate some records.
values := []float64{}
colIDs := []uint64{}
@ -388,7 +407,6 @@ func TestAPI_ImportValue(t *testing.T) {
values = append(values, float64(i)+0.1)
colIDs = append(colIDs, uint64(i))
}
// Import data with keys to node1 and verify that it gets translated and
// forwarded to the owner of shard 0 (node0; because of offsetModHasher)
req := &pilosa.ImportValueRequest{
@ -397,15 +415,12 @@ func TestAPI_ImportValue(t *testing.T) {
ColumnIDs: colIDs,
FloatValues: values,
}
qcx := m1.API.Txf().NewQcx()
if err := m1.API.ImportValue(ctx, qcx, req); err != nil {
qcx := m0.API.Txf().NewQcx()
if err := m0.API.ImportValue(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
query := fmt.Sprintf("Row(%s>6)", field)
// Query node0.
if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: query}); err != nil {
t.Fatal(err)
@ -475,7 +490,7 @@ func TestAPI_ImportValue(t *testing.T) {
if err := m0.API.ImportValue(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
pql := fmt.Sprintf(`Row(%s=="strval-110")`, field)
@ -565,12 +580,12 @@ func TestAPI_ClearFlagForImportAndImportValues(t *testing.T) {
if err := m0api.ImportValue(ctx, qcx, ivr0); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
bitIsSet := func() bool {
query := fmt.Sprintf("Row(%v=%v)", iraField, iraRowID)
res, err := m0api.Query(context.Background(), &pilosa.QueryRequest{Index: index, Query: query})
panicOn(err)
PanicOn(err)
cols := res.Results[0].(*pilosa.Row).Columns()
for i := range cols {
if cols[i] == acctOwnerID {
@ -581,13 +596,13 @@ func TestAPI_ClearFlagForImportAndImportValues(t *testing.T) {
}
if !bitIsSet() {
panic("IRA bit should have been set")
PanicOn("IRA bit should have been set")
}
queryAcct := func(m0api *pilosa.API, acctOwnerID uint64, fieldAcct0, index string) (acctBal int64) {
query := fmt.Sprintf("FieldValue(field=%v, column=%v)", fieldAcct0, acctOwnerID)
res, err := m0api.Query(context.Background(), &pilosa.QueryRequest{Index: index, Query: query})
panicOn(err)
PanicOn(err)
if len(res.Results) == 0 {
return 0
@ -599,7 +614,7 @@ func TestAPI_ClearFlagForImportAndImportValues(t *testing.T) {
bal := queryAcct(m0api, acctOwnerID, fieldAcct0, index)
if bal != acct0bal {
panic(fmt.Sprintf("expected %v, observed %v starting acct0 balance", acct0bal, bal))
PanicOn(fmt.Sprintf("expected %v, observed %v starting acct0 balance", acct0bal, bal))
}
// clear the bit
@ -608,10 +623,10 @@ func TestAPI_ClearFlagForImportAndImportValues(t *testing.T) {
if err := m0api.Import(ctx, qcx, ir0); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
if bitIsSet() {
panic("IRA bit should have been cleared")
PanicOn("IRA bit should have been cleared")
}
// clear the BSI
@ -620,11 +635,11 @@ func TestAPI_ClearFlagForImportAndImportValues(t *testing.T) {
if err := m0api.ImportValue(ctx, qcx, ivr0); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
bal = queryAcct(m0api, acctOwnerID, fieldAcct0, index)
if bal != 0 {
panic(fmt.Sprintf("expected %v, observed %v starting acct0 balance", acct0bal, 0))
PanicOn(fmt.Sprintf("expected %v, observed %v starting acct0 balance", acct0bal, 0))
}
}

22
attr.go
View file

@ -19,7 +19,7 @@ import (
"sort"
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/v2/internal"
"github.com/pilosa/pilosa/v2/pb"
)
// Attribute data type enum.
@ -119,21 +119,21 @@ func (a attrBlocks) Diff(other []AttrBlock) []uint64 {
}
}
func encodeAttrs(m map[string]interface{}) []*internal.Attr {
func encodeAttrs(m map[string]interface{}) []*pb.Attr {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
a := make([]*internal.Attr, len(keys))
a := make([]*pb.Attr, len(keys))
for i := range keys {
a[i] = encodeAttr(keys[i], m[keys[i]])
}
return a
}
func decodeAttrs(pb []*internal.Attr) map[string]interface{} {
func decodeAttrs(pb []*pb.Attr) map[string]interface{} {
m := make(map[string]interface{}, len(pb))
for i := range pb {
key, value := decodeAttr(pb[i])
@ -142,9 +142,9 @@ func decodeAttrs(pb []*internal.Attr) map[string]interface{} {
return m
}
// encodeAttr converts a key/value pair into an Attr internal representation.
func encodeAttr(key string, value interface{}) *internal.Attr {
pb := &internal.Attr{Key: key}
// encodeAttr converts a key/value pair into an Attr pb.representation.
func encodeAttr(key string, value interface{}) *pb.Attr {
pb := &pb.Attr{Key: key}
switch value := value.(type) {
case string:
pb.Type = attrTypeString
@ -165,8 +165,8 @@ func encodeAttr(key string, value interface{}) *internal.Attr {
return pb
}
// decodeAttr converts from an Attr internal representation to a key/value pair.
func decodeAttr(attr *internal.Attr) (key string, value interface{}) {
// decodeAttr converts from an Attr pb.representation to a key/value pair.
func decodeAttr(attr *pb.Attr) (key string, value interface{}) {
switch attr.Type {
case attrTypeString:
return attr.Key, attr.StringValue
@ -192,12 +192,12 @@ func cloneAttrs(m map[string]interface{}) map[string]interface{} {
// EncodeAttrs encodes an attribute map into a byte slice.
func EncodeAttrs(attr map[string]interface{}) ([]byte, error) {
return proto.Marshal(&internal.AttrMap{Attrs: encodeAttrs(attr)})
return proto.Marshal(&pb.AttrMap{Attrs: encodeAttrs(attr)})
}
// DecodeAttrs decodes a byte slice into an attribute map.
func DecodeAttrs(v []byte) (map[string]interface{}, error) {
var pb internal.AttrMap
var pb pb.AttrMap
if err := proto.Unmarshal(v, &pb); err != nil {
return nil, err
}

View file

@ -23,7 +23,7 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
//txkey "github.com/pilosa/pilosa/v2/txkey"
. "github.com/pilosa/pilosa/v2/vprint"
)
// blueGreenTx runs two Tx together and notices differences in their output.
@ -129,7 +129,7 @@ func (b *blueGreenRegistry) Close() {
b.mu.Lock()
defer b.mu.Unlock()
if len(b.m) > 0 {
panic(fmt.Sprintf("still have open/unchecked blueGreenTx: '%#v'", b.m))
PanicOn(fmt.Sprintf("still have open/unchecked blueGreenTx: '%#v'", b.m))
//AlwaysPrintf("still have unchecked blueGreenTx: '%#v'", b.m)
}
}
@ -191,7 +191,7 @@ func (c *blueGreenTx) Readonly() bool {
a := c.a.Readonly()
b := c.b.Readonly()
if a != b {
panic(fmt.Sprintf("Readonly difference, a=%v, but b =%v", a, b))
PanicOn(fmt.Sprintf("Readonly difference, a=%v, but b =%v", a, b))
}
return b
}
@ -240,41 +240,41 @@ func (c *blueGreenTx) compareTxState(index, field, view string, shard uint64) {
if aFound != bFound {
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: A(%v) ContainerIterator had aFound=%v, but B(%v) had bFound=%v; at '%v'", here, c.as, aFound, c.bs, bFound, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: A(%v) ContainerIterator had aFound=%v, but B(%v) had bFound=%v; at '%v'", here, c.as, aFound, c.bs, bFound, Stack()))
}
if aErr != nil || bErr != nil {
if aErr != nil && bErr != nil {
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: A(%v) reported err '%v'; B(%v) reported err '%v' at %v", here, c.as, aErr, c.bs, bErr, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: A(%v) reported err '%v'; B(%v) reported err '%v' at %v", here, c.as, aErr, c.bs, bErr, Stack()))
}
if aErr != nil {
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: A(%v) reported err %v at %v; but B(%v) did not", here, c.as, aErr, c.bs, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: A(%v) reported err %v at %v; but B(%v) did not", here, c.as, aErr, c.bs, Stack()))
}
if bErr != nil {
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: B(%v) reported err %v at %v; but A(%v) did not", here, c.bs, bErr, c.as, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: B(%v) reported err %v at %v; but A(%v) did not", here, c.bs, bErr, c.as, Stack()))
}
}
for aIter.Next() {
aKey, aValue := aIter.Value()
if !bIter.Next() {
AlwaysPrintf("compareTxState[%v]: A(%v) found key %v, B(%v) didn't, dump to follow, stack=\n %v\n\n and here is dump:", here, c.as, aKey, c.bs, stack())
AlwaysPrintf("compareTxState[%v]: A(%v) found key %v, B(%v) didn't, dump to follow, Stack=\n %v\n\n and here is dump:", here, c.as, aKey, c.bs, Stack())
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: A(%v) found key %v, B(%v) didn't, at %v", here, c.as, aKey, c.bs, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: A(%v) found key %v, B(%v) didn't, at %v", here, c.as, aKey, c.bs, Stack()))
}
bKey, bValue := bIter.Value()
if bKey != aKey {
AlwaysPrintf("problem in caller %v", Caller(2))
c.Dump(c.short, shard)
panic(fmt.Sprintf("compareTxState[%v]: A(%v) found key %v, B(%v) found %v, at %v", here, c.as, aKey, c.bs, bKey, stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: A(%v) found key %v, B(%v) found %v, at %v", here, c.as, aKey, c.bs, bKey, Stack()))
}
if err := aValue.BitwiseCompare(bValue); err != nil {
c.Dump(c.short, shard)
//vv("compareTxState[%v]: key %v differs: %v; A=%v; B=%v; at stack=%v", here, aKey, err, c.as, c.bs, stack())
panic(fmt.Sprintf("compareTxState[%v]: key %v differs: %v; A=%v; B=%v; at stack=%v", here, aKey, err, c.as, c.bs, stack()))
//vv("compareTxState[%v]: key %v differs: %v; A=%v; B=%v; at Stack=%v", here, aKey, err, c.as, c.bs, Stack())
PanicOn(fmt.Sprintf("compareTxState[%v]: key %v differs: %v; A=%v; B=%v; at Stack=%v", here, aKey, err, c.as, c.bs, Stack()))
}
//vv("successfully matched aKey(%v)='%v' and bKey(%v)='%v'", c.as, aKey, c.bs, bKey)
}
@ -283,7 +283,7 @@ func (c *blueGreenTx) compareTxState(index, field, view string, shard uint64) {
AlwaysPrintf("bIter has more than it should. problem in caller %v. _sn_ %v", Caller(2), c.Sn())
c.Dump(c.short, shard)
bKey, _ := bIter.Value()
panic(fmt.Sprintf("compareTxState[%v]: B(%v) found key %v, A(%v) didn't, (a.sn=%v) (b.sn=%v) at %v", here, c.bs, bKey, c.as, c.a.Sn(), c.b.Sn(), stack()))
PanicOn(fmt.Sprintf("compareTxState[%v]: B(%v) found key %v, A(%v) didn't, (a.sn=%v) (b.sn=%v) at %v", here, c.bs, bKey, c.as, c.a.Sn(), c.b.Sn(), Stack()))
}
//vv("done without problem. compareTxState here = '%v', _sn_ %v gid=%v", here, c.Sn(), curGID())
}
@ -341,7 +341,7 @@ func (c *blueGreenTx) Rollback() {
c.mu.Lock()
defer c.mu.Unlock()
if c.rollbackOrCommitDone {
return // avoid using discarded tx for Dump, which will panic.
return // avoid using discarded tx for Dump, which will PanicOn.
}
c.rollbackOrCommitDone = true
@ -350,8 +350,8 @@ func (c *blueGreenTx) Rollback() {
}
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Rollback() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Rollback() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
//vv("blueGreenTx.Rollback() about to call (%v) a.Rollback()", c.as)
@ -379,8 +379,8 @@ func (c *blueGreenTx) Commit() error {
}
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Commit() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Commit() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
errA := c.a.Commit()
@ -396,8 +396,8 @@ func (c *blueGreenTx) RoaringBitmap(index, field, view string, shard uint64) (*r
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmap() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmap() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.RoaringBitmap(index, field, view, shard)
@ -409,7 +409,7 @@ func (c *blueGreenTx) RoaringBitmap(index, field, view string, shard uint64) (*r
slcA := a.Slice()
slcB := b.Slice()
if !reflect.DeepEqual(slcA, slcB) {
panic("blueGreenTx.RoaringBitmap() returning different roaring.Bitmaps!")
PanicOn("blueGreenTx.RoaringBitmap() returning different roaring.Bitmaps!")
}
}
return b, errB
@ -419,8 +419,8 @@ func (c *blueGreenTx) Container(index, field, view string, shard uint64, key uin
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Container() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Container() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.Container(index, field, view, shard, key)
@ -429,7 +429,7 @@ func (c *blueGreenTx) Container(index, field, view string, shard uint64, key uin
if !c.o.blueGreenOff {
compareErrors(errA, errB)
err = a.BitwiseCompare(b)
panicOn(err)
PanicOn(err)
}
return b, errB
}
@ -438,8 +438,8 @@ func (c *blueGreenTx) PutContainer(index, field, view string, shard uint64, key
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see PutContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see PutContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
errA := c.a.PutContainer(index, field, view, shard, key, rc)
@ -463,14 +463,14 @@ func (c *blueGreenTx) ImportRoaringBits(index, field, view string, shard uint64,
// ================== end save comments.
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ImportRoaringBits() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ImportRoaringBits() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
// remember where the iterator started, so we can replay it a second time.
rit2 := rit.Clone()
panicOn(err)
PanicOn(err)
changedA, rowSetA, errA := c.a.ImportRoaringBits(index, field, view, shard, rit, clear, log, rowSize, data)
changedB, rowSetB, errB := c.b.ImportRoaringBits(index, field, view, shard, rit2, clear, log, rowSize, data)
@ -482,18 +482,18 @@ func (c *blueGreenTx) ImportRoaringBits(index, field, view string, shard uint64,
// case where we know that RoaringTx.ImportRoaringBits changed and rowSet will
// be inaccurate.
if changedA != changedB {
panic(fmt.Sprintf("changedA = %v, but changedB = %v", changedA, changedB))
PanicOn(fmt.Sprintf("changedA = %v, but changedB = %v", changedA, changedB))
}
if len(rowSetA) != len(rowSetB) {
panic(fmt.Sprintf("rowSetA = %#v, but rowSetB = %#v", rowSetA, rowSetB))
PanicOn(fmt.Sprintf("rowSetA = %#v, but rowSetB = %#v", rowSetA, rowSetB))
}
for k, va := range rowSetA {
vb, ok := rowSetB[k]
if !ok {
panic(fmt.Sprintf("diff on key '%v': present in rowSetA, but not in rowSet B. rowSetA = %#v, but rowSetB = %#v", k, rowSetA, rowSetB))
PanicOn(fmt.Sprintf("diff on key '%v': present in rowSetA, but not in rowSet B. rowSetA = %#v, but rowSetB = %#v", k, rowSetA, rowSetB))
}
if va != vb {
panic(fmt.Sprintf("diff on key '%v', rowSetA has value '%v', but rowSetB has value '%v'", k, va, vb))
PanicOn(fmt.Sprintf("diff on key '%v', rowSetA has value '%v', but rowSetB has value '%v'", k, va, vb))
}
}
}
@ -507,8 +507,8 @@ func (c *blueGreenTx) RemoveContainer(index, field, view string, shard uint64, k
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RemoveContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RemoveContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
errA := c.a.RemoveContainer(index, field, view, shard, key)
@ -531,9 +531,9 @@ var _ = (&blueGreenTx{}).isIn // happy linter
func (c *blueGreenTx) isIn(index, field, view string, shard uint64, ckey uint64) (r []bool) {
r = make([]bool, 2)
inA, errA := c.a.Contains(index, field, view, shard, ckey)
panicOn(errA)
PanicOn(errA)
inB, errB := c.b.Contains(index, field, view, shard, ckey)
panicOn(errB)
PanicOn(errB)
r[0] = inA
r[1] = inB
return
@ -544,8 +544,8 @@ func (c *blueGreenTx) Add(index, field, view string, shard uint64, batched bool,
//vv("blueGreenTx) Add(index=%v, field=%v, view=%v, shard=%v", index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Add() panic '%v' for index='%v', field='%v', view='%v', shard='%v' at '%v'", r, index, field, view, shard, stack())
panic(r)
AlwaysPrintf("see Add() PanicOn '%v' for index='%v', field='%v', view='%v', shard='%v' at '%v'", r, index, field, view, shard, Stack())
PanicOn(r)
}
}()
@ -562,7 +562,7 @@ func (c *blueGreenTx) Add(index, field, view string, shard uint64, batched bool,
if !c.o.blueGreenOff {
if ach != bch {
panic(fmt.Sprintf("Add() difference, ach=%v, but bch=%v; errA='%v'; errB='%v'", ach, bch, errA, errB))
PanicOn(fmt.Sprintf("Add() difference, ach=%v, but bch=%v; errA='%v'; errB='%v'", ach, bch, errA, errB))
}
compareErrors(errA, errB)
}
@ -575,14 +575,14 @@ func compareErrors(errA, errB error) {
case errA == nil && errB == nil:
// OK
case errA == nil:
panic(fmt.Sprintf("errA is nil, but errB = %#v", errB))
PanicOn(fmt.Sprintf("errA is nil, but errB = %#v", errB))
case errB == nil:
panic(fmt.Sprintf("errB is nil, but errA = %#v", errA))
PanicOn(fmt.Sprintf("errB is nil, but errA = %#v", errA))
default:
ae := errA.Error()
be := errB.Error()
if ae != be {
panic(fmt.Sprintf("errA is '%v', but errB is '%v'", ae, be))
PanicOn(fmt.Sprintf("errA is '%v', but errB is '%v'", ae, be))
}
}
}
@ -591,8 +591,8 @@ func (c *blueGreenTx) Remove(index, field, view string, shard uint64, a ...uint6
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Remove() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Remove() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
ach, errA := c.a.Remove(index, field, view, shard, a...)
@ -609,8 +609,8 @@ func (c *blueGreenTx) Contains(index, field, view string, shard uint64, key uint
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Contains() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Contains() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
ax, errA := c.a.Contains(index, field, view, shard, key)
@ -627,8 +627,8 @@ func (c *blueGreenTx) ContainerIterator(index, field, view string, shard uint64,
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ContainerIterator() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ContainerIterator() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
@ -690,7 +690,7 @@ func (bgi *blueGreenIterator) Next() bool {
na := bgi.ait.Next()
nb := bgi.bit.Next()
if na != nb {
panic(fmt.Sprintf("na=%v(%v) != nb(%v)=%v", na, bgi.as, bgi.bs, nb))
PanicOn(fmt.Sprintf("na=%v(%v) != nb(%v)=%v", na, bgi.as, bgi.bs, nb))
}
return nb
}
@ -701,10 +701,10 @@ func (bgi *blueGreenIterator) Value() (uint64, *roaring.Container) {
if !bgi.tx.o.blueGreenOff {
if ka != kb {
panic(fmt.Sprintf("ka=%v != kb=%v", ka, kb))
PanicOn(fmt.Sprintf("ka=%v != kb=%v", ka, kb))
}
err := ca.BitwiseCompare(cb)
panicOn(err)
PanicOn(err)
}
return kb, cb
}
@ -718,8 +718,8 @@ func (bgi *blueGreenIterator) Close() {
func (c *blueGreenTx) ForEach(index, field, view string, shard uint64, fn func(i uint64) error) error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEach() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEach() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEach(index, field, view, shard, fn)
@ -733,8 +733,8 @@ func (c *blueGreenTx) ForEachRange(index, field, view string, shard uint64, star
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEachRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEachRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
@ -748,8 +748,8 @@ func (c *blueGreenTx) Count(index, field, view string, shard uint64) (uint64, er
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Count() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Count() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.Count(index, field, view, shard)
@ -767,8 +767,8 @@ func (c *blueGreenTx) Max(index, field, view string, shard uint64) (uint64, erro
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Max() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Max() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.Max(index, field, view, shard)
@ -786,8 +786,8 @@ func (c *blueGreenTx) Min(index, field, view string, shard uint64) (uint64, bool
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Min() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Min() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
amin, afound, errA := c.a.Min(index, field, view, shard)
@ -805,8 +805,8 @@ func (c *blueGreenTx) UnionInPlace(index, field, view string, shard uint64, othe
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see UnionInPlace() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see UnionInPlace() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
errA := c.a.UnionInPlace(index, field, view, shard, others...)
@ -822,8 +822,8 @@ func (c *blueGreenTx) CountRange(index, field, view string, shard uint64, start,
defer func() {
if r := recover(); r != nil {
c.Dump(c.short, shard)
AlwaysPrintf("see CountRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see CountRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.CountRange(index, field, view, shard, start, end)
@ -831,7 +831,7 @@ func (c *blueGreenTx) CountRange(index, field, view string, shard uint64, start,
if !c.o.blueGreenOff {
if a != b {
panic(fmt.Sprintf("a(%v) = %v, but b(%v) = %v", c.as, a, c.bs, b))
PanicOn(fmt.Sprintf("a(%v) = %v, but b(%v) = %v", c.as, a, c.bs, b))
}
compareErrors(errA, errB)
@ -843,8 +843,8 @@ func (c *blueGreenTx) OffsetRange(index, field, view string, shard, offset, star
c.checker.see(index, field, view, shard)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see OffsetRange() on _sn_ %v, panic '%v' at '%v'", c.Sn(), r, stack())
panic(r)
AlwaysPrintf("see OffsetRange() on _sn_ %v, PanicOn '%v' at '%v'", c.Sn(), r, Stack())
PanicOn(r)
}
}()
a, errA := c.a.OffsetRange(index, field, view, shard, offset, start, end)
@ -855,7 +855,7 @@ func (c *blueGreenTx) OffsetRange(index, field, view string, shard, offset, star
err = roaringBitmapDiff(a, b)
if err != nil {
c.Dump(false, shard)
panicOn(fmt.Errorf("on _sn_ %v OffsetRange(index='%v', field='%v', view='%v', shard='%v', offset: %v start: %v, end: %v) err: %v", c.Sn(), index, field, view, int(shard), offset, start, end, err))
PanicOn(fmt.Errorf("on _sn_ %v OffsetRange(index='%v', field='%v', view='%v', shard='%v', offset: %v start: %v, end: %v) err: %v", c.Sn(), index, field, view, int(shard), offset, start, end, err))
}
compareErrors(errA, errB)
}
@ -868,8 +868,8 @@ func (c *blueGreenTx) RoaringBitmapReader(index, field, view string, shard uint6
defer func() {
if r := recover(); r != nil {
c.Dump(c.short, shard)
AlwaysPrintf("see RoaringBitmapReader() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmapReader() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
@ -891,7 +891,7 @@ func (c *blueGreenTx) RoaringBitmapReader(index, field, view string, shard uint6
}
if sizeMustMatch {
if szA != szB {
panic(fmt.Sprintf("szA(%v) = %v, but szB(%v) = %v; fragmentPathForRoaring='%v'", c.as, szA, c.bs, szB, fragmentPathForRoaring))
PanicOn(fmt.Sprintf("szA(%v) = %v, but szB(%v) = %v; fragmentPathForRoaring='%v'", c.as, szA, c.bs, szB, fragmentPathForRoaring))
}
return &MultiReaderB{a: rcA, b: rcB}, szB, errB
} else {
@ -955,14 +955,14 @@ func (m *MultiReaderB) Read(p []byte) (nB int, errB error) {
if !m.allowSizeVariation {
if errA == io.ErrUnexpectedEOF {
panic(fmt.Sprintf("MultiReaderB got ErrUnexpectedEOF: read %v bytes from B, but could only read %v bytes for A", nB, nA))
PanicOn(fmt.Sprintf("MultiReaderB got ErrUnexpectedEOF: read %v bytes from B, but could only read %v bytes for A", nB, nA))
}
if nA != nB {
panic(fmt.Sprintf("MultiReaderB read %v bytes from B, but could only read %v bytes for A", nB, nA))
PanicOn(fmt.Sprintf("MultiReaderB read %v bytes from B, but could only read %v bytes for A", nB, nA))
}
cmp := bytes.Compare(p[:nB], p2[:nB])
if cmp != 0 {
panic(fmt.Sprintf("MultiReaderB reads p and p2 (cmp= %v) differed.", cmp))
PanicOn(fmt.Sprintf("MultiReaderB reads p and p2 (cmp= %v) differed.", cmp))
}
}
return

View file

@ -24,6 +24,8 @@ import (
"testing"
cryrand "crypto/rand"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
var _ = context.Background
@ -42,7 +44,7 @@ func TestMultiReaderB(t *testing.T) {
nr := 0
for nr < n {
na, err := src.Read(a)
panicOn(err)
PanicOn(err)
nr += na
}
if nr != n {
@ -62,7 +64,7 @@ func TestMultiReaderB(t *testing.T) {
// should not trigger the internal panic of MultiReadB
ncp, err := io.Copy(ioutil.Discard, m)
panicOn(err)
PanicOn(err)
if ncp != int64(n) {
panic("short copy")
}

33
bolt.go
View file

@ -31,6 +31,7 @@ import (
"github.com/pilosa/pilosa/v2/hash"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/storage"
. "github.com/pilosa/pilosa/v2/vprint"
// On Bolt only, we still use the long txkey, because
// this allows Max() to work readily.
@ -132,7 +133,7 @@ func (r *boltRegistrar) OpenDBWrapper(path string, doAllocZero bool, cfg *storag
dir := filepath.Dir(path)
if !DirExists(path) {
panicOn(os.MkdirAll(dir, 0755))
PanicOn(os.MkdirAll(dir, 0755))
}
db, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 5 * time.Second, InitialMmapSize: TxInitialMmapSize})
@ -522,7 +523,7 @@ func (tx *BoltTx) Commit() error {
defer tx.mu.Unlock()
err := tx.tx.Commit()
panicOn(err)
PanicOn(err)
tx.o.dbs.Cleanup(tx)
return err
@ -657,15 +658,15 @@ func (tx *BoltTx) addOrRemove(index, field, view string, shard uint64, batched,
// not first time through, write what we got.
if remove && (rc == nil || rc.N() == 0) {
err = tx.RemoveContainer(index, field, view, shard, lastHi)
panicOn(err)
PanicOn(err)
} else {
err = tx.PutContainer(index, field, view, shard, lastHi, rc)
panicOn(err)
PanicOn(err)
}
}
// get the next container
rc, err = tx.Container(index, field, view, shard, hi)
panicOn(err)
PanicOn(err)
} // else same container, keep adding bits to rct.
chng := false
// rc can be nil before, and nil after, in both Remove/Add below.
@ -684,17 +685,17 @@ func (tx *BoltTx) addOrRemove(index, field, view string, shard uint64, batched,
if remove {
if rc == nil || rc.N() == 0 {
err = tx.RemoveContainer(index, field, view, shard, hi)
panicOn(err)
PanicOn(err)
} else {
err = tx.PutContainer(index, field, view, shard, hi, rc)
panicOn(err)
PanicOn(err)
}
} else {
if rc == nil || rc.N() == 0 {
panic("there should be no way to have an empty bitmap AFTER an Add() operation")
}
err = tx.PutContainer(index, field, view, shard, hi, rc)
panicOn(err)
PanicOn(err)
}
return
}
@ -955,7 +956,7 @@ type boltFinder struct {
// FindIterator lets boltFinder implement the roaring.FindIterator interface.
func (bf *boltFinder) FindIterator(seek uint64) (roaring.ContainerIterator, bool) {
a, found, err := bf.tx.ContainerIterator(bf.index, bf.field, bf.view, bf.shard, seek)
panicOn(err)
PanicOn(err)
bf.needClose = append(bf.needClose, a)
return a, found
}
@ -1015,7 +1016,7 @@ func (tx *BoltTx) ForEachRange(index, field, view string, shard uint64, start, e
func (tx *BoltTx) Count(index, field, view string, shard uint64) (uint64, error) {
a, found, err := tx.ContainerIterator(index, field, view, shard, 0)
panicOn(err)
PanicOn(err)
defer a.Close()
if !found {
return 0, nil
@ -1101,7 +1102,7 @@ func (tx *BoltTx) Min(index, field, view string, shard uint64) (uint64, bool, er
func (tx *BoltTx) UnionInPlace(index, field, view string, shard uint64, others ...*roaring.Bitmap) error {
rbm, err := tx.RoaringBitmap(index, field, view, shard)
panicOn(err)
PanicOn(err)
rbm.UnionInPlace(others...)
// iterate over the containers that changed within rbm, and write them back to disk.
@ -1115,7 +1116,7 @@ func (tx *BoltTx) UnionInPlace(index, field, view string, shard uint64, others .
// TODO: only write the changed ones back, as optimization?
// Compare to ImportRoaringBits.
err := tx.PutContainer(index, field, view, shard, containerKey, rc)
panicOn(err)
PanicOn(err)
}
return nil
}
@ -1133,7 +1134,7 @@ func (tx *BoltTx) CountRange(index, field, view string, shard uint64, start, end
citer, found, err := tx.ContainerIterator(index, field, view, shard, skey)
_ = found
panicOn(err)
PanicOn(err)
defer citer.Close()
@ -1265,7 +1266,7 @@ func (tx *BoltTx) ImportRoaringBits(index, field, view string, shard uint64, itr
// INVAR: nsynth > 0
oldC, err = tx.Container(index, field, view, shard, itrKey)
panicOn(err)
PanicOn(err)
if err != nil {
return
}
@ -1346,7 +1347,7 @@ func (tx *BoltTx) ImportRoaringBits(index, field, view string, shard uint64, itr
err = tx.PutContainer(index, field, view, shard, itrKey, newC)
if err != nil {
panicOn(err)
PanicOn(err)
return
}
continue
@ -1567,7 +1568,7 @@ func (w *BoltWrapper) DeletePrefix(prefix []byte) error {
w.muDb.Unlock()
err := tx.Commit()
panicOn(err)
PanicOn(err)
return nil
}

View file

@ -21,6 +21,7 @@ import (
"testing"
"github.com/pilosa/pilosa/v2/roaring"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// helpers, each runs their own new txn, and commits if a change/delete
@ -31,7 +32,7 @@ func BoltMustHaveBitvalue(dbwrap *BoltWrapper, index, field, view string, shard
tx, _ := dbwrap.NewTx(!writable, index, Txo{})
defer tx.Rollback()
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG bitvalue '%v' was NOT SET!!!", bitvalue))
}
@ -44,7 +45,7 @@ func BoltMustNotHaveBitvalue(dbwrap *BoltWrapper, index, field, view string, sha
tx, _ := dbwrap.NewTx(!writable, index, Txo{})
defer tx.Rollback()
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if exists {
panic(fmt.Sprintf("ARG bitvalue '%v' WAS SET but should not have been.!!!", bitvalue))
}
@ -59,36 +60,36 @@ func BoltMustSetBitvalue(dbwrap *BoltWrapper, index, field, view string, shard u
if changed != 1 {
panic("should have 1 bit changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG putme was NOT SET!!!")
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
}
func BoltMustDeleteBitvalueContainer(dbwrap *BoltWrapper, index, field, view string, shard uint64, putme uint64) {
tx, _ := dbwrap.NewTx(writable, index, Txo{})
hi := highbits(putme)
panicOn(tx.RemoveContainer(index, field, view, shard, hi))
panicOn(tx.Commit())
PanicOn(tx.RemoveContainer(index, field, view, shard, hi))
PanicOn(tx.Commit())
}
func BoltMustDeleteBitvalue(dbwrap *BoltWrapper, index, field, view string, shard uint64, putme uint64) {
tx, _ := dbwrap.NewTx(writable, index, Txo{})
_, err := tx.Remove(index, field, view, shard, putme)
panicOn(err)
panicOn(tx.Commit())
PanicOn(err)
PanicOn(tx.Commit())
}
func mustOpenEmptyBoltWrapper(path string) (w *BoltWrapper, cleaner func()) {
var err error
fn := path
panicOn(os.RemoveAll(fn))
PanicOn(os.RemoveAll(fn))
ww, err := globalBoltReg.OpenDBWrapper(fn, DetectMemAccessPastTx, nil)
panicOn(err)
PanicOn(err)
w = ww.(*BoltWrapper)
// verify it is empty
@ -99,7 +100,7 @@ func mustOpenEmptyBoltWrapper(path string) (w *BoltWrapper, cleaner func()) {
return w, func() {
w.Close()
panicOn(os.RemoveAll(fn))
PanicOn(os.RemoveAll(fn))
}
}
@ -126,28 +127,28 @@ func TestBolt_DeleteFragment(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
}
}
for _, view := range views {
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
}
}
err := tx.Commit()
panicOn(err)
PanicOn(err)
// end of setup
victim := "v1"
survivor := "v2"
err = dbwrap.DeleteFragment(index, field, victim, shard, nil)
panicOn(err)
PanicOn(err)
tx, _ = dbwrap.NewTx(!writable, index, Txo{})
defer tx.Rollback()
@ -155,7 +156,7 @@ func TestBolt_DeleteFragment(t *testing.T) {
for _, view := range views {
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if view == survivor {
if !exists {
panic(fmt.Sprintf("ARG survivor died : bit %v", v))
@ -209,7 +210,7 @@ func TestBolt_Max_on_many_containers(t *testing.T) {
for _, shard := range shards {
max, err := tx.Max(index, field, view, uint64(shard))
panicOn(err)
PanicOn(err)
if max != uint64(shard) {
panic(fmt.Sprintf("expected max (%v) to be == shard = %v", max, shard))
}
@ -217,12 +218,12 @@ func TestBolt_Max_on_many_containers(t *testing.T) {
// check for not found
max, err := tx.Max(index, field, view, uint64(200))
panicOn(err)
PanicOn(err)
if max != 0 {
panic("expected not found to give 0 max back with nil err")
}
max, err = tx.Max(index, field, view, uint64(400))
panicOn(err)
PanicOn(err)
if max != 0 {
panic("expected not found to give 0 max back with nil err")
}
@ -242,16 +243,16 @@ func TestBolt_SetBitmap(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
err = tx.Commit()
panicOn(err)
PanicOn(err)
//
// commited, so should be visible outside the txn
@ -259,13 +260,13 @@ func TestBolt_SetBitmap(t *testing.T) {
tx2, _ := dbwrap.NewTx(!writable, index, Txo{})
exists, err = tx2.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!! on tx2")
}
n, err := tx2.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if n != 1 {
panic(fmt.Sprintf("should have Count 1; instead n = %v", n))
}
@ -284,28 +285,28 @@ func TestBolt_OffsetRange(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
bitvalue2 := uint64(1<<20 + 1)
changed, err = tx.Add(index, field, view, shard, doBatched, bitvalue2)
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
exists, err = tx.Contains(index, field, view, shard, bitvalue2)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue2 was NOT SET!!!")
}
err = tx.Commit()
panicOn(err)
PanicOn(err)
offset := uint64(0 << 20)
start := uint64(0 << 16)
@ -313,7 +314,7 @@ func TestBolt_OffsetRange(t *testing.T) {
tx2, _ := dbwrap.NewTx(!writable, index, Txo{})
rbm2, err := tx2.OffsetRange(index, field, view, shard, offset, start, endx)
panicOn(err)
PanicOn(err)
tx2.Rollback()
// should see our 1M value
@ -327,7 +328,7 @@ func TestBolt_OffsetRange(t *testing.T) {
offset = uint64(2 << 20)
tx3, _ := dbwrap.NewTx(!writable, index, Txo{})
rbm3, err := tx3.OffsetRange(index, field, view, shard, offset, start, endx)
panicOn(err)
PanicOn(err)
tx3.Rollback()
//expect to see 3M == 3145728
@ -357,7 +358,7 @@ func TestBolt_Count_on_many_containers(t *testing.T) {
defer tx.Rollback()
n, err := tx.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if int(n) != len(putmeValues) {
panic(fmt.Sprintf("expected Count of %v but got n=%v", len(putmeValues), n))
}
@ -374,7 +375,7 @@ func TestBolt_Count_dense_containers(t *testing.T) {
expected := 0
for i := uint64(0); i < (1<<16)+2; i += 2 {
changed, err := tx.Add(index, field, view, shard, doBatched, i)
panicOn(err)
PanicOn(err)
if changed <= 0 {
panic("wat? should have changed")
}
@ -383,7 +384,7 @@ func TestBolt_Count_dense_containers(t *testing.T) {
defer tx.Rollback()
n, err := tx.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if int(n) != expected {
panic(fmt.Sprintf("expected Count of %v but got n=%v", expected, n))
}
@ -399,12 +400,12 @@ func TestBolt_ContainerIterator_on_empty(t *testing.T) {
defer tx.Rollback()
bitvalue := uint64(0)
citer, found, err := tx.ContainerIterator(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
defer citer.Close()
if found {
panic("should not have found anything")
}
panicOn(err)
PanicOn(err)
}
func TestBolt_ContainerIterator_on_one_bit(t *testing.T) {
@ -423,10 +424,10 @@ func TestBolt_ContainerIterator_on_one_bit(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
@ -437,7 +438,7 @@ func TestBolt_ContainerIterator_on_one_bit(t *testing.T) {
if !found {
panic("ContainerIterator did not find the 42 bit")
}
panicOn(err)
PanicOn(err)
defer citer.Close()
loopCount := 0
@ -481,10 +482,10 @@ func TestBolt_ContainerIterator_on_one_bit_fail_to_find(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG putme was NOT SET!!!")
}
@ -517,7 +518,7 @@ func TestBolt_ContainerIterator_on_one_bit_fail_to_find(t *testing.T) {
break
}
}
panicOn(err)
PanicOn(err)
}
func TestBolt_ContainerIterator_empty_iteration_loop(t *testing.T) {
@ -536,10 +537,10 @@ func TestBolt_ContainerIterator_empty_iteration_loop(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG putme was NOT SET!!!")
}
@ -547,7 +548,7 @@ func TestBolt_ContainerIterator_empty_iteration_loop(t *testing.T) {
// same Tx, continues in use.
citer, found, err := tx.ContainerIterator(index, field, view, shard, highbits(searchme))
panicOn(err)
PanicOn(err)
if found {
panic("ContainerIterator found the searchme, when it should not have")
}
@ -585,10 +586,10 @@ func TestBolt_ForEach_on_one_bit(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
exists, err := tx.Contains(index, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
@ -602,7 +603,7 @@ func TestBolt_ForEach_on_one_bit(t *testing.T) {
count += 1
return nil
})
panicOn(err)
PanicOn(err)
if count != 1 {
panic(fmt.Sprintf("Expected single iteration got %v ", count))
}
@ -637,7 +638,7 @@ func TestBolt_RemoveContainer_one_bit_test(t *testing.T) {
// delete, but rollback instead of commit
tx, _ := dbwrap.NewTx(writable, index, Txo{})
hi := highbits(putme)
panicOn(tx.RemoveContainer(index, field, view, shard, hi))
PanicOn(tx.RemoveContainer(index, field, view, shard, hi))
tx.Rollback()
// verify that the rollback undid the deletion.
@ -648,15 +649,15 @@ func TestBolt_RemoveContainer_one_bit_test(t *testing.T) {
hi = highbits(putme)
exists, err := tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG putme '%v' was NOT SET!!!", putme))
}
panicOn(tx.RemoveContainer(index, field, view, shard, hi))
PanicOn(tx.RemoveContainer(index, field, view, shard, hi))
exists, err = tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if exists {
panic(fmt.Sprintf("ARG putme '%v' was SET even after RemoveContiner in this txn.", putme))
}
@ -700,7 +701,7 @@ func TestBolt_Remove_one_bit_test(t *testing.T) {
hi, lo := highbits(putme), lowbits(putme)
_, _ = hi, lo
_, err := tx.Remove(index, field, view, shard, hi)
panicOn(err)
PanicOn(err)
tx.Rollback()
// verify that the rollback undid the deletion.
@ -710,7 +711,7 @@ func TestBolt_Remove_one_bit_test(t *testing.T) {
tx, _ = dbwrap.NewTx(writable, index, Txo{})
exists, err := tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG putme '%v' was NOT SET!!!", putme))
}
@ -718,7 +719,7 @@ func TestBolt_Remove_one_bit_test(t *testing.T) {
mustRemove(tx.Remove(index, field, view, shard, putme))
exists, err = tx.Contains(index, field, view, shard, putme)
panicOn(err)
PanicOn(err)
if exists {
panic(fmt.Sprintf("ARG putme '%v' was SET even after Remove in this txn.", putme))
}
@ -742,7 +743,7 @@ func TestBolt_Min_on_many_containers(t *testing.T) {
tx, _ := dbwrap.NewTx(!writable, index, Txo{})
min, containersExist, err := tx.Min(index, field, view, shard)
_ = min
panicOn(err)
PanicOn(err)
if containersExist {
panic("no containers should exist")
}
@ -760,7 +761,7 @@ func TestBolt_Min_on_many_containers(t *testing.T) {
defer tx.Rollback()
min, containersExist, err = tx.Min(index, field, view, shard)
panicOn(err)
PanicOn(err)
if !containersExist {
panic("containers should exist")
}
@ -779,7 +780,7 @@ func TestBolt_CountRange_on_many_containers(t *testing.T) {
// verify no containers flag works
tx, _ := dbwrap.NewTx(!writable, index, Txo{})
n, err := tx.CountRange(index, field, view, shard, 0, math.MaxUint64)
panicOn(err)
PanicOn(err)
if n != 0 {
panic("no containers should exist")
}
@ -797,7 +798,7 @@ func TestBolt_CountRange_on_many_containers(t *testing.T) {
defer tx.Rollback()
n, err = tx.CountRange(index, field, view, shard, 0, math.MaxUint64)
panicOn(err)
PanicOn(err)
if n == 0 {
panic("containers should exist")
}
@ -826,7 +827,7 @@ func TestBolt_CountRange_middle_container(t *testing.T) {
// pick out just the middle container with the 1 bit set on it.
n, err := tx.CountRange(index, field, view, shard, 4, (2<<16)+1)
panicOn(err)
PanicOn(err)
if n != 1 {
panic("middle 1 bit container should exist")
}
@ -851,7 +852,7 @@ func TestBolt_CountRange_many_middle_container(t *testing.T) {
// get them all
n, err := tx.CountRange(index, field, view, shard, 0, (4<<16)+1)
panicOn(err)
PanicOn(err)
if n != 3 {
panic("count should have been all 3 bits")
}
@ -879,7 +880,7 @@ func TestBolt_UnionInPlace(t *testing.T) {
tx2, _ := dbwrap.NewTx(!writable, index, Txo{})
n, err := tx2.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if n != 2 {
panic("should have 2 bits set")
}
@ -895,11 +896,11 @@ func TestBolt_UnionInPlace(t *testing.T) {
tx, _ := dbwrap.NewTx(writable, index, Txo{})
defer tx.Rollback()
err = tx.UnionInPlace(index, field, view, shard, others, others2, others3)
panicOn(err)
PanicOn(err)
// end game, check we got the union.
rbm, err := tx.RoaringBitmap(index, field, view, shard)
panicOn(err)
PanicOn(err)
n = rbm.Count()
if n != 7 {
panic("should have a total 3 + 3 +1 = 7 bits set on the containers")
@ -921,7 +922,7 @@ func TestBolt_RoaringBitmap(t *testing.T) {
defer tx.Rollback()
rbm, err := tx.RoaringBitmap(index, field, view, shard)
panicOn(err)
PanicOn(err)
slc := rbm.Slice()
if slc[0] != uint64(expected) {
@ -947,7 +948,7 @@ func TestBolt_ImportRoaringBits(t *testing.T) {
bits := []uint64{0, 2, 5, 1<<16 + 1, 2 << 16}
data := getTestBitmapAsRawRoaring(bits...)
itr, err := roaring.NewRoaringIterator(data)
panicOn(err)
PanicOn(err)
clear := false
logme := false
@ -956,11 +957,11 @@ func TestBolt_ImportRoaringBits(t *testing.T) {
if changed != len(bits) {
panic(fmt.Sprintf("should have changed %v bits: changed='%v', rowSet='%#v', err='%v'", len(bits), changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG bitvalue was NOT SET!!! '%v'", v))
}
@ -973,11 +974,11 @@ func TestBolt_ImportRoaringBits(t *testing.T) {
if changed != 0 {
panic(fmt.Sprintf("should have not changed any bits on the second import, but we see changed='%v', rowSet='%#v', err='%v'", changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG bitvalue was NOT SET!!! '%v'", v))
}
@ -990,17 +991,17 @@ func TestBolt_ImportRoaringBits(t *testing.T) {
// clear 1 bit at a time
data := getTestBitmapAsRawRoaring(v)
itr, err := roaring.NewRoaringIterator(data)
panicOn(err)
PanicOn(err)
changed, rowSet, err := tx.ImportRoaringBits(index, field, view, shard, itr, clear, logme, rowSize, nil)
_ = rowSet
if changed != 1 {
panic(fmt.Sprintf("should have changed 1 bit: '%v', rowSet='%#v', err='%v'", changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
}
n, err := tx.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if n != 0 {
panic(fmt.Sprintf("n = %v not zero so the clearbits didn't happen!", n))
}
@ -1027,12 +1028,12 @@ func TestBolt_ImportRoaringBits_set_nonoverlapping_bits(t *testing.T) {
bits := []uint64{0, 2, 1 << 16, 1<<16 + 2}
data := getTestBitmapAsRawRoaring(bits...)
itr, err := roaring.NewRoaringIterator(data)
panicOn(err)
PanicOn(err)
bits2 := []uint64{1, 2, 3, 1<<16 + 1, 1<<16 + 2, 1<<16 + 3} //, 5, 1<<16 + 1, 2 << 16}
data2 := getTestBitmapAsRawRoaring(bits2...)
itr2, err := roaring.NewRoaringIterator(data2)
panicOn(err)
PanicOn(err)
clear := false
logme := false
@ -1042,11 +1043,11 @@ func TestBolt_ImportRoaringBits_set_nonoverlapping_bits(t *testing.T) {
if changed != len(bits) {
panic(fmt.Sprintf("should have changed %v bits: changed='%v', rowSet='%#v', err='%v'", len(bits), changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG bitvalue was NOT SET!!! '%v'", v))
}
@ -1059,7 +1060,7 @@ func TestBolt_ImportRoaringBits_set_nonoverlapping_bits(t *testing.T) {
if changed != 4 {
panic(fmt.Sprintf("should have changed 2 bits: the 1 and the 3, but we see changed='%v', rowSet='%#v', err='%v'", changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
}
func TestBolt_ImportRoaringBits_clear_nonoverlapping_bits(t *testing.T) {
@ -1077,12 +1078,12 @@ func TestBolt_ImportRoaringBits_clear_nonoverlapping_bits(t *testing.T) {
bits := []uint64{0, 2, 1 << 16, 1<<16 + 2} //, 5, 1<<16 + 1, 2 << 16}
data := getTestBitmapAsRawRoaring(bits...)
itr, err := roaring.NewRoaringIterator(data)
panicOn(err)
PanicOn(err)
bits2 := []uint64{1, 2, 3, 1<<16 + 1, 1<<16 + 2, 1<<16 + 3} //, 5, 1<<16 + 1, 2 << 16}
data2 := getTestBitmapAsRawRoaring(bits2...)
itr2, err := roaring.NewRoaringIterator(data2)
panicOn(err)
PanicOn(err)
clear := false
logme := false
@ -1092,11 +1093,11 @@ func TestBolt_ImportRoaringBits_clear_nonoverlapping_bits(t *testing.T) {
if changed != len(bits) {
panic(fmt.Sprintf("should have changed %v bits: changed='%v', rowSet='%#v', err='%v'", len(bits), changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("ARG bitvalue was NOT SET!!! '%v'", v))
}
@ -1110,10 +1111,10 @@ func TestBolt_ImportRoaringBits_clear_nonoverlapping_bits(t *testing.T) {
if changed != 2 {
panic(fmt.Sprintf("should have changed 1 bit: the 2, but we see changed='%v', rowSet='%#v', err='%v'", changed, rowSet, err))
}
panicOn(err)
PanicOn(err)
n, err := tx.Count(index, field, view, shard)
panicOn(err)
PanicOn(err)
if n != 2 { // just the 0 and the 1<<16 bits should be left set.
panic(fmt.Sprintf("n = %v not 2 so the clearbits didn't happen!", n))
}
@ -1135,7 +1136,7 @@ func TestBolt_DeleteIndex(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
}
index2 := "i2" // should not be deleted, even though it shares a prefix with 'i'
@ -1143,38 +1144,38 @@ func TestBolt_DeleteIndex(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
for _, v := range bits {
exists, err := tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!!")
}
}
exists, err := tx.Contains(index2, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic("ARG bitvalue was NOT SET!!! on index2")
}
err = tx.Commit()
panicOn(err)
PanicOn(err)
// end of setup
err = dbwrap.DeleteIndex(index)
panicOn(err)
PanicOn(err)
tx, _ = dbwrap.NewTx(!writable, index2, Txo{})
defer tx.Rollback()
exists, err = tx.Contains(index2, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("after delete of '%v', another index '%v' was gone too?!?", index, index2))
}
for _, v := range bits {
exists, err = tx.Contains(index, field, view, shard, v)
panicOn(err)
PanicOn(err)
if exists {
allkeys := stringifiedBoltKeysTx(tx.(*BoltTx), false)
panic(fmt.Sprintf("after delete of index '%v', bit v=%v was not gone?!?; allkeys='%v'", index, v, allkeys))
@ -1199,9 +1200,9 @@ func TestBolt_DeleteIndex_over100k(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
if v%100000 == 0 {
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx, _ = dbwrap.NewTx(writable, index, Txo{})
}
}
@ -1211,25 +1212,25 @@ func TestBolt_DeleteIndex_over100k(t *testing.T) {
if changed <= 0 {
panic("should have changed")
}
panicOn(err)
PanicOn(err)
err = tx.Commit()
panicOn(err)
PanicOn(err)
// end of setup
err = dbwrap.DeleteIndex(index)
panicOn(err)
PanicOn(err)
tx, _ = dbwrap.NewTx(!writable, index2, Txo{})
defer tx.Rollback()
exists, err := tx.Contains(index2, field, view, shard, bitvalue)
panicOn(err)
PanicOn(err)
if !exists {
panic(fmt.Sprintf("after delete of '%v', another index '%v' was gone too?!?", index, index2))
}
for v := uint64(0); v < limit; v++ {
exists, err = tx.Contains(index, field, view, shard, v<<16)
panicOn(err)
PanicOn(err)
if exists {
allkeys := stringifiedBoltKeysTx(tx.(*BoltTx), false)
panic(fmt.Sprintf("after delete of index '%v', bit v=%v was not gone?!?; allkeys='%v'", index, v, allkeys))

View file

@ -20,13 +20,13 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
//txkey "github.com/pilosa/pilosa/v2/txkey"
. "github.com/pilosa/pilosa/v2/vprint"
)
// catcher is useful to report error locations with a
// stack dump before the complexity
// Stack dump before the complexity
// of the executor_test swallows up
// the location of a panic.
// the location of a PanicOn.
type catcherTx struct {
b Tx
}
@ -53,8 +53,8 @@ func (c *catcherTx) NewTxIterator(index, field, view string, shard uint64) *roar
func (c *catcherTx) ImportRoaringBits(index, field, view string, shard uint64, rit roaring.RoaringIterator, clear bool, log bool, rowSize uint64, data []byte) (changed int, rowSet map[uint64]int, err error) {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ImportRoaringBits() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ImportRoaringBits() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ImportRoaringBits(index, field, view, shard, rit, clear, log, rowSize, data)
@ -67,8 +67,8 @@ func (c *catcherTx) Dump(short bool, shard uint64) {
func (c *catcherTx) Readonly() bool {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Readonly() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Readonly() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Readonly()
@ -81,8 +81,8 @@ func (tx *catcherTx) Pointer() string {
func (c *catcherTx) Rollback() {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Rollback() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Rollback() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
c.b.Rollback()
@ -92,8 +92,8 @@ func (c *catcherTx) Commit() error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Commit() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Commit() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Commit()
@ -103,8 +103,8 @@ func (c *catcherTx) RoaringBitmap(index, field, view string, shard uint64) (*roa
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmap() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmap() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmap(index, field, view, shard)
@ -114,8 +114,8 @@ func (c *catcherTx) Container(index, field, view string, shard uint64, key uint6
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Container() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Container() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Container(index, field, view, shard, key)
@ -125,8 +125,8 @@ func (c *catcherTx) PutContainer(index, field, view string, shard uint64, key ui
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see PutContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see PutContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.PutContainer(index, field, view, shard, key, rc)
@ -136,8 +136,8 @@ func (c *catcherTx) RemoveContainer(index, field, view string, shard uint64, key
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RemoveContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RemoveContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RemoveContainer(index, field, view, shard, key)
@ -155,8 +155,8 @@ func (c *catcherTx) Add(index, field, view string, shard uint64, batched bool, a
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Add() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Add() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Add(index, field, view, shard, batched, a...)
@ -166,8 +166,8 @@ func (c *catcherTx) Remove(index, field, view string, shard uint64, a ...uint64)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Remove() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Remove() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Remove(index, field, view, shard, a...)
@ -177,8 +177,8 @@ func (c *catcherTx) Contains(index, field, view string, shard uint64, key uint64
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Contains() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Contains() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Contains(index, field, view, shard, key)
@ -188,8 +188,8 @@ func (c *catcherTx) ContainerIterator(index, field, view string, shard uint64, f
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ContainerIterator() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ContainerIterator() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ContainerIterator(index, field, view, shard, firstRoaringContainerKey)
@ -199,8 +199,8 @@ func (c *catcherTx) ForEach(index, field, view string, shard uint64, fn func(i u
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEach() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEach() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEach(index, field, view, shard, fn)
@ -210,8 +210,8 @@ func (c *catcherTx) ForEachRange(index, field, view string, shard uint64, start,
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEachRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEachRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEachRange(index, field, view, shard, start, end, fn)
@ -221,8 +221,8 @@ func (c *catcherTx) Count(index, field, view string, shard uint64) (uint64, erro
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Count() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Count() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Count(index, field, view, shard)
@ -232,8 +232,8 @@ func (c *catcherTx) Max(index, field, view string, shard uint64) (uint64, error)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Max() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Max() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Max(index, field, view, shard)
@ -243,8 +243,8 @@ func (c *catcherTx) Min(index, field, view string, shard uint64) (uint64, bool,
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Min() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Min() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Min(index, field, view, shard)
@ -254,8 +254,8 @@ func (c *catcherTx) UnionInPlace(index, field, view string, shard uint64, others
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see UnionInPlace() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see UnionInPlace() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.UnionInPlace(index, field, view, shard, others...)
@ -265,8 +265,8 @@ func (c *catcherTx) CountRange(index, field, view string, shard uint64, start, e
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see CountRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see CountRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.CountRange(index, field, view, shard, start, end)
@ -276,8 +276,8 @@ func (c *catcherTx) OffsetRange(index, field, view string, shard, offset, start,
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see OffsetRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see OffsetRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.OffsetRange(index, field, view, shard, offset, start, end)
@ -286,8 +286,8 @@ func (c *catcherTx) OffsetRange(index, field, view string, shard, offset, start,
func (c *catcherTx) RoaringBitmapReader(index, field, view string, shard uint64, fragmentPathForRoaring string) (r io.ReadCloser, sz int64, err error) {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmapReader() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmapReader() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmapReader(index, field, view, shard, fragmentPathForRoaring)

View file

@ -47,7 +47,8 @@ type FieldValue struct {
// something hasn't been architected correctly.
// While I understand that putting the entire Client behind an interface might require this many methods,
// I don't want to let it go unquestioned.
// Another note from Travis: I think we eventually want to unify `InternalClient` with the `go-pilosa` client.
// Another note from Travis: I think we eventually want to unify `InternalClient` with
// the `github.com/pilosa/pilosa/v2/client` client.
// Doing that may obviate the need to refactor this.
type InternalClient interface {
InternalQueryClient

85
client/README.md Normal file
View file

@ -0,0 +1,85 @@
# Go Client for Pilosa
Go client for Pilosa high performance distributed index.
## Usage
If you have the pilosa repo in your `GOPATH`,
you can import the library in your code using:
```go
import "github.com/pilosa/pilosa/v2/client"
```
### Quick overview
Assuming [Pilosa](https://github.com/pilosa/pilosa) server is running at `localhost:10101` (the default):
```go
package main
import (
"fmt"
"github.com/pilosa/pilosa/v2/client"
)
func main() {
// Create the default client
cli := client.DefaultClient()
// Retrieve the schema
schema, err := cli.Schema()
// Create an Index object
myindex := schema.Index("myindex")
// Create a Field object
myfield := myindex.Field("myfield")
// make sure the index and the field exists on the server
err := cli.SyncSchema(schema)
// Send a Set query. If err is non-nil, response will be nil.
response, err := cli.Query(myfield.Set(5, 42))
// Send a Row query. If err is non-nil, response will be nil.
response, err = cli.Query(myfield.Row(5))
// Get the result
result := response.Result()
// Act on the result
if result != nil {
columns := result.Row().Columns
fmt.Println("Got columns: ", columns)
}
// You can batch queries to improve throughput
response, err = cli.Query(myindex.BatchQuery(
myfield.Row(5),
myfield.Row(10)))
if err != nil {
fmt.Println(err)
}
for _, result := range response.Results() {
// Act on the result
fmt.Println(result.Row().Columns)
}
}
```
## Documentation
### Data Model and Queries
See: [Data Model and Queries](docs/data-model-queries.md)
### Executing Queries
See: [Server Interaction](docs/server-interaction.md)
### Other Documentation
* [Tracing](docs/tracing.md)

1404
client/batch.go Normal file

File diff suppressed because it is too large Load diff

1311
client/batch_test.go Normal file

File diff suppressed because it is too large Load diff

1797
client/client.go Normal file

File diff suppressed because it is too large Load diff

816
client/client_it_test.go Normal file
View file

@ -0,0 +1,816 @@
// Copyright 2017 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 client
import (
"fmt"
"io/ioutil"
"testing"
"time"
"github.com/pilosa/pilosa/v2/disco"
pnet "github.com/pilosa/pilosa/v2/net"
"github.com/pilosa/pilosa/v2/shardwidth"
"github.com/pilosa/pilosa/v2/test"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"
)
var (
testIndex *Index
testIndexWithKeys *Index
testIndexWithKeysNoTrack *Index
testIndexAtomicRecord *Index
testField *Field
testFieldTimeQuantum *Field
testFieldInt0 *Field
testFieldInt1 *Field
)
func setup(t *testing.T, r *require.Assertions, cli *Client) {
t.Helper()
testSchema := NewSchema()
testIndex = testSchema.Index("test-index")
testIndexWithKeys = testSchema.Index("test-index-keys", OptIndexKeys(true))
testIndexWithKeysNoTrack = testSchema.Index("test-index-keys-notrack",
OptIndexKeys(true),
OptIndexTrackExistence(false),
)
testField = testIndex.Field("test-field")
testFieldTimeQuantum = testIndex.Field("test-field-timequantum", OptFieldTypeTime(TimeQuantumYear))
testIndexAtomicRecord = testSchema.Index("test-index-atomic-record")
testFieldInt0 = testIndexAtomicRecord.Field("test-field-int0", OptFieldTypeInt(-1000, 1000))
testFieldInt1 = testIndexAtomicRecord.Field("test-field-int1", OptFieldTypeInt(-1000, 1000))
r.NoErrorf(cli.SyncSchema(testSchema), "SyncSchema")
}
func tearDown(t *testing.T, r *require.Assertions, cli *Client) {
t.Helper()
for _, i := range []*Index{testIndex, testIndexWithKeys, testIndexWithKeysNoTrack, testIndexAtomicRecord} {
r.NoErrorf(cli.DeleteIndex(i), "DeleteIndex(%s)", i.name)
}
}
func TestClientAgainstCluster(t *testing.T) {
require := require.New(t)
for size, replicaN := 3, 1; replicaN <= 2; replicaN++ {
testName := fmt.Sprintf("%d.%d", size, replicaN)
t.Run(testName, func(t *testing.T) {
// Start size.replicaN cluster
c := test.MustNewCluster(t, size)
for _, n := range c.Nodes {
n.Config.Cluster.ReplicaN = replicaN
}
err := c.Start()
require.NoError(err, "Start cluster "+testName)
urls := make([]string, len(c.Nodes))
for i, n := range c.Nodes {
urls[i] = n.URL()
}
defer c.Close()
// Create a new client for the cluster
cli, err := newClientFromAddresses(urls, &ClientOptions{})
require.NoErrorf(err, "newClientFromAddresses(%v): %v", urls, err)
defer cli.Close()
t.Run("GetStatus", func(t *testing.T) {
status, err := cli.Status()
require.NoErrorf(err, "GET /status")
require.Equalf(disco.ClusterStateNormal, disco.ClusterState(status.State), "GET /status")
})
t.Run("QueryRow", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
resp, err := cli.Query(testField.Row(1))
require.NoErrorf(err, "Query Row")
require.NotNil(resp, "Response should not be nil")
})
t.Run("QueryWithShards", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
shardWidth := uint64(1 << shardwidth.Exponent)
_, err := cli.Query(testField.Set(1, 1))
require.NoErrorf(err, "Set(1, %d)", 1)
_, err = cli.Query(testField.Set(1, shardWidth))
require.NoErrorf(err, "Set(1, %d)", shardWidth)
_, err = cli.Query(testField.Set(1, shardWidth*3))
require.NoErrorf(err, "Set(1, %d)", shardWidth*3)
resp, err := cli.Query(testField.Row(1), OptQueryShards(0, 3))
require.NoErrorf(err, "Row(1) OptQueryShards(0, 3)")
cols := resp.Result().Row().Columns
require.Equalf([]uint64{1, shardWidth * 3}, cols, "Unexpected results: %#v", cols)
})
t.Run("QueryWithColumns", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
targetAttrs := map[string]interface{}{
"name": "some string",
"age": int64(95),
"registered": true,
"height": 1.83,
}
_, err := cli.Query(testField.Set(1, 100))
require.NoErrorf(err, "Set(1, 100)")
resp, err := cli.Query(testIndex.SetColumnAttrs(100, targetAttrs))
require.NoErrorf(err, "SetColumnAttrs(100, %v)", targetAttrs)
require.Equalf(ColumnItem{}, resp.Column(), "No columns should be returned if it wasn't explicitly requested")
resp, err = cli.Query(testField.Row(1), &QueryOptions{ColumnAttrs: true})
require.NoErrorf(err, "Row(1) QueryOptions{ColumnAttrs: true}")
require.Equalf(1, len(resp.ColumnAttrs()), "ColumnAttrs count should be == 1")
cols := resp.Columns()
require.Equalf(1, len(cols), "Column count")
require.Equalf(uint64(100), cols[0].ID, "Column ID")
require.Equalf(targetAttrs, cols[0].Attributes, "Column attrs.")
require.Equalf(cols[0], resp.Column(), "Column() should be equivalent to first column in the response")
})
t.Run("SetRowAttrs", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
targetAttrs := map[string]interface{}{
"name": "some string",
"age": int64(95),
"registered": true,
"height": 1.83,
}
_, err := cli.Query(testField.Set(1, 100))
require.NoErrorf(err, "Set(1, 100)")
_, err = cli.Query(testField.SetRowAttrs(1, targetAttrs))
require.NoErrorf(err, "SetRowAttrs(1, %v)", targetAttrs)
resp, err := cli.Query(testField.Row(1), &QueryOptions{ColumnAttrs: true})
require.NoErrorf(err, "Row(1) QueryOptions{ColumnAttrs: true}")
require.Equalf(targetAttrs, resp.Result().Row().Attributes, "Row attributes should be set")
})
t.Run("OrmCount", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldCount := testIndex.Field("test-field-count")
err := cli.EnsureField(testFieldCount)
require.NoError(err)
qry := testIndex.BatchQuery(
testFieldCount.Set(10, 20),
testFieldCount.Set(10, 21),
testFieldCount.Set(15, 25),
)
_, err = cli.Query(qry)
require.NoErrorf(err, "BatchQuery")
resp, err := cli.Query(testIndex.Count(testFieldCount.Row(10)))
require.NoErrorf(err, "Count")
require.Equalf(int64(2), resp.Result().Count(), "Count")
})
t.Run("DecimalField", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldDec := testIndex.Field("test-field-dec", OptFieldTypeDecimal(3))
err := cli.EnsureField(testFieldDec)
require.NoError(err)
sch, err := cli.Schema()
require.NoErrorf(err, "Schema")
idx := sch.indexes[testIndex.name]
opts := idx.Field(testFieldDec.name).Options()
require.Equalf(int64(3), opts.scale, "%s scale", testFieldDec.name)
})
t.Run("IntersectReturns", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldSegments := testIndex.Field("test-field-segments")
err := cli.EnsureField(testFieldSegments)
require.NoError(err)
qry1 := testIndex.BatchQuery(
testFieldSegments.Set(2, 10),
testFieldSegments.Set(2, 15),
testFieldSegments.Set(3, 10),
testFieldSegments.Set(3, 20),
)
_, err = cli.Query(qry1)
require.NoErrorf(err, "BatchQuery")
qry2 := testIndex.Intersect(testFieldSegments.Row(2), testFieldSegments.Row(3))
resp, err := cli.Query(qry2)
require.NoErrorf(err, "Intersect")
require.Equalf(1, len(resp.Results()), "Intersect number of results")
require.Equalf([]uint64{10}, resp.Result().Row().Columns, "Intersect columns results")
})
t.Run("TopNReturns", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldTopN := testIndex.Field("test-field-topn")
err := cli.EnsureField(testFieldTopN)
require.NoError(err)
qry := testIndex.BatchQuery(
testFieldTopN.Set(10, 5),
testFieldTopN.Set(10, 10),
testFieldTopN.Set(10, 15),
testFieldTopN.Set(20, 5),
testFieldTopN.Set(30, 5),
)
_, err = cli.Query(qry)
require.NoErrorf(err, "BatchQuery")
// XXX: The following is required to make this test pass. See: https://github.com/pilosa/pilosa/issues/625
_, _, err = cli.HTTPRequest("POST", "/recalculate-caches", nil, nil)
require.NoErrorf(err, "POST /recalculate-caches")
resp, err := cli.Query(testFieldTopN.TopN(2))
require.NoErrorf(err, "TopN(2)")
items := resp.Result().CountItems()
require.Equalf(2, len(items), "TopN result CountItems")
item := items[0]
require.Equalf(uint64(10), item.ID, "TopN result item[0].ID")
require.Equalf(uint64(3), item.Count, "TopN result item[0].Count")
_, err = cli.Query(testFieldTopN.SetRowAttrs(10, map[string]interface{}{"foo": "bar"}))
require.NoErrorf(err, "SetRowAttrs(10)")
resp, err = cli.Query(testFieldTopN.FilterAttrTopN(5, nil, "foo", "bar"))
require.NoErrorf(err, `FilterAttrTopN(5, nil, "foo", "bar")`)
items = resp.Result().CountItems()
require.Equalf(1, len(items), "FilterAttrTopN result CountItems")
item = items[0]
require.Equalf(uint64(10), item.ID, "FilterAttrTopN result item[0].ID")
require.Equalf(uint64(3), item.Count, "FilterAttrTopN result item[0].Count")
})
t.Run("MinMaxRow", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldMinMax := testIndex.Field("test-field-minmax")
err := cli.EnsureField(testFieldMinMax)
require.NoError(err)
qry := testIndex.BatchQuery(
testFieldMinMax.Set(10, 5),
testFieldMinMax.Set(10, 10),
testFieldMinMax.Set(10, 15),
testFieldMinMax.Set(20, 5),
testFieldMinMax.Set(30, 5),
)
_, err = cli.Query(qry)
require.NoErrorf(err, "Setting bits")
resp, err := cli.Query(testFieldMinMax.MinRow())
require.NoErrorf(err, "MinRow")
min := resp.Result().CountItem().ID
require.Equalf(uint64(10), min, "Min")
resp, err = cli.Query(testFieldMinMax.MaxRow())
require.NoErrorf(err, "MaxRow")
max := resp.Result().CountItem().ID
require.Equalf(uint64(30), max, "Max")
})
t.Run("SetMutexField", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldMutex := testIndex.Field("test-field-mutex", OptFieldTypeMutex(CacheTypeDefault, 0))
err := cli.EnsureField(testFieldMutex)
require.NoError(err)
// can set mutex
_, err = cli.Query(testFieldMutex.Set(1, 100))
require.NoErrorf(err, "Set(1, 100)")
resp, err := cli.Query(testFieldMutex.Row(1))
require.NoErrorf(err, "Row(1)")
target := []uint64{100}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
// setting another row removes the previous
_, err = cli.Query(testFieldMutex.Set(42, 100))
require.NoErrorf(err, "Set(42, 100)")
resp, err = cli.Query(testIndex.BatchQuery(
testFieldMutex.Row(1),
testFieldMutex.Row(42),
))
require.NoErrorf(err, "BatchQuery")
target1 := []uint64(nil)
target42 := []uint64{100}
require.Equalf(target1, resp.Results()[0].Row().Columns, "Row Results[0] Columns")
require.Equalf(target42, resp.Results()[1].Row().Columns, "Row Results[1] Columns")
})
t.Run("SetBoolField", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldBool := testIndex.Field("test-field-bool", OptFieldTypeBool())
err := cli.EnsureField(testFieldBool)
require.NoError(err)
// can set bool
_, err = cli.Query(testFieldBool.Set(true, 100))
require.NoErrorf(err, "Set(true, 100)")
resp, err := cli.Query(testFieldBool.Row(true))
require.NoErrorf(err, "Row(true)")
target := []uint64{100}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
})
t.Run("ClearRowQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldClear := testIndex.Field("test-field-clear")
err := cli.EnsureField(testFieldClear)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldClear.Set(1, 100),
testFieldClear.Set(1, 200),
))
require.NoErrorf(err, "Set(1, 100) Set(1, 200)")
resp, err := cli.Query(testFieldClear.Row(1))
require.NoErrorf(err, "Row(1)")
target := []uint64{100, 200}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
_, err = cli.Query(testFieldClear.ClearRow(1))
require.NoErrorf(err, "ClearRow(1)")
resp, err = cli.Query(testFieldClear.Row(1))
require.NoErrorf(err, "Row(1)")
target = []uint64(nil)
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
})
t.Run("RowsQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldRows := testIndex.Field("test-field-rows")
err := cli.EnsureField(testFieldRows)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldRows.Set(1, 100),
testFieldRows.Set(1, 200),
testFieldRows.Set(2, 200),
))
require.NoErrorf(err, "Set(1, 100) Set(1, 200) Set(2, 200)")
resp, err := cli.Query(testFieldRows.Rows())
require.NoErrorf(err, "Rows")
target := RowIdentifiersResult{
IDs: []uint64{1, 2},
}
require.Equalf(target, resp.Result().RowIdentifiers(), "RowIdentifiers Result")
})
t.Run("UnionRowsQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldRows := testIndex.Field("test-field-rows")
err := cli.EnsureField(testFieldRows)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldRows.Set(1, 100),
testFieldRows.Set(1, 200),
testFieldRows.Set(2, 200),
))
require.NoErrorf(err, "Set(1, 100) Set(1, 200) Set(2, 200)")
resp, err := cli.Query(testFieldRows.Rows().Union())
require.NoErrorf(err, "Rows Union")
target := []uint64{100, 200}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
})
t.Run("LikeQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldLike := testIndex.Field("test-field-like", OptFieldKeys(true))
err := cli.EnsureField(testFieldLike)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldLike.Set("a", 100),
testFieldLike.Set("b", 200),
testFieldLike.Set("bc", 200),
))
require.NoErrorf(err, "Set(a, 100) Set(b, 200) Set(bc, 200)")
resp, err := cli.Query(testFieldLike.Like("b%"))
require.NoErrorf(err, `Like(b%)`)
target := RowIdentifiersResult{
Keys: []string{"b", "bc"},
}
require.Equalf(target, resp.Result().RowIdentifiers(), "RowIdentifiers Result")
})
t.Run("GroupByQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldGroupBy := testIndex.Field("test-field-group-by")
err := cli.EnsureField(testFieldGroupBy)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldGroupBy.Set(1, 100),
testFieldGroupBy.Set(1, 200),
testFieldGroupBy.Set(2, 200),
))
require.NoErrorf(err, "Set(1, 100) Set(1, 200) Set(2, 200)")
resp, err := cli.Query(testIndex.GroupBy(testFieldGroupBy.Rows()))
require.NoErrorf(err, `Like(b%)`)
target := []GroupCount{
{Groups: []FieldRow{{FieldName: "test-field-group-by", RowID: 1}}, Count: 2},
{Groups: []FieldRow{{FieldName: "test-field-group-by", RowID: 2}}, Count: 1},
}
assertGroupBy(t, require, target, resp.Result().GroupCounts())
})
t.Run("GroupByQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldGroupBy := testIndex.Field("test-field-group-by-int", OptFieldTypeInt(-10, 10))
err := cli.EnsureField(testFieldGroupBy)
require.NoError(err)
_, err = cli.Query(testIndex.RawQuery(`
Set(0, test-field-group-by-int=1)
Set(1, test-field-group-by-int=2)
Set(2, test-field-group-by-int=-2)
Set(3, test-field-group-by-int=-1)
Set(4, test-field-group-by-int=4)
Set(10, test-field-group-by-int=0)
Set(100, test-field-group-by-int=0)
Set(1000, test-field-group-by-int=0)
Set(10000, test-field-group-by-int=0)
Set(100000, test-field-group-by-int=0)
`))
require.NoError(err, "Set(0..100000)")
resp, err := cli.Query(testIndex.GroupBy(testFieldGroupBy.Rows()))
require.NoErrorf(err, `GroupBy(Rows)`)
var a, b, c, d, e, f int64 = -2, -1, 0, 1, 2, 4
target := []GroupCount{
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &a}}, Count: 1},
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &b}}, Count: 1},
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &c}}, Count: 5},
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &d}}, Count: 1},
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &e}}, Count: 1},
{Groups: []FieldRow{{FieldName: "test-field-group-by-int", Value: &f}}, Count: 1},
}
assertGroupBy(t, require, target, resp.Result().GroupCounts())
})
t.Run("CreateDeleteIndexField", func(t *testing.T) {
tmpIndex := NewIndex("tmp-index")
tmpField := tmpIndex.Field("tmp-field")
err := cli.CreateIndex(tmpIndex)
require.NoError(err)
err = cli.CreateField(tmpField)
require.NoError(err)
err = cli.DeleteField(tmpField)
require.NoError(err)
err = cli.DeleteIndex(tmpIndex)
require.NoError(err)
})
t.Run("ErrorCreatingIndexField", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
require.ErrorIs(cli.CreateIndex(testIndex), ErrIndexExists)
require.ErrorIs(cli.CreateField(testField), ErrFieldExists)
})
t.Run("Failover", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
uri, _ := pnet.NewURIFromAddress("does-not-resolve.foo.bar")
tmpcli, _ := NewClient(NewClusterWithHost(uri, uri, uri, uri), OptClientRetries(0))
attrs := map[string]interface{}{"a": 1}
_, err := tmpcli.Query(testIndex.SetColumnAttrs(0, attrs))
require.Error(err, ErrTriedMaxHosts)
})
t.Run("InvalidQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
_, _, err := cli.HTTPRequest("INVALID METHOD", "/foo", nil, nil)
require.Error(err)
_, err = cli.Query(testIndex.RawQuery("Invalid query"))
require.Error(err)
})
t.Run("Sync", func(t *testing.T) {
testIndexRemote := NewIndex("test-index-remote")
err := cli.EnsureIndex(testIndexRemote)
require.NoError(err)
testFieldRemote := testIndexRemote.Field("test-field-remote")
err = cli.EnsureField(testFieldRemote)
require.NoError(err)
schema := NewSchema()
idx1 := schema.Index("index-1")
idx1.Field("field-1-1")
idx1.Field("field-1-2")
idx2 := schema.Index("index-2")
idx2.Field("field-2-1")
schema.Index(testIndexRemote.Name())
err = cli.SyncSchema(schema)
require.NoError(err)
err = cli.DeleteIndex(testIndexRemote)
require.NoError(err)
err = cli.DeleteIndex(idx1)
require.NoError(err)
err = cli.DeleteIndex(idx2)
require.NoError(err)
})
t.Run("FetchFragmentNodes", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
nodes, err := cli.fetchFragmentNodes(testIndex.Name(), 0)
require.NoErrorf(err, "fetchFragmentNodes(%s, 0)", testIndex.name)
require.Equalf(replicaN, len(nodes), "len(nodes)")
// running the same for coverage
nodes, err = cli.fetchFragmentNodes(testIndex.Name(), 0)
require.NoErrorf(err, "fetchFragmentNodes(%s, 0)", testIndex.name)
require.Equalf(replicaN, len(nodes), "len(nodes)")
})
t.Run("RowRangeQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldRange := testIndex.Field("test-field-range", OptFieldTypeTime(TimeQuantumMonthDayHour))
err := cli.EnsureField(testFieldRange)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldRange.SetTimestamp(10, 100, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC)),
testFieldRange.SetTimestamp(10, 100, time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)),
testFieldRange.SetTimestamp(10, 100, time.Date(2019, time.January, 1, 0, 0, 0, 0, time.UTC)),
))
require.NoErrorf(err, "BatchQuery SetTimestamp")
start := time.Date(2017, time.January, 5, 0, 0, 0, 0, time.UTC)
end := time.Date(2018, time.January, 5, 0, 0, 0, 0, time.UTC)
resp, err := cli.Query(testFieldRange.RowRange(10, start, end))
require.NoErrorf(err, "RowRange(10, %v, %v)", start, end)
target := []uint64{100}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
})
t.Run("StoreQuery", func(t *testing.T) {
schema := NewSchema()
testIndexStore := schema.Index("test-index-store")
testFieldFrom := testIndexStore.Field("test-field-from")
testFieldTo := testIndexStore.Field("test-field-to")
err := cli.SyncSchema(schema)
require.NoError(err)
defer func() {
cerr := cli.DeleteIndex(testIndexStore)
require.NoErrorf(cerr, "failed to delete index: %v", testIndexStore.name)
}()
_, err = cli.Query(testIndexStore.BatchQuery(
testFieldFrom.Set(10, 100),
testFieldFrom.Set(10, 200),
testFieldTo.Store(testFieldFrom.Row(10), 1),
))
require.NoErrorf(err, "Set(10, 100) Set(10, 200) Store(Row(10), 1)")
resp, err := cli.Query(testFieldTo.Row(1))
require.NoErrorf(err, "Row(1)")
target := []uint64{100, 200}
require.Equalf(target, resp.Result().Row().Columns, "Row Result Columns")
})
t.Run("MultipleClientKeyQuery", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldMultiClient := testIndexWithKeys.Field("test-field-multiclient")
err := cli.EnsureField(testFieldMultiClient)
require.NoError(err)
eg := &errgroup.Group{}
for i := 0; i < 10; i++ {
rowID := uint64(i)
eg.Go(func() error {
_, e := cli.Query(testFieldMultiClient.Set(rowID, "col"))
return e
})
}
require.NoError(eg.Wait())
})
t.Run("ExportRowIDColumnID", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldExport := testIndex.Field("test-field-export")
err := cli.EnsureField(testFieldExport)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldExport.Set(1, 1),
testFieldExport.Set(1, 10),
testFieldExport.Set(2, 1048577),
), nil)
require.NoErrorf(err, "Set(1, 1) Set(1, 10) Set(2, 1048577)")
r, err := cli.ExportField(testFieldExport)
require.NoErrorf(err, "ExportField")
b, err := ioutil.ReadAll(r)
require.NoError(err)
target := "1,1\n1,10\n2,1048577\n"
require.Equalf(target, string(b), "Export Field Response")
})
t.Run("ExportRowIDColumnKey", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldExport := testIndexWithKeys.Field("test-field-export")
err := cli.EnsureField(testFieldExport)
require.NoError(err)
_, err = cli.Query(testIndexWithKeys.BatchQuery(
testFieldExport.Set(1, "one"),
testFieldExport.Set(1, "ten"),
testFieldExport.Set(2, "big-number"),
), nil)
require.NoErrorf(err, "Set(1, one) Set(1, ten) Set(2, big-number)")
r, err := cli.ExportField(testFieldExport)
require.NoErrorf(err, "ExportField")
b, err := ioutil.ReadAll(r)
require.NoError(err)
target := "1,one\n1,ten\n2,big-number\n"
require.Equalf(target, string(b), "Export Field Response")
})
t.Run("TranslateRowKeys", func(t *testing.T) {
setup(t, require, cli)
defer tearDown(t, require, cli)
testFieldTranslate := testIndex.Field("test-field-translate-rowkeys", OptFieldKeys(true))
err := cli.EnsureField(testFieldTranslate)
require.NoError(err)
_, err = cli.Query(testIndex.BatchQuery(
testFieldTranslate.Set("key1", 10),
testFieldTranslate.Set("key2", 1000),
))
require.NoErrorf(err, "Set(key1, 10) Set(key2, 1000)")
rowIDs, err := cli.TranslateRowKeys(testFieldTranslate, []string{"key1", "key2"})
require.NoErrorf(err, "TranslateRowKeys")
target := []uint64{1, 2}
require.Equalf(target, rowIDs, "TranslateRowKeys")
})
t.Run("TranslateColKeys", func(t *testing.T) {
trns, err := cli.StartTransaction("blah", time.Minute, false, time.Minute)
require.NoErrorf(err, "StartTransaction(blah)")
require.Equalf("blah", trns.ID, "TranslateColumnKeys ID")
require.Equalf(time.Minute, trns.Timeout, "TranslateColumnKeys Timeout")
require.Truef(trns.Active, "TranslateColumnKeys Active")
trnsMap, err := cli.Transactions()
require.NoErrorf(err, "Transactions")
require.Equalf(1, len(trnsMap), "Transactions len")
require.Truef(trnsMap["blah"].Active, "Transactions Active")
trns, err = cli.GetTransaction("blah")
require.NoErrorf(err, "GetTransaction(blah)")
require.Equalf("blah", trns.ID, "TranslateColumnKeys ID")
require.Equalf(time.Minute, trns.Timeout, "TranslateColumnKeys Timeout")
require.Truef(trns.Active, "TranslateColumnKeys Active")
trns, err = cli.FinishTransaction("blah")
require.NoErrorf(err, "FinishTransaction(blah)")
require.Equalf("blah", trns.ID, "TranslateColumnKeys ID")
require.Equalf(time.Minute, trns.Timeout, "TranslateColumnKeys Timeout")
require.Truef(trns.Active, "TranslateColumnKeys Active")
})
})
}
}
func assertGroupBy(t *testing.T, r *require.Assertions, expected, results []GroupCount) {
t.Helper()
r.Equalf(len(expected), len(results), "number of groupings mismatch")
for i, result := range results {
r.Equalf(expected[i], result, "unexpected result at %d", i)
}
}

293
client/client_test.go Normal file
View file

@ -0,0 +1,293 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"crypto/tls"
"errors"
"reflect"
"testing"
pnet "github.com/pilosa/pilosa/v2/net"
)
func TestQueryWithError(t *testing.T) {
var err error
client := DefaultClient()
index := NewIndex("foo")
field := index.Field("foo")
invalid := field.FilterAttrTopN(12, field.Row(7), "$invalid$", 80, 81)
_, err = client.Query(invalid, nil)
if err == nil {
t.Fatalf("Should have failed")
}
}
func TestClientOptions(t *testing.T) {
targets := []*ClientOptions{
{SocketTimeout: 10},
{ConnectTimeout: 5},
{PoolSizePerRoute: 7},
{TotalPoolSize: 17},
{TLSConfig: &tls.Config{InsecureSkipVerify: true}},
}
optionsList := [][]ClientOption{
{OptClientSocketTimeout(10)},
{OptClientConnectTimeout(5)},
{OptClientPoolSizePerRoute(7)},
{OptClientTotalPoolSize(17)},
{OptClientTLSConfig(&tls.Config{InsecureSkipVerify: true})},
}
for i := 0; i < len(targets); i++ {
options := &ClientOptions{}
err := options.addOptions(optionsList[i]...)
if err != nil {
t.Fatal(err)
}
target := targets[i]
if !reflect.DeepEqual(target, options) {
t.Fatalf("%v != %v", target, options)
}
}
}
func TestNewClientWithErrorredOption(t *testing.T) {
_, err := NewClient(":8888", ClientOptionErr(0))
if err == nil {
t.Fatalf("Should have failed")
}
}
func TestNewClient(t *testing.T) {
client, err := NewClient(":9999", OptClientManualServerAddress(true))
if err != nil {
t.Fatal(err)
}
targetURI, err := pnet.NewURIFromAddress(":9999")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(targetURI, client.manualServerURI) {
t.Fatalf("%v != %v", targetURI, client.manualServerURI)
}
targetFragmentNode := &fragmentNode{
Scheme: "http",
Host: "localhost",
Port: 9999,
}
if !reflect.DeepEqual(targetFragmentNode, client.manualFragmentNode) {
t.Fatalf("%v != %v", targetFragmentNode, client.manualFragmentNode)
}
client, err = NewClient(":9999")
if err != nil {
t.Fatal(err)
}
targetURI, err = pnet.NewURIFromAddress(":9999")
if err != nil {
t.Fatal(err)
}
target := []*pnet.URI{targetURI}
if !reflect.DeepEqual(target, client.cluster.hosts) {
t.Fatalf("%v != %v", target, client.cluster.hosts)
}
client, err = NewClient([]string{":9999"})
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(target, client.cluster.hosts) {
t.Fatalf("%v != %v", target, client.cluster.hosts)
}
targetURI1, err := pnet.NewURIFromAddress(":8888")
if err != nil {
t.Fatal(err)
}
targetURI2, err := pnet.NewURIFromAddress(":9999")
if err != nil {
t.Fatal(err)
}
client, err = NewClient([]*pnet.URI{targetURI1, targetURI2})
if err != nil {
t.Fatal(err)
}
target = []*pnet.URI{targetURI1, targetURI2}
if !reflect.DeepEqual(target, client.cluster.hosts) {
t.Fatalf("%v != %v", target, client.cluster.hosts)
}
client, err = NewClient([]*pnet.URI{targetURI})
if err != nil {
t.Fatal(err)
}
target = []*pnet.URI{targetURI}
if !reflect.DeepEqual(target, client.cluster.hosts) {
t.Fatalf("%v != %v", target, client.cluster.hosts)
}
client, err = NewClient(DefaultCluster())
if err != nil {
t.Fatal(err)
}
target = []*pnet.URI{}
if !reflect.DeepEqual(target, client.cluster.hosts) {
t.Fatalf("%v != %v", target, client.cluster.hosts)
}
}
func TestNewClientWithInvalidAddr(t *testing.T) {
_, err := NewClient(10)
if err != ErrAddrURIClusterExpected {
t.Fatalf("%v != %v", ErrAddrURIClusterExpected, err)
}
_, err = NewClient(":invalid")
if err == nil {
t.Fatalf("should have failed: %+v", err)
}
_, err = NewClient([]string{"valid:8000", ":invalid"})
if err != pnet.ErrInvalidAddress {
t.Fatalf("Should have failed '%v, got '%v'", pnet.ErrInvalidAddress, err)
}
}
func TestNewClientManualAddressWithNoURIs(t *testing.T) {
_, err := NewClient([]string{}, OptClientManualServerAddress(true))
if err != ErrSingleServerAddressRequired {
t.Fatalf("%v != %v", ErrSingleServerAddressRequired, err)
}
_, err = NewClient([]*pnet.URI{}, OptClientManualServerAddress(true))
if err != ErrSingleServerAddressRequired {
t.Fatalf("%v != %v", ErrSingleServerAddressRequired, err)
}
}
func TestNewClientManualAddressWithMultipleURIs(t *testing.T) {
_, err := NewClient([]string{":9000", ":5000"}, OptClientManualServerAddress(true))
if err != ErrSingleServerAddressRequired {
t.Fatalf("%v != %v", ErrSingleServerAddressRequired, err)
}
targetURI1, err := pnet.NewURIFromAddress(":9000")
if err != nil {
t.Fatal(err)
}
targetURI2, err := pnet.NewURIFromAddress(":5000")
if err != nil {
t.Fatal(err)
}
_, err = NewClient([]*pnet.URI{targetURI1, targetURI2}, OptClientManualServerAddress(true))
if err != ErrSingleServerAddressRequired {
t.Fatalf("%v != %v", ErrSingleServerAddressRequired, err)
}
}
func ClientOptionErr(int) ClientOption {
return func(*ClientOptions) error {
return errors.New("Some error")
}
}
func TestQueryOptions(t *testing.T) {
targets := []*QueryOptions{
{ColumnAttrs: true},
{ColumnAttrs: false},
{ExcludeRowAttrs: true},
{ExcludeRowAttrs: false},
{ExcludeColumns: true},
{ExcludeColumns: false},
}
optionsList := [][]interface{}{
{OptQueryColumnAttrs(true)},
{OptQueryColumnAttrs(false)},
{OptQueryExcludeAttrs(true)},
{OptQueryExcludeAttrs(false)},
{OptQueryExcludeColumns(true)},
{OptQueryExcludeColumns(false)},
}
for i := 0; i < len(targets); i++ {
options := &QueryOptions{}
err := options.addOptions(optionsList[i]...)
if err != nil {
t.Fatal(err)
}
target := targets[i]
if !reflect.DeepEqual(target, options) {
t.Fatalf("%v != %v", target, options)
}
}
target := &QueryOptions{
ColumnAttrs: true,
ExcludeRowAttrs: true,
ExcludeColumns: true,
}
options := &QueryOptions{}
err := options.addOptions(&QueryOptions{
ColumnAttrs: true,
ExcludeRowAttrs: true,
ExcludeColumns: true,
})
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(target, options) {
t.Fatalf("%v != %v", target, options)
}
}
func TestQueryOptionsWithError(t *testing.T) {
options := &QueryOptions{}
err := options.addOptions(1)
if err == nil {
t.Fatalf("should have failed")
}
err = options.addOptions(OptQueryColumnAttrs(true), nil)
if err == nil {
t.Fatalf("should have failed")
}
err = options.addOptions(OptQueryColumnAttrs(true), &QueryOptions{})
if err == nil {
t.Fatalf("should have failed")
}
err = options.addOptions(QueryOptionErr(0))
if err == nil {
t.Fatalf("should have failed")
}
}
func TestQueryOptionsError(t *testing.T) {
client := DefaultClient()
index := NewIndex("foo")
_, err := client.Query(index.RawQuery(""), QueryOptionErr(0))
if err == nil {
t.Fatalf("should have failed")
}
}
func QueryOptionErr(int) QueryOption {
return func(*QueryOptions) error {
return errors.New("Some error")
}
}

112
client/cluster.go Normal file
View file

@ -0,0 +1,112 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"sync"
pnet "github.com/pilosa/pilosa/v2/net"
)
// Cluster contains hosts in a Pilosa cluster.
type Cluster struct {
hosts []*pnet.URI
okList []bool
mutex *sync.RWMutex
lastHostIdx int
}
// DefaultCluster returns the default Cluster.
func DefaultCluster() *Cluster {
return &Cluster{
hosts: make([]*pnet.URI, 0),
okList: make([]bool, 0),
mutex: &sync.RWMutex{},
}
}
// NewClusterWithHost returns a cluster with the given URIs.
func NewClusterWithHost(hosts ...*pnet.URI) *Cluster {
cluster := DefaultCluster()
for _, host := range hosts {
cluster.AddHost(host)
}
return cluster
}
// AddHost adds a host to the cluster.
func (c *Cluster) AddHost(address *pnet.URI) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.hosts = append(c.hosts, address)
c.okList = append(c.okList, true)
}
// Host returns a host in the cluster.
func (c *Cluster) Host() *pnet.URI {
c.mutex.Lock()
var host *pnet.URI
for i := range c.okList {
idx := (i + c.lastHostIdx) % len(c.okList)
ok := c.okList[idx]
if ok {
host = c.hosts[idx]
break
}
}
c.lastHostIdx++
c.mutex.Unlock()
if host != nil {
return host
}
c.reset()
return host
}
// RemoveHost black lists the host with the given pnet.URI from the cluster.
func (c *Cluster) RemoveHost(address *pnet.URI) {
c.mutex.Lock()
defer c.mutex.Unlock()
for i, uri := range c.hosts {
if uri.Equals(address) {
c.okList[i] = false
break
}
}
}
// Hosts returns all available hosts in the cluster.
func (c *Cluster) Hosts() []pnet.URI {
c.mutex.RLock()
defer c.mutex.RUnlock()
hosts := make([]pnet.URI, 0, len(c.hosts))
for i, host := range c.hosts {
if c.okList[i] {
hosts = append(hosts, *host)
}
}
return hosts
}
func (c *Cluster) reset() {
c.mutex.Lock()
defer c.mutex.Unlock()
for i := range c.okList {
c.okList[i] = true
}
}

83
client/cluster_test.go Normal file
View file

@ -0,0 +1,83 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"testing"
pnet "github.com/pilosa/pilosa/v2/net"
)
func TestNewClusterWithHost(t *testing.T) {
c := NewClusterWithHost(pnet.DefaultURI())
hosts := c.Hosts()
if len(hosts) != 1 || !hosts[0].Equals(pnet.DefaultURI()) {
t.Fail()
}
}
func TestAddHost(t *testing.T) {
const addr = "http://localhost:3000"
c := DefaultCluster()
if c.Hosts() == nil {
t.Fatalf("Hosts should not be nil")
}
uri, err := pnet.NewURIFromAddress(addr)
if err != nil {
t.Fatalf("Cannot parse address")
}
target, err := pnet.NewURIFromAddress(addr)
if err != nil {
t.Fatalf("Cannot parse address")
}
c.AddHost(uri)
hosts := c.Hosts()
if len(hosts) != 1 || !hosts[0].Equals(target) {
t.Fail()
}
}
func TestHosts(t *testing.T) {
c := DefaultCluster()
if c.Host() != nil {
t.Fatalf("Hosts with empty cluster should return nil")
}
c = NewClusterWithHost(pnet.DefaultURI())
if !c.Host().Equals(pnet.DefaultURI()) {
t.Fatalf("Host should return a value if there are hosts in the cluster")
}
}
func TestRemoveHost(t *testing.T) {
uri, err := pnet.NewURIFromAddress("index1.pilosa.com:9999")
if err != nil {
t.Fatal(err)
}
c := NewClusterWithHost(uri)
if len(c.hosts) != 1 {
t.Fatalf("The cluster should contain the host")
}
uri, err = pnet.NewURIFromAddress("index1.pilosa.com:9999")
if err != nil {
t.Fatal(err)
}
c.RemoveHost(uri)
if len(c.Hosts()) != 0 {
t.Fatalf("The cluster should not contain the host")
}
}

194
client/csv/csv.go Normal file
View file

@ -0,0 +1,194 @@
// Copyright 2017 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 csv
import (
"bufio"
"errors"
"fmt"
"io"
"strconv"
"strings"
"time"
"github.com/pilosa/pilosa/v2/client"
)
// Format is the format of the data in the CSV file.
type Format uint
const (
// RowIDColumnID formatted data is ROW_ID,COLUMN_ID.
RowIDColumnID Format = iota
// RowIDColumnKey formatted data is ROW_ID,COLUMN_KEY.
RowIDColumnKey
// RowKeyColumnID formatted data is ROW_KEY,COLUMN_ID.
RowKeyColumnID
// RowKeyColumnKey formatted data is ROW_KEY,COLUMN_ID.
RowKeyColumnKey
// ColumnID formatted data is COLUMN_ID. Valid only for value import.
ColumnID
// ColumnKey formatted data is COLUMN_KEY. Valud only for value import.
ColumnKey
)
// ColumnUnmarshaller creates a RecordUnmarshaller for importing columns with the given format.
func ColumnUnmarshaller(format Format) RecordUnmarshaller {
return ColumnUnmarshallerWithTimestamp(format, "")
}
// ColumnUnmarshallerWithTimestamp creates a RecordUnmarshaller for importing columns with the given format and timestamp format.
func ColumnUnmarshallerWithTimestamp(format Format, timestampFormat string) RecordUnmarshaller {
return func(text string) (client.Record, error) {
var err error
column := client.Column{}
parts := strings.Split(text, ",")
if len(parts) < 2 {
return nil, errors.New("Invalid CSV line")
}
hasRowKey := format == RowKeyColumnID || format == RowKeyColumnKey
hasColumnKey := format == RowIDColumnKey || format == RowKeyColumnKey
if hasRowKey {
column.RowKey = parts[0]
} else {
column.RowID, err = strconv.ParseUint(parts[0], 10, 64)
if err != nil {
return nil, errors.New("Invalid row ID")
}
}
if hasColumnKey {
column.ColumnKey = parts[1]
} else {
column.ColumnID, err = strconv.ParseUint(parts[1], 10, 64)
if err != nil {
return nil, errors.New("Invalid column ID")
}
}
timestamp := int64(0)
if len(parts) == 3 {
if timestampFormat == "" {
if tsInt, err := strconv.Atoi(parts[2]); err != nil {
return nil, err
} else {
timestamp = int64(tsInt)
}
} else {
t, err := time.Parse(timestampFormat, parts[2])
if err != nil {
return nil, err
}
timestamp = t.Unix() * int64(time.Second) // Casting a duration to int64 gives the number of nanoseconds in that duration.
}
}
column.Timestamp = timestamp
return column, nil
}
}
// RecordUnmarshaller is a function which creates a Record from a CSV file line with column data.
type RecordUnmarshaller func(text string) (client.Record, error)
// Iterator reads records from a Reader.
// Each line should contain a single record in the following form:
// field1,field2,...
type Iterator struct {
reader io.Reader
line int
scanner *bufio.Scanner
unmarshaller RecordUnmarshaller
}
// NewIterator creates a CSVIterator from a Reader.
func NewIterator(reader io.Reader, unmarshaller RecordUnmarshaller) *Iterator {
return &Iterator{
reader: reader,
line: 0,
scanner: bufio.NewScanner(reader),
unmarshaller: unmarshaller,
}
}
// NewColumnIterator creates a new iterator for column data.
func NewColumnIterator(format Format, reader io.Reader) *Iterator {
return NewIterator(reader, ColumnUnmarshaller(format))
}
// NewColumnIteratorWithTimestampFormat creates a new iterator for column data with timestamp.
func NewColumnIteratorWithTimestampFormat(format Format, reader io.Reader, timestampFormat string) *Iterator {
return NewIterator(reader, ColumnUnmarshallerWithTimestamp(format, timestampFormat))
}
// NewValueIterator creates a new iterator for value data.
func NewValueIterator(format Format, reader io.Reader) *Iterator {
return NewIterator(reader, FieldValueUnmarshaller(format))
}
// NextRecord iterates on lines of a Reader.
// Returns io.EOF on end of iteration.
func (c *Iterator) NextRecord() (client.Record, error) {
if ok := c.scanner.Scan(); ok {
c.line++
text := strings.TrimSpace(c.scanner.Text())
if text != "" {
rc, err := c.unmarshaller(text)
if err != nil {
return nil, fmt.Errorf("%s at line: %d", err.Error(), c.line)
}
return rc, nil
}
}
err := c.scanner.Err()
if err != nil {
return nil, err
}
return nil, io.EOF
}
// FieldValueUnmarshaller is a function which creates a Record from a CSV file line with value data.
func FieldValueUnmarshaller(format Format) RecordUnmarshaller {
return func(text string) (client.Record, error) {
parts := strings.Split(text, ",")
if len(parts) < 2 {
return nil, errors.New("Invalid CSV")
}
value, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil {
return nil, errors.New("Invalid value")
}
switch format {
case ColumnID:
columnID, err := strconv.ParseUint(parts[0], 10, 64)
if err != nil {
return nil, errors.New("Invalid column ID at line: %d")
}
return client.FieldValue{
ColumnID: uint64(columnID),
Value: value,
}, nil
case ColumnKey:
return client.FieldValue{
ColumnKey: parts[0],
Value: value,
}, nil
default:
return nil, fmt.Errorf("Invalid format: %d", format)
}
}
}

60
client/csv/csv_it_test.go Normal file
View file

@ -0,0 +1,60 @@
// Copyright 2017 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 integration
package csv_test
import (
"io"
"reflect"
"strings"
"testing"
"github.com/pilosa/pilosa/v2/client"
"github.com/pilosa/pilosa/v2/client/csv"
)
func TestCSVIterate(t *testing.T) {
text := `10,7
10,5
2,3
7,1`
iterator := csv.NewColumnIterator(csv.RowIDColumnID, strings.NewReader(text))
recs := consumeIterator(t, iterator)
target := []client.Record{
client.Column{RowID: 10, ColumnID: 7},
client.Column{RowID: 10, ColumnID: 5},
client.Column{RowID: 2, ColumnID: 3},
client.Column{RowID: 7, ColumnID: 1},
}
if !reflect.DeepEqual(target, recs) {
t.Fatalf("%v != %v", target, recs)
}
}
func consumeIterator(t *testing.T, it *csv.Iterator) []client.Record {
recs := []client.Record{}
for {
r, err := it.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
recs = append(recs, r)
}
return recs
}

267
client/csv/csv_test.go Normal file
View file

@ -0,0 +1,267 @@
// Copyright 2017 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 csv_test
import (
"errors"
"io"
"reflect"
"strings"
"testing"
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/client"
"github.com/pilosa/pilosa/v2/client/csv"
)
func TestCSVColumnIterator(t *testing.T) {
reader := strings.NewReader(`1,10,683793200
5,20,683793300
3,41,683793385`)
iterator := csv.NewColumnIterator(csv.RowIDColumnID, reader)
columns := []client.Record{}
for {
column, err := iterator.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
columns = append(columns, column)
}
if len(columns) != 3 {
t.Fatalf("There should be 3 columns")
}
target := []client.Column{
{RowID: 1, ColumnID: 10, Timestamp: 683793200},
{RowID: 5, ColumnID: 20, Timestamp: 683793300},
{RowID: 3, ColumnID: 41, Timestamp: 683793385},
}
for i := range target {
if !reflect.DeepEqual(target[i], columns[i]) {
t.Fatalf("%v != %v", target[i], columns[i])
}
}
}
func TestCSVColumnIteratorWithTimestampFormatRowIDColumnID(t *testing.T) {
format := "2006-01-02T03:04"
reader := strings.NewReader(`1,10,1991-09-02T09:33
5,20,1991-09-02T09:35
3,41,1991-09-02T09:36`)
iterator := csv.NewColumnIteratorWithTimestampFormat(csv.RowIDColumnID, reader, format)
records := []client.Record{}
for {
record, err := iterator.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
records = append(records, record)
}
target := []client.Column{
{RowID: 1, ColumnID: 10, Timestamp: 683803980000000000},
{RowID: 5, ColumnID: 20, Timestamp: 683804100000000000},
{RowID: 3, ColumnID: 41, Timestamp: 683804160000000000},
}
if len(records) != len(target) {
t.Fatalf("There should be %d columns", len(target))
}
for i := range target {
if !reflect.DeepEqual(target[i], records[i]) {
t.Fatalf("%v != %v", target[i], records[i])
}
}
}
func TestCSVColumnIteratorWithTimestampFormatRowKeyColumnKey(t *testing.T) {
format := "2006-01-02T03:04"
reader := strings.NewReader(`one,ten,1991-09-02T09:33
five,twenty,1991-09-02T09:35
three,forty-one,1991-09-02T09:36`)
iterator := csv.NewColumnIteratorWithTimestampFormat(csv.RowKeyColumnKey, reader, format)
records := []client.Record{}
for {
record, err := iterator.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
records = append(records, record)
}
target := []client.Column{
{RowKey: "one", ColumnKey: "ten", Timestamp: 683803980000000000},
{RowKey: "five", ColumnKey: "twenty", Timestamp: 683804100000000000},
{RowKey: "three", ColumnKey: "forty-one", Timestamp: 683804160000000000},
}
if len(records) != len(target) {
t.Fatalf("There should be %d columns", len(target))
}
for i := range target {
if !reflect.DeepEqual(target[i], records[i]) {
t.Fatalf("%v != %v", target[i], records[i])
}
}
}
func TestCSVColumnIteratorWithTimestampFormatFail(t *testing.T) {
format := "2014-07-16"
reader := strings.NewReader(`1,10,X`)
iterator := csv.NewColumnIteratorWithTimestampFormat(csv.RowIDColumnID, reader, format)
_, err := iterator.NextRecord()
if err == nil {
t.Fatalf("Should have failed")
}
}
func TestCSVValueIteratorWithColumnID(t *testing.T) {
reader := strings.NewReader(`1,10
5,-20
3,41
`)
iterator := csv.NewValueIterator(csv.ColumnID, reader)
values := []client.Record{}
for {
value, err := iterator.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
values = append(values, value)
}
target := []pilosa.FieldValue{
{ColumnID: 1, Value: 10},
{ColumnID: 5, Value: -20},
{ColumnID: 3, Value: 41},
}
if len(values) != len(target) {
t.Fatalf("There should be %d values, got %d", len(target), len(values))
}
for i := range target {
v := values[i].(client.FieldValue)
if !reflect.DeepEqual(pilosa.FieldValue(v), target[i]) {
t.Fatalf("'%+v' != '%+v'", target[i], values[i])
}
}
}
func TestCSVValueIteratorWithColumnKey(t *testing.T) {
reader := strings.NewReader(`one,10
five,-20
three,41
`)
iterator := csv.NewValueIterator(csv.ColumnKey, reader)
values := []client.Record{}
for {
value, err := iterator.NextRecord()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
values = append(values, value)
}
target := []pilosa.FieldValue{
{ColumnKey: "one", Value: 10},
{ColumnKey: "five", Value: -20},
{ColumnKey: "three", Value: 41},
}
if len(values) != len(target) {
t.Fatalf("There should be %d values, got %d", len(target), len(values))
}
for i := range target {
v := values[i].(client.FieldValue)
if !reflect.DeepEqual(pilosa.FieldValue(v), target[i]) {
t.Fatalf("%v != %v", target[i], values[i])
}
}
}
func TestCSValueIteratorWithInvalidFormat(t *testing.T) {
reader := strings.NewReader("1,2")
iterator := csv.NewValueIterator(csv.RowIDColumnID, reader)
_, err := iterator.NextRecord()
if err == nil {
t.Fatalf("should have failed")
}
}
func TestCSVColumnIteratorInvalidInput(t *testing.T) {
invalidInputs := []string{
// less than 2 columns
"155",
// invalid row ID
"a5,155",
// invalid column ID
"155,a5",
// invalid timestamp
"155,255,a5",
}
for _, text := range invalidInputs {
iterator := csv.NewColumnIterator(csv.RowIDColumnID, strings.NewReader(text))
_, err := iterator.NextRecord()
if err == nil {
t.Fatalf("CSVColumnIterator input: %s should fail", text)
}
}
}
func TestCSVValueIteratorInvalidInput(t *testing.T) {
invalidInputs := []string{
// less than 2 columns
"155",
// invalid column ID
"a5,155",
// invalid value
"155,a5",
}
for _, text := range invalidInputs {
iterator := csv.NewValueIterator(csv.ColumnID, strings.NewReader(text))
_, err := iterator.NextRecord()
if err == nil {
t.Fatalf("CSVValueIterator input: %s should fail", text)
}
}
}
func TestCSVColumnIteratorError(t *testing.T) {
iterator := csv.NewColumnIterator(csv.RowIDColumnID, &BrokenReader{})
_, err := iterator.NextRecord()
if err == nil {
t.Fatal("CSVColumnIterator should fail with error")
}
}
func TestCSVValueIteratorError(t *testing.T) {
iterator := csv.NewValueIterator(csv.ColumnID, &BrokenReader{})
_, err := iterator.NextRecord()
if err == nil {
t.Fatal("CSVValueIterator should fail with error")
}
}
type BrokenReader struct{}
func (r BrokenReader) Read(p []byte) (n int, err error) {
return 0, errors.New("broken reader")
}

68
client/doc.go Normal file
View file

@ -0,0 +1,68 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
/*
Package client enables querying a Pilosa server.
This client uses Pilosa's http+protobuf API.
Usage:
import (
"fmt"
"github.com/pilosa/pilosa/v2/client"
)
// Create a Client instance
cli := client.DefaultClient()
// Create a Schema instance
schema, err := cli.Schema()
if err != nil {
panic(err)
}
// Create an Index instance
index, err := schema.Index("repository")
if err != nil {
panic(err)
}
// Create a Field instance
stargazer, err := index.Field("stargazer")
if err != nil {
panic(err)
}
// Sync the schema with the server-side, so non-existing indexes/fields are created on the server-side.
err = cli.SyncSchema(schema)
if err != nil {
panic(err)
}
// Execute a query
response, err := cli.Query(stargazer.Row(5))
if err != nil {
panic(err)
}
// Act on the result
fmt.Println(response.Result())
See also https://www.pilosa.com/docs/api-reference/ and https://www.pilosa.com/docs/query-language/.
*/
package client

View file

@ -0,0 +1,152 @@
# Data Model and Queries
## Indexes and Fields
*Index* and *field*s are the main data models of Pilosa. You can check the [Pilosa documentation](https://www.pilosa.com/docs/latest/data-model/) for more detail about the data model.
The `schema.Index` function is used to create an index instance. Note that this does not create an index on the server; the index object simply defines the schema.
```go
schema := client.NewSchema()
repository := schema.Index("repository")
```
You can pass options while creating index instances:
```go
repository := schema.Index("repository", pilosa.OptIndexKeys(true))
```
Field definitions are created with a call to the `Field` function of an index:
```go
stargazer := repository.Field("stargazer")
```
You can pass options to fields:
```go
stargazer := repository.Field("stargazer", pilosa.OptFieldTypeTime(TimeQuantumYearMonthDay))
```
In case the schema already exists on the server, you can retrieve that instead of creating the schema:
```go
cli := client.DefaultClient()
schema, err := cli.Schema()
if err != nil {
// act on the error
}
repository := schema.Index("repository")
```
## Queries
Once you have indexes and field definitions, you can create queries for them. Some of the queries work on the columns; corresponding methods are attached to the index. Other queries work on rows with related methods attached to fields.
For instance, `Row` queries work on rows; use a `Field` object to create those queries:
```go
rowQuery := stargazer.Row(1) // corresponds to PQL: Row(stargazer=1)
```
`Union` queries work on columns; use the index to create them:
```go
query := repository.Union(rowQuery1, rowQuery2)
```
In order to increase throughput, you may want to batch queries sent to the Pilosa server. The `index.BatchQuery` function is used for that purpose:
```go
query := repository.BatchQuery(
stargazer.Row(1),
repository.Union(stargazer.Row(100), stargazer.Row(5)))
```
The recommended way of creating query instances is using dedicated functions attached to index and field objects, but sometimes it would be desirable to send raw queries to Pilosa. You can use `index.RawQuery` method for that. Note that query string is not validated before sending to the server:
```go
query := repository.RawQuery("Row(stargazer=5)")
```
Raw queries are only sent to the coordinator node of a Pilosa cluster, so currently there's a possible performance hit using them instead of ORM functions attached to index or field instances.
This client supports [range queries using bit sliced indexes (BSI)](https://www.pilosa.com/docs/latest/query-language/#range-bsi). Read the [Range Encoded Bitmaps](https://www.pilosa.com/blog/range-encoded-bitmaps/) blog post for more information about the BSI implementation of range encoding in Pilosa.
In order to use BSI range queries, an integer field should be created. The field should have its minimum and maximum set. Here's how you would do that:
```go
index := schema.Index("animals")
captivity := index.Field("captivity", pilosa.OptFieldTypeInt(0, 956))
```
If the field with the necessary field already exists on the server, you don't need to create the field instance, `cli.SyncSchema(schema)` would load that to `schema`. You can then add some data:
```go
// Add the captivity values to the field.
data := []int{3, 392, 47, 956, 219, 14, 47, 504, 21, 0, 123, 318}
query := index.BatchQuery()
for i, x := range data {
column := uint64(i + 1)
query.Add(captivity.SetIntValue(column, x))
}
cli.Query(query)
```
Let's write a range query:
```go
// Query for all animals with more than 100 specimens
response, _ := cli.Query(captivity.GT(100))
fmt.Println(response.Result().Row().Columns)
// Query for the total number of animals in captivity
response, _ = cli.Query(captivity.Sum(nil))
fmt.Println(response.Result().Value())
```
If you pass a row query to `Sum` as a filter, then only the columns matching the filter will be considered in the `Sum` calculation:
```go
// Let's run a few set queries first
cli.Query(index.BatchQuery(
field.Set(42, 1),
field.Set(42, 6)))
// Query for the total number of animals in captivity where row 42 is set
response, _ = cli.Query(captivity.Sum(field.Row(42)))
fmt.Println(response.Result().Value())
```
See the functions further below for the list of functions that can be used with a `Field`.
Please check [Pilosa documentation](https://www.pilosa.com/docs) for PQL details. Here is a list of methods corresponding to PQL calls:
Index:
* `Union(rows *PQLRowQuery...) *PQLRowQuery`
* `Intersect(rows *PQLRowQuery...) *PQLRowQuery`
* `Difference(rows *PQLRowQuery...) *PQLRowQuery`
* `Xor(rows ...*PQLRowQuery) *PQLRowQuery`
* `Not(row) *PQLRowQuery`
* `Count(row *PQLRowQuery) *PQLBaseQuery`
* `SetColumnAttrs(columnID uint64, attrs map[string]interface{}) *PQLBaseQuery`
* `Options(row *PQLRowQuery, opts ...OptionsOption) *PQLBaseQuery`
Field:
* `Row(rowID uint64) *PQLRowQuery`
* `Set(rowID uint64, columnID uint64) *PQLBaseQuery`
* `SetTimestamp(rowID uint64, columnID uint64, timestamp time.Time) *PQLBaseQuery`
* `Clear(rowID uint64, columnID uint64) *PQLBaseQuery`
* `TopN(n uint64) *PQLRowQuery`
* `RowTopN(n uint64, row *PQLRowQuery) *PQLRowQuery`
* `FilterFieldTopN(n uint64, row *PQLRowQuery, field string, values ...interface{}) *PQLRowQuery`
* `Range(rowID uint64, start time.Time, end time.Time) *PQLRowQuery`
* `RowRange(rowID uint64, start time.Time, end time.Time) *PQLRowQuery`
* `SetRowAttrs(rowID uint64, attrs map[string]interface{}) *PQLBaseQuery`
* `ClearRow(rowIDOrKey interface{}) *PQLBaseQuery`
* `Store(row *PQLRowQuery, rowIDOrKey interface{}) *PQLBaseQuery`
* `LT(n int) *PQLRowQuery`
* `LTE(n int) *PQLRowQuery`
* `GT(n int) *PQLRowQuery`
* `GTE(n int) *PQLRowQuery`
* `Between(a int, b int) *PQLRowQuery`
* `Sum(row *PQLRowQuery) *PQLBaseQuery`
* `Min(row *PQLRowQuery) *PQLBaseQuery`
* `Max(row *PQLRowQuery) *PQLBaseQuery`
* `SetIntValue(columnID uint64, value int) *PQLBaseQuery`

View file

@ -0,0 +1,178 @@
# Server Interaction
## Pilosa URI
A Pilosa URI has the `${SCHEME}://${HOST}:${PORT}` format:
* **Scheme**: Protocol of the URI. Default: `http`.
* **Host**: Hostname or ipv4/ipv6 IP address. Default: localhost.
* **Port**: Port number. Default: `10101`.
All parts of the URI are optional, but at least one of them must be specified. The following are equivalent:
* `http://localhost:10101`
* `http://localhost`
* `http://:10101`
* `localhost:10101`
* `localhost`
* `:10101`
A Pilosa URI is represented by the `github.com/pilosa/pilosa/v2/net URI` struct. Below are a few ways to create `URI` objects:
```go
import pnet "github.com/pilosa/pilosa/v2/net"
// create the default URI: http://localhost:10101
uri1 := pnet.DefaultURI()
// create a URI from string address
uri2, err := pnet.NewURIFromAddress("index1.pilosa.com:20202");
// create a URI with the given host and port
uri3, err := pnet.NewURIFromHostPort("index1.pilosa.com", 20202);
```
## Pilosa Client
In order to interact with a Pilosa server, an instance of `client.Client` should be created. The client is thread-safe and uses a pool of connections to the server, so we recommend creating a single instance of the client and sharing it when necessary.
If the Pilosa server is running at the default address (`http://localhost:10101`) you can create the client with default options using:
```go
import "github.com/pilosa/pilosa/v2/client"
cli := client.DefaultClient()
```
To use a custom server address, use the `NewClient` function:
```go
uri, err := pnet.NewURIFromAddress("http://index1.pilosa.com:15000")
if err != nil {
// Act on the error
}
cli, err := client.NewClient(uri)
```
Equivalently:
```go
cli, err := client.NewClient("http://index1.pilosa.com:15000")
```
If you are running a cluster of Pilosa servers, you can create a `Cluster` struct that keeps addresses of those servers:
```go
uri1, err := pnet.NewURIFromAddress(":10101")
uri2, err := pnet.NewURIFromAddress(":10110")
uri3, err := pnet.NewURIFromAddress(":10111")
cluster := client.NewClusterWithHost(uri1, uri2, uri3)
// Create a client with the cluster
cli, err := client.NewClient(cluster)
```
That is equivalent to:
```go
cli, err := client.NewClient([]string{":10101", ":10110", ":10111"})
```
It is possible to customize the behaviour of the underlying HTTP client by passing `ClientOption` structs to the `NewClient` function:
```go
cli, err := client.NewClient(cluster,
client.OptClientConnectTimeout(1000), // if can't connect in a second, close the connection
client.OptClientSocketTimeout(10000), // if no response received in 10 seconds, close the connection
client.OptClientPoolSizePerRoute(3), // number of connections in the pool per host
client.OptClientTotalPoolSize(10)) // number of total connections in the pool
```
Once you create a client, you can create indexes, fields or start sending queries.
Here is how you would create a index and field:
```go
// materialize repository index definition and stargazer field definition initialized before
err := cli.SyncSchema(schema)
```
You can send queries to a Pilosa server using the `Query` function of the `Client` struct:
```go
response, err := cli.Query(field.Row(5));
```
`Query` accepts zero or more options:
```go
response, err := cli.Query(field.Row(5), pilosa.ColumnAttrs(true), pilosa.ExcludeColumns(true))
```
## Server Response
When a query is sent to a Pilosa server, the server either fulfills the query or sends an error message. In the case of an error, a `pilosa.Error` struct is returned, otherwise a `QueryResponse` struct is returned.
A `QueryResponse` struct may contain zero or more results of `QueryResult` type. You can access all results using the `Results` function of `QueryResponse` (which returns a list of `QueryResult` objects), or you can use the `Result` method (which returns either the first result or `nil` if there are no results):
```go
response, err := cli.Query(field.Row(5))
if err != nil {
// Act on the error
}
// check that there's a result and act on it
result := response.Result()
if result != nil {
// Act on the result
}
// iterate over all results
for _, result := range response.Results() {
// Act on the result
}
```
Similarly, a `QueryResponse` struct may include a number of column attributes if `ColumnAttrs` query option was set to `true`:
```go
var column *pilosa.ColumnItem
// iterate over all columns
for _, column = range response.ColumnAttrs() {
// Act on the column item
}
```
`QueryResult` objects contain:
* `Row()` function to retrieve a row result,
* `CountItems()` function to retrieve column count per row ID entries returned from `TopN` queries,
* `Count()` function to retrieve the number of rows per the given row ID returned from `Count` queries.
* `Value()` function to retrieve the result of `Min`, `Max` or `Sum` queries.
* `Changed()` function returns whether a `Set` or `Clear` query changed a column.
```go
row := result.Row()
columns := row.Columns
attributes := row.Attributes
countItems := result.CountItems()
count := result.Count()
value := result.Value()
changed := result.Changed()
```
## SSL/TLS
Make sure the Pilosa server runs on a TLS address. [How To Set Up a Secure Cluster](https://www.pilosa.com/docs/latest/tutorials/#how-to-set-up-a-secure-cluster) tutorial explains how to do that.
In order to enable TLS support on the client side, the scheme of the address should be explicitly specified as `https`, e.g.: `https://01.pilosa.local:10501`
This client library uses the `net/http` module of Go standard library. You can pass a [tls.Config](https://golang.org/pkg/crypto/tls/#Config) struct in a `pilosa.TLSConfig` option to the client. If the Pilosa server is using a certificate from a recognized authority, you can use the defaults.
If you are using a self signed certificate, just pass `pilosa.TLSConfig(&tls.Config{InsecureSkipVerify: true})` to `pilosa.NewClient` function:
```go
client, _ := pilosa.NewClient("https://01.pilosa.local:10501", pilosa.TLSConfig(&tls.Config{InsecureSkipVerify: true}))
```

111
client/docs/tracing.md Normal file
View file

@ -0,0 +1,111 @@
# Tracing
Pilosa client supports distributed tracing via the [OpenTracing](https://opentracing.io/) API.
In order to use a tracer with Go-Pilosa, you should:
1. Create the tracer,
2. Pass the `OptClientOption(tracer)` to `NewClient`.
In this document, we will be using the [Jaeger](https://www.jaegertracing.io) tracer, but OpenTracing has support for [other tracing systems](https://opentracing.io/docs/supported-tracers/).
## Running the Pilosa Server
Let's run a temporary Pilosa container:
$ docker run -it --rm -p 10101:10101 pilosa/pilosa:v1.2.0
Check that you can access Pilosa:
$ curl localhost:10101
Welcome. Pilosa is running. Visit https://www.pilosa.com/docs/ for more information.
## Running the Jaeger Server
Let's run a Jaeger Server container:
$ docker run -it --rm -p 5775:5775/udp -p 16686:16686 jaegertracing/all-in-one:latest
...<title>Jaeger UI</title>...
## Writing the Sample Code
The sample code depdends on the Jaeger Go client, so let's install it first:
$ go get -u github.com/uber/jaeger-client-go/
Save the following sample code as `gopilosa-tracing.go`:
```go
package main
import (
"log"
"time"
"github.com/pilosa/pilosa/v2/client"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
)
func main() {
// Create the tracer.
cfg := config.Configuration{
Sampler: &config.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
BufferFlushInterval: 1 * time.Second,
// Jaeger Server address
LocalAgentHostPort: "127.0.0.1:5775",
},
}
tracer, closer, err := cfg.New(
"go_pilosa_test",
config.Logger(jaeger.StdLogger),
)
// Don't forget to close the tracer.
defer closer.Close()
// Create the client, and pass the tracer.
cli, err := client.NewClient(":10101", pilosa.OptClientTracer(tracer))
if err != nil {
log.Fatal(err)
}
// Read the schema from the server.
// This should create a trace on the Jaeger server.
schema, err := cli.Schema()
if err != nil {
log.Fatal(err)
}
// Create and sync the sample schema.
// This should create a trace on the Jaeger server.
myIndex := schema.Index("my-index")
myField := myIndex.Field("my-field")
err = cli.SyncSchema(schema)
if err != nil {
log.Fatal(err)
}
// Run a query on Pilosa.
// This should create a trace on the Jaeger server.
_, err = cli.Query(myField.Set(1, 1000))
if err != nil {
log.Fatal(err)
}
}
```
## Checking the Tracing Data
Run the sample code:
$ go run gopilosa-tracing.go
* Open http://localhost:16686 in your web browser to visit Jaeger UI.
* Click on the *Search* tab and select `go_pilosa_test` in the *Service* dropdown on the right.
* Click on *Find Traces* button at the bottom left.
* You should see a couple of traces, such as: `Client.Query`, `Client.CreateField`, `Client.Schema`, etc.

123
client/egpool/egpool.go Normal file
View file

@ -0,0 +1,123 @@
// Copyright 2017 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 egpool
import (
"errors"
"fmt"
"sync"
)
type Group struct {
PoolSize int
jobs chan func() error
sema chan struct{}
errMu sync.Mutex
firstErr error
errs []error
}
func (eg *Group) Go(f func() error) {
if eg.PoolSize <= 0 {
eg.PoolSize = 1
}
if eg.jobs == nil {
eg.jobs = make(chan func() error)
eg.sema = make(chan struct{}, eg.PoolSize)
}
// Start the job in an idle worker if possible.
select {
case eg.jobs <- f:
return
default:
}
// Start a new worker if necessary.
select {
case eg.jobs <- f:
// A worker finished its previous job and took this one over.
return
case eg.sema <- struct{}{}:
// Start a new worker.
go eg.processJobs()
eg.jobs <- f
}
}
func (eg *Group) err(err error) {
eg.errMu.Lock()
defer eg.errMu.Unlock()
if eg.firstErr == nil {
eg.firstErr = err
}
eg.errs = append(eg.errs, err)
}
type ErrPanic struct {
Value interface{}
}
func (p ErrPanic) Error() string {
return fmt.Sprintf("panic: %v", p.Value)
}
var ErrGoexit = errors.New("runtime.Goexit used in job function")
func (eg *Group) processJobs() {
// Notify pool of shutdown.
defer func() { <-eg.sema }()
// Handle panic and Goexit.
var finished bool
defer func() {
if !finished {
if p := recover(); p != nil {
eg.err(ErrPanic{p})
} else {
eg.err(ErrGoexit)
}
}
}()
// Run jobs from queue.
for jobFn := range eg.jobs {
err := jobFn()
if err != nil {
eg.err(err)
}
}
finished = true
}
func (eg *Group) Wait() error {
if eg.jobs == nil {
return nil
}
close(eg.jobs)
for i := 0; i < eg.PoolSize; i++ {
eg.sema <- struct{}{}
}
return eg.firstErr
}
func (eg *Group) Errors() []error {
return eg.errs
}

View file

@ -0,0 +1,50 @@
// Copyright 2017 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 egpool_test
import (
"errors"
"testing"
"github.com/pilosa/pilosa/v2/client/egpool"
)
func TestEGPool(t *testing.T) {
eg := egpool.Group{}
a := make([]int, 10)
for i := 0; i < 10; i++ {
i := i
eg.Go(func() error {
a[i] = i
if i == 7 {
return errors.New("blah")
}
return nil
})
}
err := eg.Wait()
if err == nil || err.Error() != "blah" {
t.Errorf("expected err blah, got: %v", err)
}
for i := 0; i < 10; i++ {
if a[i] != i {
t.Errorf("expected a[%d] to be %d, but is %d", i, i, a[i])
}
}
}

38
client/error.go Normal file
View file

@ -0,0 +1,38 @@
// Copyright 2017 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 client
import "github.com/pkg/errors"
// Predefined Pilosa errors.
var (
ErrEmptyCluster = errors.New("No usable addresses in the cluster")
ErrIndexExists = errors.New("Index exists")
ErrFieldExists = errors.New("Field exists")
ErrInvalidIndexName = errors.New("Invalid index name")
ErrInvalidFieldName = errors.New("Invalid field name")
ErrInvalidLabel = errors.New("Invalid label")
ErrInvalidKey = errors.New("Invalid key")
ErrTriedMaxHosts = errors.New("Tried max hosts, still failing")
ErrAddrURIClusterExpected = errors.New("Addresses, URIs or a cluster is expected")
ErrInvalidQueryOption = errors.New("Invalid query option")
ErrInvalidIndexOption = errors.New("Invalid index option")
ErrInvalidFieldOption = errors.New("Invalid field option")
ErrNoFragmentNodes = errors.New("No fragment nodes")
ErrNoShard = errors.New("Index has no shards")
ErrUnknownType = errors.New("Unknown type")
ErrSingleServerAddressRequired = errors.New("OptClientManualServerAddress requires a single URI or address")
ErrPreconditionFailed = errors.New("Precondition failed")
)

45
client/logimport.go Normal file
View file

@ -0,0 +1,45 @@
// Copyright 2017 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 client
import (
"encoding/gob"
"io"
)
type importLog struct {
Index string
Path string
Shard uint64
IsRoaring bool
Timestamp int64 // Unix Nanoseconds
Data []byte
}
type encoder interface {
Encode(thing interface{}) error
}
func newImportLogEncoder(w io.Writer) encoder {
return gob.NewEncoder(w)
}
type decoder interface {
Decode(thing interface{}) error
}
func newImportLogDecoder(r io.Reader) decoder {
return gob.NewDecoder(r)
}

155
client/logimport_test.go Normal file
View file

@ -0,0 +1,155 @@
// Copyright 2017 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 client
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"reflect"
"testing"
)
func TestEncodeDecode(t *testing.T) {
tests := []importLog{
{
Index: "go-testindex",
Path: "/index/go-testindex/field/importfield-batchsize/import?clear=false",
Shard: 0,
Data: make([]byte, 3918),
},
{
Index: "go-testindex",
Path: "/index/go-testindex/field/importfield-batchsize/import?clear=false",
Shard: 0,
Data: make([]byte, 3918),
},
{
Index: "eheh",
Path: "blah",
Shard: 9,
Data: []byte("something"),
},
{
Index: "",
Path: "",
Shard: 0,
Data: nil,
},
{
Index: "eheh",
Path: "blah",
Shard: 10,
Data: []byte("blahaslkdjfeoiwujf"),
},
{
Index: "eheh",
Path: "blah",
Shard: 10,
Data: make([]byte, 10000),
},
{
Index: "zoop",
Path: "blah",
Shard: 8923734,
Data: []byte("blahaslkdjfeoiwujf"),
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
nl := importLog{
Index: test.Index,
Path: test.Path,
Shard: test.Shard,
Data: make([]byte, len(test.Data)),
}
copy(nl.Data, test.Data)
buf := &bytes.Buffer{}
enc := newImportLogEncoder(buf)
err := enc.Encode(nl)
if err != nil {
t.Fatalf("writing to buf: %v", err)
}
dec := newImportLogDecoder(buf)
l2 := &importLog{}
err = dec.Decode(l2)
if err != nil {
t.Fatalf("reading from buf: %v", err)
}
if l2.Index != test.Index {
t.Errorf("indexes not equal:\n%s\n%s", test.Index, l2.Index)
}
if l2.Path != test.Path {
t.Errorf("paths not equal:\n%s\n%s", test.Path, l2.Path)
}
if l2.Shard != test.Shard {
t.Errorf("shards not equal exp: %d got %d", test.Shard, l2.Shard)
}
if !reflect.DeepEqual(test.Data, l2.Data) {
t.Errorf("data not equal \n%v\n%v", test.Data, l2.Data)
}
})
}
buf, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("getting temp file: %v", err)
}
enc := newImportLogEncoder(buf)
for _, test := range tests {
a := &test
err := enc.Encode(a)
if err != nil {
t.Errorf("encoding to buf: %v", err)
}
}
name := buf.Name()
err = buf.Close()
if err != nil {
t.Fatalf("closing temp file: %v", err)
}
buf, err = os.Open(name)
if err != nil {
t.Fatalf("reopening: %v", err)
}
dec := newImportLogDecoder(buf)
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
l := &importLog{}
err := dec.Decode(l)
// err := l.ReadFrom(buf)
if err != nil {
t.Errorf("reading from buf: %v", err)
}
if l.Index != test.Index {
t.Errorf("indexes not equal:\n%s\n%s", test.Index, l.Index)
}
if l.Path != test.Path {
t.Errorf("paths not equal:\n%s\n%s", test.Path, l.Path)
}
if l.Shard != test.Shard {
t.Errorf("shards not equal exp: %d got %d", test.Shard, l.Shard)
}
if !reflect.DeepEqual(test.Data, l.Data) {
t.Errorf("data not equal \n%v\n%v", test.Data, l.Data)
}
})
}
}

29
client/metrics.go Normal file
View file

@ -0,0 +1,29 @@
// Copyright 2017 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 client
const (
// MetricBatchImportDurationSeconds records the full time of the
// RecordBatch.Import call. This includes starting and finishing a
// transaction, doing key translation, building fragments locally,
// importing all data, and resetting internal structures.
MetricBatchImportDurationSeconds = "batch_import_duration_seconds"
// MetricBatchFlushDurationSeconds records the full time for
// RecordBatch.Flush (if splitBatchMode is in use). This includes
// starting and finishing a transaction, importing all data, and
// resetting internal structures.
MetricBatchFlushDurationSeconds = "batch_flush_duration_seconds"
)

1613
client/orm.go Normal file

File diff suppressed because it is too large Load diff

1242
client/orm_test.go Normal file

File diff suppressed because it is too large Load diff

75
client/record.go Normal file
View file

@ -0,0 +1,75 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
// Record is a Column or a FieldValue.
type Record interface {
Shard(shardWidth uint64) uint64
Less(other Record) bool
}
// RecordIterator is an iterator for a record.
type RecordIterator interface {
NextRecord() (Record, error)
}
// Column defines a single Pilosa column.
type Column struct {
RowID uint64
ColumnID uint64
RowKey string
ColumnKey string
Timestamp int64
}
// Shard returns the shard for this column.
func (b Column) Shard(shardWidth uint64) uint64 {
return b.ColumnID / shardWidth
}
// Less returns true if this column sorts before the given Record.
func (b Column) Less(other Record) bool {
if ob, ok := other.(Column); ok {
if b.RowID == ob.RowID {
return b.ColumnID < ob.ColumnID
}
return b.RowID < ob.RowID
}
return false
}
// FieldValue represents the value for a column within a
// range-encoded field.
type FieldValue struct {
ColumnID uint64
ColumnKey string
Value int64
}
// Shard returns the shard for this field value.
func (v FieldValue) Shard(shardWidth uint64) uint64 {
return v.ColumnID / shardWidth
}
// Less returns true if this field value sorts before the given Record.
func (v FieldValue) Less(other Record) bool {
if ov, ok := other.(FieldValue); ok {
return v.ColumnID < ov.ColumnID
}
return false
}

83
client/record_test.go Normal file
View file

@ -0,0 +1,83 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client_test
import (
"testing"
"github.com/pilosa/pilosa/v2/client"
)
func TestColumnShard(t *testing.T) {
a := client.Column{RowID: 15, ColumnID: 55, Timestamp: 100101}
target := uint64(0)
if a.Shard(100) != target {
t.Fatalf("shard %d != %d", target, a.Shard(100))
}
target = 5
if a.Shard(10) != target {
t.Fatalf("shard %d != %d", target, a.Shard(10))
}
}
func TestColumnLess(t *testing.T) {
a := client.Column{RowID: 10, ColumnID: 200}
a2 := client.Column{RowID: 10, ColumnID: 1000}
b := client.Column{RowID: 200, ColumnID: 10}
c := client.FieldValue{ColumnID: 1}
if !a.Less(a2) {
t.Fatalf("%v should be less than %v", a, a2)
}
if !a.Less(b) {
t.Fatalf("%v should be less than %v", a, b)
}
if b.Less(a) {
t.Fatalf("%v should not be less than %v", b, a)
}
if c.Less(a) {
t.Fatalf("%v should not be less than %v", c, a)
}
}
func TestFieldValueShard(t *testing.T) {
a := client.FieldValue{ColumnID: 55, Value: 125}
target := uint64(0)
if a.Shard(100) != target {
t.Fatalf("shard %d != %d", target, a.Shard(100))
}
target = 5
if a.Shard(10) != target {
t.Fatalf("shard %d != %d", target, a.Shard(10))
}
}
func TestFieldValueLess(t *testing.T) {
a := client.FieldValue{ColumnID: 55, Value: 125}
b := client.FieldValue{ColumnID: 100, Value: 125}
c := client.Column{ColumnID: 1, RowID: 2}
if !a.Less(b) {
t.Fatalf("%v should be less than %v", a, b)
}
if b.Less(a) {
t.Fatalf("%v should not be less than %v", b, a)
}
if c.Less(a) {
t.Fatalf("%v should not be less than %v", c, a)
}
}

595
client/response.go Normal file
View file

@ -0,0 +1,595 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"encoding/json"
"errors"
"fmt"
"github.com/pilosa/pilosa/v2/pb"
)
// QueryResponse types.
const (
QueryResultTypeNil uint32 = iota
QueryResultTypeRow
QueryResultTypePairs
QueryResultTypePairsField
QueryResultTypeValCount
QueryResultTypeUint64
QueryResultTypeBool
QueryResultTypeRowIDs // this is not used by the client
QueryResultTypeGroupCounts
QueryResultTypeRowIdentifiers
QueryResultTypePair
QueryResultTypePairField
QueryResultTypeSignedRow
)
// QueryResponse represents the response from a Pilosa query.
type QueryResponse struct {
ResultList []QueryResult `json:"results,omitempty"`
ColumnList []ColumnItem `json:"columns,omitempty"`
ErrorMessage string `json:"error-message,omitempty"`
Success bool `json:"success,omitempty"`
}
func newQueryResponseFromInternal(response *pb.QueryResponse) (*QueryResponse, error) {
if response.Err != "" {
return &QueryResponse{
ErrorMessage: response.Err,
Success: false,
}, nil
}
results := make([]QueryResult, 0, len(response.Results))
for _, r := range response.Results {
result, err := newQueryResultFromInternal(r)
if err != nil {
return nil, err
}
results = append(results, result)
}
columns := make([]ColumnItem, 0, len(response.ColumnAttrSets))
for _, p := range response.ColumnAttrSets {
columnItem, err := newColumnItemFromInternal(p)
if err != nil {
return nil, err
}
columns = append(columns, columnItem)
}
return &QueryResponse{
ResultList: results,
ColumnList: columns,
Success: true,
}, nil
}
// Results returns all results in the response.
func (qr *QueryResponse) Results() []QueryResult {
return qr.ResultList
}
// Result returns the first result or nil.
func (qr *QueryResponse) Result() QueryResult {
if len(qr.ResultList) == 0 {
return nil
}
return qr.ResultList[0]
}
// Columns returns all column attributes in the response.
// *DEPRECATED*
func (qr *QueryResponse) Columns() []ColumnItem {
return qr.ColumnList
}
// Column returns the attributes for first column.
// *DEPRECATED*
func (qr *QueryResponse) Column() ColumnItem {
if len(qr.ColumnList) == 0 {
return ColumnItem{}
}
return qr.ColumnList[0]
}
// ColumnAttrs returns all column attributes in the response.
func (qr *QueryResponse) ColumnAttrs() []ColumnItem {
return qr.ColumnList
}
// QueryResult represents one of the results in the response.
type QueryResult interface {
Type() uint32
Row() RowResult
CountItems() []CountResultItem
CountItem() CountResultItem
Count() int64
Value() int64
Changed() bool
GroupCounts() []GroupCount
RowIdentifiers() RowIdentifiersResult
}
func newQueryResultFromInternal(result *pb.QueryResult) (QueryResult, error) {
switch result.Type {
case QueryResultTypeNil:
return NilResult{}, nil
case QueryResultTypeRow:
return newRowResultFromInternal(result.Row)
case QueryResultTypePairs:
return countItemsFromInternal(result.Pairs), nil
case QueryResultTypePairsField:
return countItemsFromInternal(result.PairsField.Pairs), nil
case QueryResultTypeValCount:
return &ValCountResult{
Val: result.ValCount.Val,
Cnt: result.ValCount.Count,
}, nil
case QueryResultTypeUint64:
return IntResult(result.N), nil
case QueryResultTypeBool:
return BoolResult(result.Changed), nil
case QueryResultTypeRowIdentifiers:
return &RowIdentifiersResult{
IDs: result.RowIdentifiers.Rows,
Keys: result.RowIdentifiers.Keys,
}, nil
case QueryResultTypeGroupCounts:
return groupCountsFromInternal(result.GroupCounts), nil
case QueryResultTypePair:
return CountItem{CountResultItem: countItemFromInternal(result.Pairs[0])}, nil
case QueryResultTypePairField:
return CountItem{CountResultItem: countItemFromInternal(result.PairField.Pair)}, nil
}
return nil, ErrUnknownType
}
// CountResultItem represents a result from TopN call.
type CountResultItem struct {
ID uint64 `json:"id"`
Key string `json:"key,omitempty"`
Count uint64 `json:"count"`
}
func (c *CountResultItem) String() string {
if c.Key != "" {
return fmt.Sprintf("%s:%d", c.Key, c.Count)
}
return fmt.Sprintf("%d:%d", c.ID, c.Count)
}
type CountItem struct {
CountResultItem
}
// Type is the type of this result.
func (CountItem) Type() uint32 { return QueryResultTypePairField }
// Row returns a RowResult.
func (CountItem) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (t CountItem) CountItems() []CountResultItem { return []CountResultItem{t.CountResultItem} }
// CountItem returns a CountResultItem
func (t CountItem) CountItem() CountResultItem { return t.CountResultItem }
// Count returns the result of a Count call.
func (CountItem) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (CountItem) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (CountItem) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (CountItem) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (CountItem) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
func countItemFromInternal(item *pb.Pair) CountResultItem {
return CountResultItem{ID: item.ID, Key: item.Key, Count: item.Count}
}
func countItemsFromInternal(items []*pb.Pair) TopNResult {
result := make([]CountResultItem, 0, len(items))
for _, v := range items {
result = append(result, countItemFromInternal(v))
}
return TopNResult(result)
}
// TopNResult is returned from TopN call.
type TopNResult []CountResultItem
// Type is the type of this result.
func (TopNResult) Type() uint32 { return QueryResultTypePairsField }
// Row returns a RowResult.
func (TopNResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (t TopNResult) CountItems() []CountResultItem { return t }
// CountItem returns a CountResultItem
func (t TopNResult) CountItem() CountResultItem {
if len(t) >= 1 {
return t[0]
}
return CountResultItem{}
}
// Count returns the result of a Count call.
func (TopNResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (TopNResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (TopNResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (TopNResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (TopNResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// RowResult represents a result from Row, Union, Intersect, Difference and Range PQL calls.
type RowResult struct {
Attributes map[string]interface{} `json:"attrs"`
Columns []uint64 `json:"columns"`
Keys []string `json:"keys"`
}
func newRowResultFromInternal(row *pb.Row) (*RowResult, error) {
attrs, err := convertInternalAttrsToMap(row.Attrs)
if err != nil {
return nil, err
}
result := &RowResult{
Attributes: attrs,
Columns: row.Columns,
Keys: row.Keys,
}
return result, nil
}
// Type is the type of this result.
func (RowResult) Type() uint32 { return QueryResultTypeRow }
// Row returns a RowResult.
func (b RowResult) Row() RowResult { return b }
// CountItems returns a CountResultItem slice.
func (RowResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (RowResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (RowResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (RowResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (RowResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (RowResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (RowResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// MarshalJSON serializes this row result.
func (b RowResult) MarshalJSON() ([]byte, error) {
columns := b.Columns
if columns == nil {
columns = []uint64{}
}
keys := b.Keys
if keys == nil {
keys = []string{}
}
return json.Marshal(struct {
Attributes map[string]interface{} `json:"attrs"`
Columns []uint64 `json:"columns"`
Keys []string `json:"keys"`
}{
Attributes: b.Attributes,
Columns: columns,
Keys: keys,
})
}
// ValCountResult is returned from Min, Max and Sum calls.
type ValCountResult struct {
Val int64 `json:"val"`
Cnt int64 `json:"count"`
}
// Type is the type of this result.
func (ValCountResult) Type() uint32 { return QueryResultTypeValCount }
// Row returns a RowResult.
func (ValCountResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (ValCountResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (ValCountResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (c ValCountResult) Count() int64 { return c.Cnt }
// Value returns the result of a Min, Max or Sum call.
func (c ValCountResult) Value() int64 { return c.Val }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (ValCountResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (ValCountResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (ValCountResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// IntResult is returned from Count call.
type IntResult int64
// Type is the type of this result.
func (IntResult) Type() uint32 { return QueryResultTypeUint64 }
// Row returns a RowResult.
func (IntResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (IntResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (IntResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (i IntResult) Count() int64 { return int64(i) }
// Value returns the result of a Min, Max or Sum call.
func (IntResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (IntResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (IntResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (IntResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// BoolResult is returned from Set and Clear calls.
type BoolResult bool
// Type is the type of this result.
func (BoolResult) Type() uint32 { return QueryResultTypeBool }
// Row returns a RowResult.
func (BoolResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (BoolResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (BoolResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (BoolResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (BoolResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (b BoolResult) Changed() bool { return bool(b) }
// GroupCounts returns the result of a GroupBy call.
func (BoolResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (BoolResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// NilResult is returned from calls which don't return a value, such as SetRowAttrs.
type NilResult struct{}
// Type is the type of this result.
func (NilResult) Type() uint32 { return QueryResultTypeNil }
// Row returns a RowResult.
func (NilResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (NilResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (NilResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (NilResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (NilResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (NilResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (NilResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (NilResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// FieldRow represents a Group in a GroupBy call result.
type FieldRow struct {
FieldName string `json:"field"`
RowID uint64 `json:"rowID"`
RowKey string `json:"rowKey"`
Value *int64 `json:"value,omitempty"`
}
// GroupCount contains groups and their count in a GroupBy call result.
type GroupCount struct {
Groups []FieldRow `json:"groups"`
Count int64 `json:"count"`
Agg int64 `json:"agg"`
}
// GroupCountResult is returned from GroupBy call.
type GroupCountResult []GroupCount
// Type is the type of this result.
func (GroupCountResult) Type() uint32 { return QueryResultTypeGroupCounts }
// Row returns a RowResult.
func (GroupCountResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (GroupCountResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (GroupCountResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (GroupCountResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (GroupCountResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (GroupCountResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (r GroupCountResult) GroupCounts() []GroupCount { return r }
// RowIdentifiers returns the result of a Rows call.
func (GroupCountResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
// RowIdentifiersResult is returned from a Rows call.
type RowIdentifiersResult struct {
IDs []uint64 `json:"ids"`
Keys []string `json:"keys,omitempty"`
}
// Type is the type of this result.
func (RowIdentifiersResult) Type() uint32 { return QueryResultTypeRowIdentifiers }
// Row returns a RowResult.
func (RowIdentifiersResult) Row() RowResult { return RowResult{} }
// CountItems returns a CountResultItem slice.
func (RowIdentifiersResult) CountItems() []CountResultItem { return nil }
// CountItem returns a CountResultItem
func (RowIdentifiersResult) CountItem() CountResultItem { return CountResultItem{} }
// Count returns the result of a Count call.
func (RowIdentifiersResult) Count() int64 { return 0 }
// Value returns the result of a Min, Max or Sum call.
func (RowIdentifiersResult) Value() int64 { return 0 }
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
func (RowIdentifiersResult) Changed() bool { return false }
// GroupCounts returns the result of a GroupBy call.
func (RowIdentifiersResult) GroupCounts() []GroupCount { return nil }
// RowIdentifiers returns the result of a Rows call.
func (r RowIdentifiersResult) RowIdentifiers() RowIdentifiersResult { return r }
func groupCountsFromInternal(items *pb.GroupCounts) GroupCountResult {
result := make([]GroupCount, 0, len(items.Groups))
for _, g := range items.Groups {
groups := make([]FieldRow, 0, len(g.Group))
for _, f := range g.Group {
fr := FieldRow{
FieldName: f.Field,
RowID: f.RowID,
RowKey: f.RowKey,
}
if f.Value != nil {
fr.Value = &f.Value.Value
}
groups = append(groups, fr)
}
result = append(result, GroupCount{
Groups: groups,
Count: int64(g.Count),
Agg: int64(g.Agg),
})
}
return GroupCountResult(result)
}
const (
stringType = 1
intType = 2
boolType = 3
floatType = 4
)
func convertInternalAttrsToMap(attrs []*pb.Attr) (attrsMap map[string]interface{}, err error) {
attrsMap = make(map[string]interface{}, len(attrs))
for _, attr := range attrs {
switch attr.Type {
case stringType:
attrsMap[attr.Key] = attr.StringValue
case intType:
attrsMap[attr.Key] = attr.IntValue
case boolType:
attrsMap[attr.Key] = attr.BoolValue
case floatType:
attrsMap[attr.Key] = attr.FloatValue
default:
return nil, errors.New("Unknown attribute type")
}
}
return attrsMap, nil
}
// ColumnItem represents data about a column.
// Column data is only returned if QueryOptions.Columns was set to true.
type ColumnItem struct {
ID uint64 `json:"id,omitempty"`
Key string `json:"key,omitempty"`
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
func newColumnItemFromInternal(column *pb.ColumnAttrSet) (ColumnItem, error) {
attrs, err := convertInternalAttrsToMap(column.Attrs)
if err != nil {
return ColumnItem{}, err
}
return ColumnItem{
ID: column.ID,
Key: column.Key,
Attributes: attrs,
}, nil
}

348
client/response_test.go Normal file
View file

@ -0,0 +1,348 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"encoding/json"
"fmt"
"log"
"reflect"
"testing"
"github.com/pilosa/pilosa/v2/pb"
)
func TestNewRowResultFromInternal(t *testing.T) {
targetAttrs := map[string]interface{}{
"name": "some string",
"age": int64(95),
"registered": true,
"height": 1.83,
}
targetColumns := []uint64{5, 10}
attrs := []*pb.Attr{
{Key: "name", StringValue: "some string", Type: 1},
{Key: "age", IntValue: 95, Type: 2},
{Key: "registered", BoolValue: true, Type: 3},
{Key: "height", FloatValue: 1.83, Type: 4},
}
row := &pb.Row{
Attrs: attrs,
Columns: []uint64{5, 10},
}
result, err := newRowResultFromInternal(row)
if err != nil {
t.Fatalf("Failed with error: %s", err)
}
// assertMapEquals(t, targetAttrs, result.Attributes)
if !reflect.DeepEqual(targetAttrs, result.Attributes) {
t.Fatal()
}
if !reflect.DeepEqual(targetColumns, result.Columns) {
t.Fatal()
}
}
func TestNewQueryResponseFromInternal(t *testing.T) {
targetAttrs := map[string]interface{}{
"name": "some string",
"age": int64(95),
"registered": true,
"height": 1.83,
}
targetColumns := []uint64{5, 10}
targetCountItems := []CountResultItem{
{ID: 10, Count: 100},
}
attrs := []*pb.Attr{
{Key: "name", StringValue: "some string", Type: 1},
{Key: "age", IntValue: 95, Type: 2},
{Key: "registered", BoolValue: true, Type: 3},
{Key: "height", FloatValue: 1.83, Type: 4},
}
row := &pb.Row{
Attrs: attrs,
Columns: []uint64{5, 10},
}
pairs := []*pb.Pair{
{ID: 10, Count: 100},
}
response := &pb.QueryResponse{
Results: []*pb.QueryResult{
{Type: QueryResultTypeRow, Row: row},
{Type: QueryResultTypePairs, Pairs: pairs},
},
Err: "",
}
qr, err := newQueryResponseFromInternal(response)
if err != nil {
t.Fatalf("Failed with error: %s", err)
}
if qr.ErrorMessage != "" {
t.Fatalf("ErrorMessage should be empty")
}
if !qr.Success {
t.Fatalf("IsSuccess should be true")
}
results := qr.Results()
if len(results) != 2 {
t.Fatalf("Number of results should be 2")
}
if results[0] != qr.Result() {
t.Fatalf("Result() should return the first result")
}
if !reflect.DeepEqual(targetAttrs, results[0].Row().Attributes) {
t.Fatalf("The row result should contain the attributes")
}
if !reflect.DeepEqual(targetColumns, results[0].Row().Columns) {
t.Fatalf("The row result should contain the columns")
}
if !reflect.DeepEqual(targetCountItems, results[1].CountItems()) {
t.Fatalf("The response should include count items")
}
}
func TestNewQueryResponseWithErrorFromInternal(t *testing.T) {
response := &pb.QueryResponse{
Err: "some error",
}
qr, err := newQueryResponseFromInternal(response)
if err != nil {
t.Fatalf("Failed with error: %s", err)
}
if qr.ErrorMessage != "some error" {
t.Fatalf("The response should include the error message")
}
if qr.Success {
t.Fatalf("IsSuccess should be false")
}
if qr.Result() != nil {
t.Fatalf("If there are no results, Result should return nil")
}
}
func TestNewQueryResponseFromInternalFailure(t *testing.T) {
attrs := []*pb.Attr{
{Key: "name", StringValue: "some string", Type: 99},
}
row := &pb.Row{
Attrs: attrs,
}
response := &pb.QueryResponse{
Results: []*pb.QueryResult{{Type: QueryResultTypeRow, Row: row}},
}
qr, err := newQueryResponseFromInternal(response)
if qr != nil && err == nil {
t.Fatalf("Should have failed")
}
response = &pb.QueryResponse{
ColumnAttrSets: []*pb.ColumnAttrSet{{ID: 1, Attrs: attrs}},
}
qr, err = newQueryResponseFromInternal(response)
if qr != nil && err == nil {
t.Fatalf("Should have failed")
}
}
func TestCountResultItemToString(t *testing.T) {
tests := []struct {
item *CountResultItem
expected string
}{
{item: &CountResultItem{ID: 100, Count: 50}, expected: "100:50"},
{item: &CountResultItem{Key: "blah", Count: 50}, expected: "blah:50"},
{item: &CountResultItem{Key: "blah", ID: 22, Count: 50}, expected: "blah:50"},
{item: &CountResultItem{Key: "blah", ID: 22}, expected: "blah:0"},
{item: &CountResultItem{}, expected: "0:0"},
}
for i, tst := range tests {
t.Run(fmt.Sprintf("%d: ", i), func(t *testing.T) {
if tst.expected != tst.item.String() {
t.Fatalf("%s != %s", tst.expected, tst.item.String())
}
})
}
}
func TestMarshalResults(t *testing.T) {
attrs := []*pb.Attr{
{Key: "name", StringValue: "some string", Type: 1},
{Key: "age", IntValue: 95, Type: 2},
{Key: "registered", BoolValue: true, Type: 3},
{Key: "height", FloatValue: 1.83, Type: 4},
}
row := &pb.Row{
Attrs: attrs,
Columns: []uint64{5, 10},
}
pairs := []*pb.Pair{
{ID: 10, Count: 100},
}
pbufResults := []*pb.QueryResult{
{Type: QueryResultTypeRow, Row: row},
{Type: QueryResultTypePairs, Pairs: pairs},
}
resultJSONStrings := make([]string, len(pbufResults))
for i, pr := range pbufResults {
r, err := newQueryResultFromInternal(pr)
if err != nil {
t.Fatal(err)
}
b, err := json.Marshal(r)
if err != nil {
t.Fatal(err)
}
resultJSONStrings[i] = string(b)
}
targetJSON := []string{
`{"attrs":{"age":95,"height":1.83,"name":"some string","registered":true},"columns":[5,10],"keys":[]}`,
`[{"id":10,"count":100}]`,
}
for i := range targetJSON {
if sortedString(targetJSON[i]) != sortedString(resultJSONStrings[i]) {
t.Fatalf("%v != %v ", targetJSON[i], resultJSONStrings[i])
}
}
}
func TestUnknownQueryResultType(t *testing.T) {
result := &pb.QueryResult{
Type: 999,
}
_, err := newQueryResultFromInternal(result)
if err != ErrUnknownType {
t.Fatalf("Should have failed with ErrUnknownType")
}
}
func TestTopNResult(t *testing.T) {
result := TopNResult{
CountResultItem{ID: 100, Count: 10},
}
expectResult(t, result, QueryResultTypePairsField, RowResult{}, []CountResultItem{{100, "", 10}}, 0, 0, false, nil, RowIdentifiersResult{})
}
func TestRowResult(t *testing.T) {
result := RowResult{
Columns: []uint64{1, 2, 3},
}
targetBmp := RowResult{
Columns: []uint64{1, 2, 3},
}
expectResult(t, result, QueryResultTypeRow, targetBmp, nil, 0, 0, false, nil, RowIdentifiersResult{})
}
func TestRowResultNilColumns(t *testing.T) {
result := RowResult{
Columns: nil,
}
_, err := result.MarshalJSON()
if err != nil {
t.Fatal(err)
}
}
func TestSumCountResult(t *testing.T) {
result := ValCountResult{
Val: 100,
Cnt: 50,
}
expectResult(t, result, QueryResultTypeValCount, RowResult{}, nil, 100, 50, false, nil, RowIdentifiersResult{})
}
func TestIntResult(t *testing.T) {
result := IntResult(11)
expectResult(t, result, QueryResultTypeUint64, RowResult{}, nil, 0, 11, false, nil, RowIdentifiersResult{})
}
func TestBoolResult(t *testing.T) {
result := BoolResult(true)
expectResult(t, result, QueryResultTypeBool, RowResult{}, nil, 0, 0, true, nil, RowIdentifiersResult{})
}
func TestNilResult(t *testing.T) {
result := NilResult{}
expectResult(t, result, QueryResultTypeNil, RowResult{}, nil, 0, 0, false, nil, RowIdentifiersResult{})
}
func TestGroupCountResult(t *testing.T) {
result := GroupCountResult{
{Groups: []FieldRow{{FieldName: "f1", RowID: 1}}, Count: 2},
{Groups: []FieldRow{{FieldName: "f1", RowID: 2}}, Count: 1},
}
expectResult(t, result, QueryResultTypeGroupCounts, RowResult{}, nil, 0, 0, false, []GroupCount{
{Groups: []FieldRow{{FieldName: "f1", RowID: 1}}, Count: 2},
{Groups: []FieldRow{{FieldName: "f1", RowID: 2}}, Count: 1},
}, RowIdentifiersResult{})
}
func TestGroupCountWithValueResult(t *testing.T) {
var a, b int64 = -1, 1
result := GroupCountResult{
{Groups: []FieldRow{{FieldName: "f1", Value: &a}}, Count: 1},
{Groups: []FieldRow{{FieldName: "f1", Value: &b}}, Count: 1},
}
var aa, bb int64 = -1, 1
expectResult(t, result, QueryResultTypeGroupCounts, RowResult{}, nil, 0, 0, false, []GroupCount{
{Groups: []FieldRow{{FieldName: "f1", Value: &aa}}, Count: 1},
{Groups: []FieldRow{{FieldName: "f1", Value: &bb}}, Count: 1},
}, RowIdentifiersResult{})
}
func TestRowIdentifiersResult(t *testing.T) {
result := RowIdentifiersResult{
IDs: []uint64{1, 2, 3, 4},
}
expectResult(t, result, QueryResultTypeRowIdentifiers, RowResult{}, nil, 0, 0, false, nil, RowIdentifiersResult{
IDs: []uint64{1, 2, 3, 4},
})
}
func expectResult(t *testing.T, r QueryResult, resultType uint32, bmp RowResult,
countItems []CountResultItem, sum int64, count int64, changed bool,
groupCounts []GroupCount, rowIdentifiers RowIdentifiersResult) {
if resultType != r.Type() {
log.Fatalf("Result type: %d != %d", resultType, r.Type())
}
if !reflect.DeepEqual(bmp, r.Row()) {
log.Fatalf("Row: %v != %v", bmp, r.Row())
}
if !reflect.DeepEqual(countItems, r.CountItems()) {
log.Fatalf("Count items: %v != %v", countItems, r.CountItems())
}
if count != r.Count() {
log.Fatalf("Count: %d != %d", count, r.Count())
}
if sum != r.Value() {
log.Fatalf("Sum: %d != %d", sum, r.Value())
}
if changed != r.Changed() {
log.Fatalf("Changed: %v != %v", changed, r.Changed())
}
if !reflect.DeepEqual(groupCounts, r.GroupCounts()) {
log.Fatalf("Group counts: %v != %v", groupCounts, r.GroupCounts())
}
if !reflect.DeepEqual(rowIdentifiers, r.RowIdentifiers()) {
log.Fatalf("Row identifiers: %v != %v", rowIdentifiers, r.RowIdentifiers())
}
}

66
client/shardnodes.go Normal file
View file

@ -0,0 +1,66 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"sync"
pnet "github.com/pilosa/pilosa/v2/net"
)
type shardNodes struct {
data map[string]map[uint64][]*pnet.URI
mu *sync.RWMutex
}
func newShardNodes() shardNodes {
return shardNodes{
data: make(map[string]map[uint64][]*pnet.URI),
mu: &sync.RWMutex{},
}
}
func (s shardNodes) Get(index string, shard uint64) ([]*pnet.URI, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
if idx, ok := s.data[index]; ok {
if uris, ok := idx[shard]; ok {
return uris, true
}
}
return nil, false
}
func (s shardNodes) Put(index string, shard uint64, uris []*pnet.URI) {
s.mu.Lock()
defer s.mu.Unlock()
idx, ok := s.data[index]
if !ok {
idx = make(map[uint64][]*pnet.URI)
}
idx[shard] = uris
s.data[index] = idx
}
func (s shardNodes) Invalidate() {
s.mu.Lock()
defer s.mu.Unlock()
for k := range s.data {
delete(s.data, k)
}
}

89
client/tracer.go Normal file
View file

@ -0,0 +1,89 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/log"
)
type NoopTracer struct{}
type NoopSpan struct{}
func (s NoopSpan) Finish() {
// pass
}
func (s NoopSpan) FinishWithOptions(opts opentracing.FinishOptions) {
// pass
}
func (s NoopSpan) Context() opentracing.SpanContext {
return nil
}
func (s NoopSpan) SetOperationName(operationName string) opentracing.Span {
return s
}
func (s NoopSpan) SetTag(key string, value interface{}) opentracing.Span {
return s
}
func (s NoopSpan) LogFields(fields ...log.Field) {
// pass
}
func (s NoopSpan) LogKV(alternatingKeyValues ...interface{}) {
// pass
}
func (s NoopSpan) SetBaggageItem(restrictedKey, value string) opentracing.Span {
return s
}
func (s NoopSpan) BaggageItem(restrictedKey string) string {
return ""
}
func (s NoopSpan) Tracer() opentracing.Tracer {
return nil
}
func (s NoopSpan) LogEvent(event string) {
// pass
}
func (s NoopSpan) LogEventWithPayload(event string, payload interface{}) {
// pass
}
func (s NoopSpan) Log(data opentracing.LogData) {
// pass
}
func (t NoopTracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span {
return NoopSpan{}
}
func (t NoopTracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
return nil
}
func (t NoopTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
return nil, nil
}

54
client/validate.go Normal file
View file

@ -0,0 +1,54 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"regexp"
)
const (
maxLabel = 64
maxKey = 64
)
var labelRegex = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9_-]*$")
var keyRegex = regexp.MustCompile("^[A-Za-z0-9_{}+/=.~%:-]*$")
// ValidLabel returns true if the given label is valid, otherwise false.
func ValidLabel(label string) bool {
return len(label) <= maxLabel && labelRegex.Match([]byte(label))
}
// ValidKey returns true if the given key is valid, otherwise false.
func ValidKey(key string) bool {
return len(key) <= maxKey && keyRegex.Match([]byte(key))
}
func validateLabel(label string) error {
if ValidLabel(label) {
return nil
}
return ErrInvalidLabel
}
func validateKey(key string) error {
if ValidKey(key) {
return nil
}
return ErrInvalidKey
}

73
client/validate_test.go Normal file
View file

@ -0,0 +1,73 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import "testing"
func TestValidateLabel(t *testing.T) {
labels := []string{
"a", "ab", "ab1", "d_e", "A", "Bc", "B1", "aB", "b-c",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
for _, label := range labels {
if validateLabel(label) != nil {
t.Fatalf("Should be valid label: %s", label)
}
}
}
func TestValidateLabelInvalid(t *testing.T) {
labels := []string{
"", "1", "_", "-", "'", "^", "/", "\\", "*", "a:b", "valid?no", "yüce",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1",
}
for _, label := range labels {
if validateLabel(label) == nil {
t.Fatalf("Should be invalid label: %s", label)
}
}
}
func TestValidateKey(t *testing.T) {
keys := []string{
"", "1", "ab", "ab1", "b-c", "d_e", "pilosa.com",
"bbf8d41c-7dba-40c4-94dc-94677b43bcf3", // UUID
"{bbf8d41c-7dba-40c4-94dc-94677b43bcf3}", // Windows GUID
"https%3A//www.pilosa.com/about/%23contact", // escaped URL
"aHR0cHM6Ly93d3cucGlsb3NhLmNvbS9hYm91dC8jY29udGFjdA==", // base64
"urn:isbn:1234567",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
for _, key := range keys {
if validateKey(key) != nil {
t.Fatalf("Should be valid key: %s", key)
}
}
}
func TestValidateKeyInvalid(t *testing.T) {
keys := []string{
"\"", "'", "slice\\dice", "valid?no", "yüce", "*xyz", "with space", "<script>",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1",
}
for _, key := range keys {
if validateKey(key) == nil {
t.Fatalf("Should be invalid key: %s", key)
}
}
}

21
client/version.go Normal file
View file

@ -0,0 +1,21 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
// Version is the client version.
const Version = "v1.3.0"

View file

@ -29,6 +29,7 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/testhook"
"github.com/pilosa/pilosa/v2/topology"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// GlobalPortMap avoids many races and port conflicts when setting
@ -137,7 +138,7 @@ func newHolderWithTempPath(tb testing.TB, backend string) *Holder {
cfg := mustHolderConfig()
cfg.StorageConfig.Backend = backend
h := NewHolder(path, cfg)
panicOn(h.Open())
PanicOn(h.Open())
testhook.Cleanup(tb, func() {
h.Close()
})
@ -151,7 +152,7 @@ func newIndexWithTempPath(tb testing.TB, name string) *Index {
panic(err)
}
h := NewHolder(path, nil)
panicOn(h.Open())
PanicOn(h.Open())
index, err := h.CreateIndex(name, IndexOptions{})
testhook.Cleanup(tb, func() {
h.Close()
@ -232,7 +233,7 @@ func TestFragSources(t *testing.T) {
if err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
shard = 1
tx = idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Shard: shard})
@ -241,7 +242,7 @@ func TestFragSources(t *testing.T) {
if err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
shard = 2
tx = idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Shard: shard})
@ -251,7 +252,7 @@ func TestFragSources(t *testing.T) {
if err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
shard = 3
tx = idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Shard: shard})
@ -261,7 +262,7 @@ func TestFragSources(t *testing.T) {
if err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tests := []struct {
from *cluster

View file

@ -29,11 +29,9 @@ import (
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/http"
pnet "github.com/pilosa/pilosa/v2/net"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
//"log"
"os"
//"path/filepath"
//"sort"
"strconv"
"strings"
)
@ -62,13 +60,12 @@ func UploadTar(srcFile string, client *http.InternalClient) error {
lastIndex := ""
lastField := ""
lastShard := uint64(0)
//vv("top of tar loop")
n := 0
for {
header, err := tarReader.Next()
if err == io.EOF {
if header != nil {
panic("header should not be nil on err io.EOF")
PanicOn("header should not be nil on err io.EOF")
}
//submit any stuff we have left
if len(viewData) > 0 {
@ -76,18 +73,15 @@ func UploadTar(srcFile string, client *http.InternalClient) error {
Views: viewData,
}
// Submit(lastIndex, lastField, lastShard, request)
//vv("about to submit lastIndex='%v' lastShard='%v'", lastIndex, lastShard)
uri := GetImportRoaringURI(lastIndex, lastShard)
err := client.ImportRoaring(context.Background(), uri, lastIndex, lastField, lastShard, false, request)
panicOn(err)
//vv("done with submit lastIndex='%v' lastShard='%v'", lastIndex, lastShard)
PanicOn(err)
}
return nil
}
//vv("got header '%v'", header.Name)
n++
if n%500 == 0 {
vv("n = %v, progress, elapsed '%v'", n, time.Since(t0))
VV("n = %v, progress, elapsed '%v'", n, time.Since(t0))
}
parts := strings.Split(header.Name, "/")
//vv("parts = '%#v'", parts)
@ -106,7 +100,7 @@ func UploadTar(srcFile string, client *http.InternalClient) error {
}
//vv("about to submit lastIndex='%v' lastShard='%v'", lastIndex, lastShard)
uri := GetImportRoaringURI(lastIndex, lastShard)
panicOn(client.ImportRoaring(context.Background(), uri, lastIndex, lastField, lastShard, false, request))
PanicOn(client.ImportRoaring(context.Background(), uri, lastIndex, lastField, lastShard, false, request))
viewData = make(map[string][]byte)
//vv("done with submit lastIndex='%v' lastShard='%v'; took='%v'", lastIndex, lastShard, time.Since(t0))
@ -117,7 +111,7 @@ func UploadTar(srcFile string, client *http.InternalClient) error {
return err
}
if _, already := viewData[view]; already {
panic(fmt.Sprintf("view '%v' already present!", view))
PanicOn(fmt.Sprintf("view '%v' already present!", view))
}
viewData[view] = roaringData
lastIndex = index
@ -136,12 +130,12 @@ func main() {
host := "127.0.0.1:10101"
h := &gohttp.Client{}
c, err := http.NewInternalClient(host, h)
panicOn(err)
PanicOn(err)
tarSrcPath := "q2.tar.gz"
t0 := time.Now()
panicOn(UploadTar(tarSrcPath, c))
vv("total elapsed '%v'", time.Since(t0))
PanicOn(UploadTar(tarSrcPath, c))
VV("total elapsed '%v'", time.Since(t0))
}
var globURI *pnet.URI
@ -149,7 +143,7 @@ var globURI *pnet.URI
func init() {
var err error
globURI, err = pnet.NewURIFromHostPort("127.0.0.1", 10101)
panicOn(err)
PanicOn(err)
}
// get correct node to go to.

View file

@ -1,177 +0,0 @@
// home: https://github.com/glycerine/vprint
// Copyright 2019 Jason E. Aten, Ph.D. All rights reserved.
// License: MIT
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package main
import (
"fmt"
"io"
"os"
"path"
"runtime"
"runtime/debug"
"sync"
"time"
)
const RFC3339MsecTz0 = "2006-01-02T15:04:05.000Z07:00"
const RFC3339UsecTz0 = "2006-01-02T15:04:05.000000Z07:00"
// for tons of debug output
var VerboseVerbose bool = false
// convience functions for . import
var pp = PP
var vv = VV
var panicOn = PanicOn
func init() {
// keeper linter happy
_ = pp
_ = vv
}
func PanicOn(err error) {
if err != nil {
panic(err)
}
}
func PP(format string, a ...interface{}) {
if VerboseVerbose {
TSPrintf(format, a...)
}
}
func VV(format string, a ...interface{}) {
TSPrintf(format, a...)
}
func AlwaysPrintf(format string, a ...interface{}) {
TSPrintf(format, a...)
}
var tsPrintfMut sync.Mutex
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
tsPrintfMut.Lock()
Printf("\n%s %s ", FileLine(3), ts())
Printf(format+"\n", a...)
tsPrintfMut.Unlock()
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format(RFC3339UsecTz0)
}
// so we can multi write easily, use our own printf
var OurStdout io.Writer = os.Stdout
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(OurStdout, format, a...)
}
func FileLine(depth int) string {
_, fileName, fileLine, ok := runtime.Caller(depth)
var s string
if ok {
s = fmt.Sprintf("%s:%d", path.Base(fileName), fileLine)
} else {
s = ""
}
return s
}
func stack() string {
return string(debug.Stack())
}
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}
func FileSize(name string) (int64, error) {
fi, err := os.Stat(name)
if err != nil {
return -1, err
}
return fi.Size(), nil
}
// Caller returns the name of the calling function.
func Caller(upStack int) string {
// elide ourself and runtime.Callers
target := upStack + 2
pc := make([]uintptr, target+2)
n := runtime.Callers(0, pc)
f := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(pc[:n])
for i := 0; i <= target; i++ {
contender, more := frames.Next()
if i == target {
f = contender
}
if !more {
break
}
}
}
return f.Function
}
// happy linter:
var _ = DirExists
var _ = FileExists
var _ = Caller
var _ = stack
var _ = RFC3339MsecTz0
var _ = RFC3339UsecTz0
var _ = AlwaysPrintf
var _ = FileSize

View file

@ -29,6 +29,7 @@ import (
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/http"
"github.com/pilosa/pilosa/v2/pql"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// RandomQueryConfig
@ -210,7 +211,7 @@ NewSetup:
index := indexes[cfg.Rnd.Intn(len(indexes))]
pql, err := cfg.GenQuery(index)
panicOn(err)
PanicOn(err)
if cfg.Verbose {
fmt.Printf("pql = '%v'\n", pql)
@ -355,7 +356,7 @@ func (cfg *RandomQueryConfig) Setup(api API) (err error) {
pql := fmt.Sprintf("Rows(%v)", fld.Name)
res, err := api.Query(ctx, ii.Name, &pilosa.QueryRequest{Index: ii.Name, Query: pql})
panicOn(err)
PanicOn(err)
if cfg.VeryVerbose {
fmt.Printf("success on pql = '%v'; res='%v'\n", pql, res.Results[0])
}
@ -411,7 +412,7 @@ func (cfg *RandomQueryConfig) AddIntField(index, field string, min, max pql.Deci
cfg.IndexMap[index] = f
}
if min.Scale != scale || max.Scale != scale {
panic(fmt.Sprintf("scale error; min scale %d, max scale %d, field scale %d, assumed they'd be equal",
PanicOn(fmt.Sprintf("scale error; min scale %d, max scale %d, field scale %d, assumed they'd be equal",
min.Scale, max.Scale, scale))
}

View file

@ -25,6 +25,7 @@ import (
"github.com/pilosa/pilosa/v2/http"
"github.com/pilosa/pilosa/v2/server"
"github.com/pilosa/pilosa/v2/test"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func Test_RandomQuery(t *testing.T) {
@ -139,18 +140,18 @@ func Test_RandomQuery(t *testing.T) {
if err := nodes[0].API.Import(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
//qcx.Reset()
}
// end of setup.
panicOn(cfg.Setup(wrapApiToInternalClient(nodes[0].API)))
PanicOn(cfg.Setup(wrapApiToInternalClient(nodes[0].API)))
for j := 0; j < 4; j++ {
index := indexes[rand.Intn(len(indexes))]
pql, err := cfg.GenQuery(index)
panicOn(err)
PanicOn(err)
//vv("pql = '%v'", pql)

View file

@ -1,177 +0,0 @@
// home: https://github.com/glycerine/vprint
// Copyright 2019 Jason E. Aten, Ph.D. All rights reserved.
// License: MIT
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package main
import (
"fmt"
"io"
"os"
"path"
"runtime"
"runtime/debug"
"sync"
"time"
)
const RFC3339MsecTz0 = "2006-01-02T15:04:05.000Z07:00"
const RFC3339UsecTz0 = "2006-01-02T15:04:05.000000Z07:00"
// for tons of debug output
var VerboseVerbose bool = false
// convience functions for . import
var pp = PP
var vv = VV
var panicOn = PanicOn
func init() {
// keeper linter happy
_ = pp
_ = vv
}
func PanicOn(err error) {
if err != nil {
panic(err)
}
}
func PP(format string, a ...interface{}) {
if VerboseVerbose {
TSPrintf(format, a...)
}
}
func VV(format string, a ...interface{}) {
TSPrintf(format, a...)
}
func AlwaysPrintf(format string, a ...interface{}) {
TSPrintf(format, a...)
}
var tsPrintfMut sync.Mutex
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
tsPrintfMut.Lock()
Printf("# %s %s ", FileLine(3), ts())
Printf(format+"\n", a...)
tsPrintfMut.Unlock()
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format(RFC3339UsecTz0)
}
// so we can multi write easily, use our own printf
var OurStdout io.Writer = os.Stdout
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(OurStdout, format, a...)
}
func FileLine(depth int) string {
_, fileName, fileLine, ok := runtime.Caller(depth)
var s string
if ok {
s = fmt.Sprintf("%s:%d", path.Base(fileName), fileLine)
} else {
s = ""
}
return s
}
func stack() string {
return string(debug.Stack())
}
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}
func FileSize(name string) int64 {
fi, err := os.Stat(name)
if err != nil {
return 0
}
return fi.Size()
}
// Caller returns the name of the calling function.
func Caller(upStack int) string {
// elide ourself and runtime.Callers
target := upStack + 2
pc := make([]uintptr, target+2)
n := runtime.Callers(0, pc)
f := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(pc[:n])
for i := 0; i <= target; i++ {
contender, more := frames.Next()
if i == target {
f = contender
}
if !more {
break
}
}
}
return f.Function
}
// happy linter:
var _ = DirExists
var _ = FileExists
var _ = Caller
var _ = stack
var _ = RFC3339MsecTz0
var _ = RFC3339UsecTz0
var _ = AlwaysPrintf
var _ = FileSize

View file

@ -33,6 +33,7 @@ import (
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/http"
pnet "github.com/pilosa/pilosa/v2/net"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// slurp: slurp is a load-tester for importing bulk data.
@ -59,7 +60,7 @@ func (r *stateMachine) NewHeader(h *tar.Header, tr *tar.Reader) error {
field := parts[2]
view := parts[4]
shard, err := strconv.ParseUint(parts[6], 10, 64)
panicOn(err)
PanicOn(err)
if index != r.lastIndex || field != r.lastField || shard != r.lastShard {
err := r.Upload()
if err != nil {
@ -83,7 +84,7 @@ func (r *stateMachine) NewHeader(h *tar.Header, tr *tar.Reader) error {
if err != nil {
return err
}
vv("Finished import %v", time.Since(r.start))
VV("Finished import %v", time.Since(r.start))
if r.profile != "" {
stopProfile(r.host, r.profile)
@ -103,21 +104,21 @@ func (r *stateMachine) NewHeader(h *tar.Header, tr *tar.Reader) error {
}
byteData, err := ioutil.ReadAll(tr)
panicOn(err)
PanicOn(err)
br := bytes.NewReader(byteData)
err = r.client.ImportFieldKeys(context.Background(), uri, index, fieldName, false, br)
if err != nil {
return err
}
default:
pilosa.VV("%v", h.Name)
VV("%v", h.Name)
index := parts[1]
partition, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return err
}
byteData, err := ioutil.ReadAll(tr)
panicOn(err)
PanicOn(err)
br := bytes.NewReader(byteData)
err = r.client.ImportIndexKeys(context.Background(), uri, index, int(partition), false, br)
@ -175,10 +176,10 @@ func UploadTar(srcFile string, client *http.InternalClient, profile, host string
break
}
if err != nil {
panicOn(err)
PanicOn(err)
}
err = runner.NewHeader(header, tarReader)
panicOn(err)
PanicOn(err)
}
return nil
}
@ -193,7 +194,7 @@ func main() {
flag.Parse()
uri, err := pnet.NewURIFromAddress(host)
panicOn(err)
PanicOn(err)
globURI = uri
h := &gohttp.Client{}
@ -201,12 +202,12 @@ func main() {
startProfile(host)
}
c, err := http.NewInternalClient(host, h)
panicOn(err)
PanicOn(err)
t0 := time.Now()
println("uploading", tarSrcPath)
panicOn(UploadTar(tarSrcPath, c, profile, host))
vv("total elapsed '%v'", time.Since(t0))
PanicOn(UploadTar(tarSrcPath, c, profile, host))
VV("total elapsed '%v'", time.Since(t0))
}
func startProfile(host string) {
@ -247,10 +248,10 @@ func stopProfile(host, outfile string) {
}
fd, err := os.Create(outfile)
panicOn(err)
PanicOn(err)
defer fd.Close()
_, err = io.Copy(fd, resp.Body)
panicOn(err)
PanicOn(err)
}

View file

@ -1,177 +0,0 @@
// home: https://github.com/glycerine/vprint
// Copyright 2019 Jason E. Aten, Ph.D. All rights reserved.
// License: MIT
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package main
import (
"fmt"
"io"
"os"
"path"
"runtime"
"runtime/debug"
"sync"
"time"
)
const RFC3339MsecTz0 = "2006-01-02T15:04:05.000Z07:00"
const RFC3339UsecTz0 = "2006-01-02T15:04:05.000000Z07:00"
// for tons of debug output
var VerboseVerbose bool = false
// convience functions for . import
var pp = PP
var vv = VV
var panicOn = PanicOn
func init() {
// keeper linter happy
_ = pp
_ = vv
}
func PanicOn(err error) {
if err != nil {
panic(err)
}
}
func PP(format string, a ...interface{}) {
if VerboseVerbose {
TSPrintf(format, a...)
}
}
func VV(format string, a ...interface{}) {
TSPrintf(format, a...)
}
func AlwaysPrintf(format string, a ...interface{}) {
TSPrintf(format, a...)
}
var tsPrintfMut sync.Mutex
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
tsPrintfMut.Lock()
Printf("\n%s %s ", FileLine(3), ts())
Printf(format+"\n", a...)
tsPrintfMut.Unlock()
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format(RFC3339UsecTz0)
}
// so we can multi write easily, use our own printf
var OurStdout io.Writer = os.Stdout
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(OurStdout, format, a...)
}
func FileLine(depth int) string {
_, fileName, fileLine, ok := runtime.Caller(depth)
var s string
if ok {
s = fmt.Sprintf("%s:%d", path.Base(fileName), fileLine)
} else {
s = ""
}
return s
}
func stack() string {
return string(debug.Stack())
}
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}
func FileSize(name string) (int64, error) {
fi, err := os.Stat(name)
if err != nil {
return -1, err
}
return fi.Size(), nil
}
// Caller returns the name of the calling function.
func Caller(upStack int) string {
// elide ourself and runtime.Callers
target := upStack + 2
pc := make([]uintptr, target+2)
n := runtime.Callers(0, pc)
f := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(pc[:n])
for i := 0; i <= target; i++ {
contender, more := frames.Next()
if i == target {
f = contender
}
if !more {
break
}
}
}
return f.Function
}
// happy linter:
var _ = DirExists
var _ = FileExists
var _ = Caller
var _ = stack
var _ = RFC3339MsecTz0
var _ = RFC3339UsecTz0
var _ = AlwaysPrintf
var _ = FileSize

View file

@ -270,7 +270,7 @@ func TestImportCommand_KeyReplication(t *testing.T) {
}
ctx := context.Background()
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
cmd0 := c.GetNode(0)
cmd1 := c.GetNode(1)

View file

@ -32,7 +32,7 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/internal"
"github.com/pilosa/pilosa/v2/pb"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pkg/errors"
)
@ -234,7 +234,7 @@ func (cmd *InspectCommand) Run(ctx context.Context) error {
}
// loadTopology is copied almost exactly from pilosa/cluster.go.
func loadTopology(path string) (topology internal.Topology, myID string, err error) {
func loadTopology(path string) (topology pb.Topology, myID string, err error) {
buf, err := ioutil.ReadFile(filepath.Join(path, ".topology"))
if os.IsNotExist(err) {
return topology, myID, err

View file

@ -56,14 +56,14 @@ func BuildServerFlags(cmd *cobra.Command, srv *server.Command) {
flags.IntVar(&srv.Config.Translation.MapSize, "translation.map-size", srv.Config.Translation.MapSize, "Size in bytes of mmap to allocate for key translation.")
// Etcd
// Etcd.Name used Config.Name for it's value.
// Etcd.Name used Config.Name for its value.
// Etcd.Dir defaults to a directory under the pilosa data directory.
// Etcd.ClusterName uses Cluster.Name for its value
flags.StringVar(&srv.Config.Etcd.LClientURL, "etcd.listen-client-address", srv.Config.Etcd.LClientURL, "Listen client address.")
flags.StringVar(&srv.Config.Etcd.AClientURL, "etcd.advertise-client-address", srv.Config.Etcd.AClientURL, "Advertise client address. If not provided, uses the listen client address.")
flags.StringVar(&srv.Config.Etcd.LPeerURL, "etcd.listen-peer-address", srv.Config.Etcd.LPeerURL, "Listen peer address.")
flags.StringVar(&srv.Config.Etcd.APeerURL, "etcd.advertise-peer-address", srv.Config.Etcd.APeerURL, "Advertise peer address. If not provided, uses the listen peer address.")
flags.StringVar(&srv.Config.Etcd.ClusterURL, "etcd.cluster-url", srv.Config.Etcd.ClusterURL, "Cluster URL to join.")
// Etcd.ClusterName uses Cluster.Name for its value.
flags.StringVar(&srv.Config.Etcd.InitCluster, "etcd.initial-cluster", srv.Config.Etcd.InitCluster, "Initial cluster name1=apurl1,name2=apurl2")
// AntiEntropy

View file

@ -26,9 +26,9 @@ import (
rbfcfg "github.com/pilosa/pilosa/v2/rbf/cfg"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
"github.com/pilosa/pilosa/v2/storage"
//txkey "github.com/pilosa/pilosa/v2/txkey"
"github.com/pkg/errors"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
var _ = sort.Sort
@ -176,10 +176,10 @@ func (dbs *DBShard) NewTx(write bool, initialIndexName string, o Txo) (tx Tx, er
}
}
if o.dbs != dbs {
panic(fmt.Sprintf("TxFactory.NewTx() should have set o.dbs(%p) to equal dbs(%p)", o.dbs, dbs))
PanicOn(fmt.Sprintf("TxFactory.NewTx() should have set o.dbs(%p) to equal dbs(%p)", o.dbs, dbs))
}
if o.Shard != dbs.Shard {
panic(fmt.Sprintf("shard disagreement! o.Shard='%v' but dbs.Shard='%v'", int(o.Shard), int(dbs.Shard)))
PanicOn(fmt.Sprintf("shard disagreement! o.Shard='%v' but dbs.Shard='%v'", int(o.Shard), int(dbs.Shard)))
}
var txns []Tx
@ -413,7 +413,7 @@ func (per *DBPerShard) LoadExistingDBs() (err error) {
func (txf *TxFactory) NewDBPerShard(types []txtype, holderDir string, holder *Holder) (d *DBPerShard) {
if holder.cfg == nil || holder.cfg.RBFConfig == nil || holder.cfg.StorageConfig == nil {
panic("must have holder.cfg.RBFConfig and holder.cfg.StorageConfig set here")
PanicOn("must have holder.cfg.RBFConfig and holder.cfg.StorageConfig set here")
}
useOpenList := 0
@ -522,7 +522,7 @@ func (dbs *DBShard) DumpAll() {
for i, ty := range dbs.types {
_ = i
tx, err := dbs.W[i].NewTx(!writable, "", Txo{Index: dbs.idx})
panicOn(err)
PanicOn(err)
defer tx.Rollback()
fmt.Printf("\n============= dumping dbs.W[%v] %v ========\n", i, ty)
tx.Dump(short, dbs.Shard)
@ -532,7 +532,7 @@ func (dbs *DBShard) DumpAll() {
case rbfTxn:
case boltTxn:
default:
panic(fmt.Sprintf("unknown txtyp: '%v'", ty))
PanicOn(fmt.Sprintf("unknown txtyp: '%v'", ty))
}
}
fmt.Printf("\n============= end of DumpAll index='%v', shard=%v ========\n", dbs.Index, int(dbs.Shard))
@ -627,7 +627,7 @@ func (per *DBPerShard) unprotectedGetDBShard(index string, shard uint64, idx *In
if len(per.types) == 1 && per.types[0] == roaringTxn {
// roaring txn are nil/fake anyway. Don't freak out.
} else {
panic(fmt.Sprintf("cannot retain closed dbs across holder ReOpen dbs='%p'; per.types[0]='%v'; len(per.types)=%v", dbs, per.types[0], len(per.types)))
PanicOn(fmt.Sprintf("cannot retain closed dbs across holder ReOpen dbs='%p'; per.types[0]='%v'; len(per.types)=%v", dbs, per.types[0], len(per.types)))
}
}
if !ok {
@ -663,11 +663,11 @@ func (per *DBPerShard) unprotectedGetDBShard(index string, shard uint64, idx *In
case boltTxn:
registry = globalBoltReg
default:
panic(fmt.Sprintf("unknown txtyp: '%v'", ty))
PanicOn(fmt.Sprintf("unknown txtyp: '%v'", ty))
}
path := dbs.pathForType(ty)
w, err := registry.OpenDBWrapper(path, DetectMemAccessPastTx, per.StorageConfig)
panicOn(err)
PanicOn(err)
h := idx.Holder()
w.SetHolder(h)
dbs.Open = true
@ -688,7 +688,7 @@ func (per *DBPerShard) Del(dbs *DBShard) (err error) {
if err != nil {
return
}
panicOn(dbs.DeleteDBPath())
PanicOn(dbs.DeleteDBPath())
delete(per.Flatmap, flatkey{index: dbs.Index, shard: dbs.Shard})
// delete from the heirarchy
@ -703,7 +703,7 @@ func (per *DBPerShard) Close() (err error) {
for _, dbi := range per.dbh.Index {
for _, dbs := range dbi.Shard {
err = dbs.Close()
panicOn(err)
PanicOn(err)
}
}
return
@ -716,7 +716,7 @@ func (f *TxFactory) GetShardsForIndex(idx *Index, roaringViewPath string, requir
n := len(f.types)
if n != 1 && n != 2 {
panic(fmt.Sprintf("internal error. only green or blue/green supported. we see types len %v", n))
PanicOn(fmt.Sprintf("internal error. only green or blue/green supported. we see types len %v", n))
}
var shards []map[uint64]bool
@ -810,7 +810,7 @@ func (per *DBPerShard) TypedDBPerShardGetShardsForIndex(ty txtype, idx *Index, r
ignoreEmpty := false
includeRoot := true
dbf, err := listDirUnderDir(path, includeRoot, ignoreEmpty)
panicOn(err)
PanicOn(err)
for _, nm := range dbf {
base := filepath.Base(nm)
@ -825,7 +825,7 @@ func (per *DBPerShard) TypedDBPerShardGetShardsForIndex(ty txtype, idx *Index, r
// Parse filename into integer.
shard, err := strconv.ParseUint(base[lenOfShardPrefix:], 10, 64)
if err != nil {
panicOn(err)
PanicOn(err)
continue
}
@ -938,7 +938,7 @@ func (dbs *DBShard) populateBlueFromGreen() (err error) {
n := len(dbs.W)
if n != 2 {
panic(fmt.Sprintf("populateBlueFromGreen did not find 2 open DBs: have %v", n))
PanicOn(fmt.Sprintf("populateBlueFromGreen did not find 2 open DBs: have %v", n))
}
dest := dbs.W[0] // blue
@ -948,11 +948,11 @@ func (dbs *DBShard) populateBlueFromGreen() (err error) {
// Since a shard is fairly small, we think one Tx will suffice.
readtx, err := src.NewTx(!writable, dbs.Index, Txo{Write: !writable, Index: dbs.idx, Shard: dbs.Shard})
panicOn(err)
PanicOn(err)
defer readtx.Rollback()
writetx, err := dest.NewTx(writable, dbs.Index, Txo{Write: writable, Index: dbs.idx, Shard: dbs.Shard})
panicOn(err)
PanicOn(err)
defer writetx.Rollback()
ctWriteCount := 0
@ -1024,18 +1024,18 @@ func (dbs *DBShard) verifyBlueEqualsGreen() (err error) {
n := len(dbs.W)
if n != 2 {
panic(fmt.Sprintf("verifyBlueEqualsGreen did not find 2 open DBs: have %v", n))
PanicOn(fmt.Sprintf("verifyBlueEqualsGreen did not find 2 open DBs: have %v", n))
}
blue := dbs.W[0]
green := dbs.W[1]
greentx, err := green.NewTx(!writable, dbs.Index, Txo{Write: !writable, Index: dbs.idx, Shard: dbs.Shard})
panicOn(err)
PanicOn(err)
defer greentx.Rollback()
bluetx, err := blue.NewTx(!writable, dbs.Index, Txo{Write: !writable, Index: dbs.idx, Shard: dbs.Shard})
panicOn(err)
PanicOn(err)
defer bluetx.Rollback()
for _, fld := range dbs.idx.Fields() {

View file

@ -25,6 +25,7 @@ import (
"github.com/pilosa/pilosa/v2/shardwidth"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// Shard per db evaluation
@ -51,7 +52,7 @@ func TestShardPerDB_SetBit(t *testing.T) {
}
// commit the change, and verify it is still there
panicOn(tx.Commit())
PanicOn(tx.Commit())
// Close and reopen the fragment & verify the data.
err := f.Reopen() // roaring data not being flushed? red on roaring
@ -71,7 +72,7 @@ func TestShardPerDB_SetBit(t *testing.T) {
// test that we find all *local* shards
func Test_DBPerShard_GetShardsForIndex_LocalOnly(t *testing.T) {
tmpdir, err := testhook.TempDir(t, "Test_DBPerShard_GetShardsForIndex_LocalOnly")
panicOn(err)
PanicOn(err)
defer os.RemoveAll(tmpdir)
v2s := NewFieldView2Shards()
@ -92,13 +93,13 @@ func Test_DBPerShard_GetShardsForIndex_LocalOnly(t *testing.T) {
idx := makeSampleRoaringDir(t, tmpdir, index, src, 1, holder, v2s)
if idx == nil {
idx, err = NewIndex(holder, filepath.Join(tmpdir, index), index)
panicOn(err)
PanicOn(err)
}
estd := "rick/fields/_exists/views/standard"
std := "rick/fields/f/views/standard"
shards, err := holder.txf.GetShardsForIndex(idx, tmpdir+sep+std, false)
panicOn(err)
PanicOn(err)
for _, shard := range []uint64{93, 223, 221, 215, 219, 217} {
if !shards[shard] {
@ -108,7 +109,7 @@ func Test_DBPerShard_GetShardsForIndex_LocalOnly(t *testing.T) {
if src == "roaring" {
// check estd too
shards, err = holder.txf.GetShardsForIndex(idx, tmpdir+sep+estd, false)
panicOn(err)
PanicOn(err)
for _, shard := range []uint64{93, 223, 221, 215, 219, 217} {
if !shards[shard] {
panic(fmt.Sprintf("missing shard=%v from shards='%#v'", shard, shards))
@ -117,12 +118,12 @@ func Test_DBPerShard_GetShardsForIndex_LocalOnly(t *testing.T) {
// check GetSortedFieldViewList() and roaringGetFieldView2Shards()
vs, err := roaringGetFieldView2Shards(idx)
panicOn(err)
PanicOn(err)
for _, shard := range []uint64{93, 223, 221, 215, 219, 217} {
tx := idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Shard: shard})
fvs, err := tx.GetSortedFieldViewList(idx, shard)
panicOn(err)
PanicOn(err)
// expect these same two field/views for all 6 shards
expect0 := txkey.FieldView{Field: "_exists", View: "standard"}
expect1 := txkey.FieldView{Field: "f", View: "standard"}
@ -149,7 +150,7 @@ func Test_DBPerShard_GetShardsForIndex_LocalOnly(t *testing.T) {
for _, shard := range []uint64{93, 223, 221, 215, 219, 217} {
tx := idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Shard: shard})
fvs, err := tx.GetSortedFieldViewList(idx, shard)
panicOn(err)
PanicOn(err)
// expect these same two field/views for all 6 shards
expect0 := txkey.FieldView{Field: "_exists", View: "standard"}
expect1 := txkey.FieldView{Field: "f", View: "standard"}
@ -242,12 +243,12 @@ func makeSampleRoaringDir(t *testing.T, root, index, backend string, minBytes in
}
path := root + sep + filepath.Dir(fn)
panicOn(os.MkdirAll(path, 0755))
PanicOn(os.MkdirAll(path, 0755))
fd, err := os.Create(root + sep + fn)
panicOn(err)
PanicOn(err)
if minBytes > 0 {
_, err := fd.Write(make([]byte, minBytes))
panicOn(err)
PanicOn(err)
}
fd.Close()
}
@ -256,10 +257,10 @@ func makeSampleRoaringDir(t *testing.T, root, index, backend string, minBytes in
func helperCreateDBShard(h *Holder, index string, shard uint64) *Index {
idx, err := h.CreateIndexIfNotExists(index, IndexOptions{})
panicOn(err)
PanicOn(err)
// TODO: It's not clear that this is actually doing anything.
dbs, err := h.txf.dbPerShard.GetDBShard(index, shard, idx)
panicOn(err)
PanicOn(err)
_ = dbs
return idx
}
@ -280,20 +281,20 @@ func makeRBFtestDB(path string, h *Holder, shard uint64) {
db := rbf.NewDB(path, nil)
err := db.Open()
panicOn(err)
PanicOn(err)
defer db.Close()
tx, err := db.Begin(true)
panicOn(err)
PanicOn(err)
err = tx.CreateBitmap("x")
panicOn(err)
PanicOn(err)
_, err = tx.Add("x", i)
panicOn(err)
PanicOn(err)
err = tx.Commit()
panicOn(err)
PanicOn(err)
}
func makeTxTestDBWithViewsShards(holder *Holder, idx *Index, exp *FieldView2Shards) {
@ -310,12 +311,12 @@ func makeTxTestDBWithViewsShards(holder *Holder, idx *Index, exp *FieldView2Shar
bits := []uint64{(shard << shardwidth.Exponent) + 1}
tx := idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Shard: shard})
changeCount, err := tx.Add(idx.name, field, view, shard, batched, bits...)
panicOn(err)
PanicOn(err)
if changeCount != len(bits) {
panic(fmt.Sprintf("writing field '%v', view '%v' shard '%v', expected changeCount to equal len bits = %v but was %v", field, view, shard, len(bits), changeCount))
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
}
}
}
@ -325,7 +326,7 @@ func makeTxTestDBWithViewsShards(holder *Holder, idx *Index, exp *FieldView2Shar
// test that rbf can give us a map[view]*shardSet
func Test_DBPerShard_GetFieldView2Shards_map_from_RBF(t *testing.T) {
tmpdir, err := testhook.TempDir(t, "Test_DBPerShard_GetFieldView2Shards_map_from_RBF")
panicOn(err)
PanicOn(err)
defer os.RemoveAll(tmpdir)
cfg := mustHolderConfig()
@ -343,7 +344,7 @@ func Test_DBPerShard_GetFieldView2Shards_map_from_RBF(t *testing.T) {
}
idx, err := holder.createIndex(cim, false)
panicOn(err)
PanicOn(err)
exp := NewFieldView2Shards()
@ -360,7 +361,7 @@ func Test_DBPerShard_GetFieldView2Shards_map_from_RBF(t *testing.T) {
// setup is done
view2shard, err := holder.txf.GetFieldView2ShardsMapForIndex(idx)
panicOn(err)
PanicOn(err)
// compare against setup
if !view2shard.equals(exp) {

View file

@ -25,6 +25,7 @@ import (
"github.com/pilosa/pilosa/v2/http"
"github.com/pilosa/pilosa/v2/server"
"github.com/pilosa/pilosa/v2/test"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func TestAPI_SimplerOneNode_ImportColumnKey(t *testing.T) {
@ -94,7 +95,7 @@ func TestAPI_SimplerOneNode_ImportColumnKey(t *testing.T) {
if err := m0.API.Import(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
//select {}

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,7 @@ import (
"go.etcd.io/etcd/embed"
"go.etcd.io/etcd/etcdserver/api/v3client"
"go.etcd.io/etcd/mvcc/mvccpb"
"go.etcd.io/etcd/pkg/transport"
"go.etcd.io/etcd/pkg/types"
)
@ -48,6 +49,12 @@ type Options struct {
InitCluster string `toml:"initial-cluster"`
ClusterName string `toml:"cluster-name"`
HeartbeatTTL int64 `toml:"heartbeat-ttl"`
// TLS provided tls files
TrustedCAFile string `toml:"tls-trusted-cafile"`
ClientCertFile string `toml:"tls-cert-file"`
ClientKeyFile string `toml:"tls-key-file"`
PeerCertFile string `toml:"tls-peer-cert-file"`
PeerKeyFile string `toml:"tls-peer-key-file"`
LPeerSocket []*net.TCPListener
LClientSocket []*net.TCPListener
@ -171,6 +178,17 @@ func parseOptions(opt Options) *embed.Config {
id, name := memberAdd(cli, opt.APeerURL)
log.Printf("\tid: %d, name: %s\n", id, name)
}
// can only use tls if not using pre-configured listeners
cfg.ClientTLSInfo = transport.TLSInfo{
TrustedCAFile: opt.TrustedCAFile,
CertFile: opt.ClientCertFile,
KeyFile: opt.ClientKeyFile,
}
cfg.PeerTLSInfo = transport.TLSInfo{
TrustedCAFile: opt.TrustedCAFile,
CertFile: opt.PeerCertFile,
KeyFile: opt.PeerKeyFile,
}
return cfg
}

View file

@ -66,6 +66,11 @@ func (l *leasedKV) Start(initValue string) error {
func (l *leasedKV) create(initValue string) (<-chan *clientv3.LeaseKeepAliveResponse, error) {
ctx, cancel := context.WithCancel(context.Background())
if l.cancel != nil {
l.cancel()
}
l.cancel = cancel
leaseResp, err := l.cli.Grant(ctx, l.ttlSeconds)

View file

@ -30,7 +30,7 @@ import (
"github.com/pilosa/pilosa/v2/disco"
"github.com/pilosa/pilosa/v2/pql"
pb "github.com/pilosa/pilosa/v2/proto"
"github.com/pilosa/pilosa/v2/proto"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/shardwidth"
"github.com/pilosa/pilosa/v2/testhook"
@ -2741,37 +2741,37 @@ func (r *RowIdentifiers) Clone() (clone *RowIdentifiers) {
}
// ToTable implements the ToTabler interface.
func (r RowIdentifiers) ToTable() (*pb.TableResponse, error) {
func (r RowIdentifiers) ToTable() (*proto.TableResponse, error) {
var n int
if len(r.Keys) > 0 {
n = len(r.Keys)
} else {
n = len(r.Rows)
}
return pb.RowsToTable(&r, n)
return proto.RowsToTable(&r, n)
}
// ToRows implements the ToRowser interface.
func (r RowIdentifiers) ToRows(callback func(*pb.RowResponse) error) error {
func (r RowIdentifiers) ToRows(callback func(*proto.RowResponse) error) error {
if len(r.Keys) > 0 {
ci := []*pb.ColumnInfo{{Name: r.Field(), Datatype: "string"}}
ci := []*proto.ColumnInfo{{Name: r.Field(), Datatype: "string"}}
for _, key := range r.Keys {
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: key}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_StringVal{StringVal: key}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
ci = nil
}
} else {
ci := []*pb.ColumnInfo{{Name: r.Field(), Datatype: "uint64"}}
ci := []*proto.ColumnInfo{{Name: r.Field(), Datatype: "uint64"}}
for _, id := range r.Rows {
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(id)}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Uint64Val{Uint64Val: uint64(id)}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
@ -3289,50 +3289,50 @@ func NewGroupCounts(agg string, groups ...GroupCount) *GroupCounts {
}
// ToTable implements the ToTabler interface.
func (g *GroupCounts) ToTable() (*pb.TableResponse, error) {
return pb.RowsToTable(g, len(g.Groups()))
func (g *GroupCounts) ToTable() (*proto.TableResponse, error) {
return proto.RowsToTable(g, len(g.Groups()))
}
// ToRows implements the ToRowser interface.
func (g *GroupCounts) ToRows(callback func(*pb.RowResponse) error) error {
func (g *GroupCounts) ToRows(callback func(*proto.RowResponse) error) error {
agg := g.AggregateColumn()
for i, gc := range g.Groups() {
var ci []*pb.ColumnInfo
var ci []*proto.ColumnInfo
if i == 0 {
for _, fieldRow := range gc.Group {
if fieldRow.RowKey != "" {
ci = append(ci, &pb.ColumnInfo{Name: fieldRow.Field, Datatype: "string"})
ci = append(ci, &proto.ColumnInfo{Name: fieldRow.Field, Datatype: "string"})
} else if fieldRow.Value != nil {
ci = append(ci, &pb.ColumnInfo{Name: fieldRow.Field, Datatype: "int64"})
ci = append(ci, &proto.ColumnInfo{Name: fieldRow.Field, Datatype: "int64"})
} else {
ci = append(ci, &pb.ColumnInfo{Name: fieldRow.Field, Datatype: "uint64"})
ci = append(ci, &proto.ColumnInfo{Name: fieldRow.Field, Datatype: "uint64"})
}
}
ci = append(ci, &pb.ColumnInfo{Name: "count", Datatype: "uint64"})
ci = append(ci, &proto.ColumnInfo{Name: "count", Datatype: "uint64"})
if agg != "" {
ci = append(ci, &pb.ColumnInfo{Name: agg, Datatype: "int64"})
ci = append(ci, &proto.ColumnInfo{Name: agg, Datatype: "int64"})
}
}
rowResp := &pb.RowResponse{
rowResp := &proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{},
Columns: []*proto.ColumnResponse{},
}
for _, fieldRow := range gc.Group {
if fieldRow.RowKey != "" {
rowResp.Columns = append(rowResp.Columns, &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: fieldRow.RowKey}})
rowResp.Columns = append(rowResp.Columns, &proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_StringVal{StringVal: fieldRow.RowKey}})
} else if fieldRow.Value != nil {
rowResp.Columns = append(rowResp.Columns, &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: *fieldRow.Value}})
rowResp.Columns = append(rowResp.Columns, &proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: *fieldRow.Value}})
} else {
rowResp.Columns = append(rowResp.Columns, &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: fieldRow.RowID}})
rowResp.Columns = append(rowResp.Columns, &proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Uint64Val{Uint64Val: fieldRow.RowID}})
}
}
rowResp.Columns = append(rowResp.Columns,
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: gc.Count}})
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Uint64Val{Uint64Val: gc.Count}})
if agg != "" {
rowResp.Columns = append(rowResp.Columns,
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: gc.Agg}})
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: gc.Agg}})
}
if err := callback(rowResp); err != nil {
return errors.Wrap(err, "calling callback")
@ -3868,93 +3868,93 @@ type ExtractedTable struct {
}
// ToRows implements the ToRowser interface.
func (t ExtractedTable) ToRows(callback func(*pb.RowResponse) error) error {
func (t ExtractedTable) ToRows(callback func(*proto.RowResponse) error) error {
if len(t.Columns) == 0 {
return nil
}
headers := make([]*pb.ColumnInfo, len(t.Fields)+1)
headers := make([]*proto.ColumnInfo, len(t.Fields)+1)
colType := "uint64"
if t.Columns[0].Column.Keyed {
colType = "string"
}
headers[0] = &pb.ColumnInfo{
headers[0] = &proto.ColumnInfo{
Name: "_id",
Datatype: colType,
}
dataHeaders := headers[1:]
for i, f := range t.Fields {
dataHeaders[i] = &pb.ColumnInfo{
dataHeaders[i] = &proto.ColumnInfo{
Name: f.Name,
Datatype: f.Type,
}
}
for _, c := range t.Columns {
cols := make([]*pb.ColumnResponse, len(c.Rows)+1)
cols := make([]*proto.ColumnResponse, len(c.Rows)+1)
if c.Column.Keyed {
cols[0] = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_StringVal{
cols[0] = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_StringVal{
StringVal: c.Column.Key,
},
}
} else {
cols[0] = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_Uint64Val{
cols[0] = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_Uint64Val{
Uint64Val: c.Column.ID,
},
}
}
valCols := cols[1:]
for i, r := range c.Rows {
var col *pb.ColumnResponse
var col *proto.ColumnResponse
switch r := r.(type) {
case nil:
col = &pb.ColumnResponse{}
col = &proto.ColumnResponse{}
case bool:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_BoolVal{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_BoolVal{
BoolVal: r,
},
}
case int64:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_Int64Val{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_Int64Val{
Int64Val: r,
},
}
case uint64:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_Uint64Val{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_Uint64Val{
Uint64Val: r,
},
}
case string:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_StringVal{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_StringVal{
StringVal: r,
},
}
case []uint64:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_Uint64ArrayVal{
Uint64ArrayVal: &pb.Uint64Array{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_Uint64ArrayVal{
Uint64ArrayVal: &proto.Uint64Array{
Vals: r,
},
},
}
case []string:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_StringArrayVal{
StringArrayVal: &pb.StringArray{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_StringArrayVal{
StringArrayVal: &proto.StringArray{
Vals: r,
},
},
}
case pql.Decimal:
col = &pb.ColumnResponse{
ColumnVal: &pb.ColumnResponse_DecimalVal{
DecimalVal: &pb.Decimal{
col = &proto.ColumnResponse{
ColumnVal: &proto.ColumnResponse_DecimalVal{
DecimalVal: &proto.Decimal{
Value: r.Value,
Scale: r.Scale,
},
@ -3965,7 +3965,7 @@ func (t ExtractedTable) ToRows(callback func(*pb.RowResponse) error) error {
}
valCols[i] = col
}
err := callback(&pb.RowResponse{
err := callback(&proto.RowResponse{
Headers: headers,
Columns: cols,
})
@ -3978,8 +3978,8 @@ func (t ExtractedTable) ToRows(callback func(*pb.RowResponse) error) error {
}
// ToTable converts the table to protobuf format.
func (t ExtractedTable) ToTable() (*pb.TableResponse, error) {
return pb.RowsToTable(t, len(t.Columns))
func (t ExtractedTable) ToTable() (*proto.TableResponse, error) {
return proto.RowsToTable(t, len(t.Columns))
}
type ExtractedIDColumn struct {
@ -5640,12 +5640,12 @@ func (e *executor) remoteExec(ctx context.Context, node *topology.Node, index st
EmbeddedData: embed,
}
pb, err := e.client.QueryNode(ctx, &node.URI, index, pbreq)
resp, err := e.client.QueryNode(ctx, &node.URI, index, pbreq)
if err != nil {
return nil, err
}
return pb.Results, pb.Err
return resp.Results, resp.Err
}
// shardsByNode returns a mapping of nodes to shards.
@ -7312,7 +7312,7 @@ func (s *SignedRow) Field() string {
}
// ToTable implements the ToTabler interface.
func (s SignedRow) ToTable() (*pb.TableResponse, error) {
func (s SignedRow) ToTable() (*proto.TableResponse, error) {
var n uint64
if s.Neg != nil {
n += s.Neg.Count()
@ -7320,13 +7320,13 @@ func (s SignedRow) ToTable() (*pb.TableResponse, error) {
if s.Pos != nil {
n += s.Pos.Count()
}
return pb.RowsToTable(&s, int(n))
return proto.RowsToTable(&s, int(n))
}
// ToRows implements the ToRowser interface.
func (s SignedRow) ToRows(callback func(*pb.RowResponse) error) error {
func (s SignedRow) ToRows(callback func(*proto.RowResponse) error) error {
ci := []*pb.ColumnInfo{{Name: s.Field(), Datatype: "int64"}}
ci := []*proto.ColumnInfo{{Name: s.Field(), Datatype: "int64"}}
if s.Neg != nil {
negs := s.Neg.Columns()
for i := len(negs) - 1; i >= 0; i-- {
@ -7335,10 +7335,10 @@ func (s SignedRow) ToRows(callback func(*pb.RowResponse) error) error {
return errors.Wrap(err, "converting uint64 to int64 (negative)")
}
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: val}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: val}},
},
}); err != nil {
return errors.Wrap(err, "calling callback")
@ -7353,10 +7353,10 @@ func (s SignedRow) ToRows(callback func(*pb.RowResponse) error) error {
return errors.Wrap(err, "converting uint64 to int64 (positive)")
}
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: val}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: val}},
},
}); err != nil {
return errors.Wrap(err, "calling callback")
@ -7437,51 +7437,51 @@ func (v *ValCount) Clone() (r *ValCount) {
}
// ToTable implements the ToTabler interface.
func (v ValCount) ToTable() (*pb.TableResponse, error) {
return pb.RowsToTable(&v, 1)
func (v ValCount) ToTable() (*proto.TableResponse, error) {
return proto.RowsToTable(&v, 1)
}
// ToRows implements the ToRowser interface.
func (v ValCount) ToRows(callback func(*pb.RowResponse) error) error {
var ci []*pb.ColumnInfo
func (v ValCount) ToRows(callback func(*proto.RowResponse) error) error {
var ci []*proto.ColumnInfo
// ValCount can have a decimal, float, or integer value, but
// not more than one (as of this writing).
if v.DecimalVal != nil {
ci = []*pb.ColumnInfo{
ci = []*proto.ColumnInfo{
{Name: "value", Datatype: "decimal"},
{Name: "count", Datatype: "int64"},
}
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_DecimalVal{DecimalVal: &pb.Decimal{Value: v.DecimalVal.Value, Scale: v.DecimalVal.Scale}}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: v.Count}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_DecimalVal{DecimalVal: &proto.Decimal{Value: v.DecimalVal.Value, Scale: v.DecimalVal.Scale}}},
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: v.Count}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
} else if v.FloatVal != 0 {
ci = []*pb.ColumnInfo{
ci = []*proto.ColumnInfo{
{Name: "value", Datatype: "float64"},
{Name: "count", Datatype: "int64"},
}
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Float64Val{Float64Val: v.FloatVal}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: v.Count}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Float64Val{Float64Val: v.FloatVal}},
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: v.Count}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
} else {
ci = []*pb.ColumnInfo{
ci = []*proto.ColumnInfo{
{Name: "value", Datatype: "int64"},
{Name: "count", Datatype: "int64"},
}
if err := callback(&pb.RowResponse{
if err := callback(&proto.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: v.Val}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: v.Count}},
Columns: []*proto.ColumnResponse{
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: v.Val}},
&proto.ColumnResponse{ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: v.Count}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}

View file

@ -46,6 +46,7 @@ import (
"github.com/pilosa/pilosa/v2/storage"
"github.com/pilosa/pilosa/v2/test"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
)
@ -69,7 +70,7 @@ func getTempDirString() (td *string) {
}
func TestExecutor_Execute_ConstRow(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
c.CreateField(t, "i", pilosa.IndexOptions{}, "h")
@ -1058,7 +1059,7 @@ func TestExecutor_Execute_SetRowAttrs(t *testing.T) {
}
func TestExecutor_Execute_TopK_Set(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Load some test data into a set field.
@ -1089,7 +1090,7 @@ func TestExecutor_Execute_TopK_Set(t *testing.T) {
}
func TestExecutor_Execute_TopK_Time(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Load some test data into a time field.
@ -3033,15 +3034,18 @@ func TestExecutor_Execute_Range_BSIGroup_Deprecated(t *testing.T) {
// Ensure a remote query can return a row.
func TestExecutor_Execute_Remote_Row(t *testing.T) {
c := test.MustRunCluster(t, 2,
c := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerNodeID("node0"), pilosa.OptServerClusterHasher(&test.ModHasher{}))},
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerNodeID("node1"), pilosa.OptServerClusterHasher(&test.ModHasher{}))},
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerNodeID("node2"), pilosa.OptServerClusterHasher(&test.ModHasher{}))},
)
defer c.Close()
hldr0 := c.GetHolder(0)
hldr1 := c.GetHolder(1)
hldr2 := c.GetHolder(2)
_, err := c.GetPrimary().API.CreateIndex(context.Background(), "i", pilosa.IndexOptions{})
if err != nil {
@ -3051,10 +3055,8 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
if err != nil {
t.Fatalf("creating field: %v", err)
}
hldr1.MustSetBits("i", "f", 10, ShardWidth+1, ShardWidth+2, (3*ShardWidth)+4)
hldr0.SetBit("i", "f", 10, 1)
hldr0.MustSetBits("i", "f", 10, ShardWidth+1, ShardWidth+2, (3*ShardWidth)+4)
hldr2.SetBit("i", "f", 10, 1)
if res, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Row(f=10)`}); err != nil {
t.Fatal(err)
} else if columns := res.Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(columns, []uint64{1, ShardWidth + 1, ShardWidth + 2, (3 * ShardWidth) + 4}) {
@ -3074,7 +3076,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
t.Fatalf("querying remote: %v", err)
}
if !reflect.DeepEqual(hldr1.Row("i", "f", 7).Columns(), []uint64{pilosa.ShardWidth + 1}) {
if !reflect.DeepEqual(hldr0.Row("i", "f", 7).Columns(), []uint64{pilosa.ShardWidth + 1}) {
t.Fatalf("unexpected cols from row 7: %v", hldr1.Row("i", "f", 7).Columns())
}
})
@ -3089,7 +3091,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
t.Fatalf("quuerying remote: %v", err)
}
if !reflect.DeepEqual(hldr1.RowTime("i", "z", 5, time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC), "Y").Columns(), []uint64{pilosa.ShardWidth + 1}) {
if !reflect.DeepEqual(hldr0.RowTime("i", "z", 5, time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC), "Y").Columns(), []uint64{pilosa.ShardWidth + 1}) {
t.Fatalf("unexpected cols from row 7: %v", hldr1.RowTime("i", "z", 5, time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC), "Y").Columns())
}
})
@ -3786,7 +3788,7 @@ func TestExecutor_Execute_Not(t *testing.T) {
// Ensure an all query can be executed.
func TestExecutor_Execute_FieldValue(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
node0 := c.GetNode(0)
@ -3879,7 +3881,7 @@ func TestExecutor_Execute_FieldValue(t *testing.T) {
// Ensure a Limit query can be executed.
func TestExecutor_Execute_Limit(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
c.CreateField(t, "i", pilosa.IndexOptions{TrackExistence: true}, "f")
@ -4062,12 +4064,12 @@ func TestExecutor_Execute_All(t *testing.T) {
if err := m0.API.Import(context.Background(), qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
i0, err := m0.API.Index(context.Background(), "i")
panicOn(err)
PanicOn(err)
if i0 == nil {
panic("nil index i0?")
PanicOn("nil index i0?")
}
tests := []struct {
@ -4144,7 +4146,7 @@ func TestExecutor_Execute_All(t *testing.T) {
if err := c.GetNode(0).API.Import(context.Background(), qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
tests := []struct {
qry string
@ -4675,7 +4677,7 @@ func benchmarkExistence(nn bool, b *testing.B) {
if err := nodeAPI.Import(context.Background(), qcx, req); err != nil {
b.Fatal(err)
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
}
}
@ -6735,7 +6737,7 @@ func TestExecutor_Execute_CountDistinct(t *testing.T) {
// is handled correctly.
func TestExecutor_BareDistinct(t *testing.T) {
t.Helper()
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
c.CreateField(t, "i", pilosa.IndexOptions{}, "ints",
@ -6816,7 +6818,7 @@ func TestExecutor_Execute_TopNDistinct(t *testing.T) {
}
func Test_Executor_Execute_UnionRows(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
c.CreateField(t, "i", pilosa.IndexOptions{}, "s",

View file

@ -29,6 +29,7 @@ import (
"github.com/pilosa/pilosa/v2/pql"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// Ensure a bsiGroup can adjust to its baseValue.
@ -212,7 +213,7 @@ func NewTestField(t *testing.T, opts FieldOption) *TestField {
cfg := DefaultHolderConfig()
cfg.StorageConfig.Backend = CurrentBackendOrDefault()
h := NewHolder(path, cfg)
panicOn(h.Open())
PanicOn(h.Open())
idx, err := h.CreateIndex("i", IndexOptions{})
if err != nil {
@ -238,7 +239,7 @@ func OpenField(t *testing.T, opts FieldOption) *TestField {
// Close closes the field and removes the underlying data.
func (f *TestField) Close() error {
if f.idx != nil {
panicOn(f.idx.holder.txf.CloseIndex(f.idx))
PanicOn(f.idx.holder.txf.CloseIndex(f.idx))
}
defer os.RemoveAll(f.Path())
return f.Field.Close()
@ -335,7 +336,7 @@ func TestField_RowTime(t *testing.T) {
f.MustSetBit(tx, 1, 4, time.Date(2010, time.January, 6, 12, 0, 0, 0, time.UTC))
f.MustSetBit(tx, 1, 5, time.Date(2010, time.January, 5, 13, 0, 0, 0, time.UTC))
panicOn(tx.Commit())
PanicOn(tx.Commit())
// obtain 2nd transaction to read it back.
tx = f.idx.holder.txf.NewTx(Txo{Write: !writable, Index: f.idx, Field: f.Field, Shard: 0})
@ -610,14 +611,14 @@ func TestBSIGroup_importValue(t *testing.T) {
if err := f.importValue(qcx, tt.columnIDs, tt.values, options); err != nil {
t.Fatalf("test %d, importing values: %s", i, err.Error())
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
qcx.Reset()
if row, err := f.Range(qcx, f.name, pql.EQ, tt.checkVal); err != nil {
t.Fatalf("test %d, getting range: %s", i, err.Error())
} else if !reflect.DeepEqual(row.Columns(), tt.expCols) {
t.Fatalf("test %d, expected columns: %v, but got: %v", i, tt.expCols, row.Columns())
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
qcx.Reset()
} // loop
}
@ -682,7 +683,7 @@ func TestIntField_MinMaxForShard(t *testing.T) {
if err := f.importValue(qcx, test.columnIDs, test.values, options); err != nil {
t.Fatalf("test %d, importing values: %s", i, err.Error())
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
qcx.Reset()
shard := uint64(0)
@ -909,7 +910,7 @@ func TestBSIGroup_TxReopenDB(t *testing.T) {
if err := f.importValue(qcx, tt.columnIDs, tt.values, options); err != nil {
t.Fatalf("test %d, importing values: %s", i, err.Error())
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
qcx.Reset()
if row, err := f.Range(qcx, f.name, pql.EQ, tt.checkVal); err != nil {
@ -917,7 +918,7 @@ func TestBSIGroup_TxReopenDB(t *testing.T) {
} else if !reflect.DeepEqual(row.Columns(), tt.expCols) {
t.Fatalf("test %d, expected columns: %v, but got: %v", i, tt.expCols, row.Columns())
}
panicOn(qcx.Finish())
PanicOn(qcx.Finish())
qcx.Reset()
} // loop

View file

@ -40,9 +40,9 @@ import (
"github.com/cespare/xxhash"
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/v2/internal"
"github.com/pilosa/pilosa/v2/logger"
pnet "github.com/pilosa/pilosa/v2/net"
"github.com/pilosa/pilosa/v2/pb"
"github.com/pilosa/pilosa/v2/pql"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/shardwidth"
@ -50,6 +50,7 @@ import (
"github.com/pilosa/pilosa/v2/testhook"
"github.com/pilosa/pilosa/v2/topology"
"github.com/pilosa/pilosa/v2/tracing"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
)
@ -212,7 +213,7 @@ func newFragment(holder *Holder, spec fragSpec, shard uint64, flags byte) *fragm
idx := holder.Index(spec.index.name)
if idx == nil {
panic(fmt.Sprintf("got nil idx back for '%v' from holder!", spec.index))
PanicOn(fmt.Sprintf("got nil idx back for '%v' from holder!", spec.index))
}
f := &fragment{
@ -533,7 +534,7 @@ func (f *fragment) openCache() error {
}
// Unmarshal cache data.
var pb internal.Cache
var pb pb.Cache
if err := proto.Unmarshal(buf, &pb); err != nil {
f.holder.Logger.Printf("error unmarshaling cache data, skipping: path=%s, err=%s", path, err)
return nil
@ -616,7 +617,7 @@ func (f *fragment) row(tx Tx, rowID uint64) (*Row, error) {
func (f *fragment) mustRow(tx Tx, rowID uint64) *Row {
row, err := f.row(tx, rowID)
if err != nil {
panic(err)
PanicOn(err)
}
return row
}
@ -696,7 +697,7 @@ func (f *fragment) setBit(tx Tx, rowID, columnID uint64) (changed bool, err erro
err = f.gen.Transaction(wp, doSetFunc)
} else {
if tx.Type() == RoaringTxn {
panic("internal error: f.gen was nil. should never happen under roaring b/c storage should be open")
return changed, errors.New("internal error: f.gen was nil and tx.Type is RoaringTxn - should never happen under roaring b/c storage should be open")
}
// else blue green or transactional backend. Just do it.
err = doSetFunc()
@ -1073,7 +1074,7 @@ func (f *fragment) setValueBase(txOrig Tx, columnID uint64, bitDepth uint64, val
tx = f.idx.holder.txf.NewTx(Txo{Write: writable, Index: f.idx, Fragment: f, Shard: f.shard})
defer func() {
if err == nil {
panicOn(tx.Commit())
PanicOn(tx.Commit())
} else {
tx.Rollback()
}
@ -2070,7 +2071,9 @@ func (f *fragment) Blocks() ([]FragmentBlock, error) {
idx := f.holder.Index(f.index())
if idx == nil {
panic(fmt.Sprintf("index() was nil in fragment.Blocks(): f.index()='%v'\n", f.index()))
err := fmt.Errorf("index() was nil in fragment.Blocks(): f.index()='%v'", f.index())
PanicOn(err)
return nil, err
}
tx := idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2404,7 +2407,7 @@ func (p *parallelSlices) fullPrune() {
return
}
if len(p.rows) != len(p.cols) {
panic("parallelSlices must have same length for rows and columns")
PanicOn("parallelSlices must have same length for rows and columns")
}
unsorted := p.prune()
if unsorted {
@ -2535,9 +2538,8 @@ func (f *fragment) importPositions(tx Tx, set, clear []uint64, rowSet map[uint64
err = f.gen.Transaction(wp, doFunc)
} else {
if tx.Type() == RoaringTxn {
panic("internal error: 2nd place, f.gen was nil. should never happen under roaring b/c storage should be open")
return errors.New("internal error: f.gen was nil and tx.Type is RoaringTxn - should never happen under roaring b/c storage should be open")
}
// else blue green or transactional backend. Just do it.
err = doFunc()
}
@ -2902,7 +2904,7 @@ func (f *fragment) snapshot() (err error) {
f.path(), mappedIn, mappedOut, unmappedIn, errs)
}
} else {
err = fmt.Errorf("non-error panic: %v", r)
err = fmt.Errorf("non-error PanicOn: %v", r)
}
}
}()
@ -2992,7 +2994,7 @@ func (f *fragment) flushCache() error {
ids := f.cache.IDs()
// Marshal cache data to bytes.
buf, err := proto.Marshal(&internal.Cache{IDs: ids})
buf, err := proto.Marshal(&pb.Cache{IDs: ids})
if err != nil {
return errors.Wrap(err, "marshalling")
}

View file

@ -40,6 +40,7 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/storage"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
@ -76,7 +77,7 @@ func TestFragment_SetBit(t *testing.T) {
}
// commit the change, and verify it is still there
panicOn(tx.Commit())
PanicOn(tx.Commit())
// Close and reopen the fragment & verify the data.
err := f.Reopen()
@ -114,7 +115,7 @@ func TestFragment_ClearBit(t *testing.T) {
}
// The Reopen below implies this test is looking at storage consistency.
// In that spirit, we will check that the Tx Commit is visible afterwards.
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -200,7 +201,7 @@ func TestFragment_ClearRow(t *testing.T) {
if n := f.mustRow(tx, 1000).Count(); n != 0 {
t.Fatalf("unexpected count: %d", n)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -247,7 +248,7 @@ func TestFragment_SetRow(t *testing.T) {
t.Fatalf("expected changed value: %v", changed)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -260,7 +261,7 @@ func TestFragment_SetRow(t *testing.T) {
t.Fatalf("unexpected count after set row: %d", n)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
// Close and reopen the fragment & verify the data.
@ -285,7 +286,7 @@ func TestFragment_SetRow(t *testing.T) {
if cols := f.mustRow(tx, rowID).Columns(); len(cols) != 0 {
t.Fatalf("expected setting a row with no entries to clear the cache")
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
}
// Ensure a fragment can set & read a value.
@ -543,7 +544,7 @@ func TestFragment_Sum(t *testing.T) {
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -576,7 +577,7 @@ func TestFragment_Sum(t *testing.T) {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -615,7 +616,7 @@ func TestFragment_MinMax(t *testing.T) {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
// the new tx is shared by Min/Max below.
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
@ -1215,7 +1216,7 @@ func TestFragment_Snapshot(t *testing.T) {
} else if _, err := f.clearBit(tx, 1000, 1); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -1308,7 +1309,7 @@ func TestFragment_Top_Filter(t *testing.T) {
t.Fatalf("setAttrs: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -1481,7 +1482,7 @@ func TestFragment_TopN_CacheSize(t *testing.T) {
f := frag
if err := f.Open(); err != nil {
panic(err)
PanicOn(err)
}
defer f.Clean(t)
@ -1538,7 +1539,7 @@ func TestFragment_Checksum(t *testing.T) {
} else if _, err := f.setBit(tx, HashBlockSize*2, 200); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
// Ensure new checksum is different.
if chksum, err := f.Checksum(); err != nil {
@ -1561,7 +1562,7 @@ func TestFragment_Blocks(t *testing.T) {
if _, err := f.setBit(tx, 0, 0); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
blocks, err := f.Blocks() // FAIL: TestFragment_Blocks b/c 0 blocks back
if err != nil {
t.Fatal(err)
@ -1575,7 +1576,7 @@ func TestFragment_Blocks(t *testing.T) {
if _, err := f.setBit(tx, 20, 0); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
blocks, err = f.Blocks()
if err != nil {
t.Fatal(err)
@ -1590,7 +1591,7 @@ func TestFragment_Blocks(t *testing.T) {
if _, err := f.setBit(tx, 20, 100); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
blocks, err = f.Blocks()
if err != nil {
t.Fatal(err)
@ -1609,7 +1610,7 @@ func TestFragment_Blocks_Empty(t *testing.T) {
if _, err := f.setBit(tx, 100, 1); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit()) // f.Blocks() will start a new Tx, so the SetBit needs to be visible before that.
PanicOn(tx.Commit()) // f.Blocks() will start a new Tx, so the SetBit needs to be visible before that.
// Ensure checksum for block 1 is blank.
if blocks, err := f.Blocks(); err != nil {
@ -1641,7 +1642,7 @@ func TestFragment_LRUCache_Persistence(t *testing.T) {
t.Fatalf("unexpected cache len: %d", cache.Len())
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
// Reopen the fragment.
if err := f.Reopen(); err != nil {
@ -1692,7 +1693,7 @@ func TestFragment_RankCache_Persistence(t *testing.T) {
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = index.holder.txf.NewTx(Txo{Write: !writable, Index: index, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -1837,7 +1838,7 @@ func BenchmarkFragment_IntersectionCount(b *testing.B) {
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2178,7 +2179,7 @@ func TestFragment_ImportSet_WithTxCommit(t *testing.T) {
t.Fatalf("bulk importing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2200,7 +2201,7 @@ func TestFragment_ImportSet_WithTxCommit(t *testing.T) {
t.Fatalf("bulk clearing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2230,12 +2231,12 @@ func TestFragment_ConcurrentImport(t *testing.T) {
eg := errgroup.Group{}
eg.Go(func() error {
tx := idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f, Shard: shard})
defer func() { panicOn(tx.Commit()) }()
defer func() { PanicOn(tx.Commit()) }()
return f.bulkImportStandard(tx, []uint64{1, 2}, []uint64{1, 2}, &ImportOptions{})
})
eg.Go(func() error {
tx := idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f, Shard: shard})
defer func() { panicOn(tx.Commit()) }()
defer func() { PanicOn(tx.Commit()) }()
return f.bulkImportStandard(tx, []uint64{3, 4}, []uint64{3, 4}, &ImportOptions{})
})
err := eg.Wait()
@ -2457,7 +2458,7 @@ func TestFragment_ImportMutex_WithTxCommit(t *testing.T) {
t.Fatalf("bulk importing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2479,7 +2480,7 @@ func TestFragment_ImportMutex_WithTxCommit(t *testing.T) {
t.Fatalf("bulk clearing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2707,7 +2708,7 @@ func TestFragment_ImportBool_WithTxCommit(t *testing.T) {
t.Fatalf("bulk importing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -2729,7 +2730,7 @@ func TestFragment_ImportBool_WithTxCommit(t *testing.T) {
t.Fatalf("bulk importing ids: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -3059,7 +3060,7 @@ func BenchmarkImportRoaringUpdate(b *testing.B) {
// is excessive. force storage into snapshotted state, then use import
// to generate an op log and/or snapshot.
itr, err := roaring.NewRoaringIterator(data)
panicOn(err)
PanicOn(err)
_, _, err = tx.ImportRoaringBits(f.index(), f.field(), f.view(), f.shard, itr, false, false, 0, nil)
if err != nil {
b.Errorf("import error: %v", err)
@ -3143,15 +3144,15 @@ func initBigFrag(tb testing.TB) {
data := getZipfRowsSliceRoaring(10000000, i, 0, ShardWidth)
err := f.importRoaringT(tx, data, false)
if err != nil {
panic(fmt.Sprintf("setting up fragment data: %v", err))
PanicOn(fmt.Sprintf("setting up fragment data: %v", err))
}
}
err := f.Close()
if err != nil {
panic(fmt.Sprintf("closing fragment: %v", err))
PanicOn(fmt.Sprintf("closing fragment: %v", err))
}
bigFrag = f.path()
panicOn(tx.Commit())
PanicOn(tx.Commit())
}
}
@ -3178,9 +3179,9 @@ func BenchmarkImportIntoLargeFragment(b *testing.B) {
fi.Close()
h := NewHolder(fi.Name(), nil)
panicOn(h.Open())
PanicOn(h.Open())
idx, err := h.CreateIndex("i", IndexOptions{})
panicOn(err)
PanicOn(err)
f := newFragment(h, makeTestFragSpec(fi.Name(), "i", "f", viewStandard), 0, 0)
err = f.Open()
@ -3200,7 +3201,7 @@ func BenchmarkImportIntoLargeFragment(b *testing.B) {
if err != nil {
b.Fatalf("bulkImport: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
f.Clean(b)
h.Close()
}
@ -3375,7 +3376,7 @@ func getZipfRowsSliceRoaring(numRows uint64, seed int64, startCol, endCol uint64
buf := bytes.NewBuffer(make([]byte, 0, 100000))
_, err := b.WriteTo(buf)
if err != nil {
panic(err)
PanicOn(err)
}
return buf.Bytes()
}
@ -3401,7 +3402,7 @@ func getUniformRowsSliceRoaring(numRows uint64, seed int64, startCol, endCol uin
buf := bytes.NewBuffer(make([]byte, 0, 100000))
_, err := b.WriteTo(buf)
if err != nil {
panic(err)
PanicOn(err)
}
return buf.Bytes()
}
@ -3428,7 +3429,7 @@ func getUpdataRoaring(numRows, numCols uint64, seed int64) []byte {
buf := bytes.NewBuffer(make([]byte, 0, 100000))
_, err := b.WriteTo(buf)
if err != nil {
panic(err)
PanicOn(err)
}
return buf.Bytes()
}
@ -3582,7 +3583,7 @@ func mustOpenBSIFragment(tb testing.TB, index, field, view string, shard uint64)
func newTestHolder(tb testing.TB) *Holder {
path, _ := testhook.TempDirInDir(tb, *TempDir, "holder-dir")
h := NewHolder(path, mustHolderConfig())
panicOn(h.Open())
PanicOn(h.Open())
testhook.Cleanup(tb, func() {
h.Close()
})
@ -3601,13 +3602,13 @@ func fragTestMustOpenIndex(index string, holder *Holder, opt IndexOptions) *Inde
holder.mu.Lock()
idx, err := holder.createIndex(cim, false)
holder.mu.Unlock()
panicOn(err)
PanicOn(err)
idx.keys = opt.Keys
idx.trackExistence = opt.TrackExistence
if err := idx.Open(); err != nil {
panic(err)
PanicOn(err)
}
return idx
}
@ -3625,14 +3626,14 @@ func mustOpenFragmentFlags(tb testing.TB, index, field, view string, shard uint6
}
fragDir := fmt.Sprintf("%v/%v/views/%v/fragments/", idx.path, field, view)
panicOn(os.MkdirAll(fragDir, 0777))
PanicOn(os.MkdirAll(fragDir, 0777))
fragPath := fragDir + fmt.Sprintf("%v", shard)
f := newFragment(th, makeTestFragSpec(fragPath, index, field, view), shard, flags)
tx := idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f, Shard: shard})
testhook.Cleanup(tb, func() {
tx.Rollback()
panicOn(idx.holder.txf.CloseIndex(idx))
PanicOn(idx.holder.txf.CloseIndex(idx))
})
f.CacheType = cacheType
@ -3641,7 +3642,7 @@ func mustOpenFragmentFlags(tb testing.TB, index, field, view string, shard uint6
}
if err := f.Open(); err != nil {
panic(err)
PanicOn(err)
}
return f, idx, tx
}
@ -3676,7 +3677,7 @@ func (f *fragment) Reopen() error {
func (f *fragment) mustSetBits(tx Tx, rowID uint64, columnIDs ...uint64) {
for _, columnID := range columnIDs {
if _, err := f.setBit(tx, rowID, columnID); err != nil {
panic(err)
PanicOn(err)
}
}
}
@ -3737,7 +3738,7 @@ func TestFragment_RowsIteration(t *testing.T) {
} else if _, err := f.setBit(tx, 2, 166000); err != nil {
t.Fatal(err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -3928,7 +3929,7 @@ func toRowsCols(roaring []uint64) (rowIDs, colIDs []uint64) {
func calcTop(rowIDs, colIDs []uint64) []Pair {
if len(rowIDs) != len(colIDs) {
panic("row and col ids must be of equal len")
PanicOn("row and col ids must be of equal len")
}
// make map of rowID to colID set in order to dedup
counts := make(map[uint64]map[uint64]struct{})
@ -4166,7 +4167,7 @@ func TestFragmentRowIterator_WithTxCommit(t *testing.T) {
f.mustSetBits(tx, 2, 0)
f.mustSetBits(tx, 3, 0)
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -4214,7 +4215,7 @@ func TestFragmentRowIterator_WithTxCommit(t *testing.T) {
f.mustSetBits(tx, 5, 0)
f.mustSetBits(tx, 7, 0)
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -4262,7 +4263,7 @@ func TestFragmentRowIterator_WithTxCommit(t *testing.T) {
f.mustSetBits(tx, 2, 0)
f.mustSetBits(tx, 3, 0)
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -4299,7 +4300,7 @@ func TestFragmentRowIterator_WithTxCommit(t *testing.T) {
f.mustSetBits(tx, 5, 0)
f.mustSetBits(tx, 7, 0)
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -4535,7 +4536,7 @@ func TestFragmentBSIUnsigned(t *testing.T) {
t.Fatalf("no change when setting col %d to %d", uint64(i), int64(i))
}
}
panicOn(tx.Commit()) // t.Run beolow on different goro and so need their own Tx anyway.
PanicOn(tx.Commit()) // t.Run beolow on different goro and so need their own Tx anyway.
// Generate a list of columns.
cols := make([]uint64, 1<<k)
@ -4719,7 +4720,7 @@ func TestFragmentBSIUnsigned_WithTxCommit(t *testing.T) {
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -4882,7 +4883,7 @@ func TestFragmentBSISigned(t *testing.T) {
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard: f.shard})
defer tx.Rollback()
@ -5094,7 +5095,7 @@ func TestImportClearRestart(t *testing.T) {
if err != nil {
t.Fatalf("closing fragment: %v", err)
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
err = f.Open()
tx = idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f, Shard: f.shard})
@ -5114,14 +5115,14 @@ func TestImportClearRestart(t *testing.T) {
h := newTestHolder(t)
idx2, err := h.CreateIndex("i", IndexOptions{})
_ = idx2
panicOn(err)
PanicOn(err)
// OVERWRITING the f.path with a new fragment
f2 := newFragment(h, makeTestFragSpec(f.path(), "i", "f", viewStandard), 0, 0)
f2.MaxOpN = maxOpN
f2.CacheType = f.CacheType
panicOn(tx.Commit()) // match the f.closeStorage which overlaps the f2 creation.
PanicOn(tx.Commit()) // match the f.closeStorage which overlaps the f2 creation.
tx2 := idx.holder.txf.NewTx(Txo{Write: writable, Index: idx, Fragment: f2, Shard: f2.shard})
defer tx2.Rollback()
@ -5158,7 +5159,7 @@ func TestImportClearRestart(t *testing.T) {
check(t, tx2, f2, exp)
panicOn(tx2.Commit())
PanicOn(tx2.Commit())
h3 := NewHolder(filepath.Dir(f2.path()), nil)
testhook.Cleanup(t, func() {
@ -5167,7 +5168,7 @@ func TestImportClearRestart(t *testing.T) {
idx3, err := h3.CreateIndex("i", IndexOptions{})
_ = idx3
panicOn(err)
PanicOn(err)
f3 := newFragment(h3, makeTestFragSpec(f2.path(), "i", "f", viewStandard), 0, 0)
f3.MaxOpN = maxOpN
@ -5291,7 +5292,7 @@ func TestImportMultipleValues(t *testing.T) {
}
// probably too slow, would hit disk alot:
//panicOn(tx.Commit())
//PanicOn(tx.Commit())
//tx = idx.holder.txf.NewTx(Txo{Write: !writable, Index: idx, Fragment: f, Shard:f.shard, ShardSet:true})
//defer tx.Rollback()
@ -5398,7 +5399,7 @@ func TestFragmentConcurrentReadWrite(t *testing.T) {
return errors.Wrap(err, "setting bit")
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
return nil
})
@ -5423,7 +5424,7 @@ func TestRemapCache(t *testing.T) {
defer f.Close()
index, field, view, shard := f.index(), f.field(), f.view(), f.shard
// request a panic that doesn't kill the program on fault
// request a PanicOn that doesn't kill the program on fault
wouldFault := debug.SetPanicOnFault(true)
defer func() {
debug.SetPanicOnFault(wouldFault)
@ -5435,7 +5436,7 @@ func TestRemapCache(t *testing.T) {
t.Fatalf("segfault trapped during remap test (expected failure mode)")
}
}
t.Fatalf("unexpected panic: %v", r)
t.Fatalf("unexpected PanicOn: %v", r)
}
}()

32
go.mod
View file

@ -4,31 +4,29 @@ replace go.etcd.io/etcd => github.com/molecula/etcd v0.0.0-20210115113447-5d28bd
require (
github.com/CAFxX/gcnotifier v0.0.0-20190112062741-224a280d589d
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895
github.com/DataDog/datadog-go v2.2.0+incompatible
github.com/HdrHistogram/hdrhistogram-go v1.1.0 // indirect
github.com/beevik/ntp v0.3.0
github.com/benbjohnson/immutable v0.3.0
github.com/cespare/xxhash v1.1.0
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/davecgh/go-spew v1.1.1
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 // indirect
github.com/glycerine/idem v0.0.0-20190127113923-7a8083893311
github.com/gogo/protobuf v1.2.1
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.3.3
github.com/google/go-cmp v0.5.2
github.com/google/go-cmp v0.5.5
github.com/google/uuid v1.1.4 // indirect
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/gorilla/handlers v1.3.0
github.com/gorilla/mux v1.7.0
github.com/improbable-eng/grpc-web v0.13.0
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.8.0
github.com/molecula/apophenia v0.0.0-20190827192002-68b7a14a478b
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/opentracing/opentracing-go v1.1.0
github.com/pelletier/go-toml v1.2.0
github.com/pelletier/go-toml v1.4.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.0.0
github.com/prometheus/client_model v0.1.0
@ -38,24 +36,22 @@ require (
github.com/rs/cors v1.7.0 // indirect
github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil/v3 v3.20.11
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/cobra v1.1.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.1
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/zeebo/blake3 v0.0.4
github.com/stretchr/testify v1.7.0
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/uber/jaeger-lib v2.4.0+incompatible // indirect
github.com/zeebo/blake3 v0.1.1
go.etcd.io/bbolt v1.3.5
go.etcd.io/etcd v0.0.0-20201125193152-8a03d2e9614b
golang.org/x/exp v0.0.0-20201008143054-e3b2a7f2fdc7
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.org/x/mod v0.4.2
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect
golang.org/x/text v0.3.5 // indirect
google.golang.org/grpc v1.28.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
modernc.org/mathutil v1.0.0
modernc.org/strutil v1.0.0

123
go.sum
View file

@ -16,19 +16,21 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CAFxX/gcnotifier v0.0.0-20190112062741-224a280d589d h1:n0G4ckjMEj7bWuGYUX0i8YlBeBBJuZ+HEHvHfyBDZtI=
github.com/CAFxX/gcnotifier v0.0.0-20190112062741-224a280d589d/go.mod h1:Rn2zM2MnHze07LwkneP48TWt6UiZhzQTwCvw6djVGfE=
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 h1:dmc/C8bpE5VkQn65PNbbyACDC8xw8Hpp/NEurdPmQDQ=
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go v2.2.0+incompatible h1:V5BKkxACZLjzHjSgBbr2gvLA2Ae49yhc6CSY7MLy5k4=
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/HdrHistogram/hdrhistogram-go v1.1.0 h1:6dpdDPTRoo78HxAJ6T1HfMiKSnqhgRRqzCuPshRkQ7I=
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
@ -47,11 +49,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
@ -81,7 +79,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -100,8 +98,10 @@ github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -120,8 +120,9 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -142,39 +143,28 @@ github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@ -188,7 +178,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -196,17 +185,16 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -220,11 +208,9 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
@ -250,10 +236,10 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -294,7 +280,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil/v3 v3.20.11 h1:NeVf1K0cgxsWz+N3671ojRptdgzvp7BXL3KV21R0JnA=
github.com/shirou/gopsutil/v3 v3.20.11/go.mod h1:igHnfak0qnw1biGeI2qKQvu0ZkwvEkUcCLlYhZzdr/4=
@ -308,9 +293,8 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
@ -332,31 +316,30 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o=
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY=
github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U=
github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.0+incompatible h1:fY7QsGQWiCt8pajv4r7JEvmATdCVaWxXbjwyYwsNaLQ=
github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivllc1yU3BvpjYI5BUW+zglcz6QWqeVRL5t0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.0.4 h1:vtZ4X8B2lKXZFg2Xyg6Wo36mvmnJvc2VQYTtA4RDCkI=
github.com/zeebo/blake3 v0.0.4/go.mod h1:YOZo8A49yNqM0X/Y+JmDUZshJWLt1laHsNSn5ny2i34=
github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05 h1:4pW5fMvVkrgkMXdvIsVRRTs69DWYA8uNNQsu1stfVKU=
github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05/go.mod h1:Gr+78ptB0MwXxm//LBaEvBiaXY7hXJ6KGe2V32X2F6E=
github.com/zeebo/blake3 v0.1.1 h1:Nbsts7DdKThRHHd+YNlqiGlRqGEF2bE2eXN+xQ1hsEs=
github.com/zeebo/blake3 v0.1.1/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4=
github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0=
github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@ -377,13 +360,17 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20201008143054-e3b2a7f2fdc7 h1:2/QncOxxpPAdiH+E00abYw/SaQG353gltz79Nl1zrYE=
golang.org/x/exp v0.0.0-20201008143054-e3b2a7f2fdc7/go.mod h1:1phAWC201xIgDyaFpmDeZkgf70Q4Pd/CNqfRtVPtxNw=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -398,8 +385,11 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -416,8 +406,10 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 h1:b0LrWgu8+q7z4J+0Y3Umo5q1dL7NXBkKBWkaVkAq17E=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -426,8 +418,10 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -446,23 +440,29 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b h1:tv7/y4pd+sR8bcNb2D6o7BNU6zjWm0VjQLac+w7fNNM=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -480,11 +480,19 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@ -500,7 +508,6 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
@ -525,7 +532,6 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -543,6 +549,7 @@ modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03
modernc.org/strutil v1.0.0 h1:XVFtQwFVwc02Wk+0L/Z/zDDXO81r5Lhe6iMKmGX3KhE=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View file

@ -290,7 +290,7 @@ type TranslateKeysRequest struct {
Field string
Keys []string
// it's a awkward name, just to keep backward compatibility with go-pilosa and idk.
// NotWritable is an awkward name, but it's just to keep backward compatibility with client and idk.
NotWritable bool
}

View file

@ -37,6 +37,7 @@ import (
"github.com/pilosa/pilosa/v2/testhook"
"github.com/pilosa/pilosa/v2/topology"
"github.com/pilosa/pilosa/v2/tracing"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
@ -306,7 +307,7 @@ func NewHolder(path string, cfg *HolderConfig) *Holder {
storage.SetRowCacheOn(cfg.RowcacheOn)
txf, err := NewTxFactory(cfg.StorageConfig.Backend, h.IndexesPath(), h)
panicOn(err)
PanicOn(err)
h.txf = txf
h.txf.blueGreenOffIfRunningBlueGreen()

View file

@ -22,6 +22,7 @@ import (
"github.com/pilosa/pilosa/v2/disco"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
var _ = fmt.Printf
@ -113,7 +114,7 @@ func testMustHaveBit(t *testing.T, h *Holder, index, field string, rowID, column
// hmm... if its a new holder, meta data isn't there, so ask for it.
idx, err := h.CreateIndexIfNotExists(index, IndexOptions{})
panicOn(err)
PanicOn(err)
f := idx.Field(field)
if f == nil {

View file

@ -470,11 +470,13 @@ func TestClient_ImportColumnAttrs(t *testing.T) {
// Ensure client can bulk import data.
func TestClient_ImportRoaring(t *testing.T) {
cluster := test.MustRunCluster(t, 2,
cluster := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerReplicaN(2))},
server.OptCommandServerOptions(pilosa.OptServerReplicaN(3))},
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerReplicaN(2))},
server.OptCommandServerOptions(pilosa.OptServerReplicaN(3))},
[]server.CommandOption{
server.OptCommandServerOptions(pilosa.OptServerReplicaN(3))},
)
defer cluster.Close()
@ -722,7 +724,7 @@ func TestClient_ImportKeys(t *testing.T) {
})
t.Run("MultiNode", func(t *testing.T) {
cluster := test.MustRunCluster(t, 2)
cluster := test.MustRunCluster(t, 3)
defer cluster.Close()
cmd0 := cluster.GetNode(0)
cmd1 := cluster.GetNode(1)

View file

@ -28,6 +28,7 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/stats"
"github.com/pilosa/pilosa/v2/testhook"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)

View file

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View file

@ -26,9 +26,14 @@ import (
"github.com/pkg/errors"
)
var schemeRegexp = regexp.MustCompile("^[+a-z]+$")
var hostRegexp = regexp.MustCompile(`^[0-9a-z.-]+$|^\[[:0-9a-fA-F]+\]$`)
var addressRegexp = regexp.MustCompile(`^(([+a-z]+):\/\/)?([0-9a-z.-]+|\[[:0-9a-fA-F]+\])?(:([0-9]+))?$`)
var (
schemeRegexp = regexp.MustCompile("^[+a-z]+$")
hostRegexp = regexp.MustCompile(`^[0-9a-z.-]+$|^\[[:0-9a-fA-F]+\]$`)
addressRegexp = regexp.MustCompile(`^(([+a-z]+):\/\/)?([0-9a-z.-]+|\[[:0-9a-fA-F]+\])?(:([0-9]+))?$`)
ErrInvalidAddress = errors.New("invalid address")
ErrInvalidSchema = errors.New("invalid schema")
)
// URI represents a Pilosa URI.
// A Pilosa URI consists of three parts:
@ -56,11 +61,6 @@ func (u *URI) URL() url.URL {
// DefaultURI creates and returns the default URI.
func DefaultURI() *URI {
return defaultURI()
}
// defaultURI creates and returns the default URI.
func defaultURI() *URI {
return &URI{
Scheme: "http",
Host: "localhost",
@ -83,7 +83,7 @@ func (u URIs) HostPortStrings() []string {
// NewURIFromHostPort returns a URI with specified host and port.
func NewURIFromHostPort(host string, port uint16) (*URI, error) {
uri := defaultURI()
uri := DefaultURI()
err := uri.SetHost(host)
if err != nil {
return nil, errors.Wrap(err, "setting uri host")
@ -101,7 +101,7 @@ func NewURIFromAddress(address string) (*URI, error) {
func (u *URI) SetScheme(scheme string) error {
m := schemeRegexp.FindStringSubmatch(scheme)
if m == nil {
return errors.New("invalid scheme")
return ErrInvalidSchema
}
u.Scheme = scheme
return nil
@ -133,7 +133,7 @@ func (u *URI) HostPort() string {
}
// normalize returns the address in a form usable by a HTTP client.
func (u *URI) normalize() string {
func (u *URI) Normalize() string {
scheme := u.Scheme
index := strings.Index(scheme, "+")
if index >= 0 {
@ -142,6 +142,16 @@ func (u *URI) normalize() string {
return fmt.Sprintf("%s://%s:%d", scheme, u.Host, u.Port)
}
// Equals returns true if the checked URI is equivalent to this URI.
func (u URI) Equals(other *URI) bool {
if other == nil {
return false
}
return u.Scheme == other.Scheme &&
u.Host == other.Host &&
u.Port == other.Port
}
// String returns the address as a string.
func (u URI) String() string {
return fmt.Sprintf("%s://%s:%d", u.Scheme, u.Host, u.Port)
@ -149,7 +159,7 @@ func (u URI) String() string {
// Path returns URI with path
func (u *URI) Path(path string) string {
return fmt.Sprintf("%s%s", u.normalize(), path)
return fmt.Sprintf("%s%s", u.Normalize(), path)
}
// The following methods are required to implement pflag Value interface.
@ -169,10 +179,18 @@ func (u URI) Type() string {
return "URI"
}
// Translate returns the translated URI based on the provided NAT map.
func (u URI) Translate(nat map[URI]URI) URI {
if translated, ok := nat[u]; ok {
return translated
}
return u
}
func parseAddress(address string) (uri *URI, err error) {
m := addressRegexp.FindStringSubmatch(address)
if m == nil {
return nil, errors.New("invalid address")
return nil, ErrInvalidAddress
}
scheme := "http"
if m[2] != "" {

View file

@ -17,7 +17,7 @@ package net
import "testing"
func TestDefaultURI(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
compare(t, uri, "http", "localhost", 10101)
}
@ -60,7 +60,7 @@ func TestNormalizedAddress(t *testing.T) {
if err != nil {
t.Fatalf("Can't parse address")
}
if uri.normalize() != "http://big-data.pilosa.com:6888" {
if uri.Normalize() != "http://big-data.pilosa.com:6888" {
t.Fatalf("Normalized address is not normal")
}
}
@ -77,7 +77,7 @@ func TestURIPath(t *testing.T) {
}
func TestSetScheme(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
target := "fun"
err := uri.SetScheme(target)
if err != nil {
@ -89,7 +89,7 @@ func TestSetScheme(t *testing.T) {
}
func TestSetHost(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
target := "10.20.30.40"
err := uri.SetHost(target)
if err != nil {
@ -101,7 +101,7 @@ func TestSetHost(t *testing.T) {
}
func TestSetPort(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
target := uint16(9999)
uri.SetPort(target)
if uri.Port != target {
@ -110,7 +110,7 @@ func TestSetPort(t *testing.T) {
}
func TestSetInvalidScheme(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
err := uri.SetScheme("?invalid")
if err == nil {
t.Fatalf("Should have failed")
@ -118,7 +118,7 @@ func TestSetInvalidScheme(t *testing.T) {
}
func TestSetInvalidHost(t *testing.T) {
uri := defaultURI()
uri := DefaultURI()
err := uri.SetHost("index?.pilosa.com")
if err == nil {
t.Fatalf("Should have failed")

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
package pb
import (
"io"

View file

@ -1,7 +1,24 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: private.proto
package internal
package pb
import (
fmt "fmt"
@ -2472,143 +2489,142 @@ func (m *ResizeNodeMessage) GetAction() string {
}
func init() {
proto.RegisterType((*IndexMeta)(nil), "internal.IndexMeta")
proto.RegisterType((*FieldOptions)(nil), "internal.FieldOptions")
proto.RegisterType((*ImportResponse)(nil), "internal.ImportResponse")
proto.RegisterType((*BlockDataRequest)(nil), "internal.BlockDataRequest")
proto.RegisterType((*BlockDataResponse)(nil), "internal.BlockDataResponse")
proto.RegisterType((*Cache)(nil), "internal.Cache")
proto.RegisterType((*MaxShards)(nil), "internal.MaxShards")
proto.RegisterMapType((map[string]uint64)(nil), "internal.MaxShards.StandardEntry")
proto.RegisterType((*CreateShardMessage)(nil), "internal.CreateShardMessage")
proto.RegisterType((*DeleteIndexMessage)(nil), "internal.DeleteIndexMessage")
proto.RegisterType((*CreateIndexMessage)(nil), "internal.CreateIndexMessage")
proto.RegisterType((*CreateFieldMessage)(nil), "internal.CreateFieldMessage")
proto.RegisterType((*DeleteFieldMessage)(nil), "internal.DeleteFieldMessage")
proto.RegisterType((*DeleteAvailableShardMessage)(nil), "internal.DeleteAvailableShardMessage")
proto.RegisterType((*Field)(nil), "internal.Field")
proto.RegisterType((*Schema)(nil), "internal.Schema")
proto.RegisterType((*Index)(nil), "internal.Index")
proto.RegisterType((*URI)(nil), "internal.URI")
proto.RegisterType((*Node)(nil), "internal.Node")
proto.RegisterType((*NodeStateMessage)(nil), "internal.NodeStateMessage")
proto.RegisterType((*NodeEventMessage)(nil), "internal.NodeEventMessage")
proto.RegisterType((*NodeStatus)(nil), "internal.NodeStatus")
proto.RegisterType((*IndexStatus)(nil), "internal.IndexStatus")
proto.RegisterType((*FieldStatus)(nil), "internal.FieldStatus")
proto.RegisterType((*ClusterStatus)(nil), "internal.ClusterStatus")
proto.RegisterType((*BSIGroup)(nil), "internal.BSIGroup")
proto.RegisterType((*CreateViewMessage)(nil), "internal.CreateViewMessage")
proto.RegisterType((*DeleteViewMessage)(nil), "internal.DeleteViewMessage")
proto.RegisterType((*ResizeInstruction)(nil), "internal.ResizeInstruction")
proto.RegisterType((*ResizeSource)(nil), "internal.ResizeSource")
proto.RegisterType((*TranslationResizeSource)(nil), "internal.TranslationResizeSource")
proto.RegisterType((*ResizeInstructionComplete)(nil), "internal.ResizeInstructionComplete")
proto.RegisterType((*Topology)(nil), "internal.Topology")
proto.RegisterType((*RecalculateCaches)(nil), "internal.RecalculateCaches")
proto.RegisterType((*LoadSchemaMessage)(nil), "internal.LoadSchemaMessage")
proto.RegisterType((*TransactionMessage)(nil), "internal.TransactionMessage")
proto.RegisterType((*Transaction)(nil), "internal.Transaction")
proto.RegisterType((*TransactionStats)(nil), "internal.TransactionStats")
proto.RegisterType((*ResizeAbortMessage)(nil), "internal.ResizeAbortMessage")
proto.RegisterType((*ResizeNodeMessage)(nil), "internal.ResizeNodeMessage")
proto.RegisterType((*IndexMeta)(nil), "pb.IndexMeta")
proto.RegisterType((*FieldOptions)(nil), "pb.FieldOptions")
proto.RegisterType((*ImportResponse)(nil), "pb.ImportResponse")
proto.RegisterType((*BlockDataRequest)(nil), "pb.BlockDataRequest")
proto.RegisterType((*BlockDataResponse)(nil), "pb.BlockDataResponse")
proto.RegisterType((*Cache)(nil), "pb.Cache")
proto.RegisterType((*MaxShards)(nil), "pb.MaxShards")
proto.RegisterMapType((map[string]uint64)(nil), "pb.MaxShards.StandardEntry")
proto.RegisterType((*CreateShardMessage)(nil), "pb.CreateShardMessage")
proto.RegisterType((*DeleteIndexMessage)(nil), "pb.DeleteIndexMessage")
proto.RegisterType((*CreateIndexMessage)(nil), "pb.CreateIndexMessage")
proto.RegisterType((*CreateFieldMessage)(nil), "pb.CreateFieldMessage")
proto.RegisterType((*DeleteFieldMessage)(nil), "pb.DeleteFieldMessage")
proto.RegisterType((*DeleteAvailableShardMessage)(nil), "pb.DeleteAvailableShardMessage")
proto.RegisterType((*Field)(nil), "pb.Field")
proto.RegisterType((*Schema)(nil), "pb.Schema")
proto.RegisterType((*Index)(nil), "pb.Index")
proto.RegisterType((*URI)(nil), "pb.URI")
proto.RegisterType((*Node)(nil), "pb.Node")
proto.RegisterType((*NodeStateMessage)(nil), "pb.NodeStateMessage")
proto.RegisterType((*NodeEventMessage)(nil), "pb.NodeEventMessage")
proto.RegisterType((*NodeStatus)(nil), "pb.NodeStatus")
proto.RegisterType((*IndexStatus)(nil), "pb.IndexStatus")
proto.RegisterType((*FieldStatus)(nil), "pb.FieldStatus")
proto.RegisterType((*ClusterStatus)(nil), "pb.ClusterStatus")
proto.RegisterType((*BSIGroup)(nil), "pb.BSIGroup")
proto.RegisterType((*CreateViewMessage)(nil), "pb.CreateViewMessage")
proto.RegisterType((*DeleteViewMessage)(nil), "pb.DeleteViewMessage")
proto.RegisterType((*ResizeInstruction)(nil), "pb.ResizeInstruction")
proto.RegisterType((*ResizeSource)(nil), "pb.ResizeSource")
proto.RegisterType((*TranslationResizeSource)(nil), "pb.TranslationResizeSource")
proto.RegisterType((*ResizeInstructionComplete)(nil), "pb.ResizeInstructionComplete")
proto.RegisterType((*Topology)(nil), "pb.Topology")
proto.RegisterType((*RecalculateCaches)(nil), "pb.RecalculateCaches")
proto.RegisterType((*LoadSchemaMessage)(nil), "pb.LoadSchemaMessage")
proto.RegisterType((*TransactionMessage)(nil), "pb.TransactionMessage")
proto.RegisterType((*Transaction)(nil), "pb.Transaction")
proto.RegisterType((*TransactionStats)(nil), "pb.TransactionStats")
proto.RegisterType((*ResizeAbortMessage)(nil), "pb.ResizeAbortMessage")
proto.RegisterType((*ResizeNodeMessage)(nil), "pb.ResizeNodeMessage")
}
func init() { proto.RegisterFile("private.proto", fileDescriptor_d2a91b51c7bdc125) }
var fileDescriptor_d2a91b51c7bdc125 = []byte{
// 1456 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xdd, 0x6e, 0x1b, 0xc5,
0x17, 0xff, 0xaf, 0xd7, 0x8e, 0xed, 0xe3, 0x38, 0x75, 0xa6, 0x69, 0xba, 0xcd, 0xbf, 0x0a, 0x66,
0x40, 0xd4, 0x54, 0x6a, 0xa8, 0x5a, 0x24, 0x10, 0xa8, 0x52, 0x93, 0x38, 0x2d, 0x86, 0xa6, 0x4d,
0x27, 0x69, 0xef, 0x27, 0xeb, 0x51, 0xb3, 0xca, 0x7a, 0xd7, 0xdd, 0x8f, 0xd4, 0x2e, 0x12, 0xb7,
0x20, 0xb8, 0x42, 0x70, 0xc1, 0x25, 0xef, 0xc1, 0x0b, 0x70, 0xc9, 0x23, 0xa0, 0xf2, 0x04, 0xbc,
0x01, 0x9a, 0x33, 0x33, 0xbb, 0x6b, 0xc7, 0xa9, 0x43, 0xcb, 0xdd, 0x9e, 0xef, 0xdf, 0xf9, 0x98,
0x33, 0x63, 0x43, 0x73, 0x18, 0x79, 0x27, 0x3c, 0x11, 0x1b, 0xc3, 0x28, 0x4c, 0x42, 0x52, 0xf3,
0x82, 0x44, 0x44, 0x01, 0xf7, 0xd7, 0x16, 0x87, 0xe9, 0xa1, 0xef, 0xb9, 0x8a, 0x4f, 0xef, 0x43,
0xbd, 0x17, 0xf4, 0xc5, 0x68, 0x57, 0x24, 0x9c, 0x10, 0x28, 0x7f, 0x25, 0xc6, 0xb1, 0x63, 0xb7,
0xad, 0x4e, 0x8d, 0xe1, 0x37, 0xf9, 0x00, 0x96, 0x0e, 0x22, 0xee, 0x1e, 0xef, 0x8c, 0xbc, 0x38,
0x11, 0x81, 0x2b, 0x9c, 0x32, 0x4a, 0xa7, 0xb8, 0xf4, 0x57, 0x1b, 0x16, 0xef, 0x79, 0xc2, 0xef,
0x3f, 0x1a, 0x26, 0x5e, 0x18, 0xc4, 0xd2, 0xd9, 0xc1, 0x78, 0x28, 0x9c, 0x5a, 0xdb, 0xea, 0xd4,
0x19, 0x7e, 0x93, 0xab, 0x50, 0xdf, 0xe6, 0xee, 0x91, 0x40, 0x81, 0x8d, 0x82, 0x9c, 0x91, 0x49,
0xf7, 0xbd, 0x97, 0x2a, 0x4a, 0x93, 0xe5, 0x0c, 0xd2, 0x86, 0xc6, 0x81, 0x37, 0x10, 0x8f, 0x53,
0x1e, 0x24, 0xe9, 0xc0, 0xa9, 0xa0, 0x75, 0x91, 0x45, 0x56, 0x61, 0xe1, 0x91, 0xdf, 0xdf, 0xf5,
0x02, 0xa7, 0xde, 0xb6, 0x3a, 0x36, 0xd3, 0x94, 0xe1, 0xf3, 0x91, 0x03, 0x39, 0x9f, 0x8f, 0xb2,
0x74, 0x1b, 0x93, 0xe9, 0x3e, 0x0c, 0xf7, 0x13, 0x1e, 0xf4, 0x79, 0xd4, 0x7f, 0xea, 0x89, 0x17,
0xce, 0xa2, 0x4a, 0x77, 0x92, 0x2b, 0x6d, 0xb7, 0x78, 0x2c, 0x9c, 0x26, 0x7a, 0xc4, 0x6f, 0xb2,
0x06, 0xb5, 0x2d, 0x2f, 0xe9, 0x8a, 0x61, 0x72, 0xe4, 0x2c, 0xb5, 0xad, 0x4e, 0x99, 0x65, 0x34,
0x59, 0x81, 0xca, 0xbe, 0xcb, 0x7d, 0xe1, 0x5c, 0x40, 0x03, 0x45, 0x10, 0x0a, 0x8b, 0xf7, 0xc2,
0x48, 0x78, 0xcf, 0x02, 0x6c, 0x82, 0xd3, 0xc2, 0xa4, 0x26, 0x78, 0xe4, 0x3d, 0xb0, 0x65, 0x4a,
0xcb, 0x6d, 0xab, 0xd3, 0xb8, 0xb5, 0xbc, 0x61, 0xfa, 0xb8, 0xd1, 0x15, 0xae, 0x37, 0xe0, 0x3e,
0x93, 0x52, 0x54, 0xe2, 0x23, 0x87, 0x9c, 0xad, 0xc4, 0x47, 0x94, 0xc2, 0x52, 0x6f, 0x30, 0x0c,
0xa3, 0x84, 0x89, 0x78, 0x18, 0x06, 0xb1, 0x20, 0x2d, 0xb0, 0x77, 0xa2, 0xc8, 0xb1, 0x30, 0xac,
0xfc, 0xa4, 0xdf, 0x40, 0x6b, 0xcb, 0x0f, 0xdd, 0xe3, 0x2e, 0x4f, 0x38, 0x13, 0xcf, 0x53, 0x11,
0x27, 0x12, 0xbb, 0x82, 0xa7, 0xf4, 0x14, 0x21, 0xb9, 0xd8, 0x6f, 0xa7, 0xa4, 0xb8, 0x48, 0xc8,
0xba, 0x60, 0xd5, 0x54, 0x7b, 0xf0, 0x1b, 0x73, 0x3f, 0xe2, 0x51, 0x1f, 0x7b, 0x5a, 0x66, 0x8a,
0x90, 0x5c, 0x8c, 0x84, 0x73, 0x50, 0x66, 0x8a, 0xa0, 0x3d, 0x58, 0x2e, 0xc4, 0xd7, 0x30, 0x57,
0x61, 0x81, 0x85, 0x2f, 0x7a, 0xdd, 0xd8, 0xb1, 0xda, 0x76, 0xa7, 0xcc, 0x34, 0x85, 0x03, 0x13,
0xfa, 0xe9, 0x20, 0x90, 0xa2, 0x12, 0x8a, 0x72, 0x06, 0xbd, 0x02, 0x15, 0x9c, 0x1e, 0x99, 0x65,
0x6e, 0x2b, 0x3f, 0xe9, 0xb7, 0x16, 0xd4, 0x77, 0xf9, 0x08, 0x81, 0xc4, 0xe4, 0x0e, 0xd4, 0x4c,
0x6f, 0x51, 0xa9, 0x71, 0xeb, 0xdd, 0xbc, 0x82, 0x99, 0xda, 0x86, 0xd1, 0xd9, 0x09, 0x92, 0x68,
0xcc, 0x32, 0x93, 0xb5, 0xcf, 0xa1, 0x39, 0x21, 0x92, 0xf1, 0x8e, 0xc5, 0xd8, 0x54, 0xf5, 0x58,
0x8c, 0x65, 0xae, 0x27, 0xdc, 0x4f, 0x05, 0xd6, 0xaa, 0xcc, 0x14, 0xf1, 0x59, 0xe9, 0x53, 0x8b,
0x3e, 0x05, 0xb2, 0x1d, 0x09, 0x9e, 0x08, 0x0c, 0xb2, 0x2b, 0xe2, 0x98, 0x3f, 0x13, 0xf3, 0x2a,
0x6e, 0x17, 0x2b, 0x9e, 0x55, 0xb7, 0x54, 0xa8, 0x2e, 0xbd, 0x0e, 0xa4, 0x2b, 0x7c, 0x91, 0x08,
0x7d, 0xba, 0x5f, 0xe3, 0x97, 0x3e, 0x37, 0x18, 0xe6, 0xeb, 0x92, 0x6b, 0x50, 0x96, 0xab, 0x02,
0x83, 0x35, 0x6e, 0x5d, 0xcc, 0xeb, 0x94, 0x6d, 0x11, 0x86, 0x0a, 0xd8, 0x1b, 0x74, 0xda, 0xdf,
0x4c, 0x10, 0xb0, 0xcd, 0x72, 0x06, 0xfd, 0xde, 0x32, 0x31, 0x31, 0x89, 0x73, 0xe6, 0x3d, 0x31,
0x69, 0xd7, 0x35, 0x12, 0x1b, 0x91, 0xac, 0xe6, 0x48, 0x8a, 0x5b, 0x68, 0x16, 0x98, 0xf2, 0x34,
0x98, 0xbb, 0xa6, 0x56, 0x6f, 0x8a, 0x85, 0xba, 0xf0, 0x7f, 0xe5, 0x61, 0xf3, 0x84, 0x7b, 0x3e,
0x3f, 0xf4, 0xff, 0x55, 0x3b, 0x27, 0xd2, 0x72, 0xa0, 0x8a, 0xb6, 0xbd, 0xae, 0x3e, 0x18, 0x86,
0xa4, 0x5f, 0x43, 0x7e, 0xc6, 0x1e, 0xf2, 0x81, 0xd0, 0xde, 0xf0, 0x3b, 0xab, 0x46, 0xe9, 0x1c,
0xd5, 0x58, 0x81, 0x8a, 0x3c, 0x97, 0x72, 0xcf, 0xdb, 0x32, 0x30, 0x12, 0x73, 0x6a, 0x74, 0x1b,
0x16, 0xf6, 0xdd, 0x23, 0x31, 0xe0, 0xe4, 0x43, 0xa8, 0x22, 0x7e, 0x11, 0xeb, 0xc3, 0x72, 0x61,
0x6a, 0x08, 0x98, 0x91, 0xd3, 0x1f, 0x2d, 0x9d, 0xf8, 0x4c, 0xc8, 0x13, 0x01, 0x4b, 0x53, 0x01,
0xc9, 0x0d, 0xa8, 0x6a, 0xd4, 0xb8, 0x4b, 0xce, 0x98, 0x35, 0xa3, 0x43, 0xae, 0xc1, 0x02, 0x66,
0x1a, 0x3b, 0xe5, 0x69, 0x50, 0xc8, 0x67, 0x5a, 0x4c, 0x77, 0xc0, 0x7e, 0xc2, 0x7a, 0x72, 0xa5,
0x60, 0x3e, 0x06, 0x92, 0xa6, 0x24, 0xd0, 0x2f, 0xc2, 0x38, 0xd1, 0x3d, 0xc1, 0x6f, 0xc9, 0xdb,
0x0b, 0x23, 0x35, 0xc5, 0x4d, 0x86, 0xdf, 0xf4, 0x67, 0x0b, 0xca, 0x0f, 0xc3, 0xbe, 0x20, 0x4b,
0x50, 0xea, 0x75, 0xb5, 0x93, 0x52, 0xaf, 0x4b, 0xde, 0x41, 0xff, 0xba, 0x0f, 0xcd, 0x1c, 0xc5,
0x13, 0xd6, 0x63, 0x18, 0xf9, 0x2a, 0xd4, 0x7b, 0xf1, 0x5e, 0xe4, 0x0d, 0x78, 0x34, 0xd6, 0x37,
0x6d, 0xce, 0xc0, 0xd3, 0x9c, 0xf0, 0x44, 0xdd, 0x7f, 0x75, 0xa6, 0x08, 0x72, 0x0d, 0xaa, 0xf7,
0xd9, 0xde, 0xb6, 0x74, 0x5c, 0x99, 0xe5, 0xd8, 0x48, 0xe9, 0x5d, 0x68, 0x49, 0x54, 0x68, 0x65,
0xa6, 0x6f, 0x15, 0x16, 0x24, 0x2f, 0x43, 0xa9, 0xa9, 0x3c, 0x54, 0xa9, 0x10, 0x8a, 0x3e, 0x50,
0x1e, 0x76, 0x4e, 0x44, 0x90, 0x14, 0xe6, 0x17, 0x69, 0x74, 0xd0, 0x64, 0x8a, 0x20, 0x54, 0x55,
0x40, 0xa7, 0xba, 0x94, 0x23, 0x92, 0x5c, 0x86, 0x32, 0xfa, 0x83, 0x05, 0x60, 0x00, 0xa5, 0x71,
0x66, 0x62, 0x9d, 0x6d, 0x42, 0x3a, 0x66, 0xd2, 0xf4, 0xc9, 0x6e, 0xe5, 0x5a, 0x8a, 0xcf, 0xcc,
0x24, 0x7e, 0x94, 0x4f, 0xa2, 0x6a, 0xfa, 0xa5, 0xa9, 0x11, 0x51, 0x51, 0xf3, 0x79, 0x0c, 0xa0,
0x51, 0xe0, 0xcf, 0x1c, 0xca, 0x1b, 0xd9, 0x1c, 0x95, 0xa6, 0x5d, 0x22, 0x5f, 0xbb, 0xd4, 0x4a,
0x73, 0xb6, 0x9c, 0x07, 0x8d, 0x82, 0xd1, 0xcc, 0x78, 0x1d, 0xb8, 0x30, 0xb9, 0x33, 0xcc, 0x45,
0x36, 0xcd, 0x9e, 0x13, 0xea, 0x27, 0x0b, 0x9a, 0xdb, 0x7e, 0x1a, 0x27, 0x22, 0xd2, 0xd1, 0xa4,
0xbe, 0x62, 0x64, 0x9d, 0xcf, 0x19, 0xb3, 0x9b, 0x4f, 0xde, 0x87, 0x8a, 0xec, 0x81, 0xda, 0x0c,
0xa7, 0x1b, 0xa4, 0x84, 0x85, 0x0e, 0x95, 0x5f, 0xdf, 0x21, 0xfa, 0x14, 0x6a, 0x5b, 0xfb, 0xbd,
0xfb, 0x51, 0x98, 0x0e, 0x67, 0x66, 0x6f, 0xde, 0x88, 0xa5, 0xc2, 0x1b, 0xb1, 0xa5, 0xde, 0x3b,
0x2a, 0x43, 0x7c, 0xdc, 0xb4, 0xd4, 0xe3, 0xa6, 0xac, 0x39, 0x7c, 0x44, 0xf7, 0x61, 0x59, 0xa5,
0x2e, 0x57, 0xd7, 0x9b, 0x6c, 0x59, 0xf3, 0x4c, 0xb1, 0xf3, 0x67, 0x8a, 0x74, 0xaa, 0x96, 0xf8,
0x7f, 0xe9, 0xf4, 0xef, 0x12, 0x2c, 0x33, 0x11, 0x7b, 0x2f, 0x45, 0x2f, 0x88, 0x93, 0x28, 0x75,
0xe5, 0xba, 0x92, 0xf6, 0x5f, 0x86, 0x87, 0xba, 0x2f, 0x36, 0x53, 0xc4, 0x79, 0x0e, 0x14, 0xe9,
0x40, 0xb5, 0xb8, 0x3b, 0x4e, 0xab, 0x19, 0x31, 0xb9, 0x09, 0xd5, 0xfd, 0x30, 0x8d, 0xdc, 0xec,
0x74, 0x14, 0x2e, 0x05, 0x85, 0x48, 0x89, 0x99, 0x51, 0x23, 0x8f, 0x81, 0x1c, 0x44, 0x3c, 0x88,
0x7d, 0x2e, 0x41, 0x1a, 0xe3, 0xda, 0xf4, 0x8b, 0xa8, 0xa0, 0x33, 0xe1, 0x67, 0x86, 0x31, 0xf9,
0xb8, 0x78, 0xfc, 0x9d, 0x2a, 0x22, 0x5e, 0x99, 0x44, 0xac, 0x4f, 0x54, 0x71, 0x4d, 0xdc, 0x99,
0x9a, 0x65, 0x67, 0x01, 0x0d, 0x2f, 0xe7, 0x86, 0x13, 0x62, 0x36, 0xa9, 0x4d, 0xbf, 0xb3, 0x60,
0xb1, 0x88, 0xec, 0x5c, 0x6b, 0x27, 0x6b, 0x74, 0x69, 0xfe, 0x93, 0xcb, 0x34, 0xba, 0x3c, 0xeb,
0x91, 0x5b, 0x29, 0x3e, 0xc3, 0x52, 0xb8, 0x7c, 0x46, 0xb9, 0xde, 0x02, 0x54, 0x1b, 0x1a, 0x7b,
0x3c, 0x4a, 0x3c, 0xe9, 0x52, 0x3f, 0x13, 0x2a, 0xac, 0xc8, 0xa2, 0xc7, 0x70, 0xe5, 0xd4, 0xd0,
0x6d, 0x87, 0x83, 0xa1, 0x9c, 0xee, 0xb7, 0x18, 0x3e, 0x79, 0x0f, 0x44, 0x51, 0x18, 0x99, 0x6a,
0x20, 0x41, 0xb7, 0xa0, 0x76, 0x10, 0x0e, 0x43, 0x3f, 0x7c, 0x36, 0x9e, 0xb3, 0x74, 0x1c, 0xa8,
0xaa, 0xbb, 0x47, 0x2d, 0xb9, 0x3a, 0x33, 0x24, 0xbd, 0x28, 0x4f, 0x89, 0xcb, 0x7d, 0x37, 0xf5,
0x79, 0x22, 0xf0, 0xd9, 0x8e, 0xcc, 0x07, 0x21, 0xef, 0xab, 0x5d, 0xa2, 0x0f, 0x24, 0x15, 0x7a,
0x48, 0x39, 0x26, 0x55, 0xb8, 0xe3, 0x36, 0x91, 0x61, 0xee, 0x38, 0x45, 0x91, 0x4f, 0xa0, 0x51,
0xd0, 0xd6, 0xc9, 0x5d, 0x9a, 0x9a, 0x65, 0x25, 0x64, 0x45, 0x4d, 0xfa, 0x9b, 0x35, 0x61, 0x79,
0xea, 0x9a, 0xd7, 0x01, 0x4f, 0x54, 0xc1, 0x6a, 0x4c, 0x53, 0xb2, 0x00, 0x3b, 0x23, 0xd7, 0x4f,
0x63, 0x29, 0xd2, 0xb7, 0x7b, 0xc6, 0x90, 0x05, 0x90, 0x3f, 0x58, 0xc3, 0xd4, 0xbc, 0xb0, 0x0c,
0x29, 0x7f, 0x3b, 0x76, 0x05, 0xef, 0xfb, 0x5e, 0x20, 0x70, 0x82, 0x6c, 0x96, 0xd1, 0xe4, 0xa6,
0xda, 0xd5, 0xe6, 0x18, 0xac, 0xcd, 0x84, 0x8f, 0x1a, 0x6a, 0x8f, 0xc7, 0x94, 0x40, 0x6b, 0x5a,
0x44, 0x57, 0x80, 0xa8, 0x99, 0xd8, 0x3c, 0x0c, 0x23, 0x73, 0xb5, 0xd3, 0x6d, 0xb3, 0x9e, 0x64,
0x27, 0xe6, 0xbd, 0x18, 0xf2, 0x2a, 0x97, 0x8a, 0x55, 0xde, 0x6a, 0xfd, 0xfe, 0x6a, 0xdd, 0xfa,
0xe3, 0xd5, 0xba, 0xf5, 0xe7, 0xab, 0x75, 0xeb, 0x97, 0xbf, 0xd6, 0xff, 0x77, 0xb8, 0x80, 0xff,
0x2e, 0xdc, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff, 0x17, 0x40, 0x19, 0xfb, 0x86, 0x10, 0x00, 0x00,
// 1436 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0x1b, 0xc5,
0x17, 0xff, 0xef, 0x87, 0x63, 0xfb, 0x38, 0x4e, 0x9c, 0xf9, 0x47, 0x65, 0xfb, 0x41, 0xe4, 0x0e,
0x88, 0x86, 0x4a, 0x44, 0xa2, 0x5c, 0x14, 0xc1, 0x4d, 0x93, 0x38, 0x2d, 0xa6, 0xa4, 0x0d, 0xe3,
0xb4, 0xb7, 0x68, 0xbc, 0x1e, 0x35, 0xab, 0xac, 0x77, 0xcd, 0x7e, 0xa4, 0x76, 0x2f, 0x90, 0x40,
0x20, 0x78, 0x00, 0x2e, 0x78, 0x11, 0xde, 0x81, 0x1b, 0x24, 0x1e, 0x01, 0x95, 0x17, 0x41, 0x73,
0x66, 0x66, 0x77, 0xed, 0xba, 0x35, 0x44, 0xdc, 0xed, 0xf9, 0x9d, 0x99, 0x73, 0x7e, 0xe7, 0x63,
0xce, 0xcc, 0x42, 0x7b, 0x92, 0x04, 0x17, 0x3c, 0x13, 0x7b, 0x93, 0x24, 0xce, 0x62, 0x62, 0x4f,
0x86, 0xd7, 0xd6, 0x27, 0xf9, 0x30, 0x0c, 0x7c, 0x85, 0xd0, 0x07, 0xd0, 0xec, 0x47, 0x23, 0x31,
0x3d, 0x16, 0x19, 0x27, 0x04, 0xdc, 0x87, 0x62, 0x96, 0x7a, 0x4e, 0xd7, 0xda, 0x6d, 0x30, 0xfc,
0x26, 0xef, 0xc1, 0xc6, 0x69, 0xc2, 0xfd, 0xf3, 0xa3, 0x69, 0x90, 0x66, 0x22, 0xf2, 0x85, 0xe7,
0xa2, 0x76, 0x01, 0xa5, 0x3f, 0x3b, 0xb0, 0x7e, 0x3f, 0x10, 0xe1, 0xe8, 0xf1, 0x24, 0x0b, 0xe2,
0x28, 0x95, 0xc6, 0x4e, 0x67, 0x13, 0xe1, 0x35, 0xba, 0xd6, 0x6e, 0x93, 0xe1, 0x37, 0xb9, 0x01,
0xcd, 0x43, 0xee, 0x9f, 0x09, 0x54, 0x38, 0xa8, 0x28, 0x81, 0x42, 0x3b, 0x08, 0x5e, 0x28, 0x2f,
0x6d, 0x56, 0x02, 0xa4, 0x0b, 0xad, 0xd3, 0x60, 0x2c, 0xbe, 0xcc, 0x79, 0x94, 0xe5, 0x63, 0xaf,
0x86, 0xbb, 0xab, 0x10, 0xb9, 0x02, 0x6b, 0x8f, 0xc3, 0xd1, 0x71, 0x10, 0x79, 0xcd, 0xae, 0xb5,
0xeb, 0x30, 0x2d, 0x19, 0x9c, 0x4f, 0x3d, 0x28, 0x71, 0x3e, 0x2d, 0xc2, 0x6d, 0xcd, 0x87, 0xfb,
0x28, 0x1e, 0x64, 0x3c, 0x1a, 0xf1, 0x64, 0xf4, 0x34, 0x10, 0xcf, 0xbd, 0x75, 0x15, 0xee, 0x3c,
0x2a, 0xf7, 0x1e, 0xf0, 0x54, 0x78, 0x6d, 0xb4, 0x88, 0xdf, 0xe4, 0x1a, 0x34, 0x0e, 0x82, 0xac,
0x27, 0x26, 0xd9, 0x99, 0xb7, 0xd1, 0xb5, 0x76, 0x5d, 0x56, 0xc8, 0x64, 0x1b, 0x6a, 0x03, 0x9f,
0x87, 0xc2, 0xdb, 0xc4, 0x0d, 0x4a, 0x20, 0x14, 0xd6, 0xef, 0xc7, 0x89, 0x08, 0x9e, 0x45, 0x58,
0x04, 0xaf, 0x83, 0x41, 0xcd, 0x61, 0xe4, 0x6d, 0x70, 0x64, 0x48, 0x5b, 0x5d, 0x6b, 0xb7, 0x75,
0xa7, 0xb5, 0x37, 0x19, 0xee, 0xf5, 0x84, 0x1f, 0x8c, 0x79, 0xc8, 0x24, 0x8e, 0x6a, 0x3e, 0xf5,
0xc8, 0x32, 0x35, 0x9f, 0x52, 0x0a, 0x1b, 0xfd, 0xf1, 0x24, 0x4e, 0x32, 0x26, 0xd2, 0x49, 0x1c,
0xa5, 0x82, 0x74, 0xc0, 0x39, 0x4a, 0x12, 0xcf, 0x42, 0x57, 0xf2, 0x93, 0x7e, 0x03, 0x9d, 0x83,
0x30, 0xf6, 0xcf, 0x7b, 0x3c, 0xe3, 0x4c, 0x7c, 0x9d, 0x8b, 0x34, 0x93, 0x7c, 0x15, 0x25, 0xb5,
0x4e, 0x09, 0x12, 0xc5, 0x1a, 0x7b, 0xb6, 0x42, 0x51, 0x90, 0xb9, 0xc0, 0x4c, 0xa9, 0x92, 0xe0,
0x37, 0xc6, 0x7b, 0xc6, 0x93, 0x11, 0xd6, 0xd1, 0x65, 0x4a, 0x90, 0x28, 0x7a, 0xc2, 0xda, 0xbb,
0x4c, 0x09, 0xb4, 0x0f, 0x5b, 0x15, 0xff, 0x9a, 0xe6, 0x15, 0x58, 0x63, 0xf1, 0xf3, 0x7e, 0x2f,
0xf5, 0xac, 0xae, 0xb3, 0xeb, 0x32, 0x2d, 0x61, 0x93, 0xc4, 0x61, 0x3e, 0x8e, 0xa4, 0xca, 0x46,
0x55, 0x09, 0xd0, 0xab, 0x50, 0xc3, 0x8e, 0x91, 0x51, 0x96, 0x7b, 0xe5, 0x27, 0xfd, 0xd6, 0x82,
0xe6, 0x31, 0x9f, 0x22, 0x91, 0x94, 0xdc, 0x85, 0x86, 0xa9, 0x27, 0x2e, 0x6a, 0xdd, 0xb9, 0x2e,
0x73, 0x57, 0x2c, 0xd8, 0x33, 0xda, 0xa3, 0x28, 0x4b, 0x66, 0xac, 0x58, 0x7c, 0xed, 0x53, 0x68,
0xcf, 0xa9, 0xa4, 0xa7, 0x73, 0x31, 0x33, 0xf9, 0x3c, 0x17, 0x33, 0x19, 0xe5, 0x05, 0x0f, 0x73,
0x81, 0x59, 0x72, 0x99, 0x12, 0x3e, 0xb1, 0x3f, 0xb6, 0xe8, 0x53, 0x20, 0x87, 0x89, 0xe0, 0x99,
0x40, 0x27, 0xc7, 0x22, 0x4d, 0xf9, 0x33, 0xb1, 0x2a, 0xd7, 0x4e, 0x35, 0xd7, 0x45, 0x5e, 0xed,
0x4a, 0x5e, 0xe9, 0x6d, 0x20, 0x3d, 0x11, 0x8a, 0x4c, 0xe8, 0xb3, 0xfc, 0x06, 0xbb, 0xf4, 0xdc,
0x70, 0x58, 0xbd, 0x96, 0xdc, 0x04, 0x57, 0x0e, 0x06, 0x74, 0xd6, 0xba, 0xd3, 0x96, 0x19, 0x2a,
0xa6, 0x05, 0x43, 0x15, 0xd6, 0x03, 0xcd, 0x8d, 0xf6, 0x33, 0xa4, 0xea, 0xb0, 0x12, 0xa0, 0xdf,
0x5b, 0xc6, 0x1b, 0xd2, 0xff, 0x87, 0x11, 0xcf, 0x75, 0xd7, 0xbb, 0x9a, 0x83, 0x83, 0x1c, 0x3a,
0x92, 0x43, 0x75, 0xce, 0x2c, 0xa3, 0xe1, 0x2e, 0xd2, 0xb8, 0x67, 0xf2, 0x73, 0x59, 0x16, 0xd4,
0x87, 0xeb, 0xca, 0xc2, 0xfe, 0x05, 0x0f, 0x42, 0x3e, 0x0c, 0xff, 0x55, 0x09, 0xe7, 0x02, 0xf2,
0xa0, 0x8e, 0x7b, 0xfb, 0x3d, 0x7d, 0x0c, 0x8c, 0x48, 0x73, 0x28, 0x4f, 0xd4, 0x23, 0x3e, 0x16,
0xda, 0x1a, 0x7e, 0x17, 0x79, 0xb0, 0xdf, 0x98, 0x87, 0x6d, 0xa8, 0xc9, 0xf3, 0x27, 0x67, 0xb8,
0x23, 0x5d, 0xa2, 0xb0, 0x22, 0x3b, 0x1f, 0xc0, 0xda, 0xc0, 0x3f, 0x13, 0x63, 0x4e, 0xde, 0x81,
0x3a, 0x32, 0x17, 0xa9, 0x3e, 0x14, 0xcd, 0xa2, 0xe4, 0xcc, 0x68, 0xe8, 0x0f, 0x96, 0x0e, 0x76,
0x29, 0xcd, 0x39, 0x57, 0xf6, 0x82, 0x2b, 0x72, 0x0b, 0xea, 0x9a, 0x2f, 0x4e, 0x8b, 0x57, 0x7a,
0xca, 0x68, 0xc9, 0x4d, 0x58, 0xc3, 0xe8, 0x52, 0xcf, 0x2d, 0x89, 0x20, 0xc2, 0xb4, 0x82, 0x1e,
0x81, 0xf3, 0x84, 0xf5, 0xe5, 0xa0, 0x40, 0xf6, 0x86, 0x86, 0x96, 0x24, 0xb9, 0xcf, 0xe2, 0x34,
0xd3, 0xb9, 0xc7, 0x6f, 0x89, 0x9d, 0xc4, 0x89, 0xea, 0xd3, 0x36, 0xc3, 0x6f, 0xfa, 0x93, 0x05,
0xee, 0xa3, 0x78, 0x24, 0xc8, 0x06, 0xd8, 0xfd, 0x9e, 0x36, 0x62, 0xf7, 0x7b, 0xe4, 0x2a, 0xda,
0xd7, 0xf9, 0xae, 0x4b, 0xff, 0x4f, 0x58, 0x9f, 0xa1, 0xcf, 0x1b, 0xd0, 0xec, 0xa7, 0x27, 0x49,
0x30, 0xe6, 0xc9, 0x4c, 0xdf, 0x96, 0x25, 0x80, 0x67, 0x34, 0xe3, 0x99, 0xba, 0xc3, 0x9a, 0x4c,
0x09, 0xe4, 0x26, 0xd4, 0x1f, 0xb0, 0x93, 0x43, 0x69, 0xb2, 0x36, 0x6f, 0xd2, 0xe0, 0xf4, 0x1e,
0x74, 0x24, 0x13, 0x5c, 0x6f, 0x3a, 0xeb, 0x0a, 0xac, 0x49, 0xac, 0x60, 0xa6, 0xa5, 0xd2, 0x89,
0x5d, 0x71, 0x42, 0xef, 0x2b, 0x0b, 0x47, 0x17, 0x22, 0xca, 0x2a, 0xbd, 0x89, 0x32, 0x1a, 0x68,
0x33, 0x25, 0x90, 0x1b, 0x2a, 0x6a, 0x1d, 0x5e, 0x43, 0x72, 0x91, 0x32, 0x43, 0x94, 0xce, 0x00,
0x0c, 0x93, 0x3c, 0x2d, 0xd6, 0x5a, 0xcb, 0xd6, 0x12, 0x6a, 0xda, 0x47, 0x1f, 0x51, 0x90, 0x7a,
0x85, 0x30, 0xd3, 0x58, 0xef, 0x97, 0x8d, 0xa5, 0xea, 0xb9, 0x59, 0xd4, 0x5d, 0xf9, 0x28, 0xdb,
0xeb, 0x0c, 0x5a, 0x15, 0x7c, 0x69, 0x8f, 0xdd, 0x2a, 0x9a, 0xc3, 0x2e, 0x8d, 0x21, 0xa2, 0x8d,
0x69, 0xf5, 0x8a, 0xe1, 0x14, 0x40, 0xab, 0xb2, 0x69, 0xa9, 0xa7, 0x5d, 0xd8, 0x9c, 0x3f, 0xf0,
0xe6, 0xce, 0x59, 0x84, 0x57, 0xb8, 0xfa, 0xd1, 0x82, 0xf6, 0x61, 0x98, 0xa7, 0x99, 0x48, 0x8a,
0x9c, 0x36, 0x35, 0x50, 0x94, 0xb6, 0x04, 0x96, 0x57, 0x97, 0xec, 0x40, 0x4d, 0x66, 0x5c, 0x1d,
0xee, 0x6a, 0x21, 0x14, 0x5c, 0xa9, 0x84, 0xfb, 0xba, 0x4a, 0xd0, 0xa7, 0xd0, 0x38, 0x18, 0xf4,
0x1f, 0x24, 0x71, 0x3e, 0x59, 0x1a, 0xb1, 0x79, 0xb6, 0xd9, 0x95, 0x67, 0x5b, 0x47, 0x3d, 0x41,
0x54, 0x54, 0xf8, 0xea, 0xe8, 0xa8, 0x57, 0x87, 0xab, 0x11, 0x3e, 0xa5, 0x03, 0xd8, 0x52, 0xe1,
0xca, 0x89, 0x73, 0x99, 0xb1, 0x68, 0x5e, 0x11, 0x4e, 0xf9, 0x8a, 0x90, 0x46, 0xd5, 0xd4, 0xfd,
0x2f, 0x8d, 0xfe, 0x6e, 0xc3, 0x16, 0x13, 0x69, 0xf0, 0x42, 0xf4, 0xa3, 0x34, 0x4b, 0x72, 0x5f,
0x4e, 0x1c, 0xb9, 0xff, 0xf3, 0x78, 0xa8, 0x6b, 0xe1, 0x30, 0x25, 0xbc, 0xf9, 0x94, 0x10, 0x0a,
0xf5, 0xea, 0x10, 0xa8, 0x2e, 0x30, 0x0a, 0x72, 0x1b, 0xea, 0x83, 0x38, 0x4f, 0xfc, 0xa2, 0xf3,
0x71, 0x72, 0x2b, 0xff, 0x4a, 0xc1, 0xcc, 0x02, 0xf2, 0x10, 0xc8, 0x69, 0xc2, 0xa3, 0x34, 0xe4,
0x92, 0x92, 0xd9, 0xd6, 0x28, 0x9f, 0x27, 0x15, 0xed, 0x9c, 0x85, 0x25, 0xdb, 0xc8, 0x5e, 0xf5,
0x08, 0x7b, 0x75, 0xe4, 0xb7, 0x61, 0xf8, 0xe9, 0x73, 0x52, 0x3d, 0xe4, 0x77, 0x17, 0x3a, 0xd4,
0x5b, 0xc3, 0x2d, 0x5b, 0x72, 0xcb, 0x9c, 0x82, 0xcd, 0xaf, 0xa3, 0xdf, 0x59, 0xb0, 0x5e, 0x65,
0xb3, 0x62, 0x5c, 0x14, 0xe5, 0xb3, 0x57, 0xbf, 0x76, 0x4c, 0xf9, 0xdc, 0x65, 0x2f, 0xcb, 0x5a,
0xf5, 0x05, 0x14, 0xc3, 0x5b, 0xaf, 0x49, 0xce, 0xa5, 0xe8, 0x74, 0xa1, 0x75, 0xc2, 0x93, 0x2c,
0x90, 0xc6, 0xf4, 0x3d, 0x5d, 0x63, 0x55, 0x88, 0x0a, 0xb8, 0xfa, 0x4a, 0x13, 0x1d, 0xc6, 0xe3,
0x89, 0xec, 0xd6, 0x4b, 0x35, 0x93, 0x1c, 0xd3, 0x49, 0x12, 0x27, 0x26, 0x03, 0x28, 0xd0, 0x03,
0x68, 0x9c, 0xc6, 0x93, 0x38, 0x8c, 0x9f, 0xcd, 0x56, 0x8c, 0x0c, 0x0f, 0xea, 0xea, 0x6a, 0x50,
0x23, 0xaa, 0xc9, 0x8c, 0x48, 0xff, 0x2f, 0xfb, 0xdd, 0xe7, 0xa1, 0x9f, 0x87, 0x3c, 0x13, 0xf8,
0x3e, 0x46, 0xf0, 0x8b, 0x98, 0x8f, 0xd4, 0x54, 0xd0, 0x47, 0x8b, 0x7e, 0xa5, 0x1b, 0x90, 0x63,
0x38, 0x95, 0x2b, 0x68, 0x1f, 0x01, 0x73, 0x05, 0x29, 0x89, 0x7c, 0x08, 0xad, 0xca, 0x6a, 0x1d,
0xd6, 0x66, 0xd1, 0xa7, 0x0a, 0x66, 0xd5, 0x35, 0xf4, 0x57, 0x6b, 0x6e, 0xcf, 0x2b, 0x77, 0xae,
0x76, 0x75, 0xa1, 0x92, 0xd4, 0x60, 0x5a, 0x92, 0xa1, 0x1f, 0x4d, 0xfd, 0x30, 0x4f, 0xa5, 0x4a,
0x5f, 0xb8, 0x05, 0x20, 0x43, 0x97, 0xff, 0x81, 0x71, 0x6e, 0x1e, 0x37, 0x46, 0x94, 0xbf, 0x64,
0x3d, 0xc1, 0x47, 0x61, 0x10, 0x09, 0xec, 0x17, 0x87, 0x15, 0x32, 0xb9, 0xad, 0x66, 0xac, 0x69,
0xf4, 0xed, 0x05, 0xe2, 0xa8, 0x53, 0x93, 0x37, 0xa5, 0x04, 0x3a, 0x8b, 0x2a, 0xba, 0x0d, 0x44,
0x75, 0xc0, 0xfe, 0x30, 0x4e, 0xcc, 0x6d, 0x4b, 0x0f, 0xcd, 0x70, 0x91, 0xd9, 0x5f, 0x75, 0x89,
0x97, 0x99, 0xb5, 0xab, 0x99, 0x3d, 0xe8, 0xfc, 0xf6, 0x72, 0xc7, 0xfa, 0xe3, 0xe5, 0x8e, 0xf5,
0xe7, 0xcb, 0x1d, 0xeb, 0x97, 0xbf, 0x76, 0xfe, 0x37, 0x5c, 0xc3, 0xdf, 0xf5, 0x8f, 0xfe, 0x0e,
0x00, 0x00, 0xff, 0xff, 0x77, 0x8c, 0x9b, 0xf7, 0xd1, 0x0f, 0x00, 0x00,
}
func (m *IndexMeta) Marshal() (dAtA []byte, err error) {

View file

@ -1,6 +1,6 @@
syntax = "proto3";
package internal;
package pb;
import "public.proto";

View file

@ -1,7 +1,24 @@
// Copyright 2017 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 ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: public.proto
package internal
package pb
import (
encoding_binary "encoding/binary"
@ -2726,162 +2743,160 @@ func (m *GroupCounts) GetGroups() []*GroupCount {
}
func init() {
proto.RegisterType((*Row)(nil), "internal.Row")
proto.RegisterType((*RowMatrix)(nil), "internal.RowMatrix")
proto.RegisterType((*SignedRow)(nil), "internal.SignedRow")
proto.RegisterType((*RowIdentifiers)(nil), "internal.RowIdentifiers")
proto.RegisterType((*IDList)(nil), "internal.IDList")
proto.RegisterType((*ExtractedIDColumn)(nil), "internal.ExtractedIDColumn")
proto.RegisterType((*ExtractedIDMatrix)(nil), "internal.ExtractedIDMatrix")
proto.RegisterType((*KeyList)(nil), "internal.KeyList")
proto.RegisterType((*ExtractedTableValue)(nil), "internal.ExtractedTableValue")
proto.RegisterType((*ExtractedTableColumn)(nil), "internal.ExtractedTableColumn")
proto.RegisterType((*ExtractedTableField)(nil), "internal.ExtractedTableField")
proto.RegisterType((*ExtractedTable)(nil), "internal.ExtractedTable")
proto.RegisterType((*Pair)(nil), "internal.Pair")
proto.RegisterType((*PairField)(nil), "internal.PairField")
proto.RegisterType((*PairsField)(nil), "internal.PairsField")
proto.RegisterType((*Int64)(nil), "internal.Int64")
proto.RegisterType((*FieldRow)(nil), "internal.FieldRow")
proto.RegisterType((*GroupCount)(nil), "internal.GroupCount")
proto.RegisterType((*ValCount)(nil), "internal.ValCount")
proto.RegisterType((*Decimal)(nil), "internal.Decimal")
proto.RegisterType((*ColumnAttrSet)(nil), "internal.ColumnAttrSet")
proto.RegisterType((*Attr)(nil), "internal.Attr")
proto.RegisterType((*AttrMap)(nil), "internal.AttrMap")
proto.RegisterType((*QueryRequest)(nil), "internal.QueryRequest")
proto.RegisterType((*QueryResponse)(nil), "internal.QueryResponse")
proto.RegisterType((*QueryResult)(nil), "internal.QueryResult")
proto.RegisterType((*ImportRequest)(nil), "internal.ImportRequest")
proto.RegisterType((*ImportValueRequest)(nil), "internal.ImportValueRequest")
proto.RegisterType((*AtomicRecord)(nil), "internal.AtomicRecord")
proto.RegisterType((*AtomicImportResponse)(nil), "internal.AtomicImportResponse")
proto.RegisterType((*TranslateKeysRequest)(nil), "internal.TranslateKeysRequest")
proto.RegisterType((*TranslateKeysResponse)(nil), "internal.TranslateKeysResponse")
proto.RegisterType((*TranslateIDsRequest)(nil), "internal.TranslateIDsRequest")
proto.RegisterType((*TranslateIDsResponse)(nil), "internal.TranslateIDsResponse")
proto.RegisterType((*ImportRoaringRequestView)(nil), "internal.ImportRoaringRequestView")
proto.RegisterType((*ImportRoaringRequest)(nil), "internal.ImportRoaringRequest")
proto.RegisterType((*ImportColumnAttrsRequest)(nil), "internal.ImportColumnAttrsRequest")
proto.RegisterType((*GroupCounts)(nil), "internal.GroupCounts")
proto.RegisterType((*Row)(nil), "pb.Row")
proto.RegisterType((*RowMatrix)(nil), "pb.RowMatrix")
proto.RegisterType((*SignedRow)(nil), "pb.SignedRow")
proto.RegisterType((*RowIdentifiers)(nil), "pb.RowIdentifiers")
proto.RegisterType((*IDList)(nil), "pb.IDList")
proto.RegisterType((*ExtractedIDColumn)(nil), "pb.ExtractedIDColumn")
proto.RegisterType((*ExtractedIDMatrix)(nil), "pb.ExtractedIDMatrix")
proto.RegisterType((*KeyList)(nil), "pb.KeyList")
proto.RegisterType((*ExtractedTableValue)(nil), "pb.ExtractedTableValue")
proto.RegisterType((*ExtractedTableColumn)(nil), "pb.ExtractedTableColumn")
proto.RegisterType((*ExtractedTableField)(nil), "pb.ExtractedTableField")
proto.RegisterType((*ExtractedTable)(nil), "pb.ExtractedTable")
proto.RegisterType((*Pair)(nil), "pb.Pair")
proto.RegisterType((*PairField)(nil), "pb.PairField")
proto.RegisterType((*PairsField)(nil), "pb.PairsField")
proto.RegisterType((*Int64)(nil), "pb.Int64")
proto.RegisterType((*FieldRow)(nil), "pb.FieldRow")
proto.RegisterType((*GroupCount)(nil), "pb.GroupCount")
proto.RegisterType((*ValCount)(nil), "pb.ValCount")
proto.RegisterType((*Decimal)(nil), "pb.Decimal")
proto.RegisterType((*ColumnAttrSet)(nil), "pb.ColumnAttrSet")
proto.RegisterType((*Attr)(nil), "pb.Attr")
proto.RegisterType((*AttrMap)(nil), "pb.AttrMap")
proto.RegisterType((*QueryRequest)(nil), "pb.QueryRequest")
proto.RegisterType((*QueryResponse)(nil), "pb.QueryResponse")
proto.RegisterType((*QueryResult)(nil), "pb.QueryResult")
proto.RegisterType((*ImportRequest)(nil), "pb.ImportRequest")
proto.RegisterType((*ImportValueRequest)(nil), "pb.ImportValueRequest")
proto.RegisterType((*AtomicRecord)(nil), "pb.AtomicRecord")
proto.RegisterType((*AtomicImportResponse)(nil), "pb.AtomicImportResponse")
proto.RegisterType((*TranslateKeysRequest)(nil), "pb.TranslateKeysRequest")
proto.RegisterType((*TranslateKeysResponse)(nil), "pb.TranslateKeysResponse")
proto.RegisterType((*TranslateIDsRequest)(nil), "pb.TranslateIDsRequest")
proto.RegisterType((*TranslateIDsResponse)(nil), "pb.TranslateIDsResponse")
proto.RegisterType((*ImportRoaringRequestView)(nil), "pb.ImportRoaringRequestView")
proto.RegisterType((*ImportRoaringRequest)(nil), "pb.ImportRoaringRequest")
proto.RegisterType((*ImportColumnAttrsRequest)(nil), "pb.ImportColumnAttrsRequest")
proto.RegisterType((*GroupCounts)(nil), "pb.GroupCounts")
}
func init() { proto.RegisterFile("public.proto", fileDescriptor_413a91106d7bcce8) }
var fileDescriptor_413a91106d7bcce8 = []byte{
// 1779 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4f, 0x6f, 0x23, 0x49,
0x15, 0x4f, 0xbb, 0xdb, 0xb1, 0xfd, 0xec, 0x64, 0xb2, 0x35, 0x9e, 0xa5, 0x35, 0xcc, 0x64, 0x43,
0x2b, 0xb0, 0x06, 0xad, 0xb2, 0xca, 0xb0, 0x03, 0x73, 0xe0, 0xcf, 0x26, 0xe3, 0x2c, 0x69, 0x0d,
0x93, 0x1d, 0x2a, 0x43, 0x56, 0x5c, 0x90, 0x3a, 0x76, 0xe1, 0x6d, 0xd1, 0x76, 0x9b, 0x76, 0x79,
0x9d, 0x5c, 0x90, 0xf8, 0x02, 0x5c, 0xf6, 0xc2, 0x0d, 0x71, 0xe3, 0x73, 0x70, 0x81, 0x23, 0x47,
0x24, 0x2e, 0x68, 0x38, 0xf3, 0x1d, 0xd0, 0x7b, 0xd5, 0xd5, 0x55, 0xdd, 0xee, 0x64, 0xa3, 0xd1,
0xde, 0xea, 0xfd, 0xa9, 0x57, 0xf5, 0x7e, 0xef, 0xd5, 0x7b, 0xaf, 0x1b, 0x7a, 0xf3, 0xe5, 0x65,
0x12, 0x8f, 0x0e, 0xe6, 0x59, 0x2a, 0x53, 0xd6, 0x8e, 0x67, 0x52, 0x64, 0xb3, 0x28, 0x09, 0xfe,
0xec, 0x80, 0xcb, 0xd3, 0x15, 0xf3, 0xa1, 0xf5, 0x3c, 0x4d, 0x96, 0xd3, 0xd9, 0xc2, 0x77, 0xf6,
0xdc, 0x81, 0xc7, 0x35, 0xc9, 0x18, 0x78, 0x2f, 0xc4, 0xf5, 0xc2, 0x77, 0xf7, 0xdc, 0x41, 0x87,
0xd3, 0x9a, 0xed, 0x43, 0xf3, 0x48, 0xca, 0x6c, 0xe1, 0x37, 0xf6, 0xdc, 0x41, 0xf7, 0xc9, 0xf6,
0x81, 0xb6, 0x77, 0x80, 0x6c, 0xae, 0x84, 0x68, 0x93, 0xa7, 0x51, 0x16, 0xcf, 0x26, 0xbe, 0xb7,
0xe7, 0x0c, 0x7a, 0x5c, 0x93, 0xac, 0x0f, 0xcd, 0x70, 0x36, 0x16, 0x57, 0x7e, 0x73, 0xcf, 0x19,
0x74, 0xb8, 0x22, 0x90, 0xfb, 0x49, 0x2c, 0x92, 0xb1, 0xbf, 0xa9, 0xb8, 0x44, 0x04, 0x07, 0xd0,
0xe1, 0xe9, 0xea, 0x65, 0x24, 0xb3, 0xf8, 0x8a, 0x7d, 0x0b, 0x3c, 0x9e, 0xae, 0xd4, 0x1d, 0xbb,
0x4f, 0xb6, 0xcc, 0xb9, 0x3c, 0x5d, 0x71, 0x12, 0x05, 0x2f, 0xa1, 0x73, 0x1e, 0x4f, 0x66, 0x62,
0x8c, 0x6e, 0xbd, 0x07, 0xee, 0xab, 0x14, 0xd5, 0x9d, 0x75, 0x75, 0x94, 0xa0, 0xc2, 0x99, 0x98,
0xf8, 0x8d, 0x5a, 0x85, 0x33, 0x31, 0x09, 0x9e, 0xc1, 0x36, 0x4f, 0x57, 0xe1, 0x58, 0xcc, 0x64,
0xfc, 0x9b, 0x58, 0x64, 0x04, 0x48, 0x71, 0x07, 0x4f, 0x1d, 0x5a, 0x80, 0xd4, 0x30, 0x20, 0x05,
0x0f, 0x61, 0x33, 0x1c, 0xfe, 0x3c, 0x5e, 0x48, 0xb6, 0x03, 0x6e, 0x38, 0xd4, 0x1b, 0x70, 0x19,
0x84, 0xf0, 0xce, 0xc9, 0x95, 0xcc, 0xa2, 0x91, 0x14, 0xe3, 0x70, 0xa8, 0xa0, 0x66, 0xdb, 0xd0,
0x08, 0x87, 0x74, 0x57, 0x8f, 0x37, 0xc2, 0x21, 0xdb, 0x07, 0xef, 0x22, 0x4a, 0x34, 0xc8, 0x3b,
0xe6, 0x72, 0xca, 0x2c, 0x27, 0x69, 0x70, 0x59, 0x32, 0x95, 0xe3, 0xf4, 0x2e, 0x6c, 0x12, 0x7a,
0xea, 0xd0, 0x0e, 0xcf, 0x29, 0xf6, 0xd4, 0x84, 0x59, 0x59, 0xfd, 0xa6, 0xb1, 0xba, 0x76, 0xa1,
0x22, 0x07, 0x82, 0xc7, 0xd0, 0x7a, 0x21, 0xae, 0xc9, 0x17, 0xed, 0xa9, 0x63, 0x79, 0xfa, 0x6f,
0x07, 0xee, 0x17, 0xbb, 0x5f, 0x47, 0x97, 0x89, 0xb8, 0x88, 0x92, 0xa5, 0x60, 0xfb, 0xda, 0x6f,
0xa7, 0xee, 0xfe, 0xa7, 0x1b, 0x84, 0x05, 0x7b, 0xbf, 0xc0, 0x0e, 0xd5, 0xde, 0x31, 0x6a, 0xf9,
0x91, 0xa7, 0x1b, 0x79, 0xd6, 0x3d, 0x82, 0xf6, 0xf1, 0x79, 0x48, 0xa6, 0x7d, 0x77, 0xcf, 0x19,
0xb8, 0xa7, 0x1b, 0xbc, 0xe0, 0xb0, 0x87, 0xd0, 0x7a, 0xb9, 0x94, 0xe2, 0x2a, 0x1c, 0x52, 0xb6,
0x79, 0xa7, 0x1b, 0x5c, 0x33, 0x70, 0x27, 0x2d, 0x5f, 0x88, 0x6b, 0x95, 0x72, 0xb8, 0x53, 0x73,
0x58, 0x1f, 0xbc, 0xe3, 0x34, 0x4d, 0x28, 0xed, 0xda, 0x78, 0x1a, 0x52, 0xc7, 0x2d, 0x68, 0x92,
0xe1, 0xe0, 0xf7, 0xd0, 0x2f, 0x3b, 0x97, 0x87, 0x8b, 0x81, 0x8b, 0xf6, 0x9c, 0xdc, 0x1e, 0x12,
0x6c, 0x87, 0x42, 0xd8, 0xc8, 0xcf, 0xc7, 0x20, 0x3e, 0x85, 0x4d, 0x32, 0xa3, 0x1e, 0x50, 0xf7,
0xc9, 0xe3, 0x1a, 0xc0, 0x0d, 0x64, 0x3c, 0x57, 0x3e, 0xee, 0x10, 0xe2, 0x9f, 0x66, 0xe1, 0x30,
0xf8, 0x71, 0x15, 0x5c, 0x8a, 0x25, 0x06, 0xe2, 0x2c, 0x9a, 0x0a, 0x75, 0x3e, 0xa7, 0x35, 0xf2,
0x5e, 0x5f, 0xcf, 0x05, 0x5d, 0xa0, 0xc3, 0x69, 0x1d, 0xfc, 0xc1, 0x81, 0xed, 0xf2, 0x7e, 0xbc,
0x93, 0x95, 0x1d, 0xb7, 0xdc, 0x89, 0xb4, 0x8a, 0xe4, 0x79, 0x56, 0x4d, 0x9e, 0xdd, 0x9b, 0xf6,
0x55, 0xf3, 0xe7, 0x27, 0xe0, 0xbd, 0x8a, 0xe2, 0x6c, 0x2d, 0xc3, 0x77, 0x14, 0x84, 0x2e, 0x5d,
0xd7, 0x55, 0xb1, 0x68, 0x3e, 0x4f, 0x97, 0x33, 0xa9, 0x30, 0xe4, 0x8a, 0x08, 0x4e, 0xa0, 0x83,
0xfb, 0x95, 0xe3, 0x81, 0x32, 0x96, 0xa7, 0x95, 0x55, 0x7b, 0x90, 0xcb, 0xd5, 0x41, 0x45, 0x29,
0x69, 0xd8, 0xa5, 0xe4, 0x14, 0x00, 0xa5, 0x0b, 0x65, 0x67, 0x1f, 0x9a, 0x44, 0xe5, 0x20, 0x54,
0x0d, 0x29, 0xe1, 0x0d, 0x96, 0x1e, 0x63, 0x01, 0x93, 0x3f, 0xf8, 0x08, 0xc5, 0x2a, 0x21, 0xf1,
0x36, 0x2e, 0xcf, 0x53, 0x66, 0x09, 0x6d, 0x05, 0x5d, 0xba, 0x32, 0x06, 0x1c, 0xcb, 0x00, 0x72,
0xb1, 0xac, 0x0c, 0xb5, 0x9f, 0x44, 0xe0, 0xb3, 0xe5, 0xe9, 0xca, 0x40, 0x92, 0x53, 0xec, 0xdb,
0xfa, 0x14, 0x8f, 0x7c, 0xbe, 0x67, 0x3d, 0x25, 0xbc, 0x85, 0x3e, 0xf6, 0xd7, 0x00, 0x3f, 0xcb,
0xd2, 0xe5, 0x9c, 0x40, 0x63, 0x03, 0x68, 0x12, 0x95, 0xfb, 0xc7, 0xcc, 0x26, 0x7d, 0x37, 0xae,
0x14, 0xea, 0x41, 0xc7, 0xe0, 0x1c, 0x4d, 0x26, 0xea, 0xa5, 0x71, 0x5c, 0x62, 0x2a, 0xb5, 0x2f,
0xa2, 0xa4, 0x10, 0x5f, 0x44, 0x49, 0xee, 0x37, 0x2e, 0xcb, 0x66, 0x5c, 0x6d, 0xe6, 0x21, 0xb4,
0x3f, 0x49, 0xd2, 0x48, 0xa2, 0x32, 0xda, 0x72, 0x78, 0x41, 0xb3, 0x43, 0x80, 0xa1, 0x18, 0xc5,
0xd3, 0x28, 0x41, 0xa9, 0x57, 0x2d, 0x00, 0xb9, 0x8c, 0x5b, 0x4a, 0xc1, 0x53, 0x68, 0xe5, 0x54,
0x3d, 0xf6, 0xc8, 0x3d, 0x1f, 0x45, 0x89, 0xd0, 0xb7, 0x20, 0x22, 0xf8, 0x0c, 0xb6, 0x54, 0x32,
0x62, 0x6b, 0x3a, 0x17, 0xf2, 0x0e, 0xa9, 0x78, 0xa7, 0x26, 0x17, 0xfc, 0xd5, 0x01, 0x0f, 0x57,
0xda, 0x80, 0x63, 0x0c, 0xd8, 0xaf, 0xd1, 0x53, 0xaf, 0x91, 0xed, 0x41, 0xf7, 0x5c, 0x62, 0x0f,
0x34, 0x65, 0xac, 0xc3, 0x6d, 0x16, 0xe2, 0x15, 0xce, 0xa4, 0x09, 0xb7, 0xcb, 0x0b, 0x9a, 0x3d,
0x82, 0x0e, 0xd6, 0x26, 0x25, 0xc4, 0x42, 0xd6, 0xe6, 0x86, 0xc1, 0x76, 0x01, 0x34, 0xb2, 0x4b,
0x41, 0xd5, 0xcc, 0xe1, 0x16, 0x27, 0xf8, 0x10, 0x5a, 0x78, 0xd3, 0x97, 0xd1, 0xdc, 0xf8, 0xe6,
0xdc, 0xe6, 0xdb, 0x5f, 0x1a, 0xd0, 0xfb, 0xc5, 0x52, 0x64, 0xd7, 0x5c, 0xfc, 0x6e, 0x29, 0x16,
0x12, 0xb1, 0x25, 0x5a, 0xe7, 0x32, 0x11, 0x98, 0xb5, 0xe7, 0x9f, 0x47, 0xd9, 0x58, 0x21, 0xe5,
0xf1, 0x9c, 0x42, 0x5f, 0x0d, 0xe6, 0x0b, 0xf2, 0xb5, 0xcd, 0x6d, 0x16, 0xe5, 0xbb, 0x98, 0xa6,
0x52, 0x3b, 0x93, 0x53, 0x6c, 0x00, 0xf7, 0x4e, 0xae, 0x46, 0xc9, 0x72, 0x2c, 0x78, 0xba, 0x52,
0xbb, 0xa9, 0x38, 0xf3, 0x2a, 0x9b, 0x7d, 0x07, 0x8b, 0x1b, 0xb1, 0x74, 0x69, 0x6a, 0x91, 0x62,
0x85, 0xcb, 0x0e, 0xa1, 0x77, 0x32, 0xbd, 0x14, 0xe3, 0xb1, 0x18, 0x0f, 0x23, 0x19, 0xf9, 0xed,
0xba, 0x01, 0xa2, 0xa4, 0xc2, 0xf6, 0x61, 0xeb, 0x55, 0x26, 0x5e, 0x67, 0xd1, 0x6c, 0x91, 0x44,
0x52, 0x8c, 0xfd, 0x0e, 0x59, 0x2e, 0x33, 0x83, 0x2f, 0x1d, 0xd8, 0xca, 0x31, 0x5a, 0xcc, 0xd3,
0xd9, 0x42, 0x60, 0x22, 0x9c, 0x64, 0x99, 0x4e, 0x84, 0x93, 0x2c, 0x63, 0x1f, 0x42, 0x8b, 0x8b,
0xc5, 0x32, 0x91, 0x3a, 0x97, 0x1e, 0x98, 0x73, 0xf5, 0xde, 0x65, 0x22, 0xb9, 0xd6, 0x62, 0x3f,
0x85, 0xed, 0x52, 0xb6, 0xea, 0xe6, 0xf1, 0x0d, 0xb3, 0xaf, 0x24, 0xe7, 0x15, 0xf5, 0xe0, 0x7f,
0x4d, 0xe8, 0x5a, 0x96, 0x8b, 0x54, 0x44, 0x14, 0xb7, 0xf2, 0x54, 0x7c, 0x8f, 0x26, 0xbf, 0x1b,
0x66, 0x23, 0xac, 0x5c, 0x3d, 0x70, 0xce, 0xf2, 0xe4, 0x75, 0xce, 0x4c, 0xb9, 0x74, 0x6f, 0x2b,
0x97, 0x38, 0x47, 0x7e, 0x1e, 0xcd, 0x26, 0x62, 0x4c, 0xc9, 0xdb, 0xe6, 0x9a, 0x64, 0x07, 0xa6,
0x76, 0x50, 0xb4, 0x4b, 0x15, 0x49, 0x4b, 0xb8, 0xa9, 0x2f, 0xaa, 0x16, 0xe2, 0xfc, 0xd0, 0x52,
0x59, 0xa5, 0x28, 0xf6, 0x23, 0xd8, 0xfe, 0x34, 0x19, 0x9b, 0x3a, 0xb7, 0xc8, 0x63, 0xd9, 0x37,
0xd6, 0x8c, 0x90, 0x57, 0x74, 0xd9, 0xc7, 0xd5, 0x71, 0x8e, 0xa2, 0xda, 0x7d, 0xe2, 0x97, 0xfc,
0xb7, 0xe4, 0xbc, 0x3a, 0xfe, 0x1d, 0x5a, 0xf3, 0xa5, 0x0f, 0xb4, 0xf9, 0xbe, 0xd9, 0x5c, 0x88,
0xb8, 0x35, 0x85, 0x7e, 0x64, 0xf7, 0x1d, 0xbf, 0x4b, 0x7b, 0xfa, 0x65, 0xfc, 0x94, 0x8c, 0xdb,
0xfd, 0xe9, 0xd0, 0x6a, 0x7a, 0x7e, 0xaf, 0x7a, 0x50, 0x21, 0xe2, 0x56, 0x6b, 0x0c, 0x6b, 0x66,
0x41, 0x7f, 0x8b, 0xb6, 0xd6, 0x0f, 0x7a, 0x4a, 0x85, 0xd7, 0x4c, 0x90, 0x1f, 0x57, 0xa7, 0x06,
0x7f, 0xbb, 0x0a, 0x54, 0x59, 0xce, 0xab, 0x53, 0xc6, 0xa1, 0x35, 0xb8, 0xfb, 0xf7, 0xaa, 0xf7,
0x2f, 0x44, 0xdc, 0x1a, 0xef, 0x7f, 0x08, 0x5d, 0x3b, 0xb0, 0x3b, 0xb4, 0xe9, 0x41, 0x5d, 0x60,
0x17, 0xdc, 0xd6, 0x0c, 0xfe, 0xde, 0x80, 0xad, 0x70, 0x3a, 0x4f, 0x33, 0x69, 0x95, 0x2a, 0xf5,
0x89, 0xe1, 0xd4, 0x7e, 0x62, 0x34, 0x2a, 0xcd, 0x98, 0x4a, 0x16, 0x95, 0x28, 0x8f, 0x2b, 0xc2,
0x4a, 0x40, 0xaf, 0x94, 0x80, 0x8f, 0xa0, 0xa3, 0x5e, 0x1b, 0x8a, 0x9a, 0x24, 0x32, 0x0c, 0xf5,
0xd1, 0xb3, 0xa2, 0x81, 0xb6, 0x45, 0x23, 0xb2, 0x26, 0xb1, 0x3c, 0x2b, 0x35, 0x12, 0xb6, 0x49,
0x68, 0x71, 0x50, 0xfe, 0x3a, 0x9e, 0x8a, 0x85, 0x8c, 0xa6, 0x73, 0xac, 0x77, 0xee, 0xc0, 0xe5,
0x16, 0x07, 0x4b, 0x1d, 0x39, 0xf1, 0x3c, 0x13, 0x58, 0x79, 0x8e, 0x24, 0xa5, 0xae, 0xcb, 0x2b,
0x5c, 0xd4, 0x23, 0xb7, 0x8c, 0x1e, 0x28, 0xbd, 0x32, 0x97, 0xda, 0x75, 0x22, 0xa2, 0x8c, 0x12,
0xb2, 0xcd, 0x15, 0x11, 0xfc, 0xab, 0x01, 0x4c, 0x21, 0xa9, 0x06, 0xd2, 0xaf, 0x0d, 0xce, 0xdb,
0x61, 0x2b, 0x83, 0xd3, 0x5a, 0x03, 0xe7, 0xdd, 0x62, 0x8c, 0x56, 0xc0, 0xe4, 0x14, 0xf6, 0x18,
0xd3, 0xe1, 0x14, 0xaa, 0x0e, 0xb7, 0x59, 0x2c, 0x80, 0x9e, 0xd5, 0x5e, 0xf1, 0xbd, 0xa3, 0xed,
0x12, 0xaf, 0x06, 0x5a, 0xb8, 0x23, 0xb4, 0xdd, 0xdb, 0xa1, 0xed, 0xd9, 0xd0, 0x7e, 0xe9, 0x40,
0xef, 0x48, 0xa6, 0xd3, 0x78, 0xc4, 0xc5, 0x28, 0xcd, 0xc6, 0x37, 0x83, 0xaa, 0xe0, 0x6b, 0xd8,
0xf0, 0x1d, 0x80, 0x1b, 0x7e, 0x91, 0xe5, 0xc5, 0xf7, 0x91, 0x35, 0x00, 0xae, 0xc5, 0x8a, 0xa3,
0x22, 0x7b, 0x1f, 0x1a, 0x61, 0x46, 0x99, 0x5b, 0x6a, 0x1b, 0xa5, 0x47, 0xc2, 0x1b, 0x61, 0x16,
0x7c, 0x00, 0x7d, 0x75, 0x29, 0x2d, 0xca, 0xdb, 0x58, 0x1f, 0x9a, 0x27, 0x59, 0x96, 0xea, 0x46,
0xa6, 0x88, 0xe0, 0x0a, 0xfa, 0x45, 0xf3, 0xc3, 0xc0, 0xbc, 0x4d, 0x7e, 0xd4, 0xfd, 0x51, 0xd8,
0x83, 0xee, 0x59, 0x2a, 0x3f, 0xcb, 0x62, 0x49, 0xb5, 0x46, 0xf5, 0x0e, 0x9b, 0x15, 0x7c, 0x17,
0x1e, 0x54, 0x4e, 0x36, 0xfd, 0x16, 0x53, 0xca, 0x35, 0x5f, 0xd7, 0xe7, 0x70, 0xbf, 0x50, 0x0d,
0x87, 0x6f, 0x75, 0xc7, 0x75, 0xa3, 0xdf, 0xb3, 0x3c, 0x27, 0xa3, 0xf9, 0xf1, 0x35, 0xde, 0x04,
0xc7, 0xe0, 0xe7, 0x68, 0xaa, 0x1f, 0x1e, 0xf9, 0x0d, 0x2e, 0x62, 0xb1, 0xba, 0xe9, 0xbb, 0x8d,
0xa6, 0x92, 0x06, 0xfd, 0x26, 0xa1, 0x75, 0xf0, 0xc7, 0x06, 0xf4, 0xeb, 0x8c, 0x98, 0xe4, 0x72,
0xac, 0xe4, 0x62, 0xcf, 0xa0, 0xf9, 0x45, 0x2c, 0x56, 0x7a, 0xc2, 0x08, 0xd6, 0x42, 0xbe, 0x76,
0x13, 0xae, 0x36, 0xe0, 0xd3, 0x3a, 0x1a, 0xc9, 0x38, 0x9d, 0xe9, 0x8f, 0x0e, 0x45, 0xe1, 0x39,
0xc7, 0x49, 0x3a, 0xfa, 0xad, 0xfa, 0x9c, 0xe6, 0x8a, 0xa8, 0x79, 0x2a, 0xcd, 0x3b, 0x3e, 0x95,
0xcd, 0xda, 0xa7, 0x32, 0x80, 0x7b, 0xbf, 0x9c, 0x8f, 0x23, 0x29, 0x4e, 0xae, 0xe2, 0x85, 0x14,
0xb3, 0x91, 0xc8, 0x27, 0xb8, 0x2a, 0x3b, 0xf8, 0x9b, 0xa3, 0x51, 0xb5, 0x46, 0xc8, 0xaf, 0x8c,
0xad, 0x79, 0x4a, 0xae, 0x7e, 0x4a, 0xbe, 0x9a, 0x83, 0xcd, 0xb8, 0xaf, 0x49, 0x9c, 0xbd, 0x71,
0x49, 0x7f, 0x5d, 0x3c, 0x8a, 0x67, 0x41, 0x7f, 0x45, 0xfd, 0x5a, 0x87, 0x65, 0xb3, 0x0e, 0x96,
0xe0, 0x57, 0xa5, 0x0e, 0x87, 0x46, 0x8f, 0x26, 0x93, 0x4c, 0x4c, 0x22, 0xa9, 0x33, 0xc2, 0x30,
0xd8, 0x07, 0xb0, 0x49, 0xca, 0x3a, 0xa8, 0xf5, 0x23, 0x4e, 0xae, 0x73, 0xbc, 0xf3, 0x8f, 0x37,
0xbb, 0xce, 0x3f, 0xdf, 0xec, 0x3a, 0xff, 0x79, 0xb3, 0xeb, 0xfc, 0xe9, 0xbf, 0xbb, 0x1b, 0x97,
0x9b, 0xf4, 0xb7, 0xef, 0xfb, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xa8, 0x3e, 0x99, 0xfd,
0x13, 0x00, 0x00,
// 1754 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x5f, 0x6f, 0x23, 0x49,
0x11, 0xcf, 0xfc, 0xf1, 0xbf, 0xb2, 0xe3, 0xe4, 0xfa, 0x72, 0xcb, 0xdc, 0x92, 0x33, 0xbe, 0x11,
0x3a, 0x79, 0x09, 0xca, 0x89, 0x00, 0x27, 0x38, 0x09, 0x50, 0x1c, 0xe7, 0xc8, 0x68, 0xd9, 0xdc,
0x5e, 0x3b, 0x04, 0x1e, 0x78, 0x99, 0xd8, 0x8d, 0x6f, 0xc4, 0xd8, 0x63, 0xc6, 0xe3, 0x73, 0x22,
0x3e, 0xc0, 0xf1, 0x11, 0x40, 0x3c, 0x23, 0xf1, 0x39, 0x78, 0x81, 0x37, 0x78, 0xe4, 0x11, 0x2d,
0x5f, 0x04, 0x55, 0x75, 0xf7, 0x4c, 0xcf, 0xd8, 0x7b, 0xbb, 0x5a, 0xdd, 0x5b, 0xd7, 0x9f, 0xae,
0xee, 0xfa, 0x55, 0x75, 0x55, 0xcd, 0x40, 0x67, 0xb9, 0xbe, 0x8b, 0xa3, 0xc9, 0xe9, 0x32, 0x4d,
0xb2, 0x84, 0xd9, 0xcb, 0x3b, 0xff, 0xcf, 0x16, 0x38, 0x3c, 0xd9, 0x30, 0x0f, 0x1a, 0x17, 0x49,
0xbc, 0x9e, 0x2f, 0x56, 0x9e, 0xd5, 0x77, 0x06, 0x2e, 0xd7, 0x24, 0x63, 0xe0, 0x3e, 0x15, 0x0f,
0x2b, 0xcf, 0xe9, 0x3b, 0x83, 0x16, 0xa7, 0x35, 0xeb, 0x41, 0xed, 0x3c, 0xcb, 0xd2, 0x95, 0x67,
0xf7, 0x9d, 0x41, 0xfb, 0xac, 0x79, 0xba, 0xbc, 0x3b, 0x45, 0x06, 0x97, 0x6c, 0xb4, 0xc6, 0x93,
0x30, 0x8d, 0x16, 0x33, 0xcf, 0xed, 0x5b, 0x83, 0x0e, 0xd7, 0x24, 0x3b, 0x82, 0x5a, 0xb0, 0x98,
0x8a, 0x7b, 0xaf, 0xd6, 0xb7, 0x06, 0x2d, 0x2e, 0x09, 0xe4, 0x7e, 0x12, 0x89, 0x78, 0xea, 0xd5,
0x25, 0x97, 0x08, 0x7f, 0x00, 0x2d, 0x9e, 0x6c, 0x9e, 0x85, 0x59, 0x1a, 0xdd, 0xb3, 0x6f, 0x82,
0xcb, 0x93, 0x8d, 0xbc, 0x5d, 0xfb, 0xac, 0x81, 0x27, 0xf2, 0x64, 0xc3, 0x89, 0xe9, 0x9f, 0x43,
0x6b, 0x1c, 0xcd, 0x16, 0x62, 0x8a, 0xae, 0xbc, 0x0b, 0xce, 0xf3, 0x04, 0x15, 0x2d, 0x53, 0x11,
0x79, 0x28, 0xba, 0x16, 0x33, 0xcf, 0xae, 0x88, 0xae, 0xc5, 0xcc, 0xff, 0x11, 0x74, 0x79, 0xb2,
0x09, 0xa6, 0x62, 0x91, 0x45, 0xbf, 0x8d, 0x44, 0x4a, 0x8e, 0xe7, 0x27, 0xba, 0xf2, 0xa0, 0x1c,
0x0c, 0xbb, 0x00, 0xc3, 0x7f, 0x0c, 0xf5, 0x60, 0xf4, 0x8b, 0x68, 0x95, 0xb1, 0x43, 0x70, 0x82,
0x91, 0xde, 0x80, 0x4b, 0xff, 0x02, 0xde, 0xba, 0xbc, 0xcf, 0xd2, 0x70, 0x92, 0x89, 0x69, 0x30,
0x92, 0x90, 0xb2, 0x2e, 0xd8, 0xc1, 0x88, 0xee, 0xe7, 0x72, 0x3b, 0x18, 0xb1, 0x1e, 0xb8, 0xb7,
0x61, 0xac, 0xc1, 0x04, 0xbc, 0x96, 0x34, 0xc8, 0x89, 0xef, 0xff, 0xa6, 0x64, 0x44, 0xe1, 0xf1,
0x08, 0xea, 0x84, 0x92, 0x3c, 0xae, 0xc5, 0x15, 0xc5, 0x3e, 0x2c, 0x02, 0x29, 0xed, 0xbd, 0x83,
0xf6, 0xb6, 0x2e, 0x91, 0xc7, 0xd7, 0x7f, 0x0f, 0x1a, 0x4f, 0xc5, 0x03, 0xdd, 0x5f, 0x7b, 0x67,
0x19, 0xde, 0xfd, 0xcb, 0x82, 0xb7, 0xf3, 0xdd, 0x37, 0xe1, 0x5d, 0x2c, 0x6e, 0xc3, 0x78, 0x2d,
0x58, 0x4f, 0xfb, 0x6a, 0x95, 0xef, 0x7c, 0xb5, 0x47, 0x9e, 0xb3, 0xf7, 0x73, 0xa4, 0x50, 0xa1,
0x8d, 0x0a, 0xea, 0x98, 0xab, 0x3d, 0x95, 0x45, 0xc7, 0xd0, 0x1c, 0x8e, 0x03, 0x32, 0xe7, 0x39,
0x7d, 0x6b, 0xe0, 0x5c, 0xed, 0xf1, 0x9c, 0xc3, 0x1e, 0x43, 0xe3, 0xd9, 0x3a, 0x13, 0xf7, 0xc1,
0x88, 0x72, 0xc8, 0xbd, 0xda, 0xe3, 0x9a, 0x81, 0x3b, 0x69, 0xf9, 0x54, 0x3c, 0xc8, 0x44, 0xc2,
0x9d, 0x9a, 0xc3, 0x8e, 0xc0, 0x1d, 0x26, 0x49, 0x4c, 0xc9, 0xd4, 0xc4, 0xd3, 0x90, 0x1a, 0x36,
0xa0, 0x46, 0x86, 0xfd, 0x7b, 0x38, 0x2a, 0x3b, 0xa4, 0xc2, 0xc2, 0xc0, 0x41, 0x7b, 0x96, 0xb2,
0x87, 0x04, 0x3b, 0xa4, 0x50, 0xd9, 0xea, 0x7c, 0x0c, 0xd6, 0x87, 0x50, 0x27, 0x33, 0xf2, 0x41,
0xb4, 0xcf, 0xbe, 0x51, 0x82, 0xb7, 0x00, 0x88, 0x2b, 0xb5, 0x61, 0x8b, 0xf0, 0xfd, 0x34, 0x0d,
0x46, 0xfe, 0x4f, 0xaa, 0x50, 0x52, 0xcc, 0x10, 0xf6, 0xeb, 0x70, 0x2e, 0xe4, 0xc9, 0x9c, 0xd6,
0xc8, 0xbb, 0x79, 0x58, 0x0a, 0x3a, 0xba, 0xc5, 0x69, 0xed, 0xaf, 0xa1, 0x5b, 0xde, 0x8e, 0x97,
0x31, 0x92, 0x60, 0xe7, 0x65, 0x48, 0x9e, 0x67, 0xc7, 0x59, 0x35, 0x3b, 0xbc, 0xed, 0x1d, 0xd5,
0x04, 0xf9, 0x29, 0xb8, 0xcf, 0xc3, 0x28, 0xdd, 0x4a, 0xdb, 0x43, 0x89, 0x97, 0x43, 0x37, 0x74,
0x24, 0xf0, 0xb5, 0x8b, 0x64, 0xbd, 0xc8, 0x24, 0x60, 0x5c, 0x12, 0xfe, 0xcf, 0xa0, 0x85, 0xfb,
0xa5, 0xaf, 0xc7, 0xd2, 0x98, 0xca, 0x1b, 0x2a, 0x1c, 0x48, 0x73, 0x79, 0x44, 0x5e, 0x07, 0x6c,
0xb3, 0x0e, 0x0c, 0x01, 0x50, 0xba, 0x92, 0x16, 0x7a, 0x50, 0x23, 0x4a, 0xb9, 0x5c, 0x98, 0x90,
0xec, 0x97, 0xd8, 0x78, 0x0f, 0xeb, 0x4e, 0xf6, 0xd1, 0x0f, 0x50, 0x2c, 0x33, 0x0e, 0x6f, 0xe0,
0x70, 0x95, 0x13, 0x09, 0x34, 0x25, 0x50, 0xc9, 0xa6, 0x30, 0x60, 0x19, 0x06, 0x90, 0x8b, 0xf5,
0x61, 0xa4, 0x7d, 0x23, 0x02, 0x5f, 0x21, 0x4f, 0x36, 0x05, 0x0c, 0x8a, 0x62, 0xdf, 0xd2, 0xa7,
0xb8, 0xe4, 0x67, 0x8b, 0xde, 0x07, 0x9e, 0xaf, 0x0f, 0xfc, 0x35, 0xc0, 0xcf, 0xd3, 0x64, 0xbd,
0x24, 0x88, 0x98, 0x0f, 0x35, 0xa2, 0x94, 0x4f, 0x1d, 0x54, 0xd7, 0xf7, 0xe1, 0x52, 0xb4, 0x1b,
0x5c, 0x0c, 0xc2, 0xf9, 0x6c, 0x26, 0x9f, 0x0f, 0xc7, 0xa5, 0xff, 0x07, 0x68, 0xde, 0x86, 0x71,
0x2e, 0xbd, 0x0d, 0x63, 0xe5, 0x2a, 0x2e, 0xcb, 0x56, 0x1c, 0x6d, 0xe5, 0x31, 0x34, 0x3f, 0x89,
0x93, 0x30, 0x43, 0x65, 0x34, 0x65, 0xf1, 0x9c, 0x66, 0x27, 0x00, 0x23, 0x31, 0x89, 0xe6, 0x61,
0x8c, 0x52, 0xb7, 0x78, 0xce, 0x8a, 0xcb, 0x0d, 0xb1, 0xff, 0x43, 0x68, 0x28, 0x6a, 0x37, 0xd0,
0xc8, 0x1d, 0x4f, 0xc2, 0x58, 0xe8, 0xf3, 0x89, 0xf0, 0x3f, 0x83, 0x7d, 0x99, 0x6d, 0xd8, 0x3e,
0xc6, 0x22, 0x7b, 0x8d, 0x5c, 0x7b, 0x45, 0x0b, 0xf2, 0xff, 0x66, 0x81, 0x8b, 0x2b, 0xbd, 0xd5,
0x2a, 0xb6, 0x9a, 0x6f, 0xcb, 0x95, 0x6f, 0x8b, 0xf5, 0xa1, 0x3d, 0xce, 0xb0, 0x43, 0x15, 0xe5,
0xa8, 0xc5, 0x4d, 0x16, 0x62, 0x14, 0x2c, 0xb2, 0x22, 0xaa, 0x0e, 0xcf, 0x69, 0x76, 0x0c, 0x2d,
0xac, 0x31, 0x52, 0x88, 0x05, 0xa9, 0xc9, 0x0b, 0x06, 0xeb, 0x01, 0x68, 0x34, 0xd7, 0x82, 0xaa,
0x92, 0xc5, 0x0d, 0x8e, 0xff, 0x04, 0x1a, 0x78, 0xd3, 0x67, 0xe1, 0xb2, 0xf0, 0xca, 0xda, 0xed,
0xd5, 0x5f, 0x6c, 0xe8, 0x7c, 0xb6, 0x16, 0xe9, 0x03, 0x17, 0xbf, 0x5f, 0x8b, 0x55, 0x86, 0x78,
0x12, 0xad, 0x93, 0x95, 0x08, 0x4c, 0xcb, 0xf1, 0xe7, 0x61, 0x3a, 0x95, 0xe8, 0xb8, 0x5c, 0x51,
0xe8, 0x65, 0x81, 0xf3, 0x8a, 0xbc, 0x6c, 0x72, 0x93, 0x45, 0x09, 0x2d, 0xe6, 0x49, 0xa6, 0xdd,
0x50, 0x14, 0x1b, 0xc0, 0xc1, 0xe5, 0xfd, 0x24, 0x5e, 0x4f, 0x05, 0x4f, 0x36, 0x72, 0x37, 0x95,
0x57, 0x5e, 0x65, 0xb3, 0x0f, 0xb0, 0x4a, 0x11, 0x4b, 0x57, 0x9a, 0x06, 0x29, 0x56, 0xb8, 0xec,
0x04, 0x3a, 0x97, 0xf3, 0x3b, 0x31, 0x9d, 0x8a, 0xe9, 0x28, 0xcc, 0x42, 0xaf, 0x59, 0x6e, 0xec,
0x25, 0x21, 0xfb, 0x36, 0xec, 0x3f, 0x4f, 0xc5, 0x4d, 0x1a, 0x2e, 0x56, 0x71, 0x98, 0x89, 0xa9,
0xd7, 0x22, 0x9b, 0x65, 0xa6, 0xff, 0xa5, 0x05, 0xfb, 0x0a, 0x9d, 0xd5, 0x32, 0x59, 0xac, 0x04,
0x06, 0xff, 0x32, 0x4d, 0x75, 0xf0, 0x2f, 0xd3, 0x94, 0x3d, 0x81, 0x06, 0x17, 0xab, 0x75, 0x9c,
0xe9, 0xcc, 0x39, 0xc0, 0x13, 0xf5, 0xae, 0x75, 0x9c, 0x71, 0x2d, 0x67, 0x3f, 0x86, 0x6e, 0x29,
0x2b, 0x75, 0xc9, 0x7f, 0x0b, 0x77, 0x94, 0x24, 0xbc, 0xa2, 0xe8, 0xff, 0xb5, 0x06, 0x6d, 0xc3,
0x66, 0x9e, 0x72, 0x88, 0xd9, 0xbe, 0x4a, 0xb9, 0x77, 0x69, 0xf2, 0xda, 0x9a, 0x53, 0xb0, 0x04,
0x75, 0xc0, 0xba, 0x56, 0xe9, 0x69, 0x5d, 0x17, 0x15, 0xcf, 0xd9, 0x5d, 0xf1, 0x70, 0x76, 0xfb,
0x3c, 0x5c, 0xcc, 0xc4, 0x94, 0x12, 0xb3, 0xc9, 0x35, 0xc9, 0x06, 0x45, 0x2d, 0xa0, 0x78, 0xaa,
0xd2, 0xa2, 0x79, 0xbc, 0xa8, 0x14, 0xb2, 0x90, 0x61, 0x47, 0x6f, 0xc8, 0x8c, 0x91, 0x14, 0xfb,
0x08, 0xba, 0x9f, 0xc6, 0xd3, 0xa2, 0x54, 0xad, 0x54, 0x9c, 0xba, 0x68, 0xa7, 0x60, 0xf3, 0x8a,
0x16, 0xfb, 0xb8, 0x3a, 0x4e, 0x51, 0xc4, 0xda, 0x67, 0x4c, 0xf9, 0x69, 0x48, 0x78, 0x75, 0xf0,
0x3a, 0x31, 0xa6, 0x39, 0x0f, 0x68, 0xdb, 0x3e, 0x6e, 0xcb, 0x99, 0xdc, 0x98, 0xf6, 0x4e, 0xcd,
0xe6, 0xe0, 0xb5, 0x49, 0xbb, 0xab, 0x11, 0x92, 0x5c, 0x6e, 0xb6, 0x8f, 0x13, 0xa3, 0x1b, 0x79,
0x9d, 0xc2, 0x78, 0xce, 0xe4, 0x46, 0xb7, 0xba, 0xd8, 0x31, 0x79, 0x79, 0xfb, 0xb4, 0xa9, 0x3a,
0x56, 0x49, 0x21, 0xdf, 0x31, 0xa9, 0x7d, 0x5c, 0x6d, 0xdb, 0x5e, 0xb7, 0x80, 0xa2, 0x2c, 0xe1,
0xd5, 0x06, 0x7f, 0x62, 0x8c, 0xc0, 0xde, 0x41, 0x71, 0xdb, 0x9c, 0xc9, 0x8d, 0x11, 0xf9, 0x7b,
0xd0, 0x36, 0x03, 0x75, 0x48, 0xea, 0x07, 0xe5, 0x40, 0xad, 0xb8, 0xa9, 0xe3, 0xff, 0xc3, 0x86,
0xfd, 0x60, 0xbe, 0x4c, 0xd2, 0xcc, 0x28, 0x28, 0x72, 0x40, 0xb7, 0x76, 0x0e, 0xe8, 0x76, 0xa5,
0x27, 0x52, 0x61, 0xa1, 0x42, 0xe2, 0x72, 0x49, 0x18, 0xa9, 0xe4, 0x96, 0x52, 0xe9, 0x18, 0x5a,
0xf2, 0x95, 0xa0, 0xa8, 0x46, 0xa2, 0x82, 0x21, 0x3f, 0x19, 0x36, 0x34, 0x32, 0x36, 0x68, 0xfc,
0xd4, 0x24, 0x96, 0x4f, 0xa9, 0x46, 0xc2, 0x26, 0x09, 0x0d, 0x0e, 0xca, 0x6f, 0xa2, 0xb9, 0x58,
0x65, 0xe1, 0x7c, 0x89, 0x55, 0xc9, 0x19, 0x38, 0xdc, 0xe0, 0x60, 0x41, 0x22, 0x27, 0x2e, 0x52,
0x81, 0x55, 0xe2, 0x3c, 0xa3, 0x54, 0x74, 0x78, 0x85, 0x8b, 0x7a, 0xe4, 0x56, 0xa1, 0x07, 0x52,
0xaf, 0xcc, 0xa5, 0x16, 0x1a, 0x8b, 0x30, 0xa5, 0x64, 0x6b, 0x72, 0x49, 0xf8, 0xff, 0xb1, 0x81,
0x49, 0x24, 0xe5, 0xf8, 0xf7, 0xb5, 0xc1, 0xf9, 0xd5, 0xb0, 0x95, 0xc1, 0x69, 0x6c, 0x81, 0xf3,
0x28, 0x1f, 0x57, 0x25, 0x30, 0x8a, 0xc2, 0x4e, 0x50, 0x74, 0x20, 0x89, 0xaa, 0xc5, 0x4d, 0x16,
0xf3, 0xa1, 0x63, 0xb4, 0x3f, 0x7c, 0xbf, 0x68, 0xbb, 0xc4, 0xdb, 0x01, 0x2d, 0xbc, 0x26, 0xb4,
0xed, 0xaf, 0x86, 0xb6, 0x63, 0x42, 0xfb, 0xa5, 0x05, 0x9d, 0xf3, 0x2c, 0x99, 0x47, 0x13, 0x2e,
0x26, 0x49, 0x3a, 0x7d, 0x39, 0xa8, 0x12, 0x3e, 0xdb, 0x84, 0x6f, 0x00, 0x4e, 0xf0, 0x45, 0xaa,
0x4a, 0xe7, 0x23, 0x9a, 0xc3, 0xb6, 0xa2, 0xc4, 0x51, 0x85, 0xbd, 0x0f, 0x76, 0x90, 0x52, 0xce,
0xaa, 0x12, 0x5f, 0x7a, 0x18, 0xdc, 0x0e, 0x52, 0xff, 0xbb, 0x70, 0x24, 0x2f, 0xa2, 0x45, 0xaa,
0xcd, 0x1c, 0x41, 0xed, 0x32, 0x4d, 0x13, 0xdd, 0x68, 0x24, 0x81, 0x1f, 0x1a, 0x79, 0x73, 0xc2,
0x60, 0xbc, 0x49, 0x4e, 0xec, 0xfa, 0xfa, 0xee, 0x43, 0xfb, 0x3a, 0xc9, 0x7e, 0x95, 0x46, 0x19,
0x55, 0x13, 0x59, 0xf3, 0x4d, 0x96, 0xff, 0x04, 0xde, 0xa9, 0x9c, 0x5c, 0xf4, 0x43, 0x4c, 0x23,
0xa7, 0xf8, 0x42, 0x1d, 0xc3, 0xdb, 0xb9, 0x6a, 0x30, 0x7a, 0xa3, 0x3b, 0x6e, 0x1b, 0xfd, 0x8e,
0xe1, 0x39, 0x19, 0x55, 0xc7, 0xef, 0xf0, 0xc6, 0x1f, 0x82, 0xa7, 0xd0, 0x94, 0xbf, 0x08, 0xd4,
0x0d, 0x6e, 0x23, 0xb1, 0x79, 0xd9, 0x97, 0x11, 0xcd, 0x0b, 0x36, 0xfd, 0x58, 0xa0, 0xb5, 0xff,
0x47, 0x1b, 0x8e, 0x76, 0x19, 0x29, 0x12, 0xca, 0x32, 0x12, 0x8a, 0x9d, 0x41, 0xed, 0x8b, 0x48,
0x6c, 0xf4, 0x04, 0x70, 0x6c, 0x04, 0x7b, 0xeb, 0x0e, 0x5c, 0xaa, 0xe2, 0x43, 0x3a, 0x9f, 0x64,
0x51, 0xb2, 0xd0, 0x93, 0xbe, 0xa4, 0xf0, 0x84, 0x61, 0x9c, 0x4c, 0x7e, 0x27, 0x3f, 0x52, 0xb9,
0x24, 0x76, 0x3c, 0x8c, 0xda, 0x6b, 0x3e, 0x8c, 0xfa, 0xce, 0x87, 0x31, 0x80, 0x83, 0x5f, 0x2e,
0xa7, 0x61, 0x26, 0x2e, 0xef, 0xa3, 0x55, 0x26, 0x16, 0x13, 0xa1, 0xa6, 0xaa, 0x2a, 0xdb, 0xff,
0xbb, 0xa5, 0xf1, 0x34, 0xc6, 0xba, 0x57, 0x46, 0xb5, 0x78, 0x38, 0x8e, 0x7e, 0x38, 0x9e, 0x9c,
0x4a, 0x8b, 0xb1, 0x5b, 0x93, 0x38, 0x09, 0xe3, 0x92, 0xfe, 0x59, 0xb8, 0x14, 0xc9, 0x9c, 0x7e,
0x45, 0xb5, 0xda, 0x86, 0xa5, 0xbe, 0x0b, 0x16, 0x7f, 0x5c, 0xea, 0x64, 0x68, 0xf4, 0x7c, 0x36,
0x4b, 0xc5, 0x2c, 0xcc, 0x74, 0x2e, 0x14, 0x0c, 0xf6, 0x01, 0xd4, 0x49, 0x59, 0x87, 0xb3, 0x3a,
0x9a, 0x28, 0xe9, 0xf0, 0xf0, 0x9f, 0x2f, 0x7a, 0xd6, 0xbf, 0x5f, 0xf4, 0xac, 0xff, 0xbe, 0xe8,
0x59, 0x7f, 0xfa, 0x5f, 0x6f, 0xef, 0xae, 0x4e, 0xff, 0xc1, 0xbe, 0xff, 0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0x7b, 0x22, 0x9e, 0xfd, 0x17, 0x13, 0x00, 0x00,
}
func (m *Row) Marshal() (dAtA []byte, err error) {

View file

@ -1,6 +1,6 @@
syntax = "proto3";
package internal;
package pb;
message Row {
repeated uint64 Columns = 1;

View file

@ -34,7 +34,8 @@ var (
ErrIndexExists = disco.ErrIndexExists
ErrIndexNotFound = errors.New("index not found")
ErrInvalidSchema = errors.New("invalid schema")
ErrInvalidAddress = errors.New("invalid address")
ErrInvalidSchema = errors.New("invalid schema")
ErrForeignIndexNotFound = errors.New("foreign index not found")

View file

@ -20,6 +20,7 @@ import (
"testing"
"github.com/pilosa/pilosa/v2/roaring"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func TestValidateName(t *testing.T) {
@ -76,7 +77,7 @@ func TestAPI_CombineForExistence(t *testing.T) {
bm := roaring.NewBitmap(pos(1, 1), pos(1, 2), pos(1, 3), pos(1, 65537), pos(1, 65538), pos(2, 1), pos(2, 2), pos(2, 5), pos(2, 65537), pos(2, 65538))
buf := new(bytes.Buffer)
_, err := bm.WriteTo(buf)
panicOn(err)
PanicOn(err)
raw := buf.Bytes()
results, err := combineForExistence(raw)
if err != nil {
@ -84,7 +85,7 @@ func TestAPI_CombineForExistence(t *testing.T) {
}
bm2 := roaring.NewBitmap()
_, _, err = bm2.ImportRoaringBits(results, false, false, 1<<shardVsContainerExponent)
panicOn(err)
PanicOn(err)
expected := []uint64{1, 2, 3, 5, 65537, 65538}
got := bm2.Slice()
if !reflect.DeepEqual(got, expected) {

View file

@ -40,7 +40,7 @@ func TestAddressWithDefaults(t *testing.T) {
{addr: "1.2.3.4:", expected: "1.2.3.4:10101"},
{addr: "1.2.3.4:55555", expected: "1.2.3.4:55555"},
// The following tests check the error conditions.
{addr: "[invalid][addr]:port", err: "invalid address"},
{addr: "[invalid][addr]:port", err: pilosa.ErrInvalidAddress.Error()},
}
for _, test := range tests {
actual, err := pilosa.AddressWithDefaults(test.addr)

View file

@ -24,6 +24,7 @@ import (
_ "net/http/pprof" // Imported for its side-effect of registering pprof endpoints with the server.
"github.com/pilosa/pilosa/v2/storage"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// CPUProfileForDur (where "Dur" is short for "Duration"), is used for
@ -37,7 +38,7 @@ func CPUProfileForDur(dur time.Duration, outpath string) {
}
path := outpath + "." + backend
f, err := os.Create(path)
panicOn(err)
PanicOn(err)
if dur == 0 {
dur = time.Minute
@ -63,7 +64,7 @@ func MemProfileForDur(dur time.Duration, outpath string) {
}
path := outpath + "." + backend
f, err := os.Create(path)
panicOn(err)
PanicOn(err)
if dur == 0 {
dur = time.Minute
@ -73,7 +74,7 @@ func MemProfileForDur(dur time.Duration, outpath string) {
<-time.After(dur)
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
panic(fmt.Sprintf("could not write memory profile: %v", err))
PanicOn(fmt.Sprintf("could not write memory profile: %v", err))
}
f.Close()
AlwaysPrintf("wrote memory profile after dur '%v', output: '%v'", dur, path)
@ -91,7 +92,7 @@ var _ = pprofProfile{}
func newPprof() (pp *pprofProfile) {
pp = &pprofProfile{}
f, err := os.Create("cpu.manual.pprof")
panicOn(err)
PanicOn(err)
pp.fdCpu = f
_ = pprof.StartCPUProfile(pp.fdCpu)
@ -104,11 +105,11 @@ func (pp *pprofProfile) Close() {
pp.fdCpu.Close()
f, err := os.Create("mem.manual.pprof")
panicOn(err)
PanicOn(err)
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
panic(fmt.Sprintf("could not write memory profile: %v", err))
PanicOn(fmt.Sprintf("could not write memory profile: %v", err))
}
f.Close()
}

4
rbf.go
View file

@ -32,7 +32,7 @@ import (
txkey "github.com/pilosa/pilosa/v2/short_txkey"
"github.com/pilosa/pilosa/v2/storage"
//txkey "github.com/pilosa/pilosa/v2/txkey"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
)
@ -402,7 +402,7 @@ func (tx *RBFTx) RoaringBitmapReader(index, field, view string, shard uint64, fr
func (tx *RBFTx) NewTxIterator(index, field, view string, shard uint64) *roaring.Iterator {
b, err := tx.RoaringBitmap(index, field, view, shard)
panicOn(err)
PanicOn(err)
return b.Iterator()
}

View file

@ -20,6 +20,7 @@ import (
"testing"
"github.com/pilosa/pilosa/v2/roaring"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func getRoaringIter(bitsToSet ...uint64) roaring.RoaringIterator {
@ -28,15 +29,15 @@ func getRoaringIter(bitsToSet ...uint64) roaring.RoaringIterator {
changed := b.DirectAddN(bitsToSet...)
n := len(bitsToSet)
if changed != n {
panic(fmt.Sprintf("changed=%v but bitsToSet len = %v", changed, n))
PanicOn(fmt.Sprintf("changed=%v but bitsToSet len = %v", changed, n))
}
buf := bytes.NewBuffer(make([]byte, 0, 100000))
_, err := b.WriteTo(buf)
if err != nil {
panic(err)
PanicOn(err)
}
itr, err := roaring.NewRoaringIterator(buf.Bytes())
panicOn(err)
PanicOn(err)
return itr
}
@ -59,14 +60,14 @@ func TestCursor_RoaringImport(t *testing.T) {
defer tx.Rollback()
changed, rowSet, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
_ = rowSet
if changed != 1 {
t.Fatalf("expected 1 changed, got %v", changed)
}
if false {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
cur.dump()
@ -93,7 +94,7 @@ func TestCursor_RoaringImport_clear_bits(t *testing.T) {
defer tx.Rollback()
changed, rowSet, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err)
PanicOn(err)
_ = rowSet
if changed != 1 {
t.Fatalf("expected 1 changed, got %v", changed)
@ -104,7 +105,7 @@ func TestCursor_RoaringImport_clear_bits(t *testing.T) {
itr2 := getRoaringIter([]uint64{1}...)
changed, rowSet, err = tx.ImportRoaringBits(name, itr2, clear, false, rowSize, nil)
panicOn(err)
PanicOn(err)
_ = rowSet
if changed != 1 {
t.Fatalf("expected 1 changed on clear true, got %v", changed)
@ -112,7 +113,7 @@ func TestCursor_RoaringImport_clear_bits(t *testing.T) {
if false {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
cur.dump()
@ -152,14 +153,14 @@ func TestCursor_RoaringImport_two_leaves(t *testing.T) {
defer tx.Rollback()
changed, rowSet, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
_ = rowSet
if changed != 6000 {
t.Fatalf("expected 6000 bits changed, got %v", changed)
}
if false {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
cur.dump()
@ -211,7 +212,7 @@ func TestCursor_RoaringImport_many_leaves_manual_split(t *testing.T) {
//vv("DONE WITH Add()")
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != expectedBitsChanged-3000 {
t.Fatalf("expected %v bits changed, got %v", expectedBitsChanged-3000, changed)
}
@ -219,7 +220,7 @@ func TestCursor_RoaringImport_many_leaves_manual_split(t *testing.T) {
//vv("about to do itr2, that starts with key %v", itr2.ContainerKeys()[0])
changed, _, err = tx.ImportRoaringBits(name, itr2, clear, false, rowSize, nil)
panicOn(err)
PanicOn(err)
if changed != 3000 {
t.Fatalf("expected %v bits changed, got %v", 3000, changed)
}
@ -228,7 +229,7 @@ func TestCursor_RoaringImport_many_leaves_manual_split(t *testing.T) {
dump := func() {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
//cur.dump()
_ = cur.tx.dumpAllPages(true)
}
@ -242,7 +243,7 @@ func TestCursor_RoaringImport_many_leaves_manual_split(t *testing.T) {
itr3 := getRoaringIter(want...)
changed, _, err = tx.ImportRoaringBits(name, itr3, clear, false, rowSize, nil)
panicOn(err)
PanicOn(err)
if changed != expectedBitsChanged {
// cursor_internal_test.go:235: expected 2,724,000 bits changed, got 2,721,000
t.Fatalf("expected %v bits changed, got %v", expectedBitsChanged, changed)
@ -292,7 +293,7 @@ func TestCursor_RoaringImport_auto_many_leaves(t *testing.T) {
//vv("DONE WITH Add()")
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != expectedBitsChanged {
t.Fatalf("expected %v bits changed, got %v", expectedBitsChanged, changed)
}
@ -300,7 +301,7 @@ func TestCursor_RoaringImport_auto_many_leaves(t *testing.T) {
dump := func() {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
//cur.dump()
_ = cur.tx.dumpAllPages(true)
}
@ -313,7 +314,7 @@ func TestCursor_RoaringImport_auto_many_leaves(t *testing.T) {
itr2 := getRoaringIter(want...)
changed, _, err = tx.ImportRoaringBits(name, itr2, clear, false, rowSize, nil)
panicOn(err)
PanicOn(err)
if changed != expectedBitsChanged {
t.Fatalf("expected %v bits changed, got %v", expectedBitsChanged, changed)
}
@ -372,13 +373,13 @@ func TestCursor_putBranchCellsHandlesLotsOfNewBranchesAtTheRoot(t *testing.T) {
t.Fatal(err)
}
c, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
ikeys := itr.ContainerKeys()
for _, ckey := range ikeys {
_, err := c.Seek(ckey)
panicOn(err)
PanicOn(err)
break // after the first seek
}
@ -404,7 +405,7 @@ func TestCursor_putBranchCellsHandlesLotsOfNewBranchesAtTheRoot(t *testing.T) {
branch := branchCell{LeftKey: group[0].Key}
branch.ChildPgno, err = c.tx.allocatePgno()
panicOn(err)
PanicOn(err)
branches = append(branches, branch)
//vv("on group i=%v of %v, group[0].Key = %v; branch.ChildPgno=%v; branch.Key=%v", i, len(groups.slc), int(group[0].Key), (branch.ChildPgno), int(branch.Key))
@ -422,13 +423,13 @@ func TestCursor_putBranchCellsHandlesLotsOfNewBranchesAtTheRoot(t *testing.T) {
}
err = c.tx.writePage(buf[:])
panicOn(err)
PanicOn(err)
}
//vv("branches ckeys = '%#v'", keysFromParents(branches))
err = c.putBranchCells(0, branches)
panicOn(err)
PanicOn(err)
//c.tx.dumpAllPages(true)
}
@ -476,7 +477,7 @@ func TestCursor_incrementally_add_pages_and_view_them(t *testing.T) {
defer tx.Rollback()
dump := func() {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
//cur.dump()
_ = cur.tx.dumpAllPages(true)
}
@ -487,7 +488,7 @@ func TestCursor_incrementally_add_pages_and_view_them(t *testing.T) {
itr := getRoaringIter(want[i*3000 : (i+1)*3000]...)
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != 3000 {
t.Fatalf("expected %v bits changed, got %v", 3000, changed)
}
@ -505,7 +506,7 @@ func TestCursor_incrementally_add_pages_and_view_them(t *testing.T) {
itr := getRoaringIter(want[i*3000 : (i+1)*3000]...)
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != 3000 {
t.Fatalf("expected %v bits changed, got %v", 3000, changed)
}
@ -559,7 +560,7 @@ func TestCursor_from_B_to_C(t *testing.T) {
defer tx.Rollback()
dump := func() {
cur, err := tx.cursor(name)
panicOn(err)
PanicOn(err)
//cur.dump()
_ = cur.tx.dumpAllPages(true)
}
@ -567,7 +568,7 @@ func TestCursor_from_B_to_C(t *testing.T) {
itr := getRoaringIter(want[:6000]...)
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != 6000 {
t.Fatalf("expected %v bits changed, got %v", 6000, changed)
}
@ -578,7 +579,7 @@ func TestCursor_from_B_to_C(t *testing.T) {
itr = getRoaringIter(want[6000:9000]...)
changed, _, err = tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != 3000 {
t.Fatalf("expected %v bits changed, got %v", 3000, changed)
}
@ -595,7 +596,7 @@ func TestCursor_from_B_to_C(t *testing.T) {
itr := getRoaringIter(want[i*3000 : (i+1)*3000]...)
changed, _, err := tx.ImportRoaringBits(name, itr, clear, false, rowSize, nil)
panicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
PanicOn(err) // writeTheTailOfLeafCellsFromIter has to be AFTER any pre-existing data. ckey=0 was found already in db.
if changed != 3000 {
t.Fatalf("expected %v bits changed, got %v", 3000, changed) // failing here got 0
}

View file

@ -29,8 +29,8 @@ import (
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/testhook"
// "github.com/pilosa/pilosa/v2/txkey"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func rbfName(index, field, view string, shard uint64) string {
@ -74,17 +74,17 @@ func TestIngest_lots_of_views(t *testing.T) {
}()
path, err := testhook.TempDir(t, "rbf_ingest_lots_of_views")
panicOn(err)
PanicOn(err)
defer os.Remove(path)
cfg := cfg.NewDefaultConfig()
db := NewDB(path, cfg)
panicOn(db.Open())
PanicOn(db.Open())
// setup profiling
if false {
profile, err := os.Create("./rbf_ingest_put_ct.cpu")
panicOn(err)
PanicOn(err)
_ = pprof.StartCPUProfile(profile)
defer func() {
pprof.StopCPUProfile()
@ -94,7 +94,7 @@ func TestIngest_lots_of_views(t *testing.T) {
// put containers
tx, err := db.Begin(true)
panicOn(err)
PanicOn(err)
index := "i"
field := "f"
@ -117,30 +117,30 @@ func TestIngest_lots_of_views(t *testing.T) {
view = fmt.Sprintf("view_%v", i)
name := rbfName(index, field, view, shard)
err = tx.PutContainer(name, ckey, ct)
panicOn(err)
PanicOn(err)
ct2, err := tx.Container(name, ckey)
panicOn(err)
PanicOn(err)
if err := ct2.BitwiseCompare(ct); err != nil {
panic("ct2 != ct")
PanicOn("ct2 != ct")
}
// write .dot of it...
if false { //ckey == nCt-1 {
c, err := tx.cursor(name)
if err == ErrBitmapNotFound {
panic("not found")
PanicOn("not found")
} else if err != nil {
panic(err)
PanicOn(err)
}
defer c.Close()
c.Dump("one.bitmap.dot.dump")
}
}
panicOn(tx.Commit())
PanicOn(tx.Commit())
sz, err := DiskUse(path, "")
panicOn(err)
PanicOn(err)
_ = sz
//vv("sz in bytes= %v", sz)
db.Close()
@ -153,7 +153,7 @@ func DiskUse(root string, requiredSuffix string) (tot int, err error) {
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if info == nil {
panic(fmt.Sprintf("info was nil for path = '%v'", path))
PanicOn(fmt.Sprintf("info was nil for path = '%v'", path))
}
if info.IsDir() {
// skip the size of directories themselves, only summing files.

View file

@ -30,6 +30,7 @@ import (
"github.com/benbjohnson/immutable"
"github.com/pilosa/pilosa/v2/roaring"
"github.com/pilosa/pilosa/v2/shardwidth"
. "github.com/pilosa/pilosa/v2/vprint"
)
const (
@ -355,8 +356,9 @@ func (c *leafCell) Bitmap(tx *Tx) []uint64 {
_, bm, _ := tx.leafCellBitmap(toPgno(c.Data))
return bm
default:
panic(fmt.Sprintf("invalid container type: %d", c.Type))
PanicOn(fmt.Errorf("invalid container type: %d", c.Type))
}
return nil
}
// Values returns a slice of 16-bit values from a container.
@ -382,8 +384,9 @@ func (c *leafCell) Values(tx *Tx) []uint16 {
case ContainerTypeNone:
return []uint16{}
default:
panic(fmt.Sprintf("invalid container type: %d", c.Type))
PanicOn(fmt.Errorf("invalid container type: %d", c.Type))
}
return nil
}
func bitmapValues(bm []uint64) []uint16 {
@ -409,7 +412,7 @@ func (c *leafCell) firstValue(tx *Tx) uint16 {
return r[0].Start
case ContainerTypeBitmapPtr:
_, slc, err := tx.leafCellBitmap(toPgno(c.Data))
panicOn(err)
PanicOn(err)
for i, v := range slc {
for j := uint(0); j < 64; j++ {
if v&(1<<j) != 0 {
@ -417,10 +420,12 @@ func (c *leafCell) firstValue(tx *Tx) uint16 {
}
}
}
panic(fmt.Sprintf("rbf.leafCell.firstValue(): no values set in bitmap container: key=%d", c.Key))
PanicOn(fmt.Errorf("rbf.leafCell.firstValue(): no values set in bitmap container: key=%d", c.Key))
default:
panic(fmt.Sprintf("invalid container type: %d", c.Type))
PanicOn(fmt.Errorf("invalid container type: %d", c.Type))
}
return 0
}
// helper for lastValue()
@ -432,7 +437,8 @@ func (c *leafCell) lastValueFromBitmap(a []uint64) uint16 {
}
}
}
panic(fmt.Sprintf("rbf.leafCell.lastValueFromBitmap(): no values set in bitmap container: key=%d", c.Key))
PanicOn(fmt.Errorf("rbf.leafCell.lastValueFromBitmap(): no values set in bitmap container: key=%d", c.Key))
return 0
}
// lastValue the last value from the container.
@ -451,11 +457,12 @@ func (c *leafCell) lastValue(tx *Tx) uint16 {
case ContainerTypeBitmapPtr:
_, a, err := tx.leafCellBitmap(toPgno(c.Data))
panicOn(err)
PanicOn(err)
return c.lastValueFromBitmap(a)
default:
panic(fmt.Sprintf("invalid container type: %d", c.Type))
PanicOn(fmt.Errorf("invalid container type: %d", c.Type))
}
return 0
}
// countRange returns the bit count within the given range.
@ -477,11 +484,12 @@ func (c *leafCell) countRange(tx *Tx, start, end int32) (n int) {
return int(roaring.BitmapCountRange(toArray64(c.Data), start, end))
case ContainerTypeBitmapPtr:
_, a, err := tx.leafCellBitmap(toPgno(c.Data))
panicOn(err)
PanicOn(err)
return int(roaring.BitmapCountRange(a, start, end))
default:
panic(fmt.Sprintf("invalid container type: %d", c.Type))
PanicOn(fmt.Errorf("invalid container type: %d", c.Type))
}
return
}
func readLeafCellKey(page []byte, i int) uint64 {
@ -560,8 +568,9 @@ func readLeafCellBytesAtOffset(page []byte, offset int) []byte {
case ContainerTypeBitmapPtr:
return buf[:leafCellHeaderSize+4]
default:
panic(fmt.Sprintf("invalid cell type: %d", typ))
PanicOn(fmt.Errorf("invalid cell type: %d", typ))
}
return nil
}
// leafPageSize returns the number of bytes used on a leaf page.
@ -715,13 +724,13 @@ func Walk(tx *Tx, pgno uint32, v func(uint32, []*RootRecord)) {
for pgno := readMetaRootRecordPageNo(tx.meta[:]); pgno != 0; {
page, _, err := tx.readPage(pgno)
if err != nil {
panic(err)
PanicOn(err)
}
// Read all records on the page.
a, err := readRootRecords(page)
if err != nil {
panic(err)
PanicOn(err)
}
v(pgno, a)
// Read next overflow page number.
@ -731,7 +740,7 @@ func Walk(tx *Tx, pgno uint32, v func(uint32, []*RootRecord)) {
func assert(condition bool) {
if !condition {
panic("assertion failed")
PanicOn(fmt.Errorf("assertion failed"))
}
}

View file

@ -26,7 +26,7 @@ import (
"github.com/pilosa/pilosa/v2/hash"
"github.com/pilosa/pilosa/v2/roaring"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
//txkey "github.com/pilosa/pilosa/v2/txkey"
. "github.com/pilosa/pilosa/v2/vprint"
)
var _ = txkey.ToString
@ -135,7 +135,7 @@ func (tx *Tx) Rollback() {
// Disconnect transaction from DB.
tx.db.mu.Lock()
defer tx.db.mu.Unlock()
panicOn(tx.db.removeTx(tx))
PanicOn(tx.db.removeTx(tx))
}
// Root returns the root page number for a bitmap. Returns 0 if the bitmap does not exist.
@ -919,7 +919,7 @@ func (tx *Tx) allocatePgno() (uint32, error) {
if changed, err := c.Remove(uint64(pgno)); err != nil {
return 0, err
} else if !changed {
panic(fmt.Sprintf("tx.Tx.allocatePgno(): double alloc: %d", pgno))
PanicOn(fmt.Sprintf("tx.Tx.allocatePgno(): double alloc: %d", pgno))
}
return pgno, nil
}
@ -960,7 +960,7 @@ func (tx *Tx) freePgno(pgno uint32) error {
if changed, err := c.Add(uint64(pgno)); err != nil {
return err
} else if !changed {
panic(fmt.Sprintf("rbf.Tx.freePgno(): double free: %d", pgno))
PanicOn(fmt.Sprintf("rbf.Tx.freePgno(): double free: %d", pgno))
}
return nil
}
@ -1200,7 +1200,7 @@ func (tx *Tx) ForEachRange(name string, start, end uint64, fn func(uint64) error
}
}
default:
panic(fmt.Sprintf("invalid container type: %d", cell.Type))
PanicOn(fmt.Sprintf("invalid container type: %d", cell.Type))
}
}
}
@ -1299,7 +1299,7 @@ func (tx *Tx) Min(name string) (uint64, bool, error) {
func (tx *Tx) UnionInPlace(name string, others ...*roaring.Bitmap) error {
rbm, err := tx.RoaringBitmap(name)
panicOn(err)
PanicOn(err)
rbm.UnionInPlace(others...)
// iterate over the containers that changed within rbm, and write them back to disk.
@ -1313,7 +1313,7 @@ func (tx *Tx) UnionInPlace(name string, others ...*roaring.Bitmap) error {
// TODO: only write the changed ones back, as optimization?
// Compare to ImportRoaringBits.
err := tx.PutContainer(name, containerKey, rc)
panicOn(err)
PanicOn(err)
}
return nil
}
@ -1395,11 +1395,11 @@ func (tx *Tx) CountRange(name string, start, end uint64) (uint64, error) {
func (tx *Tx) OffsetRange(name string, offset, start, endx uint64) (*roaring.Bitmap, error) {
if lowbits(offset) != 0 {
panic("offset must not contain low bits")
PanicOn("offset must not contain low bits")
} else if lowbits(start) != 0 {
panic("range start must not contain low bits")
PanicOn("range start must not contain low bits")
} else if lowbits(endx) != 0 {
panic("range endx must not contain low bits")
PanicOn("range endx must not contain low bits")
}
tx.mu.RLock()
@ -1532,7 +1532,8 @@ func (si *emptyContainerIterator) Next() bool {
return false
}
func (si *emptyContainerIterator) Value() (uint64, *roaring.Container) {
panic("emptyContainerIterator never has any Values")
PanicOn("emptyContainerIterator never has any Values")
return 0, nil
}
func (tx *Tx) Dump(short bool, shard uint64) {
@ -1544,14 +1545,14 @@ func (tx *Tx) DumpString(short bool, shard uint64) (r string) {
// grab root records, for a list of bitmaps.
records, err := tx.RootRecords()
panicOn(err)
PanicOn(err)
n := 0
for itr := records.Iterator(); !itr.Done(); {
name, _ := itr.Next()
c, err := tx.cursor(name.(string))
panicOn(err)
PanicOn(err)
defer c.Close()
err = c.First() // First will rewind to beginning.
@ -1560,17 +1561,17 @@ func (tx *Tx) DumpString(short bool, shard uint64) (r string) {
n++
continue
}
panicOn(err)
PanicOn(err)
for {
err := c.Next()
if err == io.EOF {
break
}
panicOn(err)
PanicOn(err)
elem := &c.stack.elems[c.stack.top]
leafPage, _, err := c.tx.readPage(elem.pgno)
panicOn(err)
PanicOn(err)
cell := readLeafCell(leafPage, elem.index)
ckey := cell.Key
@ -1595,7 +1596,7 @@ func containerToBytes(ct *roaring.Container) []byte {
ty := roaring.ContainerType(ct)
switch ty {
case roaring.ContainerNil:
panic("nil container")
PanicOn("nil container")
case roaring.ContainerArray:
return fromArray16(roaring.AsArray(ct))
case roaring.ContainerBitmap:
@ -1603,7 +1604,8 @@ func containerToBytes(ct *roaring.Container) []byte {
case roaring.ContainerRun:
return fromInterval16(roaring.AsRuns(ct))
}
panic(fmt.Sprintf("unknown container type '%v'", int(ty)))
PanicOn(fmt.Sprintf("unknown container type '%v'", int(ty)))
return nil
}
func bitmapAsString(rbm *roaring.Bitmap) (r string) {
@ -1785,7 +1787,7 @@ func (tx *Tx) ImportRoaringBits(name string, itr roaring.RoaringIterator, clear
err = tx.putContainerWithCursor(cur, itrKey, newC)
if err != nil {
panicOn(err)
PanicOn(err)
return
}
continue
@ -1927,7 +1929,7 @@ func (tx *Tx) Pages(pgnos []uint32) ([]Page, error) {
pages = append(pages, &FreePage{FreePageInfo: info})
default:
panic(fmt.Sprintf("invalid page info type %T", info))
PanicOn(fmt.Sprintf("invalid page info type %T", info))
}
}
@ -2047,7 +2049,7 @@ func (tx *Tx) walkPageInfo(infos []PageInfo, root uint32, name string) error {
Tree: name,
}
default:
panic(fmt.Sprintf("unexpected page type %d for page %d", typ, pgno))
PanicOn(fmt.Sprintf("unexpected page type %d for page %d", typ, pgno))
}
return nil

View file

@ -18,6 +18,7 @@ import (
"fmt"
"math"
"math/rand"
"sync"
"testing"
"time"
@ -99,17 +100,24 @@ func TestTx_CommitRollback(t *testing.T) {
db := MustOpenDB(t)
defer MustCloseDB(t, db)
var wg sync.WaitGroup
defer wg.Wait()
// Start write transaction.
ch0 := make(chan struct{})
tx0 := MustBegin(t, db, true)
wg.Add(1)
go func() {
defer wg.Done()
<-ch0
tx0.Rollback()
}()
// Start separate write transaction in different goroutine.
ch1 := make(chan struct{})
wg.Add(1)
go func() {
defer wg.Done()
tx1 := MustBegin(t, db, true)
close(ch1)
_ = tx1.Commit()

View file

@ -19,6 +19,7 @@ import (
"strings"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
. "github.com/pilosa/pilosa/v2/vprint"
)
func (tx *Tx) dumpAllPages(showLeaves bool) error {
@ -56,9 +57,9 @@ func (tx *Tx) dumpAllPages(showLeaves bool) error {
fmt.Printf("next=%d\n", info.Next)
page, _, err := tx.readPage(uint32(pgno))
panicOn(err)
PanicOn(err)
rootRecords, err := readRootRecords(page)
panicOn(err)
PanicOn(err)
for k, rr := range rootRecords {
fmt.Printf(" [%02v] Name:'%v' pgno:%v\n", k, prefixToString(rr.Name), rr.Pgno)
}
@ -73,7 +74,7 @@ func (tx *Tx) dumpAllPages(showLeaves bool) error {
fmt.Printf("flags=x%x,celln=%d\n", info.Flags, info.CellN)
page, _, err := tx.readPage(uint32(pgno))
panicOn(err)
PanicOn(err)
var leafCells [PageSize / 8]leafCell
cells := readLeafCells(page, leafCells[:])
@ -88,7 +89,7 @@ func (tx *Tx) dumpAllPages(showLeaves bool) error {
fmt.Printf("flags=x%x,celln=%d\n", info.Flags, info.CellN)
page, _, err := tx.readPage(uint32(pgno))
panicOn(err)
PanicOn(err)
cells := readBranchCells(page)
for i, cell := range cells {
@ -240,12 +241,12 @@ func (c_orig *Cursor) debugStringBitmaps() (r string) {
if err == io.EOF {
break
}
panicOn(err)
PanicOn(err)
//instead of cell := c2.cell()
elem := &c2.stack.elems[c2.stack.top]
leafPage, _, err := c2.tx.readPage(elem.pgno)
panicOn(err)
PanicOn(err)
cell := readLeafCell(leafPage, elem.index)
ckey := cell.Key

View file

@ -1,208 +0,0 @@
// home: https://github.com/glycerine/vprint
// Copyright 2019 Jason E. Aten, Ph.D. All rights reserved.
// License: MIT
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package rbf
import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"runtime"
"runtime/debug"
"strings"
"sync"
"time"
)
const RFC3339MsecTz0 = "2006-01-02T15:04:05.000Z07:00"
const RFC3339UsecTz0 = "2006-01-02T15:04:05.000000Z07:00"
// for tons of debug output
var VerboseVerbose bool = false
// convience functions for . import
var pp = PP
var vv = VV
var panicOn = PanicOn
func init() {
// keeper linter happy
_ = pp
_ = vv
}
func PanicOn(err error) {
if err != nil {
panic(err)
}
}
func PP(format string, a ...interface{}) {
if VerboseVerbose {
TSPrintf(format, a...)
}
}
func VV(format string, a ...interface{}) {
TSPrintf(format, a...)
}
func AlwaysPrintf(format string, a ...interface{}) {
TSPrintf(format, a...)
}
var tsPrintfMut sync.Mutex
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
tsPrintfMut.Lock()
Printf("\n%s %s ", FileLine(3), ts())
Printf(format+"\n", a...)
tsPrintfMut.Unlock()
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format(RFC3339UsecTz0)
}
// so we can multi write easily, use our own printf
var OurStdout io.Writer = os.Stdout
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(OurStdout, format, a...)
}
func FileLine(depth int) string {
_, fileName, fileLine, ok := runtime.Caller(depth)
var s string
if ok {
s = fmt.Sprintf("%s:%d", path.Base(fileName), fileLine)
} else {
s = ""
}
return s
}
func stack() string {
return string(debug.Stack())
}
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}
func FileSize(name string) (int64, error) {
fi, err := os.Stat(name)
if err != nil {
return -1, err
}
return fi.Size(), nil
}
// Caller returns the name of the calling function.
func Caller(upStack int) string {
// elide ourself and runtime.Callers
target := upStack + 2
pc := make([]uintptr, target+2)
n := runtime.Callers(0, pc)
f := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(pc[:n])
for i := 0; i <= target; i++ {
contender, more := frames.Next()
if i == target {
f = contender
}
if !more {
break
}
}
}
return f.Function
}
var _ = stack // happy linter
var _ = listFilesUnderDir
// listFilesUnderDir returns the paths of files found under directory root.
// If includeRoot is true, it returns the full path, otherwise paths are relative to root.
// If requriedSuffix is supplied, the returned file paths will end in that,
// and any other files found during the walk of the directory tree will be ignored.
// If ignoreEmpty is true, files of size 0 will be excluded.
func listFilesUnderDir(root string, includeRoot bool, requiredSuffix string, ignoreEmpty bool) (files []string, err error) {
if !DirExists(root) {
return nil, fmt.Errorf("listFilesUnderDir error: root directory '%v' not found", root)
}
n := len(root) + 1
if includeRoot {
n = 0
}
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if len(path) < n {
// ignore
} else {
if info == nil {
panic(fmt.Sprintf("info was nil for path = '%v'", path))
}
if info.IsDir() {
// skip directories.
} else {
if ignoreEmpty && info.Size() == 0 {
return nil
}
if requiredSuffix == "" || strings.HasSuffix(path, requiredSuffix) {
files = append(files, path[n:])
}
}
}
return nil
})
return
}

View file

@ -30,7 +30,7 @@ import (
txkey "github.com/pilosa/pilosa/v2/short_txkey"
"github.com/pilosa/pilosa/v2/storage"
//txkey "github.com/pilosa/pilosa/v2/txkey"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
"github.com/pkg/errors"
)
@ -120,7 +120,7 @@ func (tx *RoaringTx) Pointer() string {
// the transaction Commits or Rollsback.
func (tx *RoaringTx) NewTxIterator(index, field, view string, shard uint64) *roaring.Iterator {
b, err := tx.bitmap(index, field, view, shard)
panicOn(err)
PanicOn(err)
return b.Iterator()
}
@ -150,7 +150,7 @@ func (tx *RoaringTx) Readonly() bool {
func (tx *RoaringTx) IncrementOpN(index, field, view string, shard uint64, changedN int) {
frag, err := tx.getFragment(index, field, view, shard)
panicOn(err)
PanicOn(err)
frag.incrementOpN(changedN)
}

View file

@ -16,22 +16,24 @@ package pilosa
import (
"testing"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
func TestRoaring_HasData(t *testing.T) {
holder := newHolderWithTempPath(t, "roaring")
idx, err := holder.CreateIndex("i", IndexOptions{})
panicOn(err)
PanicOn(err)
defer idx.Close()
db, err := globalRoaringReg.OpenDBWrapper(idx.path, false, nil)
panicOn(err)
PanicOn(err)
db.SetHolder(idx.holder)
// HasData should start out false.
hasAnything, err := db.HasData()
panicOn(err)
PanicOn(err)
if hasAnything {
t.Fatalf("HasData reported existing data on an empty database")
@ -45,10 +47,10 @@ func TestRoaring_HasData(t *testing.T) {
defer tx.Rollback()
f, err := idx.CreateField(field)
panicOn(err)
PanicOn(err)
_, err = f.SetBit(tx, 1, 1, nil)
panicOn(err)
panicOn(tx.Commit())
PanicOn(err)
PanicOn(tx.Commit())
hasAnything, err = db.HasData()
if err != nil {

View file

@ -33,7 +33,7 @@ import (
// Ensure program can send/receive broadcast messages.
func TestMain_SendReceiveMessage(t *testing.T) {
ms := test.MustRunCluster(t, 2)
ms := test.MustRunCluster(t, 3)
m0, m1 := ms.GetNode(0), ms.GetNode(1)
defer ms.Close()
@ -128,7 +128,7 @@ func TestClusterResize_EmptyNode(t *testing.T) {
// Ensure that a cluster of empty nodes comes up in a NORMAL state.
func TestClusterResize_EmptyNodes(t *testing.T) {
clus := test.MustRunCluster(t, 2)
clus := test.MustRunCluster(t, 3)
defer clus.Close()
state0, err0 := clus.GetNode(0).API.State()
@ -156,7 +156,7 @@ func TestClusterResize_AddNode(t *testing.T) {
skipTestUnderBlueGreenWithRoaring(t)
t.Run("NoData", func(t *testing.T) {
clus := test.MustRunCluster(t, 2)
clus := test.MustRunCluster(t, 3)
defer clus.Close()
state0, err0 := clus.GetNode(0).API.State()
@ -218,7 +218,7 @@ func TestClusterResize_AddNode(t *testing.T) {
t.Run("ContinuousShards", func(t *testing.T) {
// Configure node0
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
m0 := c.GetNode(0)
@ -268,7 +268,7 @@ func TestClusterResize_AddNode(t *testing.T) {
t.Run("OneShard", func(t *testing.T) {
// Configure node0
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0
@ -316,7 +316,7 @@ func TestClusterResize_AddNode(t *testing.T) {
t.Run("SkippedShard", func(t *testing.T) {
// same reason as the ContinuousShards test above.
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0
@ -372,7 +372,7 @@ func TestClusterResize_AddNodeConcurrentIndex(t *testing.T) {
skipTestUnderBlueGreenWithRoaring(t)
t.Run("WithIndex", func(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0
@ -413,7 +413,7 @@ func TestClusterResize_AddNodeConcurrentIndex(t *testing.T) {
})
t.Run("ContinuousShards", func(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0
@ -464,7 +464,7 @@ func TestClusterResize_AddNodeConcurrentIndex(t *testing.T) {
})
t.Run("SkippedShard", func(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0
@ -515,7 +515,7 @@ func TestClusterResize_AddNodeConcurrentIndex(t *testing.T) {
})
t.Run("WithIndexKeys", func(t *testing.T) {
c := test.MustRunCluster(t, 2)
c := test.MustRunCluster(t, 3)
defer c.Close()
// Configure node0

View file

@ -351,6 +351,12 @@ func NewConfig() *Config {
c.Etcd.InitCluster = c.Name + "=" + c.Etcd.LPeerURL
c.Etcd.HeartbeatTTL = 5
c.Etcd.TrustedCAFile = ""
c.Etcd.ClientCertFile = ""
c.Etcd.ClientKeyFile = ""
c.Etcd.PeerCertFile = ""
c.Etcd.PeerKeyFile = ""
return c
}

View file

@ -1534,13 +1534,13 @@ func TestCluster_TranslateStore(t *testing.T) {
if err := cluster.GetIdleNode(0).Start(); err != nil {
t.Fatalf("starting node 0: %v", err)
}
defer cluster.GetIdleNode(0).Close()
defer cluster.GetIdleNode(0).Close() // nolint: errcheck
test.Do(t, "POST", cluster.GetIdleNode(0).URL()+"/index/i0", "{\"options\": {\"keys\": true}}")
}
func TestClusterTranslator(t *testing.T) {
cluster := test.MustRunCluster(t, 2,
cluster := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
@ -1550,6 +1550,10 @@ func TestClusterTranslator(t *testing.T) {
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
pilosa.OptServerOpenTranslateReader(http.GetOpenTranslateReaderWithLockerFunc(nil, &sync.Mutex{})),
)},
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerOpenTranslateStore(boltdb.OpenTranslateStore),
)},
)
defer cluster.Close()
@ -1591,7 +1595,7 @@ func TestClusterTranslator(t *testing.T) {
}
func TestQueryHistory(t *testing.T) {
cluster := test.MustRunCluster(t, 2,
cluster := test.MustRunCluster(t, 3,
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("1"),
@ -1600,6 +1604,10 @@ func TestQueryHistory(t *testing.T) {
server.OptCommandServerOptions(
pilosa.OptServerNodeID("0"),
)},
[]server.CommandOption{
server.OptCommandServerOptions(
pilosa.OptServerNodeID("2"),
)},
)
defer cluster.Close()

View file

@ -381,6 +381,12 @@ func (m *Command) SetupServer() error {
//
// Use name for etcd.name
m.Config.Etcd.Name = m.Config.Name
// use the pilosa provided tls credentials if available
m.Config.Etcd.TrustedCAFile = m.Config.TLS.CACertPath
m.Config.Etcd.ClientCertFile = m.Config.TLS.CertificatePath
m.Config.Etcd.ClientKeyFile = m.Config.TLS.CertificateKeyPath
m.Config.Etcd.PeerCertFile = m.Config.TLS.CertificatePath
m.Config.Etcd.PeerKeyFile = m.Config.TLS.CertificateKeyPath
//
// If an Etcd.Dir is not provided, nest a default under the pilosa data dir.
if m.Config.Etcd.Dir == "" {

View file

@ -26,6 +26,7 @@ import (
"github.com/pilosa/pilosa/v2/debugstats"
"github.com/pilosa/pilosa/v2/roaring"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
// statTx is useful to profile on a
@ -242,7 +243,8 @@ func (k kall) String() string {
case kUseRowCache:
return "kUseRowCache"
}
panic(fmt.Sprintf("unknown kall '%v'", int(k)))
PanicOn(fmt.Sprintf("unknown kall '%v'", int(k)))
return ""
}
var _ = newStatTx // happy linter
@ -293,8 +295,8 @@ func (c *statTx) ImportRoaringBits(index, field, view string, shard uint64, rit
}()
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ImportRoaringBits() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ImportRoaringBits() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ImportRoaringBits(index, field, view, shard, rit, clear, log, rowSize, data)
@ -307,8 +309,8 @@ func (c *statTx) Dump(short bool, shard uint64) {
func (c *statTx) Readonly() bool {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Readonly() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Readonly() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Readonly()
@ -327,8 +329,8 @@ func (c *statTx) Rollback() {
}()
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Rollback() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Rollback() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
c.b.Rollback()
@ -344,8 +346,8 @@ func (c *statTx) Commit() error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Commit() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Commit() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Commit()
@ -361,8 +363,8 @@ func (c *statTx) RoaringBitmap(index, field, view string, shard uint64) (*roarin
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmap() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmap() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmap(index, field, view, shard)
@ -378,8 +380,8 @@ func (c *statTx) Container(index, field, view string, shard uint64, key uint64)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Container() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Container() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Container(index, field, view, shard, key)
@ -395,8 +397,8 @@ func (c *statTx) PutContainer(index, field, view string, shard uint64, key uint6
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see PutContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see PutContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.PutContainer(index, field, view, shard, key, rc)
@ -412,8 +414,8 @@ func (c *statTx) RemoveContainer(index, field, view string, shard uint64, key ui
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RemoveContainer() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RemoveContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RemoveContainer(index, field, view, shard, key)
@ -437,8 +439,8 @@ func (c *statTx) Add(index, field, view string, shard uint64, batched bool, a ..
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Add() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Add() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Add(index, field, view, shard, batched, a...)
@ -454,8 +456,8 @@ func (c *statTx) Remove(index, field, view string, shard uint64, a ...uint64) (c
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Remove() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Remove() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Remove(index, field, view, shard, a...)
@ -471,8 +473,8 @@ func (c *statTx) Contains(index, field, view string, shard uint64, key uint64) (
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Contains() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Contains() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Contains(index, field, view, shard, key)
@ -488,8 +490,8 @@ func (c *statTx) ContainerIterator(index, field, view string, shard uint64, firs
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ContainerIterator() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ContainerIterator() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ContainerIterator(index, field, view, shard, firstRoaringContainerKey)
@ -509,8 +511,8 @@ func (c *statTx) ForEach(index, field, view string, shard uint64, fn func(i uint
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEach() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEach() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEach(index, field, view, shard, fn)
@ -526,8 +528,8 @@ func (c *statTx) ForEachRange(index, field, view string, shard uint64, start, en
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEachRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see ForEachRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEachRange(index, field, view, shard, start, end, fn)
@ -543,8 +545,8 @@ func (c *statTx) Count(index, field, view string, shard uint64) (uint64, error)
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Count() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Count() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Count(index, field, view, shard)
@ -560,8 +562,8 @@ func (c *statTx) Max(index, field, view string, shard uint64) (uint64, error) {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Max() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Max() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Max(index, field, view, shard)
@ -577,8 +579,8 @@ func (c *statTx) Min(index, field, view string, shard uint64) (uint64, bool, err
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Min() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see Min() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Min(index, field, view, shard)
@ -594,8 +596,8 @@ func (c *statTx) UnionInPlace(index, field, view string, shard uint64, others ..
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see UnionInPlace() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see UnionInPlace() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.UnionInPlace(index, field, view, shard, others...)
@ -611,8 +613,8 @@ func (c *statTx) CountRange(index, field, view string, shard uint64, start, end
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see CountRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see CountRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.CountRange(index, field, view, shard, start, end)
@ -627,8 +629,8 @@ func (c *statTx) OffsetRange(index, field, view string, shard, offset, start, en
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see OffsetRange() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see OffsetRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.OffsetRange(index, field, view, shard, offset, start, end)
@ -644,8 +646,8 @@ func (c *statTx) RoaringBitmapReader(index, field, view string, shard uint64, fr
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmapReader() panic '%v' at '%v'", r, stack())
panic(r)
AlwaysPrintf("see RoaringBitmapReader() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmapReader(index, field, view, shard, fragmentPathForRoaring)

View file

@ -49,12 +49,12 @@ func Test_SynthLoad_ImportSchema(t *testing.T) {
// get the holder.Path to write to
h := m0.API.Holder()
target := h.Path()
panicOn(h.Close())
PanicOn(h.Close())
panicOn(unpackTarball(tarball, target))
PanicOn(unpackTarball(tarball, target))
// reopen
panicOn(h.Open())
PanicOn(h.Open())
qs := strings.Split(pql, "\n\n")
//vv("qs = '%#v'", qs)
@ -92,7 +92,7 @@ func Test_SynthLoad_ImportSchema(t *testing.T) {
}
qr, err := m0.API.Query(context.Background(), req)
panicOn(err)
PanicOn(err)
vv("qr = '%#v'", qr)
}
}
@ -103,22 +103,22 @@ func applySchema(m0 *test.Command, schemaStr string) {
// don't need schema now that we import the tarball, it has it all.
schema := &pilosa.Schema{}
err := json.NewDecoder(bytes.NewBufferString(schemaStr)).Decode(schema)
panicOn(err)
PanicOn(err)
ctx := context.Background()
remote := false
err = m0.API.ApplySchema(ctx, schema, remote)
panicOn(err)
PanicOn(err)
}
func unpackTarball(tarball, target string) error {
vv("target = '%v'", target)
fd, err := os.Open(tarball)
panicOn(err)
PanicOn(err)
defer fd.Close()
gz, err := gzip.NewReader(fd)
panicOn(err)
PanicOn(err)
defer gz.Close()
tarReader := tar.NewReader(gz)
@ -134,16 +134,16 @@ func unpackTarball(tarball, target string) error {
info := header.FileInfo()
if info.IsDir() {
if err = os.MkdirAll(path, info.Mode()); err != nil {
panicOn(err)
PanicOn(err)
}
continue
}
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
panicOn(err)
PanicOn(err)
_, err = io.Copy(file, tarReader)
panicOn(err)
PanicOn(err)
file.Close()
}
return nil

View file

@ -1,170 +0,0 @@
// home: https://github.com/glycerine/vprint
// Copyright 2019 Jason E. Aten, Ph.D. All rights reserved.
// License: MIT
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package synthload
import (
"fmt"
"io"
"os"
"path"
"runtime"
"runtime/debug"
"sync"
"time"
)
const RFC3339MsecTz0 = "2006-01-02T15:04:05.000Z07:00"
const RFC3339UsecTz0 = "2006-01-02T15:04:05.000000Z07:00"
// for tons of debug output
var VerboseVerbose bool = false
// convience functions for . import
var pp = PP
var vv = VV
var panicOn = PanicOn
var _ = panicOn
func init() {
// keeper linter happy
_ = pp
_ = vv
}
func PanicOn(err error) {
if err != nil {
panic(err)
}
}
func PP(format string, a ...interface{}) {
if VerboseVerbose {
TSPrintf(format, a...)
}
}
func VV(format string, a ...interface{}) {
TSPrintf(format, a...)
}
func AlwaysPrintf(format string, a ...interface{}) {
TSPrintf(format, a...)
}
var tsPrintfMut sync.Mutex
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
tsPrintfMut.Lock()
Printf("\n%s %s ", FileLine(3), ts())
Printf(format+"\n", a...)
tsPrintfMut.Unlock()
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format(RFC3339UsecTz0)
}
// so we can multi write easily, use our own printf
var OurStdout io.Writer = os.Stdout
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(OurStdout, format, a...)
}
func FileLine(depth int) string {
_, fileName, fileLine, ok := runtime.Caller(depth)
var s string
if ok {
s = fmt.Sprintf("%s:%d", path.Base(fileName), fileLine)
} else {
s = ""
}
return s
}
func stack() string {
return string(debug.Stack())
}
var _ = stack
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}
func FileSize(name string) (int64, error) {
fi, err := os.Stat(name)
if err != nil {
return -1, err
}
return fi.Size(), nil
}
// Caller returns the name of the calling function.
func Caller(upStack int) string {
// elide ourself and runtime.Callers
target := upStack + 2
pc := make([]uintptr, target+2)
n := runtime.Callers(0, pc)
f := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(pc[:n])
for i := 0; i <= target; i++ {
contender, more := frames.Next()
if i == target {
f = contender
}
if !more {
break
}
}
}
return f.Function
}

Some files were not shown because too many files have changed in this diff Show more