| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  | use std::fs::{File, OpenOptions};
 | 
					
						
							|  |  |  | use std::io::{Read, Write};
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  | use std::path::Path;
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  | use std::sync::Arc;
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  | use anyhow::{Context, Result};
 | 
					
						
							|  |  |  | use bytes::{Buf, BufMut, Bytes};
 | 
					
						
							|  |  |  | use crossbeam_skiplist::SkipMap;
 | 
					
						
							|  |  |  | use parking_lot::Mutex;
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  | pub struct Wal {
 | 
					
						
							|  |  |  |     file: Arc<Mutex<File>>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | impl Wal {
 | 
					
						
							|  |  |  |     pub fn create(path: impl AsRef<Path>) -> Result<Self> {
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  |         Ok(Self {
 | 
					
						
							|  |  |  |             file: Arc::new(Mutex::new(
 | 
					
						
							|  |  |  |                 OpenOptions::new()
 | 
					
						
							|  |  |  |                     .read(true)
 | 
					
						
							|  |  |  |                     .create_new(true)
 | 
					
						
							|  |  |  |                     .write(true)
 | 
					
						
							|  |  |  |                     .open(path)
 | 
					
						
							|  |  |  |                     .context("failed to create WAL")?,
 | 
					
						
							|  |  |  |             )),
 | 
					
						
							|  |  |  |         })
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn recover(path: impl AsRef<Path>, skiplist: &SkipMap<Bytes, Bytes>) -> Result<Self> {
 | 
					
						
							|  |  |  |         let path = path.as_ref();
 | 
					
						
							|  |  |  |         let mut file = OpenOptions::new()
 | 
					
						
							|  |  |  |             .read(true)
 | 
					
						
							|  |  |  |             .append(true)
 | 
					
						
							|  |  |  |             .open(path)
 | 
					
						
							|  |  |  |             .context("failed to recover from WAL")?;
 | 
					
						
							|  |  |  |         let mut buf = Vec::new();
 | 
					
						
							|  |  |  |         file.read_to_end(&mut buf)?;
 | 
					
						
							|  |  |  |         let mut rbuf: &[u8] = buf.as_slice();
 | 
					
						
							|  |  |  |         while rbuf.has_remaining() {
 | 
					
						
							|  |  |  |             let key_len = rbuf.get_u16() as usize;
 | 
					
						
							|  |  |  |             let key = Bytes::copy_from_slice(&rbuf[..key_len]);
 | 
					
						
							|  |  |  |             rbuf.advance(key_len);
 | 
					
						
							|  |  |  |             let value_len = rbuf.get_u16() as usize;
 | 
					
						
							|  |  |  |             let value = Bytes::copy_from_slice(&rbuf[..value_len]);
 | 
					
						
							|  |  |  |             rbuf.advance(value_len);
 | 
					
						
							|  |  |  |             skiplist.insert(key, value);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(Self {
 | 
					
						
							|  |  |  |             file: Arc::new(Mutex::new(file)),
 | 
					
						
							|  |  |  |         })
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn put(&self, key: &[u8], value: &[u8]) -> Result<()> {
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  |         let mut file = self.file.lock();
 | 
					
						
							|  |  |  |         let mut buf: Vec<u8> =
 | 
					
						
							|  |  |  |             Vec::with_capacity(key.len() + value.len() + std::mem::size_of::<u16>());
 | 
					
						
							|  |  |  |         buf.put_u16(key.len() as u16);
 | 
					
						
							|  |  |  |         buf.put_slice(key);
 | 
					
						
							|  |  |  |         buf.put_u16(value.len() as u16);
 | 
					
						
							|  |  |  |         buf.put_slice(value);
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:44:38 +08:00
										 |  |  |         file.write_all(&buf)?;
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn sync(&self) -> Result<()> {
 | 
					
						
							| 
									
										
										
										
											2024-01-19 17:28:47 +08:00
										 |  |  |         let file = self.file.lock();
 | 
					
						
							|  |  |  |         file.sync_all()?;
 | 
					
						
							| 
									
										
										
										
											2024-01-19 11:21:38 +08:00
										 |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 |