Skip to content

Commit ab79c88

Browse files
authored
p4: more comments and more tests (#658)
* p4: more comments and more tests Signed-off-by: Alex Chi <[email protected]> * add nc-shell Signed-off-by: Alex Chi <[email protected]> * add abort/serializable tests Signed-off-by: Alex Chi <[email protected]> * fix shell Signed-off-by: Alex Chi <[email protected]> * fix compile error Signed-off-by: Alex Chi <[email protected]> * update shell Signed-off-by: Alex Chi <[email protected]> * fix comments Signed-off-by: Alex Chi <[email protected]> * fix comments Signed-off-by: Alex Chi <[email protected]> * txn support for bustub shell Signed-off-by: Alex Chi <[email protected]> * support wasm shell Signed-off-by: Alex Chi <[email protected]> * adjust txn Signed-off-by: Alex Chi <[email protected]> --------- Signed-off-by: Alex Chi <[email protected]>
1 parent 9543078 commit ab79c88

File tree

24 files changed

+694
-128
lines changed

24 files changed

+694
-128
lines changed

CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,12 @@ add_custom_target(submit-p3
369369
)
370370

371371
set(P4_FILES
372-
"src/include/concurrency/lock_manager.h"
373-
"src/concurrency/lock_manager.cpp"
374372
"src/include/concurrency/transaction_manager.h"
375373
"src/concurrency/transaction_manager.cpp"
376-
"tools/terrier_bench/terrier_bench_config.h"
374+
"src/include/concurrency/watermark.h"
375+
"src/concurrency/watermark.cpp"
376+
"src/include/execution/execution_common.h"
377+
"src/execution/execution_common.cpp"
377378
${P3_FILES}
378379
)
379380

src/binder/bind_variable.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "binder/expressions/bound_constant.h"
66
#include "binder/statement/set_show_statement.h"
77
#include "common/exception.h"
8+
#include "nodes/parsenodes.hpp"
89
namespace bustub {
910

1011
auto Binder::BindVariableSet(duckdb_libpgquery::PGVariableSetStmt *stmt) -> std::unique_ptr<VariableSetStatement> {
@@ -23,4 +24,17 @@ auto Binder::BindVariableShow(duckdb_libpgquery::PGVariableShowStmt *stmt) -> st
2324
return std::make_unique<VariableShowStatement>(stmt->name);
2425
}
2526

27+
auto Binder::BindTransaction(duckdb_libpgquery::PGTransactionStmt *stmt) -> std::unique_ptr<TransactionStatement> {
28+
switch (stmt->kind) {
29+
case duckdb_libpgquery::PG_TRANS_STMT_COMMIT:
30+
return std::make_unique<TransactionStatement>("commit");
31+
case duckdb_libpgquery::PG_TRANS_STMT_ROLLBACK:
32+
return std::make_unique<TransactionStatement>("abort");
33+
case duckdb_libpgquery::PG_TRANS_STMT_BEGIN:
34+
return std::make_unique<TransactionStatement>("begin");
35+
default:
36+
throw bustub::NotImplementedException("unsupported txn statement kind");
37+
}
38+
}
39+
2640
} // namespace bustub

src/binder/transformer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ auto Binder::BindStatement(duckdb_libpgquery::PGNode *stmt) -> std::unique_ptr<B
7272
return BindVariableSet(reinterpret_cast<duckdb_libpgquery::PGVariableSetStmt *>(stmt));
7373
case duckdb_libpgquery::T_PGVariableShowStmt:
7474
return BindVariableShow(reinterpret_cast<duckdb_libpgquery::PGVariableShowStmt *>(stmt));
75+
case duckdb_libpgquery::T_PGTransactionStmt:
76+
return BindTransaction(reinterpret_cast<duckdb_libpgquery::PGTransactionStmt *>(stmt));
7577
default:
7678
throw NotImplementedException(NodeTagToString(stmt->type));
7779
}

src/common/bustub_ddl.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "common/bustub_instance.h"
2222
#include "common/enums/statement_type.h"
2323
#include "common/exception.h"
24+
#include "common/macros.h"
2425
#include "common/util/string_util.h"
2526
#include "concurrency/lock_manager.h"
2627
#include "concurrency/transaction.h"
@@ -169,4 +170,57 @@ void BustubInstance::HandleVariableSetStatement(Transaction *txn, const Variable
169170
session_variables_[stmt.variable_] = stmt.value_;
170171
}
171172

173+
void BustubInstance::HandleTxnStatement(Transaction *txn, const TransactionStatement &stmt, ResultWriter &writer) {
174+
if (managed_txn_mode_ && current_txn_ != nullptr) {
175+
BUSTUB_ASSERT(current_txn_ == txn, "txn mismatched??");
176+
}
177+
auto dump_current_txn = [&](const std::string &prefix) {
178+
writer.OneCell(fmt::format("{}txn_id={} txn_real_id={} read_ts={} commit_ts={} status={} iso_lvl={}", prefix,
179+
current_txn_->GetTransactionIdHumanReadable(), current_txn_->GetTransactionId(),
180+
current_txn_->GetReadTs(), current_txn_->GetCommitTs(),
181+
current_txn_->GetTransactionState(), current_txn_->GetIsolationLevel()));
182+
};
183+
if (txn == nullptr) {
184+
writer.OneCell("commit / rollback can only be used with txn");
185+
return;
186+
}
187+
if (stmt.type_ == "begin") {
188+
if (!managed_txn_mode_) {
189+
writer.OneCell("begin statement is only supported in managed txn mode, please use bustub-shell");
190+
return;
191+
}
192+
bool txn_activated = current_txn_ != nullptr;
193+
auto iso_lvl = StringUtil::Lower(GetSessionVariable("global_isolation_level"));
194+
if (iso_lvl == "serializable") {
195+
current_txn_ = txn_manager_->Begin(IsolationLevel::SERIALIZABLE);
196+
} else if (iso_lvl == "snapshot_isolation" || iso_lvl.empty()) {
197+
current_txn_ = txn_manager_->Begin(IsolationLevel::SNAPSHOT_ISOLATION);
198+
} else {
199+
throw Exception("unsupported global_isolation_level");
200+
}
201+
dump_current_txn(txn_activated ? "pause current txn and begin new txn " : "begin txn ");
202+
return;
203+
}
204+
if (stmt.type_ == "commit") {
205+
auto res = txn_manager_->Commit(txn);
206+
if (res) {
207+
writer.OneCell(fmt::format("txn committed, txn_id={}, status={}, read_ts={}, commit_ts={}",
208+
txn->GetTransactionIdHumanReadable(), txn->GetTransactionState(), txn->GetReadTs(),
209+
txn->GetCommitTs()));
210+
} else {
211+
writer.OneCell(fmt::format("txn failed to commit, txn_id={}, status={}, read_ts={}, commit_ts={}",
212+
txn->GetTransactionIdHumanReadable(), txn->GetTransactionState(), txn->GetReadTs(),
213+
txn->GetCommitTs()));
214+
}
215+
current_txn_ = nullptr;
216+
return;
217+
}
218+
if (stmt.type_ == "abort") {
219+
txn_manager_->Abort(txn);
220+
writer.OneCell(fmt::format("txn aborted, txn_id={}, status={}, read_ts={}", txn->GetTransactionIdHumanReadable(),
221+
txn->GetTransactionState(), txn->GetReadTs()));
222+
current_txn_ = nullptr;
223+
return;
224+
}
225+
}
172226
} // namespace bustub

src/common/bustub_instance.cpp

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
#include "catalog/schema.h"
1717
#include "catalog/table_generator.h"
1818
#include "common/bustub_instance.h"
19+
#include "common/config.h"
1920
#include "common/exception.h"
2021
#include "common/util/string_util.h"
2122
#include "concurrency/lock_manager.h"
2223
#include "concurrency/transaction.h"
2324
#include "execution/check_options.h"
25+
#include "execution/execution_common.h"
2426
#include "execution/execution_engine.h"
2527
#include "execution/executor_context.h"
2628
#include "execution/executors/mock_scan_executor.h"
@@ -147,6 +149,22 @@ BustubInstance::BustubInstance() {
147149
execution_engine_ = std::make_unique<ExecutionEngine>(buffer_pool_manager_.get(), txn_manager_.get(), catalog_.get());
148150
}
149151

152+
void BustubInstance::CmdDbgMvcc(const std::vector<std::string> &params, ResultWriter &writer) {
153+
if (params.size() != 2) {
154+
writer.OneCell("please provide a table name");
155+
return;
156+
}
157+
const auto &table = params[1];
158+
writer.OneCell("please view the result in the BusTub console (or Chrome DevTools console), table=" + table);
159+
std::shared_lock<std::shared_mutex> lck(catalog_lock_);
160+
auto table_info = catalog_->GetTable(table);
161+
if (table_info == nullptr) {
162+
writer.OneCell("table " + table + " not found");
163+
return;
164+
}
165+
TxnMgrDbg("\\dbgmvcc", txn_manager_.get(), table_info, table_info->table_.get());
166+
}
167+
150168
void BustubInstance::CmdDisplayTables(ResultWriter &writer) {
151169
auto table_names = catalog_->GetTableNames();
152170
writer.BeginTable(false);
@@ -195,7 +213,12 @@ void BustubInstance::CmdDisplayHelp(ResultWriter &writer) {
195213
196214
\dt: show all tables
197215
\di: show all indices
216+
\dbgmvcc <table>: show version chain of a table
198217
\help: show this message again
218+
\txn: show current txn information
219+
\txn <txn_id>: switch to txn
220+
\txn gc: run garbage collection
221+
\txn -1: exit txn mode
199222
200223
BusTub shell currently only supports a small set of Postgres queries. We'll set
201224
up a doc describing the current status later. It will silently ignore some parts
@@ -210,15 +233,20 @@ see the execution plan of your query.
210233

211234
auto BustubInstance::ExecuteSql(const std::string &sql, ResultWriter &writer,
212235
std::shared_ptr<CheckOptions> check_options) -> bool {
213-
auto *txn = txn_manager_->Begin();
236+
bool is_local_txn = current_txn_ != nullptr;
237+
auto *txn = is_local_txn ? current_txn_ : txn_manager_->Begin();
214238
try {
215239
auto result = ExecuteSqlTxn(sql, writer, txn, std::move(check_options));
216-
if (!txn_manager_->Commit(txn)) {
217-
throw Exception("failed to commit txn");
240+
if (!is_local_txn) {
241+
auto res = txn_manager_->Commit(txn);
242+
if (!res) {
243+
throw Exception("failed to commit txn");
244+
}
218245
}
219246
return result;
220247
} catch (bustub::Exception &ex) {
221248
txn_manager_->Abort(txn);
249+
current_txn_ = nullptr;
222250
throw ex;
223251
}
224252
}
@@ -239,6 +267,16 @@ auto BustubInstance::ExecuteSqlTxn(const std::string &sql, ResultWriter &writer,
239267
CmdDisplayHelp(writer);
240268
return true;
241269
}
270+
if (StringUtil::StartsWith(sql, "\\dbgmvcc")) {
271+
auto split = StringUtil::Split(sql, " ");
272+
CmdDbgMvcc(split, writer);
273+
return true;
274+
}
275+
if (StringUtil::StartsWith(sql, "\\txn")) {
276+
auto split = StringUtil::Split(sql, " ");
277+
CmdTxn(split, writer);
278+
return true;
279+
}
242280
throw Exception(fmt::format("unsupported internal command: {}", sql));
243281
}
244282

@@ -280,6 +318,11 @@ auto BustubInstance::ExecuteSqlTxn(const std::string &sql, ResultWriter &writer,
280318
HandleExplainStatement(txn, explain_stmt, writer);
281319
continue;
282320
}
321+
case StatementType::TRANSACTION_STATEMENT: {
322+
const auto &txn_stmt = dynamic_cast<const TransactionStatement &>(*statement);
323+
HandleTxnStatement(txn, txn_stmt, writer);
324+
continue;
325+
}
283326
case StatementType::DELETE_STATEMENT:
284327
case StatementType::UPDATE_STATEMENT:
285328
is_delete = true;
@@ -373,4 +416,57 @@ BustubInstance::~BustubInstance() {
373416
}
374417
}
375418

419+
/** Enable managed txn mode on this BusTub instance, allowing statements like `BEGIN`. */
420+
void BustubInstance::EnableManagedTxn() { managed_txn_mode_ = true; }
421+
422+
/** Get the current transaction. */
423+
auto BustubInstance::CurrentManagedTxn() -> Transaction * { return current_txn_; }
424+
425+
void BustubInstance::CmdTxn(const std::vector<std::string> &params, ResultWriter &writer) {
426+
if (!managed_txn_mode_) {
427+
writer.OneCell("only supported in managed mode, please use bustub-shell");
428+
return;
429+
}
430+
auto dump_current_txn = [&](const std::string &prefix) {
431+
writer.OneCell(fmt::format("{}txn_id={} txn_real_id={} read_ts={} commit_ts={} status={} iso_lvl={}", prefix,
432+
current_txn_->GetTransactionIdHumanReadable(), current_txn_->GetTransactionId(),
433+
current_txn_->GetReadTs(), current_txn_->GetCommitTs(),
434+
current_txn_->GetTransactionState(), current_txn_->GetIsolationLevel()));
435+
};
436+
if (params.size() == 1) {
437+
if (current_txn_ != nullptr) {
438+
dump_current_txn("");
439+
} else {
440+
writer.OneCell("no active txn, each statement starts a new txn.");
441+
}
442+
return;
443+
}
444+
if (params.size() == 2) {
445+
const std::string &param1 = params[1];
446+
if (param1 == "gc") {
447+
txn_manager_->GarbageCollection();
448+
writer.OneCell("GC complete");
449+
return;
450+
}
451+
auto txn_id = std::stoi(param1);
452+
if (txn_id == -1) {
453+
dump_current_txn("pause current txn ");
454+
current_txn_ = nullptr;
455+
return;
456+
}
457+
auto iter = txn_manager_->txn_map_.find(txn_id);
458+
if (iter == txn_manager_->txn_map_.end()) {
459+
iter = txn_manager_->txn_map_.find(txn_id + TXN_START_ID);
460+
if (iter == txn_manager_->txn_map_.end()) {
461+
writer.OneCell("cannot find txn.");
462+
return;
463+
}
464+
}
465+
current_txn_ = iter->second.get();
466+
dump_current_txn("switch to new txn ");
467+
return;
468+
}
469+
writer.OneCell("unsupported txn cmd.");
470+
}
471+
376472
} // namespace bustub

src/include/binder/binder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ class Binder {
213213

214214
auto BindVariableShow(duckdb_libpgquery::PGVariableShowStmt *stmt) -> std::unique_ptr<VariableShowStatement>;
215215

216+
auto BindTransaction(duckdb_libpgquery::PGTransactionStmt *stmt) -> std::unique_ptr<TransactionStatement>;
217+
216218
class ContextGuard {
217219
public:
218220
explicit ContextGuard(const BoundTableRef **scope, const CTEList **cte_scope) {

src/include/binder/statement/set_show_statement.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,14 @@ class VariableShowStatement : public BoundStatement {
4444
}
4545
};
4646

47+
class TransactionStatement : public BoundStatement {
48+
public:
49+
explicit TransactionStatement(std::string type)
50+
: BoundStatement(StatementType::TRANSACTION_STATEMENT), type_(std::move(type)) {}
51+
52+
std::string type_;
53+
54+
auto ToString() const -> std::string override { return fmt::format("BoundTransaction {{ type={} }}", type_); }
55+
};
56+
4757
} // namespace bustub

src/include/common/bustub_instance.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class IndexStatement;
4747
class VariableSetStatement;
4848
class VariableShowStatement;
4949
class ExplainStatement;
50+
class TransactionStatement;
5051

5152
class ResultWriter {
5253
public:
@@ -227,7 +228,7 @@ class FortTableWriter : public ResultWriter {
227228
tables_.emplace_back(table_.to_string());
228229
table_ = fort::utf8_table{};
229230
}
230-
void OneCell(const std::string &cell) override { tables_.emplace_back(cell); }
231+
void OneCell(const std::string &cell) override { tables_.emplace_back(cell + "\n"); }
231232
fort::utf8_table table_;
232233
std::vector<std::string> tables_;
233234
};
@@ -258,6 +259,12 @@ class BustubInstance {
258259
auto ExecuteSqlTxn(const std::string &sql, ResultWriter &writer, Transaction *txn,
259260
std::shared_ptr<CheckOptions> check_options = nullptr) -> bool;
260261

262+
/** Enable managed txn mode on this BusTub instance, allowing statements like `BEGIN`. */
263+
void EnableManagedTxn();
264+
265+
/** Get the current transaction. */
266+
auto CurrentManagedTxn() -> Transaction *;
267+
261268
/**
262269
* FOR TEST ONLY. Generate test tables in this BusTub instance.
263270
* It's used in the shell to predefine some tables, as we don't support
@@ -301,17 +308,22 @@ class BustubInstance {
301308

302309
private:
303310
void CmdDisplayTables(ResultWriter &writer);
311+
void CmdDbgMvcc(const std::vector<std::string> &params, ResultWriter &writer);
312+
void CmdTxn(const std::vector<std::string> &params, ResultWriter &writer);
304313
void CmdDisplayIndices(ResultWriter &writer);
305314
void CmdDisplayHelp(ResultWriter &writer);
306315
void WriteOneCell(const std::string &cell, ResultWriter &writer);
307316

308317
void HandleCreateStatement(Transaction *txn, const CreateStatement &stmt, ResultWriter &writer);
309318
void HandleIndexStatement(Transaction *txn, const IndexStatement &stmt, ResultWriter &writer);
310319
void HandleExplainStatement(Transaction *txn, const ExplainStatement &stmt, ResultWriter &writer);
320+
void HandleTxnStatement(Transaction *txn, const TransactionStatement &stmt, ResultWriter &writer);
311321
void HandleVariableShowStatement(Transaction *txn, const VariableShowStatement &stmt, ResultWriter &writer);
312322
void HandleVariableSetStatement(Transaction *txn, const VariableSetStatement &stmt, ResultWriter &writer);
313323

314324
std::unordered_map<std::string, std::string> session_variables_;
325+
Transaction *current_txn_{nullptr};
326+
bool managed_txn_mode_{false};
315327
};
316328

317329
} // namespace bustub

src/include/common/enums/statement_type.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum class StatementType : uint8_t {
3232
INDEX_STATEMENT, // index statement type
3333
VARIABLE_SET_STATEMENT, // set variable statement type
3434
VARIABLE_SHOW_STATEMENT, // show variable statement type
35+
TRANSACTION_STATEMENT, // txn statement type
3536
};
3637

3738
} // namespace bustub
@@ -75,6 +76,9 @@ struct fmt::formatter<bustub::StatementType> : formatter<string_view> {
7576
case bustub::StatementType::VARIABLE_SET_STATEMENT:
7677
name = "VariableSet";
7778
break;
79+
case bustub::StatementType::TRANSACTION_STATEMENT:
80+
name = "Transaction";
81+
break;
7882
}
7983
return formatter<string_view>::format(name, ctx);
8084
}

0 commit comments

Comments
 (0)