@@ -10,7 +10,6 @@ package streamclient
10
10
11
11
import (
12
12
"context"
13
- gosql "database/sql"
14
13
"net"
15
14
"net/url"
16
15
@@ -19,35 +18,45 @@ import (
19
18
"github.com/cockroachdb/cockroach/pkg/roachpb"
20
19
"github.com/cockroachdb/cockroach/pkg/streaming"
21
20
"github.com/cockroachdb/cockroach/pkg/util/hlc"
21
+ "github.com/cockroachdb/cockroach/pkg/util/log"
22
22
"github.com/cockroachdb/cockroach/pkg/util/protoutil"
23
23
"github.com/cockroachdb/cockroach/pkg/util/syncutil"
24
24
"github.com/cockroachdb/cockroach/pkg/util/tracing"
25
25
"github.com/cockroachdb/errors"
26
+ "github.com/jackc/pgx/v4"
26
27
)
27
28
28
29
type partitionedStreamClient struct {
29
- srcDB * gosql.DB // DB handle to the source cluster
30
30
urlPlaceholder url.URL
31
+ pgxConfig * pgx.ConnConfig
31
32
32
33
mu struct {
33
34
syncutil.Mutex
34
35
35
36
closed bool
36
37
activeSubscriptions map [* partitionedStreamSubscription ]struct {}
38
+ srcConn * pgx.Conn // pgx connection to the source cluster
37
39
}
38
40
}
39
41
40
- func newPartitionedStreamClient (remote * url.URL ) (* partitionedStreamClient , error ) {
41
- db , err := gosql .Open ("postgres" , remote .String ())
42
+ func newPartitionedStreamClient (
43
+ ctx context.Context , remote * url.URL ,
44
+ ) (* partitionedStreamClient , error ) {
45
+ config , err := pgx .ParseConfig (remote .String ())
46
+ if err != nil {
47
+ return nil , err
48
+ }
49
+ conn , err := pgx .ConnectConfig (ctx , config )
42
50
if err != nil {
43
51
return nil , err
44
52
}
45
53
46
54
client := & partitionedStreamClient {
47
- srcDB : db ,
48
55
urlPlaceholder : * remote ,
56
+ pgxConfig : config ,
49
57
}
50
58
client .mu .activeSubscriptions = make (map [* partitionedStreamSubscription ]struct {})
59
+ client .mu .srcConn = conn
51
60
return client , nil
52
61
}
53
62
@@ -60,19 +69,16 @@ func (p *partitionedStreamClient) Create(
60
69
ctx , sp := tracing .ChildSpan (ctx , "streamclient.Client.Create" )
61
70
defer sp .Finish ()
62
71
63
- streamID := streaming .InvalidStreamID
64
-
65
- conn , err := p .srcDB .Conn (ctx )
72
+ p .mu .Lock ()
73
+ defer p .mu .Unlock ()
74
+ var streamID streaming.StreamID
75
+ row := p .mu .srcConn .QueryRow (ctx , `SELECT crdb_internal.start_replication_stream($1)` , tenantID .ToUint64 ())
76
+ err := row .Scan (& streamID )
66
77
if err != nil {
67
- return streamID , err
68
- }
69
-
70
- row := conn .QueryRowContext (ctx , `SELECT crdb_internal.start_replication_stream($1)` , tenantID .ToUint64 ())
71
- if row .Err () != nil {
72
- return streamID , errors .Wrapf (row .Err (), "error creating replication stream for tenant %s" , tenantID .String ())
78
+ return streaming .InvalidStreamID ,
79
+ errors .Wrapf (err , "error creating replication stream for tenant %s" , tenantID .String ())
73
80
}
74
81
75
- err = row .Scan (& streamID )
76
82
return streamID , err
77
83
}
78
84
@@ -83,21 +89,14 @@ func (p *partitionedStreamClient) Heartbeat(
83
89
ctx , sp := tracing .ChildSpan (ctx , "streamclient.Client.Heartbeat" )
84
90
defer sp .Finish ()
85
91
86
- conn , err := p .srcDB .Conn (ctx )
87
- if err != nil {
88
- return streampb.StreamReplicationStatus {}, err
89
- }
90
-
91
- row := conn .QueryRowContext (ctx ,
92
+ p .mu .Lock ()
93
+ defer p .mu .Unlock ()
94
+ row := p .mu .srcConn .QueryRow (ctx ,
92
95
`SELECT crdb_internal.replication_stream_progress($1, $2)` , streamID , consumed .String ())
93
- if row .Err () != nil {
94
- return streampb.StreamReplicationStatus {},
95
- errors .Wrapf (row .Err (), "error sending heartbeat to replication stream %d" , streamID )
96
- }
97
-
98
96
var rawStatus []byte
99
97
if err := row .Scan (& rawStatus ); err != nil {
100
- return streampb.StreamReplicationStatus {}, err
98
+ return streampb.StreamReplicationStatus {},
99
+ errors .Wrapf (err , "error sending heartbeat to replication stream %d" , streamID )
101
100
}
102
101
var status streampb.StreamReplicationStatus
103
102
if err := protoutil .Unmarshal (rawStatus , & status ); err != nil {
@@ -121,23 +120,19 @@ func (p *partitionedStreamClient) postgresURL(servingAddr string) (url.URL, erro
121
120
func (p * partitionedStreamClient ) Plan (
122
121
ctx context.Context , streamID streaming.StreamID ,
123
122
) (Topology , error ) {
124
- conn , err := p .srcDB .Conn (ctx )
125
- if err != nil {
126
- return nil , err
127
- }
128
-
129
- row := conn .QueryRowContext (ctx , `SELECT crdb_internal.replication_stream_spec($1)` , streamID )
130
- if row .Err () != nil {
131
- return nil , errors .Wrapf (row .Err (), "error planning replication stream %d" , streamID )
132
- }
133
-
134
- var rawSpec []byte
135
- if err := row .Scan (& rawSpec ); err != nil {
136
- return nil , err
137
- }
138
123
var spec streampb.ReplicationStreamSpec
139
- if err := protoutil .Unmarshal (rawSpec , & spec ); err != nil {
140
- return nil , err
124
+ {
125
+ p .mu .Lock ()
126
+ defer p .mu .Unlock ()
127
+
128
+ row := p .mu .srcConn .QueryRow (ctx , `SELECT crdb_internal.replication_stream_spec($1)` , streamID )
129
+ var rawSpec []byte
130
+ if err := row .Scan (& rawSpec ); err != nil {
131
+ return nil , errors .Wrapf (err , "error planning replication stream %d" , streamID )
132
+ }
133
+ if err := protoutil .Unmarshal (rawSpec , & spec ); err != nil {
134
+ return nil , err
135
+ }
141
136
}
142
137
143
138
topology := Topology {}
@@ -163,7 +158,7 @@ func (p *partitionedStreamClient) Plan(
163
158
}
164
159
165
160
// Close implements Client interface.
166
- func (p * partitionedStreamClient ) Close () error {
161
+ func (p * partitionedStreamClient ) Close (ctx context. Context ) error {
167
162
p .mu .Lock ()
168
163
defer p .mu .Unlock ()
169
164
@@ -176,7 +171,7 @@ func (p *partitionedStreamClient) Close() error {
176
171
close (sub .closeChan )
177
172
delete (p .mu .activeSubscriptions , sub )
178
173
}
179
- return p .srcDB . Close ()
174
+ return p .mu . srcConn . Close (ctx )
180
175
}
181
176
182
177
// Subscribe implements Client interface.
@@ -198,11 +193,11 @@ func (p *partitionedStreamClient) Subscribe(
198
193
}
199
194
200
195
res := & partitionedStreamSubscription {
201
- eventsChan : make (chan streamingccl.Event ),
202
- db : p . srcDB ,
203
- specBytes : specBytes ,
204
- streamID : stream ,
205
- closeChan : make (chan struct {}),
196
+ eventsChan : make (chan streamingccl.Event ),
197
+ srcConnConfig : p . pgxConfig ,
198
+ specBytes : specBytes ,
199
+ streamID : stream ,
200
+ closeChan : make (chan struct {}),
206
201
}
207
202
p .mu .Lock ()
208
203
defer p .mu .Unlock ()
@@ -215,21 +210,19 @@ func (p *partitionedStreamClient) Complete(ctx context.Context, streamID streami
215
210
ctx , sp := tracing .ChildSpan (ctx , "streamclient.Client.Complete" )
216
211
defer sp .Finish ()
217
212
218
- conn , err := p .srcDB .Conn (ctx )
219
- if err != nil {
220
- return err
221
- }
222
- row := conn .QueryRowContext (ctx , `SELECT crdb_internal.complete_replication_stream($1)` , streamID )
223
- if row .Err () != nil {
224
- return errors .Wrapf (row .Err (), "error completing replication stream %d" , streamID )
213
+ p .mu .Lock ()
214
+ defer p .mu .Unlock ()
215
+ row := p .mu .srcConn .QueryRow (ctx , `SELECT crdb_internal.complete_replication_stream($1)` , streamID )
216
+ if err := row .Scan (& streamID ); err != nil {
217
+ return errors .Wrapf (err , "error completing replication stream %d" , streamID )
225
218
}
226
219
return nil
227
220
}
228
221
229
222
type partitionedStreamSubscription struct {
230
- err error
231
- db * gosql. DB
232
- eventsChan chan streamingccl.Event
223
+ err error
224
+ srcConnConfig * pgx. ConnConfig
225
+ eventsChan chan streamingccl.Event
233
226
// Channel to send signal to close the subscription.
234
227
closeChan chan struct {}
235
228
@@ -274,16 +267,22 @@ func (p *partitionedStreamSubscription) Subscribe(ctx context.Context) error {
274
267
defer sp .Finish ()
275
268
276
269
defer close (p .eventsChan )
277
- conn , err := p .db .Conn (ctx )
270
+ // Each subscription has its own pgx connection.
271
+ srcConn , err := pgx .ConnectConfig (ctx , p .srcConnConfig )
278
272
if err != nil {
279
273
return err
280
274
}
275
+ defer func () {
276
+ if err != nil {
277
+ log .Warningf (ctx , "error when closing subscription connection: %v" , err )
278
+ }
279
+ }()
281
280
282
- _ , err = conn . ExecContext (ctx , `SET avoid_buffering = true` )
281
+ _ , err = srcConn . Exec (ctx , `SET avoid_buffering = true` )
283
282
if err != nil {
284
283
return err
285
284
}
286
- rows , err := conn . QueryContext (ctx , `SELECT * FROM crdb_internal.stream_partition($1, $2)` ,
285
+ rows , err := srcConn . Query (ctx , `SELECT * FROM crdb_internal.stream_partition($1, $2)` ,
287
286
p .streamID , p .specBytes )
288
287
if err != nil {
289
288
return err
0 commit comments