From 181d2959c96508f77bd89c08f74e65e41ae5217e Mon Sep 17 00:00:00 2001 From: Christophe Poucet Date: Tue, 30 Jun 2026 09:37:04 +0100 Subject: [PATCH] feat(graph): add per-node timing and datastore-read attribution to check debug trace Adds start_time and datastore_queries to the internal dispatch CheckDebugTrace so a single Check / CheckBulk debug trace can answer two questions that duration alone cannot: (1) whether sub-problems were traversed concurrently, and (2) where time was spent blocked on datastore reads. start_time is the wall-clock anchor for each node (the monotonic duration stays authoritative; end = start_time + duration). A context-scoped, concurrency-safe collector is installed per dispatch node; the observable datastore proxy records each relationship query (shape, start, duration, row count) into it, so reads attribute to the node that issued them. Both only activate when debug tracing is enabled, leaving the non-debug hot path untouched. This is the internal-proto-only slice; the public authzed/api CheckDebugTrace fields and the internal->public conversion follow once that field lands. Refs authzed/spicedb#3198 --- internal/datastore/proxy/observable.go | 30 +- internal/datastore/proxy/observable_test.go | 87 ++++ internal/dstrace/collector.go | 71 +++ internal/dstrace/collector_test.go | 78 ++++ internal/graph/check.go | 9 + internal/graph/computed/computecheck_test.go | 84 ++++ pkg/proto/dispatch/v1/dispatch.pb.go | 297 +++++++++---- pkg/proto/dispatch/v1/dispatch_vtproto.pb.go | 442 +++++++++++++++++++ proto/internal/dispatch/v1/dispatch.proto | 12 + 9 files changed, 1009 insertions(+), 101 deletions(-) create mode 100644 internal/dstrace/collector.go create mode 100644 internal/dstrace/collector_test.go diff --git a/internal/datastore/proxy/observable.go b/internal/datastore/proxy/observable.go index e819f7d45a..e052557c70 100644 --- a/internal/datastore/proxy/observable.go +++ b/internal/datastore/proxy/observable.go @@ -2,6 +2,7 @@ package proxy import ( "context" + "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -12,6 +13,7 @@ import ( v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" "github.com/authzed/spicedb/internal/datastore/common" + "github.com/authzed/spicedb/internal/dstrace" "github.com/authzed/spicedb/internal/telemetry/otelconv" "github.com/authzed/spicedb/pkg/datastore" "github.com/authzed/spicedb/pkg/datastore/options" @@ -230,12 +232,19 @@ func (r *observableReader) LegacyReadNamespaceByName(ctx context.Context, nsName func (r *observableReader) QueryRelationships(ctx context.Context, filter datastore.RelationshipsFilter, opts ...options.QueryOptionsOption) (datastore.RelationshipIterator, error) { queryOpts := options.NewQueryOptionsWithOptions(opts...) - ctx, closer := observe(ctx, "QueryRelationships", string(queryOpts.QueryShape), trace.WithAttributes( + queryShape := string(queryOpts.QueryShape) + ctx, closer := observe(ctx, "QueryRelationships", queryShape, trace.WithAttributes( attribute.String(otelconv.AttrDatastoreResourceType, filter.OptionalResourceType), attribute.String(otelconv.AttrDatastoreResourceRelation, filter.OptionalResourceRelation), - attribute.String(otelconv.AttrDatastoreQueryShape, string(queryOpts.QueryShape)), + attribute.String(otelconv.AttrDatastoreQueryShape, queryShape), )) + collector := dstrace.CollectorFromContext(ctx) + var start time.Time + if collector != nil { + start = time.Now() + } + iterator, err := r.delegate.QueryRelationships(ctx, filter, opts...) if err != nil { closer() @@ -253,14 +262,24 @@ func (r *observableReader) QueryRelationships(ctx context.Context, filter datast } } loadedRelationshipCount.Observe(float64(count)) + if collector != nil { + collector.Record(queryShape, start, time.Since(start), count) + } }, nil } func (r *observableReader) ReverseQueryRelationships(ctx context.Context, subjectsFilter datastore.SubjectsFilter, opts ...options.ReverseQueryOptionsOption) (datastore.RelationshipIterator, error) { queryOpts := options.NewReverseQueryOptionsWithOptions(opts...) - ctx, closer := observe(ctx, "ReverseQueryRelationships", string(queryOpts.QueryShapeForReverse), trace.WithAttributes( + queryShape := string(queryOpts.QueryShapeForReverse) + ctx, closer := observe(ctx, "ReverseQueryRelationships", queryShape, trace.WithAttributes( attribute.String(otelconv.AttrDatastoreSubjectType, subjectsFilter.SubjectType), - attribute.String(otelconv.AttrDatastoreQueryShape, string(queryOpts.QueryShapeForReverse)))) + attribute.String(otelconv.AttrDatastoreQueryShape, queryShape))) + + collector := dstrace.CollectorFromContext(ctx) + var start time.Time + if collector != nil { + start = time.Now() + } iterator, err := r.delegate.ReverseQueryRelationships(ctx, subjectsFilter, opts...) if err != nil { @@ -279,6 +298,9 @@ func (r *observableReader) ReverseQueryRelationships(ctx context.Context, subjec } } loadedRelationshipCount.Observe(float64(count)) + if collector != nil { + collector.Record(queryShape, start, time.Since(start), count) + } }, nil } diff --git a/internal/datastore/proxy/observable_test.go b/internal/datastore/proxy/observable_test.go index 60f641a503..e45e6d69a5 100644 --- a/internal/datastore/proxy/observable_test.go +++ b/internal/datastore/proxy/observable_test.go @@ -13,7 +13,10 @@ import ( "github.com/authzed/spicedb/internal/datastore/proxy/proxy_test" "github.com/authzed/spicedb/internal/datastore/revisions" + "github.com/authzed/spicedb/internal/dstrace" "github.com/authzed/spicedb/pkg/datastore" + "github.com/authzed/spicedb/pkg/datastore/options" + "github.com/authzed/spicedb/pkg/datastore/queryshape" core "github.com/authzed/spicedb/pkg/proto/core/v1" "github.com/authzed/spicedb/pkg/tuple" ) @@ -360,6 +363,90 @@ func TestObservableProxy_ReaderMethodsWithMetrics(t *testing.T) { } } +func TestObservableProxy_RecordsDatastoreQueriesToCollector(t *testing.T) { + t.Run("QueryRelationships", func(t *testing.T) { + dsMock, readerMock, _ := newMocks() + twoRelIter := datastore.RelationshipIterator(func(yield func(tuple.Relationship, error) bool) { + if !yield(tuple.MustParse("document:1#viewer@user:1"), nil) { + return + } + yield(tuple.MustParse("document:1#viewer@user:2"), nil) + }) + readerMock.On("QueryRelationships", datastore.RelationshipsFilter{OptionalResourceType: "document"}, mock.Anything). + Return(twoRelIter, nil).Once() + + sut := NewObservableDatastoreProxy(dsMock) + ctx, collector := dstrace.WithCollector(t.Context()) + + iter, err := sut.SnapshotReader(testRev).QueryRelationships( + ctx, + datastore.RelationshipsFilter{OptionalResourceType: "document"}, + options.WithQueryShape(queryshape.CheckPermissionSelectDirectSubjects), + ) + require.NoError(t, err) + for range iter { + } + + queries := collector.Queries() + require.Len(t, queries, 1) + require.Equal(t, string(queryshape.CheckPermissionSelectDirectSubjects), queries[0].QueryShape) + require.Equal(t, uint64(2), queries[0].RelationshipCount) + require.NotNil(t, queries[0].StartTime) + require.NotNil(t, queries[0].Duration) + + dsMock.AssertExpectations(t) + readerMock.AssertExpectations(t) + }) + + t.Run("ReverseQueryRelationships", func(t *testing.T) { + dsMock, readerMock, _ := newMocks() + oneRelIter := datastore.RelationshipIterator(func(yield func(tuple.Relationship, error) bool) { + yield(tuple.MustParse("document:1#viewer@user:1"), nil) + }) + readerMock.On("ReverseQueryRelationships", datastore.SubjectsFilter{SubjectType: "user"}, mock.Anything). + Return(oneRelIter, nil).Once() + + sut := NewObservableDatastoreProxy(dsMock) + ctx, collector := dstrace.WithCollector(t.Context()) + + iter, err := sut.SnapshotReader(testRev).ReverseQueryRelationships( + ctx, + datastore.SubjectsFilter{SubjectType: "user"}, + options.WithQueryShapeForReverse(queryshape.MatchingResourcesForSubject), + ) + require.NoError(t, err) + for range iter { + } + + queries := collector.Queries() + require.Len(t, queries, 1) + require.Equal(t, string(queryshape.MatchingResourcesForSubject), queries[0].QueryShape) + require.Equal(t, uint64(1), queries[0].RelationshipCount) + + dsMock.AssertExpectations(t) + readerMock.AssertExpectations(t) + }) + + t.Run("no collector is a no-op", func(t *testing.T) { + dsMock, readerMock, _ := newMocks() + iter := datastore.RelationshipIterator(func(yield func(tuple.Relationship, error) bool) { + yield(tuple.MustParse("document:1#viewer@user:1"), nil) + }) + readerMock.On("QueryRelationships", datastore.RelationshipsFilter{OptionalResourceType: "document"}). + Return(iter, nil).Once() + + sut := NewObservableDatastoreProxy(dsMock) + got, err := sut.SnapshotReader(testRev).QueryRelationships( + t.Context(), datastore.RelationshipsFilter{OptionalResourceType: "document"}) + require.NoError(t, err) + for range got { + } + + dsMock.AssertExpectations(t) + readerMock.AssertExpectations(t) + }) +} + func TestObservableProxy_RWTMethodsWithMetrics(t *testing.T) { tests := []struct { name string diff --git a/internal/dstrace/collector.go b/internal/dstrace/collector.go new file mode 100644 index 0000000000..402d5ba454 --- /dev/null +++ b/internal/dstrace/collector.go @@ -0,0 +1,71 @@ +// Package dstrace provides a context-scoped collector for attributing datastore +// query timings to a single Check dispatch node. It is populated by the +// observable datastore proxy and drained into the check debug trace, but lives +// in its own leaf package so neither side has to depend on the other. +package dstrace + +import ( + "context" + "sync" + "time" + + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1" +) + +type collectorCtxKey struct{} + +// Collector accumulates datastore query observations for a single Check +// dispatch node. It is safe for concurrent use: a node may issue multiple +// relationship queries in parallel (e.g. the branches of a union). +type Collector struct { + mu sync.Mutex + queries []*v1.DatastoreQuery +} + +// WithCollector returns a context carrying a fresh Collector, along with that +// collector. It should be called once per dispatch node when debug tracing is +// enabled so that the queries the node issues itself are attributed to it; +// dispatched children re-install their own collector and therefore capture their +// own queries. +func WithCollector(ctx context.Context) (context.Context, *Collector) { + c := &Collector{} + return context.WithValue(ctx, collectorCtxKey{}, c), c +} + +// CollectorFromContext returns the Collector stored in ctx, or nil if none is +// present (i.e. debug tracing is disabled). A nil Collector is safe to call +// Record/Queries on. +func CollectorFromContext(ctx context.Context) *Collector { + c, _ := ctx.Value(collectorCtxKey{}).(*Collector) + return c +} + +// Record appends a single datastore query observation. It is a no-op on a nil +// Collector. +func (c *Collector) Record(queryShape string, start time.Time, duration time.Duration, relationshipCount uint64) { + if c == nil { + return + } + c.mu.Lock() + defer c.mu.Unlock() + c.queries = append(c.queries, &v1.DatastoreQuery{ + QueryShape: queryShape, + StartTime: timestamppb.New(start), + Duration: durationpb.New(duration), + RelationshipCount: relationshipCount, + }) +} + +// Queries returns the collected datastore query observations. It returns nil on +// a nil Collector. +func (c *Collector) Queries() []*v1.DatastoreQuery { + if c == nil { + return nil + } + c.mu.Lock() + defer c.mu.Unlock() + return c.queries +} diff --git a/internal/dstrace/collector_test.go b/internal/dstrace/collector_test.go new file mode 100644 index 0000000000..d3cc016e86 --- /dev/null +++ b/internal/dstrace/collector_test.go @@ -0,0 +1,78 @@ +package dstrace + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestCollectorFromContextAbsentIsNilSafe(t *testing.T) { + c := CollectorFromContext(context.Background()) + require.Nil(t, c) + + // A nil collector must be safe to use. + c.Record("shape", time.Now(), time.Millisecond, 1) + require.Nil(t, c.Queries()) +} + +func TestWithCollectorRecordsQueries(t *testing.T) { + ctx, c := WithCollector(context.Background()) + require.NotNil(t, c) + require.Same(t, c, CollectorFromContext(ctx)) + + start := time.Now() + c.Record("shape-a", start, 2*time.Millisecond, 3) + c.Record("shape-b", start, 5*time.Millisecond, 0) + + queries := c.Queries() + require.Len(t, queries, 2) + + require.Equal(t, "shape-a", queries[0].QueryShape) + require.Equal(t, uint64(3), queries[0].RelationshipCount) + require.Equal(t, 2*time.Millisecond, queries[0].Duration.AsDuration()) + require.WithinDuration(t, start, queries[0].StartTime.AsTime(), time.Microsecond) + + require.Equal(t, "shape-b", queries[1].QueryShape) + require.Equal(t, uint64(0), queries[1].RelationshipCount) +} + +func TestCollectorConcurrentRecord(t *testing.T) { + _, c := WithCollector(context.Background()) + + const goroutines = 16 + const perGoroutine = 64 + + var wg sync.WaitGroup + wg.Add(goroutines) + for i := 0; i < goroutines; i++ { + go func() { + defer wg.Done() + for j := 0; j < perGoroutine; j++ { + c.Record("shape", time.Now(), time.Microsecond, 1) + } + }() + } + wg.Wait() + + require.Len(t, c.Queries(), goroutines*perGoroutine) +} + +// Each child context gets its own collector, so a parent never sees a child's +// recorded queries. +func TestNestedCollectorsAreIndependent(t *testing.T) { + parentCtx, parent := WithCollector(context.Background()) + parent.Record("parent-query", time.Now(), time.Millisecond, 1) + + childCtx, child := WithCollector(parentCtx) + child.Record("child-query", time.Now(), time.Millisecond, 2) + + require.Len(t, parent.Queries(), 1) + require.Equal(t, "parent-query", parent.Queries()[0].QueryShape) + + require.Same(t, child, CollectorFromContext(childCtx)) + require.Len(t, child.Queries(), 1) + require.Equal(t, "child-query", child.Queries()[0].QueryShape) +} diff --git a/internal/graph/check.go b/internal/graph/check.go index 6d9a9938e1..6c860ca086 100644 --- a/internal/graph/check.go +++ b/internal/graph/check.go @@ -10,8 +10,10 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/authzed/spicedb/internal/dispatch" + "github.com/authzed/spicedb/internal/dstrace" "github.com/authzed/spicedb/internal/graph/hints" log "github.com/authzed/spicedb/internal/logging" "github.com/authzed/spicedb/internal/namespace" @@ -98,9 +100,14 @@ type currentRequestContext struct { // Check performs a check request with the provided request and context func (cc *ConcurrentChecker) Check(ctx context.Context, req ValidatedCheckRequest, relation *core.Relation) (*v1.DispatchCheckResponse, error) { var startTime *time.Time + var collector *dstrace.Collector if req.Debug != v1.DispatchCheckRequest_NO_DEBUG { now := time.Now() startTime = &now + // Install a per-node collector so the datastore queries this node issues + // itself are attributed to it. Dispatched children re-enter Check and + // install their own collector, so their reads attribute to them. + ctx, collector = dstrace.WithCollector(ctx) } resolved := cc.checkInternal(ctx, req, relation) @@ -131,6 +138,8 @@ func (cc *ConcurrentChecker) Check(ctx context.Context, req ValidatedCheckReques debugInfo.Check.Request = clonedRequest debugInfo.Check.Duration = durationpb.New(time.Since(*startTime)) + debugInfo.Check.StartTime = timestamppb.New(*startTime) + debugInfo.Check.DatastoreQueries = collector.Queries() if nspkg.GetRelationKind(relation) == iv1.RelationMetadata_PERMISSION { debugInfo.Check.ResourceRelationType = v1.CheckDebugTrace_PERMISSION diff --git a/internal/graph/computed/computecheck_test.go b/internal/graph/computed/computecheck_test.go index ed0faa8861..6db33222d8 100644 --- a/internal/graph/computed/computecheck_test.go +++ b/internal/graph/computed/computecheck_test.go @@ -11,6 +11,7 @@ import ( "github.com/authzed/spicedb/internal/datastore/dsfortesting" "github.com/authzed/spicedb/internal/datastore/memdb" + "github.com/authzed/spicedb/internal/datastore/proxy" "github.com/authzed/spicedb/internal/dispatch/graph" "github.com/authzed/spicedb/internal/graph/computed" log "github.com/authzed/spicedb/internal/logging" @@ -935,6 +936,89 @@ func TestComputeBulkCheck(t *testing.T) { require.Equal(t, v1.ResourceCheckResult_NOT_MEMBER, resp["third"].Membership) } +// TestComputeCheckTraceTimingAndDatastoreQueries verifies that, with trace +// debugging enabled, every node of the dispatch trace carries a wall-clock +// start_time and that the datastore reads issued during the check are attributed +// to nodes as DatastoreQuery events. The memdb datastore is wrapped in the +// observable proxy here, mirroring the production datastore chain. +func TestComputeCheckTraceTimingAndDatastoreQueries(t *testing.T) { + req := require.New(t) + + rawDS, err := dsfortesting.NewMemDBDatastoreForTesting(t, 0, 0, memdb.DisableGC) + req.NoError(err) + ds := proxy.NewObservableDatastoreProxy(rawDS) + + dispatch, err := graph.NewLocalOnlyDispatcher(graph.MustNewDefaultDispatcherParametersForTesting()) + req.NoError(err) + ctx := log.Logger.WithContext(datalayer.ContextWithHandle(t.Context())) + req.NoError(datalayer.SetInContext(ctx, datalayer.NewDataLayer(ds))) + + revision, err := writeCaveatedTuples(ctx, t, ds, ` + definition user {} + + definition group { + relation member: user + } + + definition document { + relation viewer: user | group#member + permission view = viewer + } + `, []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@group:eng#member", "", nil}, + {tuple.UpdateOperationCreate, "group:eng#member@user:tom", "", nil}, + }) + req.NoError(err) + + results, _, debugInfos, err := computed.ComputeBulkCheck(ctx, dispatch, + caveattypes.Default.TypeSet, + computed.CheckParameters{ + ResourceType: tuple.RR("document", "view"), + Subject: tuple.ONR("user", "tom", "..."), + AtRevision: revision, + MaximumDepth: 50, + DebugOption: computed.TraceDebuggingEnabled, + SchemaHash: datalayer.NoSchemaHashForTesting, + }, + []string{"foo"}, + 100, + ) + req.NoError(err) + req.Equal(v1.ResourceCheckResult_MEMBER, results["foo"].Membership) + req.NotEmpty(debugInfos) + + var nodeCount, queryCount int + var walk func(tr *v1.CheckDebugTrace) + walk = func(tr *v1.CheckDebugTrace) { + if tr == nil { + return + } + nodeCount++ + + // Cached nodes have no request and don't re-stamp timing; skip them. + if !tr.IsCachedResult && tr.Request != nil { + req.NotNil(tr.StartTime, "every executed check node must carry a start_time") + } + + for _, q := range tr.DatastoreQueries { + queryCount++ + req.NotEmpty(q.QueryShape) + req.NotNil(q.StartTime, "datastore query must have a start_time") + req.NotNil(q.Duration, "datastore query must have a duration") + } + + for _, sp := range tr.SubProblems { + walk(sp) + } + } + for _, di := range debugInfos { + walk(di.Check) + } + + req.Positive(nodeCount) + req.Positive(queryCount, "expected at least one datastore query attributed in the trace") +} + func writeCaveatedTuples(ctx context.Context, _ *testing.T, ds datastore.Datastore, schema string, updates []caveatedUpdate) (datastore.Revision, error) { compiled, err := compiler.Compile(compiler.InputSchema{ Source: "schema", diff --git a/pkg/proto/dispatch/v1/dispatch.pb.go b/pkg/proto/dispatch/v1/dispatch.pb.go index 7f79ecafe7..eb548a1058 100644 --- a/pkg/proto/dispatch/v1/dispatch.pb.go +++ b/pkg/proto/dispatch/v1/dispatch.pb.go @@ -1641,10 +1641,14 @@ type CheckDebugTrace struct { IsCachedResult bool `protobuf:"varint,4,opt,name=is_cached_result,json=isCachedResult,proto3" json:"is_cached_result,omitempty"` SubProblems []*CheckDebugTrace `protobuf:"bytes,5,rep,name=sub_problems,json=subProblems,proto3" json:"sub_problems,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,6,opt,name=duration,proto3" json:"duration,omitempty"` - TraceId string `protobuf:"bytes,7,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` - SourceId string `protobuf:"bytes,8,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // start_time is the wall-clock start of this Check; end = start_time + duration. + StartTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + TraceId string `protobuf:"bytes,7,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` + SourceId string `protobuf:"bytes,8,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` + // datastore_queries are the relationship queries this node issued itself. + DatastoreQueries []*DatastoreQuery `protobuf:"bytes,10,rep,name=datastore_queries,json=datastoreQueries,proto3" json:"datastore_queries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CheckDebugTrace) Reset() { @@ -1719,6 +1723,13 @@ func (x *CheckDebugTrace) GetDuration() *durationpb.Duration { return nil } +func (x *CheckDebugTrace) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + func (x *CheckDebugTrace) GetTraceId() string { if x != nil { return x.TraceId @@ -1733,6 +1744,82 @@ func (x *CheckDebugTrace) GetSourceId() string { return "" } +func (x *CheckDebugTrace) GetDatastoreQueries() []*DatastoreQuery { + if x != nil { + return x.DatastoreQueries + } + return nil +} + +// DatastoreQuery records a single relationship query issued while resolving a Check node. +type DatastoreQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + QueryShape string `protobuf:"bytes,1,opt,name=query_shape,json=queryShape,proto3" json:"query_shape,omitempty"` + StartTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + Duration *durationpb.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + RelationshipCount uint64 `protobuf:"varint,4,opt,name=relationship_count,json=relationshipCount,proto3" json:"relationship_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DatastoreQuery) Reset() { + *x = DatastoreQuery{} + mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DatastoreQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DatastoreQuery) ProtoMessage() {} + +func (x *DatastoreQuery) ProtoReflect() protoreflect.Message { + mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DatastoreQuery.ProtoReflect.Descriptor instead. +func (*DatastoreQuery) Descriptor() ([]byte, []int) { + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{21} +} + +func (x *DatastoreQuery) GetQueryShape() string { + if x != nil { + return x.QueryShape + } + return "" +} + +func (x *DatastoreQuery) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *DatastoreQuery) GetDuration() *durationpb.Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *DatastoreQuery) GetRelationshipCount() uint64 { + if x != nil { + return x.RelationshipCount + } + return 0 +} + type PlanContext struct { state protoimpl.MessageState `protogen:"open.v1"` Revision string `protobuf:"bytes,1,opt,name=revision,proto3" json:"revision,omitempty"` @@ -1761,7 +1848,7 @@ type PlanContext struct { func (x *PlanContext) Reset() { *x = PlanContext{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1773,7 +1860,7 @@ func (x *PlanContext) String() string { func (*PlanContext) ProtoMessage() {} func (x *PlanContext) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1786,7 +1873,7 @@ func (x *PlanContext) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanContext.ProtoReflect.Descriptor instead. func (*PlanContext) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{21} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{22} } func (x *PlanContext) GetRevision() string { @@ -1860,7 +1947,7 @@ type DispatchQueryPlanRequest struct { func (x *DispatchQueryPlanRequest) Reset() { *x = DispatchQueryPlanRequest{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[22] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1872,7 +1959,7 @@ func (x *DispatchQueryPlanRequest) String() string { func (*DispatchQueryPlanRequest) ProtoMessage() {} func (x *DispatchQueryPlanRequest) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[22] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1885,7 +1972,7 @@ func (x *DispatchQueryPlanRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchQueryPlanRequest.ProtoReflect.Descriptor instead. func (*DispatchQueryPlanRequest) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{22} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{23} } func (x *DispatchQueryPlanRequest) GetOperation() PlanOperation { @@ -1940,7 +2027,7 @@ type DispatchQueryPlanResponse struct { func (x *DispatchQueryPlanResponse) Reset() { *x = DispatchQueryPlanResponse{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[23] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1952,7 +2039,7 @@ func (x *DispatchQueryPlanResponse) String() string { func (*DispatchQueryPlanResponse) ProtoMessage() {} func (x *DispatchQueryPlanResponse) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[23] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1965,7 +2052,7 @@ func (x *DispatchQueryPlanResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchQueryPlanResponse.ProtoReflect.Descriptor instead. func (*DispatchQueryPlanResponse) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{23} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{24} } func (x *DispatchQueryPlanResponse) GetMetadata() *ResponseMeta { @@ -2001,7 +2088,7 @@ type ResultPath struct { func (x *ResultPath) Reset() { *x = ResultPath{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[24] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2013,7 +2100,7 @@ func (x *ResultPath) String() string { func (*ResultPath) ProtoMessage() {} func (x *ResultPath) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[24] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2026,7 +2113,7 @@ func (x *ResultPath) ProtoReflect() protoreflect.Message { // Deprecated: Use ResultPath.ProtoReflect.Descriptor instead. func (*ResultPath) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{24} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{25} } func (x *ResultPath) GetResourceType() string { @@ -2120,7 +2207,7 @@ type LookupDebugInfo struct { func (x *LookupDebugInfo) Reset() { *x = LookupDebugInfo{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[25] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2132,7 +2219,7 @@ func (x *LookupDebugInfo) String() string { func (*LookupDebugInfo) ProtoMessage() {} func (x *LookupDebugInfo) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[25] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2145,7 +2232,7 @@ func (x *LookupDebugInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use LookupDebugInfo.ProtoReflect.Descriptor instead. func (*LookupDebugInfo) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{25} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{26} } func (x *LookupDebugInfo) GetCycleMembers() []string { @@ -2296,16 +2383,20 @@ const file_dispatch_v1_dispatch_proto_rawDesc = "" + "\n" + "debug_info\x18\x06 \x01(\v2\x1d.dispatch.v1.DebugInformationR\tdebugInfoJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06\"F\n" + "\x10DebugInformation\x122\n" + - "\x05check\x18\x01 \x01(\v2\x1c.dispatch.v1.CheckDebugTraceR\x05check\"\xe7\x04\n" + + "\x05check\x18\x01 \x01(\v2\x1c.dispatch.v1.CheckDebugTraceR\x05check\"\xec\x05\n" + "\x0fCheckDebugTrace\x12;\n" + "\arequest\x18\x01 \x01(\v2!.dispatch.v1.DispatchCheckRequestR\arequest\x12_\n" + "\x16resource_relation_type\x18\x02 \x01(\x0e2).dispatch.v1.CheckDebugTrace.RelationTypeR\x14resourceRelationType\x12C\n" + "\aresults\x18\x03 \x03(\v2).dispatch.v1.CheckDebugTrace.ResultsEntryR\aresults\x12(\n" + "\x10is_cached_result\x18\x04 \x01(\bR\x0eisCachedResult\x12?\n" + "\fsub_problems\x18\x05 \x03(\v2\x1c.dispatch.v1.CheckDebugTraceR\vsubProblems\x125\n" + - "\bduration\x18\x06 \x01(\v2\x19.google.protobuf.DurationR\bduration\x12\x19\n" + + "\bduration\x18\x06 \x01(\v2\x19.google.protobuf.DurationR\bduration\x129\n" + + "\n" + + "start_time\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x12\x19\n" + "\btrace_id\x18\a \x01(\tR\atraceId\x12\x1b\n" + - "\tsource_id\x18\b \x01(\tR\bsourceId\x1a\\\n" + + "\tsource_id\x18\b \x01(\tR\bsourceId\x12H\n" + + "\x11datastore_queries\x18\n" + + " \x03(\v2\x1b.dispatch.v1.DatastoreQueryR\x10datastoreQueries\x1a\\\n" + "\fResultsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x126\n" + "\x05value\x18\x02 \x01(\v2 .dispatch.v1.ResourceCheckResultR\x05value:\x028\x01\"9\n" + @@ -2313,7 +2404,14 @@ const file_dispatch_v1_dispatch_proto_rawDesc = "" + "\aUNKNOWN\x10\x00\x12\f\n" + "\bRELATION\x10\x01\x12\x0e\n" + "\n" + - "PERMISSION\x10\x02\"\xea\x02\n" + + "PERMISSION\x10\x02\"\xd2\x01\n" + + "\x0eDatastoreQuery\x12\x1f\n" + + "\vquery_shape\x18\x01 \x01(\tR\n" + + "queryShape\x129\n" + + "\n" + + "start_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x125\n" + + "\bduration\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\bduration\x12-\n" + + "\x12relationship_count\x18\x04 \x01(\x04R\x11relationshipCount\"\xea\x02\n" + "\vPlanContext\x12\x1a\n" + "\brevision\x18\x01 \x01(\tR\brevision\x12>\n" + "\x0ecaveat_context\x18\x02 \x01(\v2\x17.google.protobuf.StructR\rcaveatContext\x12.\n" + @@ -2382,7 +2480,7 @@ func file_dispatch_v1_dispatch_proto_rawDescGZIP() []byte { } var file_dispatch_v1_dispatch_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_dispatch_v1_dispatch_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_dispatch_v1_dispatch_proto_msgTypes = make([]protoimpl.MessageInfo, 30) var file_dispatch_v1_dispatch_proto_goTypes = []any{ (PlanOperation)(0), // 0: dispatch.v1.PlanOperation (DispatchCheckRequest_DebugSetting)(0), // 1: dispatch.v1.DispatchCheckRequest.DebugSetting @@ -2411,106 +2509,111 @@ var file_dispatch_v1_dispatch_proto_goTypes = []any{ (*ResponseMeta)(nil), // 24: dispatch.v1.ResponseMeta (*DebugInformation)(nil), // 25: dispatch.v1.DebugInformation (*CheckDebugTrace)(nil), // 26: dispatch.v1.CheckDebugTrace - (*PlanContext)(nil), // 27: dispatch.v1.PlanContext - (*DispatchQueryPlanRequest)(nil), // 28: dispatch.v1.DispatchQueryPlanRequest - (*DispatchQueryPlanResponse)(nil), // 29: dispatch.v1.DispatchQueryPlanResponse - (*ResultPath)(nil), // 30: dispatch.v1.ResultPath - (*LookupDebugInfo)(nil), // 31: dispatch.v1.LookupDebugInfo - nil, // 32: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry - nil, // 33: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry - nil, // 34: dispatch.v1.CheckDebugTrace.ResultsEntry - (*v1.RelationReference)(nil), // 35: core.v1.RelationReference - (*v1.ObjectAndRelation)(nil), // 36: core.v1.ObjectAndRelation - (*v1.CaveatExpression)(nil), // 37: core.v1.CaveatExpression - (*v1.RelationTupleTreeNode)(nil), // 38: core.v1.RelationTupleTreeNode - (*structpb.Struct)(nil), // 39: google.protobuf.Struct - (*durationpb.Duration)(nil), // 40: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 41: google.protobuf.Timestamp - (*v1.RelationshipIntegrity)(nil), // 42: core.v1.RelationshipIntegrity + (*DatastoreQuery)(nil), // 27: dispatch.v1.DatastoreQuery + (*PlanContext)(nil), // 28: dispatch.v1.PlanContext + (*DispatchQueryPlanRequest)(nil), // 29: dispatch.v1.DispatchQueryPlanRequest + (*DispatchQueryPlanResponse)(nil), // 30: dispatch.v1.DispatchQueryPlanResponse + (*ResultPath)(nil), // 31: dispatch.v1.ResultPath + (*LookupDebugInfo)(nil), // 32: dispatch.v1.LookupDebugInfo + nil, // 33: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry + nil, // 34: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry + nil, // 35: dispatch.v1.CheckDebugTrace.ResultsEntry + (*v1.RelationReference)(nil), // 36: core.v1.RelationReference + (*v1.ObjectAndRelation)(nil), // 37: core.v1.ObjectAndRelation + (*v1.CaveatExpression)(nil), // 38: core.v1.CaveatExpression + (*v1.RelationTupleTreeNode)(nil), // 39: core.v1.RelationTupleTreeNode + (*structpb.Struct)(nil), // 40: google.protobuf.Struct + (*durationpb.Duration)(nil), // 41: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 42: google.protobuf.Timestamp + (*v1.RelationshipIntegrity)(nil), // 43: core.v1.RelationshipIntegrity } var file_dispatch_v1_dispatch_proto_depIdxs = []int32{ 23, // 0: dispatch.v1.DispatchCheckRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 35, // 1: dispatch.v1.DispatchCheckRequest.resource_relation:type_name -> core.v1.RelationReference - 36, // 2: dispatch.v1.DispatchCheckRequest.subject:type_name -> core.v1.ObjectAndRelation + 36, // 1: dispatch.v1.DispatchCheckRequest.resource_relation:type_name -> core.v1.RelationReference + 37, // 2: dispatch.v1.DispatchCheckRequest.subject:type_name -> core.v1.ObjectAndRelation 2, // 3: dispatch.v1.DispatchCheckRequest.results_setting:type_name -> dispatch.v1.DispatchCheckRequest.ResultsSetting 1, // 4: dispatch.v1.DispatchCheckRequest.debug:type_name -> dispatch.v1.DispatchCheckRequest.DebugSetting 7, // 5: dispatch.v1.DispatchCheckRequest.check_hints:type_name -> dispatch.v1.CheckHint - 36, // 6: dispatch.v1.CheckHint.resource:type_name -> core.v1.ObjectAndRelation - 36, // 7: dispatch.v1.CheckHint.subject:type_name -> core.v1.ObjectAndRelation + 37, // 6: dispatch.v1.CheckHint.resource:type_name -> core.v1.ObjectAndRelation + 37, // 7: dispatch.v1.CheckHint.subject:type_name -> core.v1.ObjectAndRelation 9, // 8: dispatch.v1.CheckHint.result:type_name -> dispatch.v1.ResourceCheckResult 24, // 9: dispatch.v1.DispatchCheckResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 32, // 10: dispatch.v1.DispatchCheckResponse.results_by_resource_id:type_name -> dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry + 33, // 10: dispatch.v1.DispatchCheckResponse.results_by_resource_id:type_name -> dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry 3, // 11: dispatch.v1.ResourceCheckResult.membership:type_name -> dispatch.v1.ResourceCheckResult.Membership - 37, // 12: dispatch.v1.ResourceCheckResult.expression:type_name -> core.v1.CaveatExpression + 38, // 12: dispatch.v1.ResourceCheckResult.expression:type_name -> core.v1.CaveatExpression 23, // 13: dispatch.v1.DispatchExpandRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 36, // 14: dispatch.v1.DispatchExpandRequest.resource_and_relation:type_name -> core.v1.ObjectAndRelation + 37, // 14: dispatch.v1.DispatchExpandRequest.resource_and_relation:type_name -> core.v1.ObjectAndRelation 4, // 15: dispatch.v1.DispatchExpandRequest.expansion_mode:type_name -> dispatch.v1.DispatchExpandRequest.ExpansionMode 24, // 16: dispatch.v1.DispatchExpandResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 38, // 17: dispatch.v1.DispatchExpandResponse.tree_node:type_name -> core.v1.RelationTupleTreeNode + 39, // 17: dispatch.v1.DispatchExpandResponse.tree_node:type_name -> core.v1.RelationTupleTreeNode 23, // 18: dispatch.v1.DispatchLookupResources2Request.metadata:type_name -> dispatch.v1.ResolverMeta - 35, // 19: dispatch.v1.DispatchLookupResources2Request.resource_relation:type_name -> core.v1.RelationReference - 35, // 20: dispatch.v1.DispatchLookupResources2Request.subject_relation:type_name -> core.v1.RelationReference - 36, // 21: dispatch.v1.DispatchLookupResources2Request.terminal_subject:type_name -> core.v1.ObjectAndRelation - 39, // 22: dispatch.v1.DispatchLookupResources2Request.context:type_name -> google.protobuf.Struct + 36, // 19: dispatch.v1.DispatchLookupResources2Request.resource_relation:type_name -> core.v1.RelationReference + 36, // 20: dispatch.v1.DispatchLookupResources2Request.subject_relation:type_name -> core.v1.RelationReference + 37, // 21: dispatch.v1.DispatchLookupResources2Request.terminal_subject:type_name -> core.v1.ObjectAndRelation + 40, // 22: dispatch.v1.DispatchLookupResources2Request.context:type_name -> google.protobuf.Struct 12, // 23: dispatch.v1.DispatchLookupResources2Request.optional_cursor:type_name -> dispatch.v1.Cursor 14, // 24: dispatch.v1.DispatchLookupResources2Response.resource:type_name -> dispatch.v1.PossibleResource 24, // 25: dispatch.v1.DispatchLookupResources2Response.metadata:type_name -> dispatch.v1.ResponseMeta 12, // 26: dispatch.v1.DispatchLookupResources2Response.after_response_cursor:type_name -> dispatch.v1.Cursor 23, // 27: dispatch.v1.DispatchLookupResources3Request.metadata:type_name -> dispatch.v1.ResolverMeta - 35, // 28: dispatch.v1.DispatchLookupResources3Request.resource_relation:type_name -> core.v1.RelationReference - 35, // 29: dispatch.v1.DispatchLookupResources3Request.subject_relation:type_name -> core.v1.RelationReference - 36, // 30: dispatch.v1.DispatchLookupResources3Request.terminal_subject:type_name -> core.v1.ObjectAndRelation - 39, // 31: dispatch.v1.DispatchLookupResources3Request.context:type_name -> google.protobuf.Struct + 36, // 28: dispatch.v1.DispatchLookupResources3Request.resource_relation:type_name -> core.v1.RelationReference + 36, // 29: dispatch.v1.DispatchLookupResources3Request.subject_relation:type_name -> core.v1.RelationReference + 37, // 30: dispatch.v1.DispatchLookupResources3Request.terminal_subject:type_name -> core.v1.ObjectAndRelation + 40, // 31: dispatch.v1.DispatchLookupResources3Request.context:type_name -> google.protobuf.Struct 18, // 32: dispatch.v1.DispatchLookupResources3Response.items:type_name -> dispatch.v1.LR3Item 23, // 33: dispatch.v1.DispatchLookupSubjectsRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 35, // 34: dispatch.v1.DispatchLookupSubjectsRequest.resource_relation:type_name -> core.v1.RelationReference - 35, // 35: dispatch.v1.DispatchLookupSubjectsRequest.subject_relation:type_name -> core.v1.RelationReference - 37, // 36: dispatch.v1.FoundSubject.caveat_expression:type_name -> core.v1.CaveatExpression + 36, // 34: dispatch.v1.DispatchLookupSubjectsRequest.resource_relation:type_name -> core.v1.RelationReference + 36, // 35: dispatch.v1.DispatchLookupSubjectsRequest.subject_relation:type_name -> core.v1.RelationReference + 38, // 36: dispatch.v1.FoundSubject.caveat_expression:type_name -> core.v1.CaveatExpression 20, // 37: dispatch.v1.FoundSubject.excluded_subjects:type_name -> dispatch.v1.FoundSubject 20, // 38: dispatch.v1.FoundSubjects.found_subjects:type_name -> dispatch.v1.FoundSubject - 33, // 39: dispatch.v1.DispatchLookupSubjectsResponse.found_subjects_by_resource_id:type_name -> dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry + 34, // 39: dispatch.v1.DispatchLookupSubjectsResponse.found_subjects_by_resource_id:type_name -> dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry 24, // 40: dispatch.v1.DispatchLookupSubjectsResponse.metadata:type_name -> dispatch.v1.ResponseMeta 25, // 41: dispatch.v1.ResponseMeta.debug_info:type_name -> dispatch.v1.DebugInformation 26, // 42: dispatch.v1.DebugInformation.check:type_name -> dispatch.v1.CheckDebugTrace 6, // 43: dispatch.v1.CheckDebugTrace.request:type_name -> dispatch.v1.DispatchCheckRequest 5, // 44: dispatch.v1.CheckDebugTrace.resource_relation_type:type_name -> dispatch.v1.CheckDebugTrace.RelationType - 34, // 45: dispatch.v1.CheckDebugTrace.results:type_name -> dispatch.v1.CheckDebugTrace.ResultsEntry + 35, // 45: dispatch.v1.CheckDebugTrace.results:type_name -> dispatch.v1.CheckDebugTrace.ResultsEntry 26, // 46: dispatch.v1.CheckDebugTrace.sub_problems:type_name -> dispatch.v1.CheckDebugTrace - 40, // 47: dispatch.v1.CheckDebugTrace.duration:type_name -> google.protobuf.Duration - 39, // 48: dispatch.v1.PlanContext.caveat_context:type_name -> google.protobuf.Struct - 0, // 49: dispatch.v1.PlanContext.top_level_operation:type_name -> dispatch.v1.PlanOperation - 0, // 50: dispatch.v1.DispatchQueryPlanRequest.operation:type_name -> dispatch.v1.PlanOperation - 36, // 51: dispatch.v1.DispatchQueryPlanRequest.resource:type_name -> core.v1.ObjectAndRelation - 36, // 52: dispatch.v1.DispatchQueryPlanRequest.subject:type_name -> core.v1.ObjectAndRelation - 27, // 53: dispatch.v1.DispatchQueryPlanRequest.plan_context:type_name -> dispatch.v1.PlanContext - 36, // 54: dispatch.v1.DispatchQueryPlanRequest.many:type_name -> core.v1.ObjectAndRelation - 24, // 55: dispatch.v1.DispatchQueryPlanResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 30, // 56: dispatch.v1.DispatchQueryPlanResponse.paths:type_name -> dispatch.v1.ResultPath - 37, // 57: dispatch.v1.ResultPath.caveat:type_name -> core.v1.CaveatExpression - 41, // 58: dispatch.v1.ResultPath.expiration:type_name -> google.protobuf.Timestamp - 42, // 59: dispatch.v1.ResultPath.integrity:type_name -> core.v1.RelationshipIntegrity - 39, // 60: dispatch.v1.ResultPath.metadata:type_name -> google.protobuf.Struct - 30, // 61: dispatch.v1.ResultPath.excluded_subjects:type_name -> dispatch.v1.ResultPath - 9, // 62: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry.value:type_name -> dispatch.v1.ResourceCheckResult - 21, // 63: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry.value:type_name -> dispatch.v1.FoundSubjects - 9, // 64: dispatch.v1.CheckDebugTrace.ResultsEntry.value:type_name -> dispatch.v1.ResourceCheckResult - 6, // 65: dispatch.v1.DispatchService.DispatchCheck:input_type -> dispatch.v1.DispatchCheckRequest - 10, // 66: dispatch.v1.DispatchService.DispatchExpand:input_type -> dispatch.v1.DispatchExpandRequest - 19, // 67: dispatch.v1.DispatchService.DispatchLookupSubjects:input_type -> dispatch.v1.DispatchLookupSubjectsRequest - 13, // 68: dispatch.v1.DispatchService.DispatchLookupResources2:input_type -> dispatch.v1.DispatchLookupResources2Request - 16, // 69: dispatch.v1.DispatchService.DispatchLookupResources3:input_type -> dispatch.v1.DispatchLookupResources3Request - 28, // 70: dispatch.v1.DispatchService.DispatchQueryPlan:input_type -> dispatch.v1.DispatchQueryPlanRequest - 8, // 71: dispatch.v1.DispatchService.DispatchCheck:output_type -> dispatch.v1.DispatchCheckResponse - 11, // 72: dispatch.v1.DispatchService.DispatchExpand:output_type -> dispatch.v1.DispatchExpandResponse - 22, // 73: dispatch.v1.DispatchService.DispatchLookupSubjects:output_type -> dispatch.v1.DispatchLookupSubjectsResponse - 15, // 74: dispatch.v1.DispatchService.DispatchLookupResources2:output_type -> dispatch.v1.DispatchLookupResources2Response - 17, // 75: dispatch.v1.DispatchService.DispatchLookupResources3:output_type -> dispatch.v1.DispatchLookupResources3Response - 29, // 76: dispatch.v1.DispatchService.DispatchQueryPlan:output_type -> dispatch.v1.DispatchQueryPlanResponse - 71, // [71:77] is the sub-list for method output_type - 65, // [65:71] is the sub-list for method input_type - 65, // [65:65] is the sub-list for extension type_name - 65, // [65:65] is the sub-list for extension extendee - 0, // [0:65] is the sub-list for field type_name + 41, // 47: dispatch.v1.CheckDebugTrace.duration:type_name -> google.protobuf.Duration + 42, // 48: dispatch.v1.CheckDebugTrace.start_time:type_name -> google.protobuf.Timestamp + 27, // 49: dispatch.v1.CheckDebugTrace.datastore_queries:type_name -> dispatch.v1.DatastoreQuery + 42, // 50: dispatch.v1.DatastoreQuery.start_time:type_name -> google.protobuf.Timestamp + 41, // 51: dispatch.v1.DatastoreQuery.duration:type_name -> google.protobuf.Duration + 40, // 52: dispatch.v1.PlanContext.caveat_context:type_name -> google.protobuf.Struct + 0, // 53: dispatch.v1.PlanContext.top_level_operation:type_name -> dispatch.v1.PlanOperation + 0, // 54: dispatch.v1.DispatchQueryPlanRequest.operation:type_name -> dispatch.v1.PlanOperation + 37, // 55: dispatch.v1.DispatchQueryPlanRequest.resource:type_name -> core.v1.ObjectAndRelation + 37, // 56: dispatch.v1.DispatchQueryPlanRequest.subject:type_name -> core.v1.ObjectAndRelation + 28, // 57: dispatch.v1.DispatchQueryPlanRequest.plan_context:type_name -> dispatch.v1.PlanContext + 37, // 58: dispatch.v1.DispatchQueryPlanRequest.many:type_name -> core.v1.ObjectAndRelation + 24, // 59: dispatch.v1.DispatchQueryPlanResponse.metadata:type_name -> dispatch.v1.ResponseMeta + 31, // 60: dispatch.v1.DispatchQueryPlanResponse.paths:type_name -> dispatch.v1.ResultPath + 38, // 61: dispatch.v1.ResultPath.caveat:type_name -> core.v1.CaveatExpression + 42, // 62: dispatch.v1.ResultPath.expiration:type_name -> google.protobuf.Timestamp + 43, // 63: dispatch.v1.ResultPath.integrity:type_name -> core.v1.RelationshipIntegrity + 40, // 64: dispatch.v1.ResultPath.metadata:type_name -> google.protobuf.Struct + 31, // 65: dispatch.v1.ResultPath.excluded_subjects:type_name -> dispatch.v1.ResultPath + 9, // 66: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry.value:type_name -> dispatch.v1.ResourceCheckResult + 21, // 67: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry.value:type_name -> dispatch.v1.FoundSubjects + 9, // 68: dispatch.v1.CheckDebugTrace.ResultsEntry.value:type_name -> dispatch.v1.ResourceCheckResult + 6, // 69: dispatch.v1.DispatchService.DispatchCheck:input_type -> dispatch.v1.DispatchCheckRequest + 10, // 70: dispatch.v1.DispatchService.DispatchExpand:input_type -> dispatch.v1.DispatchExpandRequest + 19, // 71: dispatch.v1.DispatchService.DispatchLookupSubjects:input_type -> dispatch.v1.DispatchLookupSubjectsRequest + 13, // 72: dispatch.v1.DispatchService.DispatchLookupResources2:input_type -> dispatch.v1.DispatchLookupResources2Request + 16, // 73: dispatch.v1.DispatchService.DispatchLookupResources3:input_type -> dispatch.v1.DispatchLookupResources3Request + 29, // 74: dispatch.v1.DispatchService.DispatchQueryPlan:input_type -> dispatch.v1.DispatchQueryPlanRequest + 8, // 75: dispatch.v1.DispatchService.DispatchCheck:output_type -> dispatch.v1.DispatchCheckResponse + 11, // 76: dispatch.v1.DispatchService.DispatchExpand:output_type -> dispatch.v1.DispatchExpandResponse + 22, // 77: dispatch.v1.DispatchService.DispatchLookupSubjects:output_type -> dispatch.v1.DispatchLookupSubjectsResponse + 15, // 78: dispatch.v1.DispatchService.DispatchLookupResources2:output_type -> dispatch.v1.DispatchLookupResources2Response + 17, // 79: dispatch.v1.DispatchService.DispatchLookupResources3:output_type -> dispatch.v1.DispatchLookupResources3Response + 30, // 80: dispatch.v1.DispatchService.DispatchQueryPlan:output_type -> dispatch.v1.DispatchQueryPlanResponse + 75, // [75:81] is the sub-list for method output_type + 69, // [69:75] is the sub-list for method input_type + 69, // [69:69] is the sub-list for extension type_name + 69, // [69:69] is the sub-list for extension extendee + 0, // [0:69] is the sub-list for field type_name } func init() { file_dispatch_v1_dispatch_proto_init() } @@ -2524,7 +2627,7 @@ func file_dispatch_v1_dispatch_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_dispatch_v1_dispatch_proto_rawDesc), len(file_dispatch_v1_dispatch_proto_rawDesc)), NumEnums: 6, - NumMessages: 29, + NumMessages: 30, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go b/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go index dbf0524433..05f832dd48 100644 --- a/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go +++ b/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go @@ -617,6 +617,7 @@ func (m *CheckDebugTrace) CloneVT() *CheckDebugTrace { r.ResourceRelationType = m.ResourceRelationType r.IsCachedResult = m.IsCachedResult r.Duration = (*durationpb.Duration)((*durationpb1.Duration)(m.Duration).CloneVT()) + r.StartTime = (*timestamppb.Timestamp)((*timestamppb1.Timestamp)(m.StartTime).CloneVT()) r.TraceId = m.TraceId r.SourceId = m.SourceId if rhs := m.Results; rhs != nil { @@ -633,6 +634,13 @@ func (m *CheckDebugTrace) CloneVT() *CheckDebugTrace { } r.SubProblems = tmpContainer } + if rhs := m.DatastoreQueries; rhs != nil { + tmpContainer := make([]*DatastoreQuery, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.DatastoreQueries = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -644,6 +652,26 @@ func (m *CheckDebugTrace) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *DatastoreQuery) CloneVT() *DatastoreQuery { + if m == nil { + return (*DatastoreQuery)(nil) + } + r := new(DatastoreQuery) + r.QueryShape = m.QueryShape + r.StartTime = (*timestamppb.Timestamp)((*timestamppb1.Timestamp)(m.StartTime).CloneVT()) + r.Duration = (*durationpb.Duration)((*durationpb1.Duration)(m.Duration).CloneVT()) + r.RelationshipCount = m.RelationshipCount + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DatastoreQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *PlanContext) CloneVT() *PlanContext { if m == nil { return (*PlanContext)(nil) @@ -1679,6 +1707,26 @@ func (this *CheckDebugTrace) EqualVT(that *CheckDebugTrace) bool { if this.SourceId != that.SourceId { return false } + if !(*timestamppb1.Timestamp)(this.StartTime).EqualVT((*timestamppb1.Timestamp)(that.StartTime)) { + return false + } + if len(this.DatastoreQueries) != len(that.DatastoreQueries) { + return false + } + for i, vx := range this.DatastoreQueries { + vy := that.DatastoreQueries[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &DatastoreQuery{} + } + if q == nil { + q = &DatastoreQuery{} + } + if !p.EqualVT(q) { + return false + } + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1689,6 +1737,34 @@ func (this *CheckDebugTrace) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *DatastoreQuery) EqualVT(that *DatastoreQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.QueryShape != that.QueryShape { + return false + } + if !(*timestamppb1.Timestamp)(this.StartTime).EqualVT((*timestamppb1.Timestamp)(that.StartTime)) { + return false + } + if !(*durationpb1.Duration)(this.Duration).EqualVT((*durationpb1.Duration)(that.Duration)) { + return false + } + if this.RelationshipCount != that.RelationshipCount { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DatastoreQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DatastoreQuery) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *PlanContext) EqualVT(that *PlanContext) bool { if this == that { return true @@ -3500,6 +3576,28 @@ func (m *CheckDebugTrace) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.DatastoreQueries) > 0 { + for iNdEx := len(m.DatastoreQueries) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.DatastoreQueries[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x52 + } + } + if m.StartTime != nil { + size, err := (*timestamppb1.Timestamp)(m.StartTime).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x4a + } if len(m.SourceId) > 0 { i -= len(m.SourceId) copy(dAtA[i:], m.SourceId) @@ -3586,6 +3684,71 @@ func (m *CheckDebugTrace) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *DatastoreQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DatastoreQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DatastoreQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.RelationshipCount != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.RelationshipCount)) + i-- + dAtA[i] = 0x20 + } + if m.Duration != nil { + size, err := (*durationpb1.Duration)(m.Duration).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.StartTime != nil { + size, err := (*timestamppb1.Timestamp)(m.StartTime).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if len(m.QueryShape) > 0 { + i -= len(m.QueryShape) + copy(dAtA[i:], m.QueryShape) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.QueryShape))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *PlanContext) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -4717,6 +4880,41 @@ func (m *CheckDebugTrace) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.StartTime != nil { + l = (*timestamppb1.Timestamp)(m.StartTime).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.DatastoreQueries) > 0 { + for _, e := range m.DatastoreQueries { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *DatastoreQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.QueryShape) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.StartTime != nil { + l = (*timestamppb1.Timestamp)(m.StartTime).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Duration != nil { + l = (*durationpb1.Duration)(m.Duration).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.RelationshipCount != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.RelationshipCount)) + } n += len(m.unknownFields) return n } @@ -8913,6 +9111,250 @@ func (m *CheckDebugTrace) UnmarshalVT(dAtA []byte) error { } m.SourceId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StartTime == nil { + m.StartTime = ×tamppb.Timestamp{} + } + if err := (*timestamppb1.Timestamp)(m.StartTime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DatastoreQueries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DatastoreQueries = append(m.DatastoreQueries, &DatastoreQuery{}) + if err := m.DatastoreQueries[len(m.DatastoreQueries)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DatastoreQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DatastoreQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DatastoreQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryShape", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.QueryShape = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StartTime == nil { + m.StartTime = ×tamppb.Timestamp{} + } + if err := (*timestamppb1.Timestamp)(m.StartTime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Duration == nil { + m.Duration = &durationpb.Duration{} + } + if err := (*durationpb1.Duration)(m.Duration).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RelationshipCount", wireType) + } + m.RelationshipCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RelationshipCount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/proto/internal/dispatch/v1/dispatch.proto b/proto/internal/dispatch/v1/dispatch.proto index 1d80a5e127..19337dcbbf 100644 --- a/proto/internal/dispatch/v1/dispatch.proto +++ b/proto/internal/dispatch/v1/dispatch.proto @@ -219,8 +219,20 @@ message CheckDebugTrace { bool is_cached_result = 4; repeated CheckDebugTrace sub_problems = 5; google.protobuf.Duration duration = 6; + // start_time is the wall-clock start of this Check; end = start_time + duration. + google.protobuf.Timestamp start_time = 9; string trace_id = 7; string source_id = 8; + // datastore_queries are the relationship queries this node issued itself. + repeated DatastoreQuery datastore_queries = 10; +} + +// DatastoreQuery records a single relationship query issued while resolving a Check node. +message DatastoreQuery { + string query_shape = 1; + google.protobuf.Timestamp start_time = 2; + google.protobuf.Duration duration = 3; + uint64 relationship_count = 4; } enum PlanOperation {