Skip to content

Commit b6a546e

Browse files
Add pre-optimization for multi-versioning
This commit introduces a new pre-optimization step aimed at multi-versioning support. It inserts an internal filter into the `QueryGraph`. The newly added filter checks whether the `start_time` of the `Transaction` within the `QueryGraph` falls within the timestamp range defined by the internal attributes `$ts_begin` and `$ts_end`. With this inclusion, the implementation of append-only multi-versioning in mutable is complete.
1 parent 828be60 commit b6a546e

File tree

6 files changed

+160
-9
lines changed

6 files changed

+160
-9
lines changed

include/mutable/IR/Optimizer.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,23 @@ struct M_EXPORT Optimizer
3434
auto & cost_function() const { return cf_; }
3535

3636
/** Apply this optimizer to the given query graph to compute an operator tree. */
37-
std::unique_ptr<Producer> operator()(const QueryGraph &G) const { return optimize(G).first; }
37+
std::unique_ptr<Producer> operator()(QueryGraph &G) const { return optimize(G).first; }
3838

3939
/** Computes and constructs an optimal plan for the given query graph. Delegates to `optimize_recursive()`, then
4040
* assigns IDs to the optimal plan in post-order. */
4141
std::pair<std::unique_ptr<Producer>, PlanTableEntry>
42-
optimize(const QueryGraph &G) const;
42+
optimize(QueryGraph &G) const;
4343

4444
/** Recursively computes and constructs an optimal plan for the given query graph. Selects a `PlanTable*` type to
4545
* represent the internal state of planning progress, then delegates to `optimize_with_plantable<>()`. */
4646
std::pair<std::unique_ptr<Producer>, PlanTableEntry>
47-
optimize_recursive(const QueryGraph &G) const;
47+
optimize_recursive(QueryGraph &G) const;
4848

4949
/** Recursively computes and constructs an optimal plan for the given query graph, using the given `PlanTable` type
5050
* to represent the state of planning progress. */
5151
template<typename PlanTable>
5252
std::pair<std::unique_ptr<Producer>, PlanTable>
53-
optimize_with_plantable(const QueryGraph &G) const;
53+
optimize_with_plantable(QueryGraph &G) const;
5454

5555
private:
5656
/** Optimizes a plan table after initialization of the data source entries. */

include/mutable/IR/QueryGraph.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ struct M_EXPORT QueryGraph
190190
mutable std::unique_ptr<AdjacencyMatrix> adjacency_matrix_;
191191

192192
Scheduler::Transaction *t_ = nullptr; ///< the transaction this query graph belongs to
193+
///> Stores the expressions of custom filters that have been added to the `DataSource`s after semantic analysis.
194+
std::vector<std::unique_ptr<ast::Expr>> custom_filter_exprs_;
193195

194196
public:
195197
friend void swap(QueryGraph &first, QueryGraph &second) {
@@ -296,6 +298,18 @@ struct M_EXPORT QueryGraph
296298
/** Returns the transaction ID. */
297299
Scheduler::Transaction * transaction() const { return t_; }
298300

301+
/** Creates a `cnf::CNF` from `filter_expr` and adds it to the current filter of the given `DataSource` `ds` by logical conjunction. */
302+
void add_custom_filter(std::unique_ptr<ast::Expr> filter_expr, DataSource &ds) {
303+
M_insist(std::find_if(sources_.begin(), sources_.end(), [&](std::unique_ptr<DataSource> &source){
304+
return *source == ds;
305+
}) != sources_.end());
306+
307+
auto filter = cnf::to_CNF(*filter_expr);
308+
ds.update_filter(filter);
309+
custom_filter_exprs_.push_back(std::move(filter_expr));
310+
}
311+
312+
299313
void dump(std::ostream &out) const;
300314
void dump() const;
301315

include/mutable/catalog/Catalog.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ struct M_EXPORT Catalog
327327
using TableFactoryDecoratorCallback = std::function<std::unique_ptr<TableFactory>(std::unique_ptr<TableFactory>)>;
328328
ComponentSet<TableFactoryDecoratorCallback> table_properties_; // stores callback functions that decorate a table with the given decorator
329329

330-
using PreOptimizationCallback = std::function<void(const QueryGraph &)>;
330+
using PreOptimizationCallback = std::function<void(QueryGraph &)>;
331331
ComponentSet<PreOptimizationCallback> pre_optimizations_;
332332

333333
using PostOptimizationCallback = std::function<std::unique_ptr<Producer>(std::unique_ptr<Producer>)>;

include/mutable/parse/AST.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ struct M_EXPORT Expr
5656

5757
/** Returns the `Type` of this `Expr`. Assumes that the `Expr` has been assigned a `Type` by the `Sema`. */
5858
const Type * type() const { return M_notnull(type_); }
59+
/** Sets the `Type` of this `Expr`. Should be used when constructing an `Expr` outside of the `Sema`.
60+
* Should not be called to replace an already assigned type. */
61+
void type(const Type *type) { M_insist(not type_); type_ = type; }
5962
/** Returns true iff this `Expr` has been assigned a `Type`, most likely by `Sema`. */
6063
bool has_type() const { return type_ != nullptr; }
6164

src/IR/Optimizer.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ std::vector<cnf::CNF> optimize_filter(cnf::CNF filter)
114114
*====================================================================================================================*/
115115

116116
std::pair<std::unique_ptr<Producer>, PlanTableEntry>
117-
Optimizer::optimize(const QueryGraph &G) const
117+
Optimizer::optimize(QueryGraph &G) const
118118
{
119119
return optimize_recursive(G);
120120
}
121121

122122
std::pair<std::unique_ptr<Producer>, PlanTableEntry>
123-
Optimizer::optimize_recursive(const QueryGraph &G) const
123+
Optimizer::optimize_recursive(QueryGraph &G) const
124124
{
125125
switch (Options::Get().plan_table_type)
126126
{
@@ -151,7 +151,7 @@ Optimizer::optimize_recursive(const QueryGraph &G) const
151151

152152
template<typename PlanTable>
153153
std::pair<std::unique_ptr<Producer>, PlanTable>
154-
Optimizer::optimize_with_plantable(const QueryGraph &G) const
154+
Optimizer::optimize_with_plantable(QueryGraph &G) const
155155
{
156156
PlanTable plan_table(G);
157157
const auto num_sources = G.sources().size();
@@ -498,7 +498,7 @@ Optimizer::compute_projections_required_for_order_by(const std::vector<projectio
498498
#define DEFINE(PLANTABLE) \
499499
template \
500500
std::pair<std::unique_ptr<Producer>, PLANTABLE> \
501-
Optimizer::optimize_with_plantable(const QueryGraph &G) const; \
501+
Optimizer::optimize_with_plantable(QueryGraph &G) const; \
502502
template \
503503
void \
504504
Optimizer::optimize_locally(const QueryGraph &G, PLANTABLE &plan_table) const; \

src/catalog/Schema.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include <mutable/catalog/CostFunctionCout.hpp>
1111
#include <mutable/IR/Operator.hpp>
1212
#include <mutable/IR/PlanTable.hpp>
13+
#include <mutable/lex/Token.hpp>
1314
#include <mutable/Options.hpp>
15+
#include <mutable/parse/AST.hpp>
1416
#include <mutable/util/enum_ops.hpp>
1517
#include <mutable/util/fn.hpp>
1618
#include <stdexcept>
@@ -126,6 +128,7 @@ MultiVersioningTable::MultiVersioningTable(std::unique_ptr<Table> table)
126128
(*table_)[ts_begin].is_hidden = true;
127129
(*table_)[ts_begin].not_nullable = true;
128130
(*table_)[ts_end].is_hidden = true;
131+
(*table_)[ts_end].not_nullable = true;
129132
}
130133

131134
M_LCOV_EXCL_START
@@ -139,6 +142,137 @@ void MultiVersioningTable::dump() const { dump(std::cerr); }
139142
M_LCOV_EXCL_STOP
140143

141144

145+
namespace {
146+
147+
148+
void apply_timestamp_filter(QueryGraph &G)
149+
{
150+
Catalog &C = Catalog::Get();
151+
152+
auto pos = Position(nullptr);
153+
ast::Token ts_begin(pos, C.pool("$ts_begin"), TK_IDENTIFIER);
154+
ast::Token ts_end(pos, C.pool("$ts_end"), TK_IDENTIFIER);
155+
156+
for (auto &ds : G.sources()) {
157+
if (auto bt = cast<const BaseTable>(ds.get())) {
158+
/* Set timestamp filter */
159+
auto it = std::find_if(bt->table().cbegin_hidden(),
160+
bt->table().end_hidden(),
161+
[&](const Attribute & attr) {
162+
return attr.name == C.pool("$ts_begin");
163+
});
164+
165+
if (it != bt->table().end_hidden()) {
166+
ast::Token table_name(pos, bt->table().name(), TK_EOF);
167+
/*----- Build AST -----*/
168+
// $ts_begin
169+
std::unique_ptr<ast::Expr> ts_begin_designator = std::make_unique<ast::Designator>(
170+
ts_begin,
171+
table_name,
172+
ts_begin,
173+
Type::Get_Integer(Type::TY_Vector, 8),
174+
&*it
175+
);
176+
177+
// TST := transaction start time constant
178+
std::unique_ptr<ast::Expr> ts_begin_transaction_constant = std::make_unique<ast::Constant>(ast::Token(
179+
pos,
180+
C.pool(std::to_string(G.transaction()->start_time()).c_str()),
181+
m::TK_DEC_INT
182+
));
183+
ts_begin_transaction_constant->type(Type::Get_Integer(Type::TY_Vector, 8));
184+
185+
// $ts_begin <= TST
186+
std::unique_ptr<ast::Expr> ts_begin_filter_clause = std::make_unique<ast::BinaryExpr>(
187+
ast::Token(pos, C.pool("<="), TK_LESS_EQUAL),
188+
std::move(ts_begin_designator),
189+
std::move(ts_begin_transaction_constant)
190+
);
191+
ts_begin_filter_clause->type(Type::Get_Boolean(Type::TY_Vector));
192+
193+
// $ts_end
194+
std::unique_ptr<ast::Expr> ts_end_designator = std::make_unique<ast::Designator>(
195+
ts_end,
196+
table_name,
197+
ts_end,
198+
Type::Get_Integer(Type::TY_Vector, 8),
199+
&bt->table()[C.pool("$ts_end")]
200+
);
201+
202+
// TST := transaction start time constant
203+
std::unique_ptr<ast::Expr> ts_end_transaction_constant = std::make_unique<ast::Constant>(ast::Token(
204+
pos,
205+
C.pool(std::to_string(G.transaction()->start_time()).c_str()),
206+
m::TK_DEC_INT
207+
));
208+
ts_end_transaction_constant->type(Type::Get_Integer(Type::TY_Vector, 8));
209+
210+
// $ts_end > TST
211+
std::unique_ptr<ast::Expr> ts_end_greater_transaction_expr = std::make_unique<ast::BinaryExpr>(
212+
ast::Token(pos, C.pool(">"), TK_GREATER),
213+
std::move(ts_end_designator),
214+
std::move(ts_end_transaction_constant)
215+
);
216+
ts_end_greater_transaction_expr->type(Type::Get_Boolean(Type::TY_Vector));
217+
218+
// $ts_end
219+
std::unique_ptr<ast::Expr> ts_end_designator_2 = std::make_unique<ast::Designator>(
220+
ts_end,
221+
table_name,
222+
ts_end,
223+
Type::Get_Integer(Type::TY_Vector, 8),
224+
&bt->table()[C.pool("$ts_end")]
225+
);
226+
227+
// 1
228+
std::unique_ptr<ast::Expr> zero_constant = std::make_unique<ast::Constant>(ast::Token(
229+
pos,
230+
C.pool("0"),
231+
m::TK_DEC_INT
232+
));
233+
zero_constant->type(Type::Get_Integer(Type::TY_Vector, 8));
234+
235+
// $ts_end = 0
236+
std::unique_ptr<ast::Expr> ts_end_eq_zero = std::make_unique<ast::BinaryExpr>(
237+
ast::Token(pos, C.pool("="), TK_EQUAL),
238+
std::move(ts_end_designator_2),
239+
std::move(zero_constant)
240+
);
241+
ts_end_eq_zero->type(Type::Get_Boolean(Type::TY_Vector));
242+
243+
// $ts_end > TST OR $ts_end = 0
244+
std::unique_ptr<ast::Expr> ts_end_filter_clause = std::make_unique<ast::BinaryExpr>(
245+
ast::Token(pos, C.pool("OR"), TK_Or),
246+
std::move(ts_end_greater_transaction_expr),
247+
std::move(ts_end_eq_zero)
248+
);
249+
ts_end_filter_clause->type(Type::Get_Boolean(Type::TY_Vector));
250+
251+
// $ts_begin <= TST AND ($ts_end > TST OR $ts_end = 0)
252+
std::unique_ptr<ast::Expr> filter_expr = std::make_unique<ast::BinaryExpr>(
253+
ast::Token(pos, C.pool("AND"), TK_And),
254+
std::move(ts_begin_filter_clause),
255+
std::move(ts_end_filter_clause)
256+
);
257+
filter_expr->type(Type::Get_Boolean(Type::TY_Vector));
258+
259+
G.add_custom_filter(std::move(filter_expr), *ds);
260+
}
261+
}
262+
}
263+
}
264+
265+
__attribute__((constructor(202)))
266+
void register_pre_optimization()
267+
{
268+
Catalog &C = Catalog::Get();
269+
C.register_pre_optimization("multi-versioning", apply_timestamp_filter, "adds timestamp filters to the QueryGraph");
270+
}
271+
272+
273+
}
274+
275+
142276
/*======================================================================================================================
143277
* Function
144278
*====================================================================================================================*/

0 commit comments

Comments
 (0)