diff --git a/beast.c b/beast.c index e074f48..bc3af17 100644 --- a/beast.c +++ b/beast.c @@ -31,22 +31,14 @@ #include "ext/standard/info.h" #include "php_streams.h" #include "php_beast.h" +#include "cache.h" #include "encrypt.h" /* If you declare any globals in php_beast.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(beast) */ -#define HASH_INIT_SIZE 32 -#define FREE_CACHE_LENGTH 100 -#define DEFAULT_MAX_CACHE_SIZE 1048576 - -struct beast_cache_item { - int fsize; - int rsize; - void *data; - struct beast_cache_item *next; -}; +#define DEFAULT_CACHE_SIZE (5 * 1024 * 1024) zend_op_array* (*old_compile_file)(zend_file_handle*, int TSRMLS_DC); @@ -60,12 +52,7 @@ static char authkey[8] = { /* True global resources - no need for thread safety here */ static int le_beast; -static int max_cache_size = DEFAULT_MAX_CACHE_SIZE; -static int cache_use_mem = 0; -static int cache_threshold = 0; -static HashTable *htable; -static struct beast_cache_item *free_cache_list = NULL; -static int free_cache_len = 0; +static int max_cache_size = DEFAULT_CACHE_SIZE; static int cache_hits = 0; static int cache_miss = 0; @@ -75,8 +62,8 @@ static int cache_miss = 0; */ zend_function_entry beast_functions[] = { PHP_FE(beast_encode_file, NULL) - PHP_FE(beast_cache_status, NULL) - PHP_FE(beast_clean_caches, NULL) + PHP_FE(beast_avail_cache, NULL) + PHP_FE(beast_cache_info, NULL) {NULL, NULL, NULL} /* Must be the last line in beast_functions[] */ }; /* }}} */ @@ -95,7 +82,7 @@ zend_module_entry beast_module_entry = { PHP_RSHUTDOWN(beast), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(beast), #if ZEND_MODULE_API_NO >= 20010901 - "0.2", /* Replace with version number for your extension */ + "0.3", /* Replace with version number for your extension */ #endif STANDARD_MODULE_PROPERTIES }; @@ -106,39 +93,14 @@ ZEND_GET_MODULE(beast) #endif -struct beast_cache_item *cache_item_alloc() -{ - struct beast_cache_item *item; - - if (free_cache_len > 0) { - item = free_cache_list; - free_cache_list = free_cache_list->next; - free_cache_len--; - } else { - item = malloc(sizeof(*item)); - } - return item; -} - - -void cache_item_free(struct beast_cache_item *item) -{ - if (free_cache_len < FREE_CACHE_LENGTH) { /* cache item */ - item->next = free_cache_list; - free_cache_list = item; - free_cache_len++; - } else { - free(item); - } -} - /***************************************************************************** * * * Encrypt a plain text file and output a cipher file * * * *****************************************************************************/ -int encrypt_file(const char *inputfile, const char *outputfile, const char *key TSRMLS_DC) { +int encrypt_file(const char *inputfile, const char *outputfile, const char *key TSRMLS_DC) +{ php_stream *input_stream, *output_stream; php_stream_statbuf stat_ssb; int fsize, fcount, i; @@ -187,20 +149,6 @@ int encrypt_file(const char *inputfile, const char *outputfile, const char *key } -int beast_clean_cache(char *key, int keyLength, void *value, void *data) { - struct beast_cache_item *item; - - if (hash_remove(htable, key, &item) == 0) { - cache_use_mem -= item->rsize; - free(item->data); /* free cache data */ - cache_item_free(item); - if (cache_use_mem <= cache_threshold) { - return -1; /* break foreach */ - } - } - return 0; -} - /***************************************************************************** * * * Decrypt a cipher text file and output plain buffer * @@ -208,13 +156,16 @@ int beast_clean_cache(char *key, int keyLength, void *value, void *data) { *****************************************************************************/ int decrypt_file_return_buffer(const char *inputfile, const char *key, - char **buf, int *filesize, int *realsize TSRMLS_DC) { + char **buffer, int *filesize TSRMLS_DC) +{ php_stream *stream; - int fsize, bsize, i; - int allocsize; + php_stream_statbuf stat_ssb; + cache_key_t ckey; + cache_item_t *citem; + int fsize, bsize, msize, i; char input[8]; char header[8]; - char *plaintext, *phpcode; + char *text, *script; stream = php_stream_open_wrapper(inputfile, "r", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL); @@ -222,6 +173,27 @@ int decrypt_file_return_buffer(const char *inputfile, const char *key, return -1; } + if (php_stream_stat(stream, &stat_ssb)) { + php_stream_pclose(stream); + return -1; + } + + /* here not set file size because find cache not need file size */ + ckey.device = stat_ssb.sb.st_dev; + ckey.inode = stat_ssb.sb.st_ino; + ckey.mtime = stat_ssb.sb.st_mtime; + + citem = beast_cache_find(&ckey); /* find cache */ + if (citem) { /* found cache */ + *buffer = beast_cache_cdata(citem); + *filesize = beast_cache_fsize(citem) + 3; + php_stream_pclose(stream); + cache_hits++; + return 0; + } + + /* not found cache */ + if ((php_stream_read(stream, header, 8) != 8) || *((int *)&header[0]) != 0xe816a40c) { @@ -231,40 +203,38 @@ int decrypt_file_return_buffer(const char *inputfile, const char *key, fsize = *((int *)&header[4]); bsize = fsize / 8 + 1; /* block count */ + msize = bsize * 8 + 3; - allocsize = bsize * 8 + 3; + ckey.fsize = fsize; /* set file size */ - if (cache_use_mem + allocsize > max_cache_size) { /* exceed max cache size, free some cache */ - cache_threshold = max_cache_size - allocsize; /* set threshold value */ - hash_foreach(htable, beast_clean_cache, NULL); - } - - /* OK, enough memory to alloc caches */ - - plaintext = malloc(allocsize); /* alloc memory(1) */ - if (!plaintext) { + citem = beast_cache_create(&ckey, msize); + if (!citem) { php_stream_pclose(stream); return -1; } + text = beast_cache_cdata(citem); + /* For closing php script environment " ?>" */ - plaintext[0] = ' '; - plaintext[1] = '?'; - plaintext[2] = '>'; + text[0] = ' '; + text[1] = '?'; + text[2] = '>'; - phpcode = &plaintext[3]; + script = &text[3]; for (i = 0; i < bsize; i++) { php_stream_read(stream, input, 8); - DES_decipher(input, &(phpcode[i * 8]), key); + DES_decipher(input, &(script[i * 8]), key); } - *buf = plaintext; - *filesize = fsize + 3; - *realsize = allocsize; + php_stream_pclose(stream); - cache_use_mem += allocsize; /* all caches used memory size */ + citem = beast_cache_push(citem); /* push into cache item to manager */ + + *buffer = beast_cache_cdata(citem); + *filesize = beast_cache_fsize(citem) + 3; + + cache_miss++; - php_stream_pclose(stream); return 0; } @@ -272,37 +242,15 @@ int decrypt_file_return_buffer(const char *inputfile, const char *key, zend_op_array* my_compile_file(zend_file_handle* h, int type TSRMLS_DC) { - char *phpcode, *file_path; - int filesize, realsize; + char *script, *file_path; + int fsize; zval pv; zend_op_array *new_op_array; - struct beast_cache_item *cache; - int nfree = 0; - if (hash_lookup(htable, h->filename, (void **)&cache) == 0) { /* cache exists */ - filesize = cache->fsize; - phpcode = cache->data; - cache_hits++; - } else { /* cache not exists */ - if (decrypt_file_return_buffer(h->filename, authkey, &phpcode, - &filesize, &realsize TSRMLS_CC) != 0) - { - return old_compile_file(h, type TSRMLS_CC); - } - - cache = cache_item_alloc(); - if (!cache) { - nfree = 1; - } else { - cache->fsize = filesize; /* save file size */ - cache->rsize = realsize; /* save real size */ - cache->data = phpcode; /* save php code */ - if (hash_insert(htable, h->filename, cache) != 0) { - cache_item_free(cache); - nfree = 1; - } - } - cache_miss++; + if (decrypt_file_return_buffer(h->filename, authkey, &script, + &fsize TSRMLS_CC) != 0) + { + return old_compile_file(h, type TSRMLS_CC); } if (h->opened_path) { @@ -311,16 +259,12 @@ my_compile_file(zend_file_handle* h, int type TSRMLS_DC) file_path = h->filename; } - pv.value.str.len = filesize; - pv.value.str.val = phpcode; + pv.value.str.len = fsize; + pv.value.str.val = script; pv.type = IS_STRING; new_op_array = compile_string(&pv, file_path TSRMLS_CC); - if (nfree) { - free(phpcode); /* free memory(1) */ - } - return new_op_array; } @@ -341,14 +285,14 @@ ZEND_INI_MH(php_beast_cache_size) max_cache_size = atoi(new_value); if (max_cache_size <= 0) { - max_cache_size = DEFAULT_MAX_CACHE_SIZE; + max_cache_size = DEFAULT_CACHE_SIZE; } return SUCCESS; } PHP_INI_BEGIN() - PHP_INI_ENTRY("beast.cache_size", "1048576", PHP_INI_ALL, php_beast_cache_size) + PHP_INI_ENTRY("beast.cache_size", "5242880", PHP_INI_ALL, php_beast_cache_size) PHP_INI_END() /* }}} */ @@ -374,35 +318,23 @@ PHP_MINIT_FUNCTION(beast) /* If you have INI entries, uncomment these lines */ REGISTER_INI_ENTRIES(); + if (beast_cache_init(max_cache_size) == -1) { + return FAILURE; + } + old_compile_file = zend_compile_file; zend_compile_file = my_compile_file; - htable = hash_alloc(HASH_INIT_SIZE); - if (!htable) { - return FAILURE; - } - return SUCCESS; } /* }}} */ -void beast_destroy_handler(void *data) -{ - struct beast_cache_item *item = data; - if (item) { - free(item->data); - free(item); - } -} - /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(beast) { /* uncomment this line if you have INI entries */ UNREGISTER_INI_ENTRIES(); - - hash_destroy(htable, &beast_destroy_handler); return SUCCESS; } /* }}} */ @@ -480,42 +412,21 @@ PHP_FUNCTION(beast_encode_file) } -int beast_cache_list(char *key, int keyLength, void *value, void *data) +PHP_FUNCTION(beast_avail_cache) { - zval *retval = data; - struct beast_cache_item *item = value; - - add_assoc_long(retval, key, item->rsize); + int size = beast_mm_availspace(); + RETURN_LONG(size); } -PHP_FUNCTION(beast_cache_status) +PHP_FUNCTION(beast_cache_info) { array_init(return_value); - hash_foreach(htable, beast_cache_list, (void *)return_value); - add_assoc_long(return_value, "total", cache_use_mem); + beast_cache_info(return_value); add_assoc_long(return_value, "cache_hits", cache_hits); add_assoc_long(return_value, "cache_miss", cache_miss); } - -int __clean_cache(char *key, int keyLength, void *value, void *data) -{ - struct beast_cache_item *item; - - if (hash_remove(htable, key, &item) == 0) { - cache_use_mem -= item->rsize; - free(item->data); /* free cache data */ - cache_item_free(item); - } - return 0; -} - -PHP_FUNCTION(beast_clean_caches) -{ - hash_foreach(htable, __clean_cache, NULL); - RETURN_TRUE; -} /* }}} */ diff --git a/beast_lock.c b/beast_lock.c new file mode 100644 index 0000000..6b787a1 --- /dev/null +++ b/beast_lock.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_SEMUN +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* array for GETALL, SETALL */ + /* Linux specific part: */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; +#endif + +#ifndef SEM_R +# define SEM_R 0444 +#endif +#ifndef SEM_A +# define SEM_A 0222 +#endif + +/* always use SEM_UNDO, otherwise we risk deadlock */ +#define USE_SEM_UNDO + +#ifdef USE_SEM_UNDO +# define UNDO SEM_UNDO +#else +# define UNDO 0 +#endif + +int beast_sem_create(int initval) +{ + int semid; + union semun arg; + key_t key = IPC_PRIVATE; + + if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0777)) >= 0) { + arg.val = initval; + if (semctl(semid, 0, SETVAL, arg) < 0) { + return -1; + } + } else if (errno == EEXIST) { + if ((semid = semget(key, 1, 0777)) < 0) { + return -1; + } + } else { + return -1; + } + return semid; +} + +int beast_sem_lock(int semid) +{ + struct sembuf op; + + op.sem_num = 0; + op.sem_op = -1; /* we want alloc 1 sem */ + op.sem_flg = UNDO; + + if (semop(semid, &op, 1) < 0) { + return -1; + } + return 0; +} + +int beast_sem_unlock(int semid) +{ + struct sembuf op; + + op.sem_num = 0; + op.sem_op = 1; + op.sem_flg = UNDO; + + if (semop(semid, &op, 1) < 0) { + return -1; + } + return 0; +} + +int beast_sem_destroy(int semid) +{ + union semun arg; + semctl(semid, 0, IPC_RMID, arg); +} diff --git a/beast_lock.h b/beast_lock.h new file mode 100644 index 0000000..a6dad69 --- /dev/null +++ b/beast_lock.h @@ -0,0 +1,16 @@ +#ifndef __BEAST_LOCK_H +#define __BEAST_LOCK_H + +int beast_sem_create(int initval); +int beast_sem_lock(int semid); +int beast_sem_unlock(int semid); +int beast_sem_destroy(int semid); + +typedef int beast_locker_t; + +#define beast_locker_create() beast_sem_create(1) +#define beast_locker_lock(locker) beast_sem_lock(locker) +#define beast_locker_unlock(locker) beast_sem_unlock(locker) +#define beast_locker_destroy(locker) beast_sem_destroy(locker) + +#endif diff --git a/beast_mm.c b/beast_mm.c new file mode 100644 index 0000000..c79cbda --- /dev/null +++ b/beast_mm.c @@ -0,0 +1,296 @@ + +/* +--------------------------------+ + * | share memory manager algorithm | + * +--------------------------------+ + */ + +#include +#include +#include +#include +#include +#include + +#include "beast_lock.h" + +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif + +#define BEAST_SEGMENT_DEFAULT_SIZE (1024 * 1024) + +#define _BLOCKAT(offset) ((beast_block_t *)((char *)shmaddr + (offset))) +#define _OFFSET(block) ((int)(((char *)(block)) - (char *)shmaddr)) + +#ifdef max +#undef max +#endif +#define max(a, b) ((a) > (b) ? (a) : (b)) + + +typedef struct beast_header_s { + int segsize; /* size of entire segment */ + int avail; /* bytes available memorys */ +} beast_header_t; + + +typedef struct beast_block_s { + int size; /* size of this block */ + int next; /* offset in segment of next free block */ +} beast_block_t; + + +static int beast_mm_initialized = 0; +static void *beast_mm_block = NULL; +static int beast_mm_block_size = 0; +static beast_locker_t beast_mm_locker; + + +/* + * memory align function + * @param bits, align bits + */ +static inline int beast_mm_alignmem(int bits) +{ + typedef union { + void* p; + int i; + long l; + double d; + void (*f)(); + } beast_word_t; /* may be 8 bits */ + + return sizeof(beast_word_t) * (1 + ((bits - 1) / sizeof(beast_word_t))); +} + +static int beast_mm_allocate(void *shmaddr, int size) +{ + beast_header_t *header; /* header of shared memory segment */ + beast_block_t *prv; /* block prior to working block */ + beast_block_t *cur; /* working block in list */ + beast_block_t *prvbestfit; /* block before best fit */ + int realsize; /* actual size of block needed, including header */ + int minsize; /* for finding best fit */ + + /* Realsize must be aligned to a word boundary on some architectures. */ + realsize = beast_mm_alignmem(max(size + beast_mm_alignmem(sizeof(int)), + sizeof(beast_block_t))); + + /* + * First, insure that the segment contains at least realsize free bytes, + * even if they are not contiguous. + */ + header = (beast_header_t *)shmaddr; + if (header->avail < realsize) { + return -1; + } + + prvbestfit = 0; + minsize = INT_MAX; + + prv = _BLOCKAT(sizeof(beast_header_t)); + while (prv->next != 0) { + cur = _BLOCKAT(prv->next); + if (cur->size == realsize) { + prvbestfit = prv; + break; + } + else if (cur->size > (sizeof(beast_block_t) + realsize) && + cur->size < minsize) + { + prvbestfit = prv; + minsize = cur->size; + } + prv = cur; + } + + if (prvbestfit == 0) { + return -1; + } + + prv = prvbestfit; + cur = _BLOCKAT(prv->next); + + /* update the block header */ + header->avail -= realsize; + + if (cur->size == realsize) { + prv->next = cur->next; + } else { + beast_block_t *nxt; /* the new block (chopped part of cur) */ + int nxtoffset; /* offset of the block currently after cur */ + int oldsize; /* size of cur before split */ + + /* bestfit is too big; split it into two smaller blocks */ + nxtoffset = cur->next; + oldsize = cur->size; + prv->next += realsize; + cur->size = realsize; + nxt = _BLOCKAT(prv->next); + nxt->next = nxtoffset; + nxt->size = oldsize - realsize; + } + + return _OFFSET(cur) + beast_mm_alignmem(sizeof(int)); /* skip size field */ +} + + +static int beast_mm_deallocate(void *shmaddr, int offset) +{ + beast_header_t *header; /* header of shared memory segment */ + beast_block_t *cur; /* the new block to insert */ + beast_block_t *prv; /* the block before cur */ + beast_block_t *nxt; /* the block after cur */ + int size; /* size of deallocated block */ + + offset -= beast_mm_alignmem(sizeof(int)); + + /* find position of new block in free list */ + prv = _BLOCKAT(sizeof(beast_header_t)); + while (prv->next != 0 && prv->next < offset) { + prv = _BLOCKAT(prv->next); + } + + /* insert new block after prv */ + cur = _BLOCKAT(offset); + cur->next = prv->next; + prv->next = offset; + + /* update the block header */ + header = (beast_header_t *)shmaddr; + header->avail += cur->size; + size = cur->size; + + if (((char *)prv) + prv->size == (char *) cur) { + /* cur and prv share an edge, combine them */ + prv->size += cur->size; + prv->next = cur->next; + cur = prv; + } + + nxt = _BLOCKAT(cur->next); + if (((char *)cur) + cur->size == (char *) nxt) { + /* cur and nxt shared an edge, combine them */ + cur->size += nxt->size; + cur->next = nxt->next; + } + + return size; +} + + +/* + * init memory manager + */ +int beast_mm_init(int block_size) +{ + beast_header_t *header; + beast_block_t *block; + void *shmaddr; + + if (beast_mm_initialized) { + return 0; + } + + beast_mm_locker = beast_locker_create(); + if (beast_mm_locker == -1) { + return -1; + } + + if (block_size < BEAST_SEGMENT_DEFAULT_SIZE) { + beast_mm_block_size = BEAST_SEGMENT_DEFAULT_SIZE; + } else { + beast_mm_block_size = block_size; + } + + shmaddr = beast_mm_block = (void *)mmap(NULL, beast_mm_block_size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + if (!beast_mm_block) { + return -1; + } + + header = (beast_header_t *)beast_mm_block; + header->segsize = beast_mm_block_size; + header->avail = beast_mm_block_size - sizeof(beast_header_t) - + sizeof(beast_block_t) - beast_mm_alignmem(sizeof(int)); /* avail size */ + + /* the free list head block node */ + block = _BLOCKAT(sizeof(beast_header_t)); + block->size = 0; + block->next = sizeof(beast_header_t) + sizeof(beast_block_t); + + /* the avail block */ + block = _BLOCKAT(block->next); + block->size = header->avail; + block->next = 0; + + beast_mm_initialized = 1; + + return 0; +} + + +void *beast_mm_malloc(int size) +{ + int offset; + void *p = NULL; + + beast_locker_lock(beast_mm_locker); + + offset = beast_mm_allocate(beast_mm_block, size); + if (offset != -1) { + p = (void *)(((char *)beast_mm_block) + offset); + } + + beast_locker_unlock(beast_mm_locker); + + return p; +} + + +void *beast_mm_calloc(int size) +{ + int offset; + void *p = NULL; + + beast_locker_lock(beast_mm_locker); + + offset = beast_mm_allocate(beast_mm_block, size); + if (offset != -1) { + p = (void *)(((char *)beast_mm_block) + offset); + } + + beast_locker_unlock(beast_mm_locker); + + if (NULL != p) + memset(p, 0, size); + return p; +} + + +void beast_mm_free(void *p) +{ + int offset = (unsigned int)((char *)p - (char *)beast_mm_block); + + beast_locker_lock(beast_mm_locker); + beast_mm_deallocate(beast_mm_block, offset); + beast_locker_unlock(beast_mm_locker); +} + + +int beast_mm_availspace() +{ + beast_header_t *header = (beast_header_t *)beast_mm_block; + return header->avail; +} + + +void beast_mm_destroy() +{ + if (beast_mm_initialized) { + munmap(beast_mm_block, beast_mm_block_size); + beast_locker_destroy(beast_mm_locker); + beast_mm_initialized = 0; + } +} + diff --git a/beast_mm.h b/beast_mm.h new file mode 100644 index 0000000..4e6089d --- /dev/null +++ b/beast_mm.h @@ -0,0 +1,11 @@ +#ifndef __BEAST_MM_H +#define __BEAST_MM_H + +int beast_mm_init(int block_size); +void *beast_mm_malloc(int size); +void *beast_mm_calloc(int size); +void beast_mm_free(void *p); +int beast_mm_availspace(); +void beast_mm_destroy(); + +#endif diff --git a/cache.c b/cache.c new file mode 100644 index 0000000..a0c4708 --- /dev/null +++ b/cache.c @@ -0,0 +1,238 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Liexusong <280259971@qq.com> | + +----------------------------------------------------------------------+ +*/ + +#include +#include "beast_mm.h" +#include "beast_lock.h" +#include "php.h" +#include "cache.h" + + +#define BUCKETS_DEFAULT_SIZE 1021 + + +static int beast_cache_initialization = 0; +static cache_item_t **beast_cache_buckets = NULL; +static beast_locker_t beast_cache_locker; + + +static int beast_cache_hash(cache_key_t *key) +{ + return key->device * 3 + key->inode * 7; +} + + +int beast_cache_init(int size) +{ + int index; + + if (beast_cache_initialization) { + return 0; + } + + if (beast_mm_init(size) == -1) { + return -1; + } + + beast_cache_locker = beast_locker_create(); + if (beast_cache_locker == -1) { + return -1; + } + + beast_cache_buckets = beast_mm_malloc(sizeof(cache_item_t *) * BUCKETS_DEFAULT_SIZE); + if (!beast_cache_buckets) { + return -1; + } + + for (index = 0; index < BUCKETS_DEFAULT_SIZE; index++) { + beast_cache_buckets[index] = NULL; + } + + beast_cache_initialization = 1; + + return 0; +} + + +cache_item_t *beast_cache_find(cache_key_t *key) +{ + int hashval = beast_cache_hash(key); + int index = hashval % BUCKETS_DEFAULT_SIZE; + cache_item_t *item, *temp; + + beast_locker_lock(beast_cache_locker); + + item = beast_cache_buckets[index]; + while (item) { + if (item->key.device == key->device && + item->key.inode == key->inode) + { + break; + } + item = item->next; + } + + if (item && item->key.mtime < key->mtime) /* cache exprie */ + { + temp = beast_cache_buckets[index]; + if (temp == item) { /* first node */ + beast_cache_buckets[index] = NULL; + } else { + while (temp->next != item) + temp = temp->next; + temp->next = item->next; + } + + beast_mm_free(item); + item = NULL; + } + + beast_locker_unlock(beast_cache_locker); + + return item; +} + + +cache_item_t *beast_cache_create(cache_key_t *key, int size) +{ + cache_item_t *item, *next; + int i, msize; + + msize = sizeof(*item) + size; + + item = beast_mm_malloc(msize); + if (!item) + { + beast_locker_lock(beast_cache_locker); + + for (i = 0; i < BUCKETS_DEFAULT_SIZE; i++) { + if (beast_mm_availspace() >= msize) { + break; + } + + item = beast_cache_buckets[i]; + while (item) { + next = item->next; + beast_mm_free(item); + item = next; + } + beast_cache_buckets[i] = NULL; + } + + beast_locker_unlock(beast_cache_locker); + + item = beast_mm_malloc(msize); + if (!item) { + return NULL; + } + } + + item->key.device = key->device; + item->key.inode = key->inode; + item->key.fsize = key->fsize; + item->key.mtime = key->mtime; + item->next = NULL; + + return item; +} + + +/* + * Push cache item into cache manager, + * this function return a cache item, + * may be return value not equals push item, + * so we must use return value. + */ +cache_item_t *beast_cache_push(cache_item_t *item) +{ + int hashval = beast_cache_hash(&item->key); + int index = hashval % BUCKETS_DEFAULT_SIZE; + cache_item_t **this; + + beast_locker_lock(beast_cache_locker); + + this = &beast_cache_buckets[index]; + while (*this) { + /* this item was exists */ + if (!memcmp(&(*this)->key, &item->key, sizeof(cache_key_t))) { + beast_mm_free(item); + item = *this; + break; + } + this = &(*this)->next; + } + + *this = item; + + beast_locker_unlock(beast_cache_locker); + + return item; +} + + +int beast_cache_destroy() +{ + int index; + cache_item_t *item, *next; + + if (!beast_cache_initialization) { + return 0; + } + + beast_locker_lock(beast_cache_locker); + + for (index = 0; index < BUCKETS_DEFAULT_SIZE; index++) { + item = beast_cache_buckets[index]; + while (item) { + next = item->next; + beast_mm_free(item); + item = next; + } + } + beast_mm_free(beast_cache_buckets); + + beast_mm_destroy(); + + beast_locker_unlock(beast_cache_locker); + beast_locker_destroy(beast_cache_locker); + + beast_cache_initialization = 0; + + return 0; +} + + +void beast_cache_info(zval *retval) +{ + char key[128]; + int i; + cache_item_t *item; + + beast_locker_lock(beast_cache_locker); + + for (i = 0; i < BUCKETS_DEFAULT_SIZE; i++) { + item = beast_cache_buckets[i]; + while (item) { + sprintf(key, "{device(%d)#inode(%d)}", item->key.device, item->key.inode); + add_assoc_long(retval, key, item->key.fsize); + item = item->next; + } + } + + beast_locker_unlock(beast_cache_locker); +} diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..6d6fb17 --- /dev/null +++ b/cache.h @@ -0,0 +1,28 @@ +#ifndef __BEAST_CACHE_H +#define __BEAST_CACHE_H + +typedef struct cache_key_s { + int device; + int inode; + int mtime; + int fsize; +} cache_key_t; + + +typedef struct cache_item_s { + cache_key_t key; + struct cache_item_s *next; + char data[0]; +} cache_item_t; + + +#define beast_cache_cdata(item) (item)->data +#define beast_cache_fsize(item) (item)->key.fsize + +int beast_cache_init(); +cache_item_t *beast_cache_find(cache_key_t *key); +cache_item_t *beast_cache_create(cache_key_t *key, int size); +cache_item_t *beast_cache_push(cache_item_t *item); +int beast_cache_destroy(); + +#endif diff --git a/config.m4 b/config.m4 index 727a4c2..3bc528e 100644 --- a/config.m4 +++ b/config.m4 @@ -59,5 +59,5 @@ if test "$PHP_BEAST" != "no"; then dnl dnl PHP_SUBST(BEAST_SHARED_LIBADD) - PHP_NEW_EXTENSION(beast, beast.c encrypt.c bit.c hash.c, $ext_shared) + PHP_NEW_EXTENSION(beast, beast.c encrypt.c bit.c beast_mm.c beast_lock.c cache.c, $ext_shared) fi diff --git a/php_beast.h b/php_beast.h index cae8d42..8f03cec 100644 --- a/php_beast.h +++ b/php_beast.h @@ -41,8 +41,8 @@ PHP_RSHUTDOWN_FUNCTION(beast); PHP_MINFO_FUNCTION(beast); PHP_FUNCTION(beast_encode_file); -PHP_FUNCTION(beast_cache_status); -PHP_FUNCTION(beast_clean_caches); +PHP_FUNCTION(beast_avail_cache); +PHP_FUNCTION(beast_cache_info); /* Declare any global variables you may need between the BEGIN