Skip to content

Commit 29e8a99

Browse files
drmingdrmerclaude
andauthored
refactor(schema-api): extract SecurityApi trait (#18658)
* refactor(schema-api): extract DictionaryApi trait Extract DictionaryApi trait from monolithic SchemaApi to improve code organization and maintainability. This continues the ongoing schema API refactoring effort by moving dictionary-related operations into their own focused trait interface. * refactor(schema-api): extract LockApi trait Extract LockApi trait from monolithic SchemaApi to improve code organization and maintainability. This continues the ongoing schema API refactoring effort by moving lock management operations into their own focused trait interface. * refactor(schema-api): extract SecurityApi trait Extract SecurityApi trait from monolithic SchemaApi to improve code organization and maintainability. This continues the ongoing schema API refactoring effort by moving security policy management operations into their own focused trait interface. The extraction includes security policy operations: - set_table_column_mask_policy: Set column data masking policies for tables - set_table_row_access_policy: Set row-level access policies for tables Changes made: - Created new `security_api.rs` with SecurityApi trait definition - Moved 2 security methods with complete implementations from SchemaApi - Moved helper function `update_mask_policy` for policy management - Updated SchemaApi trait bounds to include SecurityApi dependency - Added module exports and fixed import dependencies in consuming code - Updated mutable_catalog.rs and default_database.rs to import SecurityApi Progress: 55 of 58 methods (95%) now extracted from SchemaApi into focused sub-traits, leaving only minimal specialized domains for final cleanup: GC (1), Utility (2) methods. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 21edb8b commit 29e8a99

File tree

7 files changed

+760
-579
lines changed

7 files changed

+760
-579
lines changed

src/meta/api/src/dictionary_api.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Copyright 2021 Datafuse Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use databend_common_meta_app::app_error::AppError;
16+
use databend_common_meta_app::schema::dictionary_id_ident::DictionaryId;
17+
use databend_common_meta_app::schema::dictionary_name_ident::DictionaryNameIdent;
18+
use databend_common_meta_app::schema::dictionary_name_ident::DictionaryNameRsc;
19+
use databend_common_meta_app::schema::CreateDictionaryReply;
20+
use databend_common_meta_app::schema::CreateDictionaryReq;
21+
use databend_common_meta_app::schema::DictionaryIdentity;
22+
use databend_common_meta_app::schema::DictionaryMeta;
23+
use databend_common_meta_app::schema::ListDictionaryReq;
24+
use databend_common_meta_app::schema::RenameDictionaryReq;
25+
use databend_common_meta_app::schema::UpdateDictionaryReply;
26+
use databend_common_meta_app::schema::UpdateDictionaryReq;
27+
use databend_common_meta_app::tenant_key::errors::ExistError;
28+
use databend_common_meta_kvapi::kvapi;
29+
use databend_common_meta_kvapi::kvapi::DirName;
30+
use databend_common_meta_types::ConditionResult::Eq;
31+
use databend_common_meta_types::MetaError;
32+
use databend_common_meta_types::SeqV;
33+
use databend_common_meta_types::TxnRequest;
34+
use fastrace::func_name;
35+
use log::debug;
36+
37+
use crate::kv_app_error::KVAppError;
38+
use crate::kv_pb_api::KVPbApi;
39+
use crate::meta_txn_error::MetaTxnError;
40+
use crate::name_id_value_api::NameIdValueApi;
41+
use crate::send_txn;
42+
use crate::txn_backoff::txn_backoff;
43+
use crate::txn_cond_seq;
44+
use crate::txn_op_del;
45+
use crate::util::txn_op_put_pb;
46+
47+
/// DictionaryApi defines APIs for dictionary management.
48+
///
49+
/// This trait handles:
50+
/// - Dictionary creation, update, and deletion
51+
/// - Dictionary metadata queries and listing
52+
/// - Dictionary renaming operations
53+
#[async_trait::async_trait]
54+
pub trait DictionaryApi
55+
where
56+
Self: Send + Sync,
57+
Self: kvapi::KVApi<Error = MetaError>,
58+
{
59+
#[logcall::logcall]
60+
#[fastrace::trace]
61+
async fn create_dictionary(
62+
&self,
63+
req: CreateDictionaryReq,
64+
) -> Result<CreateDictionaryReply, KVAppError> {
65+
debug!(req :? = (&req); "DictionaryApi: {}", func_name!());
66+
67+
let name_ident = &req.dictionary_ident;
68+
69+
let create_res = self
70+
.create_id_value(
71+
name_ident,
72+
&req.dictionary_meta,
73+
false,
74+
|_| vec![],
75+
|_, _| Ok(vec![]),
76+
)
77+
.await?;
78+
79+
match create_res {
80+
Ok(id) => Ok(CreateDictionaryReply { dictionary_id: *id }),
81+
Err(_existent) => Err(AppError::from(name_ident.exist_error(func_name!())).into()),
82+
}
83+
}
84+
85+
#[logcall::logcall]
86+
#[fastrace::trace]
87+
async fn update_dictionary(
88+
&self,
89+
req: UpdateDictionaryReq,
90+
) -> Result<UpdateDictionaryReply, KVAppError> {
91+
debug!(req :? = (&req); "DictionaryApi: {}", func_name!());
92+
93+
let res = self
94+
.update_id_value(&req.dictionary_ident, req.dictionary_meta)
95+
.await?;
96+
97+
if let Some((id, _meta)) = res {
98+
Ok(UpdateDictionaryReply { dictionary_id: *id })
99+
} else {
100+
Err(AppError::from(req.dictionary_ident.unknown_error(func_name!())).into())
101+
}
102+
}
103+
104+
#[logcall::logcall]
105+
#[fastrace::trace]
106+
async fn drop_dictionary(
107+
&self,
108+
name_ident: DictionaryNameIdent,
109+
) -> Result<Option<SeqV<DictionaryMeta>>, MetaTxnError> {
110+
debug!(dict_ident :? =(&name_ident); "DictionaryApi: {}", func_name!());
111+
112+
let removed = self.remove_id_value(&name_ident, |_| vec![]).await?;
113+
Ok(removed.map(|(_, meta)| meta))
114+
}
115+
116+
#[logcall::logcall]
117+
#[fastrace::trace]
118+
async fn get_dictionary(
119+
&self,
120+
name_ident: DictionaryNameIdent,
121+
) -> Result<Option<(SeqV<DictionaryId>, SeqV<DictionaryMeta>)>, MetaError> {
122+
debug!(dict_ident :? =(&name_ident); "DictionaryApi: {}", func_name!());
123+
124+
let got = self.get_id_value(&name_ident).await?;
125+
Ok(got)
126+
}
127+
128+
#[logcall::logcall]
129+
#[fastrace::trace]
130+
async fn list_dictionaries(
131+
&self,
132+
req: ListDictionaryReq,
133+
) -> Result<Vec<(String, DictionaryMeta)>, KVAppError> {
134+
debug!(req :? =(&req); "DictionaryApi: {}", func_name!());
135+
136+
let dictionary_ident = DictionaryNameIdent::new(
137+
req.tenant.clone(),
138+
DictionaryIdentity::new(req.db_id, "dummy".to_string()),
139+
);
140+
let dir = DirName::new(dictionary_ident);
141+
let name_id_values = self.list_id_value(&dir).await?;
142+
Ok(name_id_values
143+
.map(|(name, _seq_id, seq_meta)| (name.dict_name(), seq_meta.data))
144+
.collect())
145+
}
146+
147+
#[logcall::logcall]
148+
#[fastrace::trace]
149+
async fn rename_dictionary(&self, req: RenameDictionaryReq) -> Result<(), KVAppError> {
150+
debug!(req :? =(&req); "DictionaryApi: {}", func_name!());
151+
152+
let mut trials = txn_backoff(None, func_name!());
153+
loop {
154+
trials.next().unwrap()?.await;
155+
156+
let dict_id = self
157+
.get_pb(&req.name_ident)
158+
.await?
159+
.ok_or_else(|| AppError::from(req.name_ident.unknown_error(func_name!())))?;
160+
161+
let new_name_ident = DictionaryNameIdent::new(req.tenant(), req.new_dict_ident.clone());
162+
let new_dict_id_seq = self.get_seq(&new_name_ident).await?;
163+
let _ = dict_has_to_not_exist(new_dict_id_seq, &new_name_ident, "rename_dictionary")
164+
.map_err(|_| AppError::from(new_name_ident.exist_error(func_name!())))?;
165+
166+
let condition = vec![
167+
txn_cond_seq(&req.name_ident, Eq, dict_id.seq),
168+
txn_cond_seq(&new_name_ident, Eq, 0),
169+
];
170+
let if_then = vec![
171+
txn_op_del(&req.name_ident), // del old dict name
172+
txn_op_put_pb(&new_name_ident, &dict_id.data, None)?, // put new dict name
173+
];
174+
175+
let txn_req = TxnRequest::new(condition, if_then);
176+
177+
let (succ, _responses) = send_txn(self, txn_req).await?;
178+
179+
debug!(
180+
name :? =(req.name_ident),
181+
to :? =(&new_name_ident),
182+
succ = succ;
183+
"rename_dictionary"
184+
);
185+
186+
if succ {
187+
return Ok(());
188+
}
189+
}
190+
}
191+
}
192+
193+
/// Check dictionary does not exist by checking the seq number.
194+
///
195+
/// seq == 0 means does not exist.
196+
/// seq > 0 means exist.
197+
///
198+
/// If dict does not exist, return Ok(());
199+
/// Otherwise returns DictionaryAlreadyExists error
200+
fn dict_has_to_not_exist(
201+
seq: u64,
202+
name_ident: &DictionaryNameIdent,
203+
_ctx: impl std::fmt::Display,
204+
) -> Result<(), ExistError<DictionaryNameRsc, DictionaryIdentity>> {
205+
if seq == 0 {
206+
Ok(())
207+
} else {
208+
debug!(seq = seq, name_ident :? =(name_ident); "exist");
209+
Err(name_ident.exist_error(func_name!()))
210+
}
211+
}
212+
213+
#[async_trait::async_trait]
214+
impl<KV> DictionaryApi for KV
215+
where
216+
KV: Send + Sync,
217+
KV: kvapi::KVApi<Error = MetaError> + ?Sized,
218+
{
219+
}

src/meta/api/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,19 @@ mod data_mask_api;
2323
mod data_mask_api_impl;
2424
mod database_api;
2525
pub mod database_util;
26+
pub mod dictionary_api;
2627
pub mod index_api;
2728
pub mod kv_app_error;
2829
pub mod kv_pb_api;
2930
pub mod kv_pb_crud_api;
31+
pub mod lock_api;
3032
pub mod meta_txn_error;
3133
pub mod name_id_value_api;
3234
pub mod name_value_api;
3335
pub mod reply;
3436
mod schema_api;
3537
mod schema_api_test_suite;
38+
pub mod security_api;
3639
mod sequence_api;
3740
pub mod table_api;
3841
pub(crate) mod testing;
@@ -49,10 +52,13 @@ pub(crate) mod sequence_nextval_impl;
4952
pub use catalog_api::CatalogApi;
5053
pub use data_mask_api::DatamaskApi;
5154
pub use database_api::DatabaseApi;
55+
pub use dictionary_api::DictionaryApi;
5256
pub use index_api::IndexApi;
57+
pub use lock_api::LockApi;
5358
pub use row_access_policy_api::RowAccessPolicyApi;
5459
pub use schema_api::SchemaApi;
5560
pub use schema_api_test_suite::SchemaApiTestSuite;
61+
pub use security_api::SecurityApi;
5662
pub use sequence_api::SequenceApi;
5763
pub use table_api::TableApi;
5864
pub use util::assert_table_exist;

0 commit comments

Comments
 (0)