Skip to content

Commit 03ddb25

Browse files
authored
fall 2024 p4 update (#769)
* fall 2024 p4 update * lint * disable the public test * nit: copyright and format
1 parent d8f4778 commit 03ddb25

File tree

4 files changed

+398
-6
lines changed

4 files changed

+398
-6
lines changed

src/execution/execution_common.cpp

+72-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// BusTub
4+
//
5+
// execution_common.cpp
6+
//
7+
// Identification: src/execution/execution_common.cpp
8+
//
9+
// Copyright (c) 2024-2024, Carnegie Mellon University Database Group
10+
//
11+
//===----------------------------------------------------------------------===//
12+
113
#include "execution/execution_common.h"
14+
215
#include "catalog/catalog.h"
3-
#include "common/config.h"
416
#include "common/macros.h"
517
#include "concurrency/transaction_manager.h"
618
#include "fmt/core.h"
719
#include "storage/table/table_heap.h"
8-
#include "type/value.h"
9-
#include "type/value_factory.h"
1020

1121
namespace bustub {
1222

@@ -23,11 +33,70 @@ auto GenerateSortKey(const Tuple &tuple, const std::vector<OrderBy> &order_bys,
2333
* You can ignore the remaining part of this file until P4.
2434
*/
2535

36+
/**
37+
* @brief Reconstruct a tuple by applying the provided undo logs from the base tuple. All logs in the undo_logs are
38+
* applied regardless of the timestamp
39+
*
40+
* @param schema The schema of the base tuple and the returned tuple.
41+
* @param base_tuple The base tuple to start the reconstruction from.
42+
* @param base_meta The metadata of the base tuple.
43+
* @param undo_logs The list of undo logs to apply during the reconstruction, the front is applied first.
44+
* @return An optional tuple that represents the reconstructed tuple. If the tuple is deleted as the result, returns
45+
* std::nullopt.
46+
*/
2647
auto ReconstructTuple(const Schema *schema, const Tuple &base_tuple, const TupleMeta &base_meta,
2748
const std::vector<UndoLog> &undo_logs) -> std::optional<Tuple> {
2849
UNIMPLEMENTED("not implemented");
2950
}
3051

52+
/**
53+
* @brief Collects the undo logs sufficient to reconstruct the tuple w.r.t. the txn.
54+
*
55+
* @param rid The RID of the tuple.
56+
* @param base_meta The metadata of the base tuple.
57+
* @param base_tuple The base tuple.
58+
* @param undo_link The undo link to the latest undo log.
59+
* @param txn The transaction.
60+
* @param txn_mgr The transaction manager.
61+
* @return An optional vector of undo logs to pass to ReconstructTuple(). std::nullopt if the tuple did not exist at the
62+
* time.
63+
*/
64+
auto CollectUndoLogs(RID rid, const TupleMeta &base_meta, const Tuple &base_tuple, std::optional<UndoLink> undo_link,
65+
Transaction *txn, TransactionManager *txn_mgr) -> std::optional<std::vector<UndoLog>> {
66+
UNIMPLEMENTED("not implemented");
67+
}
68+
69+
/**
70+
* @brief Generates a new undo log as the transaction tries to modify this tuple at the first time.
71+
*
72+
* @param schema The schema of the table.
73+
* @param base_tuple The base tuple before the update, the one retrieved from the table heap. nullptr if the tuple is
74+
* deleted.
75+
* @param target_tuple The target tuple after the update. nullptr if this is a deletion.
76+
* @param ts The timestamp of the base tuple.
77+
* @param prev_version The undo link to the latest undo log of this tuple.
78+
* @return The generated undo log.
79+
*/
80+
auto GenerateNewUndoLog(const Schema *schema, const Tuple *base_tuple, const Tuple *target_tuple, timestamp_t ts,
81+
UndoLink prev_version) -> UndoLog {
82+
UNIMPLEMENTED("not implemented");
83+
}
84+
85+
/**
86+
* @brief Generate the updated undo log to replace the old one, whereas the tuple is already modified by this txn once.
87+
*
88+
* @param schema The schema of the table.
89+
* @param base_tuple The base tuple before the update, the one retrieved from the table heap. nullptr if the tuple is
90+
* deleted.
91+
* @param target_tuple The target tuple after the update. nullptr if this is a deletion.
92+
* @param log The original undo log.
93+
* @return The updated undo log.
94+
*/
95+
auto GenerateUpdatedUndoLog(const Schema *schema, const Tuple *base_tuple, const Tuple *target_tuple,
96+
const UndoLog &log) -> UndoLog {
97+
UNIMPLEMENTED("not implemented");
98+
}
99+
31100
void TxnMgrDbg(const std::string &info, TransactionManager *txn_mgr, const TableInfo *table_info,
32101
TableHeap *table_heap) {
33102
// always use stderr for printing logs...

src/include/execution/execution_common.h

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// BusTub
4+
//
5+
// execution_common.h
6+
//
7+
// Identification: src/include/execution/execution_common.h
8+
//
9+
// Copyright (c) 2014-2024, Carnegie Mellon University Database Group
10+
//
11+
//===----------------------------------------------------------------------===//
112
#pragma once
213

314
#include <string>
@@ -44,6 +55,15 @@ auto GenerateSortKey(const Tuple &tuple, const std::vector<OrderBy> &order_bys,
4455
auto ReconstructTuple(const Schema *schema, const Tuple &base_tuple, const TupleMeta &base_meta,
4556
const std::vector<UndoLog> &undo_logs) -> std::optional<Tuple>;
4657

58+
auto CollectUndoLogs(RID rid, const TupleMeta &base_meta, const Tuple &base_tuple, std::optional<UndoLink> undo_link,
59+
Transaction *txn, TransactionManager *txn_mgr) -> std::optional<std::vector<UndoLog>>;
60+
61+
auto GenerateNewUndoLog(const Schema *schema, const Tuple *base_tuple, const Tuple *target_tuple, timestamp_t ts,
62+
UndoLink prev_version) -> UndoLog;
63+
64+
auto GenerateUpdatedUndoLog(const Schema *schema, const Tuple *base_tuple, const Tuple *target_tuple,
65+
const UndoLog &log) -> UndoLog;
66+
4767
void TxnMgrDbg(const std::string &info, TransactionManager *txn_mgr, const TableInfo *table_info,
4868
TableHeap *table_heap);
4969

@@ -52,11 +72,9 @@ void TxnMgrDbg(const std::string &info, TransactionManager *txn_mgr, const Table
5272
// To give you a sense of what can be shared across executors / transaction manager, here are the
5373
// list of helper function names that we defined in the reference solution. You should come up with
5474
// your own when you go through the process.
55-
// * CollectUndoLogs
5675
// * WalkUndoLogs
5776
// * Modify
5877
// * IsWriteWriteConflict
59-
// * GenerateDiffLog
6078
// * GenerateNullTupleForSchema
6179
// * GetUndoLogSchema
6280
//

test/txn/txn_executor_test.cpp

+106
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,112 @@ TEST(TxnExecutorTest, DISABLED_InsertDeleteConflictTest) { // NOLINT
186186
WithTxn(txn7, CommitTxn(*bustub, _var, _txn));
187187
}
188188

189+
TEST(TxnExecutorTest, DISABLED_GenerateUndoLogTest) {
190+
{
191+
fmt::println(stderr, "--- GenerateUndoLogTest: Simple update ---");
192+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
193+
auto partial_schema = ParseCreateStatement("b double,c boolean");
194+
auto base_tuple = Tuple{{Int(0), Double(0.0), Bool(true)}, schema.get()};
195+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
196+
auto undo_log = GenerateNewUndoLog(schema.get(), &base_tuple, &target_tuple, 0, {});
197+
198+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, false}, {undo_log});
199+
ASSERT_TRUE(tuple.has_value());
200+
ASSERT_TRUE(IsTupleContentEqual(*tuple, base_tuple));
201+
}
202+
{
203+
fmt::println(stderr, "--- GenerateUndoLogTest: Simple delete ---");
204+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
205+
auto base_tuple = Tuple{{Int(0), Double(0.0), Bool(true)}, schema.get()};
206+
auto undo_log = GenerateNewUndoLog(schema.get(), &base_tuple, nullptr, 0, {});
207+
208+
auto tuple = ReconstructTuple(schema.get(), base_tuple, {0, true}, {undo_log});
209+
ASSERT_TRUE(tuple.has_value());
210+
ASSERT_TRUE(IsTupleContentEqual(*tuple, base_tuple));
211+
}
212+
{
213+
// This case is only relevant after task 4.2, where an insert may happen on a tombstone.
214+
// Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
215+
fmt::println(stderr, "--- GenerateUndoLogTest: Simple insert ---");
216+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
217+
auto partial_schema = ParseCreateStatement("");
218+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
219+
auto undo_log = GenerateNewUndoLog(schema.get(), nullptr, &target_tuple, 0, {});
220+
221+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, false}, {undo_log});
222+
ASSERT_FALSE(tuple.has_value());
223+
}
224+
{
225+
fmt::println(stderr, "--- GenerateUndoLogTest: Update twice in a txn ---");
226+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
227+
auto partial_schema = ParseCreateStatement("b double,c boolean");
228+
auto base_tuple = Tuple{{Int(0), Double(0.0), Bool(true)}, schema.get()};
229+
auto intermidiate_tuple = Tuple{{Int(0), Double(0.0), Bool(false)}, schema.get()};
230+
auto undo_log = GenerateNewUndoLog(schema.get(), &base_tuple, &intermidiate_tuple, 0, {});
231+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
232+
auto updated_undo_log = GenerateUpdatedUndoLog(schema.get(), &intermidiate_tuple, &target_tuple, undo_log);
233+
234+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, false}, {updated_undo_log});
235+
ASSERT_TRUE(tuple.has_value());
236+
ASSERT_TRUE(IsTupleContentEqual(*tuple, base_tuple));
237+
}
238+
{
239+
fmt::println(stderr, "--- GenerateUndoLogTest: Update then delete in a txn ---");
240+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
241+
auto partial_schema = ParseCreateStatement("b double,c boolean");
242+
auto base_tuple = Tuple{{Int(0), Double(0.0), Bool(true)}, schema.get()};
243+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
244+
auto undo_log = GenerateNewUndoLog(schema.get(), &base_tuple, &target_tuple, 0, {});
245+
auto updated_undo_log = GenerateUpdatedUndoLog(schema.get(), &target_tuple, nullptr, undo_log);
246+
247+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, true}, {updated_undo_log});
248+
ASSERT_TRUE(tuple.has_value());
249+
ASSERT_TRUE(IsTupleContentEqual(*tuple, base_tuple));
250+
}
251+
{
252+
// This case is only relevant after task 4.2, where an insert may happen on a tombstone.
253+
// Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
254+
fmt::println(stderr, "--- GenerateUndoLogTest: Insert then update in a txn ---");
255+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
256+
auto partial_schema = ParseCreateStatement("");
257+
auto intermediate_tuple = Tuple{{Int(0), Double(0.0), Bool(false)}, schema.get()};
258+
auto undo_log = GenerateNewUndoLog(schema.get(), nullptr, &intermediate_tuple, 0, {});
259+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
260+
auto updated_undo_log = GenerateUpdatedUndoLog(schema.get(), &intermediate_tuple, &target_tuple, undo_log);
261+
262+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, false}, {updated_undo_log});
263+
ASSERT_FALSE(tuple.has_value());
264+
}
265+
{
266+
// This case is only relevant after task 4.2, where an insert may happen on a tombstone.
267+
// Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
268+
fmt::println(stderr, "--- GenerateUndoLogTest: Insert then delete in a txn ---");
269+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
270+
auto partial_schema = ParseCreateStatement("");
271+
auto intermediate_tuple = Tuple{{Int(0), Double(0.0), Bool(false)}, schema.get()};
272+
auto undo_log = GenerateNewUndoLog(schema.get(), nullptr, &intermediate_tuple, 0, {});
273+
auto updated_undo_log = GenerateUpdatedUndoLog(schema.get(), &intermediate_tuple, nullptr, undo_log);
274+
275+
auto tuple = ReconstructTuple(schema.get(), intermediate_tuple, {0, true}, {updated_undo_log});
276+
ASSERT_FALSE(tuple.has_value());
277+
}
278+
{
279+
// This case is only relevant after task 4.2, where an insert may happen on a tombstone.
280+
// Before task 4.2, insert always generates a new tuple in table heap without any undo logs.
281+
fmt::println(stderr, "--- GenerateUndoLogTest: Delete then insert in a txn ---");
282+
auto schema = ParseCreateStatement("a integer,b double,c boolean");
283+
auto partial_schema = ParseCreateStatement("b double,c boolean");
284+
auto base_tuple = Tuple{{Int(0), Double(0.0), Bool(true)}, schema.get()};
285+
auto undo_log = GenerateNewUndoLog(schema.get(), &base_tuple, nullptr, 0, {});
286+
auto target_tuple = Tuple{{Int(0), Double(1.0), Bool(false)}, schema.get()};
287+
auto updated_undo_log = GenerateUpdatedUndoLog(schema.get(), &base_tuple, &target_tuple, undo_log);
288+
289+
auto tuple = ReconstructTuple(schema.get(), target_tuple, {0, false}, {updated_undo_log});
290+
ASSERT_TRUE(tuple.has_value());
291+
ASSERT_TRUE(IsTupleContentEqual(*tuple, base_tuple));
292+
}
293+
}
294+
189295
TEST(TxnExecutorTest, DISABLED_UpdateTest1) { // NOLINT
190296
fmt::println(stderr, "--- UpdateTest1: no undo log ---");
191297
auto bustub = std::make_unique<BusTubInstance>();

0 commit comments

Comments
 (0)