Skip to content

Commit 71e5d63

Browse files
committed
Reduce runtime allocation churn
1 parent d7a9f90 commit 71e5d63

26 files changed

Lines changed: 285 additions & 213 deletions

Makefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ PYO3_PYTHON ?= /usr/bin/python3.12
66
TPCC_MEASURE_TIME ?= 15
77
TPCC_NUM_WARE ?= 1
88
TPCC_PPROF_OUTPUT ?= /tmp/tpcc_lmdb.svg
9+
TPCC_HEAPTRACK_MEASURE_TIME ?= 300
10+
TPCC_HEAPTRACK_OUTPUT ?= /tmp/tpcc_lmdb_heaptrack
911
TPCC_SQLITE_PROFILE ?= balanced
1012

11-
.PHONY: test test-python test-wasm test-slt test-all wasm-build check tpcc tpcc-kitesql-rocksdb tpcc-kitesql-lmdb tpcc-lmdb-flamegraph tpcc-sqlite tpcc-sqlite-practical tpcc-sqlite-balanced tpcc-dual cargo-check build wasm-examples native-examples fmt clippy
13+
.PHONY: test test-python test-wasm test-slt test-all wasm-build check tpcc tpcc-kitesql-rocksdb tpcc-kitesql-lmdb tpcc-lmdb-flamegraph tpcc-lmdb-heaptrack tpcc-sqlite tpcc-sqlite-practical tpcc-sqlite-balanced tpcc-dual cargo-check build wasm-examples native-examples fmt clippy
1214

1315
## Run default Rust tests in the current environment (non-WASM).
1416
test:
@@ -66,6 +68,16 @@ tpcc-kitesql-lmdb:
6668
tpcc-lmdb-flamegraph:
6769
CARGO_PROFILE_RELEASE_DEBUG=true $(CARGO) run -p tpcc --release --features pprof -- --backend kitesql-lmdb --measure-time $(TPCC_MEASURE_TIME) --num-ware $(TPCC_NUM_WARE) --pprof-output $(TPCC_PPROF_OUTPUT)
6870

71+
## Execute TPCC on LMDB under heaptrack and emit a heap profile.
72+
tpcc-lmdb-heaptrack:
73+
@command -v heaptrack >/dev/null || { echo "heaptrack is not installed"; exit 1; }
74+
$(CARGO) build -p tpcc --release
75+
@mkdir -p $(dir $(TPCC_HEAPTRACK_OUTPUT))
76+
heaptrack -o $(TPCC_HEAPTRACK_OUTPUT) ./target/release/tpcc --backend kitesql-lmdb --measure-time $(TPCC_HEAPTRACK_MEASURE_TIME) --num-ware $(TPCC_NUM_WARE)
77+
@echo "heaptrack output:"
78+
@ls -1 $(TPCC_HEAPTRACK_OUTPUT)*
79+
@echo "open gui: heaptrack_gui $$(ls -1 $(TPCC_HEAPTRACK_OUTPUT)* | tail -n 1)"
80+
6981
## Execute the TPCC workload on SQLite with the practical profile.
7082
tpcc-sqlite:
7183
$(CARGO) run -p tpcc --release -- --backend sqlite --sqlite-profile $(TPCC_SQLITE_PROFILE) --path kite_sql_tpcc.sqlite

src/binder/alter_table.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use sqlparser::ast::{AlterColumnOperation, AlterTableOperation, ColumnOption, Ob
1717
use std::borrow::Cow;
1818

1919
use super::{attach_span_if_absent, is_valid_identifier, Binder};
20-
use crate::binder::lower_case_name;
20+
use crate::binder::{lower_case_name, lower_ident};
2121
use crate::catalog::TableName;
2222
use crate::errors::DatabaseError;
2323
use crate::expression::ScalarExpression;
@@ -137,11 +137,11 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
137137
old_column_name,
138138
new_column_name,
139139
} => {
140-
let old_column_name = old_column_name.value.to_lowercase();
141-
let new_column_name = new_column_name.value.to_lowercase();
140+
let old_column_name = lower_ident(old_column_name);
141+
let new_column_name = lower_ident(new_column_name).into_owned();
142142
let old_column = table
143-
.get_column_by_name(&old_column_name)
144-
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.clone()))?;
143+
.get_column_by_name(old_column_name.as_ref())
144+
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.to_string()))?;
145145

146146
if !is_valid_identifier(&new_column_name) {
147147
return Err(DatabaseError::invalid_column(
@@ -152,7 +152,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
152152
LogicalPlan::new(
153153
Operator::ChangeColumn(ChangeColumnOperator {
154154
table_name,
155-
old_column_name,
155+
old_column_name: old_column_name.into_owned(),
156156
new_column_name,
157157
data_type: old_column.datatype().clone(),
158158
default_change: DefaultChange::NoChange,
@@ -162,10 +162,10 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
162162
)
163163
}
164164
AlterTableOperation::AlterColumn { column_name, op } => {
165-
let old_column_name = column_name.value.to_lowercase();
165+
let old_column_name = lower_ident(column_name);
166166
let old_column = table
167-
.get_column_by_name(&old_column_name)
168-
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.clone()))?;
167+
.get_column_by_name(old_column_name.as_ref())
168+
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.to_string()))?;
169169
let old_data_type = old_column.datatype().clone();
170170

171171
let (data_type, default_change, not_null_change) = match op {
@@ -213,8 +213,8 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
213213
LogicalPlan::new(
214214
Operator::ChangeColumn(ChangeColumnOperator {
215215
table_name,
216-
new_column_name: old_column_name.clone(),
217-
old_column_name,
216+
new_column_name: old_column_name.to_string(),
217+
old_column_name: old_column_name.into_owned(),
218218
data_type,
219219
default_change,
220220
not_null_change,
@@ -233,10 +233,11 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
233233
"MODIFY COLUMN does not currently support column positions".to_string(),
234234
));
235235
}
236-
let old_column_name = col_name.value.to_lowercase();
236+
let old_column_name = lower_ident(col_name);
237237
let _ = table
238-
.get_column_by_name(&old_column_name)
239-
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.clone()))?;
238+
.get_column_by_name(old_column_name.as_ref())
239+
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.to_string()))?;
240+
let old_column_name = old_column_name.into_owned();
240241
let data_type = LogicalType::try_from(data_type.clone())?;
241242
let (default_change, not_null_change) =
242243
self.bind_change_column_options(options, &data_type)?;
@@ -265,11 +266,11 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
265266
"CHANGE COLUMN does not currently support column positions".to_string(),
266267
));
267268
}
268-
let old_column_name = old_name.value.to_lowercase();
269-
let new_column_name = new_name.value.to_lowercase();
269+
let old_column_name = lower_ident(old_name);
270+
let new_column_name = lower_ident(new_name).into_owned();
270271
let _ = table
271-
.get_column_by_name(&old_column_name)
272-
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.clone()))?;
272+
.get_column_by_name(old_column_name.as_ref())
273+
.ok_or_else(|| DatabaseError::column_not_found(old_column_name.to_string()))?;
273274

274275
if !is_valid_identifier(&new_column_name) {
275276
return Err(DatabaseError::invalid_column(
@@ -283,7 +284,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
283284
LogicalPlan::new(
284285
Operator::ChangeColumn(ChangeColumnOperator {
285286
table_name,
286-
old_column_name,
287+
old_column_name: old_column_name.into_owned(),
287288
new_column_name,
288289
data_type,
289290
default_change,

src/binder/create_index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
7777
Operator::CreateIndex(CreateIndexOperator {
7878
table_name,
7979
columns,
80-
index_name,
80+
index_name: index_name.into_owned(),
8181
if_not_exists,
8282
ty,
8383
}),

src/binder/create_table.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
use super::{attach_span_if_absent, is_valid_identifier, Binder};
16-
use crate::binder::lower_case_name;
16+
use crate::binder::{lower_case_name, lower_ident};
1717
use crate::catalog::{ColumnCatalog, ColumnDesc, TableName};
1818
use crate::errors::DatabaseError;
1919
use crate::expression::ScalarExpression;
@@ -116,11 +116,11 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
116116
"only identifier columns are supported in `PRIMARY KEY/UNIQUE`".to_string(),
117117
));
118118
};
119-
let column_name = ident.value.to_lowercase();
119+
let column_name = lower_ident(ident);
120120

121121
if let Some(column) = table_columns
122122
.iter_mut()
123-
.find(|column| column.name() == column_name)
123+
.find(|column| column.name() == column_name.as_ref())
124124
{
125125
fn_constraint(i, column.desc_mut())
126126
}
@@ -133,7 +133,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
133133
column_def: &ColumnDef,
134134
column_index: Option<usize>,
135135
) -> Result<ColumnCatalog, DatabaseError> {
136-
let column_name = column_def.name.value.to_lowercase();
136+
let column_name = lower_ident(&column_def.name).into_owned();
137137
let mut column_desc = ColumnDesc::new(
138138
LogicalType::try_from(column_def.data_type.clone())?,
139139
None,

src/binder/create_view.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
7878
projection_exprs(
7979
&view_name,
8080
mapping_schema,
81-
columns.iter().map(|column| lower_ident(&column.name)),
81+
columns
82+
.iter()
83+
.map(|column| lower_ident(&column.name).into_owned()),
8284
)
8385
};
8486
plan = self.bind_project(plan, exprs)?;

src/binder/drop_index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
3838
Ok(LogicalPlan::new(
3939
Operator::DropIndex(DropIndexOperator {
4040
table_name,
41-
index_name,
41+
index_name: index_name.into_owned(),
4242
if_exists: *if_exists,
4343
}),
4444
Childrens::None,

src/binder/expr.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,9 @@ use crate::types::tuple::SchemaRef;
4141
use crate::types::value::{DataValue, Utf8Type};
4242
use crate::types::{CharLengthUnits, ColumnId, LogicalType};
4343

44-
macro_rules! try_alias {
45-
($context:expr, $full_name:expr) => {
46-
if let Some(expr) = $context.expr_aliases.get(&$full_name) {
47-
return Ok(ScalarExpression::Alias {
48-
expr: Box::new(expr.clone()),
49-
alias: AliasType::Name($full_name.1),
50-
});
51-
}
52-
};
53-
}
54-
5544
macro_rules! try_default {
5645
($table_name:expr, $column_name:expr) => {
57-
if let (None, "default") = ($table_name, $column_name.as_str()) {
46+
if let (None, "default") = ($table_name, $column_name.as_ref()) {
5847
return Ok(ScalarExpression::Empty);
5948
}
6049
};
@@ -559,7 +548,7 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
559548
pub fn bind_column_ref_from_identifiers(
560549
&mut self,
561550
idents: &[Ident],
562-
bind_table_name: Option<String>,
551+
bind_table_name: Option<&str>,
563552
) -> Result<ScalarExpression, DatabaseError> {
564553
let full_name = match idents {
565554
[column] => (None, lower_ident(column)),
@@ -578,12 +567,22 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
578567
}
579568
};
580569
if full_name.0.is_none() {
581-
try_alias!(self.context, full_name);
570+
if let Some((_, expr)) = self
571+
.context
572+
.expr_aliases
573+
.iter()
574+
.find(|((table, column), _)| table.is_none() && column == full_name.1.as_ref())
575+
{
576+
return Ok(ScalarExpression::Alias {
577+
expr: Box::new(expr.clone()),
578+
alias: AliasType::Name(full_name.1.into_owned()),
579+
});
580+
}
582581
}
583582
if self.context.allow_default {
584583
try_default!(&full_name.0, full_name.1);
585584
}
586-
if let Some(table) = full_name.0.or(bind_table_name) {
585+
if let Some(table) = full_name.0.as_deref().or(bind_table_name) {
587586
let (schema_ref, position_offset) = match Self::resolve_source_columns_in_scope(
588587
&self.context,
589588
&mut self.table_schema_buf,
@@ -614,8 +613,8 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
614613
}
615614
}
616615
};
617-
let (position, column) = Self::find_column_in_schema(&schema_ref, full_name.1.as_str())
618-
.ok_or_else(|| Self::column_not_found_with_span(idents, full_name.1.as_str()))?;
616+
let (position, column) = Self::find_column_in_schema(&schema_ref, full_name.1.as_ref())
617+
.ok_or_else(|| Self::column_not_found_with_span(idents, full_name.1.as_ref()))?;
619618

620619
Ok(ScalarExpression::column_expr(
621620
column.clone(),
@@ -627,14 +626,14 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
627626
|context: &BinderContext<'a, T>| -> Result<Option<ScalarExpression>, DatabaseError> {
628627
Ok(context
629628
.using
630-
.get(full_name.1.as_str())
629+
.get(full_name.1.as_ref())
631630
.map(|using_column| using_column.visible_expr())
632631
.transpose()?
633632
.or_else(|| {
634633
Self::find_column_in_scope(
635634
context,
636635
&mut self.table_schema_buf,
637-
full_name.1.as_str(),
636+
full_name.1.as_ref(),
638637
)
639638
}))
640639
};
@@ -649,7 +648,7 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
649648
Some(column) => Ok(column),
650649
None => Err(Self::column_not_found_with_span(
651650
idents,
652-
full_name.1.as_str(),
651+
full_name.1.as_ref(),
653652
)),
654653
}
655654
}

src/binder/insert.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
6969
for ident in idents {
7070
match self.bind_column_ref_from_identifiers(
7171
slice::from_ref(ident),
72-
Some(table_name.to_string()),
72+
Some(table_name.as_ref()),
7373
)? {
7474
ScalarExpression::ColumnRef { column, .. } => columns.push(column),
7575
_ => return Err(DatabaseError::UnsupportedStmt(ident.to_string())),

src/binder/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use sqlparser::ast::{
3939
Statement, TableObject,
4040
};
4141
use sqlparser::tokenizer::Span;
42+
use std::borrow::Cow;
4243
use std::collections::{BTreeMap, HashMap};
4344
use std::sync::atomic::{AtomicUsize, Ordering};
4445
use std::sync::Arc;
@@ -783,18 +784,24 @@ impl<'a, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '
783784
}
784785
}
785786

786-
fn lower_ident(ident: &Ident) -> String {
787-
ident.value.to_lowercase()
787+
fn lower_ident(ident: &Ident) -> Cow<'_, str> {
788+
let value = &ident.value;
789+
790+
if value.chars().any(char::is_uppercase) {
791+
Cow::Owned(value.to_lowercase())
792+
} else {
793+
Cow::Borrowed(value)
794+
}
788795
}
789796

790-
fn lower_name_part(part: &ObjectNamePart) -> Result<String, DatabaseError> {
797+
fn lower_name_part(part: &ObjectNamePart) -> Result<Cow<'_, str>, DatabaseError> {
791798
part.as_ident()
792799
.map(lower_ident)
793800
.ok_or_else(|| attach_span_if_absent(DatabaseError::invalid_table(part.to_string()), part))
794801
}
795802

796803
/// Convert an object name into lower case
797-
fn lower_case_name(name: &ObjectName) -> Result<String, DatabaseError> {
804+
fn lower_case_name(name: &ObjectName) -> Result<Cow<'_, str>, DatabaseError> {
798805
if name.0.len() == 1 {
799806
return lower_name_part(&name.0[0]);
800807
}

src/binder/select.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
856856
}) = alias
857857
{
858858
let source_name = self.context.temp_table();
859-
let table_alias: TableName = name.value.to_lowercase().into();
859+
let table_alias: TableName = lower_ident(name).into();
860860

861861
plan = self.bind_alias(
862862
plan,
@@ -911,7 +911,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
911911
..
912912
}) = alias
913913
{
914-
table_alias = Some(name.value.to_lowercase().into());
914+
table_alias = Some(lower_ident(name).into());
915915

916916
plan = self.bind_alias(
917917
plan,
@@ -955,7 +955,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
955955
} else {
956956
alias_column
957957
.iter()
958-
.map(|column| lower_ident(&column.name))
958+
.map(|column| lower_ident(&column.name).into_owned())
959959
.zip(input_schema.iter().cloned())
960960
.collect_vec()
961961
};
@@ -1027,7 +1027,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
10271027
let mut alias_idents = None;
10281028

10291029
if let Some(TableAlias { name, columns, .. }) = alias {
1030-
table_alias = Some(name.value.to_lowercase().into());
1030+
table_alias = Some(lower_ident(name).into());
10311031
alias_idents = Some(columns);
10321032
}
10331033

@@ -1075,7 +1075,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
10751075
SelectItem::UnnamedExpr(expr) => select_items.push(self.bind_expr(expr)?),
10761076
SelectItem::ExprWithAlias { expr, alias } => {
10771077
let expr = self.bind_expr(expr)?;
1078-
let alias_name = alias.value.to_lowercase();
1078+
let alias_name = lower_ident(alias).into_owned();
10791079

10801080
self.context
10811081
.add_alias(None, alias_name.clone(), expr.clone());
@@ -1909,7 +1909,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'
19091909
));
19101910
};
19111911
self.context.add_using(
1912-
name.clone(),
1912+
name.clone().into_owned(),
19131913
join_type,
19141914
left_column,
19151915
left_position,

0 commit comments

Comments
 (0)