root/eaccelerator/branches/new-cache/cache.c

Revision 335, 20.6 kB (checked in by bart, 1 year ago)

Branch trunk for new caching code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 - 2007 eAccelerator                               |
6    | http://eaccelerator.net                                              |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    $Id$
26 */
27
28 #include "eaccelerator.h"
29 #include "eaccelerator_version.h"
30
31 #ifdef HAVE_EACCELERATOR
32
33 #include "zend.h"
34 #include "zend_API.h"
35 #include "zend_extensions.h"
36 #include "ea_store.h"
37 #include "ea_restore.h"
38
39 #include <fcntl.h>
40
41 #ifndef O_BINARY
42 #  define O_BINARY 0
43 #endif
44
45 /* variables needed from eaccelerator.c */
46 extern long ea_shm_max;
47 extern eaccelerator_mm *eaccelerator_mm_instance;
48 extern int binary_eaccelerator_version;
49 extern int binary_php_version;
50 extern int binary_zend_version;
51
52 #if defined(WITH_EACCELERATOR_CONTENT_CACHING) || defined(WITH_EACCELERATOR_SESSIONS) || defined(WITH_EACCELERATOR_SHM)
53
54 static char *build_key(const char *key, int key_len, int *xlen TSRMLS_DC)
55 {
56     int len;
57
58     /*
59      * namespace
60      */
61     len = strlen(EAG(name_space));
62     if (len > 0) {
63         char *xkey;
64         *xlen = len + key_len + 1;
65         xkey = emalloc((*xlen) + 1);
66         memcpy(xkey, EAG(name_space), len);
67         xkey[len] = ':';
68         memcpy(xkey + len + 1, key, key_len + 1);
69         return xkey;
70     }
71
72     /*
73      * hostname
74      */
75     len = strlen(EAG(hostname));
76     if (len > 0) {
77         char *xkey;
78         *xlen = len + key_len + 1;
79         xkey = emalloc((*xlen) + 1);
80         memcpy(xkey, EAG(hostname), len);
81         xkey[len] = ':';
82         memcpy(xkey + len + 1, key, key_len + 1);
83         return xkey;
84     } else {
85         *xlen = key_len;
86         return (char *) key;
87     }
88 }
89
90 /* lock the key cache */
91 int eaccelerator_lock(const char *key, int key_len TSRMLS_DC)
92 {
93     int xlen;
94     char *xkey;
95     ea_lock_entry *x;
96     ea_lock_entry **p;
97     int ok = 0;
98
99     if (eaccelerator_mm_instance == NULL)
100         return 0;
101
102     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
103     EACCELERATOR_UNPROTECT();
104     x = eaccelerator_malloc(offsetof(ea_lock_entry, key) + xlen + 1);
105     if (x == NULL) {
106         EACCELERATOR_PROTECT();
107         if (xlen != key_len)
108             efree(xkey);
109
110         return 0;
111     }
112     x->pid = getpid();
113 #ifdef ZTS
114     x->thread = tsrm_thread_id();
115 #endif
116     x->next = NULL;
117     memcpy(x->key, xkey, xlen + 1);
118     while (1) {
119         EACCELERATOR_LOCK_RW();
120         p = &eaccelerator_mm_instance->locks;
121         while ((*p) != NULL) {
122             if (strcmp((*p)->key, x->key) == 0) {
123 #ifdef ZTS
124                 if (x->pid ==(*p)->pid && x->thread == (*p)->thread) {
125 #else
126                 if (x->pid ==(*p)->pid) {
127 #endif
128                     ok = 1;
129                     eaccelerator_free_nolock(x);
130                 }
131                 break;
132             }
133             p = &(*p)->next;
134         }
135         if ((*p) == NULL) {
136             *p = x;
137             ok = 1;
138         }
139         EACCELERATOR_UNLOCK_RW();
140         if (ok) {
141             break;
142         } else {
143 #ifdef ZEND_WIN32
144             Sleep(100);
145 #else
146             struct timeval t;
147             t.tv_sec = 0;
148             t.tv_usec = 100;
149             select(0, NULL, NULL, NULL, &t);
150 #endif
151         }
152     }
153     EACCELERATOR_PROTECT();
154     if (xlen != key_len)
155         efree(xkey);
156
157     return 1;
158 }
159
160 /* unlock to key cache */
161 int eaccelerator_unlock(const char *key, int key_len TSRMLS_DC)
162 {
163     int xlen;
164     char *xkey;
165     ea_lock_entry **p;
166
167     if (eaccelerator_mm_instance == NULL)
168         return 0;
169
170     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
171     EACCELERATOR_UNPROTECT();
172     EACCELERATOR_LOCK_RW();
173     p = &eaccelerator_mm_instance->locks;
174     while ((*p) != NULL) {
175         if (strcmp((*p)->key, xkey) == 0) {
176 #ifdef ZTS
177             if ((*p)->pid == getpid() && (*p)->thread == tsrm_thread_id()) {
178 #else
179             if ((*p)->pid == getpid()) {
180 #endif
181                 ea_lock_entry *x = (*p);
182                 *p = (*p)->next;
183                 eaccelerator_free_nolock(x);
184             } else {
185                 EACCELERATOR_UNLOCK_RW();
186                 EACCELERATOR_PROTECT();
187                 if (xlen != key_len)
188                     efree(xkey);
189
190                 return 0;
191             }
192             break;
193         }
194         p = &(*p)->next;
195     }
196     EACCELERATOR_UNLOCK_RW();
197     EACCELERATOR_PROTECT();
198     if (xlen != key_len)
199         efree(xkey);
200
201     return 1;
202 }
203
204 /* put a key in the cache (shm or disk) */
205 int eaccelerator_put(const char *key, int key_len, zval * val, time_t ttl, ea_cache_place where TSRMLS_DC)
206 {
207     ea_user_cache_entry *p, *q;
208     unsigned int slot, hv;
209     long size;
210     int use_shm = 1;
211     int ret = 0;
212     char s[MAXPATHLEN];
213     int xlen;
214     char *xkey;
215
216     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
217     EAG(compress) = 1;
218     EAG(mem) = NULL;
219     zend_hash_init(&EAG(strings), 0, NULL, NULL, 0);
220     EACCELERATOR_ALIGN(EAG(mem));
221     size = offsetof(ea_user_cache_entry, key) + xlen + 1;
222     size += calc_zval(val TSRMLS_CC);
223     zend_hash_destroy(&EAG(strings));
224
225     EAG(mem) = NULL;
226     if (eaccelerator_mm_instance != NULL && (where == ea_shm_and_disk || where == ea_shm || where == ea_shm_only)) {
227         EACCELERATOR_UNPROTECT();
228         if (ea_shm_max == 0 || size <= ea_shm_max) {
229             EAG(mem) = eaccelerator_malloc(size);
230             if (EAG(mem) == NULL) {
231                 EAG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
232             }
233         }
234         if (EAG(mem) == NULL) {
235             EACCELERATOR_PROTECT();
236         }
237     }
238     if (EAG(mem) == NULL && (where == ea_shm_and_disk || where == ea_shm || where == ea_disk_only)) {
239         use_shm = 0;
240         EAG(mem) = emalloc(size);
241     }
242     if (EAG(mem)) {
243         zend_hash_init(&EAG(strings), 0, NULL, NULL, 0);
244         EACCELERATOR_ALIGN(EAG(mem));
245         q = (ea_user_cache_entry *) EAG(mem);
246         q->size = size;
247         EAG(mem) += offsetof(ea_user_cache_entry, key) + xlen + 1;
248         q->hv = zend_get_hash_value(xkey, xlen);
249         memcpy(q->key, xkey, xlen + 1);
250         memcpy(&q->value, val, sizeof(zval));
251         q->ttl = ttl ? EAG(req_start) + ttl : 0;
252         q->create = EAG(req_start);
253         /* set the refcount to 1 */
254         q->value.refcount = 1;
255         store_zval(&EAG(mem), &q->value TSRMLS_CC);
256         zend_hash_destroy(&EAG(strings));
257
258         /*
259          * storing to file
260          */
261         if ((where == ea_shm_and_disk || ((where == ea_shm) && !use_shm) || where == ea_disk_only) &&
262                         eaccelerator_md5(s, "/eaccelerator-user-", q->key TSRMLS_CC)) {
263             int f;
264             unlink(s);
265             f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
266             if (f > 0) {
267                 ea_file_header hdr;
268                 EACCELERATOR_FLOCK(f, LOCK_EX);
269                 init_header(&hdr);
270                 hdr.size = q->size;
271                 hdr.mtime = q->ttl;
272                 q->next = q;
273                 hdr.crc32 = eaccelerator_crc32((const char *) q, q->size);
274                 if (write(f, &hdr, sizeof(hdr)) == sizeof(hdr)) {
275                     ssize_t result = 0;
276                     result = write(f, q, q->size);
277                     EACCELERATOR_FLOCK(f, LOCK_UN);
278                     close(f);
279                     ret = 1;
280                 } else {
281                     EACCELERATOR_FLOCK(f, LOCK_UN);
282                     close(f);
283                     unlink(s);
284                 }
285             }
286             if (!use_shm)
287                 efree(q);
288         }
289
290         if ((where == ea_shm_and_disk || where == ea_shm || where == ea_shm_only) && use_shm) {
291             /*
292              * storing to shared memory
293              */
294             slot = q->hv & EA_USER_HASH_MAX;
295             hv = q->hv;
296             EACCELERATOR_LOCK_RW();
297             eaccelerator_mm_instance->user_hash_cnt++;
298             q->next = eaccelerator_mm_instance->user_hash[slot];
299             eaccelerator_mm_instance->user_hash[slot] = q;
300             p = q->next;
301             while (p != NULL) {
302                 if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
303                     eaccelerator_mm_instance->user_hash_cnt--;
304                     q->next = p->next;
305                     eaccelerator_free_nolock(p);
306                     break;
307                 }
308                 q = p;
309                 p = p->next;
310             }
311             EACCELERATOR_UNLOCK_RW();
312             EACCELERATOR_PROTECT();
313             ret = 1;
314         }
315     }
316     if (xlen != key_len)
317         efree(xkey);
318
319     return ret;
320 }
321
322 /* get a key from the cache */
323 int eaccelerator_get(const char *key, int key_len, zval * return_value, ea_cache_place where TSRMLS_DC)
324 {
325     unsigned int hv, slot;
326     char s[MAXPATHLEN];
327     int xlen;
328     char *xkey;
329
330     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
331     hv = zend_get_hash_value(xkey, xlen);
332     slot = hv & EA_USER_HASH_MAX;
333
334     if (eaccelerator_mm_instance != NULL && (where == ea_shm_and_disk || where == ea_shm || where == ea_shm_only)) {
335         ea_user_cache_entry *p, *q;
336         ea_user_cache_entry *x = NULL;
337         EACCELERATOR_UNPROTECT();
338         EACCELERATOR_LOCK_RW();
339         q = NULL;
340         p = eaccelerator_mm_instance->user_hash[slot];
341         while (p != NULL) {
342             if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
343                 x = p;
344                 if (p->ttl != 0 && p->ttl < EAG(req_start)) {
345                     if (q == NULL) {
346                         eaccelerator_mm_instance->user_hash[slot] = p->next;
347                     } else {
348                         q->next = p->next;
349                     }
350                     eaccelerator_mm_instance->user_hash_cnt--;
351                     eaccelerator_free_nolock(x);
352                     x = NULL;
353                 }
354                 break;
355             }
356             q = p;
357             p = p->next;
358         }
359         EACCELERATOR_UNLOCK_RW();
360         EACCELERATOR_PROTECT();
361         if (x) {
362             memcpy(return_value, &x->value, sizeof(zval));
363             restore_zval(return_value TSRMLS_CC);
364             if (xlen != key_len) {
365                 efree(xkey);
366             }
367             return 1;
368         }
369     }
370
371     /*
372      * key is not found in shared memory try to load it from file
373      */
374     if ((where == ea_shm_and_disk || where == ea_shm || where == ea_disk_only) &&
375             eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
376         int use_shm = 1;
377         int ret = 0;
378         int f;
379
380         if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
381             ea_file_header hdr;
382
383             EACCELERATOR_FLOCK(f, LOCK_SH);
384             if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr) || !check_header(&hdr)) {
385                 EACCELERATOR_FLOCK(f, LOCK_UN);
386                 close(f);
387                 unlink(s);
388                 if (xlen != key_len)
389                     efree(xkey);
390                 return 0;
391             }
392             if (hdr.mtime == 0 || hdr.mtime > EAG(req_start)) {
393                 /*
394                  * try to put it into shared memory
395                  */
396                 ea_user_cache_entry *p = NULL;
397                 if (eaccelerator_mm_instance != NULL && (where == ea_shm_and_disk || where == ea_shm)) {
398                     if (ea_shm_max == 0 || hdr.size <= ea_shm_max) {
399                         EACCELERATOR_UNPROTECT();
400                         p = eaccelerator_malloc(hdr.size);
401                         if (p == NULL) {
402                             p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
403                         }
404                         if (p == NULL) {
405                             EACCELERATOR_PROTECT();
406                         }
407                     }
408                 }
409                 if (p == NULL) {
410                     p = emalloc(hdr.size);
411                     use_shm = 0;
412                 }
413                 if (p != NULL) {
414                     if (read(f, p, hdr.size) == hdr.size && hdr.size == p->size
415                             && hdr.crc32 == eaccelerator_crc32((const char *) p, p->size)) {
416                         EAG(mem) = (char *) ((long) p - (long) p->next);
417                         EAG(compress) = 1;
418                         fixup_zval(((char *) ((long) p - (long) p->next)), &p->value TSRMLS_CC);
419
420                         if (strcmp(xkey, p->key) != 0) {
421                             if (use_shm) {
422                                 eaccelerator_free(p);
423                             } else {
424                                 efree(p);
425                             }
426                             EACCELERATOR_FLOCK(f, LOCK_UN);
427                             close(f);
428                             unlink(s);
429                             if (use_shm) {
430                                 EACCELERATOR_PROTECT();
431                             }
432                             if (xlen != key_len) {
433                                 efree(xkey);
434                             }
435                             return 0;
436                         }
437
438                         memcpy(return_value, &p->value, sizeof(zval));
439                         restore_zval(return_value TSRMLS_CC);
440                         ret = 1;
441                         if (use_shm) {
442                             /* put it into shared memory */
443                             ea_user_cache_entry *q, *prev;
444
445                             p->hv = hv;
446                             EACCELERATOR_LOCK_RW();
447                             p->next = eaccelerator_mm_instance->user_hash[slot];
448                             eaccelerator_mm_instance->user_hash[slot] = p;
449                             eaccelerator_mm_instance->user_hash_cnt++;
450                             prev = p;
451                             q = p->next;
452                             while (q != NULL) {
453                                 if ((q->hv == hv) && (strcmp(q->key, xkey) == 0)) {
454                                     prev->next = q->next;
455                                     eaccelerator_mm_instance->user_hash_cnt--;
456                                     eaccelerator_free_nolock(q);
457                                     break;
458                                 }
459                                 prev = q;
460                                 q = q->next;
461                             }
462                             EACCELERATOR_UNLOCK_RW();
463                         } else {
464                             efree(p);
465                         }
466                         EACCELERATOR_FLOCK(f, LOCK_UN);
467                         close(f);
468                     } else {
469                         if (use_shm) {
470                             eaccelerator_free(p);
471                         } else {
472                             efree(p);
473                         }
474                         EACCELERATOR_FLOCK(f, LOCK_UN);
475                         close(f);
476                         unlink(s);
477                     }
478                 }
479                 if (use_shm)
480                     EACCELERATOR_PROTECT();
481             } else {
482                 EACCELERATOR_FLOCK(f, LOCK_UN);
483                 close(f);
484                 unlink(s);
485             }
486             if (xlen != key_len) {
487                 efree(xkey);
488             }
489             return ret;
490         }
491     }
492     if (xlen != key_len) {
493         efree(xkey);
494     }
495     return 0;
496 }
497
498 /* remove a key from the cache */
499 int eaccelerator_rm(const char *key, int key_len, ea_cache_place where TSRMLS_DC)
500 {
501     unsigned int hv, slot;
502     ea_user_cache_entry *p, *q;
503     char s[MAXPATHLEN];
504     int xlen;
505     char *xkey;
506
507     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
508     /*
509      * removing file
510      */
511     if ((where == ea_shm_and_disk || where == ea_shm || where == ea_disk_only) &&
512                 eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
513         unlink(s);
514     }
515
516     /*
517      * removing from shared memory
518      */
519     if (eaccelerator_mm_instance != NULL && (where == ea_shm_and_disk ||
520                 where == ea_shm || where == ea_shm_only)) {
521         hv = zend_get_hash_value(xkey, xlen);
522         slot = hv & EA_USER_HASH_MAX;
523
524         EACCELERATOR_UNPROTECT();
525         EACCELERATOR_LOCK_RW();
526         q = NULL;
527         p = eaccelerator_mm_instance->user_hash[slot];
528         while (p != NULL) {
529             if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
530                 if (q == NULL) {
531                     eaccelerator_mm_instance->user_hash[slot] = p->next;
532                 } else {
533                     q->next = p->next;
534                 }
535                 eaccelerator_mm_instance->user_hash_cnt--;
536                 eaccelerator_free_nolock(p);
537                 break;
538             }
539             q = p;
540             p = p->next;
541         }
542         EACCELERATOR_UNLOCK_RW();
543         EACCELERATOR_PROTECT();
544     }
545     if (xlen != key_len) {
546         efree(xkey);
547     }
548     return 1;
549 }
550
551 /* do garbage collection on the keys */
552 size_t eaccelerator_gc(TSRMLS_D)
553 {
554     size_t size = 0;
555     unsigned int i;
556     time_t t = EAG(req_start);
557
558     if (eaccelerator_mm_instance == NULL) {
559         return 0;
560     }
561     EACCELERATOR_UNPROTECT();
562     EACCELERATOR_LOCK_RW();
563     for (i = 0; i < EA_USER_HASH_SIZE; i++) {
564         ea_user_cache_entry **p = &eaccelerator_mm_instance->user_hash[i];
565         while (*p != NULL) {
566             if ((*p)->ttl != 0 && (*p)->ttl < t) {
567                 ea_user_cache_entry *r = *p;
568                 *p = (*p)->next;
569                 eaccelerator_mm_instance->user_hash_cnt--;
570                 size += r->size;
571                 eaccelerator_free_nolock(r);
572             } else {
573                 p = &(*p)->next;
574             }
575         }
576     }
577     EACCELERATOR_UNLOCK_RW();
578     EACCELERATOR_PROTECT();
579     return size;
580 }
581
582 #ifdef WITH_EACCELERATOR_INFO
583 /* get list of all keys stored in memory that matches hostname or namespace */
584 int eaccelerator_list_keys(zval *return_value TSRMLS_DC)
585 {
586     unsigned int i, xlen;
587     zval *list;
588     char *xkey = "";
589     ea_user_cache_entry *p;
590
591     // create key prefix for current host / namespace
592     xlen = strlen(EAG(name_space));
593     if (xlen > 0) {
594         xkey = emalloc(xlen + 1);
595         memcpy(xkey, EAG(name_space), xlen);
596     } else {
597         xlen = strlen(EAG(hostname));
598         if (xlen > 0) {
599             xkey = emalloc(xlen + 1);
600             memcpy(xkey, EAG(hostname), xlen);
601         }
602     }
603
604     // initialize return value as an array
605     array_init(return_value);
606
607     for (i = 0; i < EA_USER_HASH_SIZE; ++i) {
608         p = eaccelerator_mm_instance->user_hash[i];
609         while(p != NULL) {
610             if (!xlen || strncmp(p->key, xkey, xlen) == 0) {
611                 list = NULL;
612                 ALLOC_INIT_ZVAL(list);
613                 array_init(list);
614                
615                 if (strlen(p->key) > xlen) {
616                     add_assoc_string(list, "name", (p->key) + xlen, 1);
617                 } else {
618                     add_assoc_string(list, "name", p->key, 1);
619                 }
620                
621                 if (p->ttl) {
622                     if (p->ttl > EAG(req_start)) {
623                         add_assoc_long(list, "ttl", p->ttl); // ttl
624                     } else {
625                         add_assoc_long(list, "ttl", -1); // expired
626                     }
627                 } else {
628                     add_assoc_long(list, "ttl", 0); // no ttl
629                 }
630                
631                 add_assoc_long(list, "created", p->create);
632                 add_assoc_long(list, "size", p->size);
633                 add_next_index_zval(return_value, list);
634             }
635             p = p->next;
636         }
637     }
638
639     if (xlen > 0)
640         efree(xkey);
641     return 1;
642 }
643 #endif /* WITH_EACCELERATOR_INFO */
644
645 #endif /* WITH_EACCELERATOR_CONTENT_CACHING) || WITH_EACCELERATOR_SESSIONS || WITH_EACCELERATOR_SHM */
646
647 #endif /* HAVE_EACCELERATOR */
648
Note: See TracBrowser for help on using the browser.