little steps towards the end goal

This commit is contained in:
Sander Hautvast 2022-10-29 18:22:39 +02:00
parent b0f00f4d87
commit 7a475577f2
4 changed files with 112 additions and 25 deletions

View file

@ -3,7 +3,7 @@ use crate::database::{Database, SchemaRecord};
use crate::page::{self, Page}; use crate::page::{self, Page};
use crate::record::Record; use crate::record::Record;
struct Builder { pub struct Builder {
current_page: Page, current_page: Page,
n_records_on_current_page: u16, n_records_on_current_page: u16,
leaf_pages: Vec<Page>, leaf_pages: Vec<Page>,
@ -21,7 +21,7 @@ impl Builder {
} }
} }
pub fn add_record(&mut self, mut record: Record) { pub fn add_record(&mut self, record: Record) {
if self.current_page_is_full(&record) { if self.current_page_is_full(&record) {
self.finish_current_page(); self.finish_current_page();
self.leaf_pages.push(mem::replace(&mut self.current_page, Page::new_leaf())); self.leaf_pages.push(mem::replace(&mut self.current_page, Page::new_leaf()));
@ -35,21 +35,8 @@ impl Builder {
self.n_records_on_current_page += 1; self.n_records_on_current_page += 1;
} }
pub fn schema(&mut self, schema: SchemaRecord) { pub fn schema(&mut self, table_name: &str, sql: &str) {
self.schema = Some(schema); self.schema = Some(SchemaRecord::new(1, table_name, 2, sql));
}
pub fn build(mut self) -> Database {
self.current_page.fw_position = page::POSITION_CELL_COUNT;
self.current_page.put_u16(self.n_records_on_current_page);
if self.n_records_on_current_page > 0 {
self.current_page.put_u16(self.current_page.bw_position);
} else {
self.current_page.put_u16(self.current_page.bw_position - 1);
}
Database::new(self.schema.unwrap(), self.leaf_pages) //panics is schema is not set
} }
fn current_page_is_full(&self, record: &Record) -> bool { fn current_page_is_full(&self, record: &Record) -> bool {
@ -63,3 +50,44 @@ impl Builder {
} }
} }
impl Into<Database> for Builder {
fn into(mut self) -> Database {
self.current_page.fw_position = page::POSITION_CELL_COUNT;
self.current_page.put_u16(self.n_records_on_current_page);
if self.n_records_on_current_page > 0 {
self.current_page.put_u16(self.current_page.bw_position);
} else {
self.current_page.put_u16(self.current_page.bw_position - 1);
}
Database::new(self.schema.unwrap(), self.leaf_pages) //panics is schema is not set
}
}
#[cfg(test)]
mod tests {
use std::fs::File;
use std::io::{BufWriter, Error};
use crate::database::write;
use crate::values;
use super::*;
#[test]
fn test_build() -> Result<(), Error>{
let mut builder = Builder::new();
builder.schema(
"foo",
"create table foo(bar varchar(10))",
);
let mut record = Record::new(1);
record.add_value(values::string("helloworld"));
builder.add_record(record);
let database: Database = builder.into();
let file = File::create("foo.txt")?;
let writer = BufWriter::new(file);
write(database, writer)?;
Ok(())
}
}

View file

@ -1,8 +1,10 @@
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Error, Write};
use std::mem; use std::mem;
use crate::varint; use crate::varint;
use crate::page; use crate::page;
use crate::page::Page; use crate::page::Page;
use crate::record::Record;
use crate::values;
pub struct Database { pub struct Database {
schema: SchemaRecord, schema: SchemaRecord,
@ -18,9 +20,37 @@ impl Database {
} }
} }
pub struct SchemaRecord {} pub struct SchemaRecord {
rowid: u64,
table_name: String,
root_page: u32,
sql: String,
}
pub fn write<W: Write>(database: Database, writer: BufWriter<W>) { impl SchemaRecord {
pub fn new(rowid: u64, table_name: &str, root_page: u32, sql: &str) -> Self {
Self {
rowid,
table_name: table_name.to_owned(),
root_page,
sql: sql.to_owned(),
}
}
}
impl Into<Record> for SchemaRecord {
fn into(self) -> Record {
let mut record = Record::new(self.rowid);
record.add_value(values::string("table"));
record.add_value(values::string(&self.table_name.to_ascii_lowercase()));
record.add_value(values::string(&self.table_name.to_ascii_lowercase()));
record.add_value(values::integer(self.root_page as i64));
record.add_value(values::string(&self.sql));
record
}
}
pub fn write<W: Write>(database: Database, mut writer: BufWriter<W>) -> Result<(), Error> {
let mut current_top_layer = database.leaf_pages; let mut current_top_layer = database.leaf_pages;
let mut n_pages = current_top_layer.len(); let mut n_pages = current_top_layer.len();
while current_top_layer.len() > 1 { // interior page needed? while current_top_layer.len() > 1 { // interior page needed?
@ -29,11 +59,33 @@ pub fn write<W: Write>(database: Database, writer: BufWriter<W>) {
} }
let table_root_page = current_top_layer.get(0); // let table_root_page = current_top_layer.get(0); //
// writeFromStart(writer, createHeaderPage(n_pages + 1)); // 1 for header page writer.write_all(&create_header_page(n_pages + 1, database.schema).data)?; // 1 for header page
// //
// recursiveAssignPagenumbers(table_root_page); // 3 extra passes... :( // recursiveAssignPagenumbers(table_root_page); // 3 extra passes... :(
// recursiveSetPageReferences(table_root_page); // don't think combining is possible // recursiveSetPageReferences(table_root_page); // don't think combining is possible
// recursiveWritePages(channel, table_root_page); // recursiveWritePages(channel, table_root_page);
Ok(())
}
fn create_header_page(n_pages: usize, schema: SchemaRecord) -> Page {
let mut header_page = Page::new_root();
write_header(&mut header_page, n_pages as u32);
let payload_location_write_location = header_page.fw_position; // mark current position
let payload_location = write_schema(&mut header_page, schema); //write schema payload from the end
header_page.fw_position = payload_location_write_location; // go back to marked position
header_page.put_u16(payload_location); //payload start
header_page.put_u8(0); // the number of fragmented free bytes within the cell content area
header_page.put_u16(payload_location); // first cell
return header_page;
}
fn write_schema(root_page: &mut Page, schema_record: SchemaRecord) -> u16 {
let record: Record = schema_record.into();
let bytes: Vec<u8> = record.into();
root_page.put_bytes_bw(&bytes);
root_page.bw_position
} }
fn create_interior_pages(mut child_pages: Vec<Page>) -> Vec<Page> { fn create_interior_pages(mut child_pages: Vec<Page>) -> Vec<Page> {
@ -61,6 +113,7 @@ fn create_interior_pages(mut child_pages: Vec<Page>) -> Vec<Page> {
} else { } else {
last_leaf = leaf_page; last_leaf = leaf_page;
} }
child_count += 1;
} }
interior_page.fw_position = page::START_OF_CONTENT_AREA; interior_page.fw_position = page::START_OF_CONTENT_AREA;
@ -78,7 +131,7 @@ fn create_cell(page: &mut Page) {
page.put_u16(page.bw_position); page.put_u16(page.bw_position);
} }
fn write_header(mut rootpage: Page, n_pages: u32) { fn write_header(rootpage: &mut Page, n_pages: u32) {
rootpage.put_bytes(&MAGIC_HEADER); rootpage.put_bytes(&MAGIC_HEADER);
rootpage.put_u16(DEFAULT_PAGE_SIZE); rootpage.put_u16(DEFAULT_PAGE_SIZE);
rootpage.put_u8(FILE_FORMAT_WRITE_VERSION); rootpage.put_u8(FILE_FORMAT_WRITE_VERSION);
@ -133,4 +186,6 @@ const NO_FREE_BLOCKS: u16 = 0;
pub const TABLE_LEAF_PAGE: u8 = 0x0d; pub const TABLE_LEAF_PAGE: u8 = 0x0d;
pub const TABLE_INTERIOR_PAGE: u8 = 0x05; pub const TABLE_INTERIOR_PAGE: u8 = 0x05;
const INDEX_LEAF_PAGE: u8 = 0x0a; const INDEX_LEAF_PAGE: u8 = 0x0a;
const INDEX_INTERIOR_PAGE: u8 = 0x02; const INDEX_INTERIOR_PAGE: u8 = 0x02;

View file

@ -48,6 +48,10 @@ impl Page {
} }
} }
pub fn new_root() -> Self {
Page::with_capacity(database::DEFAULT_PAGE_SIZE, PageType::Leaf)
}
pub fn new_leaf() -> Self { pub fn new_leaf() -> Self {
let mut page = Page::with_capacity(database::DEFAULT_PAGE_SIZE, PageType::Leaf); let mut page = Page::with_capacity(database::DEFAULT_PAGE_SIZE, PageType::Leaf);
page.put_u8(database::TABLE_LEAF_PAGE); page.put_u8(database::TABLE_LEAF_PAGE);

View file

@ -8,14 +8,14 @@ pub struct Record {
} }
impl Record { impl Record {
fn new(rowid: u64) -> Self { pub fn new(rowid: u64) -> Self {
Self { Self {
rowid, rowid,
values: vec![], values: vec![],
} }
} }
fn add_value(&mut self, value: Value) { pub fn add_value(&mut self, value: Value) {
self.values.push(value); self.values.push(value);
} }