Browse Source

restruct cached compile, add md5 table to recognize and merge file with same content

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@311 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
tags/2.0.0-beta1
Xuefer 14 years ago
parent
commit
4af40759f6
7 changed files with 527 additions and 273 deletions
  1. +31
    -0
      graph/cached_compile.dot
  2. +1
    -0
      processor/dispatch.m4
  3. +38
    -17
      processor/head.m4
  4. +9
    -2
      processor/main.m4
  5. +25
    -13
      processor/processor.m4
  6. +395
    -230
      xcache.c
  7. +28
    -11
      xcache.h

+ 31
- 0
graph/cached_compile.dot View File

@@ -0,0 +1,31 @@
digraph tree {
subgraph cluster_compiling {
label="compiling";
php_compile;
php_store;
entry_store;
}
error [color=red];
origin_compile [color=red]

begin -> origin_compile [label="compiling", color=red];

begin -> entry_init_key -> entry_lookup;
edge [label=hit, color=blue]
entry_lookup -> restore;
php_lookup -> entry_store;
edge [label=miss, color=green]
entry_lookup -> md5_init;
md5_init -> php_lookup;
php_lookup -> php_compile;

edge [label="", color=""]
php_lookup -> origin_compile [label="miss but compiling", color=red];
php_compile -> php_store -> entry_store -> restore;

edge [color=red];
md5_init -> error;
php_compile -> error;
php_store -> error;
entry_store -> error;
}

+ 1
- 0
processor/dispatch.m4 View File

@@ -22,6 +22,7 @@ define(`DISPATCH', `
, `$1', `zval_data_type', `PROC_INT(`$2', `u', `$1')'
, `$1', `xc_entry_type_t', `PROC_INT(`$2', `d', `$1')'
, `$1', `xc_hash_value_t', `PROC_INT(`$2', `lu', `$1')'
, `$1', `xc_md5sum_t', `/* is copying enough? */COPY(`$2')'
, `', `', `m4_errprint(`Unknown type "$1"')'
)
')

+ 38
- 17
processor/head.m4 View File

@@ -64,8 +64,9 @@ struct _xc_processor_t {
HashTable zvalptrs;
zend_bool reference; /* enable if to deal with reference */
zend_bool have_references;
const xc_entry_t *xce_src;
const xc_entry_t *xce_dst;
const xc_entry_data_php_t *php_src;
const xc_entry_data_php_t *php_dst;
const xc_cache_t *cache;
const zend_class_entry *cache_ce;
zend_uint cache_class_num;

@@ -185,14 +186,14 @@ static inline zstr xc_store_string_n(xc_processor_t *processor, zend_uchar type,
*/
static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry *ce) {
zend_ulong i;
const xc_entry_t *xce = processor->xce_src;
const xc_entry_data_php_t *php = processor->php_src;
zend_class_entry *ceptr;

if (processor->cache_ce == ce) {
return processor->cache_class_num;
}
for (i = 0; i < xce->data.php->classinfo_cnt; i ++) {
ceptr = CestToCePtr(xce->data.php->classinfos[i].cest);
for (i = 0; i < php->classinfo_cnt; i ++) {
ceptr = CestToCePtr(php->classinfos[i].cest);
if (ZCEP_REFCOUNT_PTR(ceptr) == ZCEP_REFCOUNT_PTR(ce)) {
processor->cache_ce = ceptr;
processor->cache_class_num = i + 1;
@@ -208,7 +209,7 @@ static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry *
static zend_class_entry *xc_get_class(xc_processor_t *processor, zend_ulong class_num) {
/* must be parent or currrent class */
assert(class_num <= processor->active_class_num);
return CestToCePtr(processor->xce_dst->data.php->classinfos[class_num - 1].cest);
return CestToCePtr(processor->php_dst->classinfos[class_num - 1].cest);
}
#endif
/* }}} */
@@ -274,13 +275,15 @@ static void xc_zend_extension_op_array_ctor_handler(zend_extension *extension, z
}
/* }}} */
dnl ================ export API
/* export: xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC); :export {{{ */
xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
xc_entry_t *dst;
define(`DEFINE_STORE_API', `
/* export: $1 *xc_processor_store_$1($1 *src TSRMLS_DC); :export {{{ */
$1 *xc_processor_store_$1($1 *src TSRMLS_DC) {
$1 *dst;
xc_processor_t processor;

memset(&processor, 0, sizeof(processor));
processor.reference = 1;
processor.cache = src->cache;

IFASSERT(`xc_stack_init(&processor.allocsizes);')

@@ -294,14 +297,18 @@ xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
/* allocate */
processor.size = ALIGN(processor.size + sizeof(src[0]));

xc_calc_xc_entry_t(&processor, src TSRMLS_CC);
xc_calc_$1(&processor, src TSRMLS_CC);
if (processor.reference) {
zend_hash_destroy(&processor.zvalptrs);
}
zend_hash_destroy(&processor.strings);
}
src->size = processor.size;
src->have_references = processor.have_references;
ifelse(`$1', `xc_entry_t', `
src->data.var->have_references = processor.have_references;
', `
src->have_references = processor.have_references;
')

IFASSERT(`xc_stack_reverse(&processor.allocsizes);')
/* store {{{ */
@@ -313,7 +320,7 @@ xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
}

/* mem :) */
processor.p = (char *) src->cache->mem->handlers->malloc(src->cache->mem, processor.size);
processor.p = (char *) processor.cache->mem->handlers->malloc(processor.cache->mem, processor.size);
if (processor.p == NULL) {
dst = NULL;
goto err_alloc;
@@ -322,10 +329,10 @@ xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
assert(processor.p == (char *) ALIGN(processor.p));

/* allocate */
dst = (xc_entry_t *) processor.p;
dst = ($1 *) processor.p;
processor.p = (char *) ALIGN(processor.p + sizeof(dst[0]));

xc_store_xc_entry_t(&processor, dst, src TSRMLS_CC);
xc_store_$1(&processor, dst, src TSRMLS_CC);
IFASSERT(` {
int real = processor.p - oldp;
int should = processor.size;
@@ -347,12 +354,26 @@ err_alloc:
return dst;
}
/* }}} */
/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC) {
')
DEFINE_STORE_API(`xc_entry_t')
DEFINE_STORE_API(`xc_entry_data_php_t')
/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC); :export {{{ */
xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC) {
xc_processor_t processor;

memset(&processor, 0, sizeof(processor));
xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);

return dst;
}
/* }}} */
/* export: xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC) {
xc_processor_t processor;

memset(&processor, 0, sizeof(processor));
processor.readonly_protection = readonly_protection;
/* this function is used for php data only */
if (src->have_references) {
processor.reference = 1;
}
@@ -360,7 +381,7 @@ xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *s
if (processor.reference) {
zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
}
xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);
xc_restore_xc_entry_data_php_t(&processor, dst, src TSRMLS_CC);
if (processor.reference) {
zend_hash_destroy(&processor.zvalptrs);
}


+ 9
- 2
processor/main.m4 View File

@@ -135,16 +135,22 @@ dnl }}}
dnl {{{ FIXPOINTER
define(`FIXPOINTER', `FIXPOINTER_EX(`$1', `dst->$2')')
define(`FIXPOINTER_EX', `IFSTORE(`
$2 = ($1 *) processor->xce_src->cache->shm->handlers->to_readonly(processor->xce_src->cache->shm, (char *)$2);
$2 = ($1 *) processor->cache->shm->handlers->to_readonly(processor->cache->shm, (char *)$2);
')')
define(`UNFIXPOINTER', `UNFIXPOINTER_EX(`$1', `dst->$2')')
define(`UNFIXPOINTER_EX', `IFSTORE(`
$2 = ($1 *) processor->xce_src->cache->shm->handlers->to_readwrite(processor->xce_src->cache->shm, (char *)$2);
$2 = ($1 *) processor->cache->shm->handlers->to_readwrite(processor->cache->shm, (char *)$2);
')')
dnl }}}
dnl {{{ COPY
define(`COPY', `IFNOTMEMCPY(`IFCOPY(`dst->$1 = src->$1;')')DONE(`$1')')
dnl }}}
dnl {{{ COPYPOINTER
define(`COPYPOINTER', `COPY(`$1')')
dnl }}}
dnl {{{ COPYARRAY
define(`COPYARRAY', `IFNOTMEMCPY(`IFCOPY(`memcpy(dst->$1, src->$1, sizeof(dst->$1));')')DONE(`$1')')
dnl }}}
dnl {{{ SETNULL_EX
define(`SETNULL_EX', `IFCOPY(`$1 = NULL;')')
define(`SETNULL', `SETNULL_EX(`dst->$1')DONE(`$1')')
@@ -222,6 +228,7 @@ EXPORT(`zend_class_entry')
EXPORT(`xc_classinfo_t')
EXPORT(`xc_funcinfo_t')
EXPORT(`xc_entry_t')
EXPORT(`xc_entry_data_php_t')
EXPORT(`zval')

include(srcdir`/processor/hashtable.m4')


+ 25
- 13
processor/processor.m4 View File

@@ -478,7 +478,7 @@ DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{
dnl shadow copy must NOT meet:
dnl readonly_protection=on
dnl main op_array && have early binding
if (!processor->readonly_protection && !(src == processor->xce_src->data.php->op_array && processor->xce_src->data.php->have_early_binding)) {
if (!processor->readonly_protection && !(src == processor->php_src->op_array && processor->php_src->have_early_binding)) {
/* really fast shallow copy */
memcpy(dst, src, sizeof(src[0]));
dst->refcount[0] = 1000;
@@ -718,13 +718,21 @@ dnl }}}
DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{
zend_uint i;

#ifdef HAVE_INODE
DISPATCH(int, device)
DISPATCH(int, inode)
#endif
DISPATCH(size_t, sourcesize)
IFCOPY(`
processor->php_dst = dst;
processor->php_src = src;
')

DISPATCH(time_t, mtime)
DISPATCH(xc_hash_value_t, hvalue)
/* skip */
DONE(next)
COPY(cache)
DISPATCH(xc_md5sum_t, md5)
DISPATCH(zend_ulong, refcount)

DISPATCH(size_t, sourcesize)
DISPATCH(zend_ulong, hits)
DISPATCH(size_t, size)

STRUCT_P(zend_op_array, op_array)

@@ -749,20 +757,18 @@ DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{
#endif
DISPATCH(zend_bool, have_early_binding)
popdef(`BEFORE_LOOP')
DISPATCH(zend_bool, have_references)
')
dnl }}}
DEF_STRUCT_P_FUNC(`xc_entry_data_var_t', , `dnl {{{
IFDPRINT(`INDENT()`'fprintf(stderr, "zval:value");')
STRUCT_P_EX(zval_ptr, dst->value, src->value, `value', `', `&')
DISPATCH(zend_bool, have_references)
DONE(value)
')
dnl }}}
dnl {{{ xc_entry_t
DEF_STRUCT_P_FUNC(`xc_entry_t', , `
IFCOPY(`
processor->xce_dst = dst;
processor->xce_src = src;
')
DISPATCH(xc_entry_type_t, type)
DISPATCH(size_t, size)

@@ -808,18 +814,24 @@ DEF_STRUCT_P_FUNC(`xc_entry_t', , `
DISABLECHECK(`
switch (src->type) {
case XC_TYPE_PHP:
STRUCT_P(xc_entry_data_php_t, data.php)
IFCALCCOPY(`DONE(data.php)', `STRUCT_P(xc_entry_data_php_t, data.php)')
break;

case XC_TYPE_VAR:
STRUCT_P(xc_entry_data_var_t, data.var)
break;

default:
assert(0);
}
')
DONE(data)
dnl }}}
DISPATCH(zend_bool, have_references)
DISPATCH(time_t, mtime)
#ifdef HAVE_INODE
DISPATCH(int, device)
DISPATCH(int, inode)
#endif
')
dnl }}}
dnl ====================================================

+ 395
- 230
xcache.c View File

@@ -105,6 +105,66 @@ ZEND_DECLARE_MODULE_GLOBALS(xcache);

/* any function in *_dmz is only safe be called within locked(single thread) area */

static void xc_php_add_dmz(xc_entry_data_php_t *php) /* {{{ */
{
xc_entry_data_php_t **head = &(php->cache->phps[php->hvalue]);
php->next = *head;
*head = php;
php->cache->phps_count ++;
}
/* }}} */
static xc_entry_data_php_t *xc_php_store_dmz(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
{
xc_entry_data_php_t *stored_php;

php->hits = 0;
php->refcount = 0;
stored_php = xc_processor_store_xc_entry_data_php_t(php TSRMLS_CC);
if (stored_php) {
xc_php_add_dmz(stored_php);
return stored_php;
}
else {
php->cache->ooms ++;
return NULL;
}
}
/* }}} */
static xc_entry_data_php_t *xc_php_find_dmz(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
{
xc_entry_data_php_t *p;
for (p = php->cache->phps[php->hvalue]; p; p = p->next) {
if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
p->hits ++;
return p;
}
}
return NULL;
}
/* }}} */
static void xc_php_free_dmz(xc_entry_data_php_t *php) /* {{{ */
{
php->cache->mem->handlers->free(php->cache->mem, (xc_entry_data_php_t *)php);
}
/* }}} */
static void xc_php_remove_dmz(xc_entry_data_php_t *php) /* {{{ */
{
if (-- php->refcount == 0) {
xc_entry_data_php_t **pp = &(php->cache->phps[php->hvalue]);
xc_entry_data_php_t *p;
for (p = *pp; p; pp = &(p->next), p = p->next) {
if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
/* unlink */
*pp = p->next;
xc_php_free_dmz(php);
return;
}
}
assert(0);
}
}
/* }}} */

static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
{
/* this function isn't required but can be in dmz */
@@ -116,11 +176,9 @@ static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
case XC_TYPE_PHP:
#ifdef HAVE_INODE
do {
xc_entry_data_php_t *ap = a->data.php;
xc_entry_data_php_t *bp = b->data.php;
if (ap->inode) {
return ap->inode == bp->inode
&& ap->device == bp->device;
if (a->inode) {
return a->inode == b->inode
&& a->device == b->device;
}
} while(0);
#endif
@@ -149,11 +207,6 @@ static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
return 0;
}
/* }}} */
static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
{
xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
}
/* }}} */
static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
{
xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
@@ -180,6 +233,14 @@ static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
}
}
/* }}} */
static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
{
if (xce->type == XC_TYPE_PHP) {
xc_php_remove_dmz(xce->data.php);
}
xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
}
/* }}} */
static void xc_entry_free_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
{
xce->cache->entries_count --;
@@ -215,7 +276,7 @@ static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
xc_entry_t *p;
for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
if (xc_entry_equal_dmz(xce, p)) {
if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
if (p->type == XC_TYPE_VAR || /* PHP */ p->mtime == xce->mtime) {
p->hits ++;
p->atime = XG(request_time);
return p;
@@ -473,10 +534,10 @@ static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /
php = entry->data.php;
add_assoc_long_ex(ei, ZEND_STRS("sourcesize"), php->sourcesize);
#ifdef HAVE_INODE
add_assoc_long_ex(ei, ZEND_STRS("device"), php->device);
add_assoc_long_ex(ei, ZEND_STRS("inode"), php->inode);
add_assoc_long_ex(ei, ZEND_STRS("device"), entry->device);
add_assoc_long_ex(ei, ZEND_STRS("inode"), entry->inode);
#endif
add_assoc_long_ex(ei, ZEND_STRS("mtime"), php->mtime);
add_assoc_long_ex(ei, ZEND_STRS("mtime"), entry->mtime);

#ifdef HAVE_XCACHE_CONSTANT
add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt);
@@ -643,19 +704,20 @@ static int xc_stat(const char *filename, const char *include_path, struct stat *
}
if (VCWD_STAT(filepath, pbuf) == 0) {
free_alloca(paths);
return 0;
return FAILURE;
}
}

free_alloca(paths);

return 1;
return SUCCESS;
}
/* }}} */

#define HASH(i) (i)
#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
#define HASH_STR_S(s, l) HASH(zend_inline_hash_func(s, l))
#define HASH_STR_L(s, l) HASH_STR_S(s, l + 1)
#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
#define HASH_NUM(n) HASH(n)
static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *xce TSRMLS_DC) /* {{{ */
@@ -668,8 +730,8 @@ static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *xce TSRMLS_DC) /* {
static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce TSRMLS_DC) /* {{{ */
{
#ifdef HAVE_INODE
if (xce->data.php->inode) {
return HASH(xce->data.php->device + xce->data.php->inode);
if (xce->inode) {
return HASH(xce->device + xce->inode);
}
#endif
return xc_entry_hash_name(xce TSRMLS_CC);
@@ -684,7 +746,7 @@ static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_p
char *ptr;

if (!filename || !SG(request_info).path_translated) {
return 0;
return FAILURE;
}

php = xce->data.php;
@@ -702,7 +764,7 @@ static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_p
pbuf = &buf;
if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
if (VCWD_STAT(filename, pbuf) != 0) {
return 0;
return FAILURE;
}
goto stat_done;
}
@@ -718,48 +780,48 @@ static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_p
}

if (VCWD_STAT(filename, pbuf) != 0) {
return 0;
return FAILURE;
}
goto stat_done;
}
not_relative_path:

/* use include_path */
if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {
return 0;
if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != SUCCESS) {
return FAILURE;
}

/* fall */

stat_done:
if (XG(request_time) - pbuf->st_mtime < 2 && !xc_test) {
return 0;
return FAILURE;
}

php->mtime = pbuf->st_mtime;
xce->mtime = pbuf->st_mtime;
#ifdef HAVE_INODE
php->device = pbuf->st_dev;
php->inode = pbuf->st_ino;
xce->device = pbuf->st_dev;
xce->inode = pbuf->st_ino;
#endif
php->sourcesize = pbuf->st_size;
}
else { /* XG(inode) */
php->mtime = 0;
xce->mtime = 0;
#ifdef HAVE_INODE
php->device = 0;
php->inode = 0;
xce->device = 0;
xce->inode = 0;
#endif
php->sourcesize = 0;
}

#ifdef HAVE_INODE
if (!php->inode)
if (!xce->inode)
#endif
{
/* hash on filename, let's expand it to real path */
filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
if (filename == NULL) {
return 0;
return FAILURE;
}
}

@@ -774,7 +836,51 @@ stat_done:
xce->hvalue = (hv & xc_php_hentry.mask);

xce->type = XC_TYPE_PHP;
return 1;
return SUCCESS;
}
/* }}} */
static inline xc_hash_value_t xc_php_hash_md5(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
{
return HASH_STR_S(php->md5, sizeof(php->md5));
}
/* }}} */
static int xc_entry_init_key_php_md5(xc_entry_data_php_t *php, xc_entry_t *xce TSRMLS_DC) /* {{{ */
{
unsigned char buf[1024];
PHP_MD5_CTX context;
int n;
php_stream *stream;
xc_hash_value_t hv;

stream = php_stream_open_wrapper(xce->name.str.val, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL);
if (!stream) {
return FAILURE;
}

PHP_MD5Init(&context);
while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) {
PHP_MD5Update(&context, buf, n);
}
PHP_MD5Final((unsigned char *) php->md5, &context);

php_stream_close(stream);

if (n < 0) {
return FAILURE;
}

hv = xc_php_hash_md5(php TSRMLS_CC);
php->cache = xce->cache;
php->hvalue = (hv & php->cache->hphp->mask);
#ifdef DEBUG
{
char md5str[33];
make_digest(md5str, (unsigned char *) php->md5);
TRACE("md5 %s", md5str);
}
#endif

return SUCCESS;
}
/* }}} */
static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
@@ -804,100 +910,34 @@ static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void
}
}
/* }}} */
static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
{
#define X_FREE(var) do {\
if (php->var) { \
efree(php->var); \
} \
} while (0)

#ifdef ZEND_ENGINE_2_1
X_FREE(autoglobals);
#endif
X_FREE(classinfos);
X_FREE(funcinfos);
#ifdef HAVE_XCACHE_CONSTANT
X_FREE(constinfos);
#endif
#undef X_FREE
}
/* }}} */
static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
{
xc_sandbox_t sandbox;
zend_op_array *op_array;
xc_entry_t xce, *stored_xce;
xc_entry_data_php_t php;
xc_cache_t *cache;
zend_bool clogged = 0;
zend_bool catched = 0;
char *filename;
char opened_path_buffer[MAXPATHLEN];
int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
int i;

if (!xc_initized) {
assert(0);
}

if (!XG(cacher)) {
op_array = origin_compile_file(h, type TSRMLS_CC);
#ifdef HAVE_XCACHE_OPTIMIZER
if (XG(optimizer)) {
xc_optimize(op_array TSRMLS_CC);
}
#endif
return op_array;
}

/* {{{ prepare key
* include_once() and require_once() gives us opened_path
* however, include() and require() non-absolute path which break
* included_files, and may confuse with (include|require)_once
* -- Xuefer
*/

filename = h->opened_path ? h->opened_path : h->filename;
xce.data.php = &php;
if (!xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC)) {
return origin_compile_file(h, type TSRMLS_CC);
}
cache = xce.cache;
/* }}} */
/* {{{ restore */
/* stale precheck */
if (cache->compiling) {
cache->clogs ++; /* is it safe here? */
return origin_compile_file(h, type TSRMLS_CC);
}

stored_xce = NULL;
op_array = NULL;
ENTER_LOCK_EX(cache) {
/* clogged */
if (cache->compiling) {
cache->clogs ++;
op_array = NULL;
clogged = 1;
break;
}

stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
/* found */
if (stored_xce) {
TRACE("found %s, catch it", stored_xce->name.str.val);
xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
cache->hits ++;
break;
}

cache->compiling = XG(request_time);
cache->misses ++;
} LEAVE_LOCK_EX(cache);

if (catched) {
cache->compiling = 0;
zend_bailout();
}

/* found */
if (stored_xce) {
goto restore;
}

/* clogged */
if (clogged) {
return origin_compile_file(h, type TSRMLS_CC);
}
/* }}} */
zend_bool catched = 0;

/* {{{ compile */
TRACE("compiling %s", filename);

/* make compile inside sandbox */
xc_sandbox_init(&sandbox, filename TSRMLS_CC);
TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename);

old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
old_funcinfo_cnt = zend_hash_num_elements(CG(function_table));
@@ -914,23 +954,9 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /
}

if (op_array == NULL) {
goto err_oparray;
goto err_op_array;
}

filename = h->opened_path ? h->opened_path : h->filename;
/* none-inode enabled entry hash/compare on name
* do not update to its name to real pathname
*/
#ifdef HAVE_INODE
if (xce.data.php->inode)
{
if (xce.name.str.val != filename) {
xce.name.str.val = filename;
xce.name.str.len = strlen(filename);
}
}
#endif

#ifdef HAVE_XCACHE_OPTIMIZER
if (XG(optimizer)) {
xc_optimize(op_array TSRMLS_CC);
@@ -938,23 +964,23 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /
#endif
/* }}} */
/* {{{ prepare */
php.op_array = op_array;
php->op_array = op_array;

#ifdef HAVE_XCACHE_CONSTANT
php.constinfo_cnt = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
php->constinfo_cnt = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
#endif
php.funcinfo_cnt = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
php.classinfo_cnt = zend_hash_num_elements(CG(class_table)) - old_classinfo_cnt;
php->funcinfo_cnt = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
php->classinfo_cnt = zend_hash_num_elements(CG(class_table)) - old_classinfo_cnt;
#ifdef ZEND_ENGINE_2_1
/* {{{ count php.autoglobal_cnt */ {
/* {{{ count php->autoglobal_cnt */ {
Bucket *b;

php.autoglobal_cnt = 0;
php->autoglobal_cnt = 0;
for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
zend_auto_global *auto_global = (zend_auto_global *) b->pData;
/* check if actived */
if (auto_global->auto_global_callback && !auto_global->armed) {
php.autoglobal_cnt ++;
php->autoglobal_cnt ++;
}
}
}
@@ -962,14 +988,14 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /
#endif

#define X_ALLOC_N(var, cnt) do { \
if (php.cnt) { \
ECALLOC_N(php.var, php.cnt); \
if (!php.var) { \
goto err_##var; \
if (php->cnt) { \
ECALLOC_N(php->var, php->cnt); \
if (!php->var) { \
goto err_alloc; \
} \
} \
else { \
php.var = NULL; \
php->var = NULL; \
} \
} while (0)

@@ -989,18 +1015,18 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /

#define COPY_H(vartype, var, cnt, name, datatype) do { \
for (i = 0; b; i ++, b = b->pListNext) { \
vartype *data = &php.var[i]; \
vartype *data = &php->var[i]; \
\
if (i < old_##cnt) { \
continue; \
} \
\
assert(i < old_##cnt + php.cnt); \
assert(i < old_##cnt + php->cnt); \
assert(b->pData); \
memcpy(&data->name, b->pData, sizeof(datatype)); \
UNISW(NOTHING, data->type = b->key.type;) \
if (UNISW(1, b->key.type == IS_STRING)) { \
ZSTR_S(data->key) = BUCKET_KEY_S(b); \
ZSTR_S(data->key) = BUCKET_KEY_S(b); \
} \
else { \
ZSTR_U(data->key) = BUCKET_KEY_U(b); \
@@ -1026,9 +1052,9 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /
zend_auto_global *auto_global = (zend_auto_global *) b->pData;
/* check if actived */
if (auto_global->auto_global_callback && !auto_global->armed) {
xc_autoglobal_t *data = &php.autoglobals[i];
xc_autoglobal_t *data = &php->autoglobals[i];

assert(i < php.autoglobal_cnt);
assert(i < php->autoglobal_cnt);
i ++;
UNISW(NOTHING, data->type = b->key.type;)
if (UNISW(1, b->key.type == IS_STRING)) {
@@ -1044,80 +1070,45 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /
}
/* }}} */
/* {{{ find inherited classes that should be early-binding */
php.have_early_binding = 0;
for (i = 0; i < php.classinfo_cnt; i ++) {
php.classinfos[i].oplineno = -1;
php->have_early_binding = 0;
for (i = 0; i < php->classinfo_cnt; i ++) {
php->classinfos[i].oplineno = -1;
}

xc_undo_pass_two(php.op_array TSRMLS_CC);
xc_foreach_early_binding_class(php.op_array, xc_cache_early_binding_class_cb, (void *) &php TSRMLS_CC);
xc_redo_pass_two(php.op_array TSRMLS_CC);
/* }}} */
#ifdef SHOW_DPRINT
xc_dprint(&xce, 0 TSRMLS_CC);
#endif
ENTER_LOCK_EX(cache) { /* {{{ store/add entry */
stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
} LEAVE_LOCK_EX(cache);
xc_undo_pass_two(php->op_array TSRMLS_CC);
xc_foreach_early_binding_class(php->op_array, xc_cache_early_binding_class_cb, (void *) &php TSRMLS_CC);
xc_redo_pass_two(php->op_array TSRMLS_CC);
/* }}} */
TRACE("%s", "stored");

#define X_FREE(var) \
if (xce.data.php->var) { \
efree(xce.data.php->var); \
} \
err_##var:
return op_array;

#ifdef ZEND_ENGINE_2_1
X_FREE(autoglobals)
#endif
X_FREE(classinfos)
X_FREE(funcinfos)
#ifdef HAVE_XCACHE_CONSTANT
X_FREE(constinfos)
#endif
#undef X_FREE
err_alloc:
xc_free_php(php TSRMLS_CC);

err_oparray:
err_bailout:
err_op_array:

if (xc_test && stored_xce) {
/* free it, no install. restore now */
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
}
else if (!op_array) {
/* failed to compile free it, no install */
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
}
else {
CG(active_op_array) = op_array;
xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
}

ENTER_LOCK(cache) {
cache->compiling = 0;
} LEAVE_LOCK(cache);
if (catched) {
zend_bailout();
}
if (xc_test && stored_xce) {
#ifdef ZEND_ENGINE_2
destroy_op_array(op_array TSRMLS_CC);
#else
destroy_op_array(op_array);
#endif
efree(op_array);
h = NULL;
goto restore;
}

return op_array;
}
/* }}} */
static zend_op_array *xc_compile_restore(xc_entry_t *stored_xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
{
zend_op_array *op_array;
xc_entry_t xce;
xc_entry_data_php_t php;
zend_bool catched;

restore:
CG(in_compilation) = 1;
CG(compiled_filename) = stored_xce->name.str.val;
CG(zend_lineno) = 0;
TRACE("restoring %s", stored_xce->name.str.val);
xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
xc_processor_restore_xc_entry_t(&xce, stored_xce TSRMLS_CC);
xc_processor_restore_xc_entry_data_php_t(&php, xce.data.php, xc_readonly_protection TSRMLS_CC);
xce.data.php = &php;
#ifdef SHOW_DPRINT
xc_dprint(&xce, 0 TSRMLS_CC);
#endif
@@ -1129,20 +1120,7 @@ restore:
catched = 1;
} zend_end_try();

#define X_FREE(var) \
if (xce.data.php->var) { \
efree(xce.data.php->var); \
}
#ifdef ZEND_ENGINE_2_1
X_FREE(autoglobals)
#endif
X_FREE(classinfos)
X_FREE(funcinfos)
#ifdef HAVE_XCACHE_CONSTANT
X_FREE(constinfos)
#endif
#undef X_FREE
efree(xce.data.php);
xc_free_php(&php TSRMLS_CC);

if (catched) {
zend_bailout();
@@ -1153,6 +1131,189 @@ restore:
return op_array;
}
/* }}} */
static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
{
zend_op_array *op_array;
xc_entry_t xce, *stored_xce;
xc_entry_data_php_t php, *stored_php;
xc_cache_t *cache;
zend_bool gaveup = 0;
zend_bool catched = 0;
zend_bool cached_php;
char *filename;
char opened_path_buffer[MAXPATHLEN];
xc_sandbox_t sandbox;

assert(xc_initized);

if (!XG(cacher)) {
op_array = origin_compile_file(h, type TSRMLS_CC);
#ifdef HAVE_XCACHE_OPTIMIZER
if (XG(optimizer)) {
xc_optimize(op_array TSRMLS_CC);
}
#endif
return op_array;
}

/* {{{ entry_init_key */
filename = h->opened_path ? h->opened_path : h->filename;
xce.data.php = &php;
if (xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC) != SUCCESS) {
return origin_compile_file(h, type TSRMLS_CC);
}
cache = xce.cache;
/* }}} */

/* stale clogs precheck */
if (cache->compiling) {
cache->clogs ++;
return origin_compile_file(h, type TSRMLS_CC);
}
/* {{{ entry_lookup/hit/md5_init/php_lookup */
stored_xce = NULL;
stored_php = NULL;
ENTER_LOCK_EX(cache) {
stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
if (stored_xce) {
cache->hits ++;

TRACE("hit %s, holding", stored_xce->name.str.val);
xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
}
else {
cache->misses ++;
TRACE("miss %s", xce.name.str.val);

if (xc_entry_init_key_php_md5(&php, &xce TSRMLS_CC) != SUCCESS) {
gaveup = 1;
break;
}

stored_php = xc_php_find_dmz(&php TSRMLS_CC);

/* miss but compiling */
if (!stored_php) {
if (cache->compiling) {
TRACE("%s", "miss but compiling");
cache->clogs ++;
gaveup = 1;
break;
}
TRACE("%s", "php_lookup miss");
}
else {
TRACE("%s", "php_lookup hit");
}

cache->compiling = XG(request_time);
}
} LEAVE_LOCK_EX(cache);

if (catched) {
cache->compiling = 0;
zend_bailout();
}

/* hit */
if (stored_xce) {
return xc_compile_restore(stored_xce, h TSRMLS_CC);
}

/* gaveup */
if (gaveup) {
return origin_compile_file(h, type TSRMLS_CC);
}
/* }}} */
op_array = NULL;
/* {{{ compile */
if (stored_php) {
cached_php = 1;
xce.data.php = stored_php;
}
else {
cached_php = 0;

/* make compile inside sandbox */
xc_sandbox_init(&sandbox, filename TSRMLS_CC);
zend_try {
op_array = xc_compile_php(&php, h, type TSRMLS_CC);
} zend_catch {
catched = 1;
} zend_end_try();
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);

if (catched) {
cache->compiling = 0;
zend_bailout();
}

xce.data.php = &php;
}
/* }}} */
#ifdef HAVE_INODE
/* {{{ path name fix
* inode enabled entry hash/compare on name
* do not update to its name to real pathname
* WARNING: this code is required to be after compile
*/
if (xce.inode) {
filename = h->opened_path ? h->opened_path : h->filename;
if (xce.name.str.val != filename) {
xce.name.str.val = filename;
xce.name.str.len = strlen(filename);
}
}
/* }}} */
#endif
#ifdef SHOW_DPRINT
xc_dprint(&xce, 0 TSRMLS_CC);
#endif
stored_xce = NULL;
ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */
/* php_store */
if (!cached_php) {
stored_php = xc_php_store_dmz(&php TSRMLS_CC);
/* error */
if (!stored_php) {
break;
}
}
/* entry_store */
stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
if (stored_xce) {
stored_xce->data.php = stored_php;
stored_php->refcount ++;
}
else {
/* error */
xc_php_remove_dmz(stored_php);
stored_php = NULL;
}
} LEAVE_LOCK_EX(cache);
/* }}} */
TRACE("%s", stored_xce ? "stored" : "store failed");

cache->compiling = 0;
if (catched) {
zend_bailout();
}

if (stored_xce) {
if (op_array) {
#ifdef ZEND_ENGINE_2
destroy_op_array(op_array TSRMLS_CC);
#else
destroy_op_array(op_array);
#endif
efree(op_array);
h = NULL;
}
return xc_compile_restore(stored_xce, h TSRMLS_CC);
}
return op_array;
}
/* }}} */

/* gdb helper functions, but N/A for coredump */
int xc_is_rw(const void *p) /* {{{ */
@@ -1278,7 +1439,7 @@ static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{
return shm;
}
/* }}} */
static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_hash_t *hphp, xc_shmsize_t shmsize) /* {{{ */
{
xc_cache_t **caches = NULL, *cache;
xc_mem_t *mem;
@@ -1305,10 +1466,14 @@ static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *h
CHECK(mem = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
CHECK(cache = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
if (hphp) {
CHECK(cache->phps= mem->handlers->calloc(mem, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");
}
CHECK(cache->lck = xc_lock_init(NULL), "can't create lock");

cache->hcache = hcache;
cache->hentry = hentry;
cache->hphp = hphp;
cache->shm = shm;
cache->mem = mem;
cache->cacheid = i;
@@ -1363,11 +1528,11 @@ static int xc_init(int module_number TSRMLS_DC) /* {{{ */
origin_compile_file = zend_compile_file;
zend_compile_file = xc_compile_file;

CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, &xc_php_hentry, xc_php_size), "failed init opcode cache");
}

if (xc_var_size) {
CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");
}
}
return 1;
@@ -1714,7 +1879,7 @@ PHP_FUNCTION(xcache_get)
stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
if (stored_xce) {
if (!VAR_ENTRY_EXPIRED(stored_xce)) {
xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
/* return */
break;
}
@@ -1863,7 +2028,7 @@ static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{
}
else {
TRACE("%s", "incdec: notlong");
xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
convert_to_long(&oldzval);
value = Z_LVAL(oldzval);
zval_dtor(&oldzval);


+ 28
- 11
xcache.h View File

@@ -164,8 +164,9 @@ typedef ZESW(zend_class_entry, zend_class_entry*) xc_cest_t;

typedef zend_op_array *(zend_compile_file_t)(zend_file_handle *h, int type TSRMLS_DC);

/* {{{ xc_cache_t */
typedef struct _xc_entry_t xc_entry_t;
typedef struct _xc_entry_data_php_t xc_entry_data_php_t;
/* {{{ xc_cache_t */
typedef struct {
int cacheid;
xc_hash_t *hcache; /* hash to cacheid */
@@ -181,9 +182,12 @@ typedef struct {

xc_entry_t **entries;
int entries_count;
xc_entry_data_php_t **phps;
int phps_count;
xc_entry_t *deletes;
int deletes_count;
xc_hash_t *hentry; /* hash to entry */
xc_hash_t *hentry; /* hash settings to entry */
xc_hash_t *hphp; /* hash settings to php */

time_t last_gc_deletes;
time_t last_gc_expires;
@@ -234,14 +238,19 @@ typedef struct {
/* }}} */
#endif
typedef enum { XC_TYPE_PHP, XC_TYPE_VAR } xc_entry_type_t;
typedef char xc_md5sum_t[16];
/* {{{ xc_entry_data_php_t */
typedef struct {
struct _xc_entry_data_php_t {
xc_hash_value_t hvalue; /* hash of md5 */
xc_entry_data_php_t *next;
xc_cache_t *cache; /* which cache it's on */

xc_md5sum_t md5; /* md5sum of the source */
zend_ulong refcount; /* count of entries referencing to this data */

size_t sourcesize;
#ifdef HAVE_INODE
int device; /* the filesystem device */
int inode; /* the filesystem inode */
#endif
time_t mtime; /* the mtime of origin source file */
zend_ulong hits; /* hits of this php */
size_t size;

zend_op_array *op_array;

@@ -261,11 +270,15 @@ typedef struct {
zend_uint autoglobal_cnt;
xc_autoglobal_t *autoglobals;
#endif
} xc_entry_data_php_t;

zend_bool have_references;
};
/* }}} */
/* {{{ xc_entry_data_var_t */
typedef struct {
zval *value;

zend_bool have_references;
} xc_entry_data_var_t;
/* }}} */
typedef zvalue_value xc_entry_name_t;
@@ -277,7 +290,7 @@ struct _xc_entry_t {
xc_cache_t *cache; /* which cache it's on */

size_t size;
zend_ulong refcount;
zend_ulong refcount; /* count of instances holding this entry */
zend_ulong hits;
time_t ctime; /* the ctime of this entry */
time_t atime; /* the atime of this entry */
@@ -294,7 +307,11 @@ struct _xc_entry_t {
xc_entry_data_var_t *var;
} data;

zend_bool have_references;
time_t mtime; /* the mtime of origin source file */
#ifdef HAVE_INODE
int device; /* the filesystem device */
int inode; /* the filesystem inode */
#endif
};
/* }}} */



Loading…
Cancel
Save