From b924ad19a0a0471995022a29605758f849edb22c Mon Sep 17 00:00:00 2001 From: jonlee Date: Sat, 27 Apr 2019 22:13:52 -0400 Subject: [PATCH 01/33] [buffer_pool.h/cpp] Make attribute public: PAGE_SIZE --- src/database/buffer_pool.cpp | 4 ---- src/include/buffer_pool.h | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/database/buffer_pool.cpp b/src/database/buffer_pool.cpp index ecc366c..76409df 100644 --- a/src/database/buffer_pool.cpp +++ b/src/database/buffer_pool.cpp @@ -11,10 +11,6 @@ BufferPool::~BufferPool() { buffer_pool = nullptr; } -int BufferPool::get_page_size() { - return PAGE_SIZE; -} - Page * BufferPool::get_page(TransactionId * tid, PageId * pid, Permissions * perm) { diff --git a/src/include/buffer_pool.h b/src/include/buffer_pool.h index 64c68b9..e5425aa 100644 --- a/src/include/buffer_pool.h +++ b/src/include/buffer_pool.h @@ -28,14 +28,17 @@ class BufferPool { */ static const int DEFAULT_PAGES = 50; + /** + * Bytes per page, including header. + */ + static const int PAGE_SIZE = 4096; + std::vector PageList; BufferPool(int num_pages, Catalog * catalog); ~BufferPool(); - static int get_page_size(); - /** * Retrieve the specified page with the associated permissions. * Will acquire a lock and may block if that lock is held by another @@ -136,10 +139,6 @@ class BufferPool { void FlushPages(TransactionId * tid); private: - /** - * Bytes per page, including header. - */ - static const int PAGE_SIZE = 4096; std::vector * buffer_pool; From b98666fc9b2b821998a31df58a09c24b68460f55 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 21:56:17 -0400 Subject: [PATCH 02/33] [heap_page.h] Update attribute specifications --- src/include/heap_page.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/include/heap_page.h b/src/include/heap_page.h index f4e202e..95f55bb 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -89,11 +89,12 @@ class HeapPage : public Page { private: HeapPageId pid; - TupleDesc * td; - // std::byte * header; - Tuple * tuples; - int numSlots; - // std::byte * old_data; + TupleDesc table_schema; + std::vector tuples; + unsigned char * header; + unsigned char * old_data; + TransactionId * id_of_transaction_that_dirtied_page; + int number_of_slots; // byte oldDataLock = new byte(0); int read_index; From 4ac021b7a180ac90ef3412223d30d939cb56f360 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sat, 27 Apr 2019 22:53:46 -0400 Subject: [PATCH 03/33] Change method signature: Page::MarkDirty --- src/database/heap_page.cpp | 2 +- src/include/heap_page.h | 2 +- src/include/page.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 1841f1a..8d4a6db 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -42,7 +42,7 @@ const TransactionId * HeapPage::get_id_of_last_dirty_transaction() const { // return null; } -void HeapPage::MarkDirty(bool dirty, TransactionId & tid) { +void HeapPage::MarkDirty(bool dirty, TransactionId * tid) { } Page * HeapPage::GetBeforeImage() { diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 95f55bb..f245afd 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -39,7 +39,7 @@ class HeapPage : public Page { /** * Sets the dirty state of the page as dirtied by a particular transaction. */ - void MarkDirty(bool dirty, TransactionId & tid) override; + void MarkDirty(bool dirty, TransactionId * tid) override; /** * Returns a representation of the Page before any modifications were made to diff --git a/src/include/page.h b/src/include/page.h index e3b44e8..17a37db 100644 --- a/src/include/page.h +++ b/src/include/page.h @@ -35,7 +35,7 @@ class Page { /** * Sets the dirty state of the page as dirtied by a particular transaction. */ - virtual void MarkDirty(bool dirty, TransactionId & tid) = 0; + virtual void MarkDirty(bool dirty, TransactionId * tid) = 0; /* Need to use another input parameter type besides byte virtual void GetPageData(std::byte content_rep[]) = 0; From fa2b97cfde4d2a83940e8ce7f95ef48ea112f5e2 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:06:26 -0400 Subject: [PATCH 04/33] [heap_page.h/cpp] Update method specifications * get_number_of_tuples * IsSlotUsed * SetSlot * CreatePageDataRepresentation * CreateEmptyPageDataRepresentation * ReadInNextTuple * DeleteTuple * InsertTuple * AddTuple: removed * ParseIntoField: added --- src/database/heap_page.cpp | 28 ++++++++++++++++------------ src/include/heap_page.h | 24 ++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 8d4a6db..96dd7c0 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -63,7 +63,7 @@ Page * HeapPage::GetBeforeImage() { void HeapPage::SetBeforeImage() { } -int HeapPage::get_num_tuples() { +int HeapPage::get_number_of_tuples() { double pagesize = (double) Database::get_buffer_pool()->get_page_size() * 8; double tuplesize = (double) (td->get_size() * 8 + 1); double res = pagesize / tuplesize; @@ -71,12 +71,11 @@ int HeapPage::get_num_tuples() { } int HeapPage::get_header_size() { - double res = (double) numSlots / (double) 8; - return (int) ceil(res); + return (number_of_slots + 7) >> 3; } -/* -Tuple HeapPage::ReadNextTuple(byte[] data, int slotId) { +Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index) { if (!isSlotUsed(slotId)) { for (int i = 0; i < td.getSize(); i++) { try { @@ -103,22 +102,24 @@ Tuple HeapPage::ReadNextTuple(byte[] data, int slotId) { return t; } -void HeapPage::GetPageData(std::byte rep[]) { +void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { } -void HeapPage::CreateEmptyPageData(std::byte rep[]) { + /* flush byte stream: necessary? int len = BufferPool.getPageSize(); return new byte[len]; +void HeapPage::CreateEmptyPageDataRepresentation(unsigned char * rep) { +void HeapPage::DeleteTuple(Tuple * t) { } */ -void HeapPage::DeleteTuple(Tuple t) { +void HeapPage::InsertTuple(Tuple * t) { } -void HeapPage::InsertTuple(Tuple t) { + for (int slot_index = 0; slot_index < number_of_slots; slot_index++) { } -void HeapPage::AddTuple(Tuple t) { + throw DbException("This page is full."); } int HeapPage::GetNumEmptySlots() { @@ -130,7 +131,7 @@ int HeapPage::GetNumEmptySlots() { return count; } -bool HeapPage::IsSlotUsed(int i) { +bool HeapPage::IsSlotUsed(int index) { int x = i / 8; int y = i % 8; @@ -139,7 +140,7 @@ bool HeapPage::IsSlotUsed(int i) { */ } -void HeapPage::SetSlot(int i, bool value) { +void HeapPage::SetSlot(int index, bool updated_status_of_slot) { } /* Not implemented @@ -152,4 +153,7 @@ Iterator HeapPage::iterator() { return arr.iterator(); } */ +Field * HeapPage::ParseIntoField(Field::Type field_type, + std::stringstream * byte_stream_pointer) { +} } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index f245afd..4f93774 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -56,32 +56,29 @@ class HeapPage : public Page { /** * Returns the number of tuples in the heap page. */ - int get_num_tuples(); + int get_number_of_tuples(); /** * Returns the size of the heap page's header. */ int get_header_size(); - /* Not implemented - Tuple ReadNextTuple(DataInputStream dis, int slotId)(); - */ + Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index); - // void GetPageData(std::byte rep[]); + void CreatePageDataRepresentation(unsigned char * rep); - // static void CreateEmptyPageData(std::byte rep[]); + static void CreateEmptyPageDataRepresentation(unsigned char * rep); - void DeleteTuple(Tuple t); + void DeleteTuple(Tuple * t); - void InsertTuple(Tuple t); - - void AddTuple(Tuple t); + void InsertTuple(Tuple * t); int GetNumEmptySlots(); - bool IsSlotUsed(int i); + bool IsSlotUsed(int index); - void SetSlot(int i, bool value); + void SetSlot(int index, bool updated_status_of_slot); /* Not implemented Iterator iterator(); @@ -98,5 +95,8 @@ class HeapPage : public Page { // byte oldDataLock = new byte(0); int read_index; + + Field * ParseIntoField(Field::Type field_type, + std::stringstream * byte_stream_pointer); }; } From b9662312b62a060f5ff68875f081a470cdec6791 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 15:35:39 -0400 Subject: [PATCH 05/33] [heap_page.cpp] Reimplement method: get_header_size --- src/database/heap_page.cpp | 5 ++--- src/include/heap_page.h | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 96dd7c0..bbe56e9 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -74,8 +74,8 @@ int HeapPage::get_header_size() { return (number_of_slots + 7) >> 3; } -Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index) { +Tuple HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index) { if (!isSlotUsed(slotId)) { for (int i = 0; i < td.getSize(); i++) { try { @@ -111,7 +111,6 @@ void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { void HeapPage::CreateEmptyPageDataRepresentation(unsigned char * rep) { void HeapPage::DeleteTuple(Tuple * t) { } -*/ void HeapPage::InsertTuple(Tuple * t) { } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 4f93774..4211ce4 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "heap_page_id.h" #include "page.h" #include "transaction_id.h" @@ -63,8 +65,8 @@ class HeapPage : public Page { */ int get_header_size(); - Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index); + Tuple ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index); void CreatePageDataRepresentation(unsigned char * rep); From b131fffb3bf8600f697d69f91d2a78c466d30e35 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sat, 27 Apr 2019 23:09:21 -0400 Subject: [PATCH 06/33] [heap_page.cpp] Reimplement method: get_id_of_last_dirty_transaction --- src/database/heap_page.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index bbe56e9..dedc3bb 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -38,8 +38,7 @@ const PageId & HeapPage::get_id() const { } const TransactionId * HeapPage::get_id_of_last_dirty_transaction() const { - // some code goes here - // return null; + return id_of_transaction_that_dirtied_page; } void HeapPage::MarkDirty(bool dirty, TransactionId * tid) { From 3457458d07a93427e0fde447c9924bab0ded7eac Mon Sep 17 00:00:00 2001 From: jonlee Date: Sat, 27 Apr 2019 23:09:50 -0400 Subject: [PATCH 07/33] [heap_page.cpp] Reimplement method: MarkDirty --- src/database/heap_page.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index dedc3bb..bc649dd 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -42,6 +42,7 @@ const TransactionId * HeapPage::get_id_of_last_dirty_transaction() const { } void HeapPage::MarkDirty(bool dirty, TransactionId * tid) { + id_of_transaction_that_dirtied_page = dirty ? tid : nullptr; } Page * HeapPage::GetBeforeImage() { From 81db4090885cfce1e0bba62d34662873638ab01a Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 21:57:03 -0400 Subject: [PATCH 08/33] [heap_page.cpp] Reimplement method: SetBeforeImage --- src/database/heap_page.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index bc649dd..136fd95 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -61,6 +61,8 @@ Page * HeapPage::GetBeforeImage() { } void HeapPage::SetBeforeImage() { + delete[] old_data; + CreatePageDataRepresentation(old_data); } int HeapPage::get_number_of_tuples() { From 01a9f73a1778592b7ab8443c1fd2872b60ad26a9 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 15:21:30 -0400 Subject: [PATCH 09/33] [heap_page.cpp] Reimplement method: get_number_of_tuples --- src/database/heap_page.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 136fd95..a7bbb8a 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -66,10 +66,12 @@ void HeapPage::SetBeforeImage() { } int HeapPage::get_number_of_tuples() { - double pagesize = (double) Database::get_buffer_pool()->get_page_size() * 8; - double tuplesize = (double) (td->get_size() * 8 + 1); - double res = pagesize / tuplesize; - return (int) floor(res); + // bitwise shift left 3 bits to convert from bytes to bits + int page_size_in_bits = Database::get_buffer_pool()->PAGE_SIZE << 3; + int tuple_size_in_bits = table_schema.get_size() << 3; + int padding_bit = 1; + + return page_size_in_bits / (tuple_size_in_bits + padding_bit); } int HeapPage::get_header_size() { From 5a2e25eaef709a9119f2eb8239a37e7914de60ab Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 21:56:47 -0400 Subject: [PATCH 10/33] [heap_page.h/cpp] Reimplement constructor --- src/database/heap_page.cpp | 44 +++++++++++++++++++++----------------- src/include/heap_page.h | 2 +- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index a7bbb8a..1380acc 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -1,37 +1,41 @@ #include #include +#include #include "database.h" #include "heap_page.h" namespace buzzdb { -/** Temporarily not available, as std::byte is only available in C++ 17 -HeapPage::HeapPage(HeapPageId id, std::byte data[]) { - this->pid = id; - this->td = &(Database::get_catalog()->get_tuple_desc(id.get_table_id())); - this->numSlots = get_num_tuples(); - //DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); - this->read_index = 0; - - this->header = new std::byte[get_header_size()]; - for (int i = 0; i < sizeof(header) / sizeof(header[0]); i++) { - header[i] = data[read_index]; - read_index++; +/** + * Implementation is possibly wrong: + * - Interactions between sstreams and unsigned chars need to be tested + */ +HeapPage::HeapPage(HeapPageId & pid, unsigned char data[]) + : pid(pid), + table_schema(Database::get_catalog()->get_tuple_desc(pid.get_table_id())), + number_of_slots(get_number_of_tuples()), + header(new unsigned char[get_header_size()]), + tuples(0), + old_data(nullptr) { + std::stringstream byte_stream; + byte_stream << data; + + char input_char = 0; + for (int i = 0; i < get_header_size(); i++) { + // TODO: handle IO exception + byte_stream.get(input_char); + header[i] = input_char; } - this->tuples = new Tuple[numSlots]; try { - // allocate and read the actual records of this page - for (int i = 0; i < sizeof(tuples) / sizeof(tuples[0]); i++) { - ReadNextTuple is not declared - tuples[i] = ReadNextTuple(data, i); + for (int i = 0; i < number_of_slots; i++) { + tuples.push_back(ReadInNextTuple(&byte_stream, i)); } - } catch (std::exception e) { - std::cout << "Exception occurred"; + } catch (NoSuchElementException e) { + // print stack trace } SetBeforeImage(); } -*/ const PageId & HeapPage::get_id() const { return pid; diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 4211ce4..16b415d 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -24,8 +24,8 @@ class HeapPage : public Page { /** * Constructor. - HeapPage(HeapPageId id, std::byte data[]); */ + HeapPage(HeapPageId & id, unsigned char data[]); /** * Returns the id of the page. From 33efc6ece9905d61a3b8de9c1c710732be8762ad Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 15:22:35 -0400 Subject: [PATCH 11/33] [heap_page.cpp] Reimplement method: GetBeforeImage --- src/database/heap_page.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 1380acc..f1caa0f 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -3,6 +3,7 @@ #include #include "database.h" #include "heap_page.h" +#include "no_such_element_exception.h" namespace buzzdb { /** @@ -49,19 +50,16 @@ void HeapPage::MarkDirty(bool dirty, TransactionId * tid) { id_of_transaction_that_dirtied_page = dirty ? tid : nullptr; } +// uses dynamic memory allocatiom: BEWARE +// update documentation to reflect this +// ensure that memory is released after use Page * HeapPage::GetBeforeImage() { try { - /* - std::byte * old_data_ref = nullptr; - old_data_ref = old_data; - return new HeapPage(pid, old_data_ref); - */ - return new HeapPage(); - } catch (std::exception e) { - /* - System.exit(1); - */ + return new HeapPage(pid, old_data); + } catch (std::exception io_exception) { + // implement properly } + return nullptr; } void HeapPage::SetBeforeImage() { From 265feef7286aab57a3d587b86bc11e7475781325 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 15:23:05 -0400 Subject: [PATCH 12/33] [heap_page.cpp] Reimplement method: IsSlotUsed --- src/database/heap_page.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index f1caa0f..68ec526 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -137,12 +137,8 @@ int HeapPage::GetNumEmptySlots() { } bool HeapPage::IsSlotUsed(int index) { - int x = i / 8; - int y = i % 8; - - /* Error here - return ((header[x] >> y) & 1) == 1; - */ + // why? + return (header[index >> 3] & (1 << (index & 7))) != 0; } void HeapPage::SetSlot(int index, bool updated_status_of_slot) { From 69bb2d12468966cb32ff44d13dc7232b0e48fe15 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:11:35 -0400 Subject: [PATCH 13/33] [heap_page.cpp] Reimplement method: SetSlot --- src/database/heap_page.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 68ec526..628c3f2 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -142,6 +142,12 @@ bool HeapPage::IsSlotUsed(int index) { } void HeapPage::SetSlot(int index, bool updated_status_of_slot) { + // why? + if (updated_status_of_slot) { + header[index >> 3] |= (1 << (index & 7)); + } else { + header[index >> 3] &= ~(1 << (index & 7)); + } } /* Not implemented From 41c5aa96f4cf195ffecfd04e2c2f7cfe25a51e92 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 15:41:36 -0400 Subject: [PATCH 14/33] [heap_page.cpp] Clean up include statements --- src/database/heap_page.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 628c3f2..1fe03dc 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include "database.h" #include "heap_page.h" #include "no_such_element_exception.h" From 867485981b0c54ae34ca3ec4c728c7bb3f87ec62 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 16:20:53 -0400 Subject: [PATCH 15/33] [heap_page.cpp] Reimplement function: ReadInNextTuple --- src/database/heap_page.cpp | 47 +++++++++++++++++++++++--------------- src/include/heap_page.h | 4 ++-- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 1fe03dc..27a3f14 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -77,32 +77,43 @@ int HeapPage::get_header_size() { return (number_of_slots + 7) >> 3; } -Tuple HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index) { - if (!isSlotUsed(slotId)) { - for (int i = 0; i < td.getSize(); i++) { +// uses dynamic memory allocatiom: BEWARE +// update documentation to reflect this +// ensure that memory is released after use +Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index) { + char input_char = 0; + if (!IsSlotUsed(slot_index)) { + for (int i = 0; i < table_schema.get_size(); i++) { try { - readIndex++; - } catch (IOException e) { - throw new NoSuchElementException("error reading empty tuple"); + byte_stream_pointer->get(input_char); + } catch (std::exception io_exception) { + // change catch type + throw NoSuchElementException("Error reading empty tuple"); } } - return null; + return nullptr; } - // read fields in the tuple - tuple t = new tuple(td); - RecordId rid = new RecordId(pid, slotId); - t.setRecordId(rid); + Tuple * next_tuple = new Tuple(table_schema); + RecordId * rid = new RecordId(pid, slot_index); + next_tuple->set_record_id(rid); + try { - for (int j = 0; j < td.numFields(); j++) { - field f = td.getFieldType(j).parse(dis); - t.setField(j, f); + for (int field_index = 0; + field_index < table_schema.get_number_fields(); + field_index++) { + Field::Type field_type = table_schema.get_field_type(field_index); + Field * parsed_field = ParseIntoField(field_type, byte_stream_pointer); + // bad design; introduces coupling with Field class and its subclasses + next_tuple->set_field(field_index, parsed_field); } - } catch (Exception e) { - throw new NoSuchElementException("parsing error!"); + } catch (std::exception e) { + // change catch type + throw NoSuchElementException("Parsing error."); } - return t; + + return next_tuple; } void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 16b415d..774de59 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -65,8 +65,8 @@ class HeapPage : public Page { */ int get_header_size(); - Tuple ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index); + Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index); void CreatePageDataRepresentation(unsigned char * rep); From ecef692d4e6465cd6d4c17cdee880f25180ad7db Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 21:55:16 -0400 Subject: [PATCH 16/33] Add method to Field interface specification: Serialize --- src/database/integer_field.cpp | 4 ++++ src/database/string_field.cpp | 4 ++++ src/include/field.h | 6 +++--- src/include/integer_field.h | 4 +--- src/include/string_field.h | 4 +--- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/database/integer_field.cpp b/src/database/integer_field.cpp index c980a59..c7b3e2f 100644 --- a/src/database/integer_field.cpp +++ b/src/database/integer_field.cpp @@ -17,6 +17,10 @@ Field::Type IntegerField::get_type() const { return Type::INTEGER; } +void IntegerField::Serialize(std::stringstream * byte_stream) { + // to be implemented +} + /* bool IntegerField::Compare(Predicate::OpType op_type, Field * operand) { IntegerField * operand_value_pointer = static_cast(operand); diff --git a/src/database/string_field.cpp b/src/database/string_field.cpp index cb8a0e1..17c4487 100644 --- a/src/database/string_field.cpp +++ b/src/database/string_field.cpp @@ -17,6 +17,10 @@ Field::Type StringField::get_type() const { return Type::STRING; } +void StringField::Serialize(std::stringstream * byte_stream) { + // to be implemented +} + /* bool StringField::Compare(Predicate::OpType op_type, Field * operand) { StringField * operand_value_pointer = static_cast(operand); diff --git a/src/include/field.h b/src/include/field.h index 513bf23..aea4250 100644 --- a/src/include/field.h +++ b/src/include/field.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace buzzdb { /** * The Field abstract class is an interface for a field in a tuple. @@ -29,9 +31,7 @@ class Field { /** * Write the bytes representing the field to the specified Stream. */ - /* - virtual void serialize(DataOutputStream dos) = 0; - */ + virtual void Serialize(std::stringstream * byte_stream) = 0; /** * Compares the value of the Field to the value of operand. diff --git a/src/include/integer_field.h b/src/include/integer_field.h index d0eb6ec..9c962e1 100644 --- a/src/include/integer_field.h +++ b/src/include/integer_field.h @@ -37,9 +37,7 @@ class IntegerField : public Field { /** * Write the bytes representing the IntegerField to the specified Stream. */ - /* To be implemented - void serialize(DataOutputStream dos) override; - */ + void Serialize(std::stringstream * byte_stream) override; /** * Compares the value of the IntegerField to the value of operand. diff --git a/src/include/string_field.h b/src/include/string_field.h index a26f4dc..7e10584 100644 --- a/src/include/string_field.h +++ b/src/include/string_field.h @@ -38,9 +38,7 @@ class StringField : public Field { /** * Write the bytes representing the StringField to the specified Stream. */ - /* To be implemented - void serialize(DataOutputStream dos) override; - */ + void Serialize(std::stringstream * byte_stream) override; /** * Compares the value of the StringField to the value of operand. From e73f8f97497d09d460f38e3936d779dae3d4f587 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:02:56 -0400 Subject: [PATCH 17/33] [heap_page.cpp] Reimplement method: CreatePageDataRepresentation --- src/database/heap_page.cpp | 75 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 27a3f14..a19aab2 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -1,3 +1,4 @@ +#include #include "database.h" #include "heap_page.h" #include "no_such_element_exception.h" @@ -117,11 +118,79 @@ Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, } void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { -} + std::stringstream byte_stream; + + // write header to stream + // might not be correct to read whole array into stream + // how about the ending characters in an array? + try { + byte_stream << *header; + } catch (std::exception io_exception) { + // change catch type + // print stack trace + } + + // write tuples to stream + for (int slot_index = 0; slot_index < number_of_slots; slot_index++) { + // slot has no tuple in it; add empty tuple to stream + if (!IsSlotUsed(slot_index)) { + for (int i = 0; i < table_schema.get_size(); i++) { + try { + byte_stream << '0'; + } catch (std::exception io_exception) { + // change catch type + // print stack trace + } + } + continue; + } + + // slot has a tuple; add it to stream + Tuple * tuple_at_slot_index = tuples.at(slot_index); + for (int field_index = 0; + field_index < table_schema.get_number_fields(); + field_index) { + Field * field = tuple_at_slot_index->get_field(field_index); + try { + field->Serialize(&byte_stream); + } catch (std::exception io_exception) { + // change catch type + // print stack trace + } + } + } + + // add padding to stream: fill the remaining space with zeroes + // the number of elements in the byte array should = BufferPool::PAGE_SIZE. + int padding_length = BufferPool::PAGE_SIZE + - (get_header_size() + + table_schema.get_size() * number_of_slots); + unsigned char padding[padding_length] = {0}; + + try { + byte_stream << padding; + } catch (std::exception io_exception) { + // change catch type + // print stack trace + } /* flush byte stream: necessary? - int len = BufferPool.getPageSize(); - return new byte[len]; + try { + // flush byte stream + } catch (std::exception io_exception) { + // change catch type + // print stack trace + } + */ + + // extracting the byte_stream contents into an unsigned char array + std::string bs_string_rep = byte_stream.str(); + char * bs_char_array_rep = new char[BufferPool::PAGE_SIZE]; + strncpy(bs_char_array_rep, bs_string_rep.c_str(), BufferPool::PAGE_SIZE); + + rep = (unsigned char *) bs_char_array_rep; +} + void HeapPage::CreateEmptyPageDataRepresentation(unsigned char * rep) { void HeapPage::DeleteTuple(Tuple * t) { } From d6ee6894fd4f0d7348e5c94bf170dea9d9cb0465 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:02:40 -0400 Subject: [PATCH 18/33] [heap_page.cpp] Reimplement method: CreateEmptyPageDataRepresentation --- src/database/heap_page.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index a19aab2..1f439e5 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -192,6 +192,9 @@ void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { } void HeapPage::CreateEmptyPageDataRepresentation(unsigned char * rep) { + rep = new unsigned char[BufferPool::PAGE_SIZE]; +} + void HeapPage::DeleteTuple(Tuple * t) { } From f6c194226345bbea5b41403c01f983111d79dfe8 Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:04:31 -0400 Subject: [PATCH 19/33] [heap_page.cpp] Reimplement method: DeleteTuple --- src/database/heap_page.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 1f439e5..bb0fcbc 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -1,6 +1,7 @@ #include #include "database.h" #include "heap_page.h" +#include "db_exception.h" #include "no_such_element_exception.h" namespace buzzdb { @@ -196,6 +197,20 @@ void HeapPage::CreateEmptyPageDataRepresentation(unsigned char * rep) { } void HeapPage::DeleteTuple(Tuple * t) { + if (pid == t->get_record_id()->get_page_id()) { + int tuple_number = t->get_record_id()->get_tuple_number(); + + if (tuple_number >= 0 + && tuple_number < number_of_slots + && IsSlotUsed(tuple_number)) { + SetSlot(tuple_number, false); + // update tuple's record id + delete t->get_record_id(); + t->set_record_id(nullptr); + } + } + + throw DbException("Tuple not found on page"); } void HeapPage::InsertTuple(Tuple * t) { From dc7a99e4465e1b745075b394e3494b3886984d2b Mon Sep 17 00:00:00 2001 From: jonlee Date: Sun, 28 Apr 2019 22:04:44 -0400 Subject: [PATCH 20/33] [heap_page.cpp] Reimplement method: InsertTuple --- src/database/heap_page.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index bb0fcbc..27ff3e4 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -214,10 +214,24 @@ void HeapPage::DeleteTuple(Tuple * t) { } void HeapPage::InsertTuple(Tuple * t) { -} + if (table_schema != t->get_tuple_desc()) { + throw DbException("Schema mismatch: Table and tuple"); + } + if (t->get_record_id() != nullptr) { + if (pid == t->get_record_id()->get_page_id()) { + throw DbException("Tuple already resides on this page."); + } + throw DbException("Tuple already resides on another page."); + } for (int slot_index = 0; slot_index < number_of_slots; slot_index++) { -} + if (!IsSlotUsed(slot_index)) { + tuples.at(slot_index) = t; + t->set_record_id(new RecordId(pid, slot_index)); + SetSlot(slot_index, true); + return; + } + } throw DbException("This page is full."); } From 864f2a06bcb0243568a1fe141aef6a583ece4361 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 02:07:27 -0400 Subject: [PATCH 21/33] [heap_page.h/cpp] Change method visibility: ReadInNextTuple --- src/database/heap_page.cpp | 77 +++++++++++++++++++------------------- src/include/heap_page.h | 6 +-- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 27ff3e4..f967a71 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -79,45 +79,6 @@ int HeapPage::get_header_size() { return (number_of_slots + 7) >> 3; } -// uses dynamic memory allocatiom: BEWARE -// update documentation to reflect this -// ensure that memory is released after use -Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index) { - char input_char = 0; - if (!IsSlotUsed(slot_index)) { - for (int i = 0; i < table_schema.get_size(); i++) { - try { - byte_stream_pointer->get(input_char); - } catch (std::exception io_exception) { - // change catch type - throw NoSuchElementException("Error reading empty tuple"); - } - } - return nullptr; - } - - Tuple * next_tuple = new Tuple(table_schema); - RecordId * rid = new RecordId(pid, slot_index); - next_tuple->set_record_id(rid); - - try { - for (int field_index = 0; - field_index < table_schema.get_number_fields(); - field_index++) { - Field::Type field_type = table_schema.get_field_type(field_index); - Field * parsed_field = ParseIntoField(field_type, byte_stream_pointer); - // bad design; introduces coupling with Field class and its subclasses - next_tuple->set_field(field_index, parsed_field); - } - } catch (std::exception e) { - // change catch type - throw NoSuchElementException("Parsing error."); - } - - return next_tuple; -} - void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { std::stringstream byte_stream; @@ -271,5 +232,43 @@ Iterator HeapPage::iterator() { */ Field * HeapPage::ParseIntoField(Field::Type field_type, std::stringstream * byte_stream_pointer) { +// update documentation to reflect this +// ensure that memory is released after use +Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index) { + char input_char = 0; + if (!IsSlotUsed(slot_index)) { + for (int i = 0; i < table_schema.get_size(); i++) { + try { + byte_stream_pointer->get(input_char); + } catch (std::exception io_exception) { + // change catch type + throw NoSuchElementException("Error reading empty tuple"); + } + } + return nullptr; + } + + Tuple * next_tuple = new Tuple(table_schema); + RecordId * rid = new RecordId(pid, slot_index); + next_tuple->set_record_id(rid); + + try { + for (int field_index = 0; + field_index < table_schema.get_number_fields(); + field_index++) { + Field::Type field_type = table_schema.get_field_type(field_index); + Field * parsed_field = ParseIntoField(byte_stream_pointer, field_type); + // bad design; introduces coupling with Field class and its subclasses + next_tuple->set_field(field_index, parsed_field); + } + } catch (std::exception e) { + // change catch type + throw NoSuchElementException("Parsing error."); + } + + return next_tuple; +} + } } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 774de59..eedc980 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -65,9 +65,6 @@ class HeapPage : public Page { */ int get_header_size(); - Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, - int slot_index); - void CreatePageDataRepresentation(unsigned char * rep); static void CreateEmptyPageDataRepresentation(unsigned char * rep); @@ -97,6 +94,9 @@ class HeapPage : public Page { // byte oldDataLock = new byte(0); int read_index; + */ + Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, + int slot_index); Field * ParseIntoField(Field::Type field_type, std::stringstream * byte_stream_pointer); From 06eba003f7e0ed26ecf55543b233352e42ab2ba0 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 01:57:57 -0400 Subject: [PATCH 22/33] [heap_page.h/cpp] Change method signature: ParseIntoField --- src/database/heap_page.cpp | 6 ++++-- src/include/heap_page.h | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index f967a71..1e994bc 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -230,8 +230,8 @@ Iterator HeapPage::iterator() { return arr.iterator(); } */ -Field * HeapPage::ParseIntoField(Field::Type field_type, - std::stringstream * byte_stream_pointer) { + +// uses dynamic memory allocatiom: BEWARE // update documentation to reflect this // ensure that memory is released after use Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, @@ -270,5 +270,7 @@ Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, return next_tuple; } +Field * HeapPage::ParseIntoField(std::stringstream * byte_stream_pointer, + Field::Type field_type) { } } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index eedc980..c2e97c9 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -92,13 +92,13 @@ class HeapPage : public Page { TransactionId * id_of_transaction_that_dirtied_page; int number_of_slots; - // byte oldDataLock = new byte(0); - int read_index; + /** + * Reads in a new tuple from the given byte stream. */ Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, int slot_index); - Field * ParseIntoField(Field::Type field_type, - std::stringstream * byte_stream_pointer); + Field * ParseIntoField(std::stringstream * byte_stream_pointer, + Field::Type field_type); }; } From 43d5ab8180219f6db12e54aa575b34506b3493e7 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 01:59:28 -0400 Subject: [PATCH 23/33] [page.h] Update documentation --- src/include/page.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/page.h b/src/include/page.h index 17a37db..b0a61ba 100644 --- a/src/include/page.h +++ b/src/include/page.h @@ -6,11 +6,12 @@ namespace buzzdb { /** * The Page interface class is an interface for page representations. + * - This interface is largely utilized by the BufferPool. * - A page contains tuples, which contain fields. - * - A page is contained in a table, which is typically implemented as a DbFile. - * - * Pages may be "dirty", meaning that they have been modified since they - * were last written out to disk. + * - A page is contained in a table, which is typically implemented as a + * DbFile. + * - A page may be "dirty", meaning that it has been modified since it was last + * written out to disk. */ class Page { public: From 8ee4ebf198d843916f273c483843e0ca0ddf6b8f Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 02:07:12 -0400 Subject: [PATCH 24/33] [heap_page.h/cpp] Rename method: ParseNextTuple --- src/database/heap_page.cpp | 8 ++++---- src/include/heap_page.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 1e994bc..7950a52 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -28,7 +28,7 @@ HeapPage::HeapPage(HeapPageId & pid, unsigned char data[]) try { for (int i = 0; i < number_of_slots; i++) { - tuples.push_back(ReadInNextTuple(&byte_stream, i)); + tuples.push_back(ParseNextTuple(&byte_stream, i)); } } catch (NoSuchElementException e) { // print stack trace @@ -234,7 +234,7 @@ Iterator HeapPage::iterator() { // uses dynamic memory allocatiom: BEWARE // update documentation to reflect this // ensure that memory is released after use -Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, +Tuple * HeapPage::ParseNextTuple(std::stringstream * byte_stream_pointer, int slot_index) { char input_char = 0; if (!IsSlotUsed(slot_index)) { @@ -243,7 +243,7 @@ Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, byte_stream_pointer->get(input_char); } catch (std::exception io_exception) { // change catch type - throw NoSuchElementException("Error reading empty tuple"); + throw NoSuchElementException("Error parsing empty tuple."); } } return nullptr; @@ -264,7 +264,7 @@ Tuple * HeapPage::ReadInNextTuple(std::stringstream * byte_stream_pointer, } } catch (std::exception e) { // change catch type - throw NoSuchElementException("Parsing error."); + throw NoSuchElementException("Error parsing tuple."); } return next_tuple; diff --git a/src/include/heap_page.h b/src/include/heap_page.h index c2e97c9..e993a25 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -95,7 +95,7 @@ class HeapPage : public Page { /** * Reads in a new tuple from the given byte stream. */ - Tuple * ReadInNextTuple(std::stringstream * byte_stream_pointer, + Tuple * ParseNextTuple(std::stringstream * byte_stream_pointer, int slot_index); Field * ParseIntoField(std::stringstream * byte_stream_pointer, From e88166f72aa1dca0eaa1665b82fd6d8426974d6f Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 02:16:32 -0400 Subject: [PATCH 25/33] [heap_page.h/cpp] Implement destructor --- src/database/heap_page.cpp | 10 ++++++++++ src/include/heap_page.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 7950a52..30a874b 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -37,6 +37,16 @@ HeapPage::HeapPage(HeapPageId & pid, unsigned char data[]) SetBeforeImage(); } +HeapPage::~HeapPage() { + for (int slot_index = 0; slot_index < number_of_slots; slot_index++) { + delete tuples.at(slot_index); + } + + delete[] header; + delete[] old_data; + delete id_of_transaction_that_dirtied_page; +} + const PageId & HeapPage::get_id() const { return pid; } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index e993a25..2a192f2 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -22,6 +22,11 @@ class HeapPage : public Page { */ HeapPage(); + /** + * Destructor + */ + ~HeapPage(); + /** * Constructor. */ From a82f7a5bad0fdb7c5d14f39fea17acdfdca30aa8 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 02:53:59 -0400 Subject: [PATCH 26/33] [heap_page.h] Delete default constructor --- src/include/heap_page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 2a192f2..9e4b66e 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -20,7 +20,7 @@ class HeapPage : public Page { /** * Default constructor. */ - HeapPage(); + HeapPage() = delete; /** * Destructor From 7770faa1b4957ec9d256c433fd03d260464b8d63 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 02:54:35 -0400 Subject: [PATCH 27/33] [heap_page.h/cpp] Update documentation --- src/database/heap_page.cpp | 4 +++ src/include/heap_page.h | 57 ++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 30a874b..d205f5a 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -96,6 +96,7 @@ void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { // might not be correct to read whole array into stream // how about the ending characters in an array? try { + // correctness needs to be checked byte_stream << *header; } catch (std::exception io_exception) { // change catch type @@ -246,6 +247,8 @@ Iterator HeapPage::iterator() { // ensure that memory is released after use Tuple * HeapPage::ParseNextTuple(std::stringstream * byte_stream_pointer, int slot_index) { + // if the slot is not set to be used, move internal stream pointer forward + // to next tuple, and return nullptr char input_char = 0; if (!IsSlotUsed(slot_index)) { for (int i = 0; i < table_schema.get_size(); i++) { @@ -259,6 +262,7 @@ Tuple * HeapPage::ParseNextTuple(std::stringstream * byte_stream_pointer, return nullptr; } + // otherwise, parse the tuple. Tuple * next_tuple = new Tuple(table_schema); RecordId * rid = new RecordId(pid, slot_index); next_tuple->set_record_id(rid); diff --git a/src/include/heap_page.h b/src/include/heap_page.h index 9e4b66e..bc34621 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -11,9 +11,6 @@ namespace buzzdb { /** * The HeapPage class represents a page in a table implemented as a HeapFile. * - This class implements the Page interface. - * - * Some functions are not available because they use std::byte, which is only - * available in C++ 17. Currently working on a different way to represent pages */ class HeapPage : public Page { public: @@ -29,6 +26,8 @@ class HeapPage : public Page { /** * Constructor. + * - data is a representation of a page's data and will be parsed by the + * constructor to build the new HeapPage. */ HeapPage(HeapPageId & id, unsigned char data[]); @@ -50,7 +49,9 @@ class HeapPage : public Page { /** * Returns a representation of the Page before any modifications were made to - * it. Used by recovery. + * it. + * + * Used by recovery. */ Page * GetBeforeImage() override; @@ -70,18 +71,58 @@ class HeapPage : public Page { */ int get_header_size(); + /** + * Generates an unsigned char array representing the heap page's contents. + * + * Used to serialize the page to disk. + * When the array created is parsed into the HeapPage constructor, a new + * heap page with identical contents should be created. + */ void CreatePageDataRepresentation(unsigned char * rep); + /** + * Generated an unsigned char array representing an empty heap page's + * contents. + */ static void CreateEmptyPageDataRepresentation(unsigned char * rep); + /** + * Deletes the specified tuple from the heap page. + * + * The tuple's record id will be updated accordingly. + * + * Throws: + * - DbException: If the tuple is not on the heap page, + * or if the tuple's slot is already empty. + */ void DeleteTuple(Tuple * t); + /** + * Adds the specified tuple to the heap page. + * + * The tuple's record id will be updated accordingly. + * + * Throws: + * - DbException: If the tuple's schema does not match the table's scheme, + * or if the tuple already resides on a page, + * or if the heap page has no empty slots. + */ void InsertTuple(Tuple * t); + /** + * Returns the number of empty slots on the heap page. + */ int GetNumEmptySlots(); + /** + * Returns true if the slot given by the index is filled, + * and false otherwise. + */ bool IsSlotUsed(int index); + /** + * Fills or clears a slot on the heap page. + */ void SetSlot(int index, bool updated_status_of_slot); /* Not implemented @@ -98,7 +139,13 @@ class HeapPage : public Page { int number_of_slots; /** - * Reads in a new tuple from the given byte stream. + * If the slot given by slot_index is set to be used, the next tuple is + * parsed from the given byte stream and returned. Otherwise, the internal + * stream pointer is moved forward to the next tuple and a nullptr is + * returned. + * + * Throws: + * - NoSuchElementException: If there is an error while parsing the tuple. */ Tuple * ParseNextTuple(std::stringstream * byte_stream_pointer, int slot_index); From 1d533763256c74110a4768d5069609d56a9961ea Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 03:01:30 -0400 Subject: [PATCH 28/33] Fix build errors --- src/database/buffer_pool.cpp | 4 ++-- src/database/heap_file.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/buffer_pool.cpp b/src/database/buffer_pool.cpp index 76409df..9c30dfe 100644 --- a/src/database/buffer_pool.cpp +++ b/src/database/buffer_pool.cpp @@ -122,7 +122,7 @@ void BufferPool::InsertTuple(TransactionId * tid, int table_id, Tuple * t) { std::vector page_vector = catalog->get_db_file(table_id)->AddTuple(*tid, *t); for (Page * page: page_vector) { - page->MarkDirty(true, *tid); + page->MarkDirty(true, tid); } } @@ -132,7 +132,7 @@ void BufferPool::DeleteTuple(TransactionId * tid, Tuple * t) { DbFile * db_file = catalog->get_db_file(table_id); - db_file->DeleteTuple(*tid, *t)->MarkDirty(true, *tid); + db_file->DeleteTuple(*tid, *t)->MarkDirty(true, tid); } void BufferPool::FlushAllPages() { diff --git a/src/database/heap_file.cpp b/src/database/heap_file.cpp index c41e2d0..853cd40 100644 --- a/src/database/heap_file.cpp +++ b/src/database/heap_file.cpp @@ -25,7 +25,7 @@ TupleDesc HeapFile::get_tuple_desc() const { } int HeapFile::get_num_pages() { - return (int) ceil(ftell(file) / BufferPool::get_page_size()); + return (int) ceil(ftell(file) / BufferPool::PAGE_SIZE); } Page * HeapFile::ReadPage(PageId * pid) { From 063772cf6cfe56b19516eb642f2d0caa93162eac Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 03:32:07 -0400 Subject: [PATCH 29/33] Fix build warnings --- src/database/heap_page.cpp | 13 ++++++++----- src/include/heap_page.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index d205f5a..53651cb 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -13,9 +13,10 @@ HeapPage::HeapPage(HeapPageId & pid, unsigned char data[]) : pid(pid), table_schema(Database::get_catalog()->get_tuple_desc(pid.get_table_id())), number_of_slots(get_number_of_tuples()), - header(new unsigned char[get_header_size()]), tuples(0), - old_data(nullptr) { + header(new unsigned char[get_header_size()]), + old_data(nullptr), + id_of_transaction_that_dirtied_page(nullptr) { std::stringstream byte_stream; byte_stream << data; @@ -122,7 +123,7 @@ void HeapPage::CreatePageDataRepresentation(unsigned char * rep) { Tuple * tuple_at_slot_index = tuples.at(slot_index); for (int field_index = 0; field_index < table_schema.get_number_fields(); - field_index) { + field_index++) { Field * field = tuple_at_slot_index->get_field(field_index); try { field->Serialize(&byte_stream); @@ -210,8 +211,8 @@ void HeapPage::InsertTuple(Tuple * t) { int HeapPage::GetNumEmptySlots() { int count = 0; - for (int i = 0; i < sizeof(tuples) / sizeof(tuples[0]); ++i) { - if (!IsSlotUsed(i)) + for (int slot_index = 0; slot_index < number_of_slots; slot_index++) { + if (!IsSlotUsed(slot_index)) count++; } return count; @@ -286,5 +287,7 @@ Tuple * HeapPage::ParseNextTuple(std::stringstream * byte_stream_pointer, Field * HeapPage::ParseIntoField(std::stringstream * byte_stream_pointer, Field::Type field_type) { + // to be implemented + return nullptr; } } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index bc34621..f2663f6 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -132,11 +132,11 @@ class HeapPage : public Page { private: HeapPageId pid; TupleDesc table_schema; + int number_of_slots; std::vector tuples; unsigned char * header; unsigned char * old_data; TransactionId * id_of_transaction_that_dirtied_page; - int number_of_slots; /** * If the slot given by slot_index is set to be used, the next tuple is From a9f9c1c96c5f449f3d193ce673a64eb988973081 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 04:50:49 -0400 Subject: [PATCH 30/33] [heap_page.h/cpp] Rename method: ParseStreamForTuple --- src/database/heap_page.cpp | 6 +++--- src/include/heap_page.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index 53651cb..bbfc5cd 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -29,7 +29,7 @@ HeapPage::HeapPage(HeapPageId & pid, unsigned char data[]) try { for (int i = 0; i < number_of_slots; i++) { - tuples.push_back(ParseNextTuple(&byte_stream, i)); + tuples.push_back(ParseStreamForTuple(&byte_stream, i)); } } catch (NoSuchElementException e) { // print stack trace @@ -246,8 +246,8 @@ Iterator HeapPage::iterator() { // uses dynamic memory allocatiom: BEWARE // update documentation to reflect this // ensure that memory is released after use -Tuple * HeapPage::ParseNextTuple(std::stringstream * byte_stream_pointer, - int slot_index) { +Tuple * HeapPage::ParseStreamForTuple(std::stringstream * byte_stream_pointer, + int slot_index) { // if the slot is not set to be used, move internal stream pointer forward // to next tuple, and return nullptr char input_char = 0; diff --git a/src/include/heap_page.h b/src/include/heap_page.h index f2663f6..e9ca503 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -147,8 +147,8 @@ class HeapPage : public Page { * Throws: * - NoSuchElementException: If there is an error while parsing the tuple. */ - Tuple * ParseNextTuple(std::stringstream * byte_stream_pointer, - int slot_index); + Tuple * ParseStreamForTuple(std::stringstream * byte_stream_pointer, + int slot_index); Field * ParseIntoField(std::stringstream * byte_stream_pointer, Field::Type field_type); From 433778294daace08c78e490514e5989a1987dfd6 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 04:45:55 -0400 Subject: [PATCH 31/33] [heap_page.h/cpp] Remove method: ParseIntoField --- src/database/heap_page.cpp | 6 ------ src/include/heap_page.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index bbfc5cd..db646f0 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -284,10 +284,4 @@ Tuple * HeapPage::ParseStreamForTuple(std::stringstream * byte_stream_pointer, return next_tuple; } - -Field * HeapPage::ParseIntoField(std::stringstream * byte_stream_pointer, - Field::Type field_type) { - // to be implemented - return nullptr; -} } diff --git a/src/include/heap_page.h b/src/include/heap_page.h index e9ca503..d5ae007 100644 --- a/src/include/heap_page.h +++ b/src/include/heap_page.h @@ -149,8 +149,5 @@ class HeapPage : public Page { */ Tuple * ParseStreamForTuple(std::stringstream * byte_stream_pointer, int slot_index); - - Field * ParseIntoField(std::stringstream * byte_stream_pointer, - Field::Type field_type); }; } From 5bb934d9ed9cf20ee596ca0047e46d151fe9f6aa Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 04:49:36 -0400 Subject: [PATCH 32/33] Add method to Field interface specification: ParseStreamForField --- src/database/integer_field.cpp | 3 ++- src/database/string_field.cpp | 3 ++- src/include/field.h | 7 +++++++ src/include/integer_field.h | 5 +++++ src/include/string_field.h | 5 +++++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/database/integer_field.cpp b/src/database/integer_field.cpp index c7b3e2f..fedc0b8 100644 --- a/src/database/integer_field.cpp +++ b/src/database/integer_field.cpp @@ -17,7 +17,8 @@ Field::Type IntegerField::get_type() const { return Type::INTEGER; } -void IntegerField::Serialize(std::stringstream * byte_stream) { +Field * IntegerField::ParseStreamForField( + std::stringstream * byte_stream_pointer) { // to be implemented } diff --git a/src/database/string_field.cpp b/src/database/string_field.cpp index 17c4487..dfec818 100644 --- a/src/database/string_field.cpp +++ b/src/database/string_field.cpp @@ -17,7 +17,8 @@ Field::Type StringField::get_type() const { return Type::STRING; } -void StringField::Serialize(std::stringstream * byte_stream) { +Field * StringField::ParseStreamForField( + std::stringstream * byte_stream_pointer) { // to be implemented } diff --git a/src/include/field.h b/src/include/field.h index aea4250..9bcd881 100644 --- a/src/include/field.h +++ b/src/include/field.h @@ -5,6 +5,13 @@ namespace buzzdb { /** * The Field abstract class is an interface for a field in a tuple. + * - Every class that implements this interface must implement the following + * method: + * static Field * ParseStreamForField(std::stringstream byte_stream_pointer) + * - The above constraint cannot be enforced by the specifications of this + * interface as static methods cannot be virtual. + * - If this method is not implemented in a particular Field subclass, it will + * not be possible to parse the particular field type from the byte stream. */ class Field { public: diff --git a/src/include/integer_field.h b/src/include/integer_field.h index 9c962e1..8ede102 100644 --- a/src/include/integer_field.h +++ b/src/include/integer_field.h @@ -34,6 +34,11 @@ class IntegerField : public Field { */ Type get_type() const override; + /** + * Creates an IntegerField by parsing the stream and returns a pointer to it. + */ + static Field * ParseStreamForField(std::stringstream * byte_stream_pointer); + /** * Write the bytes representing the IntegerField to the specified Stream. */ diff --git a/src/include/string_field.h b/src/include/string_field.h index 7e10584..0680750 100644 --- a/src/include/string_field.h +++ b/src/include/string_field.h @@ -35,6 +35,11 @@ class StringField : public Field { */ Type get_type() const override; + /** + * Creates an StringField by parsing the stream and returns a pointer to it. + */ + static Field * ParseStreamForField(std::stringstream * byte_stream_pointer); + /** * Write the bytes representing the StringField to the specified Stream. */ From e035475bd37290a7e839b935cf29e39c20525156 Mon Sep 17 00:00:00 2001 From: jonlee Date: Mon, 29 Apr 2019 04:49:56 -0400 Subject: [PATCH 33/33] Update method specification: Field::Serialize --- src/database/heap_page.cpp | 35 +++++++++++++++++++++++----------- src/database/integer_field.cpp | 4 ++++ src/database/string_field.cpp | 4 ++++ src/include/field.h | 2 +- src/include/integer_field.h | 2 +- src/include/string_field.h | 2 +- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/database/heap_page.cpp b/src/database/heap_page.cpp index db646f0..f6cb19e 100644 --- a/src/database/heap_page.cpp +++ b/src/database/heap_page.cpp @@ -2,7 +2,9 @@ #include "database.h" #include "heap_page.h" #include "db_exception.h" +#include "integer_field.h" #include "no_such_element_exception.h" +#include "string_field.h" namespace buzzdb { /** @@ -268,18 +270,29 @@ Tuple * HeapPage::ParseStreamForTuple(std::stringstream * byte_stream_pointer, RecordId * rid = new RecordId(pid, slot_index); next_tuple->set_record_id(rid); - try { - for (int field_index = 0; - field_index < table_schema.get_number_fields(); - field_index++) { - Field::Type field_type = table_schema.get_field_type(field_index); - Field * parsed_field = ParseIntoField(byte_stream_pointer, field_type); - // bad design; introduces coupling with Field class and its subclasses - next_tuple->set_field(field_index, parsed_field); + for (int field_index = 0; + field_index < table_schema.get_number_fields(); + field_index++) { + Field::Type field_type = table_schema.get_field_type(field_index); + Field * parsed_field; + try { + switch (field_type) { + case Field::Type::INTEGER: + parsed_field = + IntegerField::ParseStreamForField(byte_stream_pointer); + break; + case Field::Type::STRING: + parsed_field = + StringField::ParseStreamForField(byte_stream_pointer); + break; + default: + throw std::runtime_error("Field is of invalid type."); + } + } catch (std::exception parse_exception) { + // change catch type + throw NoSuchElementException("Error parsing tuple."); } - } catch (std::exception e) { - // change catch type - throw NoSuchElementException("Error parsing tuple."); + next_tuple->set_field(field_index, parsed_field); } return next_tuple; diff --git a/src/database/integer_field.cpp b/src/database/integer_field.cpp index fedc0b8..f4019cc 100644 --- a/src/database/integer_field.cpp +++ b/src/database/integer_field.cpp @@ -22,6 +22,10 @@ Field * IntegerField::ParseStreamForField( // to be implemented } +void IntegerField::Serialize(std::stringstream * byte_stream_pointer) { + // to be implemented +} + /* bool IntegerField::Compare(Predicate::OpType op_type, Field * operand) { IntegerField * operand_value_pointer = static_cast(operand); diff --git a/src/database/string_field.cpp b/src/database/string_field.cpp index dfec818..99ec5c7 100644 --- a/src/database/string_field.cpp +++ b/src/database/string_field.cpp @@ -22,6 +22,10 @@ Field * StringField::ParseStreamForField( // to be implemented } +void StringField::Serialize(std::stringstream * byte_stream_pointer) { + // to be implemented +} + /* bool StringField::Compare(Predicate::OpType op_type, Field * operand) { StringField * operand_value_pointer = static_cast(operand); diff --git a/src/include/field.h b/src/include/field.h index 9bcd881..354670a 100644 --- a/src/include/field.h +++ b/src/include/field.h @@ -38,7 +38,7 @@ class Field { /** * Write the bytes representing the field to the specified Stream. */ - virtual void Serialize(std::stringstream * byte_stream) = 0; + virtual void Serialize(std::stringstream * byte_stream_pointer) = 0; /** * Compares the value of the Field to the value of operand. diff --git a/src/include/integer_field.h b/src/include/integer_field.h index 8ede102..e1d3b3a 100644 --- a/src/include/integer_field.h +++ b/src/include/integer_field.h @@ -42,7 +42,7 @@ class IntegerField : public Field { /** * Write the bytes representing the IntegerField to the specified Stream. */ - void Serialize(std::stringstream * byte_stream) override; + void Serialize(std::stringstream * byte_stream_pointer) override; /** * Compares the value of the IntegerField to the value of operand. diff --git a/src/include/string_field.h b/src/include/string_field.h index 0680750..1472547 100644 --- a/src/include/string_field.h +++ b/src/include/string_field.h @@ -43,7 +43,7 @@ class StringField : public Field { /** * Write the bytes representing the StringField to the specified Stream. */ - void Serialize(std::stringstream * byte_stream) override; + void Serialize(std::stringstream * byte_stream_pointer) override; /** * Compares the value of the StringField to the value of operand.