Skip to content

Commit 5540a6d

Browse files
authored
Merge pull request #3369 from ariesdevil/raft-follower-read
follower forward ListDatabase and GetTableInfo requests
2 parents 72b2f40 + 082952f commit 5540a6d

File tree

5 files changed

+182
-10
lines changed

5 files changed

+182
-10
lines changed

common/meta/api/src/meta_api_test_suite.rs

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use common_meta_types::CreateTableReq;
2424
use common_meta_types::DropDatabaseReq;
2525
use common_meta_types::DropTableReq;
2626
use common_meta_types::GetDatabaseReq;
27+
use common_meta_types::GetTableReq;
2728
use common_meta_types::ListDatabaseReq;
2829
use common_meta_types::ListTableReq;
2930
use common_meta_types::TableIdent;
@@ -480,7 +481,7 @@ impl MetaApiTestSuite {
480481
tracing::debug!("get present database res: {:?}", res);
481482
let res = res?;
482483
assert_eq!(1, res.database_id, "db1 id is 1");
483-
assert_eq!("db1".to_string(), res.db, "db1.db is db1");
484+
assert_eq!("db1", res.db, "db1.db is db1");
484485
}
485486

486487
tracing::info!("--- get nonexistent-db on follower, expect correct error");
@@ -498,6 +499,42 @@ impl MetaApiTestSuite {
498499
Ok(())
499500
}
500501

502+
pub async fn list_database_leader_follower<MT: MetaApi>(
503+
&self,
504+
leader: &MT,
505+
follower: &MT,
506+
) -> anyhow::Result<()> {
507+
tracing::info!("--- create db1 and db3 on leader");
508+
{
509+
let dbs = vec!["db1", "db3"];
510+
for db_name in dbs {
511+
let req = CreateDatabaseReq {
512+
if_not_exists: false,
513+
db: db_name.to_string(),
514+
engine: "github".to_string(),
515+
options: Default::default(),
516+
};
517+
let res = leader.create_database(req).await;
518+
tracing::info!("create database res: {:?}", res);
519+
assert!(res.is_ok());
520+
}
521+
}
522+
523+
tracing::info!("--- list databases from follower");
524+
{
525+
let res = follower.list_databases(ListDatabaseReq {}).await;
526+
tracing::debug!("get database list: {:?}", res);
527+
let res = res?;
528+
assert_eq!(2, res.len(), "database list len is 2");
529+
assert_eq!(1, res[0].database_id, "db1 id is 1");
530+
assert_eq!("db1", res[0].db, "db1.name is db1");
531+
assert_eq!(2, res[1].database_id, "db3 id is 2");
532+
assert_eq!("db3", res[1].db, "db3.name is db3");
533+
}
534+
535+
Ok(())
536+
}
537+
501538
pub async fn list_table_leader_follower<MT: MetaApi>(
502539
&self,
503540
leader: &MT,
@@ -548,9 +585,74 @@ impl MetaApiTestSuite {
548585
let res = res?;
549586
assert_eq!(2, res.len(), "table list len is 2");
550587
assert_eq!(1, res[0].ident.table_id, "tb1 id is 1");
551-
assert_eq!("tb1".to_string(), res[0].name, "tb1.name is tb1");
588+
assert_eq!("tb1", res[0].name, "tb1.name is tb1");
552589
assert_eq!(2, res[1].ident.table_id, "tb2 id is 2");
553-
assert_eq!("tb2".to_string(), res[1].name, "tb2.name is tb2");
590+
assert_eq!("tb2", res[1].name, "tb2.name is tb2");
591+
}
592+
593+
Ok(())
594+
}
595+
596+
pub async fn table_get_leader_follower<MT: MetaApi>(
597+
&self,
598+
leader: &MT,
599+
follower: &MT,
600+
) -> anyhow::Result<()> {
601+
tracing::info!("--- create table tb1 on leader");
602+
let db_name = "db1";
603+
{
604+
let req = CreateDatabaseReq {
605+
if_not_exists: false,
606+
db: db_name.to_string(),
607+
engine: "github".to_string(),
608+
options: Default::default(),
609+
};
610+
let res = leader.create_database(req).await;
611+
tracing::info!("create database res: {:?}", res);
612+
assert!(res.is_ok());
613+
614+
let schema = Arc::new(DataSchema::new(vec![DataField::new(
615+
"number",
616+
DataType::UInt64,
617+
false,
618+
)]));
619+
620+
let options = maplit::hashmap! {"opt‐1".into() => "val-1".into()};
621+
622+
let req = CreateTableReq {
623+
if_not_exists: false,
624+
db: db_name.to_string(),
625+
table: "tb1".to_string(),
626+
table_meta: TableMeta {
627+
schema: schema.clone(),
628+
engine: "JSON".to_string(),
629+
options: options.clone(),
630+
},
631+
};
632+
633+
let res = leader.create_table(req).await;
634+
tracing::info!("create table res: {:?}", res);
635+
assert!(res.is_ok());
636+
}
637+
638+
tracing::info!("--- get tb1 on follower");
639+
{
640+
let res = follower.get_table(GetTableReq::new("db1", "tb1")).await;
641+
tracing::debug!("get present table res: {:?}", res);
642+
let res = res?;
643+
assert_eq!(1, res.ident.table_id, "tb1 id is 1");
644+
assert_eq!("tb1", res.name, "tb1.name is tb1");
645+
}
646+
647+
tracing::info!("--- get nonexistent-table on follower, expect correct error");
648+
{
649+
let res = follower
650+
.get_table(GetTableReq::new("db1", "nonexistent"))
651+
.await;
652+
tracing::debug!("get present table res: {:?}", res);
653+
let err = res.unwrap_err();
654+
println!("{:?}", err);
655+
assert_eq!(ErrorCode::UnknownTable("").code(), err.code());
554656
}
555657

556658
Ok(())

metasrv/src/executor/meta_handlers.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use std::sync::Arc;
1818

1919
use common_exception::ErrorCode;
2020
use common_exception::ToErrorCode;
21-
use common_meta_api::MetaApi;
2221
use common_meta_flight::FlightReq;
2322
use common_meta_flight::GetTableExtReq;
2423
use common_meta_types::Change;
@@ -247,8 +246,20 @@ impl RequestHandler<FlightReq<GetTableReq>> for ActionHandler {
247246
&self,
248247
act: FlightReq<GetTableReq>,
249248
) -> common_exception::Result<Arc<TableInfo>> {
250-
let sm = self.meta_node.get_state_machine().await;
251-
sm.get_table(act.req).await
249+
let res = self
250+
.meta_node
251+
.handle_admin_req(AdminRequest {
252+
forward_to_leader: true,
253+
req: AdminRequestInner::GetTable(act.req),
254+
})
255+
.await?;
256+
let res: Arc<TableInfo> = res
257+
.try_into()
258+
.map_err_to_code(ErrorCode::UnknownException, || {
259+
"handling FlightReq GetTableReq".to_string()
260+
})?;
261+
262+
Ok(res)
252263
}
253264
}
254265

@@ -279,8 +290,21 @@ impl RequestHandler<FlightReq<ListDatabaseReq>> for ActionHandler {
279290
&self,
280291
req: FlightReq<ListDatabaseReq>,
281292
) -> common_exception::Result<Vec<Arc<DatabaseInfo>>> {
282-
let sm = self.meta_node.get_state_machine().await;
283-
sm.list_databases(req.req).await
293+
let res = self
294+
.meta_node
295+
.handle_admin_req(AdminRequest {
296+
forward_to_leader: true,
297+
req: AdminRequestInner::ListDatabase(req.req),
298+
})
299+
.await?;
300+
301+
let res: Vec<Arc<DatabaseInfo>> = res
302+
.try_into()
303+
.map_err_to_code(ErrorCode::UnknownException, || {
304+
"handling FlightReq ListDatabaseReq".to_string()
305+
})?;
306+
307+
Ok(res)
284308
}
285309
}
286310

metasrv/src/meta_service/message.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use async_raft::raft::VoteRequest;
2020
use common_meta_raft_store::state_machine::AppliedState;
2121
use common_meta_types::DatabaseInfo;
2222
use common_meta_types::GetDatabaseReq;
23+
use common_meta_types::GetTableReq;
24+
use common_meta_types::ListDatabaseReq;
2325
use common_meta_types::ListTableReq;
2426
use common_meta_types::LogEntry;
2527
use common_meta_types::NodeId;
@@ -42,8 +44,10 @@ pub struct JoinRequest {
4244
pub enum AdminRequestInner {
4345
Join(JoinRequest),
4446
Write(LogEntry),
47+
ListDatabase(ListDatabaseReq),
4548
GetDatabase(GetDatabaseReq),
4649
ListTable(ListTableReq),
50+
GetTable(GetTableReq),
4751
}
4852

4953
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
@@ -65,8 +69,10 @@ impl AdminRequest {
6569
pub enum AdminResponse {
6670
Join(()),
6771
AppliedState(AppliedState),
72+
ListDatabase(Vec<Arc<DatabaseInfo>>),
6873
DatabaseInfo(Arc<DatabaseInfo>),
6974
ListTable(Vec<Arc<TableInfo>>),
75+
TableInfo(Arc<TableInfo>),
7076
}
7177

7278
impl tonic::IntoRequest<RaftRequest> for AdminRequest {

metasrv/src/meta_service/meta_leader.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,27 @@ impl<'a> MetaLeader<'a> {
6060
Ok(AdminResponse::AppliedState(res))
6161
}
6262

63+
AdminRequestInner::ListDatabase(req) => {
64+
let sm = self.meta_node.get_state_machine().await;
65+
let res = sm.list_databases(req).await?;
66+
Ok(AdminResponse::ListDatabase(res))
67+
}
68+
6369
AdminRequestInner::GetDatabase(req) => {
64-
let x = self.meta_node.get_state_machine().await;
65-
let res = x.get_database(req).await?;
70+
let sm = self.meta_node.get_state_machine().await;
71+
let res = sm.get_database(req).await?;
6672
Ok(AdminResponse::DatabaseInfo(res))
6773
}
6874
AdminRequestInner::ListTable(req) => {
6975
let sm = self.meta_node.get_state_machine().await;
7076
let res = sm.list_tables(req).await?;
7177
Ok(AdminResponse::ListTable(res))
7278
}
79+
AdminRequestInner::GetTable(req) => {
80+
let sm = self.meta_node.get_state_machine().await;
81+
let res = sm.get_table(req).await?;
82+
Ok(AdminResponse::TableInfo(res))
83+
}
7384
}
7485
}
7586

metasrv/tests/it/flight/metasrv_flight_meta_api_leader_follower.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@ async fn test_meta_api_database_create_get_drop() -> anyhow::Result<()> {
3333
.await
3434
}
3535

36+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
37+
async fn test_meta_api_list_database() -> anyhow::Result<()> {
38+
let (_log_guards, ut_span) = init_meta_ut!();
39+
let _ent = ut_span.enter();
40+
41+
let tcs = start_metasrv_cluster(&[0, 1]).await?;
42+
43+
let client0 = tcs[0].flight_client().await?;
44+
let client1 = tcs[1].flight_client().await?;
45+
46+
MetaApiTestSuite {}
47+
.list_database_leader_follower(&client0, &client1)
48+
.await
49+
}
50+
51+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
52+
async fn test_meta_api_table_create_get_drop() -> anyhow::Result<()> {
53+
let (_log_guards, ut_span) = init_meta_ut!();
54+
let _ent = ut_span.enter();
55+
56+
let tcs = start_metasrv_cluster(&[0, 1]).await?;
57+
58+
let client0 = tcs[0].flight_client().await?;
59+
let client1 = tcs[1].flight_client().await?;
60+
MetaApiTestSuite {}
61+
.table_get_leader_follower(&client0, &client1)
62+
.await
63+
}
64+
3665
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
3766
async fn test_meta_api_list_table() -> anyhow::Result<()> {
3867
let (_log_guards, ut_span) = init_meta_ut!();

0 commit comments

Comments
 (0)