1
- // Copyright 2022 CeresDB Project Authors. Licensed under Apache-2.0.
1
+ // Copyright 2022-2023 CeresDB Project Authors. Licensed under Apache-2.0.
2
2
3
3
//! A router based on the [`cluster::Cluster`].
4
4
5
5
use async_trait:: async_trait;
6
6
use ceresdbproto:: storage:: { Route , RouteRequest } ;
7
7
use cluster:: ClusterRef ;
8
8
use common_util:: error:: BoxError ;
9
- use meta_client:: types:: RouteTablesRequest ;
9
+ use meta_client:: types:: { RouteTablesRequest , TableInfo } ;
10
10
use moka:: future:: Cache ;
11
11
use snafu:: ResultExt ;
12
12
@@ -15,9 +15,16 @@ use crate::{
15
15
RouteCacheConfig , Router ,
16
16
} ;
17
17
18
+ #[ derive( Clone ) ]
19
+ struct RouteData {
20
+ table_name : String ,
21
+ table_info : TableInfo ,
22
+ endpoint : Option < Endpoint > ,
23
+ }
24
+
18
25
pub struct ClusterBasedRouter {
19
26
cluster : ClusterRef ,
20
- cache : Option < Cache < String , Route > > ,
27
+ cache : Option < Cache < String , RouteData > > ,
21
28
}
22
29
23
30
impl ClusterBasedRouter {
@@ -39,7 +46,7 @@ impl ClusterBasedRouter {
39
46
40
47
/// route table from local cache, return cache routes and tables which are
41
48
/// not in cache
42
- fn route_from_cache ( & self , tables : Vec < String > , routes : & mut Vec < Route > ) -> Vec < String > {
49
+ fn route_from_cache ( & self , tables : Vec < String > , routes : & mut Vec < RouteData > ) -> Vec < String > {
43
50
let mut miss = vec ! [ ] ;
44
51
45
52
if let Some ( cache) = & self . cache {
@@ -56,33 +63,20 @@ impl ClusterBasedRouter {
56
63
57
64
miss
58
65
}
59
- }
60
-
61
- /// Make a route according to the table name and the raw endpoint.
62
- fn make_route ( table_name : & str , endpoint : & str ) -> Result < Route > {
63
- let endpoint: Endpoint = endpoint. parse ( ) . context ( ParseEndpoint { endpoint } ) ?;
64
-
65
- Ok ( Route {
66
- table : table_name. to_string ( ) ,
67
- endpoint : Some ( endpoint. into ( ) ) ,
68
- } )
69
- }
70
-
71
- #[ async_trait]
72
- impl Router for ClusterBasedRouter {
73
- async fn route ( & self , req : RouteRequest ) -> Result < Vec < Route > > {
74
- let req_ctx = req. context . unwrap ( ) ;
75
66
67
+ async fn route_with_cache (
68
+ & self ,
69
+ tables : Vec < String > ,
70
+ database : String ,
71
+ ) -> Result < Vec < RouteData > > {
76
72
// Firstly route table from local cache.
77
- let mut routes = Vec :: with_capacity ( req. tables . len ( ) ) ;
78
- let miss = self . route_from_cache ( req. tables , & mut routes) ;
79
-
73
+ let mut routes = Vec :: with_capacity ( tables. len ( ) ) ;
74
+ let miss = self . route_from_cache ( tables, & mut routes) ;
80
75
if miss. is_empty ( ) {
81
76
return Ok ( routes) ;
82
77
}
83
-
84
78
let route_tables_req = RouteTablesRequest {
85
- schema_name : req_ctx . database ,
79
+ schema_name : database,
86
80
table_names : miss,
87
81
} ;
88
82
@@ -99,7 +93,7 @@ impl Router for ClusterBasedRouter {
99
93
for ( table_name, route_entry) in route_resp. entries {
100
94
for node_shard in route_entry. node_shards {
101
95
if node_shard. shard_info . is_leader ( ) {
102
- let route = make_route ( & table_name , & node_shard. endpoint ) ?;
96
+ let route = make_route ( route_entry . table_info . clone ( ) , & node_shard. endpoint ) ?;
103
97
if let Some ( cache) = & self . cache {
104
98
// There may be data race here, and it is acceptable currently.
105
99
cache. insert ( table_name. clone ( ) , route. clone ( ) ) . await ;
@@ -108,43 +102,59 @@ impl Router for ClusterBasedRouter {
108
102
}
109
103
}
110
104
}
111
- return Ok ( routes) ;
105
+ Ok ( routes)
106
+ }
107
+ }
108
+
109
+ /// Make a route according to the table_info and the raw endpoint.
110
+ fn make_route ( table_info : TableInfo , endpoint : & str ) -> Result < RouteData > {
111
+ let endpoint: Endpoint = endpoint. parse ( ) . context ( ParseEndpoint { endpoint } ) ?;
112
+
113
+ Ok ( RouteData {
114
+ table_name : table_info. name . clone ( ) ,
115
+ table_info,
116
+ endpoint : Some ( endpoint) ,
117
+ } )
118
+ }
119
+
120
+ #[ async_trait]
121
+ impl Router for ClusterBasedRouter {
122
+ async fn route ( & self , req : RouteRequest ) -> Result < Vec < Route > > {
123
+ let req_ctx = req. context . unwrap ( ) ;
124
+ let route_data_vec = self . route_with_cache ( req. tables , req_ctx. database ) . await ?;
125
+ Ok ( route_data_vec
126
+ . into_iter ( )
127
+ . map ( |v| Route {
128
+ table : v. table_name ,
129
+ endpoint : v. endpoint . map ( Into :: into) ,
130
+ } )
131
+ . collect ( ) )
112
132
}
113
133
114
134
async fn fetch_partition_table_info (
115
135
& self ,
116
136
schema : & str ,
117
137
table : & str ,
118
138
) -> Result < Option < PartitionTableInfo > > {
119
- let route_tables_req = RouteTablesRequest {
120
- schema_name : schema. to_string ( ) ,
121
- table_names : vec ! [ table. to_string( ) ] ,
122
- } ;
123
- let route_resp = self
124
- . cluster
125
- . route_tables ( & route_tables_req)
126
- . await
127
- . box_err ( )
128
- . with_context ( || OtherWithCause {
129
- msg : format ! ( "Failed to route tables by cluster, req:{route_tables_req:?}" ) ,
130
- } ) ?;
139
+ let mut route_data_vec = self
140
+ . route_with_cache ( vec ! [ table. to_string( ) ] , schema. to_string ( ) )
141
+ . await ?;
142
+ if route_data_vec. is_empty ( ) {
143
+ return Ok ( None ) ;
144
+ }
131
145
132
- let table_info = route_resp
133
- . entries
134
- . get ( table)
135
- . map ( |entry| entry. table_info . clone ( ) ) ;
136
- if let Some ( v) = table_info {
137
- if v. partition_info . is_some ( ) {
138
- let partition_table_info = PartitionTableInfo {
139
- id : v. id ,
140
- name : v. name ,
141
- schema_id : v. schema_id ,
142
- schema_name : v. schema_name ,
143
- partition_info : v. partition_info . unwrap ( ) ,
144
- } ;
145
- return Ok ( Some ( partition_table_info) ) ;
146
- }
146
+ let route_data = route_data_vec. remove ( 0 ) ;
147
+ let table_info = route_data. table_info ;
148
+ if table_info. partition_info . is_some ( ) {
149
+ return Ok ( Some ( PartitionTableInfo {
150
+ id : table_info. id ,
151
+ name : table_info. name ,
152
+ schema_id : table_info. schema_id ,
153
+ schema_name : table_info. schema_name ,
154
+ partition_info : table_info. partition_info . unwrap ( ) ,
155
+ } ) ) ;
147
156
}
157
+
148
158
Ok ( None )
149
159
}
150
160
}
@@ -288,7 +298,7 @@ mod tests {
288
298
let mut routes = Vec :: with_capacity ( tables. len ( ) ) ;
289
299
let miss = router. route_from_cache ( tables, & mut routes) ;
290
300
assert_eq ! ( routes. len( ) , 1 ) ;
291
- assert_eq ! ( routes[ 0 ] . table , table1. to_string( ) ) ;
301
+ assert_eq ! ( routes[ 0 ] . table_name , table1. to_string( ) ) ;
292
302
assert_eq ! ( miss. len( ) , 0 ) ;
293
303
294
304
// sleep 1.5s, table2 will be evicted, and table1 in cache
@@ -297,7 +307,7 @@ mod tests {
297
307
let mut routes = Vec :: with_capacity ( tables. len ( ) ) ;
298
308
let miss = router. route_from_cache ( tables, & mut routes) ;
299
309
assert_eq ! ( routes. len( ) , 1 ) ;
300
- assert_eq ! ( routes[ 0 ] . table , table1. to_string( ) ) ;
310
+ assert_eq ! ( routes[ 0 ] . table_name , table1. to_string( ) ) ;
301
311
assert_eq ! ( miss. len( ) , 1 ) ;
302
312
assert_eq ! ( miss[ 0 ] , table2. to_string( ) ) ;
303
313
}
0 commit comments