Skip to content

Commit f4c080d

Browse files
Merge pull request #109 from JakeRoggenbuck/save-db-state
Add state loader for database
2 parents b388d35 + 6e2c25a commit f4c080d

File tree

3 files changed

+107
-33
lines changed

3 files changed

+107
-33
lines changed

src/database.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
use super::index::RIndex;
22
use super::pagerange::PageRange;
3-
use super::table::RTable;
3+
use super::table::{RTable, RTableMetadata, StatePersistence};
44
use pyo3::prelude::*;
5+
use serde::{Deserialize, Serialize};
56
use std::collections::HashMap;
7+
use std::fs::File;
8+
use std::io::{BufReader, BufWriter, Write};
9+
use std::path::Path;
10+
11+
#[derive(Serialize, Deserialize, Debug, Default)]
12+
pub struct RDatabaseMetadata {
13+
tables: Vec<RTableMetadata>,
14+
tables_hashmap: HashMap<String, usize>,
15+
db_filepath: Option<String>,
16+
}
617

718
#[pyclass]
819
pub struct RDatabase {
920
/// This is where we keep all of the tables
1021
tables: Vec<RTable>,
1122
// Map table names to index on the tables: Vec<RTable>
1223
tables_hashmap: HashMap<String, usize>,
24+
25+
db_filepath: Option<String>,
1326
}
1427

1528
#[pymethods]
@@ -19,15 +32,67 @@ impl RDatabase {
1932
RDatabase {
2033
tables: vec![],
2134
tables_hashmap: HashMap::new(),
35+
db_filepath: None,
2236
}
2337
}
2438

25-
fn open(&self, _path: String) {
26-
// unreachable!("Not used in milestone 1");
39+
fn open(&mut self, path: String) {
40+
if self.db_filepath.is_none() {
41+
self.db_filepath = Some(path.clone());
42+
}
43+
44+
if let Some(p) = &self.db_filepath {
45+
if !Path::new(&p).exists() {
46+
// The database has not been closed yet
47+
// Assuming the users makes sure to close the database before they want to open it
48+
// again, we don't have to do anything else. We can just exit. The rest of the function
49+
// only needs to load up the database if something exists to load up
50+
return;
51+
}
52+
}
53+
54+
// Read the metadata of the database
55+
let file = BufReader::new(File::open(path).expect("Should open file."));
56+
let db_meta: RDatabaseMetadata =
57+
bincode::deserialize_from(file).expect("Should deserialize.");
58+
59+
// Load each table metadata into this current databases' tables
60+
let mut index = 0;
61+
for table in &db_meta.tables {
62+
self.tables.push(table.load_state());
63+
self.tables_hashmap.insert(table.name.clone(), index);
64+
index += 1;
65+
}
2766
}
2867

2968
fn close(&self) {
30-
// unreachable!("Not used in milestone 1");
69+
let mut database_meta = RDatabaseMetadata {
70+
tables: Vec::<RTableMetadata>::new(),
71+
tables_hashmap: self.tables_hashmap.clone(),
72+
db_filepath: self.db_filepath.clone(),
73+
};
74+
75+
for table in &self.tables {
76+
// Get the metadata for each table
77+
let tm: RTableMetadata = table.get_metadata();
78+
// Push it to database_meta.tables
79+
database_meta.tables.push(tm);
80+
81+
// Save the table to disk
82+
table.save_state();
83+
}
84+
85+
let table_bytes: Vec<u8> = bincode::serialize(&database_meta).expect("Should serialize.");
86+
87+
match &self.db_filepath {
88+
Some(p) => {
89+
let mut file = BufWriter::new(File::create(p).expect("Should open file."));
90+
file.write_all(&table_bytes).expect("Should serialize.");
91+
}
92+
None => {
93+
panic!("Could no write!") /* Quietly fail to write to disk */
94+
}
95+
}
3196
}
3297

3398
pub fn create_table(

src/table.rs

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,39 @@ use std::fs::File;
99
use std::io::{BufReader, BufWriter, Write};
1010

1111
#[derive(Serialize, Deserialize, Debug)]
12-
struct RTableMetadata {
13-
name: String,
14-
primary_key_column: usize,
15-
num_records: i64,
16-
num_columns: usize,
12+
pub struct RTableMetadata {
13+
pub name: String,
14+
pub primary_key_column: usize,
15+
pub num_records: i64,
16+
pub num_columns: usize,
17+
}
18+
19+
pub trait StatePersistence {
20+
fn load_state(&self) -> RTable {
21+
let hardcoded_filename = "./table.data";
22+
23+
let file = BufReader::new(File::open(hardcoded_filename).expect("Should open file."));
24+
let table_meta: RTableMetadata =
25+
bincode::deserialize_from(file).expect("Should deserialize.");
26+
27+
RTable {
28+
name: table_meta.name.clone(),
29+
primary_key_column: table_meta.primary_key_column,
30+
num_columns: table_meta.num_columns,
31+
num_records: table_meta.num_records,
32+
33+
// TODO: Should we load these up too or create new ones?
34+
// I think load them up to, so we need to do that as well
35+
page_range: PageRange::new(table_meta.num_columns as i64),
36+
page_directory: HashMap::new(),
37+
index: RIndex::new(),
38+
}
39+
}
1740
}
1841

42+
impl StatePersistence for RTableMetadata {}
43+
impl StatePersistence for RTable {}
44+
1945
#[derive(Clone, Default)]
2046
#[pyclass]
2147
pub struct RTable {
@@ -188,37 +214,20 @@ impl RTable {
188214
pub fn save_state(&self) {
189215
let hardcoded_filename = "./table.data";
190216

191-
let table_meta = RTableMetadata {
192-
name: self.name.clone(),
193-
num_columns: self.num_columns,
194-
num_records: self.num_records,
195-
primary_key_column: self.primary_key_column,
196-
};
217+
let table_meta = self.get_metadata();
197218

198219
let table_bytes: Vec<u8> = bincode::serialize(&table_meta).expect("Should serialize.");
199220

200221
let mut file = BufWriter::new(File::create(hardcoded_filename).expect("Should open file."));
201222
file.write_all(&table_bytes).expect("Should serialize.");
202223
}
203224

204-
pub fn load_state(&self) -> RTable {
205-
let hardcoded_filename = "./table.data";
206-
207-
let file = BufReader::new(File::open(hardcoded_filename).expect("Should open file."));
208-
let table_meta: RTableMetadata =
209-
bincode::deserialize_from(file).expect("Should deserialize.");
210-
211-
RTable {
212-
name: table_meta.name.clone(),
213-
primary_key_column: table_meta.primary_key_column,
214-
num_columns: table_meta.num_columns,
215-
num_records: table_meta.num_records,
216-
217-
// TODO: Should we load these up too or create new ones?
218-
// I think load them up to, so we need to do that as well
219-
page_range: PageRange::new(table_meta.num_columns as i64),
220-
page_directory: HashMap::new(),
221-
index: RIndex::new(),
225+
pub fn get_metadata(&self) -> RTableMetadata {
226+
RTableMetadata {
227+
name: self.name.clone(),
228+
primary_key_column: self.primary_key_column,
229+
num_columns: self.num_columns,
230+
num_records: self.num_records,
222231
}
223232
}
224233

table.data

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)