#include "usg_common.h" #include "hashtable.h" #include "mm.h" #include "svsem.h" #include "bh_api.h" #include "logger_factory.h" #include #include #include typedef struct tailq_entry_t { void *value; int key; /* * This holds the pointers to the next and previous joint in * the tail queue. */ TAILQ_ENTRY(tailq_entry_t) joint; } tailq_entry_t; typedef TAILQ_HEAD(tailq_header_t, tailq_entry_t) tailq_header_t; static size_t hashcode(int key); void hashtable_init(hashtable_t *hashtable ) { memset(hashtable, 0, sizeof(hashtable_t)); hashtable->mutex = svsem_get(IPC_PRIVATE, 1); hashtable->queueCount = 0; hashtable->currentKey = START_KEY; } void hashtable_destroy(hashtable_t *hashtable) { svsem_remove( hashtable->mutex); } static inline void *_hashtable_get(hashtable_t *hashtable, int key) { size_t code = hashcode(key); tailq_entry_t *item; tailq_header_t *my_tailq_head = hashtable->array[code]; if ((my_tailq_head == NULL) || (check_mm_valid(my_tailq_head) == false)) { hashtable->array[code] = NULL; return NULL; } TAILQ_FOREACH(item, my_tailq_head, joint) { if ((check_mm_valid(item) == true) && ((key == item->key) || (code == item->key))) return item->value; break; } hashtable->array[code] = NULL; hashtable->queueCount--; mm_free(my_tailq_head); return NULL; } static inline void * _hashtable_put(hashtable_t *hashtable, int key, void *value) { size_t code = hashcode(key); void *oldvalue; tailq_entry_t *item; tailq_header_t *my_tailq_head = hashtable->array[code]; if ((my_tailq_head == NULL) || (check_mm_valid(my_tailq_head) == false)) { if (inter_key_get() == 0) { inter_key_set(key); } my_tailq_head = (tailq_header_t*) mm_malloc(sizeof(tailq_header_t )); TAILQ_INIT(my_tailq_head); hashtable->array[code] = my_tailq_head; goto putnew; } TAILQ_FOREACH(item, my_tailq_head, joint) { if ((check_mm_valid(item) == true) && (key ==item->key)) { oldvalue = item->value; item->key= key; item->value = value; return oldvalue; } goto putnew; } putnew: if (inter_key_get() == 0) { inter_key_set(key); } item = (tailq_entry_t *) mm_malloc(sizeof(tailq_entry_t)); item->key = key; item->value = value; TAILQ_INSERT_HEAD(my_tailq_head, item, joint); return NULL; } void hashtable_remove(hashtable_t *hashtable, int key) { size_t code = hashcode(key); tailq_entry_t *item; int rv; if( (rv = svsem_uni_wait(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_remove\n"); } tailq_header_t *my_tailq_head = hashtable->array[code]; if ((my_tailq_head == NULL) || (check_mm_valid(my_tailq_head) == false)) { hashtable->array[code] = NULL; if((rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_remove\n"); } return; } else { for (item = TAILQ_FIRST(my_tailq_head); item != NULL;) { /* Remove the item from the tail queue. */ TAILQ_REMOVE(my_tailq_head, item, joint); /* mm_free the item as we don't need it anymore. */ if (check_mm_valid(item) == true) mm_free(item); hashtable->array[code] = NULL; hashtable->queueCount--; mm_free(my_tailq_head); svsem_post(hashtable->mutex); return; } if((rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_remove\n"); } return; } } void *hashtable_get(hashtable_t *hashtable, int key) { int rv; if((rv = svsem_uni_wait(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_get\n"); } void * res = _hashtable_get(hashtable, key); if((rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_get\n"); } return res; } void hashtable_put(hashtable_t *hashtable, int key, void *value) { int rv; if((rv = svsem_uni_wait(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_put\n"); } _hashtable_put(hashtable, key, value); hashtable->queueCount++; if((rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_put\n"); } } bool hashtable_check_put(hashtable_t *hashtable, int key, void *value, bool overwrite) { int rv; void * val; if(( rv = svsem_uni_wait(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_put\n"); } if(overwrite) { _hashtable_put(hashtable, key, value); goto suc; } val = _hashtable_get(hashtable, key); if(val != NULL && val != (void *)1) goto fail; _hashtable_put(hashtable, key, value); suc: if(( rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_put\n"); } return true; fail: if(( rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_put\n"); } return false; } int hashtable_get_queue_count(hashtable_t *hashtable) { return hashtable->queueCount; } int hashtable_alloc_key(hashtable_t *hashtable) { int rv; int key = hashtable->currentKey; if( key == INT_MAX || key < START_KEY) { key = START_KEY; } rv = svsem_uni_wait(hashtable->mutex); if(rv != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_alloc_key\n"); } while(_hashtable_get(hashtable, key) != NULL) { key++; } // 占用key _hashtable_put(hashtable, key, (void *)1); hashtable->currentKey = key; rv = svsem_post(hashtable->mutex); if(rv != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_alloc_key\n"); } return key; } static inline void _hashtable_foreach(hashtable_t *hashtable, std::function cb) { tailq_entry_t *item; for (int i = 0; i < MAPSIZE; i++) { tailq_header_t *my_tailq_head = hashtable->array[i] ; if (my_tailq_head == NULL ) continue; TAILQ_FOREACH(item, my_tailq_head, joint) { cb(item->key, item -> value); } } } void hashtable_foreach(hashtable_t *hashtable, std::function cb) { return _hashtable_foreach(hashtable, cb); } std::set * hashtable_keyset(hashtable_t *hashtable) { std::set *keyset = new std::set; tailq_entry_t *item; for (int i = 0; i < MAPSIZE; i++) { tailq_header_t *my_tailq_head = hashtable->array[i] ; if (my_tailq_head == NULL ) continue; TAILQ_FOREACH(item, my_tailq_head, joint) { keyset->insert(item->key); } } return keyset; } void hashtable_removeall(hashtable_t *hashtable) { tailq_entry_t *item; int rv; if( (rv = svsem_uni_wait(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_removeall\n"); } for (int i = 0; i < MAPSIZE; i++) { tailq_header_t *my_tailq_head = hashtable->array[i] ; if (my_tailq_head == NULL ) continue; while ((item = TAILQ_FIRST(my_tailq_head)) ) { TAILQ_REMOVE(my_tailq_head, item, joint); mm_free(item); } mm_free(my_tailq_head); hashtable->array[i] = NULL; } hashtable->queueCount = 0; if((rv = svsem_post(hashtable->mutex)) != 0) { LoggerFactory::getLogger()->error(errno, "hashtable_removeall\n"); } } static size_t hashcode(int key) { int val; if (key < MAPSIZE) { val = key; } else { val = key % MAPSIZE % (MAPSIZE - START_KEY) + START_KEY; } return val; } /** * for debug */ static void hashtable_printall(hashtable_t *hashtable) { tailq_entry_t *item; for (int i = 0; i < MAPSIZE; i++) { tailq_header_t *my_tailq_head = hashtable->array[i] ; if (my_tailq_head == NULL ) continue; printf("code=%d\n", i); TAILQ_FOREACH(item, my_tailq_head, joint) { printf("%d:%s\n", item->key, (char *)item->value); } printf("\n"); } }