diff --git a/apc_cache.c b/apc_cache.c index 1e952e7..ceea399 100644 --- a/apc_cache.c +++ b/apc_cache.c @@ -43,14 +43,6 @@ #define CHECK(p) { if ((p) == NULL) return NULL; } -/* {{{ locking macros */ -#define CREATE_LOCK(lock) apc_lck_create(NULL, 0, 1, lock) -#define DESTROY_LOCK(lock) apc_lck_destroy(lock) -#define LOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c->header->lock); } -#define RDLOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c->header->lock); } -#define UNLOCK(c) { apc_lck_unlock(c->header->lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } -/* }}} */ - /* {{{ key_equals */ #define key_equals(a, b) (a.inode==b.inode && a.device==b.device) /* }}} */ diff --git a/apc_cache.h b/apc_cache.h index b723c90..2cfd23a 100644 --- a/apc_cache.h +++ b/apc_cache.h @@ -49,6 +49,15 @@ #define APC_CACHE_KEY_USER 2 #define APC_CACHE_KEY_FPFILE 3 +/* {{{ locking macros */ +#define CREATE_LOCK(lock) apc_lck_create(NULL, 0, 1, lock) +#define DESTROY_LOCK(lock) apc_lck_destroy(lock) +#define LOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c->header->lock); } +#define RDLOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c->header->lock); } +#define UNLOCK(c) { apc_lck_unlock(c->header->lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } +/* }}} */ + + /* {{{ struct definition: apc_cache_key_t */ #define T apc_cache_t* typedef struct apc_cache_t apc_cache_t; /* opaque cache type */ diff --git a/apc_iterator.c b/apc_iterator.c new file mode 100644 index 0000000..26fec8d --- /dev/null +++ b/apc_iterator.c @@ -0,0 +1,535 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2008 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. | + +----------------------------------------------------------------------+ + | Authors: Brian Shire | + +----------------------------------------------------------------------+ + + */ + +/* $Id$ */ + +#include "php_apc.h" +#include "apc_iterator.h" +#include "apc_cache.h" +#include "apc_stack.h" + +#include "zend_interfaces.h" + + +#define APC_DEFAULT_CHUNK_SIZE 100 + +zend_class_entry *apc_iterator_ce; +zend_object_handlers apc_iterator_object_handlers; +#define APC_ITERATOR_NAME "APCIterator" + +typedef void* (*apc_iterator_item_cb_t)(slot_t **slot); + +/* {{{ apc_iterator_t */ +typedef struct _apc_iterator_t { + zend_object obj; /* must always be first */ + short int initialized; /* sanity check in case __construct failed */ + int (*fetch)(struct _apc_iterator_t *iterator, apc_iterator_item_cb_t cb); + /* fetch callback to fetch items from cache slots or lists */ + apc_cache_t *cache; /* cache which we are iterating on */ + int slot_idx; /* index to the slot array or linked list */ + long chunk_size; /* number of entries to pull down per fetch */ + apc_stack_t *stack; /* stack of entries pulled from cache */ + int stack_idx; /* index into the current stack */ + regex_t c_regex; /* regex filter on entry identifiers */ + char *regex; /* original regex expression or NULL */ + int regex_len; /* regex length */ + short int totals_flag; /* flag if totals have been calculated */ + long hits; /* hit total */ + size_t size; /* size total */ + long count; /* count total */ +} apc_iterator_t; +/* }}} */ + +/* {{{ apc_iterator_item */ +typedef struct _apc_iterator_item_t { + char *key; /* string key */ + long key_len; /* strlen of key */ + zval *info; /* array of entry info */ +} apc_iterator_item_t; +/* }}} */ + +/* {{{ apc_iterator_item_key */ +static void* apc_iterator_item_key(slot_t **slot_pp) { + slot_t *slot = *slot_pp; + apc_iterator_item_t *item = emalloc(sizeof(apc_iterator_item_t)); + + if (slot->key.type == APC_CACHE_KEY_FILE) { + item->key = estrdup(slot->value->data.file.filename); + item->key_len = strlen(item->key); + } else if (slot->key.type == APC_CACHE_KEY_USER) { + item->key = estrndup((char*)slot->key.data.user.identifier, slot->key.data.user.identifier_len-1); + item->key_len = slot->key.data.user.identifier_len-1; + } else if (slot->key.type == APC_CACHE_KEY_FPFILE) { + item->key = estrndup((char*)slot->key.data.fpfile.fullpath, slot->key.data.fpfile.fullpath_len-1); + item->key_len = slot->key.data.fpfile.fullpath_len-1; + } else { + apc_eprint("Internal error, invalid entry type."); + } + item->info = NULL; + + return (void*)item; +} +/* }}} */ + +/* {{{ apc_iterator_item_info */ +static void* apc_iterator_item_info(slot_t **slot_pp) { + slot_t *slot = *slot_pp; + apc_iterator_item_t *item; + + item = (apc_iterator_item_t*)apc_iterator_item_key(slot_pp); + + ALLOC_INIT_ZVAL(item->info); + array_init(item->info); + if(slot->key.type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(item->info, "filename", slot->value->data.file.filename, 1); + add_assoc_long(item->info, "device", slot->key.data.file.device); + add_assoc_long(item->info, "inode", slot->key.data.file.inode); + add_assoc_string(item->info, "type", "file", 1); + } else if(slot->key.type == APC_CACHE_ENTRY_USER) { + add_assoc_string(item->info, "info", slot->value->data.user.info, 1); + add_assoc_long(item->info, "ttl", (long)slot->value->data.user.ttl); + add_assoc_string(item->info, "type", "user", 1); + } + add_assoc_long(item->info, "num_hits", slot->num_hits); + add_assoc_long(item->info, "mtime", slot->key.mtime); + add_assoc_long(item->info, "creation_time", slot->creation_time); + add_assoc_long(item->info, "deletion_time", slot->deletion_time); + add_assoc_long(item->info, "access_time", slot->access_time); + add_assoc_long(item->info, "ref_count", slot->value->ref_count); + add_assoc_long(item->info, "mem_size", slot->value->mem_size); + + return (void*)item; +} +/* }}} */ + +/* {{{ apc_iterator_clone */ +static zend_object_value apc_iterator_clone(zval *zobject TSRMLS_DC) { + apc_eprint("APCIterator object cannot be cloned."); +} +/* }}} */ + +/* {{{ apc_iterator_item_dtor */ +static void apc_iterator_item_dtor(apc_iterator_item_t *item) { + if (item->key) { + efree(item->key); + } + if (item->info) { + zval_ptr_dtor(&item->info); + } + efree(item); +} +/* }}} */ + +/* {{{ apc_iterator_destroy */ +static void apc_iterator_destroy(void *object, zend_object_handle handle TSRMLS_DC) { + apc_iterator_t *iterator = (apc_iterator_t*)object; + apc_iterator_item_t *item; + + if (iterator->initialized == 0) { + return; + } + + while (apc_stack_size(iterator->stack) > 0) { + apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); + } + if (iterator->regex) + efree(iterator->regex); + iterator->initialized = 0; + +} +/* }}} */ + +/* {{{ acp_iterator_free */ +static void apc_iterator_free(void *object TSRMLS_DC) { + zend_object_std_dtor(object TSRMLS_CC); + efree(object); +} +/* }}} */ + +/* {{{ apc_iterator_create */ +static zend_object_value apc_iterator_create(zend_class_entry *ce TSRMLS_DC) { + zend_object_value retval; + apc_iterator_t *iterator; + + iterator = emalloc(sizeof(apc_iterator_t)); + iterator->obj.ce = ce; + ALLOC_HASHTABLE(iterator->obj.properties); + zend_hash_init(iterator->obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + iterator->obj.guards = NULL; + retval.handle = zend_objects_store_put(iterator, apc_iterator_destroy, apc_iterator_free, NULL TSRMLS_CC); + retval.handlers = &apc_iterator_object_handlers; + //retval.handlers = zend_get_std_object_handers(); + + return retval; +} +/* }}} */ + +/* {{{ apc_iterator_fetch_active */ +static int apc_iterator_fetch_active(apc_iterator_t *iterator, apc_iterator_item_cb_t item_cb) { + int count=0; + slot_t **slot; + char *key; + apc_iterator_item_t *item; + + while (apc_stack_size(iterator->stack) > 0) { + apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); + } + + LOCK(iterator->cache); + while(count <= iterator->chunk_size && iterator->slot_idx < iterator->cache->num_slots) { + slot = &iterator->cache->slots[iterator->slot_idx]; + while(*slot) { + if ((*slot)->key.type == APC_CACHE_KEY_FILE) { + key = (*slot)->value->data.file.filename; + } else if ((*slot)->key.type == APC_CACHE_KEY_USER) { + key = (char*)(*slot)->key.data.user.identifier; + } else if ((*slot)->key.type == APC_CACHE_KEY_FPFILE) { + key = (char*)(*slot)->key.data.fpfile.fullpath; + } + if (!iterator->regex || regexec(&iterator->c_regex, key, 0, NULL, 0) == 0) { + count++; + item = item_cb(slot); + if (item) { + apc_stack_push(iterator->stack, item); + } + } + slot = &(*slot)->next; + } + iterator->slot_idx++; + } + UNLOCK(iterator->cache); + iterator->stack_idx = 0; + return count; +} +/* }}} */ + +/* {{{ apc_iterator_fetch_deleted */ +static int apc_iterator_fetch_deleted(apc_iterator_t *iterator, apc_iterator_item_cb_t item_cb) { + int count=0; + slot_t **slot; + char *key; + apc_iterator_item_t *item; + + LOCK(iterator->cache); + slot = &iterator->cache->header->deleted_list; + while ((*slot) && count <= iterator->slot_idx) { + count++; + slot = &(*slot)->next; + } + count = 0; + while ((*slot) && count < iterator->chunk_size) { + if ((*slot)->key.type == APC_CACHE_KEY_FILE) { + key = (*slot)->value->data.file.filename; + } else if ((*slot)->key.type == APC_CACHE_KEY_USER) { + key = (char*)(*slot)->key.data.user.identifier; + } else if ((*slot)->key.type == APC_CACHE_KEY_FPFILE) { + key = (char*)(*slot)->key.data.fpfile.fullpath; + } + if (!iterator->regex || regexec(&iterator->c_regex, key, 0, NULL, 0) == 0) { + count++; + item = item_cb(slot); + if (item) { + apc_stack_push(iterator->stack, item); + } + } + slot = &(*slot)->next; + } + UNLOCK(iterator->cache); + iterator->slot_idx += count; + iterator->stack_idx = 0; + return count; +} +/* }}} */ + +/* {{{ apc_iterator_totals */ +static void apc_iterator_totals(apc_iterator_t *iterator) { + slot_t **slot; + int i; + char *key; + + LOCK(iterator->cache); + for (i=0; i < iterator->cache->num_slots; i++) { + (*slot) = iterator->cache->slots[i]; + while((*slot)) { + if ((*slot)->key.type == APC_CACHE_KEY_FILE) { + key = (*slot)->value->data.file.filename; + } else if ((*slot)->key.type == APC_CACHE_KEY_USER) { + key = (char*)(*slot)->key.data.user.identifier; + } else if ((*slot)->key.type == APC_CACHE_KEY_FPFILE) { + key = (char*)(*slot)->key.data.fpfile.fullpath; + } + if (!iterator->regex || regexec(&iterator->c_regex, key, 0, NULL, 0) == 0) { + iterator->size += (*slot)->value->mem_size; + iterator->hits += (*slot)->num_hits; + iterator->count++; + } + (*slot) = (*slot)->next; + } + } + UNLOCK(iterator->cache); + iterator->totals_flag = 1; +} +/* }}} */ + + +/* {{{ proto object APCIterator::__costruct(string cache [, string regex [, long chunk_size] [, list ]]]) */ +PHP_METHOD(apc_iterator, __construct) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + char *cachetype; + int cachetype_len; + long chunk_size=0; + char *regex = NULL; + int regex_len = 0; + long list=0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sll", &cachetype, &cachetype_len, ®ex, ®ex_len, &chunk_size, &list) == FAILURE) { + return; + } + + if (chunk_size < 0) { + apc_eprint("APCIterator chunk size must be greater than 0!"); + return; + } + + if (list == APC_LIST_ACTIVE) { + iterator->fetch = apc_iterator_fetch_active; + } else if (list == APC_LIST_DELETED) { + iterator->fetch = apc_iterator_fetch_deleted; + } else { + apc_wprint("APCIterator invalid list type."); + return; + } + + if(!strcasecmp(cachetype,"user")) { + iterator->cache = apc_user_cache; + } else { + iterator->cache = apc_cache; + } + + iterator->slot_idx = 0; + iterator->chunk_size = chunk_size == 0 ? APC_DEFAULT_CHUNK_SIZE : chunk_size; + iterator->stack = apc_stack_create(chunk_size); + iterator->totals_flag = 0; + iterator->count = 0; + iterator->size = 0; + iterator->hits = 0; + if (regex_len) { + iterator->regex = estrndup(regex, regex_len); + iterator->regex_len = regex_len; + if(regcomp(&iterator->c_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) { + apc_eprint("Could not compile regular expression: %s", regex); + } + } else { + iterator->regex = NULL; + iterator->regex_len = 0; + } + iterator->initialized = 1; +} +/* }}} */ + +/* {{{ proto APCIterator::rewind() */ +PHP_METHOD(apc_iterator, rewind) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + slot_t **slots = iterator->cache->slots; + apc_iterator_item_t *item; + + if (iterator->initialized == 0) { + RETURN_FALSE; + } + + iterator->slot_idx = 0; + iterator->stack_idx = 0; + iterator->fetch(iterator, (apc_iterator_item_cb_t)apc_iterator_item_info); +} +/* }}} */ + +/* {{{ proto boolean APCIterator::valid() */ +PHP_METHOD(apc_iterator, valid) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + + if (iterator->initialized == 0) { + RETURN_FALSE; + } + + if (apc_stack_size(iterator->stack) == iterator->stack_idx) { + iterator->fetch(iterator, apc_iterator_item_info); + } + + RETURN_BOOL(apc_stack_size(iterator->stack) == 0 ? 0 : 1); +} +/* }}} */ + +/* {{{ proto mixed APCIterator::current() */ +PHP_METHOD(apc_iterator, current) { + zval *object = getThis(); + apc_iterator_item_t *item; + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + if (iterator->initialized == 0) { + RETURN_FALSE; + } + if (apc_stack_size(iterator->stack) == iterator->stack_idx) { + iterator->fetch(iterator, apc_iterator_item_info); + } + item = apc_stack_get(iterator->stack, iterator->stack_idx); + RETURN_ZVAL(item->info, 1, 0); +} +/* }}} */ + +/* {{{ proto string APCIterator::key() */ +PHP_METHOD(apc_iterator, key) { + zval *object = getThis(); + apc_iterator_item_t *item; + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + if (iterator->initialized == 0) { + RETURN_FALSE; + } + item = apc_stack_get(iterator->stack, iterator->stack_idx); + RETURN_STRINGL(item->key, item->key_len, 1); +} +/* }}} */ + +/* {{{ proto APCIterator::next() */ +PHP_METHOD(apc_iterator, next) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + if (iterator->initialized == 0) { + RETURN_FALSE; + } + iterator->stack_idx++; + return; +} +/* }}} */ + +/* {{{ proto long APCIterator::getTotalHits() */ +PHP_METHOD(apc_iterator, getTotalHits) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + slot_t *slot; + int i; + long hits=0; + char *key; + + if (iterator->totals_flag == 0) { + apc_iterator_totals(iterator); + } + + RETURN_LONG(iterator->hits); +} +/* }}} */ + +/* {{{ proto long APCIterator:;getTotalSize() */ +PHP_METHOD(apc_iterator, getTotalSize) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + + if (iterator->initialized == 0) { + RETURN_FALSE; + } + + if (iterator->totals_flag == 0) { + apc_iterator_totals(iterator); + } + + RETURN_LONG(iterator->size); +} +/* }}} */ + +/* {{{ proto long APCIterator::getTotalCount() */ +PHP_METHOD(apc_iterator, getTotalCount) { + zval *object = getThis(); + apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); + + if (iterator->initialized == 0) { + RETURN_FALSE; + } + + if (iterator->totals_flag == 0) { + apc_iterator_totals(iterator); + } + + RETURN_LONG(iterator->count); +} +/* }}} */ + +/* {{{ apc_iterator_functions */ +static function_entry apc_iterator_functions[] = { + PHP_ME(apc_iterator, __construct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, rewind, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, current, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, key, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, next, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, valid, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, getTotalHits, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, getTotalSize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(apc_iterator, getTotalCount, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ apc_iterator_init */ +int apc_iterator_init(int module_number TSRMLS_DC) { + zend_class_entry ce; + INIT_CLASS_ENTRY(ce, APC_ITERATOR_NAME, apc_iterator_functions); + apc_iterator_ce = zend_register_internal_class(&ce TSRMLS_CC); + apc_iterator_ce->create_object = apc_iterator_create; + zend_class_implements(apc_iterator_ce TSRMLS_CC, 1, zend_ce_iterator); + zend_register_long_constant("APC_LIST_ACTIVE", sizeof("APC_LIST_ACTIVE"), APC_LIST_ACTIVE, CONST_PERSISTENT | CONST_CS, module_number TSRMLS_CC); + zend_register_long_constant("APC_LIST_DELETED", sizeof("APC_LIST_DELETED"), APC_LIST_DELETED, CONST_PERSISTENT | CONST_CS, module_number TSRMLS_CC); + + memcpy(&apc_iterator_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + apc_iterator_object_handlers.clone_obj = apc_iterator_clone; + + return SUCCESS; +} +/* }}} */ + + +int apc_iterator_delete(zval *zobj TSRMLS_DC) { + apc_iterator_t *iterator; + zend_class_entry *ce = Z_OBJCE_P(zobj); + apc_iterator_item_t *item; + + if (!ce || !instanceof_function(ce, apc_iterator_ce TSRMLS_CC)) { + apc_eprint("apc_delete object argument must be instance of APCIterator"); + return 0; + } + iterator = (apc_iterator_t*)zend_object_store_get_object(zobj TSRMLS_CC); + + while (iterator->fetch(iterator, apc_iterator_item_key)) { + while (iterator->stack_idx < apc_stack_size(iterator->stack)) { + item = apc_stack_get(iterator->stack, iterator->stack_idx++); + apc_cache_user_delete(apc_user_cache, item->key, item->key_len); + } + } + + return 1; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ diff --git a/apc_iterator.h b/apc_iterator.h new file mode 100644 index 0000000..bd3a3e3 --- /dev/null +++ b/apc_iterator.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2008 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. | + +----------------------------------------------------------------------+ + | Authors: Brian Shire | + +----------------------------------------------------------------------+ + + */ + +/* $Id$ */ + +#ifndef APC_ITERATOR_H +#define APC_ITERATOR_H + +#include "apc.h" + +#define APC_LIST_ACTIVE 0 +#define APC_LIST_DELETED 1 + +extern int apc_iterator_init(int module_number TSRMLS_DC); +extern int apc_iterator_delete(zval *zobj TSRMLS_DC); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ diff --git a/apc_stack.c b/apc_stack.c index 792dd78..4160a25 100644 --- a/apc_stack.c +++ b/apc_stack.c @@ -95,6 +95,7 @@ int apc_stack_size(apc_stack_t* stack) return stack->size; } + /* * Local variables: * tab-width: 4 diff --git a/config.m4 b/config.m4 index 0c236f8..57a4521 100644 --- a/config.m4 +++ b/config.m4 @@ -243,7 +243,8 @@ if test "$PHP_APC" != "no"; then apc_zend.c \ apc_rfc1867.c \ apc_signal.c \ - apc_pool.c " + apc_pool.c \ + apc_iterator.c" PHP_CHECK_LIBRARY(rt, shm_open, [PHP_ADD_LIBRARY(rt,,APC_SHARED_LIBADD)]) PHP_NEW_EXTENSION(apc, $apc_sources, $ext_shared,, \\$(APC_CFLAGS)) diff --git a/php_apc.c b/php_apc.c index 171a57b..16a312e 100644 --- a/php_apc.c +++ b/php_apc.c @@ -30,6 +30,7 @@ #include "apc_zend.h" #include "apc_cache.h" +#include "apc_iterator.h" #include "apc_main.h" #include "apc_sma.h" #include "apc_lock.h" @@ -255,6 +256,7 @@ static PHP_MINIT_FUNCTION(apc) php_rfc1867_callback = apc_rfc1867_progress; } #endif + apc_iterator_init(module_number TSRMLS_CC); } } @@ -713,24 +715,51 @@ freepool: } /* }}} */ -/* {{{ proto mixed apc_delete(string key) + +/* {{{ proto mixed apc_delete(mixed keys) */ PHP_FUNCTION(apc_delete) { - char *strkey; - int strkey_len; + zval *keys; if(!APCG(enabled)) RETURN_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &keys) == FAILURE) { return; } - if(!strkey_len) RETURN_FALSE; - - if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) { - RETURN_TRUE; + if (Z_TYPE_P(keys) == IS_STRING) { + if (!Z_STRLEN_P(keys)) RETURN_FALSE; + if(apc_cache_user_delete(apc_user_cache, Z_STRVAL_P(keys), Z_STRLEN_P(keys) + 1)) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + } else if (Z_TYPE_P(keys) == IS_ARRAY) { + HashTable *hash = Z_ARRVAL_P(keys); + HashPosition hpos; + zval **hentry; + array_init(return_value); + zend_hash_internal_pointer_reset_ex(hash, &hpos); + while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { + if(Z_TYPE_PP(hentry) != IS_STRING) { + apc_wprint("apc_delete() expects a string, array of strings, or APCIterator instance."); + } + if(apc_cache_user_delete(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1)) { + add_next_index_bool(return_value, 1); + } else { + add_next_index_bool(return_value, 0); + } + zend_hash_move_forward_ex(hash, &hpos); + } + return; + } else if (Z_TYPE_P(keys) == IS_OBJECT) { + if (apc_iterator_delete(keys) TSRMLS_CC) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } } else { - RETURN_FALSE; + apc_wprint("apc_delete() expects a string, array of strings, or APCIterator instance."); } } /* }}} */ diff --git a/tests/iterator_001.phpt b/tests/iterator_001.phpt new file mode 100644 index 0000000..102efa1 --- /dev/null +++ b/tests/iterator_001.phpt @@ -0,0 +1,110 @@ +--TEST-- +APC: APCIterator general +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +apc.file_update_protection=0 +--FILE-- +$value) { + $vals[$key] = $value['info']; +} +ksort($vals); +var_dump($vals); + +?> +===DONE=== + +--EXPECTF-- +array(41) { + ["key0"]=> + string(4) "key0" + ["key1"]=> + string(4) "key1" + ["key10"]=> + string(5) "key10" + ["key11"]=> + string(5) "key11" + ["key12"]=> + string(5) "key12" + ["key13"]=> + string(5) "key13" + ["key14"]=> + string(5) "key14" + ["key15"]=> + string(5) "key15" + ["key16"]=> + string(5) "key16" + ["key17"]=> + string(5) "key17" + ["key18"]=> + string(5) "key18" + ["key19"]=> + string(5) "key19" + ["key2"]=> + string(4) "key2" + ["key20"]=> + string(5) "key20" + ["key21"]=> + string(5) "key21" + ["key22"]=> + string(5) "key22" + ["key23"]=> + string(5) "key23" + ["key24"]=> + string(5) "key24" + ["key25"]=> + string(5) "key25" + ["key26"]=> + string(5) "key26" + ["key27"]=> + string(5) "key27" + ["key28"]=> + string(5) "key28" + ["key29"]=> + string(5) "key29" + ["key3"]=> + string(4) "key3" + ["key30"]=> + string(5) "key30" + ["key31"]=> + string(5) "key31" + ["key32"]=> + string(5) "key32" + ["key33"]=> + string(5) "key33" + ["key34"]=> + string(5) "key34" + ["key35"]=> + string(5) "key35" + ["key36"]=> + string(5) "key36" + ["key37"]=> + string(5) "key37" + ["key38"]=> + string(5) "key38" + ["key39"]=> + string(5) "key39" + ["key4"]=> + string(4) "key4" + ["key40"]=> + string(5) "key40" + ["key5"]=> + string(4) "key5" + ["key6"]=> + string(4) "key6" + ["key7"]=> + string(4) "key7" + ["key8"]=> + string(4) "key8" + ["key9"]=> + string(4) "key9" +} +===DONE=== diff --git a/tests/iterator_002.phpt b/tests/iterator_002.phpt new file mode 100644 index 0000000..0610a40 --- /dev/null +++ b/tests/iterator_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +APC: APCIterator regex +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +apc.file_update_protection=0 +--FILE-- +$value) { + $vals[$key] = $value['info']; +} +ksort($vals); +var_dump($vals); + +?> +===DONE=== + +--EXPECTF-- +array(4) { + ["key10"]=> + string(5) "key10" + ["key20"]=> + string(5) "key20" + ["key30"]=> + string(5) "key30" + ["key40"]=> + string(5) "key40" +} +===DONE=== diff --git a/tests/iterator_003.phpt b/tests/iterator_003.phpt new file mode 100644 index 0000000..f53d483 --- /dev/null +++ b/tests/iterator_003.phpt @@ -0,0 +1,110 @@ +--TEST-- +APC: APCIterator chunk size +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +apc.file_update_protection=0 +--FILE-- +$value) { + $vals[$key] = $value['info']; +} +ksort($vals); +var_dump($vals); + +?> +===DONE=== + +--EXPECTF-- +array(41) { + ["key0"]=> + string(4) "key0" + ["key1"]=> + string(4) "key1" + ["key10"]=> + string(5) "key10" + ["key11"]=> + string(5) "key11" + ["key12"]=> + string(5) "key12" + ["key13"]=> + string(5) "key13" + ["key14"]=> + string(5) "key14" + ["key15"]=> + string(5) "key15" + ["key16"]=> + string(5) "key16" + ["key17"]=> + string(5) "key17" + ["key18"]=> + string(5) "key18" + ["key19"]=> + string(5) "key19" + ["key2"]=> + string(4) "key2" + ["key20"]=> + string(5) "key20" + ["key21"]=> + string(5) "key21" + ["key22"]=> + string(5) "key22" + ["key23"]=> + string(5) "key23" + ["key24"]=> + string(5) "key24" + ["key25"]=> + string(5) "key25" + ["key26"]=> + string(5) "key26" + ["key27"]=> + string(5) "key27" + ["key28"]=> + string(5) "key28" + ["key29"]=> + string(5) "key29" + ["key3"]=> + string(4) "key3" + ["key30"]=> + string(5) "key30" + ["key31"]=> + string(5) "key31" + ["key32"]=> + string(5) "key32" + ["key33"]=> + string(5) "key33" + ["key34"]=> + string(5) "key34" + ["key35"]=> + string(5) "key35" + ["key36"]=> + string(5) "key36" + ["key37"]=> + string(5) "key37" + ["key38"]=> + string(5) "key38" + ["key39"]=> + string(5) "key39" + ["key4"]=> + string(4) "key4" + ["key40"]=> + string(5) "key40" + ["key5"]=> + string(4) "key5" + ["key6"]=> + string(4) "key6" + ["key7"]=> + string(4) "key7" + ["key8"]=> + string(4) "key8" + ["key9"]=> + string(4) "key9" +} +===DONE=== diff --git a/tests/iterator_004.phpt b/tests/iterator_004.phpt new file mode 100644 index 0000000..d3cedbb --- /dev/null +++ b/tests/iterator_004.phpt @@ -0,0 +1,36 @@ +--TEST-- +APC: APCIterator regex & chunk size & list +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +apc.file_update_protection=0 +--FILE-- +$value) { + $vals[$key] = $value['info']; +} +ksort($vals); +var_dump($vals); + +?> +===DONE=== + +--EXPECTF-- +array(4) { + ["key10"]=> + string(5) "key10" + ["key20"]=> + string(5) "key20" + ["key30"]=> + string(5) "key30" + ["key40"]=> + string(5) "key40" +} +===DONE===