Skip to content

Commit 0d774f6

Browse files
authored
Feat: Spring24 project4 starter code modification (#709)
* remove version link Signed-off-by: AveryQi115 <[email protected]> * add update tuple and undo link atomically Signed-off-by: AveryQi115 <[email protected]> * use new helper function Signed-off-by: AveryQi115 <[email protected]> --------- Signed-off-by: AveryQi115 <[email protected]>
1 parent 7868da0 commit 0d774f6

File tree

3 files changed

+64
-69
lines changed

3 files changed

+64
-69
lines changed

src/concurrency/transaction_manager_impl.cpp

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,6 @@ namespace bustub {
2727

2828
auto TransactionManager::UpdateUndoLink(RID rid, std::optional<UndoLink> prev_link,
2929
std::function<bool(std::optional<UndoLink>)> &&check) -> bool {
30-
std::function<bool(std::optional<VersionUndoLink>)> wrapper_func =
31-
[check](std::optional<VersionUndoLink> link) -> bool {
32-
if (link.has_value()) {
33-
return check(link->prev_);
34-
}
35-
return check(std::nullopt);
36-
};
37-
return UpdateVersionLink(rid, prev_link.has_value() ? std::make_optional(VersionUndoLink{*prev_link}) : std::nullopt,
38-
check != nullptr ? wrapper_func : nullptr);
39-
}
40-
41-
auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLink> prev_version,
42-
std::function<bool(std::optional<VersionUndoLink>)> &&check) -> bool {
4330
std::unique_lock<std::shared_mutex> lck(version_info_mutex_);
4431
std::shared_ptr<PageVersionInfo> pg_ver_info = nullptr;
4532
auto iter = version_info_.find(rid.GetPageId());
@@ -51,8 +38,8 @@ auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLin
5138
}
5239
std::unique_lock<std::shared_mutex> lck2(pg_ver_info->mutex_);
5340
lck.unlock();
54-
auto iter2 = pg_ver_info->prev_version_.find(rid.GetSlotNum());
55-
if (iter2 == pg_ver_info->prev_version_.end()) {
41+
auto iter2 = pg_ver_info->prev_link_.find(rid.GetSlotNum());
42+
if (iter2 == pg_ver_info->prev_link_.end()) {
5643
if (check != nullptr && !check(std::nullopt)) {
5744
return false;
5845
}
@@ -61,15 +48,15 @@ auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLin
6148
return false;
6249
}
6350
}
64-
if (prev_version.has_value()) {
65-
pg_ver_info->prev_version_[rid.GetSlotNum()] = *prev_version;
51+
if (prev_link.has_value()) {
52+
pg_ver_info->prev_link_[rid.GetSlotNum()] = *prev_link;
6653
} else {
67-
pg_ver_info->prev_version_.erase(rid.GetSlotNum());
54+
pg_ver_info->prev_link_.erase(rid.GetSlotNum());
6855
}
6956
return true;
7057
}
7158

72-
auto TransactionManager::GetVersionLink(RID rid) -> std::optional<VersionUndoLink> {
59+
auto TransactionManager::GetUndoLink(RID rid) -> std::optional<UndoLink> {
7360
std::shared_lock<std::shared_mutex> lck(version_info_mutex_);
7461
auto iter = version_info_.find(rid.GetPageId());
7562
if (iter == version_info_.end()) {
@@ -78,21 +65,13 @@ auto TransactionManager::GetVersionLink(RID rid) -> std::optional<VersionUndoLin
7865
std::shared_ptr<PageVersionInfo> pg_ver_info = iter->second;
7966
std::unique_lock<std::shared_mutex> lck2(pg_ver_info->mutex_);
8067
lck.unlock();
81-
auto iter2 = pg_ver_info->prev_version_.find(rid.GetSlotNum());
82-
if (iter2 == pg_ver_info->prev_version_.end()) {
68+
auto iter2 = pg_ver_info->prev_link_.find(rid.GetSlotNum());
69+
if (iter2 == pg_ver_info->prev_link_.end()) {
8370
return std::nullopt;
8471
}
8572
return std::make_optional(iter2->second);
8673
}
8774

88-
auto TransactionManager::GetUndoLink(RID rid) -> std::optional<UndoLink> {
89-
auto version_link = GetVersionLink(rid);
90-
if (version_link.has_value()) {
91-
return version_link->prev_;
92-
}
93-
return std::nullopt;
94-
}
95-
9675
auto TransactionManager::GetUndoLogOptional(UndoLink link) -> std::optional<UndoLog> {
9776
std::shared_lock<std::shared_mutex> lck(txn_map_mutex_);
9877
auto iter = txn_map_.find(link.prev_txn_);
@@ -122,4 +101,36 @@ void Transaction::SetTainted() {
122101
std::terminate();
123102
}
124103

104+
auto UpdateTupleAndUndoLink(
105+
TransactionManager *txn_mgr, RID rid, std::optional<UndoLink> undo_link, TableHeap *table_heap, Transaction *txn,
106+
const TupleMeta &meta, const Tuple &tuple,
107+
std::function<bool(const TupleMeta &meta, const Tuple &tuple, RID rid, std::optional<UndoLink>)> &&check) -> bool {
108+
auto page_write_guard = table_heap->AcquireTablePageWriteLock(rid);
109+
auto page = page_write_guard.AsMut<TablePage>();
110+
111+
auto [base_meta, base_tuple] = page->GetTuple(rid);
112+
if (check != nullptr && !check(base_meta, base_tuple, rid, undo_link)) {
113+
return false;
114+
}
115+
116+
// Update tuple and tupleMeta if pass in tuple and meta are different
117+
if (meta != base_meta || !IsTupleContentEqual(tuple, base_tuple)) {
118+
table_heap->UpdateTupleInPlaceWithLockAcquired(meta, tuple, rid, page);
119+
}
120+
121+
txn_mgr->UpdateUndoLink(rid, undo_link);
122+
123+
return true;
124+
}
125+
126+
auto GetTupleAndUndoLink(TransactionManager *txn_mgr, TableHeap *table_heap, RID rid)
127+
-> std::tuple<TupleMeta, Tuple, std::optional<UndoLink>> {
128+
auto page_read_guard = table_heap->AcquireTablePageReadLock(rid);
129+
auto page = page_read_guard.As<TablePage>();
130+
auto [meta, tuple] = page->GetTuple(rid);
131+
132+
auto undo_link = txn_mgr->GetUndoLink(rid);
133+
return std::make_tuple(meta, tuple, undo_link);
134+
}
135+
125136
} // namespace bustub

src/include/concurrency/transaction_manager.h

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <mutex> // NOLINT
1919
#include <optional>
2020
#include <shared_mutex>
21+
#include <tuple>
2122
#include <unordered_map>
2223
#include <unordered_set>
2324

@@ -26,32 +27,10 @@
2627
#include "concurrency/transaction.h"
2728
#include "concurrency/watermark.h"
2829
#include "recovery/log_manager.h"
30+
#include "storage/table/table_heap.h"
2931
#include "storage/table/tuple.h"
3032

3133
namespace bustub {
32-
33-
/// The first undo link in the version chain, that links table heap tuple to the undo log.
34-
struct VersionUndoLink {
35-
/** The next version in the version chain. */
36-
UndoLink prev_;
37-
/** Whether a transaction is modifying the version link. Fall 2023: you do not need to read / write this field until
38-
* task 4.2. */
39-
bool in_progress_{false};
40-
41-
friend auto operator==(const VersionUndoLink &a, const VersionUndoLink &b) {
42-
return a.prev_ == b.prev_ && a.in_progress_ == b.in_progress_;
43-
}
44-
45-
friend auto operator!=(const VersionUndoLink &a, const VersionUndoLink &b) { return !(a == b); }
46-
47-
inline static auto FromOptionalUndoLink(std::optional<UndoLink> undo_link) -> std::optional<VersionUndoLink> {
48-
if (undo_link.has_value()) {
49-
return VersionUndoLink{*undo_link};
50-
}
51-
return std::nullopt;
52-
}
53-
};
54-
5534
/**
5635
* TransactionManager keeps track of all the transactions running in the system.
5736
*/
@@ -81,25 +60,15 @@ class TransactionManager {
8160
void Abort(Transaction *txn);
8261

8362
/**
84-
* @brief Use this function before task 4.2. Update an undo link that links table heap tuple to the first undo log.
63+
* @brief Update an undo link that links table heap tuple to the first undo log.
8564
* Before updating, `check` function will be called to ensure validity.
8665
*/
8766
auto UpdateUndoLink(RID rid, std::optional<UndoLink> prev_link,
8867
std::function<bool(std::optional<UndoLink>)> &&check = nullptr) -> bool;
8968

90-
/**
91-
* @brief Use this function after task 4.2. Update an undo link that links table heap tuple to the first undo log.
92-
* Before updating, `check` function will be called to ensure validity.
93-
*/
94-
auto UpdateVersionLink(RID rid, std::optional<VersionUndoLink> prev_version,
95-
std::function<bool(std::optional<VersionUndoLink>)> &&check = nullptr) -> bool;
96-
97-
/** @brief Get the first undo log of a table heap tuple. Use this before task 4.2 */
69+
/** @brief Get the first undo log of a table heap tuple. */
9870
auto GetUndoLink(RID rid) -> std::optional<UndoLink>;
9971

100-
/** @brief Get the first undo log of a table heap tuple. Use this after task 4.2 */
101-
auto GetVersionLink(RID rid) -> std::optional<VersionUndoLink>;
102-
10372
/** @brief Access the transaction undo log buffer and get the undo log. Return nullopt if the txn does not exist. Will
10473
* still throw an exception if the index is out of range. */
10574
auto GetUndoLogOptional(UndoLink link) -> std::optional<UndoLog>;
@@ -127,7 +96,7 @@ class TransactionManager {
12796
/** Stores previous version info for all slots. Note: DO NOT use `[x]` to access it because
12897
* it will create new elements even if it does not exist. Use `find` instead.
12998
*/
130-
std::unordered_map<slot_offset_t, VersionUndoLink> prev_version_;
99+
std::unordered_map<slot_offset_t, UndoLink> prev_link_;
131100
};
132101

133102
/** protects version info */
@@ -155,4 +124,19 @@ class TransactionManager {
155124
auto VerifyTxn(Transaction *txn) -> bool;
156125
};
157126

127+
/**
128+
* @brief Update the tuple and its undo link in the table heap atomically.
129+
*/
130+
auto UpdateTupleAndUndoLink(
131+
TransactionManager *txn_mgr, RID rid, std::optional<UndoLink> undo_link, TableHeap *table_heap, Transaction *txn,
132+
const TupleMeta &meta, const Tuple &tuple,
133+
std::function<bool(const TupleMeta &meta, const Tuple &tuple, RID rid, std::optional<UndoLink>)> &&check = nullptr)
134+
-> bool;
135+
136+
/**
137+
* @brief Get the tuple and its undo link in the table heap atomically.
138+
*/
139+
auto GetTupleAndUndoLink(TransactionManager *txn_mgr, TableHeap *table_heap, RID rid)
140+
-> std::tuple<TupleMeta, Tuple, std::optional<UndoLink>>;
141+
158142
} // namespace bustub

test/txn/txn_scan_test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,16 @@ TEST(TxnScanTest, DISABLED_ScanTest) { // NOLINT
188188

189189
auto rid1 = *table_info->table_->InsertTuple(TupleMeta{txn4->GetTransactionTempTs(), false},
190190
Tuple{{Int(1), DoubleNull(), BoolNull()}, schema.get()});
191-
bustub->txn_manager_->UpdateVersionLink(rid1, VersionUndoLink{prev_log_1}, nullptr);
191+
bustub->txn_manager_->UpdateUndoLink(rid1, prev_log_1, nullptr);
192192
auto rid2 = *table_info->table_->InsertTuple(TupleMeta{txn3->GetReadTs(), false},
193193
Tuple{{Int(3), DoubleNull(), BoolNull()}, schema.get()});
194-
bustub->txn_manager_->UpdateVersionLink(rid2, VersionUndoLink{prev_log_2}, nullptr);
194+
bustub->txn_manager_->UpdateUndoLink(rid2, prev_log_2, nullptr);
195195
auto rid3 = *table_info->table_->InsertTuple(TupleMeta{txn4->GetReadTs(), true},
196196
Tuple{{IntNull(), DoubleNull(), BoolNull()}, schema.get()});
197-
bustub->txn_manager_->UpdateVersionLink(rid3, VersionUndoLink{prev_log_4}, nullptr);
197+
bustub->txn_manager_->UpdateUndoLink(rid3, prev_log_4, nullptr);
198198
auto rid4 = *table_info->table_->InsertTuple(TupleMeta{txn3->GetTransactionTempTs(), true},
199199
Tuple{{IntNull(), DoubleNull(), BoolNull()}, schema.get()});
200-
bustub->txn_manager_->UpdateVersionLink(rid4, VersionUndoLink{prev_log_5}, nullptr);
200+
bustub->txn_manager_->UpdateUndoLink(rid4, prev_log_5, nullptr);
201201

202202
TxnMgrDbg("before verify scan", bustub->txn_manager_.get(), table_info, table_info->table_.get());
203203

0 commit comments

Comments
 (0)