Skip to content

Commit 1da0016

Browse files
authored
refactor: redesign table heap (#534)
* refactor: redesign table heap Signed-off-by: Alex Chi <[email protected]> * fix clang-tidy Signed-off-by: Alex Chi <[email protected]> * fix test cases Signed-off-by: Alex Chi <[email protected]> * fix catalog test Signed-off-by: Alex Chi <[email protected]> * rm catalog test Signed-off-by: Alex Chi <[email protected]> --------- Signed-off-by: Alex Chi <[email protected]>
1 parent 4d1fd64 commit 1da0016

File tree

17 files changed

+270
-1605
lines changed

17 files changed

+270
-1605
lines changed

src/catalog/table_generator.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,8 @@ void TableGenerator::FillTable(TableInfo *info, TableInsertMeta *table_meta) {
7676
for (const auto &col : values) {
7777
entry.emplace_back(col[i]);
7878
}
79-
RID rid;
80-
bool inserted = info->table_->InsertTuple(Tuple(entry, &info->schema_), &rid, exec_ctx_->GetTransaction());
81-
BUSTUB_ENSURE(inserted, "Sequential insertion cannot fail");
79+
auto rid = info->table_->InsertTuple(TupleMeta{0, 0, false}, Tuple(entry, &info->schema_));
80+
BUSTUB_ENSURE(rid != std::nullopt, "Sequential insertion cannot fail");
8281
num_inserted++;
8382
}
8483
}

src/concurrency/transaction_manager.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <unordered_set>
1919

2020
#include "catalog/catalog.h"
21+
#include "common/macros.h"
2122
#include "storage/table/table_heap.h"
2223
namespace bustub {
2324

@@ -49,12 +50,12 @@ void TransactionManager::Commit(Transaction *txn) {
4950
// Perform all deletes before we commit.
5051
auto write_set = txn->GetWriteSet();
5152
while (!write_set->empty()) {
52-
auto &item = write_set->back();
53-
auto *table = item.table_;
54-
if (item.wtype_ == WType::DELETE) {
55-
// Note that this also releases the lock when holding the page latch.
56-
table->ApplyDelete(item.rid_, txn);
57-
}
53+
// auto &item = write_set->back();
54+
// auto *table = item.table_;
55+
// if (item.wtype_ == WType::DELETE) {
56+
// // Note that this also releases the lock when holding the page latch.
57+
// table->ApplyDelete(item.rid_, txn);
58+
// }
5859
write_set->pop_back();
5960
}
6061
write_set->clear();
@@ -70,16 +71,16 @@ void TransactionManager::Abort(Transaction *txn) {
7071
// Rollback before releasing the lock.
7172
auto table_write_set = txn->GetWriteSet();
7273
while (!table_write_set->empty()) {
73-
auto &item = table_write_set->back();
74-
auto *table = item.table_;
75-
if (item.wtype_ == WType::DELETE) {
76-
table->RollbackDelete(item.rid_, txn);
77-
} else if (item.wtype_ == WType::INSERT) {
78-
// Note that this also releases the lock when holding the page latch.
79-
table->ApplyDelete(item.rid_, txn);
80-
} else if (item.wtype_ == WType::UPDATE) {
81-
table->UpdateTuple(item.tuple_, item.rid_, txn);
82-
}
74+
// auto &item = table_write_set->back();
75+
// auto *table = item.table_;
76+
// if (item.wtype_ == WType::DELETE) {
77+
// table->RollbackDelete(item.rid_, txn);
78+
// } else if (item.wtype_ == WType::INSERT) {
79+
// // Note that this also releases the lock when holding the page latch.
80+
// table->ApplyDelete(item.rid_, txn);
81+
// } else if (item.wtype_ == WType::UPDATE) {
82+
// table->UpdateTuple(item.tuple_, item.rid_, txn);
83+
// }
8384
table_write_set->pop_back();
8485
}
8586
table_write_set->clear();

src/include/catalog/catalog.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class Catalog {
136136
// When create_table_heap == false, it means that we're running binder tests (where no txn will be provided) or
137137
// we are running shell without buffer pool. We don't need to create TableHeap in this case.
138138
if (create_table_heap) {
139-
table = std::make_unique<TableHeap>(bpm_, lock_manager_, log_manager_, txn);
139+
table = std::make_unique<TableHeap>(bpm_);
140140
}
141141

142142
// Fetch the table OID for the new table
@@ -230,9 +230,9 @@ class Catalog {
230230

231231
// Populate the index with all tuples in table heap
232232
auto *table_meta = GetTable(table_name);
233-
auto *heap = table_meta->table_.get();
234-
for (auto tuple = heap->Begin(txn); tuple != heap->End(); ++tuple) {
235-
index->InsertEntry(tuple->KeyFromTuple(schema, key_schema, key_attrs), tuple->GetRid(), txn);
233+
for (auto iter = table_meta->table_->MakeIterator(); !iter.IsEnd(); ++iter) {
234+
auto [meta, tuple] = iter.GetTuple();
235+
index->InsertEntry(tuple.KeyFromTuple(schema, key_schema, key_attrs), tuple.GetRid(), txn);
236236
}
237237

238238
// Get the next OID for the new index

src/include/concurrency/transaction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ using index_oid_t = uint32_t;
6464
*/
6565
class TableWriteRecord {
6666
public:
67+
// NOLINTNEXTLINE
6768
TableWriteRecord(RID rid, WType wtype, const Tuple &tuple, TableHeap *table)
6869
: rid_(rid), wtype_(wtype), tuple_(tuple), table_(table) {}
6970

@@ -80,6 +81,7 @@ class TableWriteRecord {
8081
*/
8182
class IndexWriteRecord {
8283
public:
84+
// NOLINTNEXTLINE
8385
IndexWriteRecord(RID rid, table_oid_t table_oid, WType wtype, const Tuple &tuple, index_oid_t index_oid,
8486
Catalog *catalog)
8587
: rid_(rid), table_oid_(table_oid), wtype_(wtype), tuple_(tuple), index_oid_(index_oid), catalog_(catalog) {}

src/include/storage/page/table_page.h

Lines changed: 36 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,22 @@
1313
#pragma once
1414

1515
#include <cstring>
16+
#include <optional>
17+
#include <tuple>
18+
#include <utility>
1619

20+
#include "common/config.h"
1721
#include "common/rid.h"
1822
#include "concurrency/lock_manager.h"
1923
#include "recovery/log_manager.h"
2024
#include "storage/page/page.h"
25+
#include "storage/table/table_heap.h"
2126
#include "storage/table/tuple.h"
2227

23-
static constexpr uint64_t DELETE_MASK = (1U << (8 * sizeof(uint32_t) - 1));
24-
2528
namespace bustub {
2629

30+
static constexpr uint64_t TABLE_PAGE_HEADER_SIZE = 8;
31+
2732
/**
2833
* Slotted page format:
2934
* ---------------------------------------------------------
@@ -34,176 +39,66 @@ namespace bustub {
3439
*
3540
* Header format (size in bytes):
3641
* ----------------------------------------------------------------------------
37-
* | PageId (4)| LSN (4)| PrevPageId (4)| NextPageId (4)| FreeSpacePointer(4) |
42+
* | NextPageId (4)| NumTuples(2) | NumDeletedTuples(2) |
3843
* ----------------------------------------------------------------------------
3944
* ----------------------------------------------------------------
40-
* | TupleCount (4) | Tuple_1 offset (4) | Tuple_1 size (4) | ... |
45+
* | Tuple_1 offset+size (4) | Tuple_2 offset+size (4) | ... |
4146
* ----------------------------------------------------------------
4247
*
48+
* Tuple format:
49+
* | meta | data |
4350
*/
44-
class TablePage : public Page {
51+
52+
class TablePage {
4553
public:
4654
/**
4755
* Initialize the TablePage header.
48-
* @param page_id the page ID of this table page
49-
* @param page_size the size of this table page
50-
* @param prev_page_id the previous table page ID
51-
* @param log_manager the log manager in use
52-
* @param txn the transaction that this page is created in
5356
*/
54-
void Init(page_id_t page_id, uint32_t page_size, page_id_t prev_page_id, LogManager *log_manager, Transaction *txn);
55-
56-
/** @return the page ID of this table page */
57-
auto GetTablePageId() -> page_id_t { return *reinterpret_cast<page_id_t *>(GetData()); }
57+
void Init();
5858

59-
/** @return the page ID of the previous table page */
60-
auto GetPrevPageId() -> page_id_t { return *reinterpret_cast<page_id_t *>(GetData() + OFFSET_PREV_PAGE_ID); }
59+
/** @return number of tuples in this page */
60+
auto GetNumTuples() const -> uint32_t { return num_tuples_; }
6161

6262
/** @return the page ID of the next table page */
63-
auto GetNextPageId() -> page_id_t { return *reinterpret_cast<page_id_t *>(GetData() + OFFSET_NEXT_PAGE_ID); }
64-
65-
/** Set the page id of the previous page in the table. */
66-
void SetPrevPageId(page_id_t prev_page_id) {
67-
memcpy(GetData() + OFFSET_PREV_PAGE_ID, &prev_page_id, sizeof(page_id_t));
68-
}
63+
auto GetNextPageId() const -> page_id_t { return next_page_id_; }
6964

7065
/** Set the page id of the next page in the table. */
71-
void SetNextPageId(page_id_t next_page_id) {
72-
memcpy(GetData() + OFFSET_NEXT_PAGE_ID, &next_page_id, sizeof(page_id_t));
73-
}
66+
void SetNextPageId(page_id_t next_page_id) { next_page_id_ = next_page_id; }
67+
68+
/** Get the next offset to insert, return nullopt if this tuple cannot fit in this page */
69+
auto GetNextTupleOffset(const TupleMeta &meta, const Tuple &tuple) const -> std::optional<uint16_t>;
7470

7571
/**
7672
* Insert a tuple into the table.
7773
* @param tuple tuple to insert
78-
* @param[out] rid rid of the inserted tuple
79-
* @param txn transaction performing the insert
80-
* @param lock_manager the lock manager
81-
* @param log_manager the log manager
8274
* @return true if the insert is successful (i.e. there is enough space)
8375
*/
84-
auto InsertTuple(const Tuple &tuple, RID *rid, Transaction *txn, LockManager *lock_manager, LogManager *log_manager)
85-
-> bool;
86-
87-
/**
88-
* Mark a tuple as deleted. This does not actually delete the tuple.
89-
* @param rid rid of the tuple to mark as deleted
90-
* @param txn transaction performing the delete
91-
* @param lock_manager the lock manager
92-
* @param log_manager the log manager
93-
* @return true if marking the tuple as deleted is successful (i.e the tuple exists)
94-
*/
95-
auto MarkDelete(const RID &rid, Transaction *txn, LockManager *lock_manager, LogManager *log_manager) -> bool;
76+
auto InsertTuple(const TupleMeta &meta, const Tuple &tuple) -> std::optional<uint16_t>;
9677

9778
/**
9879
* Update a tuple.
99-
* @param new_tuple new value of the tuple
100-
* @param[out] old_tuple old value of the tuple
101-
* @param rid rid of the tuple
102-
* @param txn transaction performing the update
103-
* @param lock_manager the lock manager
104-
* @param log_manager the log manager
105-
* @return true if updating the tuple succeeded
10680
*/
107-
auto UpdateTuple(const Tuple &new_tuple, Tuple *old_tuple, const RID &rid, Transaction *txn,
108-
LockManager *lock_manager, LogManager *log_manager) -> bool;
109-
110-
/** To be called on commit or abort. Actually perform the delete or rollback an insert. */
111-
void ApplyDelete(const RID &rid, Transaction *txn, LogManager *log_manager);
112-
113-
/** To be called on abort. Rollback a delete, i.e. this reverses a MarkDelete. */
114-
void RollbackDelete(const RID &rid, Transaction *txn, LogManager *log_manager);
81+
void UpdateTupleMeta(const TupleMeta &meta, const RID &rid);
11582

11683
/**
11784
* Read a tuple from a table.
118-
* @param rid rid of the tuple to read
119-
* @param[out] tuple the tuple that was read
120-
* @param txn transaction performing the read
121-
* @param lock_manager the lock manager
122-
* @return true if the read is successful (i.e. the tuple exists)
12385
*/
124-
auto GetTuple(const RID &rid, Tuple *tuple, Transaction *txn, LockManager *lock_manager) -> bool;
125-
126-
/** @return the rid of the first tuple in this page */
86+
auto GetTuple(const RID &rid) const -> std::pair<TupleMeta, Tuple>;
12787

128-
/**
129-
* @param[out] first_rid the RID of the first tuple in this page
130-
* @return true if the first tuple exists, false otherwise
131-
*/
132-
auto GetFirstTupleRid(RID *first_rid) -> bool;
133-
134-
/**
135-
* @param cur_rid the RID of the current tuple
136-
* @param[out] next_rid the RID of the tuple following the current tuple
137-
* @return true if the next tuple exists, false otherwise
138-
*/
139-
auto GetNextTupleRid(const RID &cur_rid, RID *next_rid) -> bool;
140-
141-
private:
14288
static_assert(sizeof(page_id_t) == 4);
14389

144-
static constexpr size_t SIZE_TABLE_PAGE_HEADER = 24;
145-
static constexpr size_t SIZE_TUPLE = 8;
146-
static constexpr size_t OFFSET_PREV_PAGE_ID = 8;
147-
static constexpr size_t OFFSET_NEXT_PAGE_ID = 12;
148-
static constexpr size_t OFFSET_FREE_SPACE = 16;
149-
static constexpr size_t OFFSET_TUPLE_COUNT = 20;
150-
static constexpr size_t OFFSET_TUPLE_OFFSET = 24; // Naming things is hard.
151-
static constexpr size_t OFFSET_TUPLE_SIZE = 28;
152-
153-
/** @return pointer to the end of the current free space, see header comment */
154-
auto GetFreeSpacePointer() -> uint32_t { return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_FREE_SPACE); }
90+
private:
91+
using TupleInfo = std::tuple<uint16_t, uint16_t, TupleMeta>;
92+
char page_start_[0];
93+
page_id_t next_page_id_;
94+
uint16_t num_tuples_;
95+
uint16_t num_deleted_tuples_;
96+
TupleInfo tuple_info_[0];
97+
98+
static constexpr size_t TUPLE_INFO_SIZE = 16;
99+
static_assert(sizeof(TupleInfo) == TUPLE_INFO_SIZE);
100+
};
155101

156-
/** Sets the pointer, this should be the end of the current free space. */
157-
void SetFreeSpacePointer(uint32_t free_space_pointer) {
158-
memcpy(GetData() + OFFSET_FREE_SPACE, &free_space_pointer, sizeof(uint32_t));
159-
}
102+
static_assert(sizeof(TablePage) == TABLE_PAGE_HEADER_SIZE);
160103

161-
/**
162-
* @note returned tuple count may be an overestimate because some slots may be empty
163-
* @return at least the number of tuples in this page
164-
*/
165-
auto GetTupleCount() -> uint32_t { return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_TUPLE_COUNT); }
166-
167-
/** Set the number of tuples in this page. */
168-
void SetTupleCount(uint32_t tuple_count) { memcpy(GetData() + OFFSET_TUPLE_COUNT, &tuple_count, sizeof(uint32_t)); }
169-
170-
auto GetFreeSpaceRemaining() -> uint32_t {
171-
return GetFreeSpacePointer() - SIZE_TABLE_PAGE_HEADER - SIZE_TUPLE * GetTupleCount();
172-
}
173-
174-
/** @return tuple offset at slot slot_num */
175-
auto GetTupleOffsetAtSlot(uint32_t slot_num) -> uint32_t {
176-
return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_TUPLE_OFFSET + SIZE_TUPLE * slot_num);
177-
}
178-
179-
/** Set tuple offset at slot slot_num. */
180-
void SetTupleOffsetAtSlot(uint32_t slot_num, uint32_t offset) {
181-
memcpy(GetData() + OFFSET_TUPLE_OFFSET + SIZE_TUPLE * slot_num, &offset, sizeof(uint32_t));
182-
}
183-
184-
/** @return tuple size at slot slot_num */
185-
auto GetTupleSize(uint32_t slot_num) -> uint32_t {
186-
return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_TUPLE_SIZE + SIZE_TUPLE * slot_num);
187-
}
188-
189-
/** Set tuple size at slot slot_num. */
190-
void SetTupleSize(uint32_t slot_num, uint32_t size) {
191-
memcpy(GetData() + OFFSET_TUPLE_SIZE + SIZE_TUPLE * slot_num, &size, sizeof(uint32_t));
192-
}
193-
194-
/** @return true if the tuple is deleted or empty */
195-
static auto IsDeleted(uint32_t tuple_size) -> bool {
196-
return static_cast<bool>(tuple_size & DELETE_MASK) || tuple_size == 0;
197-
}
198-
199-
/** @return tuple size with the deleted flag set */
200-
static auto SetDeletedFlag(uint32_t tuple_size) -> uint32_t {
201-
return static_cast<uint32_t>(tuple_size | DELETE_MASK);
202-
}
203-
204-
/** @return tuple size with the deleted flag unset */
205-
static auto UnsetDeletedFlag(uint32_t tuple_size) -> uint32_t {
206-
return static_cast<uint32_t>(tuple_size & (~DELETE_MASK));
207-
}
208-
};
209104
} // namespace bustub

0 commit comments

Comments
 (0)