diff --git a/HISTORY b/HISTORY index 5cd3ef0..f02cfe6 100644 --- a/HISTORY +++ b/HISTORY @@ -1,11 +1,12 @@ -Version 1.23 2015-11-02 +Version 1.23 2015-11-03 * sched_thread.c: task can execute in a new thread * sched_thread.c: support delay tasks * add function get_current_time_us and get_current_time_ms * mblock add stat function * add function get_sys_total_mem_size, ONLY support Linux and FreeBSD * delay task can execute in a new thread + * fast_mblock reclaimed object pool Version 1.22 2015-10-10 * export php function: fastcommon_get_first_local_ip diff --git a/src/fast_mblock.c b/src/fast_mblock.c index 430e2ca..a10c778 100644 --- a/src/fast_mblock.c +++ b/src/fast_mblock.c @@ -103,11 +103,13 @@ static void delete_from_mblock_list(struct fast_mblock_man *mblock) strcpy(pStat->name, current->info.name); \ pStat->element_size = current->info.element_size; \ } \ - pStat->total_count += current->info.total_count; \ - pStat->used_count += current->info.used_count; \ + pStat->element_total_count += current->info.element_total_count; \ + pStat->element_used_count += current->info.element_used_count; \ + pStat->trunk_total_count += current->info.trunk_total_count; \ + pStat->trunk_used_count += current->info.trunk_used_count; \ pStat->instance_count += current->info.instance_count; \ /* logInfo("name: %s, element_size: %d, total_count: %d, used_count: %d", */ \ - /* pStat->name, pStat->element_size, pStat->total_count, pStat->used_count); */\ + /* pStat->name, pStat->element_size, pStat->element_total_count, pStat->element_used_count); */\ } while (0) int fast_mblock_manager_stat(struct fast_mblock_info *stats, @@ -209,19 +211,22 @@ int fast_mblock_manager_stat_print() alloc_mem = 0; used_mem = 0; - logInfo("%32s %12s %16s %12s %12s %12s", "name", "element_size", - "instance_count", "alloc_count", "used_count", "used_ratio"); + logInfo("%32s %12s %16s %10s %10s %14s %12s %12s", "name", "element_size", + "instance_count", "trunc_alloc", "trunk_used", + "element_alloc", "element_used", "used_ratio"); stat_end = stats + count; for (pStat=stats; pStattotal_count; - used_mem += block_size * pStat->used_count; - logInfo("%32s %12d %16d %12d %12d %11.2f%%", pStat->name, + alloc_mem += block_size * pStat->element_total_count; + used_mem += block_size * pStat->element_used_count; + logInfo("%32s %12d %16d %10d %10d %14d %12d %11.2f%%", pStat->name, pStat->element_size, pStat->instance_count, - pStat->total_count, pStat->used_count, - pStat->total_count > 0 ? 100.00 * (double)pStat->used_count / - (double)pStat->total_count : 0.00); + pStat->trunk_total_count, pStat->trunk_used_count, + pStat->element_total_count, pStat->element_used_count, + pStat->element_total_count > 0 ? 100.00 * (double) + pStat->element_used_count / (double) + pStat->element_total_count : 0.00); } if (alloc_mem < 1024) @@ -296,12 +301,14 @@ int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name, } mblock->alloc_init_func = init_func; - mblock->malloc_chain_head = NULL; + INIT_HEAD(&mblock->trunks.head); + mblock->info.trunk_total_count = 0; + mblock->info.trunk_used_count = 0; mblock->free_chain_head = NULL; mblock->delay_free_chain.head = NULL; mblock->delay_free_chain.tail = NULL; - mblock->info.total_count = 0; - mblock->info.used_count = 0; + mblock->info.element_total_count = 0; + mblock->info.element_used_count = 0; mblock->info.instance_count = 1; mblock->need_lock = need_lock; @@ -361,6 +368,7 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock) return result; } } + pNode->offset = (int)(p - pNew); pNode->next = (struct fast_mblock_node *)(p + block_size); } @@ -373,38 +381,88 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock) return result; } } + ((struct fast_mblock_node *)pLast)->offset = (int)(pLast - pNew); ((struct fast_mblock_node *)pLast)->next = NULL; mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart; - pMallocNode->next = mblock->malloc_chain_head; - mblock->malloc_chain_head = pMallocNode; - mblock->info.total_count += mblock->alloc_elements_once; + pMallocNode->ref_count = 0; + pMallocNode->prev = mblock->trunks.head.prev; + pMallocNode->next = &mblock->trunks.head; + mblock->trunks.head.prev->next = pMallocNode; + mblock->trunks.head.prev = pMallocNode; + mblock->info.trunk_total_count++; + mblock->info.element_total_count += mblock->alloc_elements_once; return 0; } +static inline void fast_mblock_remove_trunk(struct fast_mblock_man *mblock, + struct fast_mblock_malloc *pMallocNode) +{ + pMallocNode->prev->next = pMallocNode->next; + pMallocNode->next->prev = pMallocNode->prev; + mblock->info.trunk_total_count--; + mblock->info.element_total_count -= mblock->alloc_elements_once; +} + +#define FAST_MBLOCK_GET_TRUNK(pNode) \ + (struct fast_mblock_malloc *)((char *)pNode - pNode->offset) + +static inline void fast_mblock_ref_counter_op(struct fast_mblock_man *mblock, + struct fast_mblock_node *pNode, const bool is_inc) +{ + struct fast_mblock_malloc *pMallocNode; + + pMallocNode = FAST_MBLOCK_GET_TRUNK(pNode); + if (is_inc) + { + if (pMallocNode->ref_count == 0) + { + mblock->info.trunk_used_count++; + } + pMallocNode->ref_count++; + } + else + { + pMallocNode->ref_count--; + if (pMallocNode->ref_count == 0) + { + mblock->info.trunk_used_count--; + } + } +} + +#define fast_mblock_ref_counter_inc(mblock, pNode) \ + fast_mblock_ref_counter_op(mblock, pNode, true) + +#define fast_mblock_ref_counter_dec(mblock, pNode) \ + fast_mblock_ref_counter_op(mblock, pNode, false) + void fast_mblock_destroy(struct fast_mblock_man *mblock) { struct fast_mblock_malloc *pMallocNode; struct fast_mblock_malloc *pMallocTmp; - if (mblock->malloc_chain_head == NULL) + if (IS_EMPTY(&mblock->trunks.head)) { return; } - pMallocNode = mblock->malloc_chain_head; - while (pMallocNode != NULL) + pMallocNode = mblock->trunks.head.next; + while (pMallocNode != &mblock->trunks.head) { pMallocTmp = pMallocNode; pMallocNode = pMallocNode->next; free(pMallocTmp); } - mblock->malloc_chain_head = NULL; + + INIT_HEAD(&mblock->trunks.head); + mblock->info.trunk_total_count = 0; + mblock->info.trunk_used_count = 0; mblock->free_chain_head = NULL; - mblock->info.used_count = 0; - mblock->info.total_count = 0; + mblock->info.element_used_count = 0; + mblock->info.element_total_count = 0; if (mblock->need_lock) pthread_mutex_destroy(&(mblock->lock)); delete_from_mblock_list(mblock); @@ -428,7 +486,9 @@ struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock) { pNode = mblock->free_chain_head; mblock->free_chain_head = pNode->next; - mblock->info.used_count++; + mblock->info.element_used_count++; + + fast_mblock_ref_counter_inc(mblock, pNode); } else { @@ -446,7 +506,8 @@ struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock) { pNode = mblock->free_chain_head; mblock->free_chain_head = pNode->next; - mblock->info.used_count++; + mblock->info.element_used_count++; + fast_mblock_ref_counter_inc(mblock, pNode); } else { @@ -481,7 +542,8 @@ int fast_mblock_free(struct fast_mblock_man *mblock, \ pNode->next = mblock->free_chain_head; mblock->free_chain_head = pNode; - mblock->info.used_count--; + mblock->info.element_used_count--; + fast_mblock_ref_counter_dec(mblock, pNode); if (mblock->need_lock && (result=pthread_mutex_unlock(&(mblock->lock))) != 0) { @@ -576,3 +638,181 @@ int fast_mblock_delay_free_count(struct fast_mblock_man *mblock) return fast_mblock_chain_count(mblock, mblock->delay_free_chain.head); } +static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock, + const int reclaim_target, int *reclaim_count, + struct fast_mblock_malloc **ppFreelist) +{ + struct fast_mblock_node *pPrevious; + struct fast_mblock_node *pCurrent; + struct fast_mblock_malloc *pMallocNode; + struct fast_mblock_malloc *freelist; + bool lookup_done; + + lookup_done = false; + *reclaim_count = 0; + freelist = NULL; + pPrevious = NULL; + pCurrent = mblock->free_chain_head; + mblock->free_chain_head = NULL; + while (pCurrent != NULL) + { + pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); + if (pMallocNode->ref_count > 0 || + (pMallocNode->ref_count == 0 && lookup_done)) + { //keep in free chain + + if (pPrevious != NULL) + { + pPrevious->next = pCurrent; + } + else + { + mblock->free_chain_head = pCurrent; + } + + pPrevious = pCurrent; + pCurrent = pCurrent->next; + if (pCurrent == NULL) + { + goto OUTER; + } + pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); + + while (pMallocNode->ref_count > 0 || + (pMallocNode->ref_count == 0 && lookup_done)) + { + pPrevious = pCurrent; + pCurrent = pCurrent->next; + if (pCurrent == NULL) + { + goto OUTER; + } + pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); + } + } + + while (pMallocNode->ref_count < 0 || + (pMallocNode->ref_count == 0 && !lookup_done)) + { + if (pMallocNode->ref_count == 0) //trigger by the first node + { + fast_mblock_remove_trunk(mblock, pMallocNode); + pMallocNode->ref_count = -1; + + pMallocNode->next = freelist; + freelist = pMallocNode; + (*reclaim_count)++; + if (*reclaim_count == reclaim_target) + { + lookup_done = true; + } + } + + pCurrent = pCurrent->next; + if (pCurrent == NULL) + { + goto OUTER; + } + pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); + } + } + + +OUTER: + if (pPrevious != NULL) + { + pPrevious->next = NULL; + } + + + { + bool old_need_lock; + old_need_lock = mblock->need_lock; + mblock->need_lock = false; + logDebug("file: "__FILE__", line: %d, " + "reclaim trunks for %p, reclaimed trunks: %d, " + "free node count: %d", __LINE__, + mblock, *reclaim_count, fast_mblock_free_count(mblock)); + mblock->need_lock = mblock->need_lock; + } + + *ppFreelist = freelist; + return (freelist != NULL ? 0 : ENOENT); +} + +void fast_mblock_free_trunks(struct fast_mblock_man *mblock, + struct fast_mblock_malloc *freelist) +{ + struct fast_mblock_malloc *pDeleted; + int count; + count = 0; + while (freelist != NULL) + { + pDeleted = freelist; + freelist = freelist->next; + free(pDeleted); + count++; + } + logDebug("file: "__FILE__", line: %d, " + "free_trunks for %p, free trunks: %d", __LINE__, + mblock, count); +} + +int fast_mblock_reclaim(struct fast_mblock_man *mblock, + const int reclaim_target, int *reclaim_count, + fast_mblock_free_trunks_func free_trunks_func) +{ + int result; + struct fast_mblock_malloc *freelist; + + if (reclaim_target <= 0) + { + *reclaim_count = 0; + return EINVAL; + } + + if (mblock->need_lock && (result=pthread_mutex_lock(&(mblock->lock))) != 0) + { + logError("file: "__FILE__", line: %d, " \ + "call pthread_mutex_lock fail, " \ + "errno: %d, error info: %s", \ + __LINE__, result, STRERROR(result)); + *reclaim_count = 0; + return result; + } + + if (mblock->info.trunk_total_count - mblock->info.trunk_used_count < reclaim_target) + { + *reclaim_count = 0; + result = E2BIG; + freelist = NULL; + } + else + { + result = fast_mblock_do_reclaim(mblock, reclaim_target, + reclaim_count, &freelist); + } + + if (mblock->need_lock && (result=pthread_mutex_unlock(&(mblock->lock))) != 0) + { + logError("file: "__FILE__", line: %d, " \ + "call pthread_mutex_unlock fail, " \ + "errno: %d, error info: %s", \ + __LINE__, result, STRERROR(result)); + } + + if (result == 0) + { + if (free_trunks_func != NULL) + { + free_trunks_func(mblock, freelist); + } + else + { + fast_mblock_free_trunks(mblock, freelist); + } + } + + return result; +} + diff --git a/src/fast_mblock.h b/src/fast_mblock.h index 21eb0b0..b5e8138 100644 --- a/src/fast_mblock.h +++ b/src/fast_mblock.h @@ -24,6 +24,7 @@ struct fast_mblock_node { struct fast_mblock_node *next; + int offset; //trunk offset int recycle_timestamp; char data[0]; //the data buffer }; @@ -31,6 +32,8 @@ struct fast_mblock_node /* malloc chain */ struct fast_mblock_malloc { + int64_t ref_count; //refference count + struct fast_mblock_malloc *prev; struct fast_mblock_malloc *next; }; @@ -45,18 +48,26 @@ struct fast_mblock_info { char name[FAST_MBLOCK_NAME_SIZE]; int element_size; //element size - int total_count; //total element count - int used_count; //used element count + int element_total_count; //total element count + int element_used_count; //used element count + int trunk_total_count; //total trunk count + int trunk_used_count; //used trunk count int instance_count; //instance count }; +struct fast_mblock_trunks +{ + struct fast_mblock_malloc head; //malloc chain to be freed +}; + struct fast_mblock_man { struct fast_mblock_info info; int alloc_elements_once; //alloc elements once struct fast_mblock_node *free_chain_head; //free node chain + struct fast_mblock_trunks trunks; struct fast_mblock_chain delay_free_chain; //delay free node chain - struct fast_mblock_malloc *malloc_chain_head; //malloc chain to be freed + fast_mblock_alloc_init_func alloc_init_func; bool need_lock; //if need mutex lock pthread_mutex_t lock; //the lock for read / write free node chain @@ -233,6 +244,32 @@ return error no, 0 for success, != 0 fail */ int fast_mblock_manager_stat_print(); +typedef void (*fast_mblock_free_trunks_func)(struct fast_mblock_man *mblock, + struct fast_mblock_malloc *freelist); + +/** +free the trunks +parameters: + mblock: the mblock pointer + freelist: the trunks to free +return error no, 0 for success, != 0 fail +*/ +void fast_mblock_free_trunks(struct fast_mblock_man *mblock, + struct fast_mblock_malloc *freelist); + +/** +reclaim the free trunks of the mblock +parameters: + mblock: the mblock pointer + reclaim_target: reclaim target trunks + reclaim_count: reclaimed trunk count + freelist: the free trunks +return error no, 0 for success, != 0 fail +*/ +int fast_mblock_reclaim(struct fast_mblock_man *mblock, + const int reclaim_target, int *reclaim_count, + fast_mblock_free_trunks_func free_trunks_func); + #ifdef __cplusplus } #endif