-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
85031: sqlproxyccl: track which side broke the connection r=JeffSwenson a=JeffSwenson Previously, the sqlproxy considered an error when copying from the client->server as a client error and an error when copying from the server->client as a server error. This logic is incorrect as either side could be the source of the broken connection. Now, a wrapper is applied to the connection, and the errors returned by the wrapper are used to properly account for which side broke the connection. Release note: None 85131: sql: add columns to node_execution_insights r=matthewtodd a=j82w This commit adds the following new columns to crdb_internal.node_execution_insights table. ``` txn_id UUID NOT NULL, txn_fingerprint_id BYTES NOT NULL, query STRING NOT NULL, status STRING NOT NULL, start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, full_scan BOOL NOT NULL, user_name STRING NOT NULL, application_name STRING NOT NULL, database_name STRING NOT NULL, plan_gist STRING NOT NULL, rows_read INT8 NOT NULL, rows_written INT8 NOT NULL, priority FLOAT NOT NULL, retries INT8 NOT NULL ``` Part of #81024 Release note (sql change): Adding txn_id, txn_fingerprint_id, query, status, start_time, end_time, full_scan, user_name, application_name, database_name, plan_gist, rows_read, rows_written, priority, and retries columns to crdb_internal.node_execution_insights Co-authored-by: Jeff <[email protected]> Co-authored-by: j82w <[email protected]>
- Loading branch information
Showing
21 changed files
with
489 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Licensed as a CockroachDB Enterprise file under the Cockroach Community | ||
// License (the "License"); you may not use this file except in compliance with | ||
// the License. You may obtain a copy of the License at | ||
// | ||
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt | ||
|
||
package sqlproxyccl | ||
|
||
import ( | ||
"net" | ||
|
||
"github.com/cockroachdb/errors" | ||
) | ||
|
||
// errorSourceConn is used to annotate errors returned by the connection. The | ||
// errors make it possible to determine which side of an io.Copy broke. | ||
type errorSourceConn struct { | ||
net.Conn | ||
readErrMarker error | ||
writeErrMarker error | ||
} | ||
|
||
// errClientWrite indicates the error occured when attempting to write to the | ||
// client connection. | ||
var errClientWrite = errors.New("client write error") | ||
|
||
// errClientRead indicates the error occured when attempting to read from the | ||
// client connection. | ||
var errClientRead = errors.New("client read error") | ||
|
||
// errServerWrite indicates the error occured when attempting to write to the | ||
// sql server. | ||
var errServerWrite = errors.New("server write error") | ||
|
||
// errServerRead indicates the error occured when attempting to read from the | ||
// sql server. | ||
var errServerRead = errors.New("server read error") | ||
|
||
// wrapConnectionError wraps the error with newErrorf and the appropriate code | ||
// if it is a known connection error. nil is returned if the error is not | ||
// recognized. | ||
func wrapConnectionError(err error) error { | ||
switch { | ||
case errors.Is(err, errClientRead): | ||
return newErrorf(codeClientReadFailed, "unable to read from client: %s", err) | ||
case errors.Is(err, errClientWrite): | ||
return newErrorf(codeClientWriteFailed, "unable to write to client: %s", err) | ||
case errors.Is(err, errServerRead): | ||
return newErrorf(codeBackendReadFailed, "unable to read from sql server: %s", err) | ||
case errors.Is(err, errServerWrite): | ||
return newErrorf(codeBackendWriteFailed, "unable to write to sql server: %s", err) | ||
} | ||
return nil | ||
} | ||
|
||
// Read wraps net.Conn.Read and annotates the returned error. | ||
func (conn *errorSourceConn) Read(b []byte) (n int, err error) { | ||
n, err = conn.Conn.Read(b) | ||
if err != nil { | ||
err = errors.Mark(err, conn.readErrMarker) | ||
} | ||
return n, err | ||
} | ||
|
||
// Write wraps net.Conn.Read and annotates the returned error. | ||
func (conn *errorSourceConn) Write(b []byte) (n int, err error) { | ||
n, err = conn.Conn.Write(b) | ||
if err != nil { | ||
err = errors.Mark(err, conn.writeErrMarker) | ||
} | ||
return n, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Licensed as a CockroachDB Enterprise file under the Cockroach Community | ||
// License (the "License"); you may not use this file except in compliance with | ||
// the License. You may obtain a copy of the License at | ||
// | ||
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt | ||
|
||
package sqlproxyccl | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/util/leaktest" | ||
"github.com/cockroachdb/errors" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type fakeConn struct { | ||
net.Conn | ||
size int | ||
readError error | ||
writeError error | ||
} | ||
|
||
func (conn *fakeConn) Read(b []byte) (n int, err error) { | ||
return conn.size, conn.readError | ||
} | ||
|
||
func (conn *fakeConn) Write(b []byte) (n int, err error) { | ||
return conn.size, conn.writeError | ||
} | ||
|
||
func TestWrapConnectionError(t *testing.T) { | ||
defer leaktest.AfterTest(t)() | ||
type testCase struct { | ||
marker error | ||
code errorCode | ||
} | ||
tests := []testCase{ | ||
{errClientRead, codeClientReadFailed}, | ||
{errClientWrite, codeClientWriteFailed}, | ||
{errServerRead, codeBackendReadFailed}, | ||
{errServerWrite, codeBackendWriteFailed}, | ||
{errors.New("some random error"), 0}, | ||
} | ||
for _, tc := range tests { | ||
var code errorCode | ||
err := wrapConnectionError(errors.Mark(errors.New("some inner error"), tc.marker)) | ||
if err != nil { | ||
codeErr := &codeError{} | ||
require.True(t, errors.As(err, &codeErr)) | ||
code = codeErr.code | ||
} | ||
require.Equal(t, code, tc.code) | ||
} | ||
} | ||
|
||
func TestErrorSourceConn(t *testing.T) { | ||
defer leaktest.AfterTest(t)() | ||
newConn := func(size int, readError error, writeError error) net.Conn { | ||
return &errorSourceConn{ | ||
Conn: &fakeConn{ | ||
size: size, | ||
readError: readError, | ||
writeError: writeError, | ||
}, | ||
readErrMarker: errClientRead, | ||
writeErrMarker: errClientWrite, | ||
} | ||
} | ||
|
||
t.Run("WrapReadError", func(t *testing.T) { | ||
internalErr := errors.New("some connection error") | ||
conn := newConn(4, internalErr, nil) | ||
|
||
size, err := conn.Read([]byte{}) | ||
require.Equal(t, size, 4) | ||
require.True(t, errors.Is(err, internalErr)) | ||
require.True(t, errors.Is(err, errClientRead)) | ||
}) | ||
|
||
t.Run("WrapWriteError", func(t *testing.T) { | ||
internalErr := errors.New("some connection error") | ||
conn := newConn(4, nil, internalErr) | ||
|
||
size, err := conn.Write([]byte{}) | ||
require.Equal(t, size, 4) | ||
require.True(t, errors.Is(err, internalErr)) | ||
require.True(t, errors.Is(err, errClientWrite)) | ||
}) | ||
|
||
t.Run("OkayRead", func(t *testing.T) { | ||
conn := newConn(4, nil, nil) | ||
|
||
size, err := conn.Read([]byte{}) | ||
require.Equal(t, size, 4) | ||
require.NoError(t, err) | ||
}) | ||
|
||
t.Run("OkayWrite", func(t *testing.T) { | ||
conn := newConn(4, nil, nil) | ||
|
||
size, err := conn.Read([]byte{}) | ||
require.Equal(t, size, 4) | ||
require.NoError(t, err) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Licensed as a CockroachDB Enterprise file under the Cockroach Community | ||
// License (the "License"); you may not use this file except in compliance with | ||
// the License. You may obtain a copy of the License at | ||
// | ||
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt | ||
|
||
package sqlproxyccl | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/util/leaktest" | ||
"github.com/cockroachdb/cockroach/pkg/util/metric" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestMetricsUpdateForError(t *testing.T) { | ||
defer leaktest.AfterTest(t)() | ||
m := makeProxyMetrics() | ||
type testCase struct { | ||
code errorCode | ||
counters []*metric.Counter | ||
} | ||
tests := []testCase{ | ||
{codeClientReadFailed, []*metric.Counter{m.ClientDisconnectCount}}, | ||
{codeClientWriteFailed, []*metric.Counter{m.ClientDisconnectCount}}, | ||
{codeClientDisconnected, []*metric.Counter{m.ClientDisconnectCount}}, | ||
|
||
{codeBackendDisconnected, []*metric.Counter{m.BackendDisconnectCount}}, | ||
{codeBackendReadFailed, []*metric.Counter{m.BackendDisconnectCount}}, | ||
{codeBackendWriteFailed, []*metric.Counter{m.BackendDisconnectCount}}, | ||
|
||
{codeExpiredClientConnection, []*metric.Counter{m.ExpiredClientConnCount}}, | ||
|
||
{codeProxyRefusedConnection, []*metric.Counter{m.RefusedConnCount, m.BackendDownCount}}, | ||
|
||
{codeParamsRoutingFailed, []*metric.Counter{m.RoutingErrCount, m.BackendDownCount}}, | ||
{codeUnavailable, []*metric.Counter{m.RoutingErrCount, m.BackendDownCount}}, | ||
|
||
{codeBackendDown, []*metric.Counter{m.BackendDownCount}}, | ||
|
||
{codeAuthFailed, []*metric.Counter{m.AuthFailedCount}}, | ||
} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.code.String(), func(t *testing.T) { | ||
var before []int64 | ||
for _, counter := range tc.counters { | ||
before = append(before, counter.Count()) | ||
} | ||
m.updateForError(newErrorf(tc.code, "test error")) | ||
for i, counter := range tc.counters { | ||
require.Equal(t, counter.Count(), before[i]+1) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.