From 640035eddc666129bf2441f04c90797ebf79d034 Mon Sep 17 00:00:00 2001
From: angelapwen
crdb_internal.num_inverted_index_entries(val: jsonb, version: int) → int
This function is used only by CockroachDB’s developers for testing purposes.
crdb_internal.payloads_for_span(span ID: int) → jsonb
Returns the payload(s) of the span whose ID is passed in the argument.
+crdb_internal.pretty_key(raw_key: bytes, skip_fields: int) → string
This function is used only by CockroachDB’s developers for testing purposes.
crdb_internal.range_stats(key: bytes) → jsonb
This function is used to retrieve range statistics information as a JSON object.
diff --git a/pkg/sql/logictest/testdata/logic_test/contention_event b/pkg/sql/logictest/testdata/logic_test/contention_event index ede473134a10..95ff95fd2b55 100644 --- a/pkg/sql/logictest/testdata/logic_test/contention_event +++ b/pkg/sql/logictest/testdata/logic_test/contention_event @@ -52,7 +52,23 @@ user root # # NB: this needs the 5node-pretend59315 config because otherwise the span is not # tracked. +# +# TODO(angelapwen): Remove this test along with num_payloads column query B SELECT count(num_payloads) > 0 FROM crdb_internal.node_inflight_trace_spans WHERE trace_id = crdb_internal.trace_id(); ---- true + +# For all spans, make sure there is 1 payload that is a contention event. +query B +WITH Spans AS ( +SELECT span_id FROM crdb_internal.node_inflight_trace_spans +WHERE trace_id = crdb_internal.trace_id() +), PayloadTypes AS ( +SELECT jsonb_array_elements(crdb_internal.payloads_for_span(span_id))->>'@type' AS type, crdb_internal.payloads_for_span(span_id) +FROM Spans +) SELECT COUNT(*) = 1 +FROM PayloadTypes +WHERE type = 'type.googleapis.com/cockroach.roachpb.ContentionEvent'; +---- +true diff --git a/pkg/sql/sem/builtins/BUILD.bazel b/pkg/sql/sem/builtins/BUILD.bazel index b699dd2b53ba..bf7c5a630f20 100644 --- a/pkg/sql/sem/builtins/BUILD.bazel +++ b/pkg/sql/sem/builtins/BUILD.bazel @@ -84,6 +84,7 @@ go_library( "//pkg/util/uuid", "@com_github_cockroachdb_apd_v2//:apd", "@com_github_cockroachdb_errors//:errors", + "@com_github_gogo_protobuf//types", "@com_github_golang_geo//s1", "@com_github_knz_strtime//:strtime", "@com_github_lib_pq//oid", diff --git a/pkg/sql/sem/builtins/builtins.go b/pkg/sql/sem/builtins/builtins.go index 09a3a34ea2cb..6abe29df5ed8 100644 --- a/pkg/sql/sem/builtins/builtins.go +++ b/pkg/sql/sem/builtins/builtins.go @@ -73,6 +73,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/util/unaccent" "github.com/cockroachdb/cockroach/pkg/util/uuid" "github.com/cockroachdb/errors" + pbtypes "github.com/gogo/protobuf/types" "github.com/knz/strtime" ) @@ -3598,6 +3599,41 @@ may increase either contention or retry errors, or both.`, }, ), + "crdb_internal.payloads_for_span": makeBuiltin( + tree.FunctionProperties{Category: categorySystemInfo}, + tree.Overload{ + Types: tree.ArgTypes{{"span ID", types.Int}}, + ReturnType: tree.FixedReturnType(types.Jsonb), + Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) { + builder := json.NewArrayBuilder(len(args)) + + spanID := uint64(*(args[0].(*tree.DInt))) + span, found := ctx.Settings.Tracer.GetActiveSpanFromID(spanID) + // A span may not be found if its ID was surfaced previously but its + // corresponding trace has ended by the time this builtin was run. + if !found { + // Returns an empty JSON array. + return tree.NewDJSON(builder.Build()), nil + } + + for _, rec := range span.GetRecording() { + rec.Structured(func(item *pbtypes.Any) { + payload, err := protoreflect.MessageToJSON(item, true /* emitDefaults */) + if err != nil { + return + } + if payload != nil { + builder.Add(payload) + } + }) + } + return tree.NewDJSON(builder.Build()), nil + }, + Info: "Returns the payload(s) of the span whose ID is passed in the argument.", + Volatility: tree.VolatilityVolatile, + }, + ), + "crdb_internal.locality_value": makeBuiltin( tree.FunctionProperties{Category: categorySystemInfo}, tree.Overload{ diff --git a/pkg/util/tracing/tracer.go b/pkg/util/tracing/tracer.go index b34ed6b35e64..8aef5f31a8be 100644 --- a/pkg/util/tracing/tracer.go +++ b/pkg/util/tracing/tracer.go @@ -155,7 +155,8 @@ type Tracer struct { // In normal operation, a local root Span is inserted on creation and // removed on .Finish(). // - // The map can be introspected by `Tracer.VisitSpans`. + // The map can be introspected by `Tracer.VisitSpans`. A Span can also be + // retrieved from its ID by `Tracer.GetActiveSpanFromID`. activeSpans struct { // NB: it might be tempting to use a sync.Map here, but // this incurs an allocation per Span (sync.Map does @@ -680,6 +681,14 @@ func (t *Tracer) ExtractMetaFrom(carrier Carrier) (*SpanMeta, error) { }, nil } +// GetActiveSpanFromID retrieves any active span given its span ID. +func (t *Tracer) GetActiveSpanFromID(spanID uint64) (*Span, bool) { + t.activeSpans.Lock() + span, found := t.activeSpans.m[spanID] + t.activeSpans.Unlock() + return span, found +} + // VisitSpans invokes the visitor with all active Spans. The function will // gracefully exit if the visitor returns iterutil.StopIteration(). func (t *Tracer) VisitSpans(visitor func(*Span) error) error {