Skip to content

Commit

Permalink
Feat: Spring24 project4 starter code modification (#709)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
AveryQi115 committed Apr 1, 2024
1 parent 7868da0 commit 0d774f6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 69 deletions.
69 changes: 40 additions & 29 deletions src/concurrency/transaction_manager_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@ namespace bustub {

auto TransactionManager::UpdateUndoLink(RID rid, std::optional<UndoLink> prev_link,
std::function<bool(std::optional<UndoLink>)> &&check) -> bool {
std::function<bool(std::optional<VersionUndoLink>)> wrapper_func =
[check](std::optional<VersionUndoLink> link) -> bool {
if (link.has_value()) {
return check(link->prev_);
}
return check(std::nullopt);
};
return UpdateVersionLink(rid, prev_link.has_value() ? std::make_optional(VersionUndoLink{*prev_link}) : std::nullopt,
check != nullptr ? wrapper_func : nullptr);
}

auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLink> prev_version,
std::function<bool(std::optional<VersionUndoLink>)> &&check) -> bool {
std::unique_lock<std::shared_mutex> lck(version_info_mutex_);
std::shared_ptr<PageVersionInfo> pg_ver_info = nullptr;
auto iter = version_info_.find(rid.GetPageId());
Expand All @@ -51,8 +38,8 @@ auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLin
}
std::unique_lock<std::shared_mutex> lck2(pg_ver_info->mutex_);
lck.unlock();
auto iter2 = pg_ver_info->prev_version_.find(rid.GetSlotNum());
if (iter2 == pg_ver_info->prev_version_.end()) {
auto iter2 = pg_ver_info->prev_link_.find(rid.GetSlotNum());
if (iter2 == pg_ver_info->prev_link_.end()) {
if (check != nullptr && !check(std::nullopt)) {
return false;
}
Expand All @@ -61,15 +48,15 @@ auto TransactionManager::UpdateVersionLink(RID rid, std::optional<VersionUndoLin
return false;
}
}
if (prev_version.has_value()) {
pg_ver_info->prev_version_[rid.GetSlotNum()] = *prev_version;
if (prev_link.has_value()) {
pg_ver_info->prev_link_[rid.GetSlotNum()] = *prev_link;
} else {
pg_ver_info->prev_version_.erase(rid.GetSlotNum());
pg_ver_info->prev_link_.erase(rid.GetSlotNum());
}
return true;
}

auto TransactionManager::GetVersionLink(RID rid) -> std::optional<VersionUndoLink> {
auto TransactionManager::GetUndoLink(RID rid) -> std::optional<UndoLink> {
std::shared_lock<std::shared_mutex> lck(version_info_mutex_);
auto iter = version_info_.find(rid.GetPageId());
if (iter == version_info_.end()) {
Expand All @@ -78,21 +65,13 @@ auto TransactionManager::GetVersionLink(RID rid) -> std::optional<VersionUndoLin
std::shared_ptr<PageVersionInfo> pg_ver_info = iter->second;
std::unique_lock<std::shared_mutex> lck2(pg_ver_info->mutex_);
lck.unlock();
auto iter2 = pg_ver_info->prev_version_.find(rid.GetSlotNum());
if (iter2 == pg_ver_info->prev_version_.end()) {
auto iter2 = pg_ver_info->prev_link_.find(rid.GetSlotNum());
if (iter2 == pg_ver_info->prev_link_.end()) {
return std::nullopt;
}
return std::make_optional(iter2->second);
}

auto TransactionManager::GetUndoLink(RID rid) -> std::optional<UndoLink> {
auto version_link = GetVersionLink(rid);
if (version_link.has_value()) {
return version_link->prev_;
}
return std::nullopt;
}

auto TransactionManager::GetUndoLogOptional(UndoLink link) -> std::optional<UndoLog> {
std::shared_lock<std::shared_mutex> lck(txn_map_mutex_);
auto iter = txn_map_.find(link.prev_txn_);
Expand Down Expand Up @@ -122,4 +101,36 @@ void Transaction::SetTainted() {
std::terminate();
}

auto UpdateTupleAndUndoLink(
TransactionManager *txn_mgr, RID rid, std::optional<UndoLink> undo_link, TableHeap *table_heap, Transaction *txn,
const TupleMeta &meta, const Tuple &tuple,
std::function<bool(const TupleMeta &meta, const Tuple &tuple, RID rid, std::optional<UndoLink>)> &&check) -> bool {
auto page_write_guard = table_heap->AcquireTablePageWriteLock(rid);
auto page = page_write_guard.AsMut<TablePage>();

auto [base_meta, base_tuple] = page->GetTuple(rid);
if (check != nullptr && !check(base_meta, base_tuple, rid, undo_link)) {
return false;
}

// Update tuple and tupleMeta if pass in tuple and meta are different
if (meta != base_meta || !IsTupleContentEqual(tuple, base_tuple)) {
table_heap->UpdateTupleInPlaceWithLockAcquired(meta, tuple, rid, page);
}

txn_mgr->UpdateUndoLink(rid, undo_link);

return true;
}

auto GetTupleAndUndoLink(TransactionManager *txn_mgr, TableHeap *table_heap, RID rid)
-> std::tuple<TupleMeta, Tuple, std::optional<UndoLink>> {
auto page_read_guard = table_heap->AcquireTablePageReadLock(rid);
auto page = page_read_guard.As<TablePage>();
auto [meta, tuple] = page->GetTuple(rid);

auto undo_link = txn_mgr->GetUndoLink(rid);
return std::make_tuple(meta, tuple, undo_link);
}

} // namespace bustub
56 changes: 20 additions & 36 deletions src/include/concurrency/transaction_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <mutex> // NOLINT
#include <optional>
#include <shared_mutex>
#include <tuple>
#include <unordered_map>
#include <unordered_set>

Expand All @@ -26,32 +27,10 @@
#include "concurrency/transaction.h"
#include "concurrency/watermark.h"
#include "recovery/log_manager.h"
#include "storage/table/table_heap.h"
#include "storage/table/tuple.h"

namespace bustub {

/// The first undo link in the version chain, that links table heap tuple to the undo log.
struct VersionUndoLink {
/** The next version in the version chain. */
UndoLink prev_;
/** Whether a transaction is modifying the version link. Fall 2023: you do not need to read / write this field until
* task 4.2. */
bool in_progress_{false};

friend auto operator==(const VersionUndoLink &a, const VersionUndoLink &b) {
return a.prev_ == b.prev_ && a.in_progress_ == b.in_progress_;
}

friend auto operator!=(const VersionUndoLink &a, const VersionUndoLink &b) { return !(a == b); }

inline static auto FromOptionalUndoLink(std::optional<UndoLink> undo_link) -> std::optional<VersionUndoLink> {
if (undo_link.has_value()) {
return VersionUndoLink{*undo_link};
}
return std::nullopt;
}
};

/**
* TransactionManager keeps track of all the transactions running in the system.
*/
Expand Down Expand Up @@ -81,25 +60,15 @@ class TransactionManager {
void Abort(Transaction *txn);

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

/**
* @brief Use this function after task 4.2. Update an undo link that links table heap tuple to the first undo log.
* Before updating, `check` function will be called to ensure validity.
*/
auto UpdateVersionLink(RID rid, std::optional<VersionUndoLink> prev_version,
std::function<bool(std::optional<VersionUndoLink>)> &&check = nullptr) -> bool;

/** @brief Get the first undo log of a table heap tuple. Use this before task 4.2 */
/** @brief Get the first undo log of a table heap tuple. */
auto GetUndoLink(RID rid) -> std::optional<UndoLink>;

/** @brief Get the first undo log of a table heap tuple. Use this after task 4.2 */
auto GetVersionLink(RID rid) -> std::optional<VersionUndoLink>;

/** @brief Access the transaction undo log buffer and get the undo log. Return nullopt if the txn does not exist. Will
* still throw an exception if the index is out of range. */
auto GetUndoLogOptional(UndoLink link) -> std::optional<UndoLog>;
Expand Down Expand Up @@ -127,7 +96,7 @@ class TransactionManager {
/** Stores previous version info for all slots. Note: DO NOT use `[x]` to access it because
* it will create new elements even if it does not exist. Use `find` instead.
*/
std::unordered_map<slot_offset_t, VersionUndoLink> prev_version_;
std::unordered_map<slot_offset_t, UndoLink> prev_link_;
};

/** protects version info */
Expand Down Expand Up @@ -155,4 +124,19 @@ class TransactionManager {
auto VerifyTxn(Transaction *txn) -> bool;
};

/**
* @brief Update the tuple and its undo link in the table heap atomically.
*/
auto UpdateTupleAndUndoLink(
TransactionManager *txn_mgr, RID rid, std::optional<UndoLink> undo_link, TableHeap *table_heap, Transaction *txn,
const TupleMeta &meta, const Tuple &tuple,
std::function<bool(const TupleMeta &meta, const Tuple &tuple, RID rid, std::optional<UndoLink>)> &&check = nullptr)
-> bool;

/**
* @brief Get the tuple and its undo link in the table heap atomically.
*/
auto GetTupleAndUndoLink(TransactionManager *txn_mgr, TableHeap *table_heap, RID rid)
-> std::tuple<TupleMeta, Tuple, std::optional<UndoLink>>;

} // namespace bustub
8 changes: 4 additions & 4 deletions test/txn/txn_scan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,16 @@ TEST(TxnScanTest, DISABLED_ScanTest) { // NOLINT

auto rid1 = *table_info->table_->InsertTuple(TupleMeta{txn4->GetTransactionTempTs(), false},
Tuple{{Int(1), DoubleNull(), BoolNull()}, schema.get()});
bustub->txn_manager_->UpdateVersionLink(rid1, VersionUndoLink{prev_log_1}, nullptr);
bustub->txn_manager_->UpdateUndoLink(rid1, prev_log_1, nullptr);
auto rid2 = *table_info->table_->InsertTuple(TupleMeta{txn3->GetReadTs(), false},
Tuple{{Int(3), DoubleNull(), BoolNull()}, schema.get()});
bustub->txn_manager_->UpdateVersionLink(rid2, VersionUndoLink{prev_log_2}, nullptr);
bustub->txn_manager_->UpdateUndoLink(rid2, prev_log_2, nullptr);
auto rid3 = *table_info->table_->InsertTuple(TupleMeta{txn4->GetReadTs(), true},
Tuple{{IntNull(), DoubleNull(), BoolNull()}, schema.get()});
bustub->txn_manager_->UpdateVersionLink(rid3, VersionUndoLink{prev_log_4}, nullptr);
bustub->txn_manager_->UpdateUndoLink(rid3, prev_log_4, nullptr);
auto rid4 = *table_info->table_->InsertTuple(TupleMeta{txn3->GetTransactionTempTs(), true},
Tuple{{IntNull(), DoubleNull(), BoolNull()}, schema.get()});
bustub->txn_manager_->UpdateVersionLink(rid4, VersionUndoLink{prev_log_5}, nullptr);
bustub->txn_manager_->UpdateUndoLink(rid4, prev_log_5, nullptr);

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

Expand Down

0 comments on commit 0d774f6

Please sign in to comment.