1 #include <lunaix/ds/lru.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/fs/twimap.h>
5 #include <lunaix/fs/twifs.h>
7 #include <klibc/string.h>
9 static struct llist_header zone_lead = { .next = &zone_lead, .prev = &zone_lead };
11 DEFINE_SPINLOCK_OPS(struct lru_zone*, lock);
15 __do_evict_lockless(struct lru_zone* zone, struct llist_header* elem)
18 if (!zone->try_evict(container_of(elem, struct lru_node, lru_nodes))) {
19 // if the node is unable to evict, raise it's rank by one, so
20 // others can have chance in the next round
21 struct llist_header* new_tail = zone->lead_node.prev;
22 llist_prepend(new_tail, elem);
27 zone->evict_stats.n_single++;
31 __lru_evict_all_lockness(struct lru_zone* zone)
33 struct llist_header* tail = zone->lead_node.prev;
34 while (tail != &zone->lead_node) {
35 __do_evict_lockless(zone, tail);
41 lru_new_zone(const char* name, evict_cb try_evict_cb)
43 struct lru_zone* zone = vzalloc(sizeof(struct lru_zone));
48 zone->try_evict = try_evict_cb;
50 strncpy(zone->name, name, sizeof(zone->name) - 1);
51 llist_init_head(&zone->lead_node);
52 llist_append(&zone_lead, &zone->zones);
53 spinlock_init(&zone->lock);
59 lru_free_zone(struct lru_zone* zone)
63 __lru_evict_all_lockness(zone);
65 if (llist_empty(&zone->lead_node)) {
66 llist_delete(&zone->zones);
72 We are unable to free it at this moment,
73 (probably due to tricky things happened
74 to some cached object). Thus mark it and
75 let the daemon try to free it asynchronously
77 zone->delayed_free = true;
84 lru_use_one(struct lru_zone* zone, struct lru_node* node)
88 assert(!zone->delayed_free);
90 if (node->lru_nodes.next && node->lru_nodes.prev) {
91 llist_delete(&node->lru_nodes);
97 llist_prepend(&zone->lead_node, &node->lru_nodes);
104 lru_evict_one(struct lru_zone* zone)
108 struct llist_header* tail = zone->lead_node.prev;
109 if (tail == &zone->lead_node) {
113 __do_evict_lockless(zone, tail);
119 lru_evict_half(struct lru_zone* zone)
123 int target = (int)(zone->objects / 2);
124 struct llist_header* tail = zone->lead_node.prev;
125 while (tail != &zone->lead_node && target > 0) {
126 __do_evict_lockless(zone, tail);
131 zone->evict_stats.n_half++;
137 lru_evict_all(struct lru_zone* zone)
141 __lru_evict_all_lockness(zone);
143 zone->evict_stats.n_full++;
149 lru_remove(struct lru_zone* zone, struct lru_node* node)
153 if (node->lru_nodes.next && node->lru_nodes.prev) {
154 llist_delete(&node->lru_nodes);
162 read_lrulist_entry(struct twimap* map)
164 struct lru_zone* zone;
166 zone = twimap_index(map, struct lru_zone*);
167 twimap_printf(map, "%s, %d, %d, %d, %d, %d, ",
171 zone->evict_stats.n_single,
172 zone->evict_stats.n_half,
173 zone->evict_stats.n_full);
175 if (zone->delayed_free) {
176 twimap_printf(map, "freeing %d attempts\n", zone->attempts);
179 twimap_printf(map, "active\n");
184 read_lrulist_reset(struct twimap* map)
186 map->index = container_of(&zone_lead, struct lru_zone, zones);
187 twimap_printf(map, "name, n_objs, hot, n_evt, n_half, n_full, status\n");
191 read_lrulist_next(struct twimap* map)
193 struct lru_zone* zone;
194 struct llist_header* next;
196 zone = twimap_index(map, struct lru_zone*);
197 next = zone->zones.next;
198 if (next == &zone_lead) {
202 map->index = container_of(next, struct lru_zone, zones);
207 lru_pool_twimappable()
211 map = twifs_mapping(NULL, NULL, "lru_pool");
212 map->read = read_lrulist_entry;
213 map->reset = read_lrulist_reset;
214 map->go_next = read_lrulist_next;
216 EXPORT_TWIFS_PLUGIN(__lru_twimap, lru_pool_twimappable);