1
+ use std:: pin:: Pin ;
1
2
use std:: sync:: Arc ;
2
3
use std:: time:: Duration ;
3
4
5
+ use futures:: Future ;
4
6
use futures_core:: future:: BoxFuture ;
5
7
use futures_core:: Stream ;
6
8
use libsql_replication:: rpc:: proxy:: proxy_client:: ProxyClient ;
@@ -9,7 +11,7 @@ use libsql_replication::rpc::proxy::{
9
11
} ;
10
12
use libsql_sys:: EncryptionConfig ;
11
13
use parking_lot:: Mutex as PMutex ;
12
- use tokio:: sync:: { mpsc, watch , Mutex } ;
14
+ use tokio:: sync:: { mpsc, Mutex } ;
13
15
use tokio_stream:: StreamExt ;
14
16
use tonic:: transport:: Channel ;
15
17
use tonic:: { Code , Request , Streaming } ;
@@ -23,16 +25,21 @@ use crate::replication::FrameNo;
23
25
use crate :: stats:: Stats ;
24
26
use crate :: { Result , DEFAULT_AUTO_CHECKPOINT } ;
25
27
28
+ use super :: connection_core:: GetCurrentFrameNo ;
26
29
use super :: program:: DescribeResponse ;
27
30
use super :: { Connection , RequestContext } ;
28
31
use super :: { MakeConnection , Program } ;
29
32
30
33
pub type RpcStream = Streaming < ExecResp > ;
34
+ pub type WaitForFrameNo = Arc <
35
+ dyn Fn ( FrameNo ) -> Pin < Box < dyn Future < Output = ( ) > + Send + ' static > > + Send + ' static + Sync ,
36
+ > ;
31
37
32
38
pub struct MakeWriteProxyConn < M > {
33
39
client : ProxyClient < Channel > ,
34
40
stats : Arc < Stats > ,
35
- applied_frame_no_receiver : watch:: Receiver < Option < FrameNo > > ,
41
+ wait_for_frame_no : WaitForFrameNo ,
42
+ get_current_frame_no : GetCurrentFrameNo ,
36
43
max_response_size : u64 ,
37
44
max_total_response_size : u64 ,
38
45
primary_replication_index : Option < FrameNo > ,
@@ -47,23 +54,25 @@ impl<M> MakeWriteProxyConn<M> {
47
54
channel : Channel ,
48
55
uri : tonic:: transport:: Uri ,
49
56
stats : Arc < Stats > ,
50
- applied_frame_no_receiver : watch :: Receiver < Option < FrameNo > > ,
57
+ wait_for_frame_no : WaitForFrameNo ,
51
58
max_response_size : u64 ,
52
59
max_total_response_size : u64 ,
53
60
primary_replication_index : Option < FrameNo > ,
54
61
encryption_config : Option < EncryptionConfig > ,
55
62
make_read_only_conn : M ,
63
+ get_current_frame_no : GetCurrentFrameNo ,
56
64
) -> Self {
57
65
let client = ProxyClient :: with_origin ( channel, uri) ;
58
66
Self {
59
67
client,
60
68
stats,
61
- applied_frame_no_receiver ,
69
+ wait_for_frame_no ,
62
70
max_response_size,
63
71
max_total_response_size,
64
72
make_read_only_conn,
65
73
primary_replication_index,
66
74
encryption_config,
75
+ get_current_frame_no,
67
76
}
68
77
}
69
78
}
@@ -78,14 +87,15 @@ where
78
87
Ok ( WriteProxyConnection :: new (
79
88
self . client . clone ( ) ,
80
89
self . stats . clone ( ) ,
81
- self . applied_frame_no_receiver . clone ( ) ,
90
+ self . wait_for_frame_no . clone ( ) ,
82
91
QueryBuilderConfig {
83
92
max_size : Some ( self . max_response_size ) ,
84
93
max_total_size : Some ( self . max_total_response_size ) ,
85
94
auto_checkpoint : DEFAULT_AUTO_CHECKPOINT ,
86
95
encryption_config : self . encryption_config . clone ( ) ,
87
96
} ,
88
97
self . primary_replication_index ,
98
+ self . get_current_frame_no . clone ( ) ,
89
99
self . make_read_only_conn . create ( ) . await ?,
90
100
) ?)
91
101
}
@@ -100,8 +110,9 @@ pub struct WriteProxyConnection<R, C> {
100
110
/// any subsequent read on this connection must wait for the replicator to catch up with this
101
111
/// frame_no
102
112
last_write_frame_no : PMutex < Option < FrameNo > > ,
103
- /// Notifier from the repliator of the currently applied frameno
104
- applied_frame_no_receiver : watch:: Receiver < Option < FrameNo > > ,
113
+ /// Notifier from the replicator of the currently applied frame_no
114
+ wait_for_frame_no : WaitForFrameNo ,
115
+ get_current_frame_no : GetCurrentFrameNo ,
105
116
builder_config : QueryBuilderConfig ,
106
117
stats : Arc < Stats > ,
107
118
@@ -115,21 +126,23 @@ impl<C: Connection> WriteProxyConnection<RpcStream, C> {
115
126
fn new (
116
127
write_proxy : ProxyClient < Channel > ,
117
128
stats : Arc < Stats > ,
118
- applied_frame_no_receiver : watch :: Receiver < Option < FrameNo > > ,
129
+ wait_for_frame_no : WaitForFrameNo ,
119
130
builder_config : QueryBuilderConfig ,
120
131
primary_replication_index : Option < u64 > ,
132
+ get_current_frame_no : GetCurrentFrameNo ,
121
133
read_conn : C ,
122
134
) -> Result < Self > {
123
135
Ok ( Self {
124
136
read_conn,
125
137
write_proxy,
126
138
state : Mutex :: new ( TxnStatus :: Init ) ,
127
139
last_write_frame_no : Default :: default ( ) ,
128
- applied_frame_no_receiver ,
140
+ wait_for_frame_no ,
129
141
builder_config,
130
142
stats,
131
143
remote_conn : Default :: default ( ) ,
132
144
primary_replication_index,
145
+ get_current_frame_no,
133
146
} )
134
147
}
135
148
@@ -200,15 +213,7 @@ impl<C: Connection> WriteProxyConnection<RpcStream, C> {
200
213
let current_fno = replication_index. or_else ( || * self . last_write_frame_no . lock ( ) ) ;
201
214
match current_fno {
202
215
Some ( current_frame_no) => {
203
- let mut receiver = self . applied_frame_no_receiver . clone ( ) ;
204
- receiver
205
- . wait_for ( |last_applied| match last_applied {
206
- Some ( x) => * x >= current_frame_no,
207
- None => true ,
208
- } )
209
- . await
210
- . map_err ( |_| Error :: ReplicatorExited ) ?;
211
-
216
+ ( self . wait_for_frame_no ) ( current_frame_no) . await ;
212
217
Ok ( ( ) )
213
218
}
214
219
None => Ok ( ( ) ) ,
@@ -220,7 +225,7 @@ impl<C: Connection> WriteProxyConnection<RpcStream, C> {
220
225
fn should_proxy ( & self ) -> bool {
221
226
// There primary has data
222
227
if let Some ( primary_index) = self . primary_replication_index {
223
- let last_applied = * self . applied_frame_no_receiver . borrow ( ) ;
228
+ let last_applied = ( self . get_current_frame_no ) ( ) ;
224
229
// if we either don't have data while the primary has, or the data we have is
225
230
// anterior to that of the primary when we loaded the namespace, then proxy the
226
231
// request to the primary
0 commit comments