#include "btree_map.h" #include #include #include "murmurhash2.h" #include "binary.h" #include "erl_nif.h" // extend std::hash to understand Binary type namespace std { template <> struct hash { size_t operator()(const Binary& b) const { return MurmurHash2(b.bin, b.size, 4242); } }; } template struct LRUNode { K key; V data; void *kvenv; LRUNode *prev; LRUNode *next; size_t size; LRUNode(void *kvenv = NULL, size_t size=0) : kvenv(kvenv), prev(NULL), next(NULL), size(size) { } /* static void *LRUNode::operator new(size_t size) { return enif_alloc(size); } static void operator delete(void *block) { enif_free(block); } */ void printChain() { LRUNode* node; int i=11; std::cout << "("; for(node = this; node && i; node = node->next, i--) { std::cout << node->key << " -> "; } if (node) { std::cout << " loop detection end "; } else { std::cout << " end "; } std::cout << ")" << std::endl; } void printNextPrevKey() { std::cout << "("; printNextKey(); printPrevKey(); std::cout << ")"; } void printNextKey() { if (next) { std::cout << "next key " << next->key << " "; } } void printPrevKey() { if (prev) { std::cout << "prev key " << prev->key << " "; } } }; template class LRUBtree { private: LRUNode *oldest; LRUNode *latest; unsigned long size; unsigned long max_size; void (*node_free)(LRUBtree *lru, LRUNode *node); void (*node_kickout)(LRUBtree *lru, LRUNode *node, void *call_env); typedef btree::btree_map*> LRUBtree_map; public: LRUBtree_map bmap; bool pid_set = false; ErlNifPid pid; typedef typename LRUBtree_map::iterator iterator; typedef typename LRUBtree_map::reverse_iterator reverse_iterator; void printLatest() { if (latest) { std::cout << " latest " << latest->key; } else { std::cout << " no data in lru "; } } private: LRUNode* erase(LRUNode *node) { if (node->next) { node->next->prev = node->prev; } if (node->prev) { node->prev->next = node->next; } if (node == oldest) { oldest = node->prev; } if (node == latest) { latest = node->next; } if (node_free) { node_free(this, node); } node->next = NULL; node->prev = NULL; return node; } void printOldest() { if(oldest) { std::cout << " oldest " << oldest->key; } else { std::cout << " no data in lru "; } } void check_size(void *call_env) { if (size > max_size) { if (oldest) { // remove check if oldest exist and rely on max_size always being positive if (node_kickout) node_kickout(this, oldest, call_env); erase(oldest->key); } } } #define SIZE_100MB 100*1024*1024 public: LRUBtree(unsigned long max_size = SIZE_100MB, void (*node_free)(LRUBtree *lru, LRUNode *node) = NULL, void (*node_kickout)(LRUBtree *lru, LRUNode *node, void *call_env) = NULL) : oldest(NULL), latest(NULL), size(0), max_size(max_size), node_free(node_free), node_kickout(node_kickout) { } ~LRUBtree() { LRUNode *node; LRUNode *next; node = latest; while(node) { if (node_free) { node_free(this, node); } next = node->next; delete node; node = next; } } void printSize() { std::cout << "size " << size << std::endl; } unsigned long getSize() { return size; } unsigned long getMaxSize() { return max_size; } void setMaxSize(unsigned long max_size) { this->max_size = max_size; } void erase(K key) { LRUNode *node; if ((node = bmap[key])) { erase(node); bmap.erase(key); size -= node->size; delete node; } } inline void put(K key, V data, void *kvenv = NULL, void *call_env = NULL, size_t size = 1) { LRUNode *node; this->size += size; check_size(call_env); // overwrite already existing key if ((node = bmap[key])) { this->size -= node->size; erase(node); node->kvenv = kvenv; node->next = latest; node->size = size; if (node->next) { node->next->prev = node; } if (!oldest) { oldest = node; } latest = node; node->key = key; node->data = data; } else if (!oldest) { node = new LRUNode; node->key = key; node->data = data; node->kvenv = kvenv; node->size = size; oldest = node; latest = node; bmap[node->key] = node; } else { node = new LRUNode; node->key = key; node->data = data; node->kvenv = kvenv; node->size = size; latest->prev = node; node->next = latest; latest = node; bmap[node->key] = node; } } LRUNode* get(K key) { return bmap[key]; } LRUNode* getOldest() { return oldest; } LRUNode* getLatest() { return latest; } LRUNode* getNext(LRUNode *node) { return node->next; } LRUNode* getPrev(LRUNode *node) { return node->prev; } };