Cache limiter cleanup and small fixes

- Made code a bit less cluttered to follow
- Fixed possible deadlock when enforcing limit
  and highest priority element is still referenced.
This commit is contained in:
Sergey Sharybin 2013-12-10 15:07:10 +06:00
parent dde5e5ce25
commit aeee7118ae
1 changed files with 59 additions and 46 deletions

View File

@ -138,8 +138,8 @@ public:
typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data); typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data);
typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority); typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority);
MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func getDataSize_) MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func data_size_func)
: getDataSize(getDataSize_) { : data_size_func(data_size_func) {
} }
~MEM_CacheLimiter() { ~MEM_CacheLimiter() {
@ -162,10 +162,16 @@ public:
} }
size_t get_memory_in_use() { size_t get_memory_in_use() {
if (getDataSize) size_t size = 0;
return total_size(); if (data_size_func) {
else for (iterator it = queue.begin(); it != queue.end(); it++) {
return MEM_get_memory_in_use(); size += data_size_func((*it)->get()->get_data());
}
}
else {
size = MEM_get_memory_in_use();
}
return size;
} }
void enforce_limits() { void enforce_limits() {
@ -188,15 +194,15 @@ public:
if (!elem) if (!elem)
break; break;
if (getDataSize) { if (data_size_func) {
cur_size = getDataSize(elem->get()->get_data()); cur_size = data_size_func(elem->get()->get_data());
} }
else { else {
cur_size = mem_in_use; cur_size = mem_in_use;
} }
if (elem->destroy_if_possible()) { if (elem->destroy_if_possible()) {
if (getDataSize) { if (data_size_func) {
mem_in_use -= cur_size; mem_in_use -= cur_size;
} }
else { else {
@ -207,15 +213,21 @@ public:
} }
void touch(MEM_CacheLimiterHandle<T> * handle) { void touch(MEM_CacheLimiterHandle<T> * handle) {
queue.push_back(handle); /* If we're using custom priority callback re-arranging the queue
queue.erase(handle->me); * doesn't make much sense because we'll iterate it all to get
iterator it = queue.end(); * least priority element anyway.
--it; */
handle->me = it; if (item_priority_func == NULL) {
queue.push_back(handle);
queue.erase(handle->me);
iterator it = queue.end();
--it;
handle->me = it;
}
} }
void set_item_priority_func(MEM_CacheLimiter_ItemPriority_Func item_priority_func) { void set_item_priority_func(MEM_CacheLimiter_ItemPriority_Func item_priority_func) {
getItemPriority = item_priority_func; this->item_priority_func = item_priority_func;
} }
private: private:
@ -223,41 +235,42 @@ private:
typedef std::list<MEM_CacheElementPtr, MEM_Allocator<MEM_CacheElementPtr> > MEM_CacheQueue; typedef std::list<MEM_CacheElementPtr, MEM_Allocator<MEM_CacheElementPtr> > MEM_CacheQueue;
typedef typename MEM_CacheQueue::iterator iterator; typedef typename MEM_CacheQueue::iterator iterator;
size_t total_size() {
size_t size = 0;
for (iterator it = queue.begin(); it != queue.end(); it++) {
size+= getDataSize((*it)->get()->get_data());
}
return size;
}
MEM_CacheElementPtr get_least_priority_destroyable_element(void) { MEM_CacheElementPtr get_least_priority_destroyable_element(void) {
if (queue.empty()) if (queue.empty())
return NULL; return NULL;
if (!getItemPriority)
return *queue.begin();
MEM_CacheElementPtr best_match_elem = NULL; MEM_CacheElementPtr best_match_elem = NULL;
int best_match_priority = 0;
iterator it;
int i;
for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) { if (!item_priority_func) {
MEM_CacheElementPtr elem = *it; for (iterator it = queue.begin(); it != queue.end(); it++) {
MEM_CacheElementPtr elem = *it;
if (!elem->can_destroy()) if (!elem->can_destroy())
continue; continue;
/* by default 0 means highest priority element */
/* casting a size type to int is questionable,
but unlikely to cause problems */
int priority = -((int)(queue.size()) - i - 1);
priority = getItemPriority(elem->get()->get_data(), priority);
if (priority < best_match_priority || best_match_elem == NULL) {
best_match_priority = priority;
best_match_elem = elem; best_match_elem = elem;
break;
}
}
else {
int best_match_priority = 0;
iterator it;
int i;
for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) {
MEM_CacheElementPtr elem = *it;
if (!elem->can_destroy())
continue;
/* by default 0 means highest priority element */
/* casting a size type to int is questionable,
but unlikely to cause problems */
int priority = -((int)(queue.size()) - i - 1);
priority = item_priority_func(elem->get()->get_data(), priority);
if (priority < best_match_priority || best_match_elem == NULL) {
best_match_priority = priority;
best_match_elem = elem;
}
} }
} }
@ -265,8 +278,8 @@ private:
} }
MEM_CacheQueue queue; MEM_CacheQueue queue;
MEM_CacheLimiter_DataSize_Func getDataSize; MEM_CacheLimiter_DataSize_Func data_size_func;
MEM_CacheLimiter_ItemPriority_Func getItemPriority; MEM_CacheLimiter_ItemPriority_Func item_priority_func;
}; };
#endif // __MEM_CACHELIMITER_H__ #endif // __MEM_CACHELIMITER_H__