root/eaccelerator/tags/0.9.4/cache.c

Revision 123, 15.2 kB (checked in by zoeloelip, 3 years ago)

* Renamed some macros from MMC (mmcache) to EA (eg MMCG is now EAG)
* Added eA file header to mm.c, mm.h and x86-spinlocks.h
* Readded a hack to the loader to prevent zend2 segfaults

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