1 /*
2 +----------------------------------------------------------------------+
3 | Yet Another Cache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2013-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Xinchen Hui <laruence@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <time.h>
26
27 #include "php.h"
28 #include "php_ini.h"
29 #include "SAPI.h"
30 #include "ext/standard/info.h"
31 #include "Zend/zend_smart_str.h"
32 #include "Zend/zend_exceptions.h"
33
34 #include "php_yac.h"
35 #include "storage/yac_storage.h"
36 #include "serializer/yac_serializer.h"
37 #ifdef HAVE_FASTLZ_H
38 #include <fastlz.h>
39 #else
40 #include "compressor/fastlz/fastlz.h"
41 #endif
42
43 zend_class_entry *yac_class_ce;
44
45 static zend_object_handlers yac_obj_handlers;
46
47 typedef struct {
48 unsigned char prefix[YAC_STORAGE_MAX_KEY_LEN];
49 uint16_t prefix_len;
50 zend_object std;
51 } yac_object;
52
53 ZEND_DECLARE_MODULE_GLOBALS(yac);
54
55 static yac_serializer_t yac_serializer;
56 static yac_unserializer_t yac_unserializer;
57
58 /** {{{ ARG_INFO
59 */
60 ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_constructor, 0, 0, 0)
61 ZEND_ARG_INFO(0, prefix)
ZEND_END_ARG_INFO()62 ZEND_END_ARG_INFO()
63
64 ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_add, 0, 0, 1)
65 ZEND_ARG_INFO(0, keys)
66 ZEND_ARG_INFO(0, value)
67 ZEND_ARG_INFO(0, ttl)
68 ZEND_END_ARG_INFO()
69
70 ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_get, 0, 0, 1)
71 ZEND_ARG_INFO(0, keys)
72 ZEND_END_ARG_INFO()
73
74 ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_delete, 0, 0, 1)
75 ZEND_ARG_INFO(0, keys)
76 ZEND_ARG_INFO(0, ttl)
77 ZEND_END_ARG_INFO()
78
79 ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_void, 0, 0, 0)
80 ZEND_END_ARG_INFO()
81 /* }}} */
82
83 static PHP_INI_MH(OnChangeKeysMemoryLimit) /* {{{ */ {
84 if (new_value) {
85 YAC_G(k_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
86 }
87 return SUCCESS;
88 }
89 /* }}} */
90
PHP_INI_MH(OnChangeValsMemoryLimit)91 static PHP_INI_MH(OnChangeValsMemoryLimit) /* {{{ */ {
92 if (new_value) {
93 YAC_G(v_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
94 }
95 return SUCCESS;
96 }
97 /* }}} */
98
PHP_INI_MH(OnChangeCompressThreshold)99 static PHP_INI_MH(OnChangeCompressThreshold) /* {{{ */ {
100 if (new_value) {
101 YAC_G(compress_threshold) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
102 if (YAC_G(compress_threshold) < YAC_MIN_COMPRESS_THRESHOLD) {
103 YAC_G(compress_threshold) = YAC_MIN_COMPRESS_THRESHOLD;
104 }
105 }
106 return SUCCESS;
107 }
108 /* }}} */
109
110 /* {{{ PHP_INI
111 */
112 PHP_INI_BEGIN()
113 STD_PHP_INI_BOOLEAN("yac.enable", "1", PHP_INI_SYSTEM, OnUpdateBool, enable, zend_yac_globals, yac_globals)
114 STD_PHP_INI_BOOLEAN("yac.debug", "0", PHP_INI_ALL, OnUpdateBool, debug, zend_yac_globals, yac_globals)
115 STD_PHP_INI_ENTRY("yac.keys_memory_size", "4M", PHP_INI_SYSTEM, OnChangeKeysMemoryLimit, k_msize, zend_yac_globals, yac_globals)
116 STD_PHP_INI_ENTRY("yac.values_memory_size", "64M", PHP_INI_SYSTEM, OnChangeValsMemoryLimit, v_msize, zend_yac_globals, yac_globals)
117 STD_PHP_INI_ENTRY("yac.compress_threshold", "-1", PHP_INI_SYSTEM, OnChangeCompressThreshold, compress_threshold, zend_yac_globals, yac_globals)
118 STD_PHP_INI_ENTRY("yac.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_yac_globals, yac_globals)
119 STD_PHP_INI_ENTRY("yac.serializer", "php", PHP_INI_SYSTEM, OnUpdateString, serializer, zend_yac_globals, yac_globals)
PHP_INI_END()120 PHP_INI_END()
121 /* }}} */
122
123 #define Z_YACOBJ_P(zv) (php_yac_fetch_object(Z_OBJ_P(zv)))
124 static inline yac_object *php_yac_fetch_object(zend_object *obj) /* {{{ */ {
125 return (yac_object *)((char*)(obj) - XtOffsetOf(yac_object, std));
126 }
127 /* }}} */
128
yac_assemble_key(yac_object * yac,zend_string * name,size_t * len)129 static const char *yac_assemble_key(yac_object *yac, zend_string *name, size_t *len) /* {{{ */ {
130 const char *key;
131
132 if ((ZSTR_LEN(name) + yac->prefix_len) > YAC_STORAGE_MAX_KEY_LEN) {
133 php_error_docref(NULL, E_WARNING,
134 "Key '%.*s%s' exceed max key length '%d' bytes",
135 yac->prefix_len, yac->prefix, ZSTR_VAL(name), YAC_STORAGE_MAX_KEY_LEN);
136 return NULL;
137 }
138
139 if (yac->prefix_len) {
140 memcpy(yac->prefix + yac->prefix_len, ZSTR_VAL(name), ZSTR_LEN(name));
141 key = (const char*)yac->prefix;
142 *len = yac->prefix_len + ZSTR_LEN(name);
143 } else {
144 key = ZSTR_VAL(name);
145 *len = ZSTR_LEN(name);
146 }
147
148 return key;
149 }
150 /* }}} */
151
yac_add_impl(yac_object * yac,zend_string * name,zval * value,int ttl,int add)152 static int yac_add_impl(yac_object *yac, zend_string *name, zval *value, int ttl, int add) /* {{{ */ {
153 int ret = 0, flag = Z_TYPE_P(value);
154 char *msg;
155 time_t tv;
156 const char *key;
157 size_t key_len;
158
159 if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
160 return ret;
161 }
162
163 tv = time(NULL);
164 switch (Z_TYPE_P(value)) {
165 case IS_NULL:
166 case IS_TRUE:
167 case IS_FALSE:
168 ret = yac_storage_update(key, key_len, (char *)&flag, sizeof(int), flag, ttl, add, tv);
169 break;
170 case IS_LONG:
171 ret = yac_storage_update(key, key_len, (char *)&Z_LVAL_P(value), sizeof(long), flag, ttl, add, tv);
172 break;
173 case IS_DOUBLE:
174 ret = yac_storage_update(key, key_len, (char *)&Z_DVAL_P(value), sizeof(double), flag, ttl, add, tv);
175 break;
176 case IS_STRING:
177 #ifdef IS_CONSTANT
178 case IS_CONSTANT:
179 #endif
180 {
181 if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) {
182 int compressed_len;
183 char *compressed;
184
185 /* if longer than this, then we can not stored the length in flag */
186 if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) {
187 php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value));
188 return ret;
189 }
190
191 compressed = emalloc(Z_STRLEN_P(value) * 1.05);
192 compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed);
193 if (!compressed_len || compressed_len > Z_STRLEN_P(value)) {
194 php_error_docref(NULL, E_WARNING, "Compression failed");
195 efree(compressed);
196 return ret;
197 }
198
199 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
200 php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value));
201 efree(compressed);
202 return ret;
203 }
204
205 flag |= YAC_ENTRY_COMPRESSED;
206 flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT);
207 ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv);
208 efree(compressed);
209 } else {
210 ret = yac_storage_update(key, key_len, Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv);
211 }
212 }
213 break;
214 case IS_ARRAY:
215 #ifdef IS_CONSTANT_ARRAY
216 case IS_CONSTANT_ARRAY:
217 #endif
218 case IS_OBJECT:
219 {
220 smart_str buf = {0};
221
222 if (yac_serializer(value, &buf, &msg)) {
223 if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) {
224 int compressed_len;
225 char *compressed;
226
227 if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) {
228 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
229 return ret;
230 }
231
232 compressed = emalloc(buf.s->len * 1.05);
233 compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed);
234 if (!compressed_len || compressed_len > buf.s->len) {
235 php_error_docref(NULL, E_WARNING, "Compression failed");
236 efree(compressed);
237 return ret;
238 }
239
240 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
241 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
242 efree(compressed);
243 return ret;
244 }
245
246 flag |= YAC_ENTRY_COMPRESSED;
247 flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT);
248 ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv);
249 efree(compressed);
250 } else {
251 ret = yac_storage_update(key, key_len, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv);
252 }
253 smart_str_free(&buf);
254 } else {
255 php_error_docref(NULL, E_WARNING, "Serialization failed");
256 smart_str_free(&buf);
257 }
258 }
259 break;
260 case IS_RESOURCE:
261 php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored");
262 break;
263 default:
264 php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag);
265 break;
266 }
267
268 return ret;
269 }
270 /* }}} */
271
yac_add_multi_impl(yac_object * yac,zval * kvs,int ttl,int add)272 static int yac_add_multi_impl(yac_object *yac, zval *kvs, int ttl, int add) /* {{{ */ {
273 HashTable *ht = Z_ARRVAL_P(kvs);
274 zend_string *key;
275 zend_ulong idx;
276 zval *value;
277
278 ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) {
279 uint32_t should_free = 0;
280 if (!key) {
281 key = strpprintf(0, "%lu", idx);
282 should_free = 1;
283 }
284 if (yac_add_impl(yac, key, value, ttl, add)) {
285 if (should_free) {
286 zend_string_release(key);
287 }
288 continue;
289 } else {
290 if (should_free) {
291 zend_string_release(key);
292 }
293 return 0;
294 }
295 } ZEND_HASH_FOREACH_END();
296
297 return 1;
298 }
299 /* }}} */
300
yac_get_impl(yac_object * yac,zend_string * name,uint32_t * cas,zval * rv)301 static zval* yac_get_impl(yac_object *yac, zend_string *name, uint32_t *cas, zval *rv) /* {{{ */ {
302 uint32_t flag, size = 0;
303 char *data, *msg;
304 time_t tv;
305 const char *key;
306 size_t key_len;
307
308 if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
309 return NULL;
310 }
311
312 tv = time(NULL);
313 if (yac_storage_find(key, key_len, &data, &size, &flag, (int *)cas, tv)) {
314 switch ((flag & YAC_ENTRY_TYPE_MASK)) {
315 case IS_NULL:
316 if (size == sizeof(int)) {
317 ZVAL_NULL(rv);
318 }
319 efree(data);
320 break;
321 case IS_TRUE:
322 if (size == sizeof(int)) {
323 ZVAL_TRUE(rv);
324 }
325 efree(data);
326 break;
327 case IS_FALSE:
328 if (size == sizeof(int)) {
329 ZVAL_FALSE(rv);
330 }
331 efree(data);
332 break;
333 case IS_LONG:
334 if (size == sizeof(long)) {
335 ZVAL_LONG(rv, *(long*)data);
336 }
337 efree(data);
338 break;
339 case IS_DOUBLE:
340 if (size == sizeof(double)) {
341 ZVAL_DOUBLE(rv, *(double*)data);
342 }
343 efree(data);
344 break;
345 case IS_STRING:
346 #ifdef IS_CONSTANT
347 case IS_CONSTANT:
348 #endif
349 {
350 if ((flag & YAC_ENTRY_COMPRESSED)) {
351 size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
352 char *origin = emalloc(orig_len + 1);
353 uint32_t length;
354 length = fastlz_decompress(data, size, origin, orig_len);
355 if (!length) {
356 php_error_docref(NULL, E_WARNING, "Decompression failed");
357 efree(data);
358 efree(origin);
359 return NULL;
360 }
361 ZVAL_STRINGL(rv, origin, length);
362 efree(origin);
363 efree(data);
364 } else {
365 ZVAL_STRINGL(rv, data, size);
366 efree(data);
367 }
368 }
369 break;
370 case IS_ARRAY:
371 #ifdef IS_CONSTANT_ARRAY
372 case IS_CONSTANT_ARRAY:
373 #endif
374 case IS_OBJECT:
375 {
376 if ((flag & YAC_ENTRY_COMPRESSED)) {
377 size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
378 char *origin = emalloc(orig_len + 1);
379 length = fastlz_decompress(data, size, origin, orig_len);
380 if (!length) {
381 php_error_docref(NULL, E_WARNING, "Decompression failed");
382 efree(data);
383 efree(origin);
384 return NULL;
385 }
386 efree(data);
387 data = origin;
388 size = length;
389 }
390 rv = yac_unserializer(data, size, &msg, rv);
391 efree(data);
392 }
393 break;
394 default:
395 php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag);
396 rv = NULL;
397 break;
398 }
399 } else {
400 rv = NULL;
401 }
402
403 return rv;
404 }
405 /* }}} */
406
yac_get_multi_impl(yac_object * yac,zval * keys,zval * cas,zval * rv)407 static zval* yac_get_multi_impl(yac_object *yac, zval *keys, zval *cas, zval *rv) /* {{{ */ {
408 zval *value;
409 HashTable *ht = Z_ARRVAL_P(keys);
410
411 array_init(rv);
412
413 ZEND_HASH_FOREACH_VAL(ht, value) {
414 uint32_t lcas = 0;
415 zval *v, tmp;
416
417 switch (Z_TYPE_P(value)) {
418 case IS_STRING:
419 if ((v = yac_get_impl(yac, Z_STR_P(value), &lcas, &tmp))) {
420 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v);
421 } else {
422 ZVAL_FALSE(&tmp);
423 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp);
424 }
425 continue;
426 default:
427 {
428 zend_string *key = zval_get_string(value);
429 if ((v = yac_get_impl(yac, key, &lcas, &tmp))) {
430 zend_symtable_update(Z_ARRVAL_P(rv), key, v);
431 } else {
432 ZVAL_FALSE(&tmp);
433 zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp);
434 }
435 zend_string_release(key);
436 }
437 continue;
438 }
439 } ZEND_HASH_FOREACH_END();
440
441 return rv;
442 }
443 /* }}} */
444
yac_delete_impl(yac_object * yac,zend_string * name,int ttl)445 static int yac_delete_impl(yac_object *yac, zend_string *name, int ttl) /* {{{ */ {
446 time_t tv = 0;
447 const char *key;
448 size_t key_len;
449
450 if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
451 return 0;
452 }
453
454 if (ttl) {
455 tv = (zend_ulong)time(NULL);
456 }
457
458 return yac_storage_delete(key, key_len, ttl, tv);
459 }
460 /* }}} */
461
yac_delete_multi_impl(yac_object * yac,zval * keys,int ttl)462 static int yac_delete_multi_impl(yac_object *yac, zval *keys, int ttl) /* {{{ */ {
463 HashTable *ht = Z_ARRVAL_P(keys);
464 int ret = 1;
465 zval *value;
466
467 ZEND_HASH_FOREACH_VAL(ht, value) {
468 switch (Z_TYPE_P(value)) {
469 case IS_STRING:
470 ret = ret & yac_delete_impl(yac, Z_STR_P(value), ttl);
471 continue;
472 default:
473 {
474 zend_string *key = zval_get_string(value);
475 ret = ret & yac_delete_impl(yac, key, ttl);
476 zend_string_release(key);
477 }
478 continue;
479 }
480 } ZEND_HASH_FOREACH_END();
481
482 return ret;
483 }
484 /* }}} */
485
yac_object_new(zend_class_entry * ce)486 static zend_object *yac_object_new(zend_class_entry *ce) /* {{{ */ {
487 yac_object *yac = emalloc(sizeof(yac_object) + zend_object_properties_size(ce));
488
489 if (!YAC_G(enable)) {
490 zend_throw_exception(NULL, "Yac is not enabled", 0);
491 }
492
493 zend_object_std_init(&yac->std, ce);
494 yac->std.handlers = &yac_obj_handlers;
495 yac->prefix_len = 0;
496
497
498 return &yac->std;
499 }
500 /* }}} */
501
yac_object_free(zend_object * object)502 static void yac_object_free(zend_object *object) /* {{{ */ {
503 zend_object_std_dtor(object);
504 }
505 /* }}} */
506
yac_read_property_ptr(zval * zobj,zval * name,int type,void ** cache_slot)507 static zval* yac_read_property_ptr(zval *zobj, zval *name, int type, void **cache_slot) /* {{{ */ {
508 return &EG(error_zval);
509 }
510 /* }}} */
511
yac_read_property(zval * zobj,zval * name,int type,void ** cache_slot,zval * rv)512 static zval* yac_read_property(zval *zobj, zval *name, int type, void **cache_slot, zval *rv) /* {{{ */ {
513 if (UNEXPECTED(type == BP_VAR_RW||type == BP_VAR_W)) {
514 return &EG(error_zval);
515 }
516
517 if (yac_get_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), NULL, rv)) {
518 return rv;
519 }
520
521 return &EG(uninitialized_zval);
522 }
523 /* }}} */
524
yac_write_property(zval * zobj,zval * name,zval * value,void ** cache_slot)525 static YAC_WHANDLER yac_write_property(zval *zobj, zval *name, zval *value, void **cache_slot) /* {{{ */ {
526 yac_add_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), value, 0, 0);
527 Z_TRY_ADDREF_P(value);
528
529 YAC_WHANDLER_RET(value);
530 }
531 /* }}} */
532
yac_unset_property(zval * zobj,zval * name,void ** cache_slot)533 static void yac_unset_property(zval *zobj, zval *name, void **cache_slot) /* {{{ */ {
534 yac_delete_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), 0);
535 }
536 /* }}} */
537
538 /** {{{ proto public Yac::__construct([string $prefix])
539 */
PHP_METHOD(yac,__construct)540 PHP_METHOD(yac, __construct) {
541 zend_string *prefix = NULL;
542
543 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) {
544 return;
545 }
546
547 if (prefix && ZSTR_LEN(prefix)) {
548 yac_object *yac;
549 if (ZSTR_LEN(prefix) > YAC_STORAGE_MAX_KEY_LEN) {
550 zend_throw_exception_ex(NULL, 0,
551 "Prefix '%s' exceed max key length '%d' bytes", ZSTR_VAL(prefix), YAC_STORAGE_MAX_KEY_LEN);
552 return;
553 }
554 yac = Z_YACOBJ_P(getThis());
555 yac->prefix_len = ZSTR_LEN(prefix);
556 memcpy(yac->prefix, ZSTR_VAL(prefix), ZSTR_LEN(prefix));
557 }
558 }
559 /* }}} */
560
561 /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl])
562 */
PHP_METHOD(yac,add)563 PHP_METHOD(yac, add) {
564 zend_long ttl = 0;
565 zval *keys, *value = NULL;
566 int ret;
567
568 switch (ZEND_NUM_ARGS()) {
569 case 1:
570 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
571 return;
572 }
573 break;
574 case 2:
575 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
576 return;
577 }
578 if (Z_TYPE_P(keys) == IS_ARRAY) {
579 if (Z_TYPE_P(value) == IS_LONG) {
580 ttl = Z_LVAL_P(value);
581 value = NULL;
582 } else {
583 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
584 return;
585 }
586 }
587 break;
588 case 3:
589 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
590 return;
591 }
592 break;
593 default:
594 WRONG_PARAM_COUNT;
595 }
596
597 if (Z_TYPE_P(keys) == IS_ARRAY) {
598 ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 1);
599 } else if (Z_TYPE_P(keys) == IS_STRING) {
600 ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 1);
601 } else {
602 zend_string *key = zval_get_string(keys);
603 ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 1);
604 zend_string_release(key);
605 }
606
607 RETURN_BOOL(ret);
608 }
609 /* }}} */
610
611 /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl])
612 */
PHP_METHOD(yac,set)613 PHP_METHOD(yac, set) {
614 zend_long ttl = 0;
615 zval *keys, *value = NULL;
616 int ret;
617
618 switch (ZEND_NUM_ARGS()) {
619 case 1:
620 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
621 return;
622 }
623 break;
624 case 2:
625 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
626 return;
627 }
628 if (Z_TYPE_P(keys) == IS_ARRAY) {
629 if (Z_TYPE_P(value) == IS_LONG) {
630 ttl = Z_LVAL_P(value);
631 value = NULL;
632 } else {
633 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
634 return;
635 }
636 }
637 break;
638 case 3:
639 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
640 return;
641 }
642 break;
643 default:
644 WRONG_PARAM_COUNT;
645 }
646
647 if (Z_TYPE_P(keys) == IS_ARRAY) {
648 ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 0);
649 } else if (Z_TYPE_P(keys) == IS_STRING) {
650 ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 0);
651 } else {
652 zend_string *key = zval_get_string(keys);
653 ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 0);
654 zend_string_release(key);
655 }
656
657 RETURN_BOOL(ret);
658 }
659 /* }}} */
660
661 /** {{{ proto public Yac::get(mixed $keys[, int &$cas])
662 */
PHP_METHOD(yac,get)663 PHP_METHOD(yac, get) {
664 uint32_t lcas = 0;
665 zval *ret, *keys, *cas = NULL;
666
667 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) {
668 return;
669 }
670
671 if (Z_TYPE_P(keys) == IS_ARRAY) {
672 ret = yac_get_multi_impl(Z_YACOBJ_P(getThis()), keys, cas, return_value);
673 } else if (Z_TYPE_P(keys) == IS_STRING) {
674 ret = yac_get_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), &lcas, return_value);
675 } else {
676 zend_string *key = zval_get_string(keys);
677 ret = yac_get_impl(Z_YACOBJ_P(getThis()), key, &lcas, return_value);
678 zend_string_release(key);
679 }
680
681 if (ret == NULL) {
682 RETURN_FALSE;
683 }
684 }
685 /* }}} */
686
687 /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0])
688 */
PHP_METHOD(yac,delete)689 PHP_METHOD(yac, delete) {
690 zend_long time = 0;
691 zval *keys;
692 int ret;
693
694 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) {
695 return;
696 }
697
698 if (Z_TYPE_P(keys) == IS_ARRAY) {
699 ret = yac_delete_multi_impl(Z_YACOBJ_P(getThis()), keys, time);
700 } else if (Z_TYPE_P(keys) == IS_STRING) {
701 ret = yac_delete_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), time);
702 } else {
703 zend_string *key = zval_get_string(keys);
704 ret = yac_delete_impl(Z_YACOBJ_P(getThis()), key, time);
705 zend_string_release(key);
706 }
707
708 RETURN_BOOL(ret);
709 }
710 /* }}} */
711
712 /** {{{ proto public Yac::flush(void)
713 */
PHP_METHOD(yac,flush)714 PHP_METHOD(yac, flush) {
715
716 yac_storage_flush();
717
718 RETURN_TRUE;
719 }
720 /* }}} */
721
722 /** {{{ proto public Yac::info(void)
723 */
PHP_METHOD(yac,info)724 PHP_METHOD(yac, info) {
725 yac_storage_info *inf;
726
727 inf = yac_storage_get_info();
728
729 array_init(return_value);
730
731 add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize);
732 add_assoc_long(return_value, "slots_memory_size", inf->k_msize);
733 add_assoc_long(return_value, "values_memory_size", inf->v_msize);
734 add_assoc_long(return_value, "segment_size", inf->segment_size);
735 add_assoc_long(return_value, "segment_num", inf->segments_num);
736 add_assoc_long(return_value, "miss", inf->miss);
737 add_assoc_long(return_value, "hits", inf->hits);
738 add_assoc_long(return_value, "fails", inf->fails);
739 add_assoc_long(return_value, "kicks", inf->kicks);
740 add_assoc_long(return_value, "recycles", inf->recycles);
741 add_assoc_long(return_value, "slots_size", inf->slots_size);
742 add_assoc_long(return_value, "slots_used", inf->slots_num);
743
744 yac_storage_free_info(inf);
745 return;
746 }
747 /* }}} */
748
749 /** {{{ proto public Yac::dump(int $limit)
750 */
PHP_METHOD(yac,dump)751 PHP_METHOD(yac, dump) {
752 long limit = 100;
753 yac_item_list *list, *l;
754
755 array_init(return_value);
756
757 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) {
758 return;
759 }
760
761 list = l = yac_storage_dump(limit);
762 for (; l; l = l->next) {
763 zval item;
764 array_init(&item);
765 add_assoc_long(&item, "index", l->index);
766 add_assoc_long(&item, "hash", l->h);
767 add_assoc_long(&item, "crc", l->crc);
768 add_assoc_long(&item, "ttl", l->ttl);
769 add_assoc_long(&item, "k_len", l->k_len);
770 add_assoc_long(&item, "v_len", l->v_len);
771 add_assoc_long(&item, "size", l->size);
772 add_assoc_string(&item, "key", (char*)l->key);
773 add_next_index_zval(return_value, &item);
774 }
775
776 yac_storage_free_list(list);
777 return;
778 }
779 /* }}} */
780
781 #if 0
782 only OO-style APIs is supported now
783 /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl])
784 */
785 PHP_FUNCTION(yac_add)
786 {
787 PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
788 }
789 /* }}} */
790
791 /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl])
792 */
793 PHP_FUNCTION(yac_set)
794 {
795 PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
796 }
797 /* }}} */
798
799 /* {{{ proto bool yac_get(mixed $keys[, int &$cas])
800 */
801 PHP_FUNCTION(yac_get)
802 {
803 PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
804 }
805 /* }}} */
806
807 /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0])
808 */
809 PHP_FUNCTION(yac_delete)
810 {
811 PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
812 }
813 /* }}} */
814
815 /* {{{ proto bool yac_flush(void)
816 */
817 PHP_FUNCTION(yac_flush)
818 {
819 PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
820 }
821 /* }}} */
822
823 /* {{{ proto bool yac_info(void)
824 */
825 PHP_FUNCTION(yac_info)
826 {
827 PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
828 }
829 /* }}} */
830
831 /* {{{ yac_functions[] */
832 zend_function_entry yac_functions[] = {
833 PHP_FE(yac_add, arginfo_yac_add)
834 PHP_FE(yac_set, arginfo_yac_add)
835 PHP_FE(yac_get, arginfo_yac_get)
836 PHP_FE(yac_delete, arginfo_yac_delete)
837 PHP_FE(yac_flush, arginfo_yac_void)
838 PHP_FE(yac_info, arginfo_yac_void)
839 {NULL, NULL}
840 };
841 /* }}} */
842 #endif
843
844 /** {{{ yac_methods
845 */
846 zend_function_entry yac_methods[] = {
847 PHP_ME(yac, __construct, arginfo_yac_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
848 PHP_ME(yac, add, arginfo_yac_add, ZEND_ACC_PUBLIC)
849 PHP_ME(yac, set, arginfo_yac_add, ZEND_ACC_PUBLIC)
850 PHP_ME(yac, get, arginfo_yac_get, ZEND_ACC_PUBLIC)
851 PHP_ME(yac, delete, arginfo_yac_delete, ZEND_ACC_PUBLIC)
852 PHP_ME(yac, flush, arginfo_yac_void, ZEND_ACC_PUBLIC)
853 PHP_ME(yac, info, arginfo_yac_void, ZEND_ACC_PUBLIC)
854 PHP_ME(yac, dump, arginfo_yac_void, ZEND_ACC_PUBLIC)
855 {NULL, NULL, NULL}
856 };
857 /* }}} */
858
859 /* {{{ PHP_GINIT_FUNCTION
860 */
PHP_GINIT_FUNCTION(yac)861 PHP_GINIT_FUNCTION(yac)
862 {
863 yac_globals->enable = 1;
864 yac_globals->k_msize = (4 * 1024 * 1024);
865 yac_globals->v_msize = (64 * 1024 * 1024);
866 yac_globals->debug = 0;
867 yac_globals->compress_threshold = -1;
868 yac_globals->enable_cli = 0;
869 #ifdef PHP_WIN32
870 yac_globals->mmap_base = NULL;
871 #endif
872 }
873 /* }}} */
874
875 /* {{{ PHP_MINIT_FUNCTION
876 */
PHP_MINIT_FUNCTION(yac)877 PHP_MINIT_FUNCTION(yac)
878 {
879 char *msg;
880 zend_class_entry ce;
881
882 REGISTER_INI_ENTRIES();
883
884 if (!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) {
885 YAC_G(enable) = 0;
886 }
887
888 if (YAC_G(enable)) {
889 if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) {
890 php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno));
891 return FAILURE;
892 }
893 }
894
895 REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
896 REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS);
897 REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS);
898 REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS);
899 REGISTER_LONG_CONSTANT("YAC_SERIALIZER_PHP", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS);
900 #if YAC_ENABLE_MSGPACK
901 REGISTER_LONG_CONSTANT("YAC_SERIALIZER_MSGPACK", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS);
902 #endif
903 #if YAC_ENABLE_IGBINARY
904 REGISTER_LONG_CONSTANT("YAC_SERIALIZER_IGBINARY", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS);
905 #endif
906 #if YAC_ENABLE_JSON
907 REGISTER_LONG_CONSTANT("YAC_SERIALIZER_JSON", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS);
908 #endif
909
910 #if YAC_ENABLE_MSGPACK
911 if (strcmp(YAC_G(serializer), "msgpack") == 0) {
912 yac_serializer = yac_serializer_msgpack_pack;
913 yac_unserializer = yac_serializer_msgpack_unpack;
914 REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS);
915 } else
916 #endif
917 #if YAC_ENABLE_IGBINARY
918 if (strcmp(YAC_G(serializer), "igbinary") == 0) {
919 yac_serializer = yac_serializer_igbinary_pack;
920 yac_unserializer = yac_serializer_igbinary_unpack;
921 REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS);
922 } else
923 #endif
924 #if YAC_ENABLE_JSON
925 if (strcmp(YAC_G(serializer), "json") == 0) {
926 yac_serializer = yac_serializer_json_pack;
927 yac_unserializer = yac_serializer_json_unpack;
928 REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS);
929 } else
930 #endif
931 {
932 yac_serializer = yac_serializer_php_pack;
933 yac_unserializer = yac_serializer_php_unpack;
934 REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS);
935 }
936
937 INIT_CLASS_ENTRY(ce, "Yac", yac_methods);
938 yac_class_ce = zend_register_internal_class(&ce);
939 yac_class_ce->ce_flags |= ZEND_ACC_FINAL;
940 yac_class_ce->create_object = yac_object_new;
941
942 memcpy(&yac_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
943 yac_obj_handlers.offset = XtOffsetOf(yac_object, std);
944 yac_obj_handlers.free_obj = yac_object_free;
945 if (YAC_G(enable)) {
946 yac_obj_handlers.read_property = yac_read_property;
947 yac_obj_handlers.write_property = yac_write_property;
948 yac_obj_handlers.unset_property = yac_unset_property;
949 yac_obj_handlers.get_property_ptr_ptr = yac_read_property_ptr;
950 }
951
952 return SUCCESS;
953 }
954 /* }}} */
955
956 /* {{{ PHP_MSHUTDOWN_FUNCTION
957 */
PHP_MSHUTDOWN_FUNCTION(yac)958 PHP_MSHUTDOWN_FUNCTION(yac)
959 {
960 UNREGISTER_INI_ENTRIES();
961 if (YAC_G(enable)) {
962 yac_storage_shutdown();
963 }
964 return SUCCESS;
965 }
966 /* }}} */
967
968 /* {{{ PHP_MINFO_FUNCTION
969 */
PHP_MINFO_FUNCTION(yac)970 PHP_MINFO_FUNCTION(yac)
971 {
972 smart_str names = {0,};
973
974 php_info_print_table_start();
975 php_info_print_table_header(2, "yac support", "enabled");
976 php_info_print_table_row(2, "Version", PHP_YAC_VERSION);
977 php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name());
978
979 smart_str_appends(&names, "php");
980 #if YAC_ENABLE_MSGPACK
981 smart_str_appends(&names, ", msgpack");
982 #endif
983 #if YAC_ENABLE_IGBINARY
984 smart_str_appends(&names, ", igbinary");
985 #endif
986 #if YAC_ENABLE_JSON
987 smart_str_appends(&names, ", json");
988 #endif
989 php_info_print_table_row(2, "Serializer", ZSTR_VAL(names.s));
990 smart_str_free(&names);
991
992 php_info_print_table_end();
993
994 DISPLAY_INI_ENTRIES();
995
996 if (YAC_G(enable)) {
997 char buf[64];
998 yac_storage_info *inf;
999 inf = yac_storage_get_info();
1000
1001 php_info_print_table_start();
1002 php_info_print_table_colspan_header(2, "Cache info");
1003 snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize);
1004 php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf);
1005 snprintf(buf, sizeof(buf), "%ld", inf->k_msize);
1006 php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf);
1007 snprintf(buf, sizeof(buf), "%ld", inf->v_msize);
1008 php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf);
1009 snprintf(buf, sizeof(buf), "%d", inf->segment_size);
1010 php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf);
1011 snprintf(buf, sizeof(buf), "%d", inf->segments_num);
1012 php_info_print_table_row(2, "Number of Segments (segment_num)", buf);
1013 snprintf(buf, sizeof(buf), "%d", inf->slots_size);
1014 php_info_print_table_row(2, "Total Slots Number(slots_size)", buf);
1015 snprintf(buf, sizeof(buf), "%d", inf->slots_num);
1016 php_info_print_table_row(2, "Total Used Slots(slots_num)", buf);
1017 php_info_print_table_end();
1018
1019 yac_storage_free_info(inf);
1020 }
1021 }
1022 /* }}} */
1023
1024 #ifdef COMPILE_DL_YAC
1025 ZEND_GET_MODULE(yac)
1026 #endif
1027
1028 static zend_module_dep yac_module_deps[] = {
1029 #if YAC_ENABLE_MSGPACK
1030 ZEND_MOD_REQUIRED("msgpack")
1031 #endif
1032 #if YAC_ENABLE_IGBINARY
1033 ZEND_MOD_REQUIRED("igbinary")
1034 #endif
1035 #if YAC_ENABLE_JSON
1036 ZEND_MOD_REQUIRED("json")
1037 #endif
1038 {NULL, NULL, NULL, 0}
1039 };
1040
1041 /* {{{ yac_module_entry
1042 */
1043 zend_module_entry yac_module_entry = {
1044 STANDARD_MODULE_HEADER_EX,
1045 NULL,
1046 yac_module_deps,
1047 "yac",
1048 NULL, /* yac_functions, */
1049 PHP_MINIT(yac),
1050 PHP_MSHUTDOWN(yac),
1051 NULL,
1052 NULL,
1053 PHP_MINFO(yac),
1054 PHP_YAC_VERSION,
1055 PHP_MODULE_GLOBALS(yac),
1056 PHP_GINIT(yac),
1057 NULL,
1058 NULL,
1059 STANDARD_MODULE_PROPERTIES_EX
1060 };
1061 /* }}} */
1062
1063 /*
1064 * Local variables:
1065 * tab-width: 4
1066 * c-basic-offset: 4
1067 * End:
1068 * vim600: noet sw=4 ts=4 fdm=marker
1069 * vim<600: noet sw=4 ts=4
1070 */
1071
1072