diff options
author | Franciszek Malinka <franciszek.malinka@gmail.com> | 2022-11-07 13:46:28 +0100 |
---|---|---|
committer | Franciszek Malinka <franciszek.malinka@gmail.com> | 2022-11-07 17:22:06 +0100 |
commit | 2262c02e374876c35b47b0b24f2af8c6cc611282 (patch) | |
tree | 703f2abe2423d63a532c1b470a43e20930b082c2 | |
parent | c46f7874ee89d78af60826fce8bcf965eec958ec (diff) |
Added heap_file_test and debugged... a lot...
- Changed field vector in Tuple to unique_ptr vector
- Lesson: if we have a class that has a unique_ptr, then we need to move
this class instead of copying it!
- Added some minor stuff like default constructors etc.
-rw-r--r-- | .bazelrc | 7 | ||||
-rw-r--r-- | encoder/create-test-data.py | 2 | ||||
-rw-r--r-- | komfydb/common/int_field.h | 2 | ||||
-rw-r--r-- | komfydb/common/string_field.h | 2 | ||||
-rw-r--r-- | komfydb/common/td_item.cc | 2 | ||||
-rw-r--r-- | komfydb/common/td_item.h | 2 | ||||
-rw-r--r-- | komfydb/common/tuple.cc | 31 | ||||
-rw-r--r-- | komfydb/common/tuple.h | 8 | ||||
-rw-r--r-- | komfydb/common/tuple_desc.cc | 6 | ||||
-rw-r--r-- | komfydb/common/tuple_desc.h | 5 | ||||
-rw-r--r-- | komfydb/common/tuple_test.cc | 2 | ||||
-rw-r--r-- | komfydb/storage/BUILD | 10 | ||||
-rw-r--r-- | komfydb/storage/heap_file.cc | 21 | ||||
-rw-r--r-- | komfydb/storage/heap_file.h | 11 | ||||
-rw-r--r-- | komfydb/storage/heap_file_test.cc | 66 | ||||
-rw-r--r-- | komfydb/storage/heap_file_test.dat | bin | 0 -> 274432 bytes | |||
-rw-r--r-- | komfydb/storage/heap_page.cc | 21 | ||||
-rw-r--r-- | komfydb/storage/heap_page.h | 4 | ||||
-rw-r--r-- | komfydb/storage/record.h | 2 |
19 files changed, 139 insertions, 65 deletions
diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..0f96668 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,7 @@ +build --cxxopt='-std=c++17' --cxxopt='-march=native' + +build:asan --strip=never +build:asan --copt -fsanitize=address +build:asan --copt -g +build:asan --linkopt -fsanitize=address + diff --git a/encoder/create-test-data.py b/encoder/create-test-data.py index b14db75..684e39c 100644 --- a/encoder/create-test-data.py +++ b/encoder/create-test-data.py @@ -3,7 +3,9 @@ import sys f_name = sys.argv[1] n_tuples = int(sys.argv[2]) +seed = sys.argv[3] if len(sys.argv) > 3 else 2137 +random.seed(seed) alphabet = 'abcdefghjijklmnopqrstuvwxyz0123456789' diff --git a/komfydb/common/int_field.h b/komfydb/common/int_field.h index a2f9e36..f633f20 100644 --- a/komfydb/common/int_field.h +++ b/komfydb/common/int_field.h @@ -10,7 +10,7 @@ class IntField : public Field { int value; public: - IntField(int value); + IntField(int value = 0); ~IntField() override {} diff --git a/komfydb/common/string_field.h b/komfydb/common/string_field.h index 05fccbf..2af55ed 100644 --- a/komfydb/common/string_field.h +++ b/komfydb/common/string_field.h @@ -15,7 +15,7 @@ class StringField : public Field { std::string value; public: - StringField(const absl::string_view& s); + StringField(const absl::string_view& s = ""); ~StringField() override {} diff --git a/komfydb/common/td_item.cc b/komfydb/common/td_item.cc index bfcd30b..5857d9e 100644 --- a/komfydb/common/td_item.cc +++ b/komfydb/common/td_item.cc @@ -6,7 +6,7 @@ namespace komfydb::common { -TDItem::TDItem(const Type& t, absl::string_view name) +TDItem::TDItem(const Type t, absl::string_view name) : field_type(t), field_name(name) {} TDItem::operator std::string() const { diff --git a/komfydb/common/td_item.h b/komfydb/common/td_item.h index b628ff4..24868d4 100644 --- a/komfydb/common/td_item.h +++ b/komfydb/common/td_item.h @@ -11,7 +11,7 @@ namespace komfydb::common { class TDItem { public: - TDItem(const Type& t, absl::string_view name); + TDItem(const Type t, absl::string_view name); Type field_type; diff --git a/komfydb/common/tuple.cc b/komfydb/common/tuple.cc index 71544ce..4658260 100644 --- a/komfydb/common/tuple.cc +++ b/komfydb/common/tuple.cc @@ -9,24 +9,6 @@ namespace komfydb::common { Tuple::Tuple(const TupleDesc* td) : td(td) { fields.resize(td->Length()); - for (int i = 0; i < td->Length(); i++) { - switch (td->GetFieldType(i)->GetValue()) { - case Type::INT: - fields[i] = new IntField(0); - break; - case Type::STRING: - fields[i] = new StringField(""); - break; - default: - assert(false); - } - } -} - -Tuple::~Tuple() { - for (auto f : fields) { - delete f; - } } const TupleDesc* Tuple::GetTupleDesc() { @@ -37,20 +19,23 @@ absl::StatusOr<Field*> Tuple::GetField(int i) { if (fields.size() <= i || i < 0) { return absl::InvalidArgumentError("Index out of range"); } - return fields[i]; + if (fields[i] == nullptr) { + return absl::InvalidArgumentError("Field not set yet."); + } + return fields[i].get(); } // TODO(Tuple) This is bad imho. Here we assume that f is allocated by the // caller and what if this is not the case? We need to be careful.. -absl::Status Tuple::SetField(int i, Field* f) { +absl::Status Tuple::SetField(int i, std::unique_ptr<Field> f) { if (fields.size() <= i || i < 0) { return absl::InvalidArgumentError("Index out of range"); } - if (fields[i]->GetType() != f->GetType()) { + if (fields[i].get() && fields[i]->GetType() != f->GetType()) { return absl::InvalidArgumentError("Fields differ in type"); } - delete fields[i]; - fields[i] = f; + + fields[i] = std::move(f); return absl::OkStatus(); } diff --git a/komfydb/common/tuple.h b/komfydb/common/tuple.h index 7fd5be6..170c54d 100644 --- a/komfydb/common/tuple.h +++ b/komfydb/common/tuple.h @@ -18,18 +18,16 @@ class Tuple { protected: const TupleDesc* td; - std::vector<Field*> fields; + std::vector<std::unique_ptr<Field>> fields; public: - Tuple(const TupleDesc* td); - - ~Tuple(); + Tuple(const TupleDesc* td = nullptr); const TupleDesc* GetTupleDesc(); absl::StatusOr<Field*> GetField(int i); - absl::Status SetField(int i, Field* f); + absl::Status SetField(int i, std::unique_ptr<Field> f); operator std::string() const; diff --git a/komfydb/common/tuple_desc.cc b/komfydb/common/tuple_desc.cc index 7f9351c..93f6188 100644 --- a/komfydb/common/tuple_desc.cc +++ b/komfydb/common/tuple_desc.cc @@ -9,8 +9,8 @@ namespace komfydb::common { -TupleDesc::TupleDesc(std::vector<Type>& types, - std::vector<std::string>& fields) { +TupleDesc::TupleDesc(const std::vector<Type>& types, + const std::vector<std::string>& fields) { int sz = types.size(); items.reserve(sz); @@ -22,7 +22,7 @@ TupleDesc::TupleDesc(std::vector<Type>& types, } } -TupleDesc::TupleDesc(std::vector<Type>& types) { +TupleDesc::TupleDesc(const std::vector<Type>& types) { int sz = types.size(); items.reserve(sz); diff --git a/komfydb/common/tuple_desc.h b/komfydb/common/tuple_desc.h index 1b649b9..9ae36fe 100644 --- a/komfydb/common/tuple_desc.h +++ b/komfydb/common/tuple_desc.h @@ -13,9 +13,10 @@ namespace komfydb::common { class TupleDesc { public: - TupleDesc(std::vector<Type>& types, std::vector<std::string>& fields); + TupleDesc(const std::vector<Type>& types, + const std::vector<std::string>& fields); - TupleDesc(std::vector<Type>& types); + TupleDesc(const std::vector<Type>& types); TupleDesc(const TupleDesc& td1, const TupleDesc& td2); diff --git a/komfydb/common/tuple_test.cc b/komfydb/common/tuple_test.cc index aa1a12d..29ed8e4 100644 --- a/komfydb/common/tuple_test.cc +++ b/komfydb/common/tuple_test.cc @@ -18,7 +18,7 @@ TEST(Tuple, StringConversion) { TupleDesc td(tv, nv); Tuple tuple(&td); - EXPECT_TRUE(tuple.SetField(0, new IntField(1)).ok()); + EXPECT_TRUE(tuple.SetField(0, std::make_unique<IntField>(1)).ok()); auto f1 = tuple.GetField(0); ASSERT_TRUE(f1.ok()); diff --git a/komfydb/storage/BUILD b/komfydb/storage/BUILD index 583a7f3..2ed64a1 100644 --- a/komfydb/storage/BUILD +++ b/komfydb/storage/BUILD @@ -33,3 +33,13 @@ cc_library( ], visibility = ["//visibility:public"], ) + +cc_test( + name = "heap_file_test", + srcs = ["heap_file_test.cc"], + data = ["heap_file_test.dat"], + deps = [ + ":storage", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/komfydb/storage/heap_file.cc b/komfydb/storage/heap_file.cc index 078506d..dec3918 100644 --- a/komfydb/storage/heap_file.cc +++ b/komfydb/storage/heap_file.cc @@ -2,6 +2,7 @@ #include <fstream> #include <iostream> +#include <memory> #include "komfydb/common/tuple_desc.h" #include "komfydb/config.h" @@ -13,23 +14,26 @@ namespace komfydb::storage { uint32_t HeapFile::table_cnt = 0; -HeapFile::HeapFile(std::fstream& file, TupleDesc td, uint32_t table_id, +HeapFile::HeapFile(std::fstream file, TupleDesc td, uint32_t table_id, Permissions permissions) - : file(file), td(td), table_id(table_id), permissions(permissions) {} + : file(std::move(file)), + td(td), + table_id(table_id), + permissions(permissions) {} HeapFile::~HeapFile() { file.close(); } absl::StatusOr<std::unique_ptr<HeapFile>> HeapFile::Create( - const std::string& file_path, TupleDesc td, Permissions permissions) { + const absl::string_view file_path, TupleDesc td, Permissions permissions) { std::ios_base::openmode mode = std::ios::binary | std::ios::in; if (permissions == Permissions::READ_WRITE) { mode |= std::ios::out; } std::fstream file; - file.open(file_path, mode); + file.open(std::string(file_path), mode); if (!file.good()) { return absl::InvalidArgumentError("Could not open specified db file."); } @@ -42,11 +46,11 @@ absl::StatusOr<std::unique_ptr<HeapFile>> HeapFile::Create( } return std::unique_ptr<HeapFile>( - new HeapFile(file, td, ++table_cnt, permissions)); + new HeapFile(std::move(file), td, ++table_cnt, permissions)); } -std::fstream& HeapFile::GetFile() { - return file; +std::fstream* HeapFile::GetFile() { + return &file; } uint32_t HeapFile::GetId() { @@ -64,8 +68,7 @@ absl::StatusOr<std::unique_ptr<Page>> HeapFile::ReadPage(PageId id) { file.seekg(0, file.end); uint32_t file_length = file.tellg(); - - int page_pos = CONFIG_PAGE_SIZE * id.GetPageNumber(); + uint64_t page_pos = (uint64_t)CONFIG_PAGE_SIZE * (uint64_t)id.GetPageNumber(); if (page_pos >= file_length) { return absl::InvalidArgumentError("Page number out of range."); } diff --git a/komfydb/storage/heap_file.h b/komfydb/storage/heap_file.h index 7638bc6..9ccd494 100644 --- a/komfydb/storage/heap_file.h +++ b/komfydb/storage/heap_file.h @@ -4,6 +4,7 @@ #include <fstream> #include <iostream> #include <list> +#include <memory> #include "absl/status/status.h" #include "absl/status/statusor.h" @@ -20,9 +21,7 @@ namespace { using komfydb::common::Permissions; -using komfydb::common::Tuple; using komfydb::common::TupleDesc; -using komfydb::transaction::TransactionId; }; // namespace @@ -30,7 +29,7 @@ namespace komfydb::storage { class HeapFile : DbFile { private: - std::fstream& file; + std::fstream file; TupleDesc td; uint32_t table_id; Permissions permissions; @@ -39,16 +38,16 @@ class HeapFile : DbFile { // thread safe. Probably it would be better to get some file's hash code. static uint32_t table_cnt; - HeapFile(std::fstream& file, TupleDesc td, uint32_t table_id, + HeapFile(std::fstream file, TupleDesc td, uint32_t table_id, Permissions permissions); public: ~HeapFile(); static absl::StatusOr<std::unique_ptr<HeapFile>> Create( - const std::string& file_name, TupleDesc td, Permissions permissions); + const absl::string_view file_name, TupleDesc td, Permissions permissions); - std::fstream& GetFile(); + std::fstream* GetFile(); absl::StatusOr<std::unique_ptr<Page>> ReadPage(PageId id) override; diff --git a/komfydb/storage/heap_file_test.cc b/komfydb/storage/heap_file_test.cc new file mode 100644 index 0000000..0ad4dd4 --- /dev/null +++ b/komfydb/storage/heap_file_test.cc @@ -0,0 +1,66 @@ +#include "komfydb/storage/heap_file.h" + +#include <filesystem> +#include <vector> + +#include "gtest/gtest.h" + +#include "komfydb/config.h" +#include "komfydb/storage/heap_page.h" + +namespace { + +using namespace komfydb::storage; +using komfydb::common::Type; + +class HeapFileTest : public ::testing::Test { + protected: + const char* kTestDataFilePath = "komfydb/storage/heap_file_test.dat"; + const int tuples = 1000; + int tuple_sz; + int pages_cnt; + int tuples_per_page; + int table_id; + const std::vector<Type> types = {Type::INT, Type::STRING, Type::INT, + Type::STRING}; + std::unique_ptr<TupleDesc> td; + std::unique_ptr<HeapFile> hp; + + void SetUp() override { + td = std::make_unique<TupleDesc>(types); + tuple_sz = td->GetSize(); + tuples_per_page = (CONFIG_PAGE_SIZE * 8) / (tuple_sz * 8 + td->Length()); + pages_cnt = tuples / tuples_per_page; + + absl::StatusOr<std::unique_ptr<HeapFile>> status_or_hp = + HeapFile::Create(kTestDataFilePath, *td, Permissions::READ_ONLY); + + if (!status_or_hp.ok()) { + FAIL() << "HeapFile::Create failed: " << status_or_hp.status(); + } + + hp = std::move(status_or_hp.value()); + table_id = hp->GetId(); + } +}; + +TEST_F(HeapFileTest, ReadPageErrors) { + absl::StatusOr<std::unique_ptr<Page>> page; + + page = hp->ReadPage(PageId(table_id, pages_cnt + 1)); + ASSERT_FALSE(page.ok()); + EXPECT_EQ(page.status().message(), "Page number out of range."); + + page = hp->ReadPage(PageId(table_id + 1, 0)); + ASSERT_FALSE(page.ok()); + EXPECT_EQ(page.status().message(), "Table ID does not match."); +} + +TEST_F(HeapFileTest, ReadPage) { + absl::StatusOr<std::unique_ptr<Page>> page; + for (int i = 0; i < pages_cnt; i++) { + ASSERT_TRUE(hp->ReadPage(PageId(table_id, i)).ok()); + } +} + +}; // namespace diff --git a/komfydb/storage/heap_file_test.dat b/komfydb/storage/heap_file_test.dat Binary files differnew file mode 100644 index 0000000..971e8bd --- /dev/null +++ b/komfydb/storage/heap_file_test.dat diff --git a/komfydb/storage/heap_page.cc b/komfydb/storage/heap_page.cc index 2c99b98..fb19c9b 100644 --- a/komfydb/storage/heap_page.cc +++ b/komfydb/storage/heap_page.cc @@ -14,16 +14,19 @@ absl::StatusOr<bool> TuplePresent(std::vector<uint8_t>& header, int i) { return header[i / 8] & (1 << (i % 8)); } -IntField* ParseInt(std::vector<uint8_t>& data, int& data_idx) { - IntField* field = new IntField(*((int*)&data[data_idx])); +std::unique_ptr<IntField> ParseInt(std::vector<uint8_t>& data, int& data_idx) { + std::unique_ptr<IntField> field = + std::make_unique<IntField>(*((int*)&data[data_idx])); data_idx += Type::INT_LEN; return field; } -StringField* ParseString(std::vector<uint8_t>& data, int& data_idx) { - char* value = (char*)&data[data_idx]; +std::unique_ptr<StringField> ParseString(std::vector<uint8_t>& data, + int& data_idx) { + std::unique_ptr<StringField> value = + std::make_unique<StringField>((char*)&data[data_idx]); data_idx += Type::STR_LEN; - return new StringField(value); + return value; } void DumpString(Field* field, std::vector<uint8_t>& result) { @@ -56,7 +59,7 @@ absl::StatusOr<std::unique_ptr<HeapPage>> HeapPage::Create( header.insert(header.end(), data.begin(), data.begin() + header_len); for (int i = 0; i < n_slots; i++) { - Tuple tuple = Tuple(td); + Tuple tuple(td); for (int j = 0; j < n_fields; j++) { ASSIGN_OR_RETURN(Type field_type, td->GetFieldType(j)); @@ -67,11 +70,11 @@ absl::StatusOr<std::unique_ptr<HeapPage>> HeapPage::Create( RETURN_IF_ERROR(tuple.SetField(j, ParseString(data, data_idx))); } } - tuples.push_back(tuple); + tuples.push_back(std::move(tuple)); } return std::unique_ptr<HeapPage>( - new HeapPage(id, td, header, tuples, n_slots)); + new HeapPage(id, td, header, std::move(tuples), n_slots)); } PageId HeapPage::GetId() { @@ -99,7 +102,7 @@ absl::StatusOr<std::vector<uint8_t>> HeapPage::GetPageData() { result.insert(result.end(), td->GetSize(), '\0'); continue; } - Tuple tuple = tuples[i]; + Tuple& tuple = tuples[i]; for (int j = 0; j < tuple_len; j++) { ASSIGN_OR_RETURN(Type field_type, td->GetFieldType(j)); ASSIGN_OR_RETURN(Field * field, tuple.GetField(j)); diff --git a/komfydb/storage/heap_page.h b/komfydb/storage/heap_page.h index c68a14d..d87f79e 100644 --- a/komfydb/storage/heap_page.h +++ b/komfydb/storage/heap_page.h @@ -41,8 +41,8 @@ class HeapPage : public Page { : pid(pid), td(td), header(header), - tuples(tuples), - num_slots(num_slots){}; + tuples(std::move(tuples)), + num_slots(num_slots) {} public: ~HeapPage() override {} diff --git a/komfydb/storage/record.h b/komfydb/storage/record.h index 0807444..b6f9bad 100644 --- a/komfydb/storage/record.h +++ b/komfydb/storage/record.h @@ -19,7 +19,7 @@ namespace komfydb::storage { // and shouldn't have any code regarding I/O operations (i.e. storage) // That's why we need Record, which is a tuple residing on the disk and have // it's own RecordId. -class Record : Tuple, RecordId { +class Record : public Tuple, public RecordId { public: Record(const TupleDesc* td, PageId pid, int tuple_no) : Tuple(td), RecordId(pid, tuple_no) {} |