func (n *Node) batchInternal( ctx context.Context, args *roachpb.BatchRequest, ) (*roachpb.BatchResponse, error) { // TODO(marc): grpc's authentication model (which gives credential access in // the request handler) doesn't really fit with the current design of the // security package (which assumes that TLS state is only given at connection // time) - that should be fixed. if peer, ok := peer.FromContext(ctx); ok { if tlsInfo, ok := peer.AuthInfo.(credentials.TLSInfo); ok { certUser, err := security.GetCertificateUser(&tlsInfo.State) if err != nil { return nil, err } if certUser != security.NodeUser { return nil, errors.Errorf("user %s is not allowed", certUser) } } } var br *roachpb.BatchResponse type snowballInfo struct { syncutil.Mutex collectedSpans [][]byte done bool } var snowball *snowballInfo if err := n.stopper.RunTaskWithErr(func() error { const opName = "node.Batch" sp, err := tracing.JoinOrNew(n.storeCfg.AmbientCtx.Tracer, args.TraceContext, opName) if err != nil { return err } // If this is a snowball span, it gets special treatment: It skips the // regular tracing machinery, and we instead send the collected spans // back with the response. This is more expensive, but then again, // those are individual requests traced by users, so they can be. if sp.BaggageItem(tracing.Snowball) != "" { sp.LogEvent("delegating to snowball tracing") sp.Finish() snowball = new(snowballInfo) recorder := func(rawSpan basictracer.RawSpan) { snowball.Lock() defer snowball.Unlock() if snowball.done { // This is a late span that we must discard because the request was // already completed. return } encSp, err := tracing.EncodeRawSpan(&rawSpan, nil) if err != nil { log.Warning(ctx, err) } snowball.collectedSpans = append(snowball.collectedSpans, encSp) } if sp, err = tracing.JoinOrNewSnowball(opName, args.TraceContext, recorder); err != nil { return err } } defer sp.Finish() traceCtx := opentracing.ContextWithSpan(ctx, sp) log.Event(traceCtx, args.Summary()) tStart := timeutil.Now() var pErr *roachpb.Error br, pErr = n.stores.Send(traceCtx, *args) if pErr != nil { br = &roachpb.BatchResponse{} log.ErrEventf(traceCtx, "%T", pErr.GetDetail()) } if br.Error != nil { panic(roachpb.ErrorUnexpectedlySet(n.stores, br)) } n.metrics.callComplete(timeutil.Since(tStart), pErr) br.Error = pErr return nil }); err != nil { return nil, err } if snowball != nil { snowball.Lock() br.CollectedSpans = snowball.collectedSpans snowball.done = true snowball.Unlock() } return br, nil }
// resetForNewSQLTxn (re)initializes the txnState for a new transaction. // It creates a new client.Txn and initializes it using the session defaults. // txnState.State will be set to Open. func (ts *txnState) resetForNewSQLTxn(e *Executor, s *Session) { if ts.sp != nil { panic(fmt.Sprintf("txnState.reset() called on ts with active span. How come "+ "finishSQLTxn() wasn't called previously? ts: %+v", ts)) } // Reset state vars to defaults. ts.retrying = false ts.retryIntent = false ts.autoRetry = false ts.commitSeen = false // Discard previously collected spans. We start collecting anew on // every fresh SQL txn. ts.CollectedSpans = nil // Create a context for this transaction. It will include a // root span that will contain everything executed as part of the // upcoming SQL txn, including (automatic or user-directed) retries. // The span is closed by finishSQLTxn(). // TODO(andrei): figure out how to close these spans on server shutdown? ctx := s.context var sp opentracing.Span if traceSQL { var err error sp, err = tracing.JoinOrNewSnowball("coordinator", nil, func(sp basictracer.RawSpan) { ts.CollectedSpans = append(ts.CollectedSpans, sp) }) if err != nil { log.Warningf(ctx, "unable to create snowball tracer: %s", err) return } } else if traceSQLFor7881 { var err error sp, _, err = tracing.NewTracerAndSpanFor7881(func(sp basictracer.RawSpan) { ts.CollectedSpans = append(ts.CollectedSpans, sp) }) if err != nil { log.Fatalf(ctx, "couldn't create a tracer for debugging #7881: %s", err) } } else { if parentSp := opentracing.SpanFromContext(ctx); parentSp != nil { // Create a child span for this SQL txn. tracer := parentSp.Tracer() sp = tracer.StartSpan("sql txn", opentracing.ChildOf(parentSp.Context())) } else { // Create a root span for this SQL txn. tracer := e.cfg.AmbientCtx.Tracer sp = tracer.StartSpan("sql txn") } } // Put the new span in the context. ts.sp = sp ctx = opentracing.ContextWithSpan(ctx, sp) ts.Ctx = ctx ts.mon.Start(ctx, &s.mon, mon.BoundAccount{}) ts.txn = client.NewTxn(ts.Ctx, *e.cfg.DB) ts.txn.Proto.Isolation = s.DefaultIsolationLevel ts.State = Open // Discard the old schemaChangers, if any. ts.schemaChangers = schemaChangerCollection{} }