Skip to content

Commit

Permalink
[ISSUES nacos-group#19] add common cache component
Browse files Browse the repository at this point in the history
- support data sync to disk

relate nacos-group#19
  • Loading branch information
onewe committed Apr 20, 2023
1 parent 2050852 commit 3109b27
Show file tree
Hide file tree
Showing 5 changed files with 659 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ http = "0.2.9"
pin-project = "1.0.12"
futures-util = "0.3.28"
want = "0.3.0"
dashmap = "5.4.0"
home = "0.5.4"


[dev-dependencies]
Expand Down
5 changes: 0 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
use std::path::PathBuf;

fn main() {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
println!("cargo:warning={:?}", out_path);

tonic_build::configure()
.build_client(true)
.build_server(false)
Expand Down
163 changes: 163 additions & 0 deletions src/common/cache/disk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use std::{borrow::Cow, collections::HashMap, io::BufReader, path::PathBuf};

use serde::de;
use tokio::{
fs::{remove_file, OpenOptions},
io::AsyncWriteExt,
};
use tonic::async_trait;
use tracing::{debug, warn};

use super::Store;

pub(crate) struct DiskStore {
disk_path: PathBuf,
}

impl DiskStore {
pub(crate) fn new(disk_path: PathBuf) -> Self {
Self { disk_path }
}
}

#[async_trait]
impl<V> Store<V> for DiskStore
where
V: de::DeserializeOwned,
{
fn name(&self) -> Cow<str> {
Cow::from("disk store")
}

fn load(&mut self) -> HashMap<String, V> {
let mut default_map = HashMap::default();

let disk_path_display = self.disk_path.display();

if !self.disk_path.exists() {
warn!("disk path is not exists, trying create it.");
let ret = std::fs::create_dir_all(&self.disk_path);
if let Err(e) = ret {
warn!("create directory {} failed {}.", disk_path_display, e);
return default_map;
}
}

if !self.disk_path.is_dir() {
warn!("disk path is not a directory. {}", disk_path_display);
return default_map;
}

let dir_iter = std::fs::read_dir(&self.disk_path);
if let Err(e) = dir_iter {
warn!(
"read directory {} failed {}, trying create a empty directory",
disk_path_display, e
);
return default_map;
}

let dir_iter = dir_iter.unwrap();

for entry in dir_iter {
if entry.is_err() {
// skip
debug!("entry error");
continue;
}

let entry = entry.unwrap();
let path = entry.path();
if path.is_dir() {
// directory skip
continue;
}
let file = std::fs::File::open(&path);

if let Err(e) = file {
warn!("cannot open file {}, {}", path.display(), e);
continue;
}
let file = file.unwrap();
let reader = std::io::BufReader::new(file);

let ret = serde_json::from_reader::<BufReader<std::fs::File>, V>(reader);
if let Err(e) = ret {
warn!("cannot deserialize {}, {}.", path.display(), e);
continue;
}

let value = ret.unwrap();
let key = path.file_name();
if key.is_none() {
// skip
continue;
}

let key = key.unwrap();
let key: String = key.to_string_lossy().into();

default_map.insert(key, value);
}

default_map
}

async fn save(&mut self, key: &str, value: Vec<u8>) {
let mut write_path = PathBuf::from(&self.disk_path);
write_path.push(key);

let write_path_display = write_path.display();
debug!("save {}", write_path_display);

let file = OpenOptions::new()
.write(true)
.create(true)
.open(write_path.as_path())
.await;

if let Err(e) = file {
debug!("open file {} failed {}.", write_path_display, e);
return;
}

let mut file = file.unwrap();
let ret = file.write(&value).await;

if let Err(e) = ret {
let str = String::from_utf8(value);
if str.is_ok() {
warn!(
"the data {} cannot write to file {}, {}.",
str.unwrap(),
write_path_display,
e
);
} else {
warn!(
"write to file {} failed {} and the data cannot convert to string.",
write_path_display, e
);
}
return;
}
}

async fn remove(&mut self, key: &str) {
let mut delete_path = PathBuf::from(&self.disk_path);
delete_path.push(key);

let delete_path_display = delete_path.display();
debug!("remove {}", delete_path_display);

if !delete_path.exists() {
return;
}

let ret = remove_file(&delete_path).await;

if let Err(e) = ret {
warn!("delete file {} failed {}.", delete_path_display, e);
}
}
}
Loading

0 comments on commit 3109b27

Please sign in to comment.