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