Skip to content

Commit b6d61da

Browse files
Merge pull request #111 from JakeRoggenbuck/page-save-state
Save state of everything
2 parents f4c080d + c356c24 commit b6d61da

File tree

5 files changed

+249
-5
lines changed

5 files changed

+249
-5
lines changed

src/container.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,45 @@
11
use super::page::PhysicalPage;
22
use super::record::{Record, RecordAddress};
3+
use serde::{Deserialize, Serialize};
4+
use std::fs::File;
5+
use std::io::{BufReader, BufWriter, Write};
36
use std::sync::{Arc, Mutex};
47

8+
#[derive(Clone, Default, Deserialize, Serialize, Debug)]
9+
pub struct BaseContainerMetadata {
10+
// This takes the place of the actual pages in the disk version
11+
// With this number, we are able to load all of the pages
12+
num_pages: usize,
13+
14+
num_cols: i64,
15+
16+
rid_column: i64,
17+
schema_encoding_column: i64,
18+
indirection_column: i64,
19+
}
20+
21+
impl BaseContainerMetadata {
22+
pub fn load_state(&self) -> BaseContainer {
23+
let mut base = BaseContainer::new(self.num_cols);
24+
25+
for i in 0..self.num_pages {
26+
// Load the page
27+
let p = PhysicalPage::load_state(i as i64);
28+
// Put the page into an Arc Mutex
29+
let m = Arc::new(Mutex::new(p));
30+
31+
// Add the physical page
32+
base.physical_pages.push(m);
33+
}
34+
35+
base.rid_column = self.rid_column;
36+
base.schema_encoding_column = self.schema_encoding_column;
37+
base.indirection_column = self.indirection_column;
38+
39+
return base;
40+
}
41+
}
42+
543
#[derive(Clone, Default)]
644
pub struct BaseContainer {
745
// pages
@@ -181,6 +219,71 @@ impl BaseContainer {
181219

182220
values
183221
}
222+
223+
pub fn save_state(&self) {
224+
let base_meta = self.get_metadata();
225+
let hardcoded_filename = "./base_container.data";
226+
227+
let mut index = 0;
228+
// The Rust compiler suggested that I clone here but it's definitely way better to not copy
229+
// all of the data and just use a reference
230+
for p in &self.physical_pages {
231+
// Save the page
232+
let m = p.lock().unwrap();
233+
m.save_state(index);
234+
index += 1;
235+
}
236+
237+
let base_bytes: Vec<u8> = bincode::serialize(&base_meta).expect("Should serialize.");
238+
239+
let mut file = BufWriter::new(File::create(hardcoded_filename).expect("Should open file."));
240+
file.write_all(&base_bytes).expect("Should serialize.");
241+
}
242+
243+
pub fn get_metadata(&self) -> BaseContainerMetadata {
244+
BaseContainerMetadata {
245+
num_pages: self.physical_pages.len(),
246+
num_cols: self.num_cols,
247+
rid_column: self.rid_column,
248+
schema_encoding_column: self.schema_encoding_column,
249+
indirection_column: self.indirection_column,
250+
}
251+
}
252+
}
253+
254+
#[derive(Clone, Default, Deserialize, Serialize, Debug)]
255+
pub struct TailContainerMetadata {
256+
// This takes the place of the actual pages in the disk version
257+
// With this number, we are able to load all of the pages
258+
num_pages: usize,
259+
260+
num_cols: i64,
261+
262+
rid_column: i64,
263+
schema_encoding_column: i64,
264+
indirection_column: i64,
265+
}
266+
267+
impl TailContainerMetadata {
268+
pub fn load_state(&self) -> TailContainer {
269+
let mut tail = TailContainer::new(self.num_cols);
270+
271+
for i in 0..self.num_pages {
272+
// Load the page
273+
let p = PhysicalPage::load_state(i as i64);
274+
// Put the page into an Arc Mutex
275+
let m = Arc::new(Mutex::new(p));
276+
277+
// Add the physical page
278+
tail.physical_pages.push(m);
279+
}
280+
281+
tail.rid_column = self.rid_column;
282+
tail.schema_encoding_column = self.schema_encoding_column;
283+
tail.indirection_column = self.indirection_column;
284+
285+
return tail;
286+
}
184287
}
185288

186289
#[derive(Clone, Default)]
@@ -357,6 +460,36 @@ impl TailContainer {
357460

358461
values
359462
}
463+
464+
pub fn save_state(&self) {
465+
let tail_meta = self.get_metadata();
466+
let hardcoded_filename = "./tail_container.data";
467+
468+
let mut index = 0;
469+
// The Rust compiler suggested that I clone here but it's definitely way better to not copy
470+
// all of the data and just use a reference
471+
for p in &self.physical_pages {
472+
// Save the page
473+
let m = p.lock().unwrap();
474+
m.save_state(index);
475+
index += 1;
476+
}
477+
478+
let tail_bytes: Vec<u8> = bincode::serialize(&tail_meta).expect("Should serialize.");
479+
480+
let mut file = BufWriter::new(File::create(hardcoded_filename).expect("Should open file."));
481+
file.write_all(&tail_bytes).expect("Should serialize.");
482+
}
483+
484+
pub fn get_metadata(&self) -> TailContainerMetadata {
485+
TailContainerMetadata {
486+
num_pages: self.physical_pages.len(),
487+
num_cols: self.num_cols,
488+
rid_column: self.rid_column,
489+
schema_encoding_column: self.schema_encoding_column,
490+
indirection_column: self.indirection_column,
491+
}
492+
}
360493
}
361494

362495
#[cfg(test)]

src/page.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use pyo3::prelude::*;
22
use serde::{Deserialize, Serialize};
3+
use std::fs::File;
4+
use std::io::{BufReader, BufWriter, Write};
35

46
static MAX_SIZE_RECORD: i64 = i64::MAX;
57

@@ -36,6 +38,24 @@ impl PhysicalPage {
3638
pub fn read(&self, index: usize) -> Option<i64> {
3739
Some(self.data[index])
3840
}
41+
42+
pub fn save_state(&self, id: i64) {
43+
let hardcoded_filename = format!("./{}-page.data", id);
44+
45+
let table_bytes: Vec<u8> = bincode::serialize(&self).expect("Should serialize.");
46+
47+
let mut file = BufWriter::new(File::create(hardcoded_filename).expect("Should open file."));
48+
file.write_all(&table_bytes).expect("Should serialize.");
49+
}
50+
51+
pub fn load_state(id: i64) -> PhysicalPage {
52+
let hardcoded_filename = format!("./{}-page.data", id);
53+
54+
let file = BufReader::new(File::open(hardcoded_filename).expect("Should open file."));
55+
let page: PhysicalPage = bincode::deserialize_from(file).expect("Should deserialize.");
56+
57+
return page;
58+
}
3959
}
4060

4161
#[cfg(test)]
@@ -50,6 +70,48 @@ mod tests {
5070
assert_eq!(phys_page.read(0).unwrap(), 10);
5171
}
5272

73+
#[test]
74+
fn save_load_test() {
75+
// Scope so that page_one and page_two get unallocated and leave scope
76+
{
77+
let mut page_one = PhysicalPage::new();
78+
let mut page_two = PhysicalPage::new();
79+
80+
// Write to page_one
81+
page_one.write(100);
82+
page_one.write(200);
83+
page_one.write(300);
84+
85+
// Write to page_two
86+
page_two.write(111);
87+
page_two.write(222);
88+
page_two.write(333);
89+
90+
// Save page_one and page_two
91+
page_one.save_state(1);
92+
page_two.save_state(2);
93+
}
94+
95+
// Load page_one and page_two
96+
let mut page_one = PhysicalPage::load_state(1);
97+
let mut page_two = PhysicalPage::load_state(2);
98+
99+
// Write to both pages once more
100+
page_one.write(400);
101+
page_two.write(444);
102+
103+
// Check that all the data is there
104+
assert_eq!(page_one.read(0), Some(100));
105+
assert_eq!(page_one.read(1), Some(200));
106+
assert_eq!(page_one.read(2), Some(300));
107+
assert_eq!(page_one.read(3), Some(400));
108+
109+
assert_eq!(page_two.read(0), Some(111));
110+
assert_eq!(page_two.read(1), Some(222));
111+
assert_eq!(page_two.read(2), Some(333));
112+
assert_eq!(page_two.read(3), Some(444));
113+
}
114+
53115
#[test]
54116
fn many_writes_page_test() {
55117
let mut phys_page = PhysicalPage::new();

src/pagerange.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
use super::container::{BaseContainer, TailContainer};
1+
use super::container::{
2+
BaseContainer, BaseContainerMetadata, TailContainer, TailContainerMetadata,
3+
};
24
use super::record::Record;
5+
use serde::{Deserialize, Serialize};
6+
use std::fs::File;
7+
use std::io::{BufReader, BufWriter, Write};
8+
9+
#[derive(Clone, Default, Deserialize, Serialize, Debug)]
10+
pub struct PageRangeMetadata {
11+
pub base_container: BaseContainerMetadata,
12+
pub tail_container: TailContainerMetadata,
13+
}
314

415
#[derive(Clone, Default)]
516
pub struct PageRange {
@@ -29,4 +40,39 @@ impl PageRange {
2940
pub fn read(&self, record: Record) -> Option<Vec<i64>> {
3041
Some(self.base_container.read_record(record))
3142
}
43+
44+
pub fn save_state(&self) {
45+
// Save the state of the two containers
46+
self.base_container.save_state();
47+
self.tail_container.save_state();
48+
49+
let hardcoded_filename = "./pagerange.data";
50+
51+
let pr_meta = self.get_metadata();
52+
53+
let pr_bytes: Vec<u8> = bincode::serialize(&pr_meta).expect("Should serialize.");
54+
55+
let mut file = BufWriter::new(File::create(hardcoded_filename).expect("Should open file."));
56+
file.write_all(&pr_bytes).expect("Should serialize.");
57+
}
58+
59+
pub fn load_state() -> PageRange {
60+
let hardcoded_filename = "./pagerange.data";
61+
62+
let file = BufReader::new(File::open(hardcoded_filename).expect("Should open file."));
63+
let pr_meta: PageRangeMetadata =
64+
bincode::deserialize_from(file).expect("Should deserialize.");
65+
66+
PageRange {
67+
base_container: pr_meta.base_container.load_state(),
68+
tail_container: pr_meta.tail_container.load_state(),
69+
}
70+
}
71+
72+
pub fn get_metadata(&self) -> PageRangeMetadata {
73+
PageRangeMetadata {
74+
base_container: self.base_container.get_metadata(),
75+
tail_container: self.tail_container.get_metadata(),
76+
}
77+
}
3278
}

src/table.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::index::RIndex;
2-
use super::pagerange::PageRange;
2+
use super::pagerange::{PageRange, PageRangeMetadata};
33
use super::record::Record;
44
use bincode;
55
use pyo3::prelude::*;
@@ -14,6 +14,7 @@ pub struct RTableMetadata {
1414
pub primary_key_column: usize,
1515
pub num_records: i64,
1616
pub num_columns: usize,
17+
pub page_range: PageRangeMetadata,
1718
}
1819

1920
pub trait StatePersistence {
@@ -30,9 +31,7 @@ pub trait StatePersistence {
3031
num_columns: table_meta.num_columns,
3132
num_records: table_meta.num_records,
3233

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),
34+
page_range: PageRange::load_state(),
3635
page_directory: HashMap::new(),
3736
index: RIndex::new(),
3837
}
@@ -214,6 +213,9 @@ impl RTable {
214213
pub fn save_state(&self) {
215214
let hardcoded_filename = "./table.data";
216215

216+
// Save the state of the page range
217+
self.page_range.save_state();
218+
217219
let table_meta = self.get_metadata();
218220

219221
let table_bytes: Vec<u8> = bincode::serialize(&table_meta).expect("Should serialize.");
@@ -228,6 +230,7 @@ impl RTable {
228230
primary_key_column: self.primary_key_column,
229231
num_columns: self.num_columns,
230232
num_records: self.num_records,
233+
page_range: self.page_range.get_metadata(),
231234
}
232235
}
233236

table.data

80 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)