root/eaccelerator/tags/0.9.5-beta2/cache.c

Revision 191, 21.1 kB (checked in by bart, 3 years ago)

* Moved the FLOCK stuff to a place so it can be used by eLoader to
* Fixed quite some compile warnings on Win32
* Updated VC6 project files for Win32

(Note: I feel dirty now, I'm going to take a shower ;-) )

  • 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, "EACCELERATOR", 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                     write(f, q, q->size);
282                     EACCELERATOR_FLOCK(f, LOCK_UN);
283                     close(f);
284                     ret = 1;
285                 } else {
286                     EACCELERATOR_FLOCK(f, LOCK_UN);
287                     close(f);
288                     unlink(s);
289                 }
290             }
291             if (!use_shm)
292                 efree(q);
293         }
294
295         if ((where == eaccelerator_shm_and_disk || where == eaccelerator_shm || where == eaccelerator_shm_only) && use_shm) {
296             /*
297              * storing to shared memory
298              */
299             slot = q->hv & MM_USER_HASH_MAX;
300             hv = q->hv;
301             EACCELERATOR_LOCK_RW();
302             eaccelerator_mm_instance->user_hash_cnt++;
303             q->next = eaccelerator_mm_instance->user_hash[slot];
304             eaccelerator_mm_instance->user_hash[slot] = q;
305             p = q->next;
306             while (p != NULL) {
307                 if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
308                     eaccelerator_mm_instance->user_hash_cnt--;
309                     q->next = p->next;
310                     eaccelerator_free_nolock(p);
311                     break;
312                 }
313                 q = p;
314                 p = p->next;
315             }
316             EACCELERATOR_UNLOCK_RW();
317             EACCELERATOR_PROTECT();
318             ret = 1;
319         }
320     }
321     if (xlen != key_len)
322         efree(xkey);
323
324     return ret;
325 }
326
327 /* get a key from the cache */
328 int eaccelerator_get(const char *key, int key_len, zval * return_value,
329                   eaccelerator_cache_place where TSRMLS_DC)
330 {
331     unsigned int hv, slot;
332     char s[MAXPATHLEN];
333     int xlen;
334     char *xkey;
335
336     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
337     hv = hash_mm(xkey, xlen);
338     slot = hv & MM_USER_HASH_MAX;
339
340     if (eaccelerator_mm_instance != NULL && (where == eaccelerator_shm_and_disk
341                 || where == eaccelerator_shm || where == eaccelerator_shm_only)) {
342         mm_user_cache_entry *p, *q;
343         mm_user_cache_entry *x = NULL;
344         EACCELERATOR_UNPROTECT();
345         EACCELERATOR_LOCK_RW();
346         q = NULL;
347         p = eaccelerator_mm_instance->user_hash[slot];
348         while (p != NULL) {
349             if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
350                 x = p;
351                 if (p->ttl != 0 && p->ttl < time(0)) {
352                     if (q == NULL) {
353                         eaccelerator_mm_instance->user_hash[slot] = p->next;
354                     } else {
355                         q->next = p->next;
356                     }
357                     eaccelerator_mm_instance->user_hash_cnt--;
358                     eaccelerator_free_nolock(x);
359                     x = NULL;
360                 }
361                 break;
362             }
363             q = p;
364             p = p->next;
365         }
366         EACCELERATOR_UNLOCK_RW();
367         EACCELERATOR_PROTECT();
368         if (x) {
369             memcpy(return_value, &x->value, sizeof(zval));
370             restore_zval(return_value TSRMLS_CC);
371             if (xlen != key_len) {
372                 efree(xkey);
373             }
374             return 1;
375         }
376     }
377
378     /*
379      * key is not found in shared memory try to load it from file
380      */
381     if ((where == eaccelerator_shm_and_disk || where == eaccelerator_shm ||
382             where == eaccelerator_disk_only) &&
383             eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
384         time_t t = time(0);
385         int use_shm = 1;
386         int ret = 0;
387         int f;
388
389         if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
390             mm_file_header hdr;
391
392             EACCELERATOR_FLOCK(f, LOCK_SH);
393             if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr) || strncmp(hdr.magic, "EACCELERATOR", 8) != 0 ||
394                     hdr.eaccelerator_version != binary_eaccelerator_version || hdr.zend_version != binary_zend_version
395                     || hdr.php_version != binary_php_version) {
396                 EACCELERATOR_FLOCK(f, LOCK_UN);
397                 close(f);
398                 unlink(s);
399                 if (xlen != key_len)
400                     efree(xkey);
401                 return 0;
402             }
403             if (hdr.mtime == 0 || hdr.mtime > t) {
404                 /*
405                  * try to put it into shared memory
406                  */
407                 mm_user_cache_entry *p = NULL;
408                 if (eaccelerator_mm_instance != NULL && (where == eaccelerator_shm_and_disk || where == eaccelerator_shm)) {
409                     if (eaccelerator_shm_max == 0 || hdr.size <= eaccelerator_shm_max) {
410                         EACCELERATOR_UNPROTECT();
411                         p = eaccelerator_malloc(hdr.size);
412                         if (p == NULL) {
413                             p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
414                         }
415                         if (p == NULL) {
416                             EACCELERATOR_PROTECT();
417                         }
418                     }
419                 }
420                 if (p == NULL) {
421                     p = emalloc(hdr.size);
422                     use_shm = 0;
423                 }
424                 if (p != NULL) {
425                     if (read(f, p, hdr.size) == hdr.size && hdr.size == p->size
426                             && hdr.crc32 == eaccelerator_crc32((const char *) p, p->size)) {
427                         EAG(mem) = (char *) ((long) p - (long) p->next);
428                         EAG(compress) = 1;
429                         fixup_zval(&p->value TSRMLS_CC);
430
431                         if (strcmp(xkey, p->key) != 0) {
432                             if (use_shm) {
433                                 eaccelerator_free(p);
434                             } else {
435                                 efree(p);
436                             }
437                             EACCELERATOR_FLOCK(f, LOCK_UN);
438                             close(f);
439                             unlink(s);
440                             if (use_shm) {
441                                 EACCELERATOR_PROTECT();
442                             }
443                             if (xlen != key_len) {
444                                 efree(xkey);
445                             }
446                             return 0;
447                         }
448
449                         memcpy(return_value, &p->value, sizeof(zval));
450                         restore_zval(return_value TSRMLS_CC);
451                         ret = 1;
452                         if (use_shm) {
453                             /* put it into shared memory */
454                             mm_user_cache_entry *q, *prev;
455
456                             p->hv = hv;
457                             EACCELERATOR_LOCK_RW();
458                             p->next = eaccelerator_mm_instance->user_hash[slot];
459                             eaccelerator_mm_instance->user_hash[slot] = p;
460                             eaccelerator_mm_instance->user_hash_cnt++;
461                             prev = p;
462                             q = p->next;
463                             while (q != NULL) {
464                                 if ((q->hv == hv) && (strcmp(q->key, xkey) == 0)) {
465                                     prev->next = q->next;
466                                     eaccelerator_mm_instance->user_hash_cnt--;
467                                     eaccelerator_free_nolock(q);
468                                     break;
469                                 }
470                                 prev = q;
471                                 q = q->next;
472                             }
473                             EACCELERATOR_UNLOCK_RW();
474                         } else {
475                             efree(p);
476                         }
477                         EACCELERATOR_FLOCK(f, LOCK_UN);
478                         close(f);
479                     } else {
480                         if (use_shm) {
481                             eaccelerator_free(p);
482                         } else {
483                             efree(p);
484                         }
485                         EACCELERATOR_FLOCK(f, LOCK_UN);
486                         close(f);
487                         unlink(s);
488                     }
489                 }
490                 if (use_shm)
491                     EACCELERATOR_PROTECT();
492             } else {
493                 EACCELERATOR_FLOCK(f, LOCK_UN);
494                 close(f);
495                 unlink(s);
496             }
497             if (xlen != key_len) {
498                 efree(xkey);
499             }
500             return ret;
501         }
502     }
503     if (xlen != key_len) {
504         efree(xkey);
505     }
506     return 0;
507 }
508
509 /* remove a key from the cache */
510 int eaccelerator_rm(const char *key, int key_len,
511                  eaccelerator_cache_place where TSRMLS_DC)
512 {
513     unsigned int hv, slot;
514     mm_user_cache_entry *p, *q;
515     char s[MAXPATHLEN];
516     int xlen;
517     char *xkey;
518
519     xkey = build_key(key, key_len, &xlen TSRMLS_CC);
520     /*
521      * removing file
522      */
523     if ((where == eaccelerator_shm_and_disk || where == eaccelerator_shm ||
524                 where == eaccelerator_disk_only) && eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
525         unlink(s);
526     }
527
528     /*
529      * removing from shared memory
530      */
531     if (eaccelerator_mm_instance != NULL && (where == eaccelerator_shm_and_disk ||
532                 where == eaccelerator_shm || where == eaccelerator_shm_only)) {
533         hv = hash_mm(xkey, xlen);
534         slot = hv & MM_USER_HASH_MAX;
535
536         EACCELERATOR_UNPROTECT();
537         EACCELERATOR_LOCK_RW();
538         q = NULL;
539         p = eaccelerator_mm_instance->user_hash[slot];
540         while (p != NULL) {
541             if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
542                 if (q == NULL) {
543                     eaccelerator_mm_instance->user_hash[slot] = p->next;
544                 } else {
545                     q->next = p->next;
546                 }
547                 eaccelerator_mm_instance->user_hash_cnt--;
548                 eaccelerator_free_nolock(p);
549                 break;
550             }
551             q = p;
552             p = p->next;
553         }
554         EACCELERATOR_UNLOCK_RW();
555         EACCELERATOR_PROTECT();
556     }
557     if (xlen != key_len) {
558         efree(xkey);
559     }
560     return 1;
561 }
562
563 /* do garbage collection on the keys */
564 size_t eaccelerator_gc(TSRMLS_D)
565 {
566     size_t size = 0;
567     unsigned int i;
568     time_t t = time(0);
569
570     if (eaccelerator_mm_instance == NULL) {
571         return 0;
572     }
573     EACCELERATOR_UNPROTECT();
574     EACCELERATOR_LOCK_RW();
575     for (i = 0; i < MM_USER_HASH_SIZE; i++) {
576         mm_user_cache_entry **p = &eaccelerator_mm_instance->user_hash[i];
577         while (*p != NULL) {
578             if ((*p)->ttl != 0 && (*p)->ttl < t) {
579                 mm_user_cache_entry *r = *p;
580                 *p = (*p)->next;
581                 eaccelerator_mm_instance->user_hash_cnt--;
582                 size += r->size;
583                 eaccelerator_free_nolock(r);
584             } else {
585                 p = &(*p)->next;
586             }
587         }
588     }
589     EACCELERATOR_UNLOCK_RW();
590     EACCELERATOR_PROTECT();
591     return size;
592 }
593
594 /* get list of all keys stored in memory that matches hostname or namespace */
595 int eaccelerator_list_keys(zval *return_value TSRMLS_DC)
596 {
597     unsigned int i, xlen;
598     zval *list;
599     char *xkey;
600     mm_user_cache_entry *p;
601     time_t t = time(0);
602
603     // create key prefix for current host / namespace
604     xlen = strlen(EAG(name_space));
605     if (xlen > 0) {
606         xkey = emalloc(xlen + 1);
607         memcpy(xkey, EAG(name_space), xlen);
608     } else {
609         xlen = strlen(EAG(hostname));
610         if (xlen > 0) {
611             xkey = emalloc(xlen + 1);
612             memcpy(xkey, EAG(hostname), xlen);
613         }
614     }
615
616     // initialize return value as an array
617     array_init(return_value);
618
619     for (i = 0; i < MM_USER_HASH_SIZE; ++i) {
620         p = eaccelerator_mm_instance->user_hash[i];
621         while(p != NULL) {
622             if (!xlen || strncmp(p->key, xkey, xlen) == 0) {
623                 list = NULL;
624                 ALLOC_INIT_ZVAL(list);
625                 array_init(list);
626                
627                 if (strlen(p->key) > xlen) {
628                     add_assoc_string(list, "name", (p->key) + xlen, 1);
629                 } else {
630                     add_assoc_string(list, "name", p->key, 1);
631                 }
632                
633                 if (p->ttl) {
634                     if (p->ttl < t) {
635                         add_assoc_long(list, "ttl", (p->ttl -t)); // ttl
636                     } else {
637                         add_assoc_long(list, "ttl", -1); // expired
638                     }
639                 } else {
640                     add_assoc_long(list, "ttl", 0); // no ttl
641                 }
642                
643                 add_assoc_long(list, "created", p->create);
644                 add_assoc_long(list, "size", p->size);
645                 add_next_index_zval(return_value, list);
646             }
647             p = p->next;
648         }
649     }
650
651     if (xlen > 0)
652         efree(xkey);
653     return 1;
654 }
655
656 #endif /* HAVE_EACCELERATOR */
657
Note: See TracBrowser for help on using the browser.