little steps towards the end goal
This commit is contained in:
parent
b0f00f4d87
commit
7a475577f2
4 changed files with 112 additions and 25 deletions
|
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -134,3 +187,5 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue