1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
extern crate lru;
use std::collections::{BTreeMap, BTreeSet,HashMap};
use std::hash::Hash;
use lru::LruCache;
struct Page<K,V,E,P> {
key: K,
value: V,
expiry: E,
priority: P,
}
#[derive(Ord,PartialOrd, PartialEq, Eq)]
struct ItemExpiry<E,K> {
expiry: E,
key: K,
}
pub struct PECache<K,V,E,P> {
access_map: HashMap<K, Page<K,V,E,P>>,
evict_expiry: BTreeSet<ItemExpiry<E,K>>,
evict_priority: BTreeMap<P, LruCache<K, bool>>,
}
impl <K:Clone+Hash+Ord,
V: Clone+Eq+Hash+PartialEq,
E: Clone + Ord + Eq,
P: Clone + Ord
>PECache<K,V,E,P> {
/// Creates a new PE Cache.
///
/// # Examples
/// ```
/// use priority_expiry_cache::PECache;
/// let mut new_cache:PECache<String,String,u32,u32>= PECache::new();
/// ```
pub fn new() -> Self {
Self {
access_map: Default::default(),
evict_expiry: Default::default(),
evict_priority: Default::default(),
}
}
/// Add a new item to the cache or override the existing one if present in O(1) time.
///
/// # Examples
/// ```
/// use priority_expiry_cache::PECache;
/// let mut new_cache:PECache<String,String,u32,u32>= PECache::new();
/// let (key, value, expiry, priority) = (
/// String::from("key"),
/// String::from("value"), 1, 1);
/// new_cache.set(key.clone(),value.clone(), expiry, priority);
///
/// ```
pub fn set(&mut self, key: K, value: V, expiry: E, priority: P) {
// addition to the btree for time
let key_expiry: ItemExpiry<E, K> = ItemExpiry {
expiry: expiry.clone(),
key: key.clone(),
};
self.evict_expiry.insert(key_expiry);
// addition to the btree for priority
self.evict_priority.entry(priority.clone())
.or_insert(LruCache::unbounded()).push(key.clone(), true);
// add to the map
let page = Page { key: key.clone(), value, expiry, priority };
self.access_map.insert(key, page);
return;
}
/// Gat the value associated with the key if present or None if not in O(1) time.
///
/// # Examples
/// ```
/// use priority_expiry_cache::PECache;
/// let mut new_cache:PECache<String,String,u32,u32>= PECache::new();
///
/// // the get operation
/// let extracted_value = new_cache.get("key".to_string());
/// ```
pub fn get(&mut self, key: K) -> Option<V> {
if let Some(page) = self.access_map.get(&key) {
// change the order in the last recently data structure
self.evict_priority.get_mut(&page.priority).unwrap().promote(&page.key);
return Some(page.value.clone());
}
None
}
/// Evict 1 element following this policy if at least one element is present in O(1).
///
/// Policy:
/// - If an expired item is available. Remove it. If multiple items have the same expiry, removing any one suffices.
/// - If condition #1 can’t be satisfied, remove an item with the least priority.
/// - If more than one item satisfies condition #2, remove the least recently used one.
/// - Multiple items can have the same priority and expiry.
///
/// # Examples
/// ```
/// use priority_expiry_cache::PECache;
/// let mut new_cache:PECache<String,String,u32,u32>= PECache::new();
///
///
/// let extracted_value = new_cache.evict(10);
/// ```
pub fn evict(&mut self, barrier: E) {
if self.access_map.len() == 0 {
return;
}
// get key by check firs by time and then by priority/lru
let target_item = self.evict_expiry.first().unwrap();
let key_target = if target_item.expiry <= barrier { target_item.key.clone() } else {
let target_item = self.evict_priority.first_entry().unwrap();
let (key,_) = target_item.get().peek_lru().unwrap();
key.clone()
};
// delete from the map
let page = self.access_map.remove(&key_target).unwrap();
// delete from the expiry tree
self.evict_expiry.remove(&ItemExpiry{expiry: page.expiry.clone(),key: page.key.clone()});
// delete from priority tree
let node_priority = self.evict_priority.get_mut(&page.priority).unwrap();
node_priority.pop(&page.key);
// delete the node if empty after the item removal
if node_priority.len() == 0 {
self.evict_priority.remove(&page.priority);
}
return
}
/// Return the Length of Cache items in O(1).
///
/// # Examples
/// ```
/// use priority_expiry_cache::PECache;
/// let mut new_cache:PECache<String,String,u32,u32>= PECache::new();
///
///
/// let cache_n_size = new_cache.len();
/// ```
pub fn len(&self)->usize{
self.access_map.len()
}
}