Skip to content

Commit 79d0986

Browse files
authored
feat: impl Keyword AUTOINCREMENT (#18715)
* feat: impl Keyword `AUTO INCREMENT` * chore: codefmt * chore: replace table name to table id on auto increment sequence name * chore: codefmt * feat: support `IDENTITY` & drop auto increment sequence on vacuum * chore: fmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: resolve review comment * chore: complete the auto increment sequence and create table in the same transaction * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: codefmt * chore: add unit test `test_vacuum_dropped_table_clean_sequences` * chore: rebase * refactor: separate AutoIncrementIdent from SequenceIdent * chore: typo * chore: codefmt * chore: codefmt * chore: codefmt * chore: code comment on add column * chore: refactoring `AutoIncrementMeta` and add `AutoIncrementStorageIdent` * chore: codefmt * chore: codefmt * chore: remove auto_increment_display on `v3::TableField` * chore: force clean auto increment sequence on vacuum drop table * chore: codefmt * refactor: Implement AutoIncrementAPI * chore: codefmt * chore: merge main * chore: codefmt like review comment * chore: codefmt * chore: fix `get_auto_increment_next_value` & `next_val` return error * chore: add `auto_increment_api_test_suite` * chore: add comment on metadata.proto AutoIncrementExpr * chore: codefmt * chore: codefmt * chore: Increase the minimum version of meta to 1.2.764 to support `fetch_add` and enable AutoIncrement to work * chore: codefmt * chore: Increase the minimum version of meta to 1.2.768 to support `fetch_add` and enable AutoIncrement to work * chore: modify the column allocation method of auto increment expr and add auto increment check of add column * chore: codefmt
1 parent 4085be4 commit 79d0986

File tree

61 files changed

+1830
-89
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1830
-89
lines changed

src/common/exception/src/exception_code.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ build_exceptions! {
291291
ConstraintError(1133),
292292
}
293293

294-
// Sequence Errors [1124-1126, 3101]
294+
// Sequence Errors [1124-1126, 3101-3102]
295295
build_exceptions! {
296296
/// Out of sequence range
297297
OutofSequenceRange(1124),
@@ -301,6 +301,8 @@ build_exceptions! {
301301
UnknownSequence(1126),
302302
/// Sequence error
303303
SequenceError(3101),
304+
/// AutoIncrement error
305+
AutoIncrementError(3102),
304306
}
305307

306308
// Virtual Column Errors [1128-1129]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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::schema::GetAutoIncrementNextValueReply;
16+
use databend_common_meta_app::schema::GetAutoIncrementNextValueReq;
17+
18+
use crate::errors::AutoIncrementError;
19+
use crate::meta_txn_error::MetaTxnError;
20+
21+
#[async_trait::async_trait]
22+
pub trait AutoIncrementApi: Send + Sync {
23+
async fn get_auto_increment_next_value(
24+
&self,
25+
req: GetAutoIncrementNextValueReq,
26+
) -> Result<Result<GetAutoIncrementNextValueReply, AutoIncrementError>, MetaTxnError>;
27+
}
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
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 std::sync::Arc;
16+
17+
use chrono::Utc;
18+
use databend_common_expression::types::NumberDataType;
19+
use databend_common_expression::AutoIncrementExpr;
20+
use databend_common_expression::TableDataType;
21+
use databend_common_expression::TableField;
22+
use databend_common_expression::TableSchema;
23+
use databend_common_meta_app::principal::AutoIncrementKey;
24+
use databend_common_meta_app::schema::database_name_ident::DatabaseNameIdent;
25+
use databend_common_meta_app::schema::AutoIncrementStorageIdent;
26+
use databend_common_meta_app::schema::CreateDatabaseReq;
27+
use databend_common_meta_app::schema::CreateOption;
28+
use databend_common_meta_app::schema::CreateTableReq;
29+
use databend_common_meta_app::schema::DatabaseMeta;
30+
use databend_common_meta_app::schema::GcDroppedTableReq;
31+
use databend_common_meta_app::schema::GetAutoIncrementNextValueReq;
32+
use databend_common_meta_app::schema::ListDroppedTableReq;
33+
use databend_common_meta_app::schema::TableMeta;
34+
use databend_common_meta_app::schema::TableNameIdent;
35+
use databend_common_meta_app::tenant::Tenant;
36+
use databend_common_meta_kvapi::kvapi;
37+
use databend_common_meta_kvapi::kvapi::Key;
38+
use databend_common_meta_kvapi::kvapi::KvApiExt;
39+
use databend_common_meta_types::MetaError;
40+
use fastrace::func_name;
41+
use log::info;
42+
43+
use crate::kv_pb_api::KVPbApi;
44+
use crate::AutoIncrementApi;
45+
use crate::DatabaseApi;
46+
use crate::DatamaskApi;
47+
use crate::GarbageCollectionApi;
48+
use crate::RowAccessPolicyApi;
49+
use crate::SchemaApi;
50+
use crate::TableApi;
51+
52+
/// Test suite of `AutoIncrementApi`.
53+
///
54+
/// It is not used by this crate, but is used by other crate that impl `AutoIncrementApi`,
55+
/// to ensure an impl works as expected,
56+
/// such as `meta/embedded` and `metasrv`.
57+
#[derive(Copy, Clone)]
58+
pub struct AutoIncrementApiTestSuite {}
59+
60+
impl AutoIncrementApiTestSuite {
61+
/// Test AutoIncrementApi on a single node
62+
pub async fn test_single_node<B, MT>(b: B) -> anyhow::Result<()>
63+
where
64+
B: kvapi::ApiBuilder<MT>,
65+
MT: kvapi::KVApi<Error = MetaError>
66+
+ SchemaApi
67+
+ DatamaskApi
68+
+ AutoIncrementApi
69+
+ RowAccessPolicyApi
70+
+ 'static,
71+
{
72+
let suite = AutoIncrementApiTestSuite {};
73+
suite.table_commit_table_meta(&b.build().await).await?;
74+
Ok(())
75+
}
76+
77+
#[fastrace::trace]
78+
async fn table_commit_table_meta<MT: AutoIncrementApi + kvapi::KVApi<Error = MetaError>>(
79+
&self,
80+
mt: &MT,
81+
) -> anyhow::Result<()> {
82+
let tenant_name = "table_commit_table_meta_tenant";
83+
let db_name = "db1";
84+
let tbl_name = "tb2";
85+
86+
info!("--- prepare db");
87+
let mut util = Util::new(mt, tenant_name, db_name, "");
88+
util.create_db().await?;
89+
90+
let schema = || {
91+
Arc::new(TableSchema::new(vec![TableField::new(
92+
"number",
93+
TableDataType::Number(NumberDataType::UInt64),
94+
)
95+
.with_auto_increment_expr(Some(AutoIncrementExpr {
96+
column_id: 0,
97+
start: 0,
98+
step: 1,
99+
is_ordered: true,
100+
}))]))
101+
};
102+
let options = || maplit::btreemap! {"opt‐1".into() => "val-1".into()};
103+
104+
let drop_table_meta = |created_on| TableMeta {
105+
schema: schema(),
106+
engine: "JSON".to_string(),
107+
options: options(),
108+
created_on,
109+
drop_on: Some(created_on),
110+
..TableMeta::default()
111+
};
112+
let created_on = Utc::now();
113+
114+
// verify the auto increment will be vacuum
115+
{
116+
// use a new tenant and db do test
117+
let db_name = "orphan_db";
118+
let tenant_name = "orphan_tenant";
119+
let mut orphan_util = Util::new(mt, tenant_name, db_name, "");
120+
orphan_util.create_db().await?;
121+
let tenant = orphan_util.tenant();
122+
123+
let create_table_req = CreateTableReq {
124+
create_option: CreateOption::CreateOrReplace,
125+
catalog_name: Some("default".to_string()),
126+
name_ident: TableNameIdent {
127+
tenant: Tenant::new_or_err(tenant_name, func_name!())?,
128+
db_name: db_name.to_string(),
129+
table_name: tbl_name.to_string(),
130+
},
131+
table_meta: drop_table_meta(created_on),
132+
as_dropped: true,
133+
table_properties: None,
134+
table_partition: None,
135+
};
136+
137+
let create_table_as_dropped_resp = mt.create_table(create_table_req.clone()).await?;
138+
139+
let auto_increment_key =
140+
AutoIncrementKey::new(create_table_as_dropped_resp.table_id, 0);
141+
let auto_increment_sequence_storage =
142+
AutoIncrementStorageIdent::new_generic(&tenant, auto_increment_key.clone());
143+
144+
// assert auto increment exists
145+
let seqv = mt
146+
.get_kv(&auto_increment_sequence_storage.to_string_key())
147+
.await?;
148+
assert!(seqv.is_some() && seqv.unwrap().seq != 0);
149+
150+
// auto increment next val
151+
let expr = AutoIncrementExpr {
152+
column_id: 0,
153+
start: 0,
154+
step: 1,
155+
is_ordered: true,
156+
};
157+
let next_val_req = GetAutoIncrementNextValueReq {
158+
tenant: tenant.clone(),
159+
expr,
160+
key: auto_increment_key,
161+
count: 1,
162+
};
163+
mt.get_auto_increment_next_value(next_val_req)
164+
.await?
165+
.unwrap();
166+
167+
// assert auto increment current is 1 after next val
168+
let seqv = mt.get_pb(&auto_increment_sequence_storage).await?;
169+
assert!(seqv.as_ref().unwrap().seq != 0);
170+
assert_eq!(seqv.as_ref().unwrap().data.inner().0, 1);
171+
172+
// assert auto increment exists
173+
let seqv = mt
174+
.get_kv(&auto_increment_sequence_storage.to_string_key())
175+
.await?;
176+
assert!(seqv.is_some() && seqv.unwrap().seq != 0);
177+
178+
// vacuum drop table
179+
let req = ListDroppedTableReq::new(&tenant);
180+
let resp = mt.get_drop_table_infos(req).await?;
181+
assert!(!resp.drop_ids.is_empty());
182+
183+
let req = GcDroppedTableReq {
184+
tenant: Tenant::new_or_err(tenant_name, func_name!())?,
185+
catalog: "default".to_string(),
186+
drop_ids: resp.drop_ids.clone(),
187+
};
188+
mt.gc_drop_tables(req).await?;
189+
190+
// assert auto increment has been vacuum
191+
let seqv = mt
192+
.get_kv(&auto_increment_sequence_storage.to_string_key())
193+
.await?;
194+
assert!(seqv.is_none());
195+
}
196+
197+
Ok(())
198+
}
199+
}
200+
201+
struct Util<'a, MT>
202+
// where MT: AutoIncrementApi
203+
where MT: kvapi::KVApi<Error = MetaError> + AutoIncrementApi
204+
{
205+
tenant: Tenant,
206+
db_name: String,
207+
engine: String,
208+
db_id: u64,
209+
mt: &'a MT,
210+
}
211+
212+
impl<'a, MT> Util<'a, MT>
213+
where MT: AutoIncrementApi + kvapi::KVApi<Error = MetaError>
214+
{
215+
fn new(
216+
mt: &'a MT,
217+
tenant: impl ToString,
218+
db_name: impl ToString,
219+
engine: impl ToString,
220+
) -> Self {
221+
Self {
222+
tenant: Tenant::new_or_err(tenant, func_name!()).unwrap(),
223+
db_name: db_name.to_string(),
224+
engine: engine.to_string(),
225+
db_id: 0,
226+
mt,
227+
}
228+
}
229+
230+
fn tenant(&self) -> Tenant {
231+
self.tenant.clone()
232+
}
233+
234+
fn engine(&self) -> String {
235+
self.engine.clone()
236+
}
237+
238+
fn db_name(&self) -> String {
239+
self.db_name.clone()
240+
}
241+
242+
async fn create_db(&mut self) -> anyhow::Result<()> {
243+
let plan = CreateDatabaseReq {
244+
create_option: CreateOption::Create,
245+
catalog_name: None,
246+
name_ident: DatabaseNameIdent::new(self.tenant(), self.db_name()),
247+
meta: DatabaseMeta {
248+
engine: self.engine(),
249+
..DatabaseMeta::default()
250+
},
251+
};
252+
253+
let res = self.mt.create_database(plan).await?;
254+
self.db_id = *res.db_id;
255+
256+
Ok(())
257+
}
258+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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::schema::GetAutoIncrementNextValueReply;
16+
use databend_common_meta_app::schema::GetAutoIncrementNextValueReq;
17+
use databend_common_meta_kvapi::kvapi;
18+
use databend_common_meta_types::MetaError;
19+
use fastrace::func_name;
20+
use log::debug;
21+
22+
use crate::auto_increment_api::AutoIncrementApi;
23+
use crate::auto_increment_nextval_impl::NextVal;
24+
use crate::errors::AutoIncrementError;
25+
use crate::meta_txn_error::MetaTxnError;
26+
27+
#[async_trait::async_trait]
28+
#[tonic::async_trait]
29+
impl<KV: kvapi::KVApi<Error = MetaError> + ?Sized> AutoIncrementApi for KV {
30+
async fn get_auto_increment_next_value(
31+
&self,
32+
req: GetAutoIncrementNextValueReq,
33+
) -> Result<Result<GetAutoIncrementNextValueReply, AutoIncrementError>, MetaTxnError> {
34+
debug!(req :? =(&req); "AutoIncrementApi: {}", func_name!());
35+
36+
let next_val = NextVal {
37+
kv_api: self,
38+
key: req.key.clone(),
39+
expr: req.expr.clone(),
40+
};
41+
42+
let (start, end) = match next_val.next_val(&req.tenant, req.count).await? {
43+
Ok(resp) => (resp.before, resp.after),
44+
Err(err) => {
45+
return Ok(Err(err));
46+
}
47+
};
48+
49+
Ok(Ok(GetAutoIncrementNextValueReply {
50+
start,
51+
step: req.expr.step,
52+
end,
53+
}))
54+
}
55+
}

0 commit comments

Comments
 (0)