root/eaccelerator/tags/0.9.5/cache.c

Revision 276, 21.2 kB (checked in by bart, 2 years ago)

* Fix a bug in the ttl of the cache. see ticket #182

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