simple_db_rust/btree/
buffer_pool.rs

1use log::info;
2
3use crate::{util::simple_int_tuple_scheme, Tuple};
4
5use std::{
6    cell::RefCell,
7    collections::HashMap,
8    fs::File,
9    io::{prelude::*, Result, Seek, SeekFrom},
10    rc::Rc,
11    sync::atomic::{AtomicUsize, Ordering},
12};
13
14use std::{mem, sync::Once};
15
16use super::{
17    page::{BTreeInternalPage, BTreeRootPointerPage, PageCategory},
18    tuple::TupleScheme,
19};
20
21use super::{
22    catalog::Catalog,
23    page::{BTreeLeafPage, BTreePageID},
24};
25
26pub const DEFAULT_PAGE_SIZE: usize = 4096;
27static PAGE_SIZE: AtomicUsize = AtomicUsize::new(DEFAULT_PAGE_SIZE);
28
29pub struct BufferPool {
30    roop_pointer_buffer:
31        HashMap<BTreePageID, Rc<RefCell<BTreeRootPointerPage>>>,
32    pub internal_buffer: HashMap<BTreePageID, Rc<RefCell<BTreeInternalPage>>>,
33    pub leaf_buffer: HashMap<BTreePageID, Rc<RefCell<BTreeLeafPage>>>,
34}
35
36type Key = BTreePageID;
37
38impl BufferPool {
39    fn new() -> BufferPool {
40        BufferPool {
41            roop_pointer_buffer: HashMap::new(),
42            internal_buffer: HashMap::new(),
43            leaf_buffer: HashMap::new(),
44        }
45    }
46
47    pub fn global() -> &'static mut Self {
48        // Initialize it to a null value
49        static mut SINGLETON: *mut BufferPool = 0 as *mut BufferPool;
50        static ONCE: Once = Once::new();
51
52        ONCE.call_once(|| {
53            // Make it
54            let singleton = Self::new();
55
56            unsafe {
57                // Put it in the heap so it can outlive this call
58                SINGLETON = mem::transmute(Box::new(singleton));
59            }
60        });
61
62        unsafe {
63            // Now we give out a copy of the data that is safe to use
64            // concurrently. (*SINGLETON).clone()
65            // SINGLETON.as_ref().unwrap()
66            SINGLETON.as_mut().unwrap()
67        }
68    }
69
70    pub fn clear(&mut self) {
71        self.roop_pointer_buffer.clear();
72        self.internal_buffer.clear();
73        self.leaf_buffer.clear();
74    }
75
76    fn read_page(&self, file: &mut File, key: &Key) -> Result<Vec<u8>> {
77        let page_size = Self::get_page_size();
78        let start_pos = key.page_index * page_size;
79        file.seek(SeekFrom::Start(start_pos as u64))
80            .expect("io error");
81
82        let mut buf: Vec<u8> = vec![0; page_size];
83        file.read_exact(&mut buf).expect("io error");
84        Ok(buf)
85    }
86
87    pub fn get_internal_page(
88        &mut self,
89        key: &Key,
90    ) -> Result<Rc<RefCell<BTreeInternalPage>>> {
91        match self.internal_buffer.get(key) {
92            Some(_) => {}
93            None => {
94                // 1. get table
95                let v =
96                    Catalog::global().get_table(key.get_table_id()).unwrap();
97                let table = v.borrow();
98
99                // 2. read page content
100                let buf = self.read_page(&mut table.get_file(), key)?;
101
102                // 3. instantiate page
103                let page = BTreeInternalPage::new(
104                    key,
105                    buf.to_vec(),
106                    &table.tuple_scheme,
107                    table.key_field,
108                );
109
110                // 4. put page into buffer pool
111                self.internal_buffer
112                    .insert(*key, Rc::new(RefCell::new(page)));
113            }
114        }
115
116        Ok(Rc::clone(self.internal_buffer.get(key).unwrap()))
117    }
118
119    pub fn get_leaf_page(
120        &mut self,
121        key: &Key,
122    ) -> Result<Rc<RefCell<BTreeLeafPage>>> {
123        match self.leaf_buffer.get(key) {
124            Some(_) => {}
125            None => {
126                // 1. get table
127                let v =
128                    Catalog::global().get_table(key.get_table_id()).unwrap();
129                let table = v.borrow();
130
131                // 2. read page content
132                let buf = self.read_page(&mut table.get_file(), key)?;
133
134                // 3. instantiate page
135                let page = BTreeLeafPage::new(
136                    key,
137                    buf.to_vec(),
138                    &table.tuple_scheme,
139                    table.key_field,
140                );
141
142                // 4. put page into buffer pool
143                self.leaf_buffer.insert(*key, Rc::new(RefCell::new(page)));
144            }
145        }
146
147        Ok(Rc::clone(self.leaf_buffer.get(key).unwrap()))
148    }
149
150    pub fn get_root_pointer_page(
151        &mut self,
152        key: &Key,
153    ) -> Result<Rc<RefCell<BTreeRootPointerPage>>> {
154        match self.roop_pointer_buffer.get(key) {
155            Some(_) => {}
156            None => {
157                // 1. get table
158                let v =
159                    Catalog::global().get_table(key.get_table_id()).unwrap();
160                let table = v.borrow();
161
162                // 2. read page content
163                let buf = self.read_page(&mut table.get_file(), key)?;
164
165                // 3. instantiate page
166                let pid = BTreePageID::new(
167                    PageCategory::RootPointer,
168                    table.get_id(),
169                    0,
170                );
171                let page = BTreeRootPointerPage::new(&pid, buf.to_vec());
172
173                // 4. put page into buffer pool
174                self.roop_pointer_buffer
175                    .insert(*key, Rc::new(RefCell::new(page)));
176            }
177        }
178
179        Ok(Rc::clone(self.roop_pointer_buffer.get(key).unwrap()))
180    }
181
182    pub fn set_page_size(page_size: usize) {
183        PAGE_SIZE.store(page_size, Ordering::Relaxed);
184
185        info!("set page size to {}", page_size);
186        let scheme = simple_int_tuple_scheme(2, "");
187        info!(
188            "leaf page slot count: {}",
189            BTreeLeafPage::get_max_tuples(&scheme)
190        );
191        info!(
192            "internal page entries count: {}, children count: {}",
193            BTreeInternalPage::get_max_entries(4),
194            BTreeInternalPage::get_max_entries(4) + 1,
195        );
196    }
197
198    pub fn rows_per_page(scheme: &TupleScheme) -> usize {
199        BTreeLeafPage::get_max_tuples(&scheme)
200    }
201
202    pub fn children_per_page() -> usize {
203        BTreeInternalPage::get_max_entries(4) + 1
204    }
205
206    pub fn get_page_size() -> usize {
207        PAGE_SIZE.load(Ordering::Relaxed)
208    }
209
210    /**
211    Add a tuple to the specified table on behalf of transaction tid.  Will
212    acquire a write lock on the page the tuple is added to and any other
213    pages that are updated (Lock acquisition is not needed for lab2).
214    May block if the lock(s) cannot be acquired.
215
216    Marks any pages that were dirtied by the operation as dirty by calling
217    their markDirty bit, and adds versions of any pages that have
218    been dirtied to the cache (replacing any existing versions of those pages) so
219    that future requests see up-to-date pages.
220    */
221    pub fn insert_tuple(&mut self, table_id: i32, t: Tuple) {
222        let v = Catalog::global().get_table(&table_id).unwrap().borrow();
223        v.insert_tuple(&t);
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use crate::{
230        btree::page::PageCategory, util::simple_int_tuple_scheme, BTreeTable,
231    };
232
233    use super::*;
234
235    #[test]
236    fn test_buffer_pool() {
237        let bp = BufferPool::global();
238
239        // add table to catalog
240        let table = BTreeTable::new(
241            "test_buffer_pool.db",
242            0,
243            &simple_int_tuple_scheme(3, ""),
244        );
245        let table_id = table.get_id();
246        Catalog::global().add_table(Rc::new(RefCell::new(table)));
247
248        // write page to disk
249
250        // get page
251        let page_id = BTreePageID::new(PageCategory::RootPointer, table_id, 0);
252        match bp.get_root_pointer_page(&page_id) {
253            Ok(_) => {}
254            Err(e) => {
255                panic!("err: {}", e)
256            }
257        }
258
259        let page_id = BTreePageID::new(PageCategory::Leaf, table_id, 1);
260        match bp.get_root_pointer_page(&page_id) {
261            Ok(_) => {}
262            Err(e) => {
263                panic!("err: {}", e)
264            }
265        }
266
267        let page_id = BTreePageID::new(PageCategory::Leaf, table_id, 1);
268        match bp.get_root_pointer_page(&page_id) {
269            Ok(_) => {}
270            Err(e) => {
271                panic!("err: {}", e)
272            }
273        }
274    }
275}