aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranciszek Malinka <franciszek.malinka@gmail.com>2022-11-07 13:46:28 +0100
committerFranciszek Malinka <franciszek.malinka@gmail.com>2022-11-07 17:22:06 +0100
commit2262c02e374876c35b47b0b24f2af8c6cc611282 (patch)
tree703f2abe2423d63a532c1b470a43e20930b082c2
parentc46f7874ee89d78af60826fce8bcf965eec958ec (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--.bazelrc7
-rw-r--r--encoder/create-test-data.py2
-rw-r--r--komfydb/common/int_field.h2
-rw-r--r--komfydb/common/string_field.h2
-rw-r--r--komfydb/common/td_item.cc2
-rw-r--r--komfydb/common/td_item.h2
-rw-r--r--komfydb/common/tuple.cc31
-rw-r--r--komfydb/common/tuple.h8
-rw-r--r--komfydb/common/tuple_desc.cc6
-rw-r--r--komfydb/common/tuple_desc.h5
-rw-r--r--komfydb/common/tuple_test.cc2
-rw-r--r--komfydb/storage/BUILD10
-rw-r--r--komfydb/storage/heap_file.cc21
-rw-r--r--komfydb/storage/heap_file.h11
-rw-r--r--komfydb/storage/heap_file_test.cc66
-rw-r--r--komfydb/storage/heap_file_test.datbin0 -> 274432 bytes
-rw-r--r--komfydb/storage/heap_page.cc21
-rw-r--r--komfydb/storage/heap_page.h4
-rw-r--r--komfydb/storage/record.h2
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
new file mode 100644
index 0000000..971e8bd
--- /dev/null
+++ b/komfydb/storage/heap_file_test.dat
Binary files differ
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) {}