From f2bde49d2594d263e3f0adaec70009dd9dfd3c61 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 7 Sep 2020 09:39:26 -0600 Subject: [PATCH 1/6] Fix RBF WAL replay/truncation --- rbf/db.go | 26 +++++++++++++++++--------- rbf/wal.go | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/rbf/db.go b/rbf/db.go index a286370d4..c8b4cf9ac 100644 --- a/rbf/db.go +++ b/rbf/db.go @@ -188,6 +188,7 @@ func (db *DB) checkpoint(exclusive bool) error { return err } walID := readMetaWALID(page) + maxCheckpointedWALID := walID // Determine the high water mark for WAL pages that can be copied. minActiveWALID := db.minActiveWALID() @@ -195,7 +196,6 @@ func (db *DB) checkpoint(exclusive bool) error { // Loop over each transaction walID++ pageMap := immutable.NewMap(&uint32Hasher{}) - var maxCheckpointedWALID int64 for { // Determine last page of transaction. metaWALID, err := db.findNextWALMetaPage(walID) @@ -255,7 +255,7 @@ func (db *DB) checkpoint(exclusive bool) error { if maxCheckpointedWALID != 0 { for len(db.segments) > 0 { segment := db.segments[0] - if segment.MaxWALID() >= maxCheckpointedWALID { + if segment.MaxWALID() > maxCheckpointedWALID { break } @@ -331,17 +331,18 @@ func (db *DB) findLastWALMetaPage() (walID int64, err error) { return 0, nil } - var maxWALID int64 - for walID := db.segments[0].MinWALID(); walID <= maxWALID; walID++ { + var maxMetaWALID int64 + maxWALID := db.maxWALID() + for walID := db.minWALID(); walID <= maxWALID; walID++ { if page, err := db.readWALPage(walID); err != nil { return walID, err } else if IsBitmapHeader(page) { walID++ // skip next page for bitmap headers } else if IsMetaPage(page) { - maxWALID = walID // save max meta WAL ID + maxMetaWALID = walID // save max meta WAL ID } } - return maxWALID, nil + return maxMetaWALID, nil } // minActiveWALID returns the lowest WAL ID in use by any active transaction. @@ -459,7 +460,6 @@ func (db *DB) writeBitmapPage(pgno uint32, page []byte) (walID int64, err error) } func (db *DB) ensureWritableWALSegment() error { - if s := db.activeWALSegment(); s != nil && s.Size() < MaxWALSegmentFileSize { return nil } @@ -469,13 +469,21 @@ func (db *DB) ensureWritableWALSegment() error { // addWALSegment appends a new, writable segment and closing an existing segments for write. func (db *DB) addWALSegment() error { - // Close previous last segment for writes. - base := int64(1) + // If we have a current active WAL segment then close it and start the + // next segment from the next WAL ID. If there is no existing WAL segments, + // read the last checkpointed WAL ID from the DB and start after that. + var base int64 if s := db.activeWALSegment(); s != nil { base = s.MaxWALID() + 1 if err := s.CloseForWrite(); err != nil { return err } + } else { + page, err := db.readPage(db.pageMap, 0) + if err != nil { + return err + } + base = readMetaWALID(page) + 1 } // Create new segment file. diff --git a/rbf/wal.go b/rbf/wal.go index 9a50fdde2..7a0518d96 100644 --- a/rbf/wal.go +++ b/rbf/wal.go @@ -233,7 +233,7 @@ func (s *WALSegment) TruncateAfter(walID int64) error { // Update to new page size. newPageN := int((walID - s.minWALID) + 1) // new page count of segment - truncPageN := newPageN - s.pageN // number of pages removed + truncPageN := s.pageN - newPageN // number of pages removed s.pageN = newPageN // Check to see if we are only truncating from the write cache. From a51c53076300c142ac9b753b34b33faa98a09e44 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Tue, 8 Sep 2020 08:03:06 -0600 Subject: [PATCH 2/6] Add direct import option; remove tx from fragment.Open() --- api.go | 1 + cmd/slurp/slurp.go | 11 +- encoding/proto/proto.go | 2 + field.go | 3 - fragment.go | 41 ++++--- handler.go | 1 + internal/public.pb.go | 249 +++++++++++++++++++++++----------------- internal/public.proto | 2 +- rbf.go | 9 +- txfactory.go | 10 ++ 10 files changed, 195 insertions(+), 134 deletions(-) diff --git a/api.go b/api.go index b23e81e1b..260c40c6f 100644 --- a/api.go +++ b/api.go @@ -451,6 +451,7 @@ func (api *API) ImportRoaring(ctx context.Context, indexName, fieldName string, } qcx := api.Txf().NewQcx() + qcx.Direct = req.Direct defer qcx.Abort() nodes := api.cluster.shardNodes(indexName, shard) diff --git a/cmd/slurp/slurp.go b/cmd/slurp/slurp.go index 1412fb057..a000a779b 100644 --- a/cmd/slurp/slurp.go +++ b/cmd/slurp/slurp.go @@ -50,6 +50,7 @@ type stateMachine struct { state string client *http.InternalClient start time.Time + direct bool } func (r *stateMachine) NewHeader(h *tar.Header, tr *tar.Reader) error { @@ -129,7 +130,8 @@ func (r *stateMachine) NewHeader(h *tar.Header, tr *tar.Reader) error { func (r *stateMachine) Upload() error { if len(r.viewData) > 0 { request := &pilosa.ImportRoaringRequest{ - Views: r.viewData, + Views: r.viewData, + Direct: r.direct, } uri := GetImportRoaringURI(r.lastIndex, r.lastShard) err := r.client.ImportRoaring(context.Background(), uri, r.lastIndex, r.lastField, r.lastShard, false, request) @@ -141,7 +143,7 @@ func (r *stateMachine) Upload() error { return nil } -func UploadTar(srcFile string, client *http.InternalClient) error { +func UploadTar(srcFile string, direct bool, client *http.InternalClient) error { f, err := os.Open(srcFile) if err != nil { @@ -161,6 +163,7 @@ func UploadTar(srcFile string, client *http.InternalClient) error { runner := &stateMachine{ viewData: make(map[string][]byte), start: time.Now(), + direct: direct, } runner.client = client for { @@ -180,8 +183,10 @@ func UploadTar(srcFile string, client *http.InternalClient) error { func main() { var host string + var direct bool var tarSrcPath string flag.StringVar(&host, "host", "127.0.0.1:10101", "host to import into") + flag.BoolVar(&direct, "direct", false, "direct write to database (unsafe)") flag.StringVar(&tarSrcPath, "src", "q2.tar.gz", "data to import") flag.Parse() @@ -195,7 +200,7 @@ func main() { t0 := time.Now() println("uploading", tarSrcPath) - panicOn(UploadTar(tarSrcPath, c)) + panicOn(UploadTar(tarSrcPath, direct, c)) vv("total elapsed '%v'", time.Since(t0)) } diff --git a/encoding/proto/proto.go b/encoding/proto/proto.go index a1453cd62..ac4b56e07 100644 --- a/encoding/proto/proto.go +++ b/encoding/proto/proto.go @@ -460,6 +460,7 @@ func (s Serializer) encodeImportRoaringRequest(m *pilosa.ImportRoaringRequest) * Action: m.Action, Block: uint64(m.Block), Views: views, + Direct: m.Direct, } } @@ -1233,6 +1234,7 @@ func (s Serializer) decodeImportRoaringRequest(pb *internal.ImportRoaringRequest m.Views = views m.IndexCreatedAt = pb.IndexCreatedAt m.FieldCreatedAt = pb.FieldCreatedAt + m.Direct = pb.Direct } func (s Serializer) decodeImportColumnAttrsRequest(pb *internal.ImportColumnAttrsRequest, m *pilosa.ImportColumnAttrsRequest) { diff --git a/field.go b/field.go index 950de776b..2073bf8ac 100644 --- a/field.go +++ b/field.go @@ -1870,9 +1870,6 @@ func (f *Field) importRoaringOverwrite(ctx context.Context, tx Tx, data []byte, switch f.Options().Type { case FieldTypeInt, FieldTypeDecimal: frag.mu.Lock() - if err := frag.calculateMaxRowID(tx); err != nil { - return err - } maxRowID, _, err := frag.maxRow(tx, nil) frag.mu.Unlock() if err != nil { diff --git a/fragment.go b/fragment.go index cef03de05..cc8423e02 100644 --- a/fragment.go +++ b/fragment.go @@ -143,9 +143,6 @@ type fragment struct { CacheSize uint32 - // Stats reporting. - maxRowID uint64 - // Cache containing full rows (not just counts). rowCache bitmapCache @@ -248,11 +245,7 @@ func (f *fragment) Open() error { // Clear checksums. f.checksums = make(map[int][]byte) - - // Read last bit to determine max row. - tx := f.idx.Txf.NewTx(Txo{Write: false, Index: f.idx, Fragment: f, Shard: f.shard}) // first index 'i' shard 0 - defer tx.Rollback() - return f.calculateMaxRowID(tx) + return nil }(); err != nil { f.close() return err @@ -703,11 +696,6 @@ func (f *fragment) unprotectedSetBit(tx Tx, rowID, columnID uint64) (changed boo f.stats.Count(MetricSetBit, 1, 1.0) - // Update row count if they have increased. - if rowID > f.maxRowID { - f.maxRowID = rowID - } - return changed, nil } @@ -1310,8 +1298,15 @@ func (f *fragment) minRow(tx Tx, filter *Row) (uint64, uint64, error) { if filter == nil { return minRowID, 1, nil } + + // Read last bit to determine max row. + maxRowID, err := f.maxRowID(tx) + if err != nil { + return 0, 0, err + } + // iterate from min row ID and return the first that intersects with filter. - for i := minRowID; i <= f.maxRowID; i++ { + for i := minRowID; i <= maxRowID; i++ { row, err := f.row(tx, i) if err != nil { return 0, 0, err @@ -1336,12 +1331,17 @@ func (f *fragment) maxRow(tx Tx, filter *Row) (uint64, uint64, error) { return 0, 0, err } if hasRowID { + maxRowID, err := f.maxRowID(tx) + if err != nil { + return 0, 0, err + } + if filter == nil { - return f.maxRowID, 1, nil + return maxRowID, 1, nil } // iterate back from max row ID and return the first that intersects with filter. // TODO: implement reverse container iteration to improve performance here for sparse data. --Jaffee - for i := f.maxRowID; i >= minRowID; i-- { + for i := maxRowID; i >= minRowID; i-- { row, err := f.row(tx, i) if err != nil { return 0, 0, err @@ -1357,15 +1357,14 @@ func (f *fragment) maxRow(tx Tx, filter *Row) (uint64, uint64, error) { return 0, 0, nil } -// calculateMaxRowID determines the field's maxRowID value based +// maxRowID determines the field's maxRowID value based // on the contents of its storage, and sets the struct argument. -func (f *fragment) calculateMaxRowID(tx Tx) (err error) { +func (f *fragment) maxRowID(tx Tx) (_ uint64, err error) { max, err := tx.Max(f.index, f.field, f.view, f.shard) if err != nil { - return err + return 0, err } - f.maxRowID = max / ShardWidth - return nil + return max / ShardWidth, nil } // rangeOp returns bitmaps with a bsiGroup value encoding matching the predicate. diff --git a/handler.go b/handler.go index 619583ab2..495641255 100644 --- a/handler.go +++ b/handler.go @@ -242,6 +242,7 @@ type ImportRoaringRequest struct { Action string // [set, clear, overwrite] Block int Views map[string][]byte + Direct bool } // ValidateWithTimestamp ensures that the payload of the request is valid. diff --git a/internal/public.pb.go b/internal/public.pb.go index ce418fb74..219625518 100644 --- a/internal/public.pb.go +++ b/internal/public.pb.go @@ -2394,6 +2394,7 @@ type ImportRoaringRequest struct { Block uint64 `protobuf:"varint,4,opt,name=Block,proto3" json:"Block,omitempty"` IndexCreatedAt int64 `protobuf:"varint,5,opt,name=IndexCreatedAt,proto3" json:"IndexCreatedAt,omitempty"` FieldCreatedAt int64 `protobuf:"varint,6,opt,name=FieldCreatedAt,proto3" json:"FieldCreatedAt,omitempty"` + Direct bool `protobuf:"varint,7,opt,name=Direct,proto3" json:"Direct,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2474,6 +2475,13 @@ func (m *ImportRoaringRequest) GetFieldCreatedAt() int64 { return 0 } +func (m *ImportRoaringRequest) GetDirect() bool { + if m != nil { + return m.Direct + } + return false +} + type ImportColumnAttrsRequest struct { Index string `protobuf:"bytes,1,opt,name=Index,proto3" json:"Index,omitempty"` Shard int64 `protobuf:"varint,2,opt,name=Shard,proto3" json:"Shard,omitempty"` @@ -2603,110 +2611,110 @@ func init() { func init() { proto.RegisterFile("public.proto", fileDescriptor_413a91106d7bcce8) } var fileDescriptor_413a91106d7bcce8 = []byte{ - // 1639 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4f, 0x6f, 0xdb, 0xca, - 0x11, 0x37, 0x45, 0xca, 0x92, 0x46, 0xb2, 0xe3, 0x6c, 0x94, 0x94, 0x48, 0x1d, 0x47, 0x20, 0xdc, - 0x46, 0x2d, 0x0a, 0x07, 0x4e, 0x93, 0x20, 0x97, 0xb6, 0xb1, 0x23, 0xa7, 0x26, 0x52, 0xbb, 0xe9, - 0xca, 0x70, 0x6f, 0x05, 0x68, 0x69, 0xeb, 0x10, 0xa5, 0x44, 0x95, 0xa2, 0x22, 0xfb, 0x52, 0xa0, - 0x9f, 0x21, 0x97, 0x7e, 0x84, 0x7e, 0x8e, 0x5e, 0xfa, 0x8e, 0xef, 0xf8, 0x80, 0x77, 0x79, 0xc8, - 0x7b, 0xdf, 0x22, 0x97, 0x87, 0x99, 0xe5, 0x6a, 0x97, 0x14, 0xed, 0x18, 0xc1, 0xbb, 0xed, 0xfc, - 0xd9, 0xd9, 0x99, 0xdf, 0xcc, 0xce, 0x0e, 0x09, 0xad, 0xc9, 0xec, 0x2c, 0x0a, 0x07, 0x3b, 0x93, - 0x24, 0x4e, 0x63, 0x56, 0x0f, 0xc7, 0xa9, 0x48, 0xc6, 0x41, 0xe4, 0x4d, 0xc1, 0xe6, 0xf1, 0x9c, - 0xb9, 0x50, 0x7b, 0x15, 0x47, 0xb3, 0xd1, 0x78, 0xea, 0x5a, 0x1d, 0xbb, 0xeb, 0x70, 0x45, 0x32, - 0x06, 0xce, 0x1b, 0x71, 0x39, 0x75, 0xed, 0x8e, 0xdd, 0x6d, 0x70, 0x5a, 0xb3, 0x6d, 0xa8, 0xee, - 0xa5, 0x69, 0x32, 0x75, 0x2b, 0x1d, 0xbb, 0xdb, 0x7c, 0xb2, 0xbe, 0xa3, 0xcc, 0xed, 0x20, 0x9b, - 0x4b, 0x21, 0xda, 0xe4, 0x71, 0x90, 0x84, 0xe3, 0x73, 0xd7, 0xe9, 0x58, 0xdd, 0x16, 0x57, 0xa4, - 0x77, 0x04, 0x8d, 0x7e, 0x78, 0x3e, 0x16, 0x43, 0x3c, 0xfa, 0x21, 0xd8, 0x6f, 0x63, 0x3c, 0xd6, - 0xea, 0x36, 0x9f, 0xac, 0x69, 0x53, 0x3c, 0x9e, 0x73, 0x94, 0xa0, 0xc2, 0xb1, 0x38, 0x77, 0x2b, - 0xa5, 0x0a, 0xc7, 0xe2, 0xdc, 0x7b, 0x01, 0xeb, 0x3c, 0x9e, 0xfb, 0x43, 0x31, 0x4e, 0xc3, 0xbf, - 0x87, 0x22, 0x21, 0xa7, 0x79, 0x3c, 0x57, 0xb1, 0xd0, 0x7a, 0x11, 0x48, 0x45, 0x07, 0xe2, 0xdd, - 0x87, 0x55, 0xbf, 0xf7, 0xa7, 0x70, 0x9a, 0xb2, 0x0d, 0xb0, 0xfd, 0x9e, 0xda, 0x80, 0x4b, 0xcf, - 0x87, 0xdb, 0x07, 0x17, 0x69, 0x12, 0x0c, 0x52, 0x31, 0xf4, 0x7b, 0x12, 0x0e, 0xb6, 0x0e, 0x15, - 0xbf, 0x47, 0xbe, 0x3a, 0xbc, 0xe2, 0xf7, 0xd8, 0x36, 0x38, 0xa7, 0x41, 0xa4, 0x80, 0xd8, 0xd0, - 0xce, 0x49, 0xb3, 0x9c, 0xa4, 0xde, 0x59, 0xce, 0xd4, 0x51, 0x90, 0x26, 0xe1, 0x05, 0xbb, 0x07, - 0xab, 0xaf, 0x43, 0x11, 0x0d, 0xe5, 0xa1, 0x0d, 0x9e, 0x51, 0xec, 0x99, 0x4e, 0x85, 0xb4, 0xfa, - 0x73, 0x6d, 0x75, 0xc9, 0xa1, 0x45, 0x9e, 0xbc, 0x07, 0x50, 0x7b, 0x23, 0x2e, 0x29, 0x16, 0x15, - 0xa9, 0x65, 0x44, 0xfa, 0xad, 0x05, 0x77, 0x16, 0xbb, 0x4f, 0x82, 0xb3, 0x48, 0x9c, 0x06, 0xd1, - 0x4c, 0xb0, 0x6d, 0x15, 0xb7, 0x55, 0xe6, 0xff, 0xe1, 0x0a, 0x61, 0xc1, 0x1e, 0x2d, 0xb0, 0x43, - 0xb5, 0xdb, 0x5a, 0x2d, 0x3b, 0xf2, 0x70, 0x25, 0xab, 0x8c, 0x4d, 0xa8, 0xef, 0xf7, 0x7d, 0x32, - 0xed, 0xda, 0x1d, 0xab, 0x6b, 0x1f, 0xae, 0xf0, 0x05, 0x87, 0xdd, 0x87, 0xda, 0xd1, 0x2c, 0x15, - 0x17, 0x7e, 0x8f, 0x2a, 0xc2, 0x39, 0x5c, 0xe1, 0x8a, 0x81, 0x3b, 0x69, 0xf9, 0x46, 0x5c, 0xba, - 0xd5, 0x8e, 0xd5, 0x6d, 0xe0, 0x4e, 0xc5, 0x61, 0x6d, 0x70, 0xf6, 0xe3, 0x38, 0x72, 0x57, 0x3b, - 0x56, 0xb7, 0x8e, 0xa7, 0x21, 0xb5, 0x5f, 0x83, 0x2a, 0x19, 0xf6, 0xfe, 0x05, 0xed, 0x7c, 0x70, - 0x59, 0xba, 0x18, 0xd8, 0x68, 0xcf, 0xca, 0xec, 0x21, 0xc1, 0x36, 0x28, 0x85, 0x95, 0xec, 0x7c, - 0x4c, 0xe2, 0x33, 0x58, 0x25, 0x33, 0xb2, 0xc8, 0x9b, 0x4f, 0x1e, 0x94, 0x00, 0xae, 0x21, 0xe3, - 0x99, 0xf2, 0x7e, 0x83, 0x10, 0xff, 0x73, 0xe2, 0xf7, 0xbc, 0xdf, 0x15, 0xc1, 0xa5, 0x5c, 0x62, - 0x22, 0x8e, 0x83, 0x91, 0x90, 0xe7, 0x73, 0x5a, 0x23, 0xef, 0xe4, 0x72, 0x22, 0xc8, 0x81, 0x06, - 0xa7, 0xb5, 0xf7, 0x6f, 0x0b, 0xd6, 0xf3, 0xfb, 0xd1, 0x27, 0xa3, 0x3a, 0xae, 0xf1, 0x89, 0xb4, - 0x16, 0xc5, 0xf3, 0xa2, 0x58, 0x3c, 0x5b, 0x57, 0xed, 0x2b, 0xd6, 0xcf, 0xef, 0xc1, 0x79, 0x1b, - 0x84, 0xc9, 0x52, 0x85, 0x6f, 0x48, 0x08, 0x6d, 0x72, 0xd7, 0x96, 0xb9, 0xa8, 0xbe, 0x8a, 0x67, - 0xe3, 0x54, 0x62, 0xc8, 0x25, 0xe1, 0x1d, 0x40, 0x03, 0xf7, 0xcb, 0xc0, 0x3d, 0x69, 0x2c, 0x2b, - 0x2b, 0xa3, 0x3f, 0x20, 0x97, 0xcb, 0x83, 0xda, 0x50, 0x25, 0xe5, 0x0c, 0x09, 0x49, 0x78, 0x87, - 0x00, 0x28, 0x9d, 0x4a, 0x3b, 0xdb, 0x50, 0x25, 0x2a, 0x03, 0xa1, 0x68, 0x48, 0x0a, 0xaf, 0xb0, - 0xf4, 0x00, 0xaa, 0xfe, 0x38, 0x7d, 0xfe, 0x14, 0xc5, 0xb2, 0x20, 0xd1, 0x1b, 0x9b, 0x67, 0x25, - 0x33, 0x83, 0xba, 0x84, 0x2e, 0x9e, 0x6b, 0x03, 0x96, 0x61, 0x00, 0xb9, 0xd8, 0x56, 0x7a, 0x2a, - 0x4e, 0x22, 0xf0, 0xda, 0xf2, 0x78, 0xae, 0x21, 0xc9, 0x28, 0xf6, 0x0b, 0x75, 0x8a, 0x43, 0x31, - 0xdf, 0x32, 0xae, 0x12, 0x7a, 0xa1, 0x8e, 0xfd, 0x1b, 0xc0, 0x1f, 0x93, 0x78, 0x36, 0x21, 0xd0, - 0x58, 0x17, 0xaa, 0x44, 0x65, 0xf1, 0x31, 0xbd, 0x49, 0xf9, 0xc6, 0xa5, 0x42, 0x39, 0xe8, 0x98, - 0x9c, 0xfe, 0x6c, 0x24, 0x6f, 0x1a, 0xc7, 0x25, 0x96, 0x52, 0xfd, 0x34, 0x88, 0x16, 0xe2, 0xd3, - 0x20, 0xca, 0xe2, 0xc6, 0x65, 0xde, 0x8c, 0xad, 0xcc, 0xdc, 0x87, 0xfa, 0xeb, 0x28, 0x0e, 0x52, - 0x54, 0x46, 0x5b, 0x16, 0x5f, 0xd0, 0x6c, 0x17, 0xa0, 0x27, 0x06, 0xe1, 0x28, 0x88, 0x50, 0xea, - 0x14, 0x1b, 0x40, 0x26, 0xe3, 0x86, 0x92, 0xf7, 0x0c, 0x6a, 0x19, 0x55, 0x8e, 0x3d, 0x72, 0xfb, - 0x83, 0x20, 0x12, 0xca, 0x0b, 0x22, 0xbc, 0xbf, 0xc2, 0x9a, 0x2c, 0x46, 0x7c, 0x3e, 0xfa, 0x22, - 0xbd, 0x41, 0x29, 0xde, 0xe8, 0x21, 0xf2, 0xfe, 0x6b, 0x81, 0x83, 0x2b, 0x65, 0xc0, 0xd2, 0x06, - 0xcc, 0xdb, 0xe8, 0xc8, 0xdb, 0xc8, 0x3a, 0xd0, 0xec, 0xa7, 0xf8, 0x4e, 0xe9, 0x36, 0xd6, 0xe0, - 0x26, 0x0b, 0xf1, 0xf2, 0xc7, 0xa9, 0x4e, 0xb7, 0xcd, 0x17, 0x34, 0xdb, 0x84, 0x06, 0xf6, 0x26, - 0x29, 0xc4, 0x46, 0x56, 0xe7, 0x9a, 0xc1, 0xb6, 0x00, 0x14, 0xb2, 0x33, 0x41, 0xdd, 0xcc, 0xe2, - 0x06, 0xc7, 0x7b, 0x0c, 0x35, 0xf4, 0xf4, 0x28, 0x98, 0xe8, 0xd8, 0xac, 0xeb, 0x62, 0xfb, 0x64, - 0x41, 0xeb, 0x2f, 0x33, 0x91, 0x5c, 0x72, 0xf1, 0xcf, 0x99, 0x98, 0xa6, 0x88, 0x2d, 0xd1, 0xaa, - 0x96, 0x89, 0xc0, 0xaa, 0xed, 0xbf, 0x0b, 0x92, 0xa1, 0x44, 0xca, 0xe1, 0x19, 0x85, 0xb1, 0x6a, - 0xcc, 0xa7, 0x14, 0x6b, 0x9d, 0x9b, 0x2c, 0xaa, 0x77, 0x31, 0x8a, 0x53, 0x15, 0x4c, 0x46, 0xb1, - 0x2e, 0xdc, 0x3a, 0xb8, 0x18, 0x44, 0xb3, 0xa1, 0xe0, 0xf1, 0x5c, 0xee, 0xa6, 0xe6, 0xcc, 0x8b, - 0x6c, 0xf6, 0x4b, 0x6c, 0x6e, 0xc4, 0x52, 0xad, 0xa9, 0x46, 0x8a, 0x05, 0x2e, 0xdb, 0x85, 0xd6, - 0xc1, 0xe8, 0x4c, 0x0c, 0x87, 0x62, 0xd8, 0x0b, 0xd2, 0xc0, 0xad, 0x53, 0xdc, 0x85, 0x07, 0x3f, - 0xa7, 0xe2, 0x7d, 0xb0, 0x60, 0x2d, 0x8b, 0x7e, 0x3a, 0x89, 0xc7, 0x53, 0x81, 0x29, 0x3e, 0x48, - 0x12, 0x95, 0xe2, 0x83, 0x24, 0x61, 0x8f, 0xa1, 0xc6, 0xc5, 0x74, 0x16, 0xa5, 0xaa, 0x4a, 0xee, - 0x6a, 0x8b, 0x6a, 0xef, 0x2c, 0x4a, 0xb9, 0xd2, 0x62, 0x7f, 0x80, 0xf5, 0x5c, 0x1d, 0xaa, 0x67, - 0xe1, 0x67, 0x7a, 0x5f, 0x4e, 0xce, 0x0b, 0xea, 0xde, 0x27, 0x07, 0x9a, 0x86, 0xe5, 0x45, 0x91, - 0x21, 0x3e, 0x6b, 0x59, 0x91, 0x3d, 0xa4, 0xb9, 0xeb, 0x8a, 0xa9, 0x07, 0x7b, 0x52, 0x0b, 0xac, - 0xe3, 0xac, 0x2c, 0xad, 0x63, 0xdd, 0x08, 0xed, 0xeb, 0x1a, 0x21, 0x4e, 0x71, 0xef, 0x82, 0xf1, - 0xb9, 0x18, 0x52, 0x59, 0xd6, 0xb9, 0x22, 0xd9, 0x8e, 0xee, 0x0a, 0x94, 0xc7, 0x5c, 0xaf, 0x51, - 0x12, 0xae, 0x3b, 0x87, 0xec, 0x72, 0x38, 0x19, 0xd4, 0x64, 0xbd, 0x48, 0x8a, 0x3d, 0x87, 0xa6, - 0x6e, 0x5f, 0xd3, 0x2c, 0x45, 0x6d, 0x6d, 0x4a, 0x0b, 0xb9, 0xa9, 0xc8, 0x5e, 0x16, 0x47, 0x34, - 0xb7, 0x41, 0x5e, 0xb8, 0xb9, 0xc8, 0x0d, 0x39, 0x2f, 0x8e, 0x74, 0xbb, 0xc6, 0xcc, 0xe8, 0x02, - 0x6d, 0xbe, 0xa3, 0x37, 0x2f, 0x44, 0xdc, 0x98, 0x2c, 0x9f, 0x9a, 0x6f, 0x89, 0xdb, 0xa4, 0x3d, - 0xed, 0x3c, 0x72, 0x52, 0xc6, 0xcd, 0x37, 0x67, 0xd7, 0x78, 0xc8, 0xdc, 0x56, 0xf1, 0xa0, 0x85, - 0x88, 0x1b, 0xcf, 0x9d, 0x5f, 0x32, 0xdf, 0xb9, 0x6b, 0xb4, 0xb5, 0x7c, 0x78, 0x93, 0x2a, 0xbc, - 0x64, 0x2a, 0x7c, 0x59, 0x9c, 0x04, 0xdc, 0xf5, 0x22, 0x50, 0x79, 0x39, 0x2f, 0xe8, 0x7b, 0xff, - 0xaf, 0xc0, 0x9a, 0x3f, 0x9a, 0xc4, 0x49, 0x6a, 0xb4, 0x04, 0x7f, 0x3c, 0x14, 0x17, 0xaa, 0x25, - 0x10, 0x51, 0xfe, 0x6a, 0x52, 0x6b, 0xc6, 0xd6, 0x40, 0xad, 0xc0, 0xe1, 0x92, 0x30, 0xca, 0xc1, - 0xc9, 0x95, 0xc3, 0x26, 0x34, 0x64, 0xed, 0xa3, 0xa8, 0x4a, 0x22, 0xcd, 0x90, 0x1f, 0x00, 0x73, - 0x1a, 0x1c, 0x6b, 0x34, 0x8a, 0x2a, 0x12, 0xdb, 0xa0, 0x54, 0x23, 0x61, 0x9d, 0x84, 0x06, 0x07, - 0xe5, 0x27, 0xe1, 0x48, 0x4c, 0xd3, 0x60, 0x34, 0xc1, 0xbe, 0x62, 0x77, 0x6d, 0x6e, 0x70, 0xb0, - 0xa5, 0x50, 0x10, 0xaf, 0x12, 0x11, 0xa4, 0x62, 0xb8, 0x97, 0x52, 0x39, 0xd9, 0xbc, 0xc0, 0x45, - 0x3d, 0x0a, 0x4b, 0xeb, 0x81, 0xd4, 0xcb, 0x73, 0xe9, 0x59, 0x8c, 0x44, 0x90, 0x50, 0x91, 0xd4, - 0xb9, 0x24, 0xbc, 0x6f, 0x2a, 0xc0, 0x24, 0x92, 0x72, 0xf0, 0xfb, 0xc9, 0xe0, 0xbc, 0x1e, 0xb6, - 0x3c, 0x38, 0xb5, 0x25, 0x70, 0xee, 0x2d, 0xc6, 0x55, 0x09, 0x4c, 0x46, 0x61, 0x2f, 0xd7, 0x2f, - 0x89, 0x44, 0xd5, 0xe2, 0x26, 0x8b, 0x79, 0xd0, 0x32, 0x9e, 0x31, 0xbc, 0x83, 0x68, 0x3b, 0xc7, - 0x2b, 0x81, 0x16, 0x6e, 0x08, 0x6d, 0xf3, 0x7a, 0x68, 0x5b, 0x26, 0xb4, 0x1f, 0x2c, 0x68, 0xed, - 0xa5, 0xf1, 0x28, 0x1c, 0x70, 0x31, 0x88, 0x93, 0xe1, 0xd5, 0xa0, 0x4a, 0xf8, 0x2a, 0x26, 0x7c, - 0x3b, 0x60, 0xfb, 0xef, 0x93, 0xac, 0x15, 0x6e, 0x1a, 0x83, 0xd6, 0x52, 0xae, 0x38, 0x2a, 0xb2, - 0x47, 0x50, 0xf1, 0x13, 0xaa, 0xdc, 0x5c, 0x13, 0xcf, 0x5d, 0x12, 0x5e, 0xf1, 0x13, 0xef, 0x37, - 0xd0, 0x96, 0x4e, 0x29, 0x51, 0xf6, 0xa8, 0xb4, 0xa1, 0x7a, 0x90, 0x24, 0xb1, 0x7a, 0x56, 0x24, - 0xe1, 0x9d, 0x42, 0xfb, 0x24, 0x09, 0xc6, 0xd3, 0x28, 0x48, 0x05, 0x26, 0xe6, 0x4b, 0xea, 0xa3, - 0xe4, 0xeb, 0xda, 0xfb, 0x15, 0xdc, 0x2d, 0xd8, 0xd5, 0x6f, 0x1b, 0x16, 0x8c, 0xad, 0xbf, 0x51, - 0xfb, 0x70, 0x67, 0xa1, 0xea, 0xf7, 0xbe, 0xc8, 0x83, 0x65, 0xa3, 0xbf, 0x36, 0xe2, 0x22, 0xa3, - 0xd9, 0xf1, 0x65, 0xbe, 0xee, 0x83, 0x9b, 0x61, 0x25, 0x3f, 0xed, 0x33, 0x0f, 0x4e, 0x43, 0x31, - 0xbf, 0xea, 0xeb, 0x87, 0xde, 0xf6, 0x0a, 0xfd, 0x10, 0xa0, 0xb5, 0xf7, 0x83, 0x05, 0xed, 0x32, - 0x23, 0xba, 0x74, 0x2c, 0xa3, 0x74, 0xd8, 0x0b, 0xa8, 0xbe, 0x0f, 0xc5, 0x5c, 0xbd, 0xe6, 0xde, - 0x52, 0x42, 0x97, 0x3c, 0xe1, 0x72, 0x03, 0x5e, 0x9c, 0xbd, 0x41, 0x1a, 0xc6, 0x63, 0x35, 0xba, - 0x4b, 0x0a, 0xcf, 0xd9, 0x8f, 0xe2, 0xc1, 0x3f, 0xe4, 0x47, 0x29, 0x97, 0x44, 0xc9, 0x45, 0xa8, - 0xde, 0xf0, 0x22, 0xac, 0x96, 0x5d, 0x04, 0xef, 0x7f, 0x96, 0xc2, 0xca, 0x18, 0xaf, 0x3e, 0x9b, - 0x31, 0x5d, 0xfe, 0xb6, 0x2a, 0x7f, 0x57, 0xce, 0x88, 0x7a, 0x14, 0x56, 0x24, 0xce, 0xa5, 0xb8, - 0xa4, 0x3f, 0x12, 0x0e, 0x65, 0x69, 0x41, 0x7f, 0xa6, 0xe7, 0x2c, 0x07, 0xbb, 0x5a, 0x16, 0xec, - 0xfe, 0xc6, 0x57, 0x1f, 0xb7, 0xac, 0xaf, 0x3f, 0x6e, 0x59, 0xdf, 0x7d, 0xdc, 0xb2, 0xfe, 0xf3, - 0xfd, 0xd6, 0xca, 0xd9, 0x2a, 0xfd, 0x51, 0xfa, 0xed, 0x8f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa2, - 0x18, 0x37, 0x1a, 0x61, 0x12, 0x00, 0x00, + // 1648 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xcd, 0x6e, 0xdb, 0xc6, + 0x13, 0x37, 0x45, 0xea, 0x6b, 0x24, 0x3b, 0xce, 0x46, 0xc9, 0x9f, 0xc8, 0xdf, 0x71, 0x04, 0xc2, + 0x6d, 0xd4, 0xa2, 0x70, 0xe0, 0x34, 0x09, 0x72, 0x69, 0x1b, 0x3b, 0x72, 0x6a, 0x22, 0xb5, 0x9b, + 0xae, 0x0c, 0xf7, 0x56, 0x80, 0x96, 0xb6, 0x0e, 0x51, 0x4a, 0x54, 0x29, 0x2a, 0xb2, 0x2f, 0x05, + 0xfa, 0x0c, 0xb9, 0xf4, 0x11, 0xfa, 0x1c, 0xbd, 0xb4, 0xc7, 0x1e, 0x0b, 0xf4, 0x52, 0xa4, 0x8f, + 0x91, 0x1e, 0x8a, 0x99, 0xe5, 0x6a, 0x49, 0x8a, 0x76, 0x8c, 0xa0, 0xb7, 0x9d, 0x8f, 0x9d, 0x9d, + 0xf9, 0xcd, 0xec, 0xec, 0x90, 0xd0, 0x1c, 0x4f, 0x8f, 0x03, 0xbf, 0xbf, 0x39, 0x8e, 0xc2, 0x38, + 0x64, 0x35, 0x7f, 0x14, 0x8b, 0x68, 0xe4, 0x05, 0xce, 0x04, 0x4c, 0x1e, 0xce, 0x98, 0x0d, 0xd5, + 0x27, 0x61, 0x30, 0x1d, 0x8e, 0x26, 0xb6, 0xd1, 0x36, 0x3b, 0x16, 0x57, 0x24, 0x63, 0x60, 0x3d, + 0x13, 0x67, 0x13, 0xdb, 0x6c, 0x9b, 0x9d, 0x3a, 0xa7, 0x35, 0xdb, 0x80, 0xf2, 0x76, 0x1c, 0x47, + 0x13, 0xbb, 0xd4, 0x36, 0x3b, 0x8d, 0x7b, 0x2b, 0x9b, 0xca, 0xdc, 0x26, 0xb2, 0xb9, 0x14, 0xa2, + 0x4d, 0x1e, 0x7a, 0x91, 0x3f, 0x3a, 0xb1, 0xad, 0xb6, 0xd1, 0x69, 0x72, 0x45, 0x3a, 0xfb, 0x50, + 0xef, 0xf9, 0x27, 0x23, 0x31, 0xc0, 0xa3, 0x6f, 0x83, 0xf9, 0x3c, 0xc4, 0x63, 0x8d, 0x4e, 0xe3, + 0xde, 0xb2, 0x36, 0xc5, 0xc3, 0x19, 0x47, 0x09, 0x2a, 0x1c, 0x88, 0x13, 0xbb, 0x54, 0xa8, 0x70, + 0x20, 0x4e, 0x9c, 0x47, 0xb0, 0xc2, 0xc3, 0x99, 0x3b, 0x10, 0xa3, 0xd8, 0xff, 0xd6, 0x17, 0x11, + 0x39, 0xcd, 0xc3, 0x99, 0x8a, 0x85, 0xd6, 0xf3, 0x40, 0x4a, 0x3a, 0x10, 0xe7, 0x26, 0x54, 0xdc, + 0xee, 0x17, 0xfe, 0x24, 0x66, 0xab, 0x60, 0xba, 0x5d, 0xb5, 0x01, 0x97, 0x8e, 0x0b, 0x57, 0x77, + 0x4f, 0xe3, 0xc8, 0xeb, 0xc7, 0x62, 0xe0, 0x76, 0x25, 0x1c, 0x6c, 0x05, 0x4a, 0x6e, 0x97, 0x7c, + 0xb5, 0x78, 0xc9, 0xed, 0xb2, 0x0d, 0xb0, 0x8e, 0xbc, 0x40, 0x01, 0xb1, 0xaa, 0x9d, 0x93, 0x66, + 0x39, 0x49, 0x9d, 0xe3, 0x8c, 0xa9, 0x7d, 0x2f, 0x8e, 0xfc, 0x53, 0x76, 0x03, 0x2a, 0x4f, 0x7d, + 0x11, 0x0c, 0xe4, 0xa1, 0x75, 0x9e, 0x50, 0xec, 0x81, 0x4e, 0x85, 0xb4, 0xfa, 0x7f, 0x6d, 0x75, + 0xc1, 0xa1, 0x79, 0x9e, 0x9c, 0x5b, 0x50, 0x7d, 0x26, 0xce, 0x28, 0x16, 0x15, 0xa9, 0x91, 0x8a, + 0xf4, 0x4f, 0x03, 0xae, 0xcd, 0x77, 0x1f, 0x7a, 0xc7, 0x81, 0x38, 0xf2, 0x82, 0xa9, 0x60, 0x1b, + 0x2a, 0x6e, 0xa3, 0xc8, 0xff, 0xbd, 0x25, 0xc2, 0x82, 0xdd, 0x99, 0x63, 0x87, 0x6a, 0x57, 0xb5, + 0x5a, 0x72, 0xe4, 0xde, 0x52, 0x52, 0x19, 0x6b, 0x50, 0xdb, 0xe9, 0xb9, 0x64, 0xda, 0x36, 0xdb, + 0x46, 0xc7, 0xdc, 0x5b, 0xe2, 0x73, 0x0e, 0xbb, 0x09, 0xd5, 0xfd, 0x69, 0x2c, 0x4e, 0xdd, 0x2e, + 0x55, 0x84, 0xb5, 0xb7, 0xc4, 0x15, 0x03, 0x77, 0xd2, 0xf2, 0x99, 0x38, 0xb3, 0xcb, 0x6d, 0xa3, + 0x53, 0xc7, 0x9d, 0x8a, 0xc3, 0x5a, 0x60, 0xed, 0x84, 0x61, 0x60, 0x57, 0xda, 0x46, 0xa7, 0x86, + 0xa7, 0x21, 0xb5, 0x53, 0x85, 0x32, 0x19, 0x76, 0x7e, 0x80, 0x56, 0x36, 0xb8, 0x24, 0x5d, 0x0c, + 0x4c, 0xb4, 0x67, 0x24, 0xf6, 0x90, 0x60, 0xab, 0x94, 0xc2, 0x52, 0x72, 0x3e, 0x26, 0xf1, 0x01, + 0x54, 0xc8, 0x8c, 0x2c, 0xf2, 0xc6, 0xbd, 0x5b, 0x05, 0x80, 0x6b, 0xc8, 0x78, 0xa2, 0xbc, 0x53, + 0x27, 0xc4, 0xbf, 0x8c, 0xdc, 0xae, 0xf3, 0x49, 0x1e, 0x5c, 0xca, 0x25, 0x26, 0xe2, 0xc0, 0x1b, + 0x0a, 0x79, 0x3e, 0xa7, 0x35, 0xf2, 0x0e, 0xcf, 0xc6, 0x82, 0x1c, 0xa8, 0x73, 0x5a, 0x3b, 0x3f, + 0x1a, 0xb0, 0x92, 0xdd, 0x8f, 0x3e, 0xa5, 0xaa, 0xe3, 0x02, 0x9f, 0x48, 0x6b, 0x5e, 0x3c, 0x8f, + 0xf2, 0xc5, 0xb3, 0x7e, 0xde, 0xbe, 0x7c, 0xfd, 0x7c, 0x0a, 0xd6, 0x73, 0xcf, 0x8f, 0x16, 0x2a, + 0x7c, 0x55, 0x42, 0x68, 0x92, 0xbb, 0xa6, 0xcc, 0x45, 0xf9, 0x49, 0x38, 0x1d, 0xc5, 0x12, 0x43, + 0x2e, 0x09, 0x67, 0x17, 0xea, 0xb8, 0x5f, 0x06, 0xee, 0x48, 0x63, 0x49, 0x59, 0xa5, 0xfa, 0x03, + 0x72, 0xb9, 0x3c, 0xa8, 0x05, 0x65, 0x52, 0x4e, 0x90, 0x90, 0x84, 0xb3, 0x07, 0x80, 0xd2, 0x89, + 0xb4, 0xb3, 0x01, 0x65, 0xa2, 0x12, 0x10, 0xf2, 0x86, 0xa4, 0xf0, 0x1c, 0x4b, 0xb7, 0xa0, 0xec, + 0x8e, 0xe2, 0x87, 0xf7, 0x51, 0x2c, 0x0b, 0x12, 0xbd, 0x31, 0x79, 0x52, 0x32, 0x53, 0xa8, 0x49, + 0xe8, 0xc2, 0x99, 0x36, 0x60, 0xa4, 0x0c, 0x20, 0x17, 0xdb, 0x4a, 0x57, 0xc5, 0x49, 0x04, 0x5e, + 0x5b, 0x1e, 0xce, 0x34, 0x24, 0x09, 0xc5, 0xde, 0x53, 0xa7, 0x58, 0x14, 0xf3, 0x95, 0xd4, 0x55, + 0x42, 0x2f, 0xd4, 0xb1, 0xdf, 0x00, 0x7c, 0x1e, 0x85, 0xd3, 0x31, 0x81, 0xc6, 0x3a, 0x50, 0x26, + 0x2a, 0x89, 0x8f, 0xe9, 0x4d, 0xca, 0x37, 0x2e, 0x15, 0x8a, 0x41, 0xc7, 0xe4, 0xf4, 0xa6, 0x43, + 0x79, 0xd3, 0x38, 0x2e, 0xb1, 0x94, 0x6a, 0x47, 0x5e, 0x30, 0x17, 0x1f, 0x79, 0x41, 0x12, 0x37, + 0x2e, 0xb3, 0x66, 0x4c, 0x65, 0xe6, 0x26, 0xd4, 0x9e, 0x06, 0xa1, 0x17, 0xa3, 0x32, 0xda, 0x32, + 0xf8, 0x9c, 0x66, 0x5b, 0x00, 0x5d, 0xd1, 0xf7, 0x87, 0x5e, 0x80, 0x52, 0x2b, 0xdf, 0x00, 0x12, + 0x19, 0x4f, 0x29, 0x39, 0x0f, 0xa0, 0x9a, 0x50, 0xc5, 0xd8, 0x23, 0xb7, 0xd7, 0xf7, 0x02, 0xa1, + 0xbc, 0x20, 0xc2, 0xf9, 0x1a, 0x96, 0x65, 0x31, 0xe2, 0xf3, 0xd1, 0x13, 0xf1, 0x25, 0x4a, 0xf1, + 0x52, 0x0f, 0x91, 0xf3, 0xb3, 0x01, 0x16, 0xae, 0x94, 0x01, 0x43, 0x1b, 0x48, 0xdf, 0x46, 0x4b, + 0xde, 0x46, 0xd6, 0x86, 0x46, 0x2f, 0xc6, 0x77, 0x4a, 0xb7, 0xb1, 0x3a, 0x4f, 0xb3, 0x10, 0x2f, + 0x77, 0x14, 0xeb, 0x74, 0x9b, 0x7c, 0x4e, 0xb3, 0x35, 0xa8, 0x63, 0x6f, 0x92, 0x42, 0x6c, 0x64, + 0x35, 0xae, 0x19, 0x6c, 0x1d, 0x40, 0x21, 0x3b, 0x15, 0xd4, 0xcd, 0x0c, 0x9e, 0xe2, 0x38, 0x77, + 0xa1, 0x8a, 0x9e, 0xee, 0x7b, 0x63, 0x1d, 0x9b, 0x71, 0x51, 0x6c, 0x6f, 0x0c, 0x68, 0x7e, 0x35, + 0x15, 0xd1, 0x19, 0x17, 0xdf, 0x4f, 0xc5, 0x24, 0x46, 0x6c, 0x89, 0x56, 0xb5, 0x4c, 0x04, 0x56, + 0x6d, 0xef, 0x85, 0x17, 0x0d, 0x24, 0x52, 0x16, 0x4f, 0x28, 0x8c, 0x55, 0x63, 0x3e, 0xa1, 0x58, + 0x6b, 0x3c, 0xcd, 0xa2, 0x7a, 0x17, 0xc3, 0x30, 0x56, 0xc1, 0x24, 0x14, 0xeb, 0xc0, 0x95, 0xdd, + 0xd3, 0x7e, 0x30, 0x1d, 0x08, 0x1e, 0xce, 0xe4, 0x6e, 0x6a, 0xce, 0x3c, 0xcf, 0x66, 0xef, 0x63, + 0x73, 0x23, 0x96, 0x6a, 0x4d, 0x55, 0x52, 0xcc, 0x71, 0xd9, 0x16, 0x34, 0x77, 0x87, 0xc7, 0x62, + 0x30, 0x10, 0x83, 0xae, 0x17, 0x7b, 0x76, 0x8d, 0xe2, 0xce, 0x3d, 0xf8, 0x19, 0x15, 0xe7, 0x95, + 0x01, 0xcb, 0x49, 0xf4, 0x93, 0x71, 0x38, 0x9a, 0x08, 0x4c, 0xf1, 0x6e, 0x14, 0xa9, 0x14, 0xef, + 0x46, 0x11, 0xbb, 0x0b, 0x55, 0x2e, 0x26, 0xd3, 0x20, 0x56, 0x55, 0x72, 0x5d, 0x5b, 0x54, 0x7b, + 0xa7, 0x41, 0xcc, 0x95, 0x16, 0xfb, 0x0c, 0x56, 0x32, 0x75, 0xa8, 0x9e, 0x85, 0xff, 0xe9, 0x7d, + 0x19, 0x39, 0xcf, 0xa9, 0x3b, 0x6f, 0x2c, 0x68, 0xa4, 0x2c, 0xcf, 0x8b, 0x0c, 0xf1, 0x59, 0x4e, + 0x8a, 0xec, 0x36, 0xcd, 0x5d, 0xe7, 0x4c, 0x3d, 0xd8, 0x93, 0x9a, 0x60, 0x1c, 0x24, 0x65, 0x69, + 0x1c, 0xe8, 0x46, 0x68, 0x5e, 0xd4, 0x08, 0x71, 0x8a, 0x7b, 0xe1, 0x8d, 0x4e, 0xc4, 0x80, 0xca, + 0xb2, 0xc6, 0x15, 0xc9, 0x36, 0x75, 0x57, 0xa0, 0x3c, 0x66, 0x7a, 0x8d, 0x92, 0x70, 0xdd, 0x39, + 0x64, 0x97, 0xc3, 0xc9, 0xa0, 0x2a, 0xeb, 0x45, 0x52, 0xec, 0x21, 0x34, 0x74, 0xfb, 0x9a, 0x24, + 0x29, 0x6a, 0x69, 0x53, 0x5a, 0xc8, 0xd3, 0x8a, 0xec, 0x71, 0x7e, 0x44, 0xb3, 0xeb, 0xe4, 0x85, + 0x9d, 0x89, 0x3c, 0x25, 0xe7, 0xf9, 0x91, 0x6e, 0x2b, 0x35, 0x33, 0xda, 0x40, 0x9b, 0xaf, 0xe9, + 0xcd, 0x73, 0x11, 0x4f, 0x4d, 0x96, 0xf7, 0xd3, 0x6f, 0x89, 0xdd, 0xa0, 0x3d, 0xad, 0x2c, 0x72, + 0x52, 0xc6, 0xd3, 0x6f, 0xce, 0x56, 0xea, 0x21, 0xb3, 0x9b, 0xf9, 0x83, 0xe6, 0x22, 0x9e, 0x7a, + 0xee, 0xdc, 0x82, 0xf9, 0xce, 0x5e, 0xa6, 0xad, 0xc5, 0xc3, 0x9b, 0x54, 0xe1, 0x05, 0x53, 0xe1, + 0xe3, 0xfc, 0x24, 0x60, 0xaf, 0xe4, 0x81, 0xca, 0xca, 0x79, 0x4e, 0xdf, 0xf9, 0xb5, 0x04, 0xcb, + 0xee, 0x70, 0x1c, 0x46, 0x71, 0xaa, 0x25, 0xb8, 0xa3, 0x81, 0x38, 0x55, 0x2d, 0x81, 0x88, 0xe2, + 0x57, 0x93, 0x5a, 0x33, 0xb6, 0x06, 0x6a, 0x05, 0x16, 0x97, 0x44, 0xaa, 0x1c, 0xac, 0x4c, 0x39, + 0xac, 0x41, 0x5d, 0xd6, 0x3e, 0x8a, 0xca, 0x24, 0xd2, 0x0c, 0xf9, 0x01, 0x30, 0xa3, 0xc1, 0xb1, + 0x4a, 0xa3, 0xa8, 0x22, 0xb1, 0x0d, 0x4a, 0x35, 0x12, 0xd6, 0x48, 0x98, 0xe2, 0xa0, 0xfc, 0xd0, + 0x1f, 0x8a, 0x49, 0xec, 0x0d, 0xc7, 0xd8, 0x57, 0xcc, 0x8e, 0xc9, 0x53, 0x1c, 0x6c, 0x29, 0x14, + 0xc4, 0x93, 0x48, 0x78, 0xb1, 0x18, 0x6c, 0xc7, 0x54, 0x4e, 0x26, 0xcf, 0x71, 0x51, 0x8f, 0xc2, + 0xd2, 0x7a, 0x20, 0xf5, 0xb2, 0x5c, 0x7a, 0x16, 0x03, 0xe1, 0x45, 0x54, 0x24, 0x35, 0x2e, 0x09, + 0xe7, 0x8f, 0x12, 0x30, 0x89, 0xa4, 0x1c, 0xfc, 0xfe, 0x33, 0x38, 0x2f, 0x86, 0x2d, 0x0b, 0x4e, + 0x75, 0x01, 0x9c, 0x1b, 0xf3, 0x71, 0x55, 0x02, 0x93, 0x50, 0xd8, 0xcb, 0xf5, 0x4b, 0x22, 0x51, + 0x35, 0x78, 0x9a, 0xc5, 0x1c, 0x68, 0xa6, 0x9e, 0x31, 0xbc, 0x83, 0x68, 0x3b, 0xc3, 0x2b, 0x80, + 0x16, 0x2e, 0x09, 0x6d, 0xe3, 0x62, 0x68, 0x9b, 0x69, 0x68, 0x5f, 0x19, 0xd0, 0xdc, 0x8e, 0xc3, + 0xa1, 0xdf, 0xe7, 0xa2, 0x1f, 0x46, 0x83, 0xf3, 0x41, 0x95, 0xf0, 0x95, 0xd2, 0xf0, 0x6d, 0x82, + 0xe9, 0xbe, 0x8c, 0x92, 0x56, 0xb8, 0x96, 0x1a, 0xb4, 0x16, 0x72, 0xc5, 0x51, 0x91, 0xdd, 0x81, + 0x92, 0x1b, 0x51, 0xe5, 0x66, 0x9a, 0x78, 0xe6, 0x92, 0xf0, 0x92, 0x1b, 0x39, 0x1f, 0x41, 0x4b, + 0x3a, 0xa5, 0x44, 0xc9, 0xa3, 0xd2, 0x82, 0xf2, 0x6e, 0x14, 0x85, 0xea, 0x59, 0x91, 0x84, 0x73, + 0x04, 0xad, 0xc3, 0xc8, 0x1b, 0x4d, 0x02, 0x2f, 0x16, 0x98, 0x98, 0x77, 0xa9, 0x8f, 0x82, 0xaf, + 0x6b, 0xe7, 0x03, 0xb8, 0x9e, 0xb3, 0xab, 0xdf, 0x36, 0x2c, 0x18, 0x53, 0x7f, 0xa3, 0xf6, 0xe0, + 0xda, 0x5c, 0xd5, 0xed, 0xbe, 0x93, 0x07, 0x8b, 0x46, 0x3f, 0x4c, 0xc5, 0x45, 0x46, 0x93, 0xe3, + 0x8b, 0x7c, 0xdd, 0x01, 0x3b, 0xc1, 0x4a, 0x7e, 0xda, 0x27, 0x1e, 0x1c, 0xf9, 0x62, 0x76, 0xde, + 0xd7, 0x0f, 0xbd, 0xed, 0x25, 0xfa, 0x21, 0x40, 0x6b, 0xe7, 0x1f, 0x03, 0x5a, 0x45, 0x46, 0x74, + 0xe9, 0x18, 0xa9, 0xd2, 0x61, 0x8f, 0xa0, 0xfc, 0xd2, 0x17, 0x33, 0xf5, 0x9a, 0x3b, 0x0b, 0x09, + 0x5d, 0xf0, 0x84, 0xcb, 0x0d, 0x78, 0x71, 0xb6, 0xfb, 0xb1, 0x1f, 0x8e, 0xd4, 0xe8, 0x2e, 0x29, + 0x3c, 0x67, 0x27, 0x08, 0xfb, 0xdf, 0xc9, 0x8f, 0x52, 0x2e, 0x89, 0x82, 0x8b, 0x50, 0xbe, 0xe4, + 0x45, 0xa8, 0x14, 0x5e, 0x84, 0x1b, 0x50, 0xe9, 0xfa, 0x91, 0xe8, 0xc7, 0xc9, 0xf8, 0x93, 0x50, + 0xce, 0x2f, 0x86, 0xc2, 0x30, 0x35, 0x76, 0xbd, 0x35, 0x93, 0xfa, 0x5a, 0x98, 0xea, 0x5a, 0xd8, + 0x72, 0x76, 0xd4, 0x23, 0xb2, 0x22, 0x71, 0x5e, 0xc5, 0x25, 0xfd, 0xa9, 0xb0, 0x28, 0x7b, 0x73, + 0xfa, 0x2d, 0xbd, 0x68, 0x11, 0x84, 0x4a, 0x11, 0x08, 0x3b, 0xab, 0xbf, 0xbd, 0x5e, 0x37, 0x7e, + 0x7f, 0xbd, 0x6e, 0xfc, 0xf5, 0x7a, 0xdd, 0xf8, 0xe9, 0xef, 0xf5, 0xa5, 0xe3, 0x0a, 0xfd, 0x69, + 0xfa, 0xf8, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x19, 0xaa, 0x41, 0xe0, 0x79, 0x12, 0x00, 0x00, } func (m *Row) Marshal() (dAtA []byte, err error) { @@ -4886,6 +4894,16 @@ func (m *ImportRoaringRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Direct { + i-- + if m.Direct { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } if m.FieldCreatedAt != 0 { i = encodeVarintPublic(dAtA, i, uint64(m.FieldCreatedAt)) i-- @@ -6046,6 +6064,9 @@ func (m *ImportRoaringRequest) Size() (n int) { if m.FieldCreatedAt != 0 { n += 1 + sovPublic(uint64(m.FieldCreatedAt)) } + if m.Direct { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -12075,6 +12096,26 @@ func (m *ImportRoaringRequest) Unmarshal(dAtA []byte) error { break } } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Direct", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPublic + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Direct = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPublic(dAtA[iNdEx:]) diff --git a/internal/public.proto b/internal/public.proto index 9b102651f..4a4bf71c5 100644 --- a/internal/public.proto +++ b/internal/public.proto @@ -235,7 +235,7 @@ message ImportRoaringRequest { uint64 Block = 4; int64 IndexCreatedAt = 5; int64 FieldCreatedAt = 6; - + bool Direct = 7; } message ImportColumnAttrsRequest { diff --git a/rbf.go b/rbf.go index 5b28a8ead..6317022e7 100644 --- a/rbf.go +++ b/rbf.go @@ -470,8 +470,13 @@ func (w *RbfDBWrapper) Close() error { var globalNextTxSnRBFTx int64 -func (w *RbfDBWrapper) NewTx(write bool, initialIndex string, o Txo) (Tx, error) { - tx, err := w.db.Begin(write) +func (w *RbfDBWrapper) NewTx(write bool, initialIndex string, o Txo) (_ Tx, err error) { + var tx *rbf.Tx + if write && o.Direct { // obtain exclusive lock if writing directly to db. + tx, err = w.db.BeginWithExclusiveLock() + } else { + tx, err = w.db.Begin(write) + } if err != nil { return nil, err } diff --git a/txfactory.go b/txfactory.go index c403e5104..53d063a5e 100644 --- a/txfactory.go +++ b/txfactory.go @@ -123,6 +123,10 @@ type Qcx struct { // efficient access to the options for RequiredForAtomicWriteTx RequiredTxo *Txo + // Option for direct writes to the database. RBF only. + // This option is unsafe and should only be used for imports. + Direct bool + isRoaring bool } @@ -220,6 +224,11 @@ func (qcx *Qcx) GetTx(o Txo) (tx Tx, finisher func(perr *error)) { qcx.mu.Lock() defer qcx.mu.Unlock() + // Use direct option if set on QCX. + if qcx.Direct { + o.Direct = true + } + // roaring uses finer grain, a file per fragment rather than // db per shard. So we can't re-use the readTx. Moreover, // roaring Tx are No-ops anyway, so just give it a new Tx @@ -469,6 +478,7 @@ func NewTxFactory(txsrc string, holderDir string, holder *Holder) (f *TxFactory, // Txo holds the transaction options type Txo struct { Write bool + Direct bool // directly write to the database. rbf only. (unsafe) Field *Field Index *Index Fragment *fragment From ecacbf65d484039aaba2aa99850f01bb6d64fe2a Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 8 Sep 2020 11:44:56 -0500 Subject: [PATCH 3/6] Document copy-on-write semantics, at all. The copy-on-write semantics were previously documented only in the 125-line commit log from the patch which introduced them. Add documentation for them in a few likely places. --- roaring/container_stash.go | 24 +++++++++++++++++++++++- roaring/roaring.go | 15 +++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/roaring/container_stash.go b/roaring/container_stash.go index 6cdd53287..e18725d6f 100644 --- a/roaring/container_stash.go +++ b/roaring/container_stash.go @@ -34,6 +34,26 @@ const ( // less than 4,096 values, an array is often used. Containers with long runs of // integers would use run length encoding, and more random data usually uses // bitmap encoding. +// +// The Container type has somewhat magical semantics. Containers can be marked +// as "frozen" by the Freeze method, after which, nothing should ever modify +// that specific container object again, no matter what. Because of this, but +// also sometimes for Even More Esoteric Reasons, *no* container method should +// ever be assumed to be genuinely modifying the container it was called on, +// and *every* container method that might modify a container should return +// the "modified" *Container, which *may point to a different object*. The +// caller should always use this resulting container, and if you're storing +// a *Container in a data structure, you need to update the data structure's +// pointer too. +// +// A nil *Container is a valid empty container. +// +// In general, operations on containers which produce new containers *may* +// yield new containers, and *may* yield their operands. +// +// The reason for all of this is to allow containers to have copy-on-write +// semantics, which allow us to reduce memory usage dramatically, and GC +// load even more dramatically. type Container struct { pointer *uint16 // the data pointer len, cap int32 // length and cap @@ -264,7 +284,9 @@ func (c *Container) setMapped(mapped bool) { // Freeze returns an unmodifiable container identical to c. This might // be c, now marked unmodifiable, or might be a new container. If c // is currently marked as "mapped", referring to a backing store that's -// not a conventional Go pointer, the storage may be copied. +// not a conventional Go pointer, the storage may (or may not) be copied. +// Do not call Freeze on a temporarily-corrupt container, such as one +// returned from UnionInPlace but on which you haven't since called Repair. func (c *Container) Freeze() *Container { if c == nil { return nil diff --git a/roaring/roaring.go b/roaring/roaring.go index d6dc93362..88733db2e 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -6876,9 +6876,14 @@ func ConvertRunToBitmap(c *Container) *Container { return c.runToBitmap() } +// Optimize yields a container with the same bits as c, but +// adjusted to the smallest-storage type by Roaring rules (thus, +// runs where that's smaller, otherwise arrays for N < 4096 and +// bitmaps for N >= 4096). func Optimize(c *Container) *Container { return c.optimize() } + func Union(a, b *Container) (c *Container) { c = union(a, b) // c can be have arrays that are too big, and need @@ -6890,10 +6895,16 @@ func Difference(a, b *Container) *Container { return difference(a, b) } +// Add yields a container identical to c, but with the given bit set; added +// is true if the bit wasn't previously set. It is unspecified whether +// the original container is modified. func (c *Container) Add(v uint16) (newC *Container, added bool) { return c.add(v) } +// Add yields a container identical to c, but with the given bit cleared; +// removed is true if the bit was previously set. It is unspecified whether +// the original container is modified. func (c *Container) Remove(v uint16) (c2 *Container, removed bool) { return c.remove(v) } @@ -6906,6 +6917,10 @@ func (c *Container) CountRange(start, end int32) (n int32) { return c.countRange(start, end) } +// UnionInPlace yields a container containing all the bits set in either +// c or other. It may, or may not, modify c. The resulting container's +// count, as returned by c.N(), may be incorrect; see (*Container).Repair(). +// Do not freeze a container produced by this operation before repairing it. func (c *Container) UnionInPlace(other *Container) (r *Container) { return c.unionInPlace(other) } From 17ba2e35a902a9dae568bd44df49d53bc35c528c Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 8 Sep 2020 12:21:01 -0500 Subject: [PATCH 4/6] call helper functions every time to get new run slices If you just stash the results of the function when defining the test cases, the outcome is in part that you are reusing the same slices for multiple things. So, for instance, if you perform a union on the OddBitsSet slice, with the EvenBitsSet slice, the result is to overwrite the first entry in that slice with the 0-ffff run... But the original slice still exists, and then we reuse it and get a slice with a bit count of around 98,000. The underlying issue is that doContainer() is calling NewContainerRun(), which is simply using the provided slice, not copying it -- which is intentional, but the test has to be careful about it. We call repair on the one we think should be a bitmap. Theoretically maybe we should also repair the other one in case unionRunRun some day starts returning unrepaired bitmaps, which in principle it's allowed to do... --- roaring/roaring_internal_test.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index b10964cb5..c75df2140 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -4375,26 +4375,28 @@ func BenchmarkUnionRunRunInPlace(bm *testing.B) { func TestUnionRunRunInPlaceBitwiseCompare(t *testing.T) { runs := []struct { name string - run []Interval16 + fn func() []Interval16 }{ - {name: "FirstBitSet", run: runFirstBitSet()}, - {name: "LastBitSet", run: runLastBitSet()}, - {name: "FirstBitUnset", run: runFirstBitUnset()}, - {name: "LastBitUnset", run: runLastBitUnset()}, - {name: "InnerBitsSet", run: runInnerBitsSet()}, - {name: "OuterBitsSet", run: runOuterBitsSet()}, - {name: "OddBitsSet", run: runOddBitsSet()}, - {name: "EvenBitsSet", run: runEvenBitsSet()}, + {name: "FirstBitSet", fn: runFirstBitSet}, + {name: "LastBitSet", fn: runLastBitSet}, + {name: "FirstBitUnset", fn: runFirstBitUnset}, + {name: "LastBitUnset", fn: runLastBitUnset}, + {name: "InnerBitsSet", fn: runInnerBitsSet}, + {name: "OuterBitsSet", fn: runOuterBitsSet}, + {name: "OddBitsSet", fn: runOddBitsSet}, + {name: "EvenBitsSet", fn: runEvenBitsSet}, } for _, a := range runs { for _, b := range runs { t.Run(a.name+"-"+b.name, func(t *testing.T) { - arun := doContainer(ContainerRun, a.run) - brun := doContainer(ContainerRun, b.run) + arun := doContainer(ContainerRun, a.fn()) + abm := doContainer(ContainerRun, a.fn()).runToBitmap() + brun := doContainer(ContainerRun, b.fn()) - out1 := unionBitmapRunInPlace(arun.runToBitmap(), brun) + out1 := unionBitmapRunInPlace(abm, brun) out2 := unionRunRunInPlace(arun, brun) + out1.Repair() err := out1.BitwiseCompare(out2.runToBitmap()) if err != nil { From c079d4764befce5927fa1a4d3cad49171a716c20 Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 8 Sep 2020 13:16:54 -0500 Subject: [PATCH 5/6] Check for possibly-dirty N values in containers modified in-place After documenting the semantics, I noticed an arguable hole in them, which is that you could Freeze() a dirty container, and then Repair() wouldn't work on it. On further study, I added a roaringparanoia check for attempts to access the N of dirty containers. It turns out there's several such. But also, it turns out, there's circumstances where unionInPlace is relying on the assumption that N is valid, which it isn't always for dirty containers. Also, there's at least one case where we rely on the assumption that forcibly thawing a container, then calling unionInPlace on it, always modifies that container. But that's not supposed to be true for an empty container -- an empty container might be better handled by just returning the container it's being unioned with. So, we drop the unnecessary thaw (all the *InPlace ops are already thawing if/when they need to), but we use the return from unionInPlace. --- roaring/container_stash.go | 59 +++++++++++++++++++++++++++++++++++--- roaring/roaring.go | 51 +++++++++++++++++++++----------- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/roaring/container_stash.go b/roaring/container_stash.go index e18725d6f..e08f823a6 100644 --- a/roaring/container_stash.go +++ b/roaring/container_stash.go @@ -74,16 +74,25 @@ var containerFlagStrings = [...]string{ "pristine/mapped", "pristine/frozen", "pristine/frozen/mapped", + "dirty", + "mapped/dirty", + "frozen/dirty", + "frozen/mapped/dirty", + "pristine/dirty", + "pristine/mapped/dirty", + "pristine/frozen/dirty", + "pristine/frozen/mapped/dirty", } func (f containerFlags) String() string { - return containerFlagStrings[f&7] + return containerFlagStrings[f&15] } const ( - flagMapped = containerFlags(1 << iota) - flagFrozen - flagPristine + flagMapped = containerFlags(1 << iota) // using memory-mapped or otherwise external storage + flagFrozen // not modifiable + flagPristine // flagPristine is used for mmapped containers referring to storage + flagDirty // flagDirty is used for containers which may have invalid N ) func (c *Container) String() string { @@ -232,11 +241,30 @@ func (c *Container) frozen() bool { return (c.flags & flagFrozen) != 0 } +// SafeN returns N, true if it can, otherwise it returns 0, false. For +// instance, a container subject to in-place operations can not know its +// current N, and it's not meaningful or safe to query it until a repair, +// so you can use this to get N "if it's available". +func (c *Container) SafeN() (int32, bool) { + if c == nil { + return 0, true + } + if (c.flags & flagDirty) != 0 { + return 0, false + } + return c.n, true +} + // N returns the 1-count of the container. func (c *Container) N() int32 { if c == nil { return 0 } + if roaringParanoia { + if c.flags&flagDirty != 0 { + panic("trying to call N() on a dirty container") + } + } return c.n } @@ -281,6 +309,21 @@ func (c *Container) setMapped(mapped bool) { } } +// setDirty marks a container as "dirty" -- we don't trust container's n. +// this should never happen except for bitmaps. +func (c *Container) setDirty(dirty bool) { + if roaringParanoia { + if c == nil || c.frozen() { + panic("setDirty on nil or frozen container") + } + } + if dirty { + c.flags |= flagDirty + } else { + c.flags &^= flagDirty + } +} + // Freeze returns an unmodifiable container identical to c. This might // be c, now marked unmodifiable, or might be a new container. If c // is currently marked as "mapped", referring to a backing store that's @@ -291,6 +334,14 @@ func (c *Container) Freeze() *Container { if c == nil { return nil } + if c.flags&flagDirty != 0 { + if roaringParanoia { + panic("freezing dirty container") + } + // c.Repair won't work if this is already frozen, but in + // theory that can't happen? + c.Repair() + } // don't need to freeze if c.flags&flagFrozen != 0 { return c diff --git a/roaring/roaring.go b/roaring/roaring.go index 88733db2e..eabec3b86 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1366,11 +1366,12 @@ func (b *Bitmap) unionInPlace(others ...*Bitmap) { tContainer := target.Containers.Get(iKey) // if the target's full, short-circuit out. if tContainer != nil { - if tContainer.N() == MaxContainerVal+1 { + tN, ok := tContainer.SafeN() + if ok && tN == MaxContainerVal+1 { bitmapIters.markItersWithKeyAsHandled(i, iKey) continue } - expectedN = int64(tContainer.N()) + expectedN = int64(tN) } // Check i and later iters for any max-range containers, and // find out how many there are. @@ -1445,8 +1446,7 @@ func (b *Bitmap) unionInPlace(others ...*Bitmap) { jKey, jContainer := iter.iter.Value() if iKey == jKey { - tContainer = tContainer.Thaw() - tContainer.unionInPlace(jContainer) + tContainer = tContainer.unionInPlace(jContainer) // "iter" is a local copy from the range // loop, not the actual slice member. itersToUnion[j].handled = true @@ -3191,15 +3191,24 @@ func (c *Container) optimize() *Container { // it is possible that the returned container will not actually be the // original container; in-place is a suggestion. func (c *Container) unionInPlace(other *Container) *Container { - if c == nil { - return other.Freeze() - } - if other == nil { - return c - } // short-circuit the trivial cases - if c.N() == MaxContainerVal+1 || other.N() == MaxContainerVal+1 { - return fullContainer + cN, cOk := c.SafeN() + if cOk { + if cN == MaxContainerVal+1 { + return fullContainer + } + if cN == 0 { + return other.Clone() + } + } + oN, oOk := other.SafeN() + if oOk { + if oN == MaxContainerVal+1 { + return fullContainer + } + if oN == 0 { + return c + } } switch c.typ() { case ContainerBitmap: @@ -3487,6 +3496,11 @@ func (c *Container) runToBitmap() *Container { } return nil } + if roaringParanoia { + if c.N() > 65536 { + panic(fmt.Sprintf("runToBitmap: container N %d", c.N())) + } + } // return early if empty if c.N() == 0 { @@ -3864,6 +3878,7 @@ func (c *Container) Repair() { } if c.isBitmap() { c.bitmapRepair() + c.setDirty(false) } } @@ -4536,6 +4551,7 @@ func unionBitmapRun(a, b *Container) *Container { // a will need to be repaired after the fact. func unionBitmapRunInPlace(a, b *Container) *Container { a = a.Thaw() + a.setDirty(true) bitmap := a.bitmap() statsHit("union/BitmapRun") for _, run := range b.runs() { @@ -4708,10 +4724,11 @@ func compareArrayArray(a1, a2 []uint16) error { // an error describing any difference it finds. This is mostly intended // for use in tests that expect equality. func (c *Container) BitwiseCompare(c2 *Container) error { - if c.N() != c2.N() { - return errors.New("containers are different lengths") + cn, c2n := c.N(), c2.N() + if cn != c2n { + return fmt.Errorf("containers are different lengths (%d vs %d)", cn, c2n) } - if c.N() == 0 { + if cn == 0 { return nil } switch typePair(c.typ(), c2.typ()) { @@ -4728,7 +4745,7 @@ func (c *Container) BitwiseCompare(c2 *Container) error { default: c3 := xor(c, c2) if c3.N() != 0 { - return fmt.Errorf("%d bits differenct between containers", c3.N()) + return fmt.Errorf("%d bits different between containers", c3.N()) } } return nil @@ -4753,6 +4770,7 @@ func unionArrayBitmap(a, b *Container) *Container { func unionBitmapArrayInPlace(a, b *Container) *Container { a = a.Thaw() bitmap := a.bitmap() + a.setDirty(true) for _, v := range b.array() { bitmap[v>>6] |= (uint64(1) << (v % 64)) } @@ -4800,6 +4818,7 @@ func unionBitmapBitmapInPlace(a, b *Container) *Container { ab[i+2] |= bb[i+2] ab[i+3] |= bb[i+3] } + a.setDirty(true) return a } From 6ff224308d4c09ebfb8476a48a6b14a98a2d1b1e Mon Sep 17 00:00:00 2001 From: Nia Weiss Date: Wed, 9 Sep 2020 09:11:21 -0400 Subject: [PATCH 6/6] fix inspect panic from incorrect handling of the many types of empty argument --- server/grpc.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/server/grpc.go b/server/grpc.go index b66a44364..a6b456d4e 100644 --- a/server/grpc.go +++ b/server/grpc.go @@ -454,9 +454,13 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe offset := req.Offset if !index.Keys() { - ints, ok := req.Columns.Type.(*pb.IdsOrKeys_Ids) - if !ok { - return errors.New("invalid int columns") + var cols []uint64 + if req.Columns != nil { + ints, ok := req.Columns.Type.(*pb.IdsOrKeys_Ids) + if !ok { + return errors.New("invalid int columns") + } + cols = ints.Ids.Vals } ci := []*pb.ColumnInfo{ {Name: "_id", Datatype: "uint64"}, @@ -471,7 +475,6 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe // If Columns is empty, then get the _exists list (via All()), // from the index and loop over that instead. - cols := ints.Ids.Vals if len(cols) > 0 { // Apply limit/offset to the provided columns. if int(offset) >= len(cols) { @@ -733,15 +736,17 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe } else { var cols []string - switch keys := req.Columns.Type.(type) { - case *pb.IdsOrKeys_Ids: - // The default behavior (in api/client/grpc.go) is to - // send an empty set of Ids even if the index supports - // keys, so in that case we just need to ignore it. - case *pb.IdsOrKeys_Keys: - cols = keys.Keys.Vals - default: - return errToStatusError(errors.New("invalid key columns")) + if req.Columns != nil { + switch keys := req.Columns.Type.(type) { + case *pb.IdsOrKeys_Ids: + // The default behavior (in api/client/grpc.go) is to + // send an empty set of Ids even if the index supports + // keys, so in that case we just need to ignore it. + case *pb.IdsOrKeys_Keys: + cols = keys.Keys.Vals + default: + return errToStatusError(errors.New("invalid key columns")) + } } forceSend := false