Added last access time to cache.

This commit is contained in:
Jeff Baskin 2022-12-21 10:27:16 -05:00
parent 3164da0f4c
commit f0f8e7455e
1 changed files with 55 additions and 29 deletions

View File

@ -7,19 +7,19 @@ use async_std::{
}; };
use error::DBError; use error::DBError;
use rand::{distributions::Alphanumeric, thread_rng, Rng}; use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::{collections::HashMap, fmt, str}; use std::{collections::HashMap, fmt, str, time::Instant};
const DATA: &str = "data"; const DATA: &str = "data";
#[derive(Clone)] #[derive(Clone)]
enum CacheEntry { enum CacheType {
Raw(String), Raw(String),
} }
impl CacheEntry { impl CacheType {
fn entry_type(&self) -> String { fn entry_type(&self) -> String {
match self { match self {
CacheEntry::Raw(_) => "Raw".to_string(), CacheType::Raw(_) => "Raw".to_string(),
} }
} }
@ -27,12 +27,12 @@ impl CacheEntry {
let mut output = self.entry_type().into_bytes(); let mut output = self.entry_type().into_bytes();
output.push(0); output.push(0);
match self { match self {
CacheEntry::Raw(s) => output.append(&mut s.as_bytes().to_vec()), CacheType::Raw(s) => output.append(&mut s.as_bytes().to_vec()),
} }
return output; return output;
} }
fn from_bytes(data: Vec<u8>) -> CacheEntry { fn from_bytes(data: Vec<u8>) -> CacheType {
let mut data_iter = data.iter(); let mut data_iter = data.iter();
let mut holder: u8 = *data_iter.next().unwrap(); let mut holder: u8 = *data_iter.next().unwrap();
while holder != 0 { while holder != 0 {
@ -42,15 +42,36 @@ impl CacheEntry {
for letter in data_iter { for letter in data_iter {
output.push(letter.clone()); output.push(letter.clone());
} }
CacheEntry::Raw(str::from_utf8(&output).unwrap().to_string()) CacheType::Raw(str::from_utf8(&output).unwrap().to_string())
}
}
impl fmt::Display for CacheType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CacheType::Raw(s) => write!(f, "{}", s),
}
}
}
#[derive(Clone)]
struct CacheEntry {
data: CacheType,
last_used: Instant,
}
impl CacheEntry {
fn new(data: CacheType) -> Self {
Self {
data: data,
last_used: Instant::now(),
}
} }
} }
impl fmt::Display for CacheEntry { impl fmt::Display for CacheEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { write!(f, "{}", self.data)
CacheEntry::Raw(s) => write!(f, "{}", s),
}
} }
} }
@ -79,7 +100,7 @@ impl MoreThanText {
}) })
} }
async fn add_entry(&self, entry: CacheEntry) -> Result<String, DBError> { async fn add_entry(&self, entry: CacheType) -> Result<String, DBError> {
let mut id: String = "".to_string(); let mut id: String = "".to_string();
let mut dup = true; let mut dup = true;
while dup { while dup {
@ -95,7 +116,8 @@ impl MoreThanText {
} }
}; };
let mut cache = self.cache.lock().await; let mut cache = self.cache.lock().await;
cache.insert(id.clone(), entry); let data = CacheEntry::new(entry);
cache.insert(id.clone(), data);
Ok(id) Ok(id)
} }
@ -104,13 +126,16 @@ impl MoreThanText {
match cache.get(id) { match cache.get(id) {
Some(id) => Ok(id.clone()), Some(id) => Ok(id.clone()),
None => match read(Path::new(&self.dir).join(&id)).await { None => match read(Path::new(&self.dir).join(&id)).await {
Ok(content) => Ok(CacheEntry::from_bytes(content)), Ok(content) => {
let data = CacheType::from_bytes(content);
Ok(CacheEntry::new(data))
}
Err(_) => Err(DBError::new("cache entry not found")), Err(_) => Err(DBError::new("cache entry not found")),
}, },
} }
} }
async fn update_entry(&self, id: &str, entry: CacheEntry) -> Result<(), DBError> { async fn update_entry(&self, id: &str, entry: CacheType) -> Result<(), DBError> {
match self.get_entry(id).await { match self.get_entry(id).await {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(err), Err(err) => return Err(err),
@ -124,7 +149,8 @@ impl MoreThanText {
} }
} }
let mut cache = self.cache.lock().await; let mut cache = self.cache.lock().await;
cache.insert(id.to_string(), entry); let data = CacheEntry::new(entry);
cache.insert(id.to_string(), data);
Ok(()) Ok(())
} }
} }
@ -208,8 +234,8 @@ mod cache {
#[async_std::test] #[async_std::test]
async fn entry_ids_are_random() { async fn entry_ids_are_random() {
let mtt = MTT::new().await; let mtt = MTT::new().await;
let data1 = CacheEntry::Raw("one".to_string()); let data1 = CacheType::Raw("one".to_string());
let data2 = CacheEntry::Raw("two".to_string()); let data2 = CacheType::Raw("two".to_string());
let id1 = mtt.db.add_entry(data1).await.unwrap(); let id1 = mtt.db.add_entry(data1).await.unwrap();
let id2 = mtt.db.add_entry(data2).await.unwrap(); let id2 = mtt.db.add_entry(data2).await.unwrap();
assert_ne!(id1, id2, "Ids should be unique.") assert_ne!(id1, id2, "Ids should be unique.")
@ -219,7 +245,7 @@ mod cache {
async fn store_cache() { async fn store_cache() {
let mtt = MTT::new().await; let mtt = MTT::new().await;
let data = "something"; let data = "something";
let expected = CacheEntry::Raw(data.to_string()); let expected = CacheType::Raw(data.to_string());
let id = mtt.db.add_entry(expected.clone()).await.unwrap(); let id = mtt.db.add_entry(expected.clone()).await.unwrap();
let output = mtt.db.get_entry(&id).await.unwrap(); let output = mtt.db.get_entry(&id).await.unwrap();
assert_eq!(output.to_string(), data); assert_eq!(output.to_string(), data);
@ -233,7 +259,7 @@ mod cache {
async fn retrieve_from_disk() { async fn retrieve_from_disk() {
let mtt = MTT::new().await; let mtt = MTT::new().await;
let id = "someid"; let id = "someid";
let data = CacheEntry::Raw("stored".to_string()); let data = CacheType::Raw("stored".to_string());
write(mtt.dir.path().join(DATA).join(id), data.to_bytes()) write(mtt.dir.path().join(DATA).join(id), data.to_bytes())
.await .await
.unwrap(); .unwrap();
@ -246,7 +272,7 @@ mod cache {
let mtt = MTT::new().await; let mtt = MTT::new().await;
let msg = "could not write to file"; let msg = "could not write to file";
mtt.create_io_error().await; mtt.create_io_error().await;
match mtt.db.add_entry(CacheEntry::Raw("fail".to_string())).await { match mtt.db.add_entry(CacheType::Raw("fail".to_string())).await {
Ok(_) => assert!(false, "This test should fail."), Ok(_) => assert!(false, "This test should fail."),
Err(err) => { Err(err) => {
assert_eq!(err.to_string(), "data write"); assert_eq!(err.to_string(), "data write");
@ -271,11 +297,11 @@ mod cache {
let mtt = MTT::new().await; let mtt = MTT::new().await;
let id = mtt let id = mtt
.db .db
.add_entry(CacheEntry::Raw("same".to_string())) .add_entry(CacheType::Raw("same".to_string()))
.await .await
.unwrap(); .unwrap();
let expected = "different"; let expected = "different";
let expect = CacheEntry::Raw(expected.to_string()); let expect = CacheType::Raw(expected.to_string());
mtt.db.update_entry(&id, expect.clone()).await.unwrap(); mtt.db.update_entry(&id, expect.clone()).await.unwrap();
let output = mtt.db.get_entry(&id).await.unwrap(); let output = mtt.db.get_entry(&id).await.unwrap();
assert_eq!(output.to_string(), expected); assert_eq!(output.to_string(), expected);
@ -288,7 +314,7 @@ mod cache {
let mtt = MTT::new().await; let mtt = MTT::new().await;
match mtt match mtt
.db .db
.update_entry("wilma", CacheEntry::Raw("wrong".to_string())) .update_entry("wilma", CacheType::Raw("wrong".to_string()))
.await .await
{ {
Ok(_) => assert!(false, "Bad id should raise an error."), Ok(_) => assert!(false, "Bad id should raise an error."),
@ -302,13 +328,13 @@ mod cache {
let msg = "could not write to file"; let msg = "could not write to file";
let id = mtt let id = mtt
.db .db
.add_entry(CacheEntry::Raw("fleeting".to_string())) .add_entry(CacheType::Raw("fleeting".to_string()))
.await .await
.unwrap(); .unwrap();
mtt.create_io_error().await; mtt.create_io_error().await;
match mtt match mtt
.db .db
.update_entry(&id, CacheEntry::Raw("failure".to_string())) .update_entry(&id, CacheType::Raw("failure".to_string()))
.await .await
{ {
Ok(_) => assert!(false, "This should produce a write failure."), Ok(_) => assert!(false, "This should produce a write failure."),
@ -328,14 +354,14 @@ mod cache_entry {
#[test] #[test]
fn raw_get_type() { fn raw_get_type() {
let holder = CacheEntry::Raw("nothing important".to_string()); let holder = CacheType::Raw("nothing important".to_string());
assert_eq!(holder.entry_type(), "Raw"); assert_eq!(holder.entry_type(), "Raw");
} }
#[test] #[test]
fn raw_get_bytes() { fn raw_get_bytes() {
let data = "addams"; let data = "addams";
let holder = CacheEntry::Raw(data.to_string()); let holder = CacheType::Raw(data.to_string());
let mut expected = holder.entry_type().into_bytes(); let mut expected = holder.entry_type().into_bytes();
expected.push(0); expected.push(0);
expected.append(&mut data.as_bytes().to_vec()); expected.append(&mut data.as_bytes().to_vec());
@ -345,9 +371,9 @@ mod cache_entry {
#[test] #[test]
fn raw_from_bytes() { fn raw_from_bytes() {
let holder = CacheEntry::Raw("stored item".to_string()); let holder = CacheType::Raw("stored item".to_string());
let data = holder.to_bytes(); let data = holder.to_bytes();
let output = CacheEntry::from_bytes(data); let output = CacheType::from_bytes(data);
assert_eq!(output.to_string(), holder.to_string()); assert_eq!(output.to_string(), holder.to_string());
} }
} }