From f85583c4cc240670fb940e2df8f3060b6129dd14 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Mon, 11 Sep 2017 11:49:58 -0400 Subject: [PATCH] Finish step 5 --- db.c | 75 +++++++++++++++++++++++++++++++++++++++++++++-- spec/main_spec.rb | 6 +++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/db.c b/db.c index 2a67162..dea9694 100644 --- a/db.c +++ b/db.c @@ -114,8 +114,70 @@ void read_input(InputBuffer* input_buffer) { input_buffer->buffer[bytes_read - 1] = 0; } -MetaCommandResult do_meta_command(InputBuffer* input_buffer) { +void pager_flush(Pager* pager, uint32_t page_num, uint32_t size) { + if (pager->pages[page_num] == NULL) { + printf("Tried to flush null page\n"); + exit(EXIT_FAILURE); + } + + off_t offset = lseek(pager->file_descriptor, page_num * PAGE_SIZE, SEEK_SET); + + if (offset == -1) { + printf("Error seeking: %d\n", errno); + exit(EXIT_FAILURE); + } + + ssize_t bytes_written = write(pager->file_descriptor, pager->pages[page_num], size); + + if (bytes_written == -1) { + printf("Error writing: %d\n", errno); + exit(EXIT_FAILURE); + } +} + +void db_close(Table* table) { + Pager* pager = table->pager; + uint32_t num_full_pages = table->num_rows / ROWS_PER_PAGE; + + for (uint32_t i = 0; i < num_full_pages; i++) { + if (pager->pages[i] == NULL) { + continue; + } + pager_flush(pager, i, PAGE_SIZE); + free(pager->pages[i]); + pager->pages[i] = NULL; + } + + // There may be a partial page to write to the end of the file + // This should not be needed after we switch to a B-tree + uint32_t num_additional_rows = table->num_rows % ROWS_PER_PAGE; + if (num_additional_rows > 0) { + uint32_t page_num = num_full_pages; + if (pager->pages[page_num] != NULL) { + pager_flush(pager, page_num, num_additional_rows * ROW_SIZE); + free(pager->pages[page_num]); + pager->pages[page_num] = NULL; + } + } + + int result = close(pager->file_descriptor); + if (result == -1) { + printf("Error closing db file.\n"); + exit(EXIT_FAILURE); + } + for(uint32_t i = 0; i < TABLE_MAX_PAGES; i++) { + void* page = pager->pages[i]; + if (page) { + free(page); + pager->pages[i] = NULL; + } + } + free(pager); +} + +MetaCommandResult do_meta_command(InputBuffer* input_buffer, Table* table) { if (strcmp(input_buffer->buffer, ".exit") == 0) { + db_close(table); exit(EXIT_SUCCESS); } else { return META_COMMAND_UNRECOGNIZED_COMMAND; @@ -285,14 +347,21 @@ Table* db_open(const char* filename) { } int main(int argc, char* argv[]) { - Table* table = new_table(); + if (argc < 2) { + printf("Must supply a database filename\n"); + exit(EXIT_FAILURE); + } + + char* filename = argv[1]; + Table* table = db_open(filename); + InputBuffer* input_buffer = new_input_buffer(); while (true) { print_prompt(); read_input(input_buffer); if (input_buffer->buffer[0] == '.') { - switch (do_meta_command(input_buffer)) { + switch (do_meta_command(input_buffer, table)) { case (META_COMMAND_SUCCESS): continue; diff --git a/spec/main_spec.rb b/spec/main_spec.rb index bd02bc3..0bd17ea 100644 --- a/spec/main_spec.rb +++ b/spec/main_spec.rb @@ -1,7 +1,11 @@ describe 'database' do + before do + `rm -rf test.db` + end + def run_script(commands) raw_output = nil - IO.popen("./db", "r+") do |pipe| + IO.popen("./db test.db", "r+") do |pipe| commands.each do |command| pipe.puts command end