Ai
2 Star 7 Fork 0

Moses/php-memcache-test

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
memcache.c 59.51 KB
一键复制 编辑 原始数据 按行查看 历史
renfeng 提交于 2014-11-27 11:44 +08:00 . php-memcache3.0.8 初始版本
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 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_0.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: Antony Dovgal <tony2001@phpclub.net> |
| Mikael Johansson <mikael AT synd DOT info> |
+----------------------------------------------------------------------+
*/
/* $Id: memcache.c 329835 2013-03-19 22:39:10Z hradtke $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "ext/standard/php_string.h"
#include "php_memcache.h"
#ifndef ZEND_ENGINE_2
#define OnUpdateLong OnUpdateInt
#endif
/* True global resources - no need for thread safety here */
static int le_memcache_pool, le_memcache_server;
static zend_class_entry *memcache_pool_ce;
static zend_class_entry *memcache_ce;
ZEND_EXTERN_MODULE_GLOBALS(memcache)
/* {{{ memcache_functions[]
*/
zend_function_entry memcache_functions[] = {
PHP_FE(memcache_connect, NULL)
PHP_FE(memcache_pconnect, NULL)
PHP_FE(memcache_add_server, NULL)
PHP_FE(memcache_set_server_params, NULL)
PHP_FE(memcache_set_failure_callback, NULL)
PHP_FE(memcache_get_server_status, NULL)
PHP_FE(memcache_get_version, NULL)
PHP_FE(memcache_add, NULL)
PHP_FE(memcache_set, NULL)
PHP_FE(memcache_replace, NULL)
PHP_FE(memcache_cas, NULL)
PHP_FE(memcache_append, NULL)
PHP_FE(memcache_prepend, NULL)
PHP_FE(memcache_get, NULL)
PHP_FE(memcache_delete, NULL)
PHP_FE(memcache_debug, NULL)
PHP_FE(memcache_get_stats, NULL)
PHP_FE(memcache_get_extended_stats, NULL)
PHP_FE(memcache_set_compress_threshold, NULL)
PHP_FE(memcache_increment, NULL)
PHP_FE(memcache_decrement, NULL)
PHP_FE(memcache_close, NULL)
PHP_FE(memcache_flush, NULL)
{NULL, NULL, NULL}
};
static zend_function_entry php_memcache_pool_class_functions[] = {
PHP_NAMED_FE(connect, zif_memcache_pool_connect, NULL)
PHP_NAMED_FE(addserver, zif_memcache_pool_addserver, NULL)
PHP_FALIAS(setserverparams, memcache_set_server_params, NULL)
PHP_FALIAS(setfailurecallback, memcache_set_failure_callback, NULL)
PHP_FALIAS(getserverstatus, memcache_get_server_status, NULL)
PHP_NAMED_FE(findserver, zif_memcache_pool_findserver, NULL)
PHP_FALIAS(getversion, memcache_get_version, NULL)
PHP_FALIAS(add, memcache_add, NULL)
PHP_FALIAS(set, memcache_set, NULL)
PHP_FALIAS(replace, memcache_replace, NULL)
PHP_FALIAS(cas, memcache_cas, NULL)
PHP_FALIAS(append, memcache_append, NULL)
PHP_FALIAS(prepend, memcache_prepend, NULL)
PHP_FALIAS(get, memcache_get, NULL)
PHP_FALIAS(delete, memcache_delete, NULL)
PHP_FALIAS(getstats, memcache_get_stats, NULL)
PHP_FALIAS(getextendedstats, memcache_get_extended_stats, NULL)
PHP_FALIAS(setcompressthreshold, memcache_set_compress_threshold, NULL)
PHP_FALIAS(increment, memcache_increment, NULL)
PHP_FALIAS(decrement, memcache_decrement, NULL)
PHP_FALIAS(close, memcache_close, NULL)
PHP_FALIAS(flush, memcache_flush, NULL)
{NULL, NULL, NULL}
};
static zend_function_entry php_memcache_class_functions[] = {
PHP_FALIAS(connect, memcache_connect, NULL)
PHP_FALIAS(pconnect, memcache_pconnect, NULL)
PHP_FALIAS(addserver, memcache_add_server, NULL)
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ memcache_module_entry
*/
zend_module_entry memcache_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"memcache",
memcache_functions,
PHP_MINIT(memcache),
PHP_MSHUTDOWN(memcache),
NULL,
NULL,
PHP_MINFO(memcache),
#if ZEND_MODULE_API_NO >= 20010901
PHP_MEMCACHE_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_MEMCACHE
ZEND_GET_MODULE(memcache)
#endif
static PHP_INI_MH(OnUpdateChunkSize) /* {{{ */
{
long int lval;
lval = strtol(new_value, NULL, 10);
if (lval <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.chunk_size must be a positive integer ('%s' given)", new_value);
return FAILURE;
}
return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* }}} */
static PHP_INI_MH(OnUpdateFailoverAttempts) /* {{{ */
{
long int lval;
lval = strtol(new_value, NULL, 10);
if (lval <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.max_failover_attempts must be a positive integer ('%s' given)", new_value);
return FAILURE;
}
return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* }}} */
static PHP_INI_MH(OnUpdateProtocol) /* {{{ */
{
if (!strcasecmp(new_value, "ascii")) {
MEMCACHE_G(protocol) = MMC_ASCII_PROTOCOL;
}
else if (!strcasecmp(new_value, "binary")) {
MEMCACHE_G(protocol) = MMC_BINARY_PROTOCOL;
}
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.protocol must be in set {ascii, binary} ('%s' given)", new_value);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
static PHP_INI_MH(OnUpdateHashStrategy) /* {{{ */
{
if (!strcasecmp(new_value, "standard")) {
MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH;
}
else if (!strcasecmp(new_value, "consistent")) {
MEMCACHE_G(hash_strategy) = MMC_CONSISTENT_HASH;
}
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.hash_strategy must be in set {standard, consistent} ('%s' given)", new_value);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
static PHP_INI_MH(OnUpdateHashFunction) /* {{{ */
{
if (!strcasecmp(new_value, "crc32")) {
MEMCACHE_G(hash_function) = MMC_HASH_CRC32;
}
else if (!strcasecmp(new_value, "fnv")) {
MEMCACHE_G(hash_function) = MMC_HASH_FNV1A;
}
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.hash_function must be in set {crc32, fnv} ('%s' given)", new_value);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
static PHP_INI_MH(OnUpdateRedundancy) /* {{{ */
{
long int lval;
lval = strtol(new_value, NULL, 10);
if (lval <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.redundancy must be a positive integer ('%s' given)", new_value);
return FAILURE;
}
return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* }}} */
static PHP_INI_MH(OnUpdateCompressThreshold) /* {{{ */
{
long int lval;
lval = strtol(new_value, NULL, 10);
if (lval < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.compress_threshold must be a positive integer ('%s' given)", new_value);
return FAILURE;
}
return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* }}} */
static PHP_INI_MH(OnUpdateLockTimeout) /* {{{ */
{
long int lval;
lval = strtol(new_value, NULL, 10);
if (lval <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.lock_timeout must be a positive integer ('%s' given)", new_value);
return FAILURE;
}
return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* }}} */
/* {{{ PHP_INI */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("memcache.allow_failover", "1", PHP_INI_ALL, OnUpdateLong, allow_failover, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.max_failover_attempts", "20", PHP_INI_ALL, OnUpdateFailoverAttempts, max_failover_attempts, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.default_port", "11211", PHP_INI_ALL, OnUpdateLong, default_port, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.chunk_size", "32768", PHP_INI_ALL, OnUpdateChunkSize, chunk_size, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.protocol", "ascii", PHP_INI_ALL, OnUpdateProtocol, protocol, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.hash_strategy", "consistent", PHP_INI_ALL, OnUpdateHashStrategy, hash_strategy, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.hash_function", "crc32", PHP_INI_ALL, OnUpdateHashFunction, hash_function, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.redundancy", "1", PHP_INI_ALL, OnUpdateRedundancy, redundancy, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.session_redundancy", "2", PHP_INI_ALL, OnUpdateRedundancy, session_redundancy, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.compress_threshold", "20000", PHP_INI_ALL, OnUpdateCompressThreshold, compress_threshold, zend_memcache_globals, memcache_globals)
STD_PHP_INI_ENTRY("memcache.lock_timeout", "15", PHP_INI_ALL, OnUpdateLockTimeout, lock_timeout, zend_memcache_globals, memcache_globals)
PHP_INI_END()
/* }}} */
/* {{{ internal function protos */
static void _mmc_pool_list_dtor(zend_rsrc_list_entry * TSRMLS_DC);
static void _mmc_server_list_dtor(zend_rsrc_list_entry * TSRMLS_DC);
static void php_mmc_set_failure_callback(mmc_pool_t *, zval *, zval * TSRMLS_DC);
static void php_mmc_failure_callback(mmc_pool_t *, mmc_t *, void * TSRMLS_DC);
/* }}} */
/* {{{ php_memcache_init_globals()
*/
static void php_memcache_init_globals(zend_memcache_globals *memcache_globals_p TSRMLS_DC)
{
MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH;
MEMCACHE_G(hash_function) = MMC_HASH_CRC32;
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(memcache)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "MemcachePool", php_memcache_pool_class_functions);
memcache_pool_ce = zend_register_internal_class(&ce TSRMLS_CC);
INIT_CLASS_ENTRY(ce, "Memcache", php_memcache_class_functions);
memcache_ce = zend_register_internal_class_ex(&ce, memcache_pool_ce, NULL TSRMLS_CC);
le_memcache_pool = zend_register_list_destructors_ex(_mmc_pool_list_dtor, NULL, "memcache connection", module_number);
le_memcache_server = zend_register_list_destructors_ex(NULL, _mmc_server_list_dtor, "persistent memcache connection", module_number);
#ifdef ZTS
ts_allocate_id(&memcache_globals_id, sizeof(zend_memcache_globals), (ts_allocate_ctor) php_memcache_init_globals, NULL);
#else
php_memcache_init_globals(&memcache_globals TSRMLS_CC);
#endif
REGISTER_LONG_CONSTANT("MEMCACHE_COMPRESSED", MMC_COMPRESSED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MEMCACHE_USER1", MMC_RESERVED_APPLICATIONDEFINEDFLAG_12, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MEMCACHE_USER2", MMC_RESERVED_APPLICATIONDEFINEDFLAG_13, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MEMCACHE_USER3", MMC_RESERVED_APPLICATIONDEFINEDFLAG_14, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MEMCACHE_USER4", MMC_RESERVED_APPLICATIONDEFINEDFLAG_15, CONST_CS | CONST_PERSISTENT);
REGISTER_INI_ENTRIES();
#if HAVE_MEMCACHE_SESSION
REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 1, CONST_CS | CONST_PERSISTENT);
php_session_register_module(ps_memcache_ptr);
#else
REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 0, CONST_CS | CONST_PERSISTENT);
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(memcache)
{
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(memcache)
{
php_info_print_table_start();
php_info_print_table_header(2, "memcache support", "enabled");
php_info_print_table_row(2, "Version", PHP_MEMCACHE_VERSION);
php_info_print_table_row(2, "Revision", "$Revision: 329835 $");
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* ------------------
internal functions
------------------ */
static void _mmc_pool_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
{
mmc_pool_t *pool = (mmc_pool_t *)rsrc->ptr;
if (pool->failure_callback_param) {
zval_ptr_dtor((zval **)&pool->failure_callback_param);
pool->failure_callback_param = NULL;
}
mmc_pool_free(pool TSRMLS_CC);
}
/* }}} */
static void _mmc_server_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
{
mmc_server_free((mmc_t *)rsrc->ptr TSRMLS_CC);
}
/* }}} */
static int mmc_get_pool(zval *id, mmc_pool_t **pool TSRMLS_DC) /* {{{ */
{
zval **connection;
int resource_type;
if (Z_TYPE_P(id) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(id), "connection", sizeof("connection"), (void **)&connection) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "No servers added to memcache connection");
return 0;
}
*pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type);
if (!*pool || resource_type != le_memcache_pool) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid MemcachePool->connection member variable");
return 0;
}
return Z_LVAL_PP(connection);
}
/* }}} */
int mmc_stored_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
handles SET/ADD/REPLACE response, param is a zval pointer to store result into {{{ */
{
zval *result = (zval *)param;
if (response == MMC_OK) {
if (Z_TYPE_P(result) == IS_NULL) {
ZVAL_TRUE(result);
}
return MMC_REQUEST_DONE;
}
/* return FALSE or catch memory errors without failover */
if (response == MMC_RESPONSE_EXISTS || response == MMC_RESPONSE_OUT_OF_MEMORY || response == MMC_RESPONSE_TOO_LARGE
|| response == MMC_RESPONSE_CLIENT_ERROR) {
ZVAL_FALSE(result);
if (response != MMC_RESPONSE_EXISTS) {
/* trigger notice but no need for failover */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
mmc->host, mmc->tcp.port, mmc->udp.port, message, response);
}
return MMC_REQUEST_DONE;
}
return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
}
/* }}} */
static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
{
mmc_pool_t *pool;
mmc_request_t *request;
zval *keys, *value = 0, *mmc_object = getThis();
long flags = 0, exptime = 0, cas = 0;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zlll", &mmc_object, memcache_pool_ce, &keys, &value, &flags, &exptime, &cas) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zlll", &keys, &value, &flags, &exptime, &cas) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
RETVAL_NULL();
if (Z_TYPE_P(keys) == IS_ARRAY) {
zstr key;
char keytmp[MAX_LENGTH_OF_LONG + 1];
unsigned int key_len;
unsigned long index;
int key_type;
zval **arrval;
HashPosition pos;
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&arrval, &pos) == SUCCESS) {
key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(keys), &key, &key_len, &index, 0, &pos);
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
switch (key_type) {
case HASH_KEY_IS_STRING:
key_len--;
break;
case HASH_KEY_IS_LONG:
key_len = sprintf(keytmp, "%lu", index);
key = ZSTR(keytmp);
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
continue;
}
/* allocate request */
request = mmc_pool_request(pool, MMC_PROTO_TCP,
mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
if (mmc_prepare_key_ex(ZSTR_VAL(key), key_len, request->key, &(request->key_len)) != MMC_OK) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
mmc_pool_release(pool, request);
continue;
}
/* assemble command */
if (pool->protocol->store(pool, request, op, request->key, request->key_len, flags, exptime, cas, *arrval TSRMLS_CC) != MMC_OK) {
mmc_pool_release(pool, request);
continue;
}
/* schedule request */
if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
continue;
}
/* begin sending requests immediatly */
mmc_pool_select(pool TSRMLS_CC);
}
}
else if (value) {
/* allocate request */
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
mmc_pool_release(pool, request);
RETURN_FALSE;
}
/* assemble command */
if (pool->protocol->store(pool, request, op, request->key, request->key_len, flags, exptime, cas, value TSRMLS_CC) != MMC_OK) {
mmc_pool_release(pool, request);
RETURN_FALSE;
}
/* schedule request */
if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
RETURN_FALSE;
}
}
else {
WRONG_PARAM_COUNT;
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
if (Z_TYPE_P(return_value) == IS_NULL) {
RETVAL_FALSE;
}
}
/* }}} */
int mmc_numeric_response_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
handles a mutate response line, param is a zval pointer to store result into {{{ */
{
zval *result = (zval *)param;
if (response == MMC_OK) {
if (Z_TYPE_P(result) == IS_ARRAY) {
add_assoc_bool_ex(result, request->key, request->key_len + 1, 1);
}
else if (Z_TYPE_P(result) == IS_NULL) {
/* switch only from null to true, not from false to true */
ZVAL_TRUE(result);
}
return MMC_REQUEST_DONE;
}
if (response == MMC_RESPONSE_NOT_FOUND || response == MMC_RESPONSE_CLIENT_ERROR) {
if (Z_TYPE_P(result) == IS_ARRAY) {
add_assoc_bool_ex(result, request->key, request->key_len + 1, 0);
}
else {
ZVAL_FALSE(result);
}
if (response != MMC_RESPONSE_NOT_FOUND) {
php_error_docref(NULL TSRMLS_CC,
E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
mmc->host, mmc->tcp.port,
mmc->udp.port, message, response);
}
return MMC_REQUEST_DONE;
}
return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
}
/* }}} */
static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int invert) /*
sends one or several commands which have a single optional numeric parameter (incr, decr, delete) {{{ */
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
zval *keys;
long value = 1, defval = 0, exptime = 0;
mmc_request_t *request;
void *value_handler_param[3];
int defval_used = 0;
if (mmc_object == NULL) {
if (deleted) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|l", &mmc_object, memcache_pool_ce, &keys, &value) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|lll", &mmc_object, memcache_pool_ce, &keys, &value, &defval, &exptime) == FAILURE) {
return;
}
defval_used = ZEND_NUM_ARGS() >= 4;
}
}
else {
if (deleted) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &keys, &value) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lll", &keys, &value, &defval, &exptime) == FAILURE) {
return;
}
defval_used = ZEND_NUM_ARGS() >= 3;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
value_handler_param[0] = return_value;
value_handler_param[1] = NULL;
value_handler_param[2] = NULL;
if (Z_TYPE_P(keys) == IS_ARRAY) {
zval **key;
HashPosition pos;
if (deleted) {
/* changed to true/false by mmc_numeric_response_handler */
RETVAL_NULL();
}
else {
/* populated with responses by mmc_numeric_response_handler and mmc_value_handler_multi */
array_init(return_value);
}
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
/* allocate request */
request = mmc_pool_request(
pool, MMC_PROTO_TCP, mmc_numeric_response_handler, return_value,
mmc_pool_failover_handler, NULL TSRMLS_CC);
request->value_handler = mmc_value_handler_multi;
request->value_handler_param = value_handler_param;
if (mmc_prepare_key(*key, request->key, &(request->key_len)) != MMC_OK) {
mmc_pool_release(pool, request);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
continue;
}
if (deleted) {
pool->protocol->delete(request, request->key, request->key_len, exptime);
}
else {
pool->protocol->mutate(request, *key, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
}
/* schedule request */
if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
continue;
}
/* begin sending requests immediatly */
mmc_pool_select(pool TSRMLS_CC);
}
}
else {
/* changed to true/false by mmc_numeric_response_handler or set to a value
* by mmc_value_handler_single if incr/decr returns one */
RETVAL_NULL();
/* allocate request */
request = mmc_pool_request(pool, MMC_PROTO_TCP,
mmc_numeric_response_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
request->value_handler = mmc_value_handler_single;
request->value_handler_param = value_handler_param;
if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
mmc_pool_release(pool, request);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
RETURN_FALSE;
}
if (deleted) {
pool->protocol->delete(request, request->key, request->key_len, exptime);
}
else {
pool->protocol->mutate(request, keys, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
}
/* schedule request */
if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
RETURN_FALSE;
}
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
}
/* }}} */
mmc_t *mmc_find_persistent(const char *host, int host_len, unsigned short port, unsigned short udp_port, double timeout, int retry_interval TSRMLS_DC) /* {{{ */
{
mmc_t *mmc;
zend_rsrc_list_entry *le;
char *key;
int key_len;
key_len = spprintf(&key, 0, "memcache:server:%s:%u:%u", host, port, udp_port);
if (zend_hash_find(&EG(persistent_list), key, key_len+1, (void **)&le) == FAILURE) {
zend_rsrc_list_entry new_le;
mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
new_le.type = le_memcache_server;
new_le.ptr = mmc;
/* register new persistent connection */
if (zend_hash_update(&EG(persistent_list), key, key_len+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
mmc_server_free(mmc TSRMLS_CC);
mmc = NULL;
} else {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3)
zend_list_insert(mmc, le_memcache_server);
#else
zend_list_insert(mmc, le_memcache_server TSRMLS_CC);
#endif
}
}
else if (le->type != le_memcache_server || le->ptr == NULL) {
zend_rsrc_list_entry new_le;
zend_hash_del(&EG(persistent_list), key, key_len+1);
mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
new_le.type = le_memcache_server;
new_le.ptr = mmc;
/* register new persistent connection */
if (zend_hash_update(&EG(persistent_list), key, key_len+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
mmc_server_free(mmc TSRMLS_CC);
mmc = NULL;
}
else {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3)
zend_list_insert(mmc, le_memcache_server);
#else
zend_list_insert(mmc, le_memcache_server TSRMLS_CC);
#endif
}
}
else {
mmc = (mmc_t *)le->ptr;
mmc->timeout = double_to_timeval(timeout);
mmc->tcp.retry_interval = retry_interval;
/* attempt to reconnect this node before failover in case connection has gone away */
if (mmc->tcp.status == MMC_STATUS_CONNECTED) {
mmc->tcp.status = MMC_STATUS_UNKNOWN;
}
if (mmc->udp.status == MMC_STATUS_CONNECTED) {
mmc->udp.status = MMC_STATUS_UNKNOWN;
}
}
efree(key);
return mmc;
}
/* }}} */
static mmc_t *php_mmc_pool_addserver(
zval *mmc_object, const char *host, int host_len, long tcp_port, long udp_port, long weight,
zend_bool persistent, double timeout, long retry_interval, zend_bool status, mmc_pool_t **pool_result TSRMLS_DC) /* {{{ */
{
zval **connection;
mmc_pool_t *pool;
mmc_t *mmc;
int list_id, resource_type;
if (weight < 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer");
return NULL;
}
/* initialize pool if need be */
if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void **)&connection) == FAILURE) {
pool = mmc_pool_new(TSRMLS_C);
pool->failure_callback = &php_mmc_failure_callback;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3)
list_id = zend_list_insert(pool, le_memcache_pool);
#else
list_id = zend_list_insert(pool, le_memcache_pool TSRMLS_CC);
#endif
add_property_resource(mmc_object, "connection", list_id);
}
else {
pool = (mmc_pool_t *)zend_list_find(Z_LVAL_PP(connection), &resource_type);
if (!pool || resource_type != le_memcache_pool) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown connection identifier");
return NULL;
}
}
/* binary protocol isn't support over UDP yet */
if (udp_port && pool->protocol == &mmc_binary_protocol) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "binary protocol isn't support over UDP, defaulting to TCP");
udp_port = 0;
}
/* lazy initialization of server struct */
if (persistent && status) {
mmc = mmc_find_persistent(host, host_len, tcp_port, udp_port, timeout, retry_interval TSRMLS_CC);
}
else {
mmc = mmc_server_new(host, host_len, tcp_port, udp_port, 0, timeout, retry_interval TSRMLS_CC);
}
/* add server in failed mode */
if (!status) {
mmc->tcp.status = MMC_STATUS_FAILED;
mmc->udp.status = MMC_STATUS_FAILED;
}
mmc_pool_add(pool, mmc, weight);
if (pool_result != NULL) {
*pool_result = pool;
}
return mmc;
}
/* }}} */
static void php_mmc_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool persistent) /* {{{ */
{
zval *mmc_object = getThis();
mmc_pool_t *pool;
mmc_t *mmc;
char *host;
int host_len;
long tcp_port = MEMCACHE_G(default_port);
double timeout = MMC_DEFAULT_TIMEOUT;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ld", &host, &host_len, &tcp_port, &timeout) == FAILURE) {
return;
}
/* initialize pool and object if need be */
if (!mmc_object) {
int list_id;
mmc_pool_t *pool = mmc_pool_new(TSRMLS_C);
pool->failure_callback = &php_mmc_failure_callback;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3)
list_id = zend_list_insert(pool, le_memcache_pool);
#else
list_id = zend_list_insert(pool, le_memcache_pool TSRMLS_CC);
#endif
mmc_object = return_value;
object_init_ex(mmc_object, memcache_ce);
add_property_resource(mmc_object, "connection", list_id);
}
else {
RETVAL_TRUE;
}
mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, 1, persistent, timeout, MMC_DEFAULT_RETRY, 1, NULL TSRMLS_CC);
if (mmc == NULL) {
RETURN_FALSE;
}
/* force a reconnect attempt if stream EOF */
if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
/* force a tcp connect (if not persistently connected) */
if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
RETURN_FALSE;
}
}
/* }}} */
/*
* STAT 6:chunk_size 64
*/
static int mmc_stats_parse_stat(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */
{
char *space, *colon, *key;
long index = 0;
if (Z_TYPE_P(result) != IS_ARRAY) {
array_init(result);
}
/* find space delimiting key and value */
if ((space = php_memnstr(start, " ", 1, end)) == NULL) {
return 0;
}
/* find colon delimiting subkeys */
if ((colon = php_memnstr(start, ":", 1, space - 1)) != NULL) {
zval *element, **elem;
key = estrndup(start, colon - start);
/* find existing or create subkey array in result */
if ((is_numeric_string(key, colon - start, &index, NULL, 0) &&
zend_hash_index_find(Z_ARRVAL_P(result), index, (void **)&elem) != FAILURE) ||
zend_hash_find(Z_ARRVAL_P(result), key, colon - start + 1, (void **)&elem) != FAILURE) {
element = *elem;
}
else {
MAKE_STD_ZVAL(element);
array_init(element);
add_assoc_zval_ex(result, key, colon - start + 1, element);
}
efree(key);
return mmc_stats_parse_stat(colon + 1, end, element TSRMLS_CC);
}
/* no more subkeys, add value under last subkey */
key = estrndup(start, space - start);
add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1);
efree(key);
return 1;
}
/* }}} */
/*
* ITEM test_key [3 b; 1157099416 s]
*/
static int mmc_stats_parse_item(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */
{
char *space, *value, *value_end, *key;
zval *element;
if (Z_TYPE_P(result) != IS_ARRAY) {
array_init(result);
}
/* find space delimiting key and value */
if ((space = php_memnstr(start, " ", 1, end)) == NULL) {
return 0;
}
MAKE_STD_ZVAL(element);
array_init(element);
/* parse each contained value */
for (value = php_memnstr(space, "[", 1, end); value != NULL && value <= end; value = php_memnstr(value + 1, ";", 1, end)) {
do {
value++;
} while (*value == ' ' && value <= end);
if (value <= end && (value_end = php_memnstr(value, " ", 1, end)) != NULL && value_end <= end) {
add_next_index_stringl(element, value, value_end - value, 1);
}
}
/* add parsed values under key */
key = estrndup(start, space - start);
add_assoc_zval_ex(result, key, space - start + 1, element);
efree(key);
return 1;
}
/* }}} */
static int mmc_stats_parse_generic(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */
{
char *space, *key;
if (Z_TYPE_P(result) != IS_ARRAY) {
array_init(result);
}
if (start < end) {
if ((space = php_memnstr(start, " ", 1, end)) != NULL) {
key = estrndup(start, space - start);
add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1);
efree(key);
}
else {
add_next_index_stringl(result, start, end - start, 1);
}
}
else {
return 0;
}
return 1;
}
/* }}} */
static void php_mmc_failure_callback(mmc_pool_t *pool, mmc_t *mmc, void *param TSRMLS_DC) /* {{{ */
{
zval **callback;
/* check for userspace callback */
if (param != NULL && zend_hash_find(Z_OBJPROP_P((zval *)param), "_failureCallback", sizeof("_failureCallback"), (void **)&callback) == SUCCESS && Z_TYPE_PP(callback) != IS_NULL) {
if (IS_CALLABLE(*callback, 0, NULL)) {
zval *retval = NULL;
zval *host, *tcp_port, *udp_port, *error, *errnum;
zval **params[5];
params[0] = &host;
params[1] = &tcp_port;
params[2] = &udp_port;
params[3] = &error;
params[4] = &errnum;
MAKE_STD_ZVAL(host);
MAKE_STD_ZVAL(tcp_port); MAKE_STD_ZVAL(udp_port);
MAKE_STD_ZVAL(error); MAKE_STD_ZVAL(errnum);
ZVAL_STRING(host, mmc->host, 1);
ZVAL_LONG(tcp_port, mmc->tcp.port); ZVAL_LONG(udp_port, mmc->udp.port);
if (mmc->error != NULL) {
ZVAL_STRING(error, mmc->error, 1);
}
else {
ZVAL_NULL(error);
}
ZVAL_LONG(errnum, mmc->errnum);
call_user_function_ex(EG(function_table), NULL, *callback, &retval, 5, params, 0, NULL TSRMLS_CC);
zval_ptr_dtor(&host);
zval_ptr_dtor(&tcp_port); zval_ptr_dtor(&udp_port);
zval_ptr_dtor(&error); zval_ptr_dtor(&errnum);
if (retval != NULL) {
zval_ptr_dtor(&retval);
}
}
else {
php_mmc_set_failure_callback(pool, (zval *)param, NULL TSRMLS_CC);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
}
}
else {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
mmc->host, mmc->tcp.port, mmc->udp.port, mmc->error, mmc->errnum);
}
}
/* }}} */
static void php_mmc_set_failure_callback(mmc_pool_t *pool, zval *mmc_object, zval *callback TSRMLS_DC) /* {{{ */
{
// Decrease refcount of old mmc_object
if (pool->failure_callback_param) {
zval_ptr_dtor((zval **)&pool->failure_callback_param);
}
if (callback != NULL) {
zval *callback_tmp;
ALLOC_ZVAL(callback_tmp);
*callback_tmp = *callback;
zval_copy_ctor(callback_tmp);
INIT_PZVAL(callback_tmp);
add_property_zval(mmc_object, "_failureCallback", callback_tmp);
pool->failure_callback_param = mmc_object;
zval_add_ref(&mmc_object);
INIT_PZVAL(callback_tmp);
}
else {
add_property_null(mmc_object, "_failureCallback");
pool->failure_callback_param = NULL;
}
}
/* }}} */
/* ----------------
module functions
---------------- */
/* {{{ proto bool MemcachePool::connect(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, double timeout [, int retry_interval] ] ] ] ] ])
Connects to server and returns a Memcache object */
PHP_NAMED_FUNCTION(zif_memcache_pool_connect)
{
zval *mmc_object = getThis();
mmc_pool_t *pool;
mmc_t *mmc;
char *host;
int host_len;
long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, retry_interval = MMC_DEFAULT_RETRY;
double timeout = MMC_DEFAULT_TIMEOUT;
zend_bool persistent = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llbldl",
&host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval) == FAILURE) {
return;
}
mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, 1, NULL TSRMLS_CC);
if (mmc == NULL) {
RETURN_FALSE;
}
/* force a reconnect attempt if stream EOF */
if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
/* force a tcp connect (if not persistently connected) */
if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto object memcache_connect(string host [, int port [, double timeout ] ])
Connects to server and returns a Memcache object */
PHP_FUNCTION(memcache_connect)
{
php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ proto object memcache_pconnect(string host [, int port [, double timeout ] ])
Connects to server and returns a Memcache object */
PHP_FUNCTION(memcache_pconnect)
{
php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ proto bool MemcachePool::addServer(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, double timeout [, int retry_interval [, bool status] ] ] ] ])
Adds a server to the pool */
PHP_NAMED_FUNCTION(zif_memcache_pool_addserver)
{
zval *mmc_object = getThis();
mmc_t *mmc;
char *host;
int host_len;
long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, retry_interval = MMC_DEFAULT_RETRY;
double timeout = MMC_DEFAULT_TIMEOUT;
zend_bool persistent = 1, status = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llbldlb",
&host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval, &status) == FAILURE) {
return;
}
mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, status, NULL TSRMLS_CC);
if (mmc == NULL) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string MemcachePool::findServer(string key)
Returns the server corresponding to a key
*/
PHP_NAMED_FUNCTION(zif_memcache_pool_findserver)
{
zval *mmc_object = getThis();
mmc_pool_t *pool;
mmc_t *mmc;
zval *zkey;
char key[MMC_MAX_KEY_LEN + 1];
unsigned int key_len;
char *hostname;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zkey) == FAILURE) {
return;
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
if (mmc_prepare_key(zkey, key, &key_len) != MMC_OK) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
RETURN_FALSE;
}
mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
spprintf(&hostname, 0, "%s:%d", mmc->host, mmc->tcp.port);
RETURN_STRING(hostname, 0);
}
/* }}} */
/* {{{ proto bool memcache_add_server(string host [, int port [, bool persistent [, int weight [, double timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ] ] ])
Adds a connection to the pool. The order in which this function is called is significant */
PHP_FUNCTION(memcache_add_server)
{
zval *mmc_object = getThis(), *failure_callback = NULL;
mmc_pool_t *pool;
mmc_t *mmc;
char *host;
int host_len;
long tcp_port = MEMCACHE_G(default_port), weight = 1, retry_interval = MMC_DEFAULT_RETRY;
double timeout = MMC_DEFAULT_TIMEOUT;
zend_bool persistent = 1, status = 1;
if (mmc_object) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbldlbz",
&host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lbldlbz", &mmc_object, memcache_ce,
&host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
return;
}
}
if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
if (!IS_CALLABLE(failure_callback, 0, NULL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
RETURN_FALSE;
}
}
mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, weight, persistent, timeout, retry_interval, status, &pool TSRMLS_CC);
if (mmc == NULL) {
RETURN_FALSE;
}
if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool memcache_set_server_params( string host [, int port [, double timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ])
Changes server parameters at runtime */
PHP_FUNCTION(memcache_set_server_params)
{
zval *mmc_object = getThis(), *failure_callback = NULL;
mmc_pool_t *pool;
mmc_t *mmc = NULL;
long tcp_port = MEMCACHE_G(default_port), retry_interval = MMC_DEFAULT_RETRY;
double timeout = MMC_DEFAULT_TIMEOUT;
zend_bool status = 1;
int host_len, i;
char *host;
if (mmc_object) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ldlbz",
&host, &host_len, &tcp_port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|ldlbz", &mmc_object, memcache_pool_ce,
&host, &host_len, &tcp_port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
for (i=0; i<pool->num_servers; i++) {
if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->tcp.port == tcp_port) {
mmc = pool->servers[i];
break;
}
}
if (!mmc) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool");
RETURN_FALSE;
}
if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
if (!IS_CALLABLE(failure_callback, 0, NULL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
RETURN_FALSE;
}
}
mmc->timeout = double_to_timeval(timeout);
mmc->tcp.retry_interval = retry_interval;
/* store the smallest timeout for any server */
if (timeval_to_double(mmc->timeout) < timeval_to_double(pool->timeout)) {
pool->timeout = mmc->timeout;
}
if (!status) {
mmc->tcp.status = MMC_STATUS_FAILED;
mmc->udp.status = MMC_STATUS_FAILED;
}
else {
if (mmc->tcp.status == MMC_STATUS_FAILED) {
mmc->tcp.status = MMC_STATUS_DISCONNECTED;
}
if (mmc->udp.status == MMC_STATUS_FAILED) {
mmc->udp.status = MMC_STATUS_DISCONNECTED;
}
}
if (failure_callback != NULL) {
if (Z_TYPE_P(failure_callback) != IS_NULL) {
php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
}
else {
php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
}
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool memcache_set_failure_callback( callback failure_callback )
Changes the failover callback */
PHP_FUNCTION(memcache_set_failure_callback)
{
zval *mmc_object = getThis(), *failure_callback;
mmc_pool_t *pool;
if (mmc_object) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",
&failure_callback) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz", &mmc_object, memcache_pool_ce,
&failure_callback) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
if (Z_TYPE_P(failure_callback) != IS_NULL) {
if (!IS_CALLABLE(failure_callback, 0, NULL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
RETURN_FALSE;
}
}
if (Z_TYPE_P(failure_callback) != IS_NULL) {
php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
}
else {
php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int memcache_get_server_status( string host [, int port ])
Returns server status (0 if server is failed, otherwise non-zero) */
PHP_FUNCTION(memcache_get_server_status)
{
zval *mmc_object = getThis();
mmc_pool_t *pool;
mmc_t *mmc = NULL;
long tcp_port = MEMCACHE_G(default_port);
int host_len, i;
char *host;
if (mmc_object) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &tcp_port) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_pool_ce, &host, &host_len, &tcp_port) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
for (i=0; i<pool->num_servers; i++) {
if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->tcp.port == tcp_port) {
mmc = pool->servers[i];
break;
}
}
if (!mmc) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool");
RETURN_FALSE;
}
RETURN_LONG(mmc->tcp.status > MMC_STATUS_FAILED ? 1 : 0);
}
/* }}} */
static int mmc_version_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
parses the VERSION response line, param is a zval pointer to store version into {{{ */
{
if (response != MMC_RESPONSE_ERROR) {
char *version = emalloc(message_len + 1);
if (sscanf(message, "VERSION %s", version) == 1) {
ZVAL_STRING((zval *)param, version, 0);
}
else {
efree(version);
ZVAL_STRINGL((zval *)param, (char *)message, message_len, 1);
}
return MMC_REQUEST_DONE;
}
return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
}
/* }}} */
/* {{{ proto string memcache_get_version( object memcache )
Returns server's version */
PHP_FUNCTION(memcache_get_version)
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
int i;
mmc_request_t *request;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_pool_ce) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
RETVAL_FALSE;
for (i=0; i<pool->num_servers; i++) {
/* run command and check for valid return value */
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_version_handler, return_value, NULL, NULL TSRMLS_CC);
pool->protocol->version(request);
if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
mmc_pool_run(pool TSRMLS_CC);
if (Z_TYPE_P(return_value) == IS_STRING) {
break;
}
}
}
}
/* }}} */
/* {{{ proto bool memcache_add(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
Adds new item. Item with such key should not exist. */
PHP_FUNCTION(memcache_add)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_ADD);
}
/* }}} */
/* {{{ proto bool memcache_set(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
Sets the value of an item. Item may exist or not */
PHP_FUNCTION(memcache_set)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_SET);
}
/* }}} */
/* {{{ proto bool memcache_replace(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] )
Replaces existing item. Returns false if item doesn't exist */
PHP_FUNCTION(memcache_replace)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_REPLACE);
}
/* }}} */
/* {{{ proto bool memcache_cas(object memcache, mixed key [, mixed var [, int flag [, int exptime [, long cas ] ] ] ])
Sets the value of an item if the CAS value is the same (Compare-And-Swap) */
PHP_FUNCTION(memcache_cas)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_CAS);
}
/* }}} */
/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
Appends a value to the stored value, value must exist */
PHP_FUNCTION(memcache_append)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_APPEND);
}
/* }}} */
/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
Prepends a value to the stored value, value must exist */
PHP_FUNCTION(memcache_prepend)
{
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_PREPEND);
}
/* }}} */
int mmc_value_handler_multi(
const char *key, unsigned int key_len, zval *value,
unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
receives a multiple values, param is a zval** array to store value and flags in {{{ */
{
zval **result = (zval **)param;
/* add value to result */
if (Z_TYPE_P(result[0]) != IS_ARRAY) {
array_init(result[0]);
}
add_assoc_zval_ex(result[0], (char *)key, key_len + 1, value);
/* add flags to result */
if (result[1] != NULL) {
if (Z_TYPE_P(result[1]) != IS_ARRAY) {
array_init(result[1]);
}
add_assoc_long_ex(result[1], (char *)key, key_len + 1, flags);
}
/* add CAS value to result */
if (result[2] != NULL) {
if (Z_TYPE_P(result[2]) != IS_ARRAY) {
array_init(result[2]);
}
add_assoc_long_ex(result[2], (char *)key, key_len + 1, cas);
}
return MMC_REQUEST_DONE;
}
/* }}} */
int mmc_value_handler_single(
const char *key, unsigned int key_len, zval *value,
unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
receives a single value, param is a zval pointer to store value to {{{ */
{
zval **result = (zval **)param;
ZVAL_ZVAL(result[0], value, 1, 1);
if (result[1] != NULL) {
ZVAL_LONG(result[1], flags);
}
if (result[2] != NULL) {
ZVAL_LONG(result[2], cas);
}
return MMC_REQUEST_DONE;
}
/* }}} */
static int mmc_value_failover_handler(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
uses keys and return value to reschedule requests to other servers, param is a zval ** pointer {{{ */
{
zval **key, *keys = ((zval **)param)[0], **value_handler_param = (zval **)((void **)param)[1];
HashPosition pos;
if (!MEMCACHE_G(allow_failover) || request->failed_servers.len >= MEMCACHE_G(max_failover_attempts)) {
mmc_pool_release(pool, request);
return MMC_REQUEST_FAILURE;
}
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
/* re-schedule key if it does not exist in return value array */
if (Z_TYPE_P(value_handler_param[0]) != IS_ARRAY ||
!zend_hash_exists(Z_ARRVAL_P(value_handler_param[0]), Z_STRVAL_PP(key), Z_STRLEN_PP(key) + 1))
{
mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
value_handler_param[2] != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
request->value_handler, request->value_handler_param,
request->failover_handler, request->failover_handler_param, request TSRMLS_CC);
}
}
mmc_pool_release(pool, request);
return MMC_OK;
}
/* }}}*/
/* {{{ proto mixed memcache_get( object memcache, mixed key [, mixed &flags [, mixed &cas ] ] )
Returns value of existing item or false */
PHP_FUNCTION(memcache_get)
{
mmc_pool_t *pool;
zval *keys, *flags = NULL, *cas = NULL, *mmc_object = getThis();
void *value_handler_param[3], *failover_handler_param[2];
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zz", &mmc_object, memcache_pool_ce, &keys, &flags, &cas) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zz", &keys, &flags, &cas) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
value_handler_param[0] = return_value;
value_handler_param[1] = flags;
value_handler_param[2] = cas;
if (Z_TYPE_P(keys) == IS_ARRAY) {
zval **key;
HashPosition pos;
/* return empty array if no keys found */
array_init(return_value);
failover_handler_param[0] = keys;
failover_handler_param[1] = value_handler_param;
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
/* schedule request */
mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
cas != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
mmc_value_handler_multi, value_handler_param,
mmc_value_failover_handler, failover_handler_param, NULL TSRMLS_CC);
}
}
else {
mmc_request_t *request;
/* return false if key isn't found */
ZVAL_FALSE(return_value);
/* allocate request */
request = mmc_pool_request_get(
pool, MMC_PROTO_UDP,
mmc_value_handler_single, value_handler_param,
mmc_pool_failover_handler, NULL TSRMLS_CC);
if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
mmc_pool_release(pool, request);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
return;
}
pool->protocol->get(request, cas != NULL ? MMC_OP_GETS : MMC_OP_GET, keys, request->key, request->key_len);
/* schedule request */
if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, 1 TSRMLS_CC) != MMC_OK) {
return;
}
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
}
/* }}} */
static int mmc_stats_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
parses the stats response line, param is a zval pointer to store stats into {{{ */
{
if (response != MMC_RESPONSE_ERROR)
{
char *line = (char *)message;
if(!message_len) {
return MMC_REQUEST_DONE;
}
if (mmc_str_left(line, "RESET", message_len, sizeof("RESET")-1)) {
ZVAL_TRUE((zval *)param);
return MMC_REQUEST_DONE;
}
else if (mmc_str_left(line, "STAT ", message_len, sizeof("STAT ")-1)) {
if (mmc_stats_parse_stat(line + sizeof("STAT ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
return MMC_REQUEST_AGAIN;
}
}
else if (mmc_str_left(line, "ITEM ", message_len, sizeof("ITEM ")-1)) {
if (mmc_stats_parse_item(line + sizeof("ITEM ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
return MMC_REQUEST_AGAIN;
}
}
else if (mmc_str_left(line, "END", message_len, sizeof("END")-1)) {
return MMC_REQUEST_DONE;
}
else if (mmc_stats_parse_generic(line, line + message_len, (zval *)param TSRMLS_CC)) {
return MMC_REQUEST_AGAIN;
}
zval_dtor((zval *)param);
ZVAL_FALSE((zval *)param);
return MMC_REQUEST_FAILURE;
}
return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
}
/* }}} */
static int mmc_stats_checktype(const char *type) { /* {{{ */
return type == NULL ||
!strcmp(type, "reset") ||
!strcmp(type, "malloc") ||
!strcmp(type, "slabs") ||
!strcmp(type, "cachedump") ||
!strcmp(type, "items") ||
!strcmp(type, "sizes");
}
/* }}} */
/* {{{ proto array memcache_get_stats( object memcache [, string type [, int slabid [, int limit ] ] ])
Returns server's statistics */
PHP_FUNCTION(memcache_get_stats)
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
char *type = NULL;
int i, type_len = 0;
long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
mmc_request_t *request;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &type, &type_len, &slabid, &limit) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
if (!mmc_stats_checktype(type)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
RETURN_FALSE;
}
ZVAL_FALSE(return_value);
for (i=0; i<pool->num_servers; i++) {
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, return_value, NULL, NULL TSRMLS_CC);
pool->protocol->stats(request, type, slabid, limit);
/* run command and check for valid return value */
if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
mmc_pool_run(pool TSRMLS_CC);
if (Z_TYPE_P(return_value) != IS_BOOL || Z_BVAL_P(return_value)) {
break;
}
}
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
}
/* }}} */
/* {{{ proto array memcache_get_extended_stats( object memcache [, string type [, int slabid [, int limit ] ] ])
Returns statistics for each server in the pool */
PHP_FUNCTION(memcache_get_extended_stats)
{
mmc_pool_t *pool;
zval *mmc_object = getThis(), *stats;
char *host, *type = NULL;
int i, host_len, type_len = 0;
long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
mmc_request_t *request;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &type, &type_len, &slabid, &limit) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
if (!mmc_stats_checktype(type)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
RETURN_FALSE;
}
array_init(return_value);
for (i=0; i<pool->num_servers; i++) {
MAKE_STD_ZVAL(stats);
ZVAL_FALSE(stats);
host_len = spprintf(&host, 0, "%s:%u", pool->servers[i]->host, pool->servers[i]->tcp.port);
add_assoc_zval_ex(return_value, host, host_len + 1, stats);
efree(host);
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, stats, NULL, NULL TSRMLS_CC);
pool->protocol->stats(request, type, slabid, limit);
if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
mmc_pool_run(pool TSRMLS_CC);
}
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
}
/* }}} */
/* {{{ proto array memcache_set_compress_threshold( object memcache, int threshold [, float min_savings ] )
Set automatic compress threshold */
PHP_FUNCTION(memcache_set_compress_threshold)
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
long threshold;
double min_savings = MMC_DEFAULT_SAVINGS;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|d", &mmc_object, memcache_pool_ce, &threshold, &min_savings) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &threshold, &min_savings) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
if (threshold < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "threshold must be a positive integer");
RETURN_FALSE;
}
pool->compress_threshold = threshold;
if (min_savings != MMC_DEFAULT_SAVINGS) {
if (min_savings < 0 || min_savings > 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "min_savings must be a float in the 0..1 range");
RETURN_FALSE;
}
pool->min_compress_savings = min_savings;
}
else {
pool->min_compress_savings = MMC_DEFAULT_SAVINGS;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool memcache_delete(object memcache, mixed key [, int exptime ])
Deletes existing item */
PHP_FUNCTION(memcache_delete)
{
php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
}
/* }}} */
/* {{{ proto mixed memcache_increment(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
Increments existing variable */
PHP_FUNCTION(memcache_increment)
{
php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
}
/* }}} */
/* {{{ proto mixed memcache_decrement(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
Decrements existing variable */
PHP_FUNCTION(memcache_decrement)
{
php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
}
/* }}} */
/* {{{ proto bool memcache_close( object memcache )
Closes connection to memcached */
PHP_FUNCTION(memcache_close)
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_pool_ce) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
mmc_pool_close(pool TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
static int mmc_flush_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
parses the OK response line, param is an int pointer to increment on success {{{ */
{
if (response == MMC_OK) {
(*((int *)param))++;
return MMC_REQUEST_DONE;
}
if (response == MMC_RESPONSE_CLIENT_ERROR) {
ZVAL_FALSE((zval *)param);
php_error_docref(NULL TSRMLS_CC, E_NOTICE,
"Server %s (tcp %d, udp %d) failed with: %s (%d)",
mmc->host, mmc->tcp.port,
mmc->udp.port, message, response);
return MMC_REQUEST_DONE;
}
return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
}
/* }}} */
/* {{{ proto bool memcache_flush( object memcache [, int delay ] )
Flushes cache, optionally at after the specified delay */
PHP_FUNCTION(memcache_flush)
{
mmc_pool_t *pool;
zval *mmc_object = getThis();
mmc_request_t *request;
unsigned int i, responses = 0;
long delay = 0;
if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &mmc_object, memcache_pool_ce, &delay) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) {
return;
}
}
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
RETURN_FALSE;
}
for (i=0; i<pool->num_servers; i++) {
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_flush_handler, &responses, NULL, NULL TSRMLS_CC);
pool->protocol->flush(request, delay);
if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
/* begin sending requests immediatly */
mmc_pool_select(pool TSRMLS_CC);
}
}
/* execute all requests */
mmc_pool_run(pool TSRMLS_CC);
if (responses < pool->num_servers) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool memcache_debug( bool onoff ) */
PHP_FUNCTION(memcache_debug)
{
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache_debug() is deprecated, please use a debugger (like Eclipse + CDT)");
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/moxi/php-memcache-test.git
git@gitee.com:moxi/php-memcache-test.git
moxi
php-memcache-test
php-memcache-test
master

搜索帮助