root/eaccelerator/branches/0.9.4/cache.c

Revision 215, 15.2 kB (checked in by bart, 3 years ago)

* Branched the 0.9.4 release to fix win32
* Fixes from Simon Westwood

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