New upstream version 2.2.1+0.9.2
Ondřej Surý
3 years ago
2 | 2 | <name>yac</name> |
3 | 3 | <channel>pecl.php.net</channel> |
4 | 4 | <summary>lockless user data cache</summary> |
5 | <description>yac is a shared memory user data cache for PHP. it can be used to replace APC or local memcached. | |
6 | ||
7 | yac is lockless, that means, it is very fast, but there could be a chance you will get a wrong data(depends on how many key slots are allocated and how many keys are stored), so you'd better make sure that your product is not very sensitive to that.</description> | |
5 | <description>yac is a fast, lock-free, shared memory user data cache for PHP. it can be used to replace APC or local memcached.</description> | |
8 | 6 | <lead> |
9 | 7 | <name>Xinchen Hui</name> |
10 | 8 | <user>laruence</user> |
11 | 9 | <email>laruence@php.net</email> |
12 | 10 | <active>yes</active> |
13 | 11 | </lead> |
14 | <developer> | |
15 | <name>Wei Dai</name> | |
16 | <user>Demon</user> | |
17 | <email>zxcvdavid@gmail.com</email> | |
18 | <active>yes</active> | |
19 | </developer> | |
20 | <date>2020-03-19</date> | |
21 | <time>04:42:02</time> | |
12 | <date>2020-05-15</date> | |
13 | <time>04:17:14</time> | |
22 | 14 | <version> |
23 | <release>2.0.4</release> | |
24 | <api>2.0.4</api> | |
15 | <release>2.2.1</release> | |
16 | <api>2.2.1</api> | |
25 | 17 | </version> |
26 | 18 | <stability> |
27 | <release>beta</release> | |
28 | <api>beta</api> | |
19 | <release>stable</release> | |
20 | <api>stable</api> | |
29 | 21 | </stability> |
30 | 22 | <license uri="http://www.php.net/license">PHP</license> |
31 | 23 | <notes> |
32 | - Fixed PHP-7.4 windows build | |
24 | - Refactor key manipulation, avoding memory allocation | |
25 | - Refactor Yac::__set/__get by using native objects_handler | |
33 | 26 | </notes> |
34 | 27 | <contents> |
35 | 28 | <dir name="/"> |
37 | 30 | <file md5sum="ba23da7a1141b5b0b1222641f9948d46" name="storage/allocator/allocators/mmap.c" role="src" /> |
38 | 31 | <file md5sum="d719e0643e649a89ad307ee41b82e0fd" name="storage/allocator/allocators/shm.c" role="src" /> |
39 | 32 | <file md5sum="5aa4302988e0a26b7673741de836a4d2" name="storage/allocator/yac_allocator.h" role="src" /> |
40 | <file md5sum="135ac2305a28288ae89099679e0e070b" name="storage/allocator/yac_allocator.c" role="src" /> | |
41 | <file md5sum="6a45b887b874e2341f0d4123016d2a50" name="storage/yac_storage.h" role="src" /> | |
42 | <file md5sum="cd0ba257e1ced1d07188f7bfb3d5f6fd" name="storage/yac_storage.c" role="src" /> | |
33 | <file md5sum="65411ac45fa24b952f0fe8a570b5f2b8" name="storage/allocator/yac_allocator.c" role="src" /> | |
34 | <file md5sum="38742caebaa3a6cad4e298c9f7dd1ec4" name="storage/yac_storage.h" role="src" /> | |
35 | <file md5sum="fb944b23ed1d05c06e76e5317f3c5136" name="storage/yac_storage.c" role="src" /> | |
36 | <file md5sum="2c7bdae5e04ba2dbd2dfd95b9545b320" name="storage/yac_atomic.h" role="src" /> | |
43 | 37 | <file md5sum="543b3b1b8571c4b9c02eafee4a6f3fa3" name="compressor/fastlz/LICENSE" role="doc" /> |
44 | <file md5sum="fa4d2340c50946340603066b02f7e6dd" name="compressor/fastlz/README.TXT" role="doc" /> | |
38 | <file md5sum="4c76809627c49a1b1082a20699fb4482" name="compressor/fastlz/README.TXT" role="doc" /> | |
45 | 39 | <file md5sum="d49275e3dcc1d23d6ce0041648be8e14" name="compressor/fastlz/fastlz.h" role="src" /> |
46 | 40 | <file md5sum="89384a08695fc238e9fbc41b0a14b5a7" name="compressor/fastlz/fastlz.c" role="src" /> |
47 | <file md5sum="bf1cbe22980777ba06be4a1d7d03266d" name="serializer/yac_serializer.h" role="src" /> | |
48 | <file md5sum="b0f27e20d0823e891413aee3fe97a120" name="serializer/php.c" role="src" /> | |
49 | <file md5sum="af01e88cd9b050363a069a526d07989b" name="serializer/msgpack.c" role="src" /> | |
41 | <file md5sum="ceccb8a1237d9291ed527b12184cac7c" name="serializer/yac_serializer.h" role="src" /> | |
42 | <file md5sum="6bb7b710c83d297c24a6bb7b6d906235" name="serializer/php.c" role="src" /> | |
43 | <file md5sum="eb1f7ba8afb1d199e108ea2a8ed5ef9e" name="serializer/msgpack.c" role="src" /> | |
44 | <file md5sum="f4433aa570612f012eb1a9b57d4ce889" name="serializer/json.c" role="src" /> | |
45 | <file md5sum="292f300c457afe1c5d7b6c52dd7a9b6d" name="serializer/igbinary.c" role="src" /> | |
50 | 46 | <file md5sum="4ff407df4fb138f1fdefa97a72e4769f" name="tests/001.phpt" role="test" /> |
51 | <file md5sum="ad4a91d346d21c285ab21b4befcb538e" name="tests/002.phpt" role="test" /> | |
52 | <file md5sum="59f0d14be6b86915ded044110b9148da" name="tests/003.phpt" role="test" /> | |
47 | <file md5sum="702ee40db31edb24c2c633ae6ce9a29e" name="tests/002.phpt" role="test" /> | |
48 | <file md5sum="809b97bbef7dd58aafd905660043446b" name="tests/003.phpt" role="test" /> | |
53 | 49 | <file md5sum="69b6eab19f3e907097fd41ec6dfc024a" name="tests/004.phpt" role="test" /> |
54 | 50 | <file md5sum="0c45c663d4bb4580344278d93d72697c" name="tests/005.phpt" role="test" /> |
55 | 51 | <file md5sum="44354a5ac454a1bce3b00d8f5f9d6c4c" name="tests/006.phpt" role="test" /> |
59 | 55 | <file md5sum="1bf41dadf4a96d8730d37d89fb8257a6" name="tests/010.phpt" role="test" /> |
60 | 56 | <file md5sum="0f47511cd434d57d01f78ad8a65a13cb" name="tests/011.phpt" role="test" /> |
61 | 57 | <file md5sum="4c3a616f6563f090ccf781ed6a4671af" name="tests/012.phpt" role="test" /> |
62 | <file md5sum="717d306b5ea2e5ae1aaef6894c3aaf2a" name="tests/013.phpt" role="test" /> | |
63 | <file md5sum="56f31a4a48c4d28a14e3939ce87abdb3" name="tests/014.phpt" role="test" /> | |
64 | <file md5sum="88ff06bab70e76cc0aa6e79aa4ee7e21" name="tests/015.phpt" role="test" /> | |
58 | <file md5sum="59924bf44844ea20bf3ab073e9bd28e3" name="tests/013.phpt" role="test" /> | |
59 | <file md5sum="07101b0387d80a78d298472b50e10fc7" name="tests/014.phpt" role="test" /> | |
60 | <file md5sum="5493a51288d0b3950c3bb2013eb54571" name="tests/015.phpt" role="test" /> | |
61 | <file md5sum="e8be5f292141214466103bf22d38c93e" name="tests/016.phpt" role="test" /> | |
62 | <file md5sum="6c78da4fb6a77aa333d60c12aeec3e10" name="tests/017.phpt" role="test" /> | |
63 | <file md5sum="d9f4f5ce592bffa74cb2a41cedadea0d" name="tests/018.phpt" role="test" /> | |
64 | <file md5sum="6c8431543f431d8805dcceada3ab944f" name="tests/019.phpt" role="test" /> | |
65 | <file md5sum="2705ab4cd8d284adcc48ee9afcd8d482" name="tests/020.phpt" role="test" /> | |
66 | <file md5sum="6bb18debb309f320cd2061ba103f7e67" name="tests/021.phpt" role="test" /> | |
67 | <file md5sum="544fd003bea3e33b8c4ed4dc1e5126b3" name="tests/022.phpt" role="test" /> | |
68 | <file md5sum="bd7b561c2df8c52bdec8c52fa2909733" name="tests/023.phpt" role="test" /> | |
65 | 69 | <file md5sum="4c4242640be3dfdccf4b46600dbe3682" name="tests/issue012.phpt" role="test" /> |
66 | 70 | <file md5sum="ac36c858a802d2d8c791b4de479adb59" name="config.w32" role="src" /> |
67 | 71 | <file md5sum="dd34a70236f008af999de817b93a5e3a" name="LICENSE" role="doc" /> |
68 | 72 | <file md5sum="e4313698b2307a62bdbac09fd596ae53" name="CREDITS" role="doc" /> |
69 | <file md5sum="38d7ad86c61e3e0a6fc0e95dffd5f90c" name="config.m4" role="src" /> | |
70 | <file md5sum="5f7b041ae7f25719318e368f38cb5fdd" name="yac.c" role="src" /> | |
71 | <file md5sum="3e22c72def09200431f3f971c88e52da" name="php_yac.h" role="src" /> | |
73 | <file md5sum="655d9ecb38f3f2fb2025d8f1202ca243" name="config.m4" role="src" /> | |
74 | <file md5sum="05be4e0f96781cb052139b4dc5bd0148" name="yac.c" role="src" /> | |
75 | <file md5sum="8ea02c4b57d3b2faa1ad89ecaf929a6d" name="php_yac.h" role="src" /> | |
72 | 76 | </dir> |
73 | 77 | </contents> |
74 | 78 | <dependencies> |
82 | 86 | </required> |
83 | 87 | </dependencies> |
84 | 88 | <providesextension>yac</providesextension> |
85 | <extsrcrelease /> | |
89 | <extsrcrelease> | |
90 | <configureoption default="no" name="enable-igbinary" prompt="enable igbinary serializer support?" /> | |
91 | <configureoption default="no" name="enable-json" prompt="enable json serializer support?" /> | |
92 | <configureoption default="no" name="enable-msgpack" prompt="enable msgpack serializer support?" /> | |
93 | </extsrcrelease> | |
86 | 94 | <changelog> |
95 | <release> | |
96 | <date>2020-03-31</date> | |
97 | <version> | |
98 | <release>2.2.1</release> | |
99 | <api>2.2.1</api> | |
100 | </version> | |
101 | <stability> | |
102 | <release>stable</release> | |
103 | <api>stable</api> | |
104 | </stability> | |
105 | <license uri="http://www.php.net/license">PHP License</license> | |
106 | <notes> | |
107 | - Refactor key manipulation, avoding memory allocation | |
108 | - Refactor Yac::__set/__get by using native objects_handler | |
109 | </notes> | |
110 | </release> | |
111 | <release> | |
112 | <date>2020-03-31</date> | |
113 | <version> | |
114 | <release>2.2.0</release> | |
115 | <api>2.2.0</api> | |
116 | </version> | |
117 | <stability> | |
118 | <release>stable</release> | |
119 | <api>stable</api> | |
120 | </stability> | |
121 | <license uri="http://www.php.net/license">PHP License</license> | |
122 | <notes> | |
123 | - Added json serializer | |
124 | - Added igbinary serializer | |
125 | - change yac.serilalizer to string, "php", "json" etc | |
126 | </notes> | |
127 | </release> | |
128 | <release> | |
129 | <date>2020-03-27</date> | |
130 | <version> | |
131 | <release>2.1.2</release> | |
132 | <api>2.1.2</api> | |
133 | </version> | |
134 | <stability> | |
135 | <release>stable</release> | |
136 | <api>stable</api> | |
137 | </stability> | |
138 | <license uri="http://www.php.net/license">PHP License</license> | |
139 | <notes> | |
140 | - Fixed compiler warning of redefinition of macros | |
141 | - Fixed crc32c only pick the first byte | |
142 | - Also use crc32_u32 in 64 bits | |
143 | </notes> | |
144 | </release> | |
145 | <release> | |
146 | <date>2020-03-25</date> | |
147 | <version> | |
148 | <release>2.1.1</release> | |
149 | <api>2.1.1</api> | |
150 | </version> | |
151 | <stability> | |
152 | <release>stable</release> | |
153 | <api>stable</api> | |
154 | </stability> | |
155 | <license uri="http://www.php.net/license">PHP License</license> | |
156 | <notes> | |
157 | - Fixed Build in 32bits | |
158 | </notes> | |
159 | </release> | |
160 | <release> | |
161 | <date>2020-03-25</date> | |
162 | <version> | |
163 | <release>2.1.0</release> | |
164 | <api>2.1.0</api> | |
165 | </version> | |
166 | <stability> | |
167 | <release>stable</release> | |
168 | <api>stable</api> | |
169 | </stability> | |
170 | <license uri="http://www.php.net/license">PHP License</license> | |
171 | <notes> | |
172 | - Implemnented CAS based lock-free protection | |
173 | - Use SSE4.2 _mm_crc32 instead of normal crc32 to make speedup | |
174 | - Some optimization to avoding memory usage | |
175 | </notes> | |
176 | </release> | |
87 | 177 | <release> |
88 | 178 | <date>2020-03-19</date> |
89 | 179 | <version> |
0 | -------------------------------------------------------------------- | |
1 | The PHP License, version 3.01 | |
2 | Copyright (c) 1999 - 2011 The PHP Group. All rights reserved. | |
3 | -------------------------------------------------------------------- | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, is permitted provided that the following conditions | |
7 | are met: | |
8 | ||
9 | 1. Redistributions of source code must retain the above copyright | |
10 | notice, this list of conditions and the following disclaimer. | |
11 | ||
12 | 2. Redistributions in binary form must reproduce the above copyright | |
13 | notice, this list of conditions and the following disclaimer in | |
14 | the documentation and/or other materials provided with the | |
15 | distribution. | |
16 | ||
17 | 3. The name "PHP" must not be used to endorse or promote products | |
18 | derived from this software without prior written permission. For | |
19 | written permission, please contact group@php.net. | |
20 | ||
21 | 4. Products derived from this software may not be called "PHP", nor | |
22 | may "PHP" appear in their name, without prior written permission | |
23 | from group@php.net. You may indicate that your software works in | |
24 | conjunction with PHP by saying "Foo for PHP" instead of calling | |
25 | it "PHP Foo" or "phpfoo" | |
26 | ||
27 | 5. The PHP Group may publish revised and/or new versions of the | |
28 | license from time to time. Each version will be given a | |
29 | distinguishing version number. | |
30 | Once covered code has been published under a particular version | |
31 | of the license, you may always continue to use it under the terms | |
32 | of that version. You may also choose to use such covered code | |
33 | under the terms of any subsequent version of the license | |
34 | published by the PHP Group. No one other than the PHP Group has | |
35 | the right to modify the terms applicable to covered code created | |
36 | under this License. | |
37 | ||
38 | 6. Redistributions of any form whatsoever must retain the following | |
39 | acknowledgment: | |
40 | "This product includes PHP software, freely available from | |
41 | <http://www.php.net/software/>". | |
42 | ||
43 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND | |
44 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
45 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
46 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP | |
47 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
48 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
49 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
50 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
52 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
53 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
54 | OF THE POSSIBILITY OF SUCH DAMAGE. | |
55 | ||
56 | -------------------------------------------------------------------- | |
57 | ||
58 | This software consists of voluntary contributions made by many | |
59 | individuals on behalf of the PHP Group. | |
60 | ||
61 | The PHP Group can be contacted via Email at group@php.net. | |
62 | ||
63 | For more information on the PHP Group and the PHP project, | |
64 | please see <http://www.php.net>. | |
65 | ||
66 | PHP includes the Zend Engine, freely available at | |
67 | <http://www.zend.com>. |
0 | FastLZ - lightning-fast lossless compression library | |
1 | ||
2 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
3 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | of this software and associated documentation files (the "Software"), to deal | |
8 | in the Software without restriction, including without limitation the rights | |
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | copies of the Software, and to permit persons to whom the Software is | |
11 | furnished to do so, subject to the following conditions: | |
12 | ||
13 | The above copyright notice and this permission notice shall be included in | |
14 | all copies or substantial portions of the Software. | |
15 | ||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | THE SOFTWARE. | |
23 |
0 | FastLZ - lightning-fast lossless compression library | |
1 | ||
2 | Author: Ariya Hidayat | |
3 | Official website: http://www.fastlz.org | |
4 | ||
5 | FastLZ is distributed using the MIT license, see file LICENSE | |
6 | for details. | |
7 | ||
8 | FastLZ consists of two files: fastlz.h and fastlz.c. Just add these | |
9 | files to your project in order to use FastLZ. For information on | |
10 | compression and decompression routines, see fastlz.h. | |
11 | ||
12 | A simple file compressor called 6pack is included as an example | |
13 | on how to use FastLZ. The corresponding decompressor is 6unpack. | |
14 | ||
15 | To compile using GCC: | |
16 | ||
17 | gcc -o 6pack 6pack.c fastlz.c | |
18 | gcc -o 6unpack 6unpack.c fastlz.c | |
19 | ||
20 | To compile using MinGW: | |
21 | ||
22 | mingw32-gcc -o 6pack 6pack.c fastlz.c | |
23 | mingw32-gcc -o 6unpack 6unpack.c fastlz.c | |
24 | ||
25 | To compile using Microsoft Visual C++: | |
26 | ||
27 | cl 6pack.c fastlz.c | |
28 | cl 6unpack.c fastlz.c | |
29 | ||
30 | To compile using Borland C++: | |
31 | ||
32 | bcc32 6pack.c fastlz.c | |
33 | bcc32 6unpack.c fastlz.c | |
34 | ||
35 | To compile using OpenWatcom C/C++: | |
36 | ||
37 | cl386 6pack.c fastlz.c | |
38 | cl386 6unpack.c fastlz.c | |
39 | ||
40 | To compile using Intel C++ compiler for Windows: | |
41 | ||
42 | icl 6pack.c fastlz.c | |
43 | icl 6unpack.c fastlz.c | |
44 | ||
45 | To compile using Intel C++ compiler for Linux: | |
46 | ||
47 | icc -o 6pack 6pack.c fastlz.c | |
48 | icc -o 6unpack 6unpack.c fastlz.c | |
49 | ||
50 | To compile 6pack using LCC-Win32: | |
51 | ||
52 | lc 6pack.c fastlz.c | |
53 | lc 6unpack.c fastlz.c | |
54 | ||
55 | To compile 6pack using Pelles C: | |
56 | ||
57 | pocc 6pack.c | |
58 | pocc 6unpack.c | |
59 | pocc fastlz.c | |
60 | polink 6pack.obj fastlz.obj | |
61 | polink 6unpack.obj fastlz.obj | |
62 | ||
63 | For speed optimization, always use proper compile flags for optimization options. | |
64 | Typical compiler flags are given below: | |
65 | ||
66 | * GCC (pre 4.2): -march=pentium -O3 -fomit-frame-pointer -mtune=pentium | |
67 | * GCC 4.2 or later: -march=pentium -O3 -fomit-frame-pointer -mtune=generic | |
68 | * Digital Mars C/C++: -o+all -5 | |
69 | * Intel C++ (Windows): /O3 /Qipo | |
70 | * Intel C++ (Linux): -O2 -march=pentium -mtune=pentium | |
71 | * Borland C++: -O2 -5 | |
72 | * LCC-Win32: -O | |
73 | * Pelles C: /O2 | |
74 |
0 | /* | |
1 | FastLZ - lightning-fast lossless compression library | |
2 | ||
3 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
5 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
6 | ||
7 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | of this software and associated documentation files (the "Software"), to deal | |
9 | in the Software without restriction, including without limitation the rights | |
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | copies of the Software, and to permit persons to whom the Software is | |
12 | furnished to do so, subject to the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included in | |
15 | all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) | |
27 | ||
28 | /* | |
29 | * Always check for bound when decompressing. | |
30 | * Generally it is best to leave it defined. | |
31 | */ | |
32 | #define FASTLZ_SAFE | |
33 | ||
34 | /* | |
35 | * Give hints to the compiler for branch prediction optimization. | |
36 | */ | |
37 | #if defined(__GNUC__) && (__GNUC__ > 2) | |
38 | #define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) | |
39 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) | |
40 | #else | |
41 | #define FASTLZ_EXPECT_CONDITIONAL(c) (c) | |
42 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) | |
43 | #endif | |
44 | ||
45 | /* | |
46 | * Use inlined functions for supported systems. | |
47 | */ | |
48 | #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) | |
49 | #define FASTLZ_INLINE inline | |
50 | #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) | |
51 | #define FASTLZ_INLINE __inline | |
52 | #else | |
53 | #define FASTLZ_INLINE | |
54 | #endif | |
55 | ||
56 | /* | |
57 | * Prevent accessing more than 8-bit at once, except on x86 architectures. | |
58 | */ | |
59 | #if !defined(FASTLZ_STRICT_ALIGN) | |
60 | #define FASTLZ_STRICT_ALIGN | |
61 | #if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ | |
62 | #undef FASTLZ_STRICT_ALIGN | |
63 | #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ | |
64 | #undef FASTLZ_STRICT_ALIGN | |
65 | #elif defined(_M_IX86) /* Intel, MSVC */ | |
66 | #undef FASTLZ_STRICT_ALIGN | |
67 | #elif defined(__386) | |
68 | #undef FASTLZ_STRICT_ALIGN | |
69 | #elif defined(_X86_) /* MinGW */ | |
70 | #undef FASTLZ_STRICT_ALIGN | |
71 | #elif defined(__I86__) /* Digital Mars */ | |
72 | #undef FASTLZ_STRICT_ALIGN | |
73 | #endif | |
74 | #endif | |
75 | ||
76 | /* | |
77 | * FIXME: use preprocessor magic to set this on different platforms! | |
78 | */ | |
79 | typedef unsigned char flzuint8; | |
80 | typedef unsigned short flzuint16; | |
81 | typedef unsigned int flzuint32; | |
82 | ||
83 | /* prototypes */ | |
84 | int fastlz_compress(const void* input, int length, void* output); | |
85 | int fastlz_compress_level(int level, const void* input, int length, void* output); | |
86 | int fastlz_decompress(const void* input, int length, void* output, int maxout); | |
87 | ||
88 | #define MAX_COPY 32 | |
89 | #define MAX_LEN 264 /* 256 + 8 */ | |
90 | #define MAX_DISTANCE 8192 | |
91 | ||
92 | #if !defined(FASTLZ_STRICT_ALIGN) | |
93 | #define FASTLZ_READU16(p) *((const flzuint16*)(p)) | |
94 | #else | |
95 | #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) | |
96 | #endif | |
97 | ||
98 | #define HASH_LOG 13 | |
99 | #define HASH_SIZE (1<< HASH_LOG) | |
100 | #define HASH_MASK (HASH_SIZE-1) | |
101 | #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } | |
102 | ||
103 | #undef FASTLZ_LEVEL | |
104 | #define FASTLZ_LEVEL 1 | |
105 | ||
106 | #undef FASTLZ_COMPRESSOR | |
107 | #undef FASTLZ_DECOMPRESSOR | |
108 | #define FASTLZ_COMPRESSOR fastlz1_compress | |
109 | #define FASTLZ_DECOMPRESSOR fastlz1_decompress | |
110 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); | |
111 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); | |
112 | #include "fastlz.c" | |
113 | ||
114 | #undef FASTLZ_LEVEL | |
115 | #define FASTLZ_LEVEL 2 | |
116 | ||
117 | #undef MAX_DISTANCE | |
118 | #define MAX_DISTANCE 8191 | |
119 | #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) | |
120 | ||
121 | #undef FASTLZ_COMPRESSOR | |
122 | #undef FASTLZ_DECOMPRESSOR | |
123 | #define FASTLZ_COMPRESSOR fastlz2_compress | |
124 | #define FASTLZ_DECOMPRESSOR fastlz2_decompress | |
125 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); | |
126 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); | |
127 | #include "fastlz.c" | |
128 | ||
129 | int fastlz_compress(const void* input, int length, void* output) | |
130 | { | |
131 | /* for short block, choose fastlz1 */ | |
132 | if(length < 65536) | |
133 | return fastlz1_compress(input, length, output); | |
134 | ||
135 | /* else... */ | |
136 | return fastlz2_compress(input, length, output); | |
137 | } | |
138 | ||
139 | int fastlz_decompress(const void* input, int length, void* output, int maxout) | |
140 | { | |
141 | /* magic identifier for compression level */ | |
142 | int level = ((*(const flzuint8*)input) >> 5) + 1; | |
143 | ||
144 | if(level == 1) | |
145 | return fastlz1_decompress(input, length, output, maxout); | |
146 | if(level == 2) | |
147 | return fastlz2_decompress(input, length, output, maxout); | |
148 | ||
149 | /* unknown level, trigger error */ | |
150 | return 0; | |
151 | } | |
152 | ||
153 | int fastlz_compress_level(int level, const void* input, int length, void* output) | |
154 | { | |
155 | if(level == 1) | |
156 | return fastlz1_compress(input, length, output); | |
157 | if(level == 2) | |
158 | return fastlz2_compress(input, length, output); | |
159 | ||
160 | return 0; | |
161 | } | |
162 | ||
163 | #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ | |
164 | ||
165 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) | |
166 | { | |
167 | const flzuint8* ip = (const flzuint8*) input; | |
168 | const flzuint8* ip_bound = ip + length - 2; | |
169 | const flzuint8* ip_limit = ip + length - 12; | |
170 | flzuint8* op = (flzuint8*) output; | |
171 | ||
172 | const flzuint8* htab[HASH_SIZE]; | |
173 | const flzuint8** hslot; | |
174 | flzuint32 hval; | |
175 | ||
176 | flzuint32 copy; | |
177 | ||
178 | /* sanity check */ | |
179 | if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) | |
180 | { | |
181 | if(length) | |
182 | { | |
183 | /* create literal copy only */ | |
184 | *op++ = length-1; | |
185 | ip_bound++; | |
186 | while(ip <= ip_bound) | |
187 | *op++ = *ip++; | |
188 | return length+1; | |
189 | } | |
190 | else | |
191 | return 0; | |
192 | } | |
193 | ||
194 | /* initializes hash table */ | |
195 | for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) | |
196 | *hslot = ip; | |
197 | ||
198 | /* we start with literal copy */ | |
199 | copy = 2; | |
200 | *op++ = MAX_COPY-1; | |
201 | *op++ = *ip++; | |
202 | *op++ = *ip++; | |
203 | ||
204 | /* main loop */ | |
205 | while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) | |
206 | { | |
207 | const flzuint8* ref; | |
208 | flzuint32 distance; | |
209 | ||
210 | /* minimum match length */ | |
211 | flzuint32 len = 3; | |
212 | ||
213 | /* comparison starting-point */ | |
214 | const flzuint8* anchor = ip; | |
215 | ||
216 | /* check for a run */ | |
217 | #if FASTLZ_LEVEL==2 | |
218 | if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) | |
219 | { | |
220 | distance = 1; | |
221 | ip += 3; | |
222 | ref = anchor - 1 + 3; | |
223 | goto match; | |
224 | } | |
225 | #endif | |
226 | ||
227 | /* find potential match */ | |
228 | HASH_FUNCTION(hval,ip); | |
229 | hslot = htab + hval; | |
230 | ref = htab[hval]; | |
231 | ||
232 | /* calculate distance to the match */ | |
233 | distance = anchor - ref; | |
234 | ||
235 | /* update hash table */ | |
236 | *hslot = anchor; | |
237 | ||
238 | /* is this a match? check the first 3 bytes */ | |
239 | if(distance==0 || | |
240 | #if FASTLZ_LEVEL==1 | |
241 | (distance >= MAX_DISTANCE) || | |
242 | #else | |
243 | (distance >= MAX_FARDISTANCE) || | |
244 | #endif | |
245 | *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) | |
246 | goto literal; | |
247 | ||
248 | #if FASTLZ_LEVEL==2 | |
249 | /* far, needs at least 5-byte match */ | |
250 | if(distance >= MAX_DISTANCE) | |
251 | { | |
252 | if(*ip++ != *ref++ || *ip++!= *ref++) | |
253 | goto literal; | |
254 | len += 2; | |
255 | } | |
256 | ||
257 | match: | |
258 | #endif | |
259 | ||
260 | /* last matched byte */ | |
261 | ip = anchor + len; | |
262 | ||
263 | /* distance is biased */ | |
264 | distance--; | |
265 | ||
266 | if(!distance) | |
267 | { | |
268 | /* zero distance means a run */ | |
269 | flzuint8 x = ip[-1]; | |
270 | while(ip < ip_bound) | |
271 | if(*ref++ != x) break; else ip++; | |
272 | } | |
273 | else | |
274 | for(;;) | |
275 | { | |
276 | /* safe because the outer check against ip limit */ | |
277 | if(*ref++ != *ip++) break; | |
278 | if(*ref++ != *ip++) break; | |
279 | if(*ref++ != *ip++) break; | |
280 | if(*ref++ != *ip++) break; | |
281 | if(*ref++ != *ip++) break; | |
282 | if(*ref++ != *ip++) break; | |
283 | if(*ref++ != *ip++) break; | |
284 | if(*ref++ != *ip++) break; | |
285 | while(ip < ip_bound) | |
286 | if(*ref++ != *ip++) break; | |
287 | break; | |
288 | } | |
289 | ||
290 | /* if we have copied something, adjust the copy count */ | |
291 | if(copy) | |
292 | /* copy is biased, '0' means 1 byte copy */ | |
293 | *(op-copy-1) = copy-1; | |
294 | else | |
295 | /* back, to overwrite the copy count */ | |
296 | op--; | |
297 | ||
298 | /* reset literal counter */ | |
299 | copy = 0; | |
300 | ||
301 | /* length is biased, '1' means a match of 3 bytes */ | |
302 | ip -= 3; | |
303 | len = ip - anchor; | |
304 | ||
305 | /* encode the match */ | |
306 | #if FASTLZ_LEVEL==2 | |
307 | if(distance < MAX_DISTANCE) | |
308 | { | |
309 | if(len < 7) | |
310 | { | |
311 | *op++ = (len << 5) + (distance >> 8); | |
312 | *op++ = (distance & 255); | |
313 | } | |
314 | else | |
315 | { | |
316 | *op++ = (7 << 5) + (distance >> 8); | |
317 | for(len-=7; len >= 255; len-= 255) | |
318 | *op++ = 255; | |
319 | *op++ = len; | |
320 | *op++ = (distance & 255); | |
321 | } | |
322 | } | |
323 | else | |
324 | { | |
325 | /* far away, but not yet in the another galaxy... */ | |
326 | if(len < 7) | |
327 | { | |
328 | distance -= MAX_DISTANCE; | |
329 | *op++ = (len << 5) + 31; | |
330 | *op++ = 255; | |
331 | *op++ = distance >> 8; | |
332 | *op++ = distance & 255; | |
333 | } | |
334 | else | |
335 | { | |
336 | distance -= MAX_DISTANCE; | |
337 | *op++ = (7 << 5) + 31; | |
338 | for(len-=7; len >= 255; len-= 255) | |
339 | *op++ = 255; | |
340 | *op++ = len; | |
341 | *op++ = 255; | |
342 | *op++ = distance >> 8; | |
343 | *op++ = distance & 255; | |
344 | } | |
345 | } | |
346 | #else | |
347 | ||
348 | if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) | |
349 | while(len > MAX_LEN-2) | |
350 | { | |
351 | *op++ = (7 << 5) + (distance >> 8); | |
352 | *op++ = MAX_LEN - 2 - 7 -2; | |
353 | *op++ = (distance & 255); | |
354 | len -= MAX_LEN-2; | |
355 | } | |
356 | ||
357 | if(len < 7) | |
358 | { | |
359 | *op++ = (len << 5) + (distance >> 8); | |
360 | *op++ = (distance & 255); | |
361 | } | |
362 | else | |
363 | { | |
364 | *op++ = (7 << 5) + (distance >> 8); | |
365 | *op++ = len - 7; | |
366 | *op++ = (distance & 255); | |
367 | } | |
368 | #endif | |
369 | ||
370 | /* update the hash at match boundary */ | |
371 | HASH_FUNCTION(hval,ip); | |
372 | htab[hval] = ip++; | |
373 | HASH_FUNCTION(hval,ip); | |
374 | htab[hval] = ip++; | |
375 | ||
376 | /* assuming literal copy */ | |
377 | *op++ = MAX_COPY-1; | |
378 | ||
379 | continue; | |
380 | ||
381 | literal: | |
382 | *op++ = *anchor++; | |
383 | ip = anchor; | |
384 | copy++; | |
385 | if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) | |
386 | { | |
387 | copy = 0; | |
388 | *op++ = MAX_COPY-1; | |
389 | } | |
390 | } | |
391 | ||
392 | /* left-over as literal copy */ | |
393 | ip_bound++; | |
394 | while(ip <= ip_bound) | |
395 | { | |
396 | *op++ = *ip++; | |
397 | copy++; | |
398 | if(copy == MAX_COPY) | |
399 | { | |
400 | copy = 0; | |
401 | *op++ = MAX_COPY-1; | |
402 | } | |
403 | } | |
404 | ||
405 | /* if we have copied something, adjust the copy length */ | |
406 | if(copy) | |
407 | *(op-copy-1) = copy-1; | |
408 | else | |
409 | op--; | |
410 | ||
411 | #if FASTLZ_LEVEL==2 | |
412 | /* marker for fastlz2 */ | |
413 | *(flzuint8*)output |= (1 << 5); | |
414 | #endif | |
415 | ||
416 | return op - (flzuint8*)output; | |
417 | } | |
418 | ||
419 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) | |
420 | { | |
421 | const flzuint8* ip = (const flzuint8*) input; | |
422 | const flzuint8* ip_limit = ip + length; | |
423 | flzuint8* op = (flzuint8*) output; | |
424 | flzuint8* op_limit = op + maxout; | |
425 | flzuint32 ctrl = (*ip++) & 31; | |
426 | int loop = 1; | |
427 | ||
428 | do | |
429 | { | |
430 | const flzuint8* ref = op; | |
431 | flzuint32 len = ctrl >> 5; | |
432 | flzuint32 ofs = (ctrl & 31) << 8; | |
433 | ||
434 | if(ctrl >= 32) | |
435 | { | |
436 | #if FASTLZ_LEVEL==2 | |
437 | flzuint8 code; | |
438 | #endif | |
439 | len--; | |
440 | ref -= ofs; | |
441 | if (len == 7-1) | |
442 | #if FASTLZ_LEVEL==1 | |
443 | len += *ip++; | |
444 | ref -= *ip++; | |
445 | #else | |
446 | do | |
447 | { | |
448 | code = *ip++; | |
449 | len += code; | |
450 | } while (code==255); | |
451 | code = *ip++; | |
452 | ref -= code; | |
453 | ||
454 | /* match from 16-bit distance */ | |
455 | if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) | |
456 | if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) | |
457 | { | |
458 | ofs = (*ip++) << 8; | |
459 | ofs += *ip++; | |
460 | ref = op - ofs - MAX_DISTANCE; | |
461 | } | |
462 | #endif | |
463 | ||
464 | #ifdef FASTLZ_SAFE | |
465 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) | |
466 | return 0; | |
467 | ||
468 | if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) | |
469 | return 0; | |
470 | #endif | |
471 | ||
472 | if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) | |
473 | ctrl = *ip++; | |
474 | else | |
475 | loop = 0; | |
476 | ||
477 | if(ref == op) | |
478 | { | |
479 | /* optimize copy for a run */ | |
480 | flzuint8 b = ref[-1]; | |
481 | *op++ = b; | |
482 | *op++ = b; | |
483 | *op++ = b; | |
484 | for(; len; --len) | |
485 | *op++ = b; | |
486 | } | |
487 | else | |
488 | { | |
489 | #if !defined(FASTLZ_STRICT_ALIGN) | |
490 | const flzuint16* p; | |
491 | flzuint16* q; | |
492 | #endif | |
493 | /* copy from reference */ | |
494 | ref--; | |
495 | *op++ = *ref++; | |
496 | *op++ = *ref++; | |
497 | *op++ = *ref++; | |
498 | ||
499 | #if !defined(FASTLZ_STRICT_ALIGN) | |
500 | /* copy a byte, so that now it's word aligned */ | |
501 | if(len & 1) | |
502 | { | |
503 | *op++ = *ref++; | |
504 | len--; | |
505 | } | |
506 | ||
507 | /* copy 16-bit at once */ | |
508 | q = (flzuint16*) op; | |
509 | op += len; | |
510 | p = (const flzuint16*) ref; | |
511 | for(len>>=1; len > 4; len-=4) | |
512 | { | |
513 | *q++ = *p++; | |
514 | *q++ = *p++; | |
515 | *q++ = *p++; | |
516 | *q++ = *p++; | |
517 | } | |
518 | for(; len; --len) | |
519 | *q++ = *p++; | |
520 | #else | |
521 | for(; len; --len) | |
522 | *op++ = *ref++; | |
523 | #endif | |
524 | } | |
525 | } | |
526 | else | |
527 | { | |
528 | ctrl++; | |
529 | #ifdef FASTLZ_SAFE | |
530 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) | |
531 | return 0; | |
532 | if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) | |
533 | return 0; | |
534 | #endif | |
535 | ||
536 | *op++ = *ip++; | |
537 | for(--ctrl; ctrl; ctrl--) | |
538 | *op++ = *ip++; | |
539 | ||
540 | loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); | |
541 | if(loop) | |
542 | ctrl = *ip++; | |
543 | } | |
544 | } | |
545 | while(FASTLZ_EXPECT_CONDITIONAL(loop)); | |
546 | ||
547 | return op - (flzuint8*)output; | |
548 | } | |
549 | ||
550 | #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ |
0 | /* | |
1 | FastLZ - lightning-fast lossless compression library | |
2 | ||
3 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
5 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
6 | ||
7 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | of this software and associated documentation files (the "Software"), to deal | |
9 | in the Software without restriction, including without limitation the rights | |
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | copies of the Software, and to permit persons to whom the Software is | |
12 | furnished to do so, subject to the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included in | |
15 | all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #ifndef FASTLZ_H | |
27 | #define FASTLZ_H | |
28 | ||
29 | #define FASTLZ_VERSION 0x000100 | |
30 | ||
31 | #define FASTLZ_VERSION_MAJOR 0 | |
32 | #define FASTLZ_VERSION_MINOR 0 | |
33 | #define FASTLZ_VERSION_REVISION 0 | |
34 | ||
35 | #define FASTLZ_VERSION_STRING "0.1.0" | |
36 | ||
37 | #if defined (__cplusplus) | |
38 | extern "C" { | |
39 | #endif | |
40 | ||
41 | /** | |
42 | Compress a block of data in the input buffer and returns the size of | |
43 | compressed block. The size of input buffer is specified by length. The | |
44 | minimum input buffer size is 16. | |
45 | ||
46 | The output buffer must be at least 5% larger than the input buffer | |
47 | and can not be smaller than 66 bytes. | |
48 | ||
49 | If the input is not compressible, the return value might be larger than | |
50 | length (input buffer size). | |
51 | ||
52 | The input buffer and the output buffer can not overlap. | |
53 | */ | |
54 | ||
55 | int fastlz_compress(const void* input, int length, void* output); | |
56 | ||
57 | /** | |
58 | Decompress a block of compressed data and returns the size of the | |
59 | decompressed block. If error occurs, e.g. the compressed data is | |
60 | corrupted or the output buffer is not large enough, then 0 (zero) | |
61 | will be returned instead. | |
62 | ||
63 | The input buffer and the output buffer can not overlap. | |
64 | ||
65 | Decompression is memory safe and guaranteed not to write the output buffer | |
66 | more than what is specified in maxout. | |
67 | */ | |
68 | ||
69 | int fastlz_decompress(const void* input, int length, void* output, int maxout); | |
70 | ||
71 | /** | |
72 | Compress a block of data in the input buffer and returns the size of | |
73 | compressed block. The size of input buffer is specified by length. The | |
74 | minimum input buffer size is 16. | |
75 | ||
76 | The output buffer must be at least 5% larger than the input buffer | |
77 | and can not be smaller than 66 bytes. | |
78 | ||
79 | If the input is not compressible, the return value might be larger than | |
80 | length (input buffer size). | |
81 | ||
82 | The input buffer and the output buffer can not overlap. | |
83 | ||
84 | Compression level can be specified in parameter level. At the moment, | |
85 | only level 1 and level 2 are supported. | |
86 | Level 1 is the fastest compression and generally useful for short data. | |
87 | Level 2 is slightly slower but it gives better compression ratio. | |
88 | ||
89 | Note that the compressed data, regardless of the level, can always be | |
90 | decompressed using the function fastlz_decompress above. | |
91 | */ | |
92 | ||
93 | int fastlz_compress_level(int level, const void* input, int length, void* output); | |
94 | ||
95 | #if defined (__cplusplus) | |
96 | } | |
97 | #endif | |
98 | ||
99 | #endif /* FASTLZ_H */ |
0 | dnl $Id$ | |
1 | dnl config.m4 for extension yac | |
2 | ||
3 | PHP_ARG_ENABLE(yac, whether to enable yac support, | |
4 | [ --enable-yac Enable yac support]) | |
5 | ||
6 | PHP_ARG_WITH(system-fastlz, whether to use system FastLZ library, | |
7 | [ --with-system-fastlz Use system FastLZ library], no, no) | |
8 | ||
9 | dnl PHP_ARG_ENABLE(yac, whether to use msgpack as serializer, | |
10 | dnl [ --enable-msgpack Use Messagepack as serializer]) | |
11 | ||
12 | dnl copied from Zend Optimizer Plus | |
13 | AC_MSG_CHECKING(for sysvipc shared memory support) | |
14 | AC_TRY_RUN([ | |
15 | #include <sys/types.h> | |
16 | #include <sys/wait.h> | |
17 | #include <sys/ipc.h> | |
18 | #include <sys/shm.h> | |
19 | #include <unistd.h> | |
20 | #include <string.h> | |
21 | ||
22 | int main() { | |
23 | pid_t pid; | |
24 | int status; | |
25 | int ipc_id; | |
26 | char *shm; | |
27 | struct shmid_ds shmbuf; | |
28 | ||
29 | ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W)); | |
30 | if (ipc_id == -1) { | |
31 | return 1; | |
32 | } | |
33 | ||
34 | shm = shmat(ipc_id, NULL, 0); | |
35 | if (shm == (void *)-1) { | |
36 | shmctl(ipc_id, IPC_RMID, NULL); | |
37 | return 2; | |
38 | } | |
39 | ||
40 | if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) { | |
41 | shmdt(shm); | |
42 | shmctl(ipc_id, IPC_RMID, NULL); | |
43 | return 3; | |
44 | } | |
45 | ||
46 | shmbuf.shm_perm.uid = getuid(); | |
47 | shmbuf.shm_perm.gid = getgid(); | |
48 | shmbuf.shm_perm.mode = 0600; | |
49 | ||
50 | if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) { | |
51 | shmdt(shm); | |
52 | shmctl(ipc_id, IPC_RMID, NULL); | |
53 | return 4; | |
54 | } | |
55 | ||
56 | shmctl(ipc_id, IPC_RMID, NULL); | |
57 | ||
58 | strcpy(shm, "hello"); | |
59 | ||
60 | pid = fork(); | |
61 | if (pid < 0) { | |
62 | return 5; | |
63 | } else if (pid == 0) { | |
64 | strcpy(shm, "bye"); | |
65 | return 6; | |
66 | } | |
67 | if (wait(&status) != pid) { | |
68 | return 7; | |
69 | } | |
70 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
71 | return 8; | |
72 | } | |
73 | if (strcmp(shm, "bye") != 0) { | |
74 | return 9; | |
75 | } | |
76 | return 0; | |
77 | } | |
78 | ],dnl | |
79 | AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support]) | |
80 | msg=yes,msg=no,msg=no) | |
81 | AC_MSG_RESULT([$msg]) | |
82 | ||
83 | AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support) | |
84 | AC_TRY_RUN([ | |
85 | #include <sys/types.h> | |
86 | #include <sys/wait.h> | |
87 | #include <sys/mman.h> | |
88 | #include <unistd.h> | |
89 | #include <string.h> | |
90 | ||
91 | #ifndef MAP_ANON | |
92 | # ifdef MAP_ANONYMOUS | |
93 | # define MAP_ANON MAP_ANONYMOUS | |
94 | # endif | |
95 | #endif | |
96 | #ifndef MAP_FAILED | |
97 | # define MAP_FAILED ((void*)-1) | |
98 | #endif | |
99 | ||
100 | int main() { | |
101 | pid_t pid; | |
102 | int status; | |
103 | char *shm; | |
104 | ||
105 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); | |
106 | if (shm == MAP_FAILED) { | |
107 | return 1; | |
108 | } | |
109 | ||
110 | strcpy(shm, "hello"); | |
111 | ||
112 | pid = fork(); | |
113 | if (pid < 0) { | |
114 | return 5; | |
115 | } else if (pid == 0) { | |
116 | strcpy(shm, "bye"); | |
117 | return 6; | |
118 | } | |
119 | if (wait(&status) != pid) { | |
120 | return 7; | |
121 | } | |
122 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
123 | return 8; | |
124 | } | |
125 | if (strcmp(shm, "bye") != 0) { | |
126 | return 9; | |
127 | } | |
128 | return 0; | |
129 | } | |
130 | ],dnl | |
131 | AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support]) | |
132 | msg=yes,msg=no,msg=no) | |
133 | AC_MSG_RESULT([$msg]) | |
134 | ||
135 | AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support) | |
136 | AC_TRY_RUN([ | |
137 | #include <sys/types.h> | |
138 | #include <sys/wait.h> | |
139 | #include <sys/mman.h> | |
140 | #include <sys/stat.h> | |
141 | #include <fcntl.h> | |
142 | #include <unistd.h> | |
143 | #include <string.h> | |
144 | ||
145 | #ifndef MAP_FAILED | |
146 | # define MAP_FAILED ((void*)-1) | |
147 | #endif | |
148 | ||
149 | int main() { | |
150 | pid_t pid; | |
151 | int status; | |
152 | int fd; | |
153 | char *shm; | |
154 | ||
155 | fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); | |
156 | if (fd == -1) { | |
157 | return 1; | |
158 | } | |
159 | ||
160 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | |
161 | if (shm == MAP_FAILED) { | |
162 | return 2; | |
163 | } | |
164 | ||
165 | strcpy(shm, "hello"); | |
166 | ||
167 | pid = fork(); | |
168 | if (pid < 0) { | |
169 | return 5; | |
170 | } else if (pid == 0) { | |
171 | strcpy(shm, "bye"); | |
172 | return 6; | |
173 | } | |
174 | if (wait(&status) != pid) { | |
175 | return 7; | |
176 | } | |
177 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
178 | return 8; | |
179 | } | |
180 | if (strcmp(shm, "bye") != 0) { | |
181 | return 9; | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | ],dnl | |
186 | AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support]) | |
187 | msg=yes,msg=no,msg=no) | |
188 | AC_MSG_RESULT([$msg]) | |
189 | ||
190 | dnl if test "$PHP_MSGPACK" != "no"; then | |
191 | dnl AC_DEFINE(ENABLE_MSGPACK,1,[enable msgpack packager]) | |
192 | dnl ifdef([PHP_ADD_EXTENSION_DEP], | |
193 | dnl [ | |
194 | dnl PHP_ADD_EXTENSION_DEP(yac, msgpack, true) | |
195 | dnl ]) | |
196 | dnl fi | |
197 | ||
198 | YAC_FILES="yac.c storage/yac_storage.c storage/allocator/yac_allocator.c storage/allocator/allocators/shm.c storage/allocator/allocators/mmap.c serializer/php.c serializer/msgpack.c" | |
199 | if test "$PHP_SYSTEM_FASTLZ" != "no"; then | |
200 | AC_CHECK_HEADERS([fastlz.h]) | |
201 | PHP_CHECK_LIBRARY(fastlz, fastlz_compress, | |
202 | [PHP_ADD_LIBRARY(fastlz, 1, YAC_SHARED_LIBADD)], | |
203 | [AC_MSG_ERROR(FastLZ library not found)]) | |
204 | else | |
205 | YAC_FILES="${YAC_FILES} compressor/fastlz/fastlz.c" | |
206 | fi | |
207 | ||
208 | if test "$PHP_YAC" != "no"; then | |
209 | PHP_SUBST(YAC_SHARED_LIBADD) | |
210 | PHP_NEW_EXTENSION(yac, ${YAC_FILES}, $ext_shared) | |
211 | PHP_ADD_BUILD_DIR([$ext_builddir/storage]) | |
212 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator]) | |
213 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator/allocators]) | |
214 | PHP_ADD_BUILD_DIR([$ext_builddir/serializer]) | |
215 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor]) | |
216 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor/fastlz]) | |
217 | fi |
0 | // $Id$ | |
1 | // vim:ft=javascript | |
2 | ||
3 | ARG_ENABLE("yac", "enable yac support", "no"); | |
4 | ||
5 | if (PHP_YAC != "no") { | |
6 | if( CHECK_HEADER_ADD_INCLUDE("fastlz.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\compressor\\fastlz") && | |
7 | CHECK_HEADER_ADD_INCLUDE("yac_serializer.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\serializer") && | |
8 | CHECK_HEADER_ADD_INCLUDE("yac_storage.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage") && | |
9 | CHECK_HEADER_ADD_INCLUDE("yac_allocator.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage\\allocator")) { | |
10 | ||
11 | EXTENSION("yac", "yac.c"); | |
12 | ||
13 | ADD_SOURCES(configure_module_dirname + "\\compressor\\fastlz", "fastlz.c", "yac"); | |
14 | ADD_SOURCES(configure_module_dirname + "\\serializer", "php.c", "yac"); | |
15 | ADD_SOURCES(configure_module_dirname + "\\storage", "yac_storage.c", "yac"); | |
16 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator", "yac_allocator.c", "yac"); | |
17 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator\\allocators", "createfilemapping.c", "yac"); | |
18 | ||
19 | AC_DEFINE('HAVE_YAC', 1, 'Have yac library'); | |
20 | ||
21 | ADD_FLAG("CFLAGS_YAC", ' /I "' + configure_module_dirname + '" '); | |
22 | ||
23 | } else { | |
24 | WARNING("yac not enabled, headers not found"); | |
25 | } | |
26 | } | |
27 |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef PHP_YAC_H | |
21 | #define PHP_YAC_H | |
22 | ||
23 | extern zend_module_entry yac_module_entry; | |
24 | #define phpext_yac_ptr &yac_module_entry | |
25 | ||
26 | #ifdef PHP_WIN32 | |
27 | #define PHP_YAC_API __declspec(dllexport) | |
28 | #else | |
29 | #define PHP_YAC_API | |
30 | #endif | |
31 | ||
32 | #ifdef ZTS | |
33 | #include "TSRM.h" | |
34 | #endif | |
35 | ||
36 | #define PHP_YAC_VERSION "2.0.4" | |
37 | ||
38 | #define YAC_CLASS_PROPERTY_PREFIX "_prefix" | |
39 | #define YAC_ENTRY_COMPRESSED 0x0020 | |
40 | #define YAC_ENTRY_TYPE_MASK 0x1f | |
41 | #define YAC_ENTRY_ORIG_LEN_SHIT 6 | |
42 | #define YAC_ENTRY_MAX_ORIG_LEN ((1U << ((sizeof(int)*8 - YAC_ENTRY_ORIG_LEN_SHIT))) - 1) | |
43 | #define YAC_MIN_COMPRESS_THRESHOLD 1024 | |
44 | ||
45 | ZEND_BEGIN_MODULE_GLOBALS(yac) | |
46 | zend_bool enable; | |
47 | zend_bool debug; | |
48 | size_t k_msize; | |
49 | size_t v_msize; | |
50 | zend_ulong compress_threshold; | |
51 | zend_bool enable_cli; | |
52 | #ifdef PHP_WIN32 | |
53 | char *mmap_base; | |
54 | #endif | |
55 | ZEND_END_MODULE_GLOBALS(yac) | |
56 | ||
57 | PHP_MINIT_FUNCTION(yac); | |
58 | PHP_MSHUTDOWN_FUNCTION(yac); | |
59 | PHP_RINIT_FUNCTION(yac); | |
60 | PHP_RSHUTDOWN_FUNCTION(yac); | |
61 | PHP_MINFO_FUNCTION(yac); | |
62 | ||
63 | #ifdef ZTS | |
64 | #define YAC_G(v) TSRMG(yac_globals_id, zend_yac_globals *, v) | |
65 | extern int yac_globals_id; | |
66 | #else | |
67 | #define YAC_G(v) (yac_globals.v) | |
68 | extern zend_yac_globals yac_globals; | |
69 | #endif | |
70 | ||
71 | #endif /* PHP_YAC_H */ | |
72 | /* | |
73 | * Local variables: | |
74 | * tab-width: 4 | |
75 | * c-basic-offset: 4 | |
76 | * End: | |
77 | * vim600: noet sw=4 ts=4 fdm=marker | |
78 | * vim<600: noet sw=4 ts=4 | |
79 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yar - Light, concurrent RPC framework | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2012-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | | Zhenyu Zhang <zhangzhenyu@php.net> | | |
16 | +----------------------------------------------------------------------+ | |
17 | */ | |
18 | ||
19 | /* $Id$ */ | |
20 | ||
21 | #ifdef HAVE_CONFIG_H | |
22 | #include "config.h" | |
23 | #endif | |
24 | ||
25 | #ifdef ENABLE_MSGPACK | |
26 | ||
27 | #include "php.h" | |
28 | #include "zend_smart_str.h" /* for smart_str */ | |
29 | ||
30 | #include "yac_serializer.h" | |
31 | ||
32 | extern void php_msgpack_serialize(smart_str *buf, zval *val); | |
33 | extern void php_msgpack_unserialize(zval *return_value, char *str, size_t str_len); | |
34 | ||
35 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
36 | php_msgpack_serialize(buf, pzval); | |
37 | return 1; | |
38 | } /* }}} */ | |
39 | ||
40 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
41 | ZVAL_NULL(rv); | |
42 | php_msgpack_unserialize(rv, content, len); | |
43 | return rv; | |
44 | } /* }}} */ | |
45 | ||
46 | #endif | |
47 | ||
48 | /* | |
49 | * Local variables: | |
50 | * tab-width: 4 | |
51 | * c-basic-offset: 4 | |
52 | * End: | |
53 | * vim600: noet sw=4 ts=4 fdm=marker | |
54 | * vim<600: noet sw=4 ts=4 | |
55 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifdef HAVE_CONFIG_H | |
21 | #include "config.h" | |
22 | #endif | |
23 | ||
24 | #if !ENABLE_MSGPACK | |
25 | ||
26 | #include "php.h" | |
27 | #include "ext/standard/php_var.h" /* for serialize */ | |
28 | #include "zend_smart_str.h" | |
29 | ||
30 | #include "yac_serializer.h" | |
31 | ||
32 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
33 | php_serialize_data_t var_hash; | |
34 | ||
35 | PHP_VAR_SERIALIZE_INIT(var_hash); | |
36 | php_var_serialize(buf, pzval, &var_hash); | |
37 | PHP_VAR_SERIALIZE_DESTROY(var_hash); | |
38 | ||
39 | return 1; | |
40 | } /* }}} */ | |
41 | ||
42 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
43 | const unsigned char *p; | |
44 | php_unserialize_data_t var_hash; | |
45 | p = (const unsigned char*)content; | |
46 | ||
47 | ZVAL_FALSE(rv); | |
48 | PHP_VAR_UNSERIALIZE_INIT(var_hash); | |
49 | if (!php_var_unserialize(rv, &p, p + len, &var_hash)) { | |
50 | zval_ptr_dtor(rv); | |
51 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
52 | spprintf(msg, 0, "unpack error at offset %ld of %ld bytes", (long)((char*)p - content), len); | |
53 | return NULL; | |
54 | } | |
55 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
56 | ||
57 | return rv; | |
58 | } /* }}} */ | |
59 | ||
60 | #endif | |
61 | ||
62 | /* | |
63 | * Local variables: | |
64 | * tab-width: 4 | |
65 | * c-basic-offset: 4 | |
66 | * End: | |
67 | * vim600: noet sw=4 ts=4 fdm=marker | |
68 | * vim<600: noet sw=4 ts=4 | |
69 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef YAC_SERIALIZER_H | |
21 | #define YAC_SERIALIZER_H | |
22 | ||
23 | #if ENABLE_MSGPACK | |
24 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg); | |
25 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv); | |
26 | #else | |
27 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg); | |
28 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv); | |
29 | #endif | |
30 | ||
31 | #endif /* YAC_SERIALIZER_H */ | |
32 | ||
33 | /* | |
34 | * Local variables: | |
35 | * tab-width: 4 | |
36 | * c-basic-offset: 4 | |
37 | * End: | |
38 | * vim600: noet sw=4 ts=4 fdm=marker | |
39 | * vim<600: noet sw=4 ts=4 | |
40 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | | Dmitry Stogov <dmitry@zend.com> | | |
16 | | Wei Dai <demon@php.net> | | |
17 | +----------------------------------------------------------------------+ | |
18 | */ | |
19 | ||
20 | #include "php.h" | |
21 | ||
22 | #include "php_yac.h" | |
23 | #include "storage/yac_storage.h" | |
24 | #include "storage/allocator/yac_allocator.h" | |
25 | ||
26 | #include <stdio.h> | |
27 | #include <windows.h> | |
28 | #include <Lmcons.h> | |
29 | ||
30 | #define ACCEL_FILEMAP_NAME "Yac.SharedMemoryArea" | |
31 | #define ACCEL_FILEMAP_BASE "Yac.MemoryBase" | |
32 | #define MAX_MAP_RETRIES 25 | |
33 | ||
34 | static HANDLE memfile = NULL; | |
35 | static void *mapping_base; | |
36 | ||
37 | typedef struct { | |
38 | yac_shared_segment common; | |
39 | unsigned long size; | |
40 | } yac_shared_segment_create_file; | |
41 | ||
42 | #ifdef USE_FILE_MAPPING | |
43 | static char *create_name_with_username(char *name) /* {{{ */ { | |
44 | static char newname[MAXPATHLEN + UNLEN + 4]; | |
45 | char uname[UNLEN + 1]; | |
46 | DWORD unsize = UNLEN; | |
47 | ||
48 | GetUserName(uname, &unsize); | |
49 | snprintf(newname, sizeof(newname) - 1, "%s@%s", name, uname); | |
50 | return newname; | |
51 | } | |
52 | /* }}} */ | |
53 | ||
54 | static char *get_mmap_base_file(void) /* {{{ */ { | |
55 | static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@")]; | |
56 | char uname[UNLEN + 1]; | |
57 | DWORD unsize = UNLEN; | |
58 | int l; | |
59 | ||
60 | GetTempPath(MAXPATHLEN, windir); | |
61 | GetUserName(uname, &unsize); | |
62 | l = strlen(windir); | |
63 | snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s", ACCEL_FILEMAP_BASE, uname); | |
64 | return windir; | |
65 | } | |
66 | /* }}} */ | |
67 | ||
68 | static int yac_shared_alloc_reattach(size_t requested_size, char **error_in) /* {{{ */ { | |
69 | void *wanted_mapping_base; | |
70 | char *mmap_base_file = get_mmap_base_file(); | |
71 | FILE *fp = fopen(mmap_base_file, "r"); | |
72 | MEMORY_BASIC_INFORMATION info; | |
73 | ||
74 | if (!fp) { | |
75 | *error_in="fopen"; | |
76 | return ALLOC_FAILURE; | |
77 | } | |
78 | ||
79 | if (!fscanf(fp, "%p", &wanted_mapping_base)) { | |
80 | *error_in="read mapping base"; | |
81 | fclose(fp); | |
82 | return ALLOC_FAILURE; | |
83 | } | |
84 | fclose(fp); | |
85 | ||
86 | /* Check if the requested address space is free */ | |
87 | if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0) { | |
88 | *error_in="VirtualQuery"; | |
89 | return ALLOC_FAILURE; | |
90 | } | |
91 | ||
92 | if (info.State != MEM_FREE) { | |
93 | *error_in="info.State"; | |
94 | return ALLOC_FAILURE; | |
95 | } | |
96 | ||
97 | if (info.RegionSize < requested_size) { | |
98 | *error_in="info.RegionSize"; | |
99 | return ALLOC_FAILURE; | |
100 | } | |
101 | ||
102 | mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base); | |
103 | ||
104 | if (mapping_base == NULL) { | |
105 | return ALLOC_FAIL_MAPPING; | |
106 | } | |
107 | ||
108 | return SUCCESSFULLY_REATTACHED; | |
109 | } | |
110 | /* }}} */ | |
111 | ||
112 | static int create_segments(unsigned long k_size, unsigned long v_size, yac_shared_segment_create_file **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
113 | int ret; | |
114 | unsigned long allocate_size, occupied_size = 0; | |
115 | unsigned int i, segment_size, segments_num = 1024, is_reattach = 0; | |
116 | int map_retries = 0; | |
117 | yac_shared_segment_create_file first_segment; | |
118 | void *default_mapping_base_set[] = {0, 0}; | |
119 | /* TODO: | |
120 | improve fixed addresses on x64. It still makes no sense to do it as Windows addresses are virtual per se and can or should be randomized anyway | |
121 | through Address Space Layout Radomization (ASLR). We can still let the OS do its job and be sure that each process gets the same address if | |
122 | desired. Not done yet, @zend refused but did not remember the exact reason, pls add info here if one of you know why :) | |
123 | */ | |
124 | #if defined(_WIN64) | |
125 | void *vista_mapping_base_set[] = { (void *) 0x0000100000000000, (void *) 0x0000200000000000, (void *) 0x0000300000000000, (void *) 0x0000700000000000, 0 }; | |
126 | #else | |
127 | void *vista_mapping_base_set[] = { (void *) 0x20000000, (void *) 0x21000000, (void *) 0x30000000, (void *) 0x31000000, (void *) 0x50000000, 0 }; | |
128 | #endif | |
129 | void **wanted_mapping_base = default_mapping_base_set; | |
130 | ||
131 | ||
132 | k_size = YAC_SMM_ALIGNED_SIZE(k_size); | |
133 | v_size = YAC_SMM_ALIGNED_SIZE(v_size); | |
134 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
135 | segments_num >>= 1; | |
136 | } | |
137 | ||
138 | segment_size = v_size / segments_num; | |
139 | ++segments_num; | |
140 | ||
141 | allocate_size = k_size + v_size; | |
142 | ||
143 | /* Mapping retries: When Apache2 restarts, the parent process startup routine | |
144 | can be called before the child process is killed. In this case, the map will fail | |
145 | and we have to sleep some time (until the child releases the mapping object) and retry.*/ | |
146 | do { | |
147 | memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME)); | |
148 | if (memfile == NULL) { | |
149 | break; | |
150 | } | |
151 | ||
152 | ret = yac_shared_alloc_reattach((size_t)k_size, error_in); | |
153 | if (ret == ALLOC_FAIL_MAPPING) { | |
154 | /* Mapping failed, wait for mapping object to get freed and retry */ | |
155 | CloseHandle(memfile); | |
156 | memfile = NULL; | |
157 | Sleep(1000 * (map_retries + 1)); | |
158 | } else if (ret == SUCCESSFULLY_REATTACHED) { | |
159 | is_reattach = 1; | |
160 | break; | |
161 | } else { | |
162 | return ret; | |
163 | } | |
164 | } while (++map_retries < MAX_MAP_RETRIES); | |
165 | ||
166 | if (map_retries == MAX_MAP_RETRIES) { | |
167 | *error_in = "OpenFileMapping"; | |
168 | return 0; | |
169 | } | |
170 | ||
171 | *shared_segments_p = (yac_shared_segment_create_file *)calloc(1, segments_num * sizeof(yac_shared_segment_create_file)); | |
172 | if(!*shared_segments_p) { | |
173 | *error_in = "calloc"; | |
174 | return 0; | |
175 | } | |
176 | *shared_segments_count = segments_num; | |
177 | ||
178 | /* Starting from windows Vista, heap randomization occurs which might cause our mapping base to | |
179 | be taken (fail to map). So under Vista, we try to map into a hard coded predefined addresses | |
180 | in high memory. */ | |
181 | if (!YAC_G(mmap_base) || !*YAC_G(mmap_base)) { | |
182 | do { | |
183 | OSVERSIONINFOEX osvi; | |
184 | SYSTEM_INFO si; | |
185 | ||
186 | ZeroMemory(&si, sizeof(SYSTEM_INFO)); | |
187 | ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | |
188 | ||
189 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
190 | ||
191 | if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) { | |
192 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
193 | if (!GetVersionEx((OSVERSIONINFO *)&osvi)) { | |
194 | break; | |
195 | } | |
196 | } | |
197 | ||
198 | GetSystemInfo(&si); | |
199 | ||
200 | /* Are we running Vista ? */ | |
201 | if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6) { | |
202 | wanted_mapping_base = vista_mapping_base_set; | |
203 | } | |
204 | } while (0); | |
205 | } else { | |
206 | char *s = YAC_G(mmap_base); | |
207 | ||
208 | /* skip leading 0x, %p assumes hexdeciaml format anyway */ | |
209 | if (*s == '0' && *(s + 1) == 'x') { | |
210 | s += 2; | |
211 | } | |
212 | if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) { | |
213 | *error_in = "mapping"; | |
214 | return 0; | |
215 | } | |
216 | } | |
217 | ||
218 | if (is_reattach == 0) { | |
219 | memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, allocate_size, create_name_with_username(ACCEL_FILEMAP_NAME)); | |
220 | if (memfile == NULL) { | |
221 | *error_in = "CreateFileMapping"; | |
222 | return 0; | |
223 | } | |
224 | ||
225 | do { | |
226 | first_segment.common.p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base); | |
227 | if (wanted_mapping_base == NULL) { | |
228 | break; | |
229 | } | |
230 | *wanted_mapping_base++; | |
231 | } while (!mapping_base); | |
232 | } | |
233 | ||
234 | if(mapping_base == NULL) { | |
235 | *error_in = "MapViewOfFileEx"; | |
236 | return 0; | |
237 | } else { | |
238 | char *mmap_base_file = get_mmap_base_file(); | |
239 | FILE *fp = fopen(mmap_base_file, "w"); | |
240 | if (!fp) { | |
241 | *error_in = "get_mmap_base_file"; | |
242 | return 0; | |
243 | } | |
244 | fprintf(fp, "%p", mapping_base); | |
245 | fclose(fp); | |
246 | } | |
247 | ||
248 | first_segment.common.p = mapping_base; | |
249 | first_segment.size = allocate_size; | |
250 | first_segment.common.size = k_size; | |
251 | first_segment.common.pos = 0; | |
252 | ||
253 | (*shared_segments_p)[0] = first_segment; | |
254 | ||
255 | occupied_size = k_size; | |
256 | for (i = 1; i < segments_num; i++) { | |
257 | (*shared_segments_p)[i].size = 0; | |
258 | (*shared_segments_p)[i].common.pos = 0; | |
259 | (*shared_segments_p)[i].common.p = (void *)((char *)first_segment.common.p + occupied_size); | |
260 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) { | |
261 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
262 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size); | |
263 | } else { | |
264 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size); | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | return 1; | |
270 | } | |
271 | /* }}} */ | |
272 | ||
273 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ { | |
274 | if (!shared_segment->size && mapping_base) { | |
275 | UnmapViewOfFile(mapping_base); | |
276 | CloseHandle(memfile); | |
277 | } | |
278 | return 0; | |
279 | } | |
280 | /* }}} */ | |
281 | ||
282 | static unsigned long segment_type_size(void) /* {{{ */ { | |
283 | return sizeof(yac_shared_segment_create_file); | |
284 | } | |
285 | /* }}} */ | |
286 | ||
287 | yac_shared_memory_handlers yac_alloc_create_file_handlers = /* {{{ */ { | |
288 | (create_segments_t)create_segments, | |
289 | detach_segment, | |
290 | segment_type_size | |
291 | }; | |
292 | /* }}} */ | |
293 | #endif /* USE_CREATE_FILE */ | |
294 | ||
295 | /* | |
296 | * Local variables: | |
297 | * tab-width: 4 | |
298 | * c-basic-offset: 4 | |
299 | * End: | |
300 | * vim600: noet sw=4 ts=4 fdm=marker | |
301 | * vim<600: noet sw=4 ts=4 | |
302 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include "storage/yac_storage.h" | |
19 | #include "storage/allocator/yac_allocator.h" | |
20 | ||
21 | #ifdef USE_MMAP | |
22 | ||
23 | #include <sys/types.h> | |
24 | #include <sys/stat.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <sys/mman.h> | |
28 | ||
29 | #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) | |
30 | # define MAP_ANONYMOUS MAP_ANON | |
31 | #endif | |
32 | ||
33 | #ifndef MAP_FAILED | |
34 | #define MAP_FAILED (void *)-1 | |
35 | #endif | |
36 | ||
37 | typedef struct { | |
38 | yac_shared_segment common; | |
39 | unsigned long size; | |
40 | } yac_shared_segment_mmap; | |
41 | ||
42 | static int create_segments(unsigned long k_size, unsigned long v_size, yac_shared_segment_mmap **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
43 | unsigned long allocate_size, occupied_size = 0; | |
44 | unsigned int i, segment_size, segments_num = 1024; | |
45 | yac_shared_segment_mmap first_segment; | |
46 | ||
47 | k_size = YAC_SMM_ALIGNED_SIZE(k_size); | |
48 | v_size = YAC_SMM_ALIGNED_SIZE(v_size); | |
49 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
50 | segments_num >>= 1; | |
51 | } | |
52 | ||
53 | segment_size = v_size / segments_num; | |
54 | ++segments_num; | |
55 | ||
56 | allocate_size = k_size + v_size; | |
57 | ||
58 | first_segment.common.p = mmap(0, allocate_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); | |
59 | if (first_segment.common.p == MAP_FAILED) { | |
60 | *error_in = "mmap"; | |
61 | return 0; | |
62 | } | |
63 | first_segment.size = allocate_size; | |
64 | first_segment.common.size = k_size; | |
65 | first_segment.common.pos = 0; | |
66 | ||
67 | *shared_segments_p = (yac_shared_segment_mmap *)calloc(1, segments_num * sizeof(yac_shared_segment_mmap)); | |
68 | if (!*shared_segments_p) { | |
69 | munmap(first_segment.common.p, first_segment.size); | |
70 | *error_in = "calloc"; | |
71 | return 0; | |
72 | } else { | |
73 | *shared_segments_p[0] = first_segment; | |
74 | } | |
75 | *shared_segments_count = segments_num; | |
76 | ||
77 | occupied_size = k_size; | |
78 | for (i = 1; i < segments_num; i++) { | |
79 | (*shared_segments_p)[i].size = 0; | |
80 | (*shared_segments_p)[i].common.pos = 0; | |
81 | (*shared_segments_p)[i].common.p = first_segment.common.p + occupied_size; | |
82 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) { | |
83 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
84 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size); | |
85 | } else { | |
86 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size); | |
87 | break; | |
88 | } | |
89 | } | |
90 | ||
91 | return 1; | |
92 | } | |
93 | /* }}} */ | |
94 | ||
95 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ { | |
96 | if (shared_segment->size) { | |
97 | munmap(shared_segment->p, shared_segment->size); | |
98 | } | |
99 | return 0; | |
100 | } | |
101 | /* }}} */ | |
102 | ||
103 | static unsigned long segment_type_size(void) /* {{{ */ { | |
104 | return sizeof(yac_shared_segment_mmap); | |
105 | } | |
106 | /* }}} */ | |
107 | ||
108 | yac_shared_memory_handlers yac_alloc_mmap_handlers = /* {{{ */ { | |
109 | (create_segments_t)create_segments, | |
110 | detach_segment, | |
111 | segment_type_size | |
112 | }; | |
113 | /* }}} */ | |
114 | ||
115 | #endif /* USE_MMAP */ | |
116 | ||
117 | /* | |
118 | * Local variables: | |
119 | * tab-width: 4 | |
120 | * c-basic-offset: 4 | |
121 | * End: | |
122 | * vim600: noet sw=4 ts=4 fdm=marker | |
123 | * vim<600: noet sw=4 ts=4 | |
124 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include "storage/yac_storage.h" | |
19 | #include "storage/allocator/yac_allocator.h" | |
20 | ||
21 | #ifdef USE_SHM | |
22 | ||
23 | #if defined(__FreeBSD__) | |
24 | # include <machine/param.h> | |
25 | #endif | |
26 | #include <sys/types.h> | |
27 | #include <sys/shm.h> | |
28 | #include <sys/ipc.h> | |
29 | #include <dirent.h> | |
30 | #include <signal.h> | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <unistd.h> | |
34 | #include <errno.h> | |
35 | ||
36 | #include <sys/stat.h> | |
37 | #include <fcntl.h> | |
38 | ||
39 | typedef struct { | |
40 | yac_shared_segment common; | |
41 | int shm_id; | |
42 | } yac_shared_segment_shm; | |
43 | ||
44 | static int create_segments(size_t k_size, size_t v_size, yac_shared_segment_shm **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
45 | struct shmid_ds sds; | |
46 | int shm_id, shmget_flags; | |
47 | yac_shared_segment_shm *shared_segments, first_segment; | |
48 | unsigned int i, j, allocate_size, allocated_num, segments_num, segment_size; | |
49 | ||
50 | shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; | |
51 | segments_num = 1024; | |
52 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
53 | segments_num >>= 1; | |
54 | } | |
55 | segment_size = v_size / segments_num; | |
56 | allocate_size = YAC_SMM_SEGMENT_MAX_SIZE; | |
57 | ||
58 | while ((shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags)) < 0) { | |
59 | allocate_size >>= 1; | |
60 | } | |
61 | ||
62 | if (shm_id < 0) { | |
63 | /* this should never happen */ | |
64 | *error_in = "shmget"; | |
65 | return 0; | |
66 | } | |
67 | ||
68 | if (allocate_size < YAC_SMM_SEGMENT_MIN_SIZE) { | |
69 | /* this should never happen */ | |
70 | *error_in = "shmget"; | |
71 | return 0; | |
72 | } | |
73 | ||
74 | if (k_size <= allocate_size) { | |
75 | first_segment.shm_id = shm_id; | |
76 | first_segment.common.pos = 0; | |
77 | first_segment.common.size = allocate_size; | |
78 | first_segment.common.p = shmat(shm_id, NULL, 0); | |
79 | shmctl(shm_id, IPC_RMID, &sds); | |
80 | if (first_segment.common.p == (void *)-1) { | |
81 | *error_in = "shmat"; | |
82 | return 0; | |
83 | } | |
84 | } else { | |
85 | shmctl(shm_id, IPC_RMID, &sds); | |
86 | *error_in = "shmget"; | |
87 | return 0; | |
88 | } | |
89 | ||
90 | allocated_num = (v_size % allocate_size)? (v_size / allocate_size) + 1 : (v_size / allocate_size); | |
91 | shared_segments = (yac_shared_segment_shm *)calloc(1, (allocated_num) * sizeof(yac_shared_segment_shm)); | |
92 | if (!shared_segments) { | |
93 | *error_in = "calloc"; | |
94 | return 0; | |
95 | } | |
96 | ||
97 | for (i = 0; i < allocated_num; i ++) { | |
98 | shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags); | |
99 | if (shm_id == -1) { | |
100 | *error_in = "shmget"; | |
101 | for (j = 0; j < i; j++) { | |
102 | shmdt(shared_segments[j].common.p); | |
103 | } | |
104 | free(shared_segments); | |
105 | return 0; | |
106 | } | |
107 | shared_segments[i].shm_id = shm_id; | |
108 | shared_segments[i].common.pos = 0; | |
109 | shared_segments[i].common.size = allocate_size; | |
110 | shared_segments[i].common.p = shmat(shm_id, NULL, 0); | |
111 | shmctl(shm_id, IPC_RMID, &sds); | |
112 | if (shared_segments[i].common.p == (void *)-1) { | |
113 | *error_in = "shmat"; | |
114 | for (j = 0; j < i; j++) { | |
115 | shmdt(shared_segments[j].common.p); | |
116 | } | |
117 | free(shared_segments); | |
118 | return 0; | |
119 | } | |
120 | } | |
121 | ||
122 | ++segments_num; | |
123 | *shared_segments_p = (yac_shared_segment_shm *)calloc(1, segments_num * sizeof(yac_shared_segment_shm)); | |
124 | if (!*shared_segments_p) { | |
125 | free(shared_segments); | |
126 | *error_in = "calloc"; | |
127 | return 0; | |
128 | } else { | |
129 | *shared_segments_p[0] = first_segment; | |
130 | } | |
131 | *shared_segments_count = segments_num; | |
132 | ||
133 | j = 0; | |
134 | for (i = 1; i < segments_num; i++) { | |
135 | if (shared_segments[j].common.pos == 0) { | |
136 | (*shared_segments_p)[i].shm_id = shared_segments[j].shm_id; | |
137 | } | |
138 | ||
139 | if ((shared_segments[j].common.size - shared_segments[j].common.pos) >= (2 * YAC_SMM_ALIGNED_SIZE(segment_size))) { | |
140 | (*shared_segments_p)[i].common.pos = 0; | |
141 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
142 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); | |
143 | shared_segments[j].common.pos += YAC_SMM_ALIGNED_SIZE(segment_size); | |
144 | } else { | |
145 | (*shared_segments_p)[i].common.pos = 0; | |
146 | (*shared_segments_p)[i].common.size = shared_segments[j].common.size - shared_segments[j].common.pos; | |
147 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); | |
148 | j++; | |
149 | } | |
150 | } | |
151 | ||
152 | free(shared_segments); | |
153 | ||
154 | return 1; | |
155 | } | |
156 | /* }}} */ | |
157 | ||
158 | static int detach_segment(yac_shared_segment_shm *shared_segment) /* {{{ */ { | |
159 | if (shared_segment->shm_id) { | |
160 | shmdt(shared_segment->common.p); | |
161 | } | |
162 | return 1; | |
163 | } | |
164 | /* }}} */ | |
165 | ||
166 | static size_t segment_type_size(void) /* {{{ */ { | |
167 | return sizeof(yac_shared_segment_shm); | |
168 | } | |
169 | /* }}} */ | |
170 | ||
171 | yac_shared_memory_handlers yac_alloc_shm_handlers = /* {{{ */ { | |
172 | (create_segments_t)create_segments, | |
173 | (detach_segment_t)detach_segment, | |
174 | segment_type_size | |
175 | }; | |
176 | /* }}} */ | |
177 | ||
178 | #endif /* USE_SHM */ | |
179 | ||
180 | /* | |
181 | * Local variables: | |
182 | * tab-width: 4 | |
183 | * c-basic-offset: 4 | |
184 | * End: | |
185 | * vim600: noet sw=4 ts=4 fdm=marker | |
186 | * vim<600: noet sw=4 ts=4 | |
187 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include <errno.h> | |
19 | #include <time.h> | |
20 | #include <sys/types.h> | |
21 | ||
22 | #include "php.h" | |
23 | #include "storage/yac_storage.h" | |
24 | #include "yac_allocator.h" | |
25 | ||
26 | static const yac_shared_memory_handlers *shared_memory_handler = NULL; | |
27 | static const char *shared_model; | |
28 | ||
29 | int yac_allocator_startup(unsigned long k_size, unsigned long size, char **msg) /* {{{ */ { | |
30 | char *p; | |
31 | yac_shared_segment *segments = NULL; | |
32 | int i, segments_num, segments_array_size, segment_size; | |
33 | const yac_shared_memory_handlers *he; | |
34 | ||
35 | if ((he = &yac_shared_memory_handler)) { | |
36 | int ret = he->create_segments(k_size, size, &segments, &segments_num, msg); | |
37 | ||
38 | if (!ret) { | |
39 | if (segments) { | |
40 | int i; | |
41 | for (i = 0; i < segments_num; i++) { | |
42 | if (segments[i].p && segments[i].p != (void *)-1) { | |
43 | he->detach_segment(&segments[i]); | |
44 | } | |
45 | } | |
46 | free(segments); | |
47 | } | |
48 | return 0; | |
49 | } | |
50 | } else { | |
51 | return 0; | |
52 | } | |
53 | ||
54 | segment_size = he->segment_type_size(); | |
55 | segments_array_size = (segments_num - 1) * segment_size; | |
56 | ||
57 | yac_storage = segments[0].p; | |
58 | memcpy(&YAC_SG(first_seg), (char *)(&segments[0]), segment_size); | |
59 | ||
60 | YAC_SG(segments_num) = segments_num - 1; | |
61 | YAC_SG(segments_num_mask) = YAC_SG(segments_num) - 1; | |
62 | YAC_SG(segments) = (yac_shared_segment **)((char *)yac_storage + YAC_SMM_ALIGNED_SIZE(sizeof(yac_storage_globals) + segment_size - sizeof(yac_shared_segment))); | |
63 | ||
64 | p = (char *)YAC_SG(segments) + (sizeof(void *) * YAC_SG(segments_num)); | |
65 | memcpy(p, (char *)segments + segment_size, segments_array_size); | |
66 | for (i = 0; i < YAC_SG(segments_num); i++) { | |
67 | YAC_SG(segments)[i] = (yac_shared_segment *)p; | |
68 | p += segment_size; | |
69 | } | |
70 | YAC_SG(slots) = (yac_kv_key *)((char *)YAC_SG(segments) | |
71 | + (YAC_SG(segments_num) * sizeof(void *)) + YAC_SMM_ALIGNED_SIZE(segments_array_size)); | |
72 | ||
73 | free(segments); | |
74 | ||
75 | return 1; | |
76 | } | |
77 | /* }}} */ | |
78 | ||
79 | void yac_allocator_shutdown(void) /* {{{ */ { | |
80 | yac_shared_segment **segments; | |
81 | const yac_shared_memory_handlers *he; | |
82 | ||
83 | segments = YAC_SG(segments); | |
84 | if (segments) { | |
85 | if ((he = &yac_shared_memory_handler)) { | |
86 | int i = 0; | |
87 | for (i = 0; i < YAC_SG(segments_num); i++) { | |
88 | he->detach_segment(segments[i]); | |
89 | } | |
90 | he->detach_segment(&YAC_SG(first_seg)); | |
91 | } | |
92 | } | |
93 | } | |
94 | /* }}} */ | |
95 | ||
96 | static inline void *yac_allocator_alloc_algo2(unsigned long size, int hash) /* {{{ */ { | |
97 | yac_shared_segment *segment; | |
98 | unsigned int seg_size, retry, pos, current; | |
99 | ||
100 | current = hash & YAC_SG(segments_num_mask); | |
101 | /* do we really need lock here? it depends the real life exam */ | |
102 | retry = 3; | |
103 | do_retry: | |
104 | segment = YAC_SG(segments)[current]; | |
105 | seg_size = segment->size; | |
106 | pos = segment->pos; | |
107 | if ((seg_size - pos) >= size) { | |
108 | do_alloc: | |
109 | pos += size; | |
110 | segment->pos = pos; | |
111 | if (segment->pos == pos) { | |
112 | return (void *)((char *)segment->p + (pos - size)); | |
113 | } else if (retry--) { | |
114 | goto do_retry; | |
115 | } | |
116 | return NULL; | |
117 | } else { | |
118 | int i, max; | |
119 | max = (YAC_SG(segments_num) > 4)? 4 : YAC_SG(segments_num); | |
120 | for (i = 1; i < max; i++) { | |
121 | segment = YAC_SG(segments)[(current + i) & YAC_SG(segments_num_mask)]; | |
122 | seg_size = segment->size; | |
123 | pos = segment->pos; | |
124 | if ((seg_size - pos) >= size) { | |
125 | current = (current + i) & YAC_SG(segments_num_mask); | |
126 | goto do_alloc; | |
127 | } | |
128 | } | |
129 | segment->pos = 0; | |
130 | pos = 0; | |
131 | ++YAC_SG(recycles); | |
132 | goto do_alloc; | |
133 | } | |
134 | } | |
135 | /* }}} */ | |
136 | ||
137 | #if 0 | |
138 | static inline void *yac_allocator_alloc_algo1(unsigned long size) /* {{{ */ { | |
139 | int i, j, picked_seg, atime; | |
140 | picked_seg = (YAC_SG(current_seg) + 1) & YAC_SG(segments_num_mask); | |
141 | ||
142 | atime = YAC_SG(segments)[picked_seg]->atime; | |
143 | for (i = 0; i < 10; i++) { | |
144 | j = (picked_seg + 1) & YAC_SG(segments_num_mask); | |
145 | if (YAC_SG(segments)[j]->atime < atime) { | |
146 | picked_seg = j; | |
147 | atime = YAC_SG(segments)[j]->atime; | |
148 | } | |
149 | } | |
150 | ||
151 | YAC_SG(current_seg) = picked_seg; | |
152 | YAC_SG(segments)[picked_seg]->pos = 0; | |
153 | return yac_allocator_alloc_algo2(size); | |
154 | } | |
155 | /* }}} */ | |
156 | #endif | |
157 | ||
158 | unsigned long yac_allocator_real_size(unsigned long size) /* {{{ */ { | |
159 | unsigned long real_size = YAC_SMM_TRUE_SIZE(size); | |
160 | ||
161 | if (real_size > YAC_SG(segments)[0]->size) { | |
162 | return 0; | |
163 | } | |
164 | ||
165 | return real_size; | |
166 | } | |
167 | /* }}} */ | |
168 | ||
169 | void * yac_allocator_raw_alloc(unsigned long real_size, int hash) /* {{{ */ { | |
170 | ||
171 | return yac_allocator_alloc_algo2(real_size, hash); | |
172 | /* | |
173 | if (YAC_SG(exhausted)) { | |
174 | return yac_allocator_alloc_algo1(real_size); | |
175 | } else { | |
176 | void *p; | |
177 | if ((p = yac_allocator_alloc_algo2(real_size))) { | |
178 | return p; | |
179 | } | |
180 | return yac_allocator_alloc_algo1(real_size); | |
181 | } | |
182 | */ | |
183 | } | |
184 | /* }}} */ | |
185 | ||
186 | #if 0 | |
187 | void yac_allocator_touch(void *p, unsigned long atime) /* {{{ */ { | |
188 | yac_shared_block_header h = *(yac_shared_block_header *)(p - sizeof(yac_shared_block_header)); | |
189 | ||
190 | if (h.seg >= YAC_SG(segments_num)) { | |
191 | return; | |
192 | } | |
193 | ||
194 | YAC_SG(segments)[h.seg]->atime = atime; | |
195 | } | |
196 | /* }}} */ | |
197 | #endif | |
198 | ||
199 | /* | |
200 | * Local variables: | |
201 | * tab-width: 4 | |
202 | * c-basic-offset: 4 | |
203 | * End: | |
204 | * vim600: noet sw=4 ts=4 fdm=marker | |
205 | * vim<600: noet sw=4 ts=4 | |
206 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #ifndef YAC_ALLOCATOR_H | |
19 | #define YAC_ALLOCATOR_H | |
20 | ||
21 | #ifdef HAVE_CONFIG_H | |
22 | #include "config.h" | |
23 | #endif | |
24 | ||
25 | #define YAC_SMM_ALIGNMENT 8 | |
26 | #define YAC_SMM_ALIGNMENT_LOG2 3 | |
27 | #define YAC_SMM_ALIGNMENT_MASK ~(YAC_SMM_ALIGNMENT - 1) | |
28 | #define YAC_SMM_BLOCK_HEADER_SIZE YAC_SMM_ALIGNED_SIZE(sizeof(yac_shared_block_header)) | |
29 | ||
30 | #define YAC_SMM_MAIN_SEG_SIZE (4*1024*1024) | |
31 | #define YAC_SMM_SEGMENT_MAX_SIZE (32*1024*1024) | |
32 | #define YAC_SMM_SEGMENT_MIN_SIZE (4*1024*1024) | |
33 | #define YAC_SMM_MIN_BLOCK_SIZE 128 | |
34 | #define YAC_SMM_ALIGNED_SIZE(x) (((x) + YAC_SMM_ALIGNMENT - 1) & YAC_SMM_ALIGNMENT_MASK) | |
35 | #define YAC_SMM_TRUE_SIZE(x) ((x < YAC_SMM_MIN_BLOCK_SIZE)? (YAC_SMM_MIN_BLOCK_SIZE) : (YAC_SMM_ALIGNED_SIZE(x))) | |
36 | ||
37 | #ifdef PHP_WIN32 | |
38 | # define USE_FILE_MAPPING 1 | |
39 | # define inline __inline | |
40 | #elif defined(HAVE_SHM_MMAP_ANON) | |
41 | # define USE_MMAP 1 | |
42 | #elif defined(HAVE_SHM_IPC) | |
43 | # define USE_SHM 1 | |
44 | #else | |
45 | #error(no builtin shared memory supported) | |
46 | #endif | |
47 | ||
48 | #define ALLOC_FAILURE 0 | |
49 | #define ALLOC_SUCCESS 1 | |
50 | #define FAILED_REATTACHED 2 | |
51 | #define SUCCESSFULLY_REATTACHED 4 | |
52 | #define ALLOC_FAIL_MAPPING 8 | |
53 | ||
54 | typedef int (*create_segments_t)(unsigned long k_size, unsigned long v_size, yac_shared_segment **shared_segments, int *shared_segment_count, char **error_in); | |
55 | typedef int (*detach_segment_t)(yac_shared_segment *shared_segment); | |
56 | ||
57 | typedef struct { | |
58 | create_segments_t create_segments; | |
59 | detach_segment_t detach_segment; | |
60 | unsigned long (*segment_type_size)(void); | |
61 | } yac_shared_memory_handlers; | |
62 | ||
63 | typedef struct { | |
64 | const char *name; | |
65 | yac_shared_memory_handlers *handler; | |
66 | } yac_shared_memory_handler_entry; | |
67 | ||
68 | int yac_allocator_startup(unsigned long first_seg_size, unsigned long size, char **err); | |
69 | void yac_allocator_shutdown(void); | |
70 | unsigned long yac_allocator_real_size(unsigned long size); | |
71 | void *yac_allocator_raw_alloc(unsigned long real_size, int seg); | |
72 | int yac_allocator_free(void *p); | |
73 | ||
74 | static inline void * yac_allocator_alloc(unsigned long size, int seg) { | |
75 | unsigned long real_size = yac_allocator_real_size(size); | |
76 | if (!real_size) { | |
77 | return (void *)0; | |
78 | } | |
79 | return yac_allocator_raw_alloc(real_size, seg); | |
80 | } | |
81 | ||
82 | #if defined(USE_MMAP) | |
83 | extern yac_shared_memory_handlers yac_alloc_mmap_handlers; | |
84 | #define yac_shared_memory_handler yac_alloc_mmap_handlers | |
85 | #define YAC_SHARED_MEMORY_HANDLER_NAME "mmap" | |
86 | #elif defined(USE_SHM) | |
87 | extern yac_shared_memory_handlers yac_alloc_shm_handlers; | |
88 | #define yac_shared_memory_handler yac_alloc_shm_handlers | |
89 | #define YAC_SHARED_MEMORY_HANDLER_NAME "shm" | |
90 | #elif defined(USE_FILE_MAPPING) | |
91 | extern yac_shared_memory_handlers yac_alloc_create_file_handlers; | |
92 | #define yac_shared_memory_handler yac_alloc_create_file_handlers | |
93 | #define YAC_SHARED_MEMORY_HANDLER_NAME "file_mapping" | |
94 | #endif | |
95 | ||
96 | #endif /* YAC_ALLOCATOR_H */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #include "php.h" | |
21 | #include "yac_storage.h" | |
22 | #include "allocator/yac_allocator.h" | |
23 | ||
24 | yac_storage_globals *yac_storage; | |
25 | ||
26 | static inline unsigned int yac_storage_align_size(unsigned int size) /* {{{ */ { | |
27 | int bits = 0; | |
28 | while ((size = size >> 1)) { | |
29 | ++bits; | |
30 | } | |
31 | return (1 << bits); | |
32 | } | |
33 | /* }}} */ | |
34 | ||
35 | int yac_storage_startup(unsigned long fsize, unsigned long size, char **msg) /* {{{ */ { | |
36 | unsigned long real_size; | |
37 | ||
38 | if (!yac_allocator_startup(fsize, size, msg)) { | |
39 | return 0; | |
40 | } | |
41 | ||
42 | size = YAC_SG(first_seg).size - ((char *)YAC_SG(slots) - (char *)yac_storage); | |
43 | real_size = yac_storage_align_size(size / sizeof(yac_kv_key)); | |
44 | if (!((size / sizeof(yac_kv_key)) & ~(real_size << 1))) { | |
45 | real_size <<= 1; | |
46 | } | |
47 | ||
48 | YAC_SG(slots_size) = real_size; | |
49 | YAC_SG(slots_mask) = real_size - 1; | |
50 | YAC_SG(slots_num) = 0; | |
51 | YAC_SG(fails) = 0; | |
52 | YAC_SG(hits) = 0; | |
53 | YAC_SG(miss) = 0; | |
54 | YAC_SG(kicks) = 0; | |
55 | ||
56 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * real_size); | |
57 | ||
58 | return 1; | |
59 | } | |
60 | /* }}} */ | |
61 | ||
62 | void yac_storage_shutdown(void) /* {{{ */ { | |
63 | yac_allocator_shutdown(); | |
64 | } | |
65 | /* }}} */ | |
66 | ||
67 | /* {{{ MurmurHash2 (Austin Appleby) | |
68 | */ | |
69 | static inline uint64_t yac_inline_hash_func1(char *data, unsigned int len) { | |
70 | unsigned int h, k; | |
71 | ||
72 | h = 0 ^ len; | |
73 | ||
74 | while (len >= 4) { | |
75 | k = data[0]; | |
76 | k |= data[1] << 8; | |
77 | k |= data[2] << 16; | |
78 | k |= data[3] << 24; | |
79 | ||
80 | k *= 0x5bd1e995; | |
81 | k ^= k >> 24; | |
82 | k *= 0x5bd1e995; | |
83 | ||
84 | h *= 0x5bd1e995; | |
85 | h ^= k; | |
86 | ||
87 | data += 4; | |
88 | len -= 4; | |
89 | } | |
90 | ||
91 | switch (len) { | |
92 | case 3: | |
93 | h ^= data[2] << 16; | |
94 | case 2: | |
95 | h ^= data[1] << 8; | |
96 | case 1: | |
97 | h ^= data[0]; | |
98 | h *= 0x5bd1e995; | |
99 | } | |
100 | ||
101 | h ^= h >> 13; | |
102 | h *= 0x5bd1e995; | |
103 | h ^= h >> 15; | |
104 | ||
105 | return h; | |
106 | } | |
107 | /* }}} */ | |
108 | ||
109 | /* {{{ DJBX33A (Daniel J. Bernstein, Times 33 with Addition) | |
110 | * | |
111 | * This is Daniel J. Bernstein's popular `times 33' hash function as | |
112 | * posted by him years ago on comp->lang.c. It basically uses a function | |
113 | * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best | |
114 | * known hash functions for strings. Because it is both computed very | |
115 | * fast and distributes very well. | |
116 | * | |
117 | * The magic of number 33, i.e. why it works better than many other | |
118 | * constants, prime or not, has never been adequately explained by | |
119 | * anyone. So I try an explanation: if one experimentally tests all | |
120 | * multipliers between 1 and 256 (as RSE did now) one detects that even | |
121 | * numbers are not useable at all. The remaining 128 odd numbers | |
122 | * (except for the number 1) work more or less all equally well. They | |
123 | * all distribute in an acceptable way and this way fill a hash table | |
124 | * with an average percent of approx. 86%. | |
125 | * | |
126 | * If one compares the Chi^2 values of the variants, the number 33 not | |
127 | * even has the best value. But the number 33 and a few other equally | |
128 | * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great | |
129 | * advantage to the remaining numbers in the large set of possible | |
130 | * multipliers: their multiply operation can be replaced by a faster | |
131 | * operation based on just one shift plus either a single addition | |
132 | * or subtraction operation. And because a hash function has to both | |
133 | * distribute good _and_ has to be very fast to compute, those few | |
134 | * numbers should be preferred and seems to be the reason why Daniel J. | |
135 | * Bernstein also preferred it. | |
136 | * | |
137 | * | |
138 | * -- Ralf S. Engelschall <rse@engelschall.com> | |
139 | */ | |
140 | ||
141 | static inline uint64_t yac_inline_hash_func2(char *key, uint32_t len) { | |
142 | register uint64_t hash = 5381; | |
143 | ||
144 | /* variant with the hash unrolled eight times */ | |
145 | for (; len >= 8; len -= 8) { | |
146 | hash = ((hash << 5) + hash) + *key++; | |
147 | hash = ((hash << 5) + hash) + *key++; | |
148 | hash = ((hash << 5) + hash) + *key++; | |
149 | hash = ((hash << 5) + hash) + *key++; | |
150 | hash = ((hash << 5) + hash) + *key++; | |
151 | hash = ((hash << 5) + hash) + *key++; | |
152 | hash = ((hash << 5) + hash) + *key++; | |
153 | hash = ((hash << 5) + hash) + *key++; | |
154 | } | |
155 | switch (len) { | |
156 | case 7: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
157 | case 6: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
158 | case 5: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
159 | case 4: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
160 | case 3: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
161 | case 2: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
162 | case 1: hash = ((hash << 5) + hash) + *key++; break; | |
163 | case 0: break; | |
164 | default: break; | |
165 | } | |
166 | return hash; | |
167 | } | |
168 | /* }}} */ | |
169 | ||
170 | /* {{{ COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or | |
171 | * code or tables extracted from it, as desired without restriction. | |
172 | * | |
173 | * First, the polynomial itself and its table of feedback terms. The | |
174 | * polynomial is | |
175 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 | |
176 | * | |
177 | * Note that we take it "backwards" and put the highest-order term in | |
178 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the | |
179 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in | |
180 | * the MSB being 1 | |
181 | * | |
182 | * Note that the usual hardware shift register implementation, which | |
183 | * is what we're using (we're merely optimizing it by doing eight-bit | |
184 | * chunks at a time) shifts bits into the lowest-order term. In our | |
185 | * implementation, that means shifting towards the right. Why do we | |
186 | * do it this way? Because the calculated CRC must be transmitted in | |
187 | * order from highest-order term to lowest-order term. UARTs transmit | |
188 | * characters in order from LSB to MSB. By storing the CRC this way | |
189 | * we hand it to the UART in the order low-byte to high-byte; the UART | |
190 | * sends each low-bit to hight-bit; and the result is transmission bit | |
191 | * by bit from highest- to lowest-order term without requiring any bit | |
192 | * shuffling on our part. Reception works similarly | |
193 | * | |
194 | * The feedback terms table consists of 256, 32-bit entries. Notes | |
195 | * | |
196 | * The table can be generated at runtime if desired; code to do so | |
197 | * is shown later. It might not be obvious, but the feedback | |
198 | * terms simply represent the results of eight shift/xor opera | |
199 | * tions for all combinations of data and CRC register values | |
200 | * | |
201 | * The values must be right-shifted by eight bits by the "updcrc | |
202 | * logic; the shift must be unsigned (bring in zeroes). On some | |
203 | * hardware you could probably optimize the shift in assembler by | |
204 | * using byte-swap instructions | |
205 | * polynomial $edb88320 | |
206 | * | |
207 | * | |
208 | * CRC32 code derived from work by Gary S. Brown. | |
209 | */ | |
210 | ||
211 | static unsigned int crc32_tab[] = { | |
212 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | |
213 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | |
214 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | |
215 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | |
216 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | |
217 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | |
218 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | |
219 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | |
220 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | |
221 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | |
222 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | |
223 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | |
224 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | |
225 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | |
226 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | |
227 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | |
228 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | |
229 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | |
230 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | |
231 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | |
232 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | |
233 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | |
234 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | |
235 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | |
236 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | |
237 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | |
238 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | |
239 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | |
240 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | |
241 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | |
242 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | |
243 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | |
244 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | |
245 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | |
246 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | |
247 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | |
248 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | |
249 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | |
250 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | |
251 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | |
252 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | |
253 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | |
254 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | |
255 | }; | |
256 | ||
257 | static inline unsigned int crc32(char *buf, unsigned int size) { | |
258 | const char *p; | |
259 | register int crc = 0; | |
260 | ||
261 | p = buf; | |
262 | while (size--) { | |
263 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); | |
264 | } | |
265 | ||
266 | return crc ^ ~0U; | |
267 | } | |
268 | /* }}} */ | |
269 | ||
270 | static inline unsigned int yac_crc32(char *data, unsigned int size) /* {{{ */ { | |
271 | if (size < YAC_FULL_CRC_THRESHOLD) { | |
272 | return crc32(data, size); | |
273 | } else { | |
274 | int i = 0; | |
275 | char crc_contents[YAC_FULL_CRC_THRESHOLD]; | |
276 | int head = YAC_FULL_CRC_THRESHOLD >> 2; | |
277 | int tail = YAC_FULL_CRC_THRESHOLD >> 4; | |
278 | int body = YAC_FULL_CRC_THRESHOLD - head - tail; | |
279 | char *p = data + head; | |
280 | char *q = crc_contents + head; | |
281 | int step = (size - tail - head) / body; | |
282 | ||
283 | memcpy(crc_contents, data, head); | |
284 | for (; i < body; i++, q++, p+= step) { | |
285 | *q = *p; | |
286 | } | |
287 | memcpy(q, p, tail); | |
288 | ||
289 | return crc32(crc_contents, YAC_FULL_CRC_THRESHOLD); | |
290 | } | |
291 | } | |
292 | /* }}} */ | |
293 | ||
294 | int yac_storage_find(char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv) /* {{{ */ { | |
295 | uint64_t h, hash, seed; | |
296 | yac_kv_key k, *p; | |
297 | yac_kv_val v; | |
298 | ||
299 | hash = h = yac_inline_hash_func1(key, len); | |
300 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
301 | k = *p; | |
302 | if (k.val) { | |
303 | char *s; | |
304 | uint32_t i; | |
305 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
306 | v = *(k.val); | |
307 | if (!memcmp(k.key, key, len)) { | |
308 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1); | |
309 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k)); | |
310 | do_verify: | |
311 | if (k.len != v.len) { | |
312 | USER_FREE(s); | |
313 | ++YAC_SG(miss); | |
314 | return 0; | |
315 | } | |
316 | ||
317 | if (k.ttl) { | |
318 | if (k.ttl <= tv) { | |
319 | ++YAC_SG(miss); | |
320 | USER_FREE(s); | |
321 | return 0; | |
322 | } | |
323 | } | |
324 | ||
325 | if (k.crc != yac_crc32(s, YAC_KEY_VLEN(k))) { | |
326 | USER_FREE(s); | |
327 | ++YAC_SG(miss); | |
328 | return 0; | |
329 | } | |
330 | s[YAC_KEY_VLEN(k)] = '\0'; | |
331 | k.val->atime = tv; | |
332 | *data = s; | |
333 | *size = YAC_KEY_VLEN(k); | |
334 | *flag = k.flag; | |
335 | ++YAC_SG(hits); | |
336 | return 1; | |
337 | } | |
338 | } | |
339 | ||
340 | seed = yac_inline_hash_func2(key, len); | |
341 | for (i = 0; i < 3; i++) { | |
342 | h += seed & YAC_SG(slots_mask); | |
343 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
344 | k = *p; | |
345 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
346 | v = *(k.val); | |
347 | if (!memcmp(k.key, key, len)) { | |
348 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1); | |
349 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k)); | |
350 | goto do_verify; | |
351 | } | |
352 | } | |
353 | } | |
354 | } | |
355 | ||
356 | ++YAC_SG(miss); | |
357 | ||
358 | return 0; | |
359 | } | |
360 | /* }}} */ | |
361 | ||
362 | void yac_storage_delete(char *key, unsigned int len, int ttl, unsigned long tv) /* {{{ */ { | |
363 | uint64_t hash, h, seed; | |
364 | yac_kv_key k, *p; | |
365 | ||
366 | hash = h = yac_inline_hash_func1(key, len); | |
367 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
368 | k = *p; | |
369 | if (k.val) { | |
370 | uint32_t i; | |
371 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
372 | if (!memcmp((char *)k.key, key, len)) { | |
373 | if (ttl == 0) { | |
374 | p->ttl = 1; | |
375 | } else { | |
376 | p->ttl = ttl + tv; | |
377 | } | |
378 | return; | |
379 | } | |
380 | } | |
381 | ||
382 | seed = yac_inline_hash_func2(key, len); | |
383 | for (i = 0; i < 3; i++) { | |
384 | h += seed & YAC_SG(slots_mask); | |
385 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
386 | k = *p; | |
387 | if (k.val == NULL) { | |
388 | return; | |
389 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
390 | p->ttl = 1; | |
391 | return; | |
392 | } | |
393 | } | |
394 | } | |
395 | } | |
396 | /* }}} */ | |
397 | ||
398 | int yac_storage_update(char *key, unsigned int len, char *data, unsigned int size, unsigned int flag, int ttl, int add, unsigned long tv) /* {{{ */ { | |
399 | uint64_t hash, h; | |
400 | int idx = 0, is_valid; | |
401 | yac_kv_key *p, k, *paths[4]; | |
402 | yac_kv_val *val, *s; | |
403 | unsigned long real_size; | |
404 | ||
405 | hash = h = yac_inline_hash_func1(key, len); | |
406 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
407 | k = *p; | |
408 | if (k.val) { | |
409 | /* Found the exact match */ | |
410 | if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
411 | do_update: | |
412 | is_valid = 0; | |
413 | if (k.crc == yac_crc32(k.val->data, YAC_KEY_VLEN(k))) { | |
414 | is_valid = 1; | |
415 | } | |
416 | if (add && (!k.ttl || k.ttl > tv) && is_valid) { | |
417 | return 0; | |
418 | } | |
419 | if (k.size >= size && is_valid) { | |
420 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
421 | memcpy(s->data, data, size); | |
422 | if (ttl) { | |
423 | k.ttl = (uint64_t)tv + ttl; | |
424 | } else { | |
425 | k.ttl = 0; | |
426 | } | |
427 | s->atime = tv; | |
428 | YAC_KEY_SET_LEN(*s, len, size); | |
429 | memcpy((char *)k.val, (char *)s, sizeof(yac_kv_val) + size - 1); | |
430 | k.crc = yac_crc32(s->data, size); | |
431 | k.flag = flag; | |
432 | memcpy(k.key, key, len); | |
433 | YAC_KEY_SET_LEN(k, len, size); | |
434 | *p = k; | |
435 | USER_FREE(s); | |
436 | return 1; | |
437 | } else { | |
438 | uint32_t msize; | |
439 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1); | |
440 | if (!real_size) { | |
441 | ++YAC_SG(fails); | |
442 | return 0; | |
443 | } | |
444 | msize = sizeof(yac_kv_val) + size - 1; | |
445 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
446 | memcpy(s->data, data, size); | |
447 | s->atime = tv; | |
448 | YAC_KEY_SET_LEN(*s, len, size); | |
449 | val = yac_allocator_raw_alloc(real_size, (int)hash); | |
450 | if (val) { | |
451 | memcpy((char *)val, (char *)s, msize); | |
452 | if (ttl) { | |
453 | k.ttl = tv + ttl; | |
454 | } else { | |
455 | k.ttl = 0; | |
456 | } | |
457 | k.crc = yac_crc32(s->data, size); | |
458 | k.val = val; | |
459 | k.flag = flag; | |
460 | k.size = real_size; | |
461 | memcpy(k.key, key, len); | |
462 | YAC_KEY_SET_LEN(k, len, size); | |
463 | *p = k; | |
464 | USER_FREE(s); | |
465 | return 1; | |
466 | } | |
467 | ++YAC_SG(fails); | |
468 | USER_FREE(s); | |
469 | return 0; | |
470 | } | |
471 | } else { | |
472 | uint32_t i; | |
473 | uint64_t seed, max_atime; | |
474 | ||
475 | seed = yac_inline_hash_func2(key, len); | |
476 | for (i = 0; i < 3; i++) { | |
477 | h += seed & YAC_SG(slots_mask); | |
478 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
479 | k = *p; | |
480 | if (k.val == NULL) { | |
481 | goto do_add; | |
482 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
483 | /* Found the exact match */ | |
484 | goto do_update; | |
485 | } | |
486 | } | |
487 | ||
488 | --idx; | |
489 | max_atime = paths[idx]->val->atime; | |
490 | for (i = 0; i < idx; i++) { | |
491 | if ((paths[i]->ttl && paths[i]->ttl <= tv) || paths[i]->len != paths[i]->val->len) { | |
492 | p = paths[i]; | |
493 | goto do_add; | |
494 | } else if (paths[i]->val->atime < max_atime) { | |
495 | max_atime = paths[i]->val->atime; | |
496 | p = paths[i]; | |
497 | } | |
498 | } | |
499 | ++YAC_SG(kicks); | |
500 | k = *p; | |
501 | k.h = hash; | |
502 | ||
503 | goto do_update; | |
504 | } | |
505 | } else { | |
506 | do_add: | |
507 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1); | |
508 | if (!real_size) { | |
509 | ++YAC_SG(fails); | |
510 | return 0; | |
511 | } | |
512 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
513 | memcpy(s->data, data, size); | |
514 | s->atime = tv; | |
515 | YAC_KEY_SET_LEN(*s, len, size); | |
516 | val = yac_allocator_raw_alloc(real_size, (int)hash); | |
517 | if (val) { | |
518 | memcpy((char *)val, (char *)s, sizeof(yac_kv_val) + size - 1); | |
519 | if (p->val == NULL) { | |
520 | ++YAC_SG(slots_num); | |
521 | } | |
522 | k.h = hash; | |
523 | k.val = val; | |
524 | k.flag = flag; | |
525 | k.size = real_size; | |
526 | k.crc = yac_crc32(s->data, size); | |
527 | memcpy(k.key, key, len); | |
528 | YAC_KEY_SET_LEN(k, len, size); | |
529 | if (ttl) { | |
530 | k.ttl = tv + ttl; | |
531 | } else { | |
532 | k.ttl = 0; | |
533 | } | |
534 | *p = k; | |
535 | USER_FREE(s); | |
536 | return 1; | |
537 | } | |
538 | ++YAC_SG(fails); | |
539 | USER_FREE(s); | |
540 | } | |
541 | ||
542 | return 0; | |
543 | } | |
544 | /* }}} */ | |
545 | ||
546 | void yac_storage_flush(void) /* {{{ */ { | |
547 | YAC_SG(slots_num) = 0; | |
548 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * YAC_SG(slots_size)); | |
549 | } | |
550 | /* }}} */ | |
551 | ||
552 | yac_storage_info * yac_storage_get_info(void) /* {{{ */ { | |
553 | yac_storage_info *info = USER_ALLOC(sizeof(yac_storage_info)); | |
554 | ||
555 | info->k_msize = (unsigned long)YAC_SG(first_seg).size; | |
556 | info->v_msize = (unsigned long)YAC_SG(segments)[0]->size * (unsigned long)YAC_SG(segments_num); | |
557 | info->segment_size = YAC_SG(segments)[0]->size; | |
558 | info->segments_num = YAC_SG(segments_num); | |
559 | info->hits = YAC_SG(hits); | |
560 | info->miss = YAC_SG(miss); | |
561 | info->fails = YAC_SG(fails); | |
562 | info->kicks = YAC_SG(kicks); | |
563 | info->recycles = YAC_SG(recycles); | |
564 | info->slots_size = YAC_SG(slots_size); | |
565 | info->slots_num = YAC_SG(slots_num); | |
566 | ||
567 | return info; | |
568 | } | |
569 | /* }}} */ | |
570 | ||
571 | void yac_storage_free_info(yac_storage_info *info) /* {{{ */ { | |
572 | USER_FREE(info); | |
573 | } | |
574 | /* }}} */ | |
575 | ||
576 | yac_item_list * yac_storage_dump(unsigned int limit) /* {{{ */ { | |
577 | yac_kv_key k; | |
578 | yac_item_list *item, *list = NULL; | |
579 | ||
580 | if (YAC_SG(slots_num)) { | |
581 | unsigned int i = 0, n = 0; | |
582 | for (; i<YAC_SG(slots_size) && n < YAC_SG(slots_num) && n < limit; i++) { | |
583 | k = YAC_SG(slots)[i]; | |
584 | if (k.val) { | |
585 | item = USER_ALLOC(sizeof(yac_item_list)); | |
586 | item->index = i; | |
587 | item->h = k.h; | |
588 | item->crc = k.crc; | |
589 | item->ttl = k.ttl; | |
590 | item->k_len = YAC_KEY_KLEN(k); | |
591 | item->v_len = YAC_KEY_VLEN(k); | |
592 | item->flag = k.flag; | |
593 | item->size = k.size; | |
594 | memcpy(item->key, k.key, YAC_STORAGE_MAX_KEY_LEN); | |
595 | item->next = list; | |
596 | list = item; | |
597 | ++n; | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
602 | return list; | |
603 | } | |
604 | /* }}} */ | |
605 | ||
606 | void yac_storage_free_list(yac_item_list *list) /* {{{ */ { | |
607 | yac_item_list *l; | |
608 | while (list) { | |
609 | l = list; | |
610 | list = list->next; | |
611 | USER_FREE(l); | |
612 | } | |
613 | } | |
614 | /* }}} */ | |
615 | ||
616 | const char * yac_storage_shared_memory_name(void) /* {{{ */ { | |
617 | return YAC_SHARED_MEMORY_HANDLER_NAME; | |
618 | } | |
619 | /* }}} */ | |
620 | ||
621 | /* | |
622 | * Local variables: | |
623 | * tab-width: 4 | |
624 | * c-basic-offset: 4 | |
625 | * End: | |
626 | * vim600: noet sw=4 ts=4 fdm=marker | |
627 | * vim<600: noet sw=4 ts=4 | |
628 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef YAC_STORAGE_H | |
21 | #define YAC_STORAGE_H | |
22 | ||
23 | #define YAC_STORAGE_MAX_ENTRY_LEN (1 << 20) | |
24 | #define YAC_STORAGE_MAX_KEY_LEN (48) | |
25 | #define YAC_STORAGE_FACTOR (1.25) | |
26 | #define YAC_KEY_KLEN_MASK (255) | |
27 | #define YAC_KEY_VLEN_BITS (8) | |
28 | #define YAC_KEY_KLEN(k) ((k).len & YAC_KEY_KLEN_MASK) | |
29 | #define YAC_KEY_VLEN(k) ((k).len >> YAC_KEY_VLEN_BITS) | |
30 | #define YAC_KEY_SET_LEN(k, kl, vl) ((k).len = (vl << YAC_KEY_VLEN_BITS) | (kl & YAC_KEY_KLEN_MASK)) | |
31 | #define YAC_FULL_CRC_THRESHOLD 256 | |
32 | ||
33 | #define USER_ALLOC emalloc | |
34 | #define USER_FREE efree | |
35 | ||
36 | typedef struct { | |
37 | unsigned long atime; | |
38 | unsigned int len; | |
39 | char data[1]; | |
40 | } yac_kv_val; | |
41 | ||
42 | typedef struct { | |
43 | unsigned long h; | |
44 | unsigned long crc; | |
45 | unsigned int ttl; | |
46 | unsigned int len; | |
47 | unsigned int flag; | |
48 | unsigned int size; | |
49 | yac_kv_val *val; | |
50 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN]; | |
51 | } yac_kv_key; | |
52 | ||
53 | typedef struct _yac_item_list { | |
54 | unsigned int index; | |
55 | unsigned long h; | |
56 | unsigned long crc; | |
57 | unsigned int ttl; | |
58 | unsigned int k_len; | |
59 | unsigned int v_len; | |
60 | unsigned int flag; | |
61 | unsigned int size; | |
62 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN]; | |
63 | struct _yac_item_list *next; | |
64 | } yac_item_list; | |
65 | ||
66 | typedef struct { | |
67 | volatile unsigned int pos; | |
68 | unsigned int size; | |
69 | void *p; | |
70 | } yac_shared_segment; | |
71 | ||
72 | typedef struct { | |
73 | unsigned long k_msize; | |
74 | unsigned long v_msize; | |
75 | unsigned int segments_num; | |
76 | unsigned int segment_size; | |
77 | unsigned int slots_num; | |
78 | unsigned int slots_size; | |
79 | unsigned int miss; | |
80 | unsigned int fails; | |
81 | unsigned int kicks; | |
82 | unsigned int recycles; | |
83 | unsigned long hits; | |
84 | } yac_storage_info; | |
85 | ||
86 | typedef struct { | |
87 | yac_kv_key *slots; | |
88 | unsigned int slots_mask; | |
89 | unsigned int slots_num; | |
90 | unsigned int slots_size; | |
91 | unsigned int miss; | |
92 | unsigned int fails; | |
93 | unsigned int kicks; | |
94 | unsigned int recycles; | |
95 | unsigned long hits; | |
96 | yac_shared_segment **segments; | |
97 | unsigned int segments_num; | |
98 | unsigned int segments_num_mask; | |
99 | yac_shared_segment first_seg; | |
100 | } yac_storage_globals; | |
101 | ||
102 | extern yac_storage_globals *yac_storage; | |
103 | ||
104 | #define YAC_SG(element) (yac_storage->element) | |
105 | ||
106 | int yac_storage_startup(unsigned long first_size, unsigned long size, char **err); | |
107 | void yac_storage_shutdown(void); | |
108 | int yac_storage_find(char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv); | |
109 | int yac_storage_update(char *key, unsigned int len, char *data, unsigned int size, unsigned int falg, int ttl, int add, unsigned long tv); | |
110 | void yac_storage_delete(char *key, unsigned int len, int ttl, unsigned long tv); | |
111 | void yac_storage_flush(void); | |
112 | const char * yac_storage_shared_memory_name(void); | |
113 | yac_storage_info * yac_storage_get_info(void); | |
114 | void yac_storage_free_info(yac_storage_info *info); | |
115 | yac_item_list * yac_storage_dump(unsigned int limit); | |
116 | void yac_storage_free_list(yac_item_list *list); | |
117 | #define yac_storage_exists(ht, key, len) yac_storage_find(ht, key, len, NULL) | |
118 | ||
119 | #endif /* YAC_STORAGE_H */ | |
120 | ||
121 | /* | |
122 | * Local variables: | |
123 | * tab-width: 4 | |
124 | * c-basic-offset: 4 | |
125 | * End: | |
126 | * vim600: noet sw=4 ts=4 fdm=marker | |
127 | * vim<600: noet sw=4 ts=4 | |
128 | */ |
0 | --TEST-- | |
1 | Check for yac presence | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --FILE-- | |
5 | <?php | |
6 | echo "yac extension is available"; | |
7 | /* | |
8 | you can add regression tests for your extension here | |
9 | ||
10 | the output of your test code has to be equal to the | |
11 | text in the --EXPECT-- section below for the tests | |
12 | to pass, differences between the output and the | |
13 | expected text are interpreted as failure | |
14 | ||
15 | see php5/README.TESTING for further information on | |
16 | writing regression tests | |
17 | */ | |
18 | ?> | |
19 | --EXPECT-- | |
20 | yac extension is available |
0 | --TEST-- | |
1 | Check for yac basic functions | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (YAC_SERIALIZER != "PHP") print "skip"; ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | --FILE-- | |
11 | <?php | |
12 | $yac = new Yac(); | |
13 | ||
14 | $key = "foo"; | |
15 | $value = "dummy"; | |
16 | ||
17 | var_dump($yac->set($key, $value)); | |
18 | var_dump($yac->get($key)); | |
19 | ||
20 | $value = NULL; | |
21 | var_dump($yac->set($key, $value)); | |
22 | var_dump($yac->get($key)); | |
23 | ||
24 | $value = TRUE; | |
25 | var_dump($yac->set($key, $value)); | |
26 | var_dump($yac->get($key)); | |
27 | ||
28 | $value = FALSE; | |
29 | var_dump($yac->set($key, $value)); | |
30 | var_dump($yac->get($key)); | |
31 | ||
32 | $value = range(1, 5); | |
33 | var_dump($yac->set($key, $value)); | |
34 | var_dump($yac->get($key)); | |
35 | ||
36 | $value = 9234324; | |
37 | var_dump($yac->set($key, $value)); | |
38 | var_dump($yac->get($key)); | |
39 | ||
40 | $value = 9234324.123456; | |
41 | var_dump($yac->set($key, $value)); | |
42 | var_dump($yac->get($key)); | |
43 | ||
44 | $value = new StdClass();; | |
45 | var_dump($yac->set($key, $value)); | |
46 | var_dump($yac->get($key)); | |
47 | ||
48 | $value = fopen("php://input", "r"); | |
49 | var_dump($yac->set($key, $value)); | |
50 | ||
51 | $value = range(1, 5); | |
52 | var_dump($yac->set($key, $value)); | |
53 | var_dump($yac->delete($key)); | |
54 | var_dump($yac->get($key)); | |
55 | ||
56 | ?> | |
57 | --EXPECTF-- | |
58 | bool(true) | |
59 | string(5) "dummy" | |
60 | bool(true) | |
61 | NULL | |
62 | bool(true) | |
63 | bool(true) | |
64 | bool(true) | |
65 | bool(false) | |
66 | bool(true) | |
67 | array(5) { | |
68 | [0]=> | |
69 | int(1) | |
70 | [1]=> | |
71 | int(2) | |
72 | [2]=> | |
73 | int(3) | |
74 | [3]=> | |
75 | int(4) | |
76 | [4]=> | |
77 | int(5) | |
78 | } | |
79 | bool(true) | |
80 | int(9234324) | |
81 | bool(true) | |
82 | float(9234324.123456) | |
83 | bool(true) | |
84 | object(stdClass)#3 (0) { | |
85 | } | |
86 | ||
87 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s002.php on line %d | |
88 | bool(false) | |
89 | bool(true) | |
90 | bool(true) | |
91 | bool(false) |
0 | --TEST-- | |
1 | Check for yac errors | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = str_repeat("k", YAC_MAX_KEY_LEN - 1); | |
14 | $value = NULL; | |
15 | ||
16 | var_dump($yac->set($key, $value)); | |
17 | var_dump($yac->get($key)); | |
18 | ||
19 | $key = str_repeat("k", YAC_MAX_KEY_LEN); | |
20 | var_dump($yac->set($key, $value)); | |
21 | var_dump($yac->get($key)); | |
22 | ||
23 | $key = str_repeat("k", YAC_MAX_KEY_LEN + 1); | |
24 | var_dump($yac->set($key, $value)); | |
25 | var_dump($yac->get($key)); | |
26 | ||
27 | $yac = new Yac("dummy"); | |
28 | var_dump($yac->set($key, $value)); | |
29 | var_dump($yac->get($key)); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | NULL | |
34 | bool(true) | |
35 | NULL | |
36 | ||
37 | Warning: Yac::set(): Key can not be longer than 48 bytes in %s003.php on line %d | |
38 | bool(false) | |
39 | ||
40 | Warning: Yac::get(): Key can not be longer than 48 bytes in %s003.php on line %d | |
41 | bool(false) | |
42 | ||
43 | Warning: Yac::set(): Key(include prefix) can not be longer than 48 bytes in %s003.php on line %d | |
44 | bool(false) | |
45 | ||
46 | Warning: Yac::get(): Key(include prefix) can not be longer than 48 bytes in %s003.php on line %d | |
47 | bool(false) |
0 | --TEST-- | |
1 | Check for yac ttl | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = "foo"; | |
14 | $value = "dummy"; | |
15 | ||
16 | var_dump($yac->set($key, $value, 1)); | |
17 | var_dump($yac->get($key)); | |
18 | sleep(1); | |
19 | var_dump($yac->get($key)); | |
20 | ||
21 | var_dump($yac->set($key, $value)); | |
22 | var_dump($yac->get($key)); | |
23 | var_dump($yac->delete($key, 1)); | |
24 | var_dump($yac->get($key)); | |
25 | sleep(1); | |
26 | var_dump($yac->get($key)); | |
27 | ||
28 | ?> | |
29 | --EXPECTF-- | |
30 | bool(true) | |
31 | string(5) "dummy" | |
32 | bool(false) | |
33 | bool(true) | |
34 | string(5) "dummy" | |
35 | bool(true) | |
36 | string(5) "dummy" | |
37 | bool(false) |
0 | --TEST-- | |
1 | Check for yac non-string key | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = md5(12345); | |
14 | $value = "dummy"; | |
15 | ||
16 | var_dump($yac->set($key, $value, 1)); | |
17 | var_dump($yac->get($key)); | |
18 | ||
19 | $key = 12345.12345; | |
20 | var_dump($yac->set($key, $value, 1)); | |
21 | var_dump($yac->get($key)); | |
22 | ||
23 | $key = range(1, 2); | |
24 | var_dump($yac->set($key, $value, 1)); | |
25 | var_dump($yac->get($key)); | |
26 | ||
27 | $key = new StdClass(); | |
28 | var_dump($yac->set($key, $value, 1)); | |
29 | var_dump($yac->get($key)); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | string(5) "dummy" | |
34 | bool(true) | |
35 | string(5) "dummy" | |
36 | bool(true) | |
37 | array(2) { | |
38 | [1]=> | |
39 | int(2) | |
40 | [2]=> | |
41 | bool(false) | |
42 | } | |
43 | ||
44 | %s error:%sObject of class stdClass could not be converted to string in %s005.php%A |
0 | --TEST-- | |
1 | Check for yac multi set/get | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | ||
12 | $yac = new Yac(); | |
13 | ||
14 | for ($i = 0; $i<1000; $i++) { | |
15 | $key = "xxx" . rand(1, 100000); | |
16 | $value = str_repeat("a", rand(1, 100000)); | |
17 | ||
18 | if (!$yac->set($key, $value)) { | |
19 | var_dump($key, $value); | |
20 | var_dump("write " . $i); | |
21 | } | |
22 | ||
23 | if ($value != ($new = $yac->get($key))) { | |
24 | var_dump($new); | |
25 | var_dump("read " . $i); | |
26 | } | |
27 | } | |
28 | ||
29 | var_dump($i); | |
30 | --EXPECTF-- | |
31 | int(1000) |
0 | --TEST-- | |
1 | Check for yac info | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | ||
12 | $yac = new Yac(); | |
13 | ||
14 | for ($i = 0; $i<1000; $i++) { | |
15 | $key = "xxx" . rand(1, 1000); | |
16 | $value = str_repeat("a", rand(1, 100000)); | |
17 | ||
18 | if (!$yac->set($key, $value)) { | |
19 | var_dump($key, $value); | |
20 | var_dump("write " . $i); | |
21 | } | |
22 | ||
23 | if ($value != ($new = $yac->get($key))) { | |
24 | var_dump($new); | |
25 | var_dump("read " . $i); | |
26 | } | |
27 | } | |
28 | ||
29 | $info = $yac->info(); | |
30 | var_dump($info['slots_used'] <= 1000); | |
31 | var_dump($info['hits']); | |
32 | var_dump($info['miss']); | |
33 | var_dump($info['fails']); | |
34 | var_dump($info['kicks']); | |
35 | --EXPECTF-- | |
36 | bool(true) | |
37 | int(1000) | |
38 | int(0) | |
39 | int(0) | |
40 | int(0) |
0 | --TEST-- | |
1 | Check for yac prefix | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac("dummy_"); | |
12 | $yac2 = new Yac(); | |
13 | ||
14 | $key = "bar"; | |
15 | $value = true; | |
16 | ||
17 | $yac->set($key, $value); | |
18 | var_dump($yac->get($key)); //true | |
19 | var_dump($yac2->get($key)); //false | |
20 | var_dump($yac2->get("dummy_" . $key)); //true | |
21 | ||
22 | $yac2->delete($key); //fail | |
23 | var_dump($yac->get($key)); //true | |
24 | ||
25 | $yac->delete($key); //okey | |
26 | var_dump($yac->get($key)); //false | |
27 | ||
28 | $yac->set($key, $value); | |
29 | $yac2->delete("dummy_" . $key); //okey | |
30 | var_dump($yac->get($key)); //false | |
31 | ?> | |
32 | --EXPECTF-- | |
33 | bool(true) | |
34 | bool(false) | |
35 | bool(true) | |
36 | bool(true) | |
37 | bool(false) | |
38 | bool(false) |
0 | --TEST-- | |
1 | Check for yac multi ops | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $values = array(); | |
14 | $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; | |
15 | for ($i = 0; $i < 100; $i++) { | |
16 | $key = substr(str_shuffle($chars), 0, rand(16, 32)); | |
17 | $value = md5($key . rand(1, 10000)); | |
18 | $values[$key] = $value; | |
19 | } | |
20 | ||
21 | $numbers = count($values); | |
22 | ||
23 | var_dump($yac->set($values)); | |
24 | ||
25 | $keys = array_keys($values); | |
26 | $ret = $yac->get($keys); | |
27 | var_dump(count(array_filter($ret)) == $numbers); | |
28 | ||
29 | $disable = array_slice($keys, 0, -10); | |
30 | $yac->delete($disable); | |
31 | ||
32 | $ret = $yac->get($keys); | |
33 | var_dump(count(array_filter($ret)) == 10); | |
34 | ?> | |
35 | --EXPECTF-- | |
36 | bool(true) | |
37 | bool(true) | |
38 | bool(true) |
0 | --TEST-- | |
1 | Check for yac::flush | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $values = array(); | |
14 | $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; | |
15 | for ($i = 0; $i < 100; $i++) { | |
16 | $key = substr(str_shuffle($chars), 0, rand(16, 32)); | |
17 | $value = md5($key . rand(1, 10000)); | |
18 | $values[$key] = $value; | |
19 | } | |
20 | ||
21 | $numbers = count($values); | |
22 | ||
23 | var_dump($yac->set($values)); | |
24 | ||
25 | $yac->flush(); | |
26 | ||
27 | var_dump($yac->get($key)); | |
28 | $info = $yac->info(); | |
29 | var_dump($info['slots_used']); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | bool(false) | |
34 | int(0) |
0 | --TEST-- | |
1 | Check for yac::add | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = "dummy"; | |
14 | $value = "foo"; | |
15 | var_dump($yac->add($key, $value)); // true | |
16 | var_dump($yac->add($key, $value)); // false | |
17 | var_dump($yac->set($key, $value)); // true | |
18 | var_dump($yac->get($key)); // foo | |
19 | var_dump($yac->delete($key)); // true | |
20 | $value = "bar"; | |
21 | var_dump($yac->add($key, $value, 1)); //true | |
22 | var_dump($yac->add($key, $value, 1)); //false | |
23 | var_dump($yac->get($key)); //bar | |
24 | sleep(1); | |
25 | var_dump($yac->add($key, $value)); //true | |
26 | ||
27 | ?> | |
28 | --EXPECTF-- | |
29 | bool(true) | |
30 | bool(false) | |
31 | bool(true) | |
32 | string(3) "foo" | |
33 | bool(true) | |
34 | bool(true) | |
35 | bool(false) | |
36 | string(3) "bar" | |
37 | bool(true) |
0 | --TEST-- | |
1 | Check for functional apis | |
2 | --SKIPIF-- | |
3 | <?php | |
4 | if (!extension_loaded("yac")) print "skip"; | |
5 | print "skip Functional style APIs are not enabled"; | |
6 | ?> | |
7 | --INI-- | |
8 | yac.enable=1 | |
9 | yac.enable_cli=1 | |
10 | yac.keys_memory_size=4M | |
11 | yac.values_memory_size=32M | |
12 | --FILE-- | |
13 | <?php | |
14 | $key = "dummy"; | |
15 | $value = "foo"; | |
16 | var_dump(yac_set($key, $value)); //true | |
17 | var_dump(yac_add($key, $value)); //false | |
18 | var_dump(yac_get($key)); //foo | |
19 | var_dump(yac_delete($key)); //true | |
20 | var_dump(yac_set($key, $value)); //true | |
21 | var_dump(yac_flush()); //true | |
22 | $info = yac_info(); | |
23 | var_dump($info['slots_used']); //0 | |
24 | ?> | |
25 | --EXPECTF-- | |
26 | bool(true) | |
27 | bool(false) | |
28 | string(3) "foo" | |
29 | bool(true) | |
30 | bool(true) | |
31 | bool(true) | |
32 | int(0) |
0 | --TEST-- | |
1 | Check for ttl bug | |
2 | --INI-- | |
3 | yac.enable=1 | |
4 | yac.enable_cli=1 | |
5 | yac.keys_memory_size=4M | |
6 | yac.values_memory_size=32M | |
7 | --FILE-- | |
8 | <?php | |
9 | $yac = new Yac(); | |
10 | $yac->set('test', 1, 1); | |
11 | sleep(2); | |
12 | var_dump($yac->get('test')); | |
13 | ?> | |
14 | --EXPECTF-- | |
15 | bool(false) |
0 | --TEST-- | |
1 | Check for ttl bug | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (YAC_SERIALIZER != "PHP") print "skip"; ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | yac.compress_threshold=1024 | |
11 | --FILE-- | |
12 | <?php | |
13 | error_reporting(E_ALL); | |
14 | $yac = new Yac(); | |
15 | ||
16 | for($i = 0; $i<100; $i++) { | |
17 | $value[] = ($i + 100000)."sdfsfsfsfs"; | |
18 | } | |
19 | ||
20 | $yac->set('test', $value); | |
21 | ||
22 | echo count($yac->get('test')); | |
23 | ?> | |
24 | --EXPECTF-- | |
25 | 100 |
0 | --TEST-- | |
1 | Check for Yac::dump | |
2 | --INI-- | |
3 | yac.enable=1 | |
4 | yac.enable_cli=1 | |
5 | yac.keys_memory_size=4M | |
6 | yac.values_memory_size=32M | |
7 | yac.compress_threshold=1024 | |
8 | --FILE-- | |
9 | <?php | |
10 | $yac = new Yac(); | |
11 | ||
12 | for ($i = 0; $i<100; $i++) { | |
13 | $yac->set("key". $i, "kjslkdfkldasjkf"); | |
14 | } | |
15 | for ($i = 0; $i<100; $i++) { | |
16 | $yac->set("key". $i, "kjslkdfkldasjkf"); | |
17 | } | |
18 | ||
19 | var_dump(count($yac->dump(1000))); | |
20 | --EXPECTF-- | |
21 | int(100) |
0 | --TEST-- | |
1 | ISSUE #12 segfault if use mmap&k_size bigger than 4M | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=8M | |
8 | yac.values_memory_size=128M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | $i = 0; | |
13 | while (true) { | |
14 | $yac->set(rand(), strval(rand()), 2); | |
15 | $i++; | |
16 | if ($i > 20000) { | |
17 | break; | |
18 | } | |
19 | } | |
20 | ?> | |
21 | OKEY | |
22 | --EXPECTF-- | |
23 | OKEY |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifdef HAVE_CONFIG_H | |
21 | #include "config.h" | |
22 | #endif | |
23 | ||
24 | #include <time.h> | |
25 | ||
26 | #include "php.h" | |
27 | #include "php_ini.h" | |
28 | #include "ext/standard/info.h" | |
29 | #include "zend_smart_str.h" | |
30 | #include "SAPI.h" | |
31 | ||
32 | #include "php_yac.h" | |
33 | #include "storage/yac_storage.h" | |
34 | #include "serializer/yac_serializer.h" | |
35 | #ifdef HAVE_FASTLZ_H | |
36 | #include <fastlz.h> | |
37 | #else | |
38 | #include "compressor/fastlz/fastlz.h" | |
39 | #endif | |
40 | ||
41 | zend_class_entry *yac_class_ce; | |
42 | ||
43 | ZEND_DECLARE_MODULE_GLOBALS(yac); | |
44 | ||
45 | /** {{{ ARG_INFO | |
46 | */ | |
47 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_constructor, 0, 0, 0) | |
48 | ZEND_ARG_INFO(0, prefix) | |
49 | ZEND_END_ARG_INFO() | |
50 | ||
51 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_add, 0, 0, 1) | |
52 | ZEND_ARG_INFO(0, keys) | |
53 | ZEND_ARG_INFO(0, value) | |
54 | ZEND_ARG_INFO(0, ttl) | |
55 | ZEND_END_ARG_INFO() | |
56 | ||
57 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_setter, 0, 0, 2) | |
58 | ZEND_ARG_INFO(0, key) | |
59 | ZEND_ARG_INFO(0, value) | |
60 | ZEND_END_ARG_INFO() | |
61 | ||
62 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_get, 0, 0, 1) | |
63 | ZEND_ARG_INFO(0, keys) | |
64 | ZEND_END_ARG_INFO() | |
65 | ||
66 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_getter, 0, 0, 1) | |
67 | ZEND_ARG_INFO(0, key) | |
68 | ZEND_END_ARG_INFO() | |
69 | ||
70 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_delete, 0, 0, 1) | |
71 | ZEND_ARG_INFO(0, keys) | |
72 | ZEND_ARG_INFO(0, ttl) | |
73 | ZEND_END_ARG_INFO() | |
74 | ||
75 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_void, 0, 0, 0) | |
76 | ZEND_END_ARG_INFO() | |
77 | /* }}} */ | |
78 | ||
79 | static PHP_INI_MH(OnChangeKeysMemoryLimit) /* {{{ */ { | |
80 | if (new_value) { | |
81 | YAC_G(k_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
82 | } | |
83 | return SUCCESS; | |
84 | } | |
85 | /* }}} */ | |
86 | ||
87 | static PHP_INI_MH(OnChangeValsMemoryLimit) /* {{{ */ { | |
88 | if (new_value) { | |
89 | YAC_G(v_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
90 | } | |
91 | return SUCCESS; | |
92 | } | |
93 | /* }}} */ | |
94 | ||
95 | static PHP_INI_MH(OnChangeCompressThreshold) /* {{{ */ { | |
96 | if (new_value) { | |
97 | YAC_G(compress_threshold) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
98 | if (YAC_G(compress_threshold) < YAC_MIN_COMPRESS_THRESHOLD) { | |
99 | YAC_G(compress_threshold) = YAC_MIN_COMPRESS_THRESHOLD; | |
100 | } | |
101 | } | |
102 | return SUCCESS; | |
103 | } | |
104 | /* }}} */ | |
105 | ||
106 | /* {{{ PHP_INI | |
107 | */ | |
108 | PHP_INI_BEGIN() | |
109 | STD_PHP_INI_BOOLEAN("yac.enable", "1", PHP_INI_SYSTEM, OnUpdateBool, enable, zend_yac_globals, yac_globals) | |
110 | STD_PHP_INI_BOOLEAN("yac.debug", "0", PHP_INI_ALL, OnUpdateBool, debug, zend_yac_globals, yac_globals) | |
111 | STD_PHP_INI_ENTRY("yac.keys_memory_size", "4M", PHP_INI_SYSTEM, OnChangeKeysMemoryLimit, k_msize, zend_yac_globals, yac_globals) | |
112 | STD_PHP_INI_ENTRY("yac.values_memory_size", "64M", PHP_INI_SYSTEM, OnChangeValsMemoryLimit, v_msize, zend_yac_globals, yac_globals) | |
113 | STD_PHP_INI_ENTRY("yac.compress_threshold", "-1", PHP_INI_SYSTEM, OnChangeCompressThreshold, compress_threshold, zend_yac_globals, yac_globals) | |
114 | STD_PHP_INI_ENTRY("yac.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_yac_globals, yac_globals) | |
115 | PHP_INI_END() | |
116 | /* }}} */ | |
117 | ||
118 | static int yac_add_impl(zend_string *prefix, zend_string *key, zval *value, int ttl, int add) /* {{{ */ { | |
119 | int ret = 0, flag = Z_TYPE_P(value); | |
120 | char *msg; | |
121 | time_t tv; | |
122 | zend_string *prefix_key; | |
123 | ||
124 | if ((ZSTR_LEN(key) + prefix->len) > YAC_STORAGE_MAX_KEY_LEN) { | |
125 | php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes", | |
126 | prefix->len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN); | |
127 | return ret; | |
128 | } | |
129 | ||
130 | if (prefix->len) { | |
131 | prefix_key = strpprintf(YAC_STORAGE_MAX_KEY_LEN, "%s%s", ZSTR_VAL(prefix), ZSTR_VAL(key)); | |
132 | key = prefix_key; | |
133 | } | |
134 | ||
135 | tv = time(NULL); | |
136 | switch (Z_TYPE_P(value)) { | |
137 | case IS_NULL: | |
138 | case IS_TRUE: | |
139 | case IS_FALSE: | |
140 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), (char *)&flag, sizeof(int), flag, ttl, add, tv); | |
141 | break; | |
142 | case IS_LONG: | |
143 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), (char *)&Z_LVAL_P(value), sizeof(long), flag, ttl, add, tv); | |
144 | break; | |
145 | case IS_DOUBLE: | |
146 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), (char *)&Z_DVAL_P(value), sizeof(double), flag, ttl, add, tv); | |
147 | break; | |
148 | case IS_STRING: | |
149 | #ifdef IS_CONSTANT | |
150 | case IS_CONSTANT: | |
151 | #endif | |
152 | { | |
153 | if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) { | |
154 | int compressed_len; | |
155 | char *compressed; | |
156 | ||
157 | /* if longer than this, then we can not stored the length in flag */ | |
158 | if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) { | |
159 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value)); | |
160 | if (prefix->len) { | |
161 | zend_string_release(prefix_key); | |
162 | } | |
163 | return ret; | |
164 | } | |
165 | ||
166 | compressed = emalloc(Z_STRLEN_P(value) * 1.05); | |
167 | compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed); | |
168 | if (!compressed_len || compressed_len > Z_STRLEN_P(value)) { | |
169 | php_error_docref(NULL, E_WARNING, "Compression failed"); | |
170 | efree(compressed); | |
171 | if (prefix->len) { | |
172 | zend_string_release(prefix_key); | |
173 | } | |
174 | return ret; | |
175 | } | |
176 | ||
177 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
178 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value)); | |
179 | efree(compressed); | |
180 | if (prefix->len) { | |
181 | zend_string_release(prefix_key); | |
182 | } | |
183 | return ret; | |
184 | } | |
185 | ||
186 | flag |= YAC_ENTRY_COMPRESSED; | |
187 | flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT); | |
188 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv); | |
189 | efree(compressed); | |
190 | } else { | |
191 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv); | |
192 | } | |
193 | } | |
194 | break; | |
195 | case IS_ARRAY: | |
196 | #ifdef IS_CONSTANT_ARRAY | |
197 | case IS_CONSTANT_ARRAY: | |
198 | #endif | |
199 | case IS_OBJECT: | |
200 | { | |
201 | smart_str buf = {0}; | |
202 | #if ENABLE_MSGPACK | |
203 | if (yac_serializer_msgpack_pack(value, &buf, &msg)) | |
204 | #else | |
205 | ||
206 | if (yac_serializer_php_pack(value, &buf, &msg)) | |
207 | #endif | |
208 | { | |
209 | if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
210 | int compressed_len; | |
211 | char *compressed; | |
212 | ||
213 | if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) { | |
214 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored"); | |
215 | if (prefix->len) { | |
216 | zend_string_release(prefix_key); | |
217 | } | |
218 | return ret; | |
219 | } | |
220 | ||
221 | compressed = emalloc(buf.s->len * 1.05); | |
222 | compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed); | |
223 | if (!compressed_len || compressed_len > buf.s->len) { | |
224 | php_error_docref(NULL, E_WARNING, "Compression failed"); | |
225 | efree(compressed); | |
226 | if (prefix->len) { | |
227 | zend_string_release(prefix_key); | |
228 | } | |
229 | return ret; | |
230 | } | |
231 | ||
232 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
233 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored"); | |
234 | efree(compressed); | |
235 | if (prefix->len) { | |
236 | zend_string_release(prefix_key); | |
237 | } | |
238 | return ret; | |
239 | } | |
240 | ||
241 | flag |= YAC_ENTRY_COMPRESSED; | |
242 | flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT); | |
243 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv); | |
244 | efree(compressed); | |
245 | } else { | |
246 | ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv); | |
247 | } | |
248 | smart_str_free(&buf); | |
249 | } else { | |
250 | php_error_docref(NULL, E_WARNING, "Serialization failed"); | |
251 | smart_str_free(&buf); | |
252 | } | |
253 | } | |
254 | break; | |
255 | case IS_RESOURCE: | |
256 | php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored"); | |
257 | break; | |
258 | default: | |
259 | php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag); | |
260 | break; | |
261 | } | |
262 | ||
263 | if (prefix->len) { | |
264 | zend_string_release(prefix_key); | |
265 | } | |
266 | ||
267 | return ret; | |
268 | } | |
269 | /* }}} */ | |
270 | ||
271 | static int yac_add_multi_impl(zend_string *prefix, zval *kvs, int ttl, int add) /* {{{ */ { | |
272 | HashTable *ht = Z_ARRVAL_P(kvs); | |
273 | zend_string *key; | |
274 | zend_ulong idx; | |
275 | zval *value; | |
276 | ||
277 | ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) { | |
278 | uint32_t should_free = 0; | |
279 | if (!key) { | |
280 | key = strpprintf(0, "%lu", idx); | |
281 | should_free = 1; | |
282 | } | |
283 | if (yac_add_impl(prefix, key, value, ttl, add)) { | |
284 | if (should_free) { | |
285 | zend_string_release(key); | |
286 | } | |
287 | continue; | |
288 | } else { | |
289 | if (should_free) { | |
290 | zend_string_release(key); | |
291 | } | |
292 | return 0; | |
293 | } | |
294 | } ZEND_HASH_FOREACH_END(); | |
295 | ||
296 | return 1; | |
297 | } | |
298 | /* }}} */ | |
299 | ||
300 | static zval * yac_get_impl(zend_string *prefix, zend_string *key, uint32_t *cas, zval *rv) /* {{{ */ { | |
301 | uint32_t flag, size = 0; | |
302 | char *data, *msg; | |
303 | time_t tv; | |
304 | zend_string *prefix_key; | |
305 | ||
306 | if ((ZSTR_LEN(key) + prefix->len) > YAC_STORAGE_MAX_KEY_LEN) { | |
307 | php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes", | |
308 | prefix->len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN); | |
309 | return NULL; | |
310 | } | |
311 | ||
312 | if (prefix->len) { | |
313 | prefix_key = strpprintf(YAC_STORAGE_MAX_KEY_LEN, "%s%s", ZSTR_VAL(prefix), ZSTR_VAL(key)); | |
314 | key = prefix_key; | |
315 | } | |
316 | ||
317 | tv = time(NULL); | |
318 | if (yac_storage_find(ZSTR_VAL(key), ZSTR_LEN(key), &data, &size, &flag, (int *)cas, tv)) { | |
319 | switch ((flag & YAC_ENTRY_TYPE_MASK)) { | |
320 | case IS_NULL: | |
321 | if (size == sizeof(int)) { | |
322 | ZVAL_NULL(rv); | |
323 | } | |
324 | efree(data); | |
325 | break; | |
326 | case IS_TRUE: | |
327 | if (size == sizeof(int)) { | |
328 | ZVAL_TRUE(rv); | |
329 | } | |
330 | efree(data); | |
331 | break; | |
332 | case IS_FALSE: | |
333 | if (size == sizeof(int)) { | |
334 | ZVAL_FALSE(rv); | |
335 | } | |
336 | efree(data); | |
337 | break; | |
338 | case IS_LONG: | |
339 | if (size == sizeof(long)) { | |
340 | ZVAL_LONG(rv, *(long*)data); | |
341 | } | |
342 | efree(data); | |
343 | break; | |
344 | case IS_DOUBLE: | |
345 | if (size == sizeof(double)) { | |
346 | ZVAL_DOUBLE(rv, *(double*)data); | |
347 | } | |
348 | efree(data); | |
349 | break; | |
350 | case IS_STRING: | |
351 | #ifdef IS_CONSTANT | |
352 | case IS_CONSTANT: | |
353 | #endif | |
354 | { | |
355 | if ((flag & YAC_ENTRY_COMPRESSED)) { | |
356 | size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT); | |
357 | char *origin = emalloc(orig_len + 1); | |
358 | uint32_t length; | |
359 | length = fastlz_decompress(data, size, origin, orig_len); | |
360 | if (!length) { | |
361 | php_error_docref(NULL, E_WARNING, "Decompression failed"); | |
362 | efree(data); | |
363 | efree(origin); | |
364 | if (prefix->len) { | |
365 | zend_string_release(prefix_key); | |
366 | } | |
367 | return NULL; | |
368 | } | |
369 | ZVAL_STRINGL(rv, origin, length); | |
370 | efree(origin); | |
371 | efree(data); | |
372 | } else { | |
373 | ZVAL_STRINGL(rv, data, size); | |
374 | efree(data); | |
375 | } | |
376 | } | |
377 | break; | |
378 | case IS_ARRAY: | |
379 | #ifdef IS_CONSTANT_ARRAY | |
380 | case IS_CONSTANT_ARRAY: | |
381 | #endif | |
382 | case IS_OBJECT: | |
383 | { | |
384 | if ((flag & YAC_ENTRY_COMPRESSED)) { | |
385 | size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT); | |
386 | char *origin = emalloc(orig_len + 1); | |
387 | length = fastlz_decompress(data, size, origin, orig_len); | |
388 | if (!length) { | |
389 | php_error_docref(NULL, E_WARNING, "Decompression failed"); | |
390 | efree(data); | |
391 | efree(origin); | |
392 | if (prefix->len) { | |
393 | zend_string_release(prefix_key); | |
394 | } | |
395 | return NULL; | |
396 | } | |
397 | efree(data); | |
398 | data = origin; | |
399 | size = length; | |
400 | } | |
401 | #if ENABLE_MSGPACK | |
402 | rv = yac_serializer_msgpack_unpack(data, size, &msg, rv); | |
403 | #else | |
404 | rv = yac_serializer_php_unpack(data, size, &msg, rv); | |
405 | #endif | |
406 | if (!rv) { | |
407 | php_error_docref(NULL, E_WARNING, "Unserialization failed"); | |
408 | } | |
409 | efree(data); | |
410 | } | |
411 | break; | |
412 | default: | |
413 | php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag); | |
414 | rv = NULL; | |
415 | break; | |
416 | } | |
417 | } else { | |
418 | rv = NULL; | |
419 | } | |
420 | ||
421 | if (prefix->len) { | |
422 | zend_string_release(prefix_key); | |
423 | } | |
424 | ||
425 | return rv; | |
426 | } | |
427 | /* }}} */ | |
428 | ||
429 | static zval * yac_get_multi_impl(zend_string *prefix, zval *keys, zval *cas, zval *rv) /* {{{ */ { | |
430 | zval *value; | |
431 | HashTable *ht = Z_ARRVAL_P(keys); | |
432 | ||
433 | array_init(rv); | |
434 | ||
435 | ZEND_HASH_FOREACH_VAL(ht, value) { | |
436 | uint32_t lcas = 0; | |
437 | zval *v, tmp_rv; | |
438 | ||
439 | ZVAL_UNDEF(&tmp_rv); | |
440 | ||
441 | switch (Z_TYPE_P(value)) { | |
442 | case IS_STRING: | |
443 | if ((v = yac_get_impl(prefix, Z_STR_P(value), &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) { | |
444 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v); | |
445 | } else { | |
446 | ZVAL_FALSE(&tmp_rv); | |
447 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp_rv); | |
448 | } | |
449 | continue; | |
450 | default: | |
451 | { | |
452 | zend_string *key = zval_get_string(value); | |
453 | if ((v = yac_get_impl(prefix, key, &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) { | |
454 | zend_symtable_update(Z_ARRVAL_P(rv), key, v); | |
455 | } else { | |
456 | ZVAL_FALSE(&tmp_rv); | |
457 | zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp_rv); | |
458 | } | |
459 | zend_string_release(key); | |
460 | } | |
461 | continue; | |
462 | } | |
463 | } ZEND_HASH_FOREACH_END(); | |
464 | ||
465 | return rv; | |
466 | } | |
467 | /* }}} */ | |
468 | ||
469 | void yac_delete_impl(char *prefix, uint32_t prefix_len, char *key, uint32_t len, int ttl) /* {{{ */ { | |
470 | char buf[YAC_STORAGE_MAX_KEY_LEN]; | |
471 | time_t tv = 0; | |
472 | ||
473 | if ((len + prefix_len) > YAC_STORAGE_MAX_KEY_LEN) { | |
474 | php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes", | |
475 | prefix_len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN); | |
476 | return; | |
477 | } | |
478 | ||
479 | if (prefix_len) { | |
480 | len = snprintf(buf, sizeof(buf), "%s%s", prefix, key); | |
481 | key = (char *)buf; | |
482 | } | |
483 | ||
484 | if (ttl) { | |
485 | tv = (zend_ulong)time(NULL); | |
486 | } | |
487 | ||
488 | yac_storage_delete(key, len, ttl, tv); | |
489 | } | |
490 | /* }}} */ | |
491 | ||
492 | static void yac_delete_multi_impl(char *prefix, uint32_t prefix_len, zval *keys, int ttl) /* {{{ */ { | |
493 | HashTable *ht = Z_ARRVAL_P(keys); | |
494 | zval *value; | |
495 | ||
496 | ZEND_HASH_FOREACH_VAL(ht, value) { | |
497 | switch (Z_TYPE_P(value)) { | |
498 | case IS_STRING: | |
499 | yac_delete_impl(prefix, prefix_len, Z_STRVAL_P(value), Z_STRLEN_P(value), ttl); | |
500 | continue; | |
501 | default: | |
502 | { | |
503 | zval copy; | |
504 | zend_make_printable_zval(value, ©); | |
505 | yac_delete_impl(prefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), ttl); | |
506 | zval_dtor(©); | |
507 | } | |
508 | continue; | |
509 | } | |
510 | } ZEND_HASH_FOREACH_END(); | |
511 | } | |
512 | /* }}} */ | |
513 | ||
514 | /** {{{ proto public Yac::__construct([string $prefix]) | |
515 | */ | |
516 | PHP_METHOD(yac, __construct) { | |
517 | zend_string *prefix = NULL; | |
518 | ||
519 | if (!YAC_G(enable)) { | |
520 | return; | |
521 | } | |
522 | ||
523 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) { | |
524 | return; | |
525 | } | |
526 | ||
527 | if (!prefix) { | |
528 | return; | |
529 | } | |
530 | ||
531 | zend_update_property_str(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), prefix); | |
532 | ||
533 | } | |
534 | /* }}} */ | |
535 | ||
536 | /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl]) | |
537 | */ | |
538 | PHP_METHOD(yac, add) { | |
539 | long ttl = 0; | |
540 | zval rv, *keys, *prefix, *value = NULL; | |
541 | uint32_t ret; | |
542 | ||
543 | if (!YAC_G(enable)) { | |
544 | RETURN_FALSE; | |
545 | } | |
546 | ||
547 | switch (ZEND_NUM_ARGS()) { | |
548 | case 1: | |
549 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) { | |
550 | return; | |
551 | } | |
552 | break; | |
553 | case 2: | |
554 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) { | |
555 | return; | |
556 | } | |
557 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
558 | if (Z_TYPE_P(value) == IS_LONG) { | |
559 | ttl = Z_LVAL_P(value); | |
560 | value = NULL; | |
561 | } else { | |
562 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer"); | |
563 | return; | |
564 | } | |
565 | } | |
566 | break; | |
567 | case 3: | |
568 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) { | |
569 | return; | |
570 | } | |
571 | break; | |
572 | default: | |
573 | WRONG_PARAM_COUNT; | |
574 | } | |
575 | ||
576 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
577 | ||
578 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
579 | ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 1); | |
580 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
581 | ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 1); | |
582 | } else { | |
583 | zval copy; | |
584 | zend_make_printable_zval(keys, ©); | |
585 | ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 1); | |
586 | zval_dtor(©); | |
587 | } | |
588 | ||
589 | RETURN_BOOL(ret); | |
590 | } | |
591 | /* }}} */ | |
592 | ||
593 | /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl]) | |
594 | */ | |
595 | PHP_METHOD(yac, set) { | |
596 | long ttl = 0; | |
597 | zval rv, *keys, *prefix, *value = NULL; | |
598 | uint32_t ret; | |
599 | ||
600 | if (!YAC_G(enable)) { | |
601 | RETURN_FALSE; | |
602 | } | |
603 | ||
604 | switch (ZEND_NUM_ARGS()) { | |
605 | case 1: | |
606 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) { | |
607 | return; | |
608 | } | |
609 | break; | |
610 | case 2: | |
611 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) { | |
612 | return; | |
613 | } | |
614 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
615 | if (Z_TYPE_P(value) == IS_LONG) { | |
616 | ttl = Z_LVAL_P(value); | |
617 | value = NULL; | |
618 | } else { | |
619 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer"); | |
620 | return; | |
621 | } | |
622 | } | |
623 | break; | |
624 | case 3: | |
625 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) { | |
626 | return; | |
627 | } | |
628 | break; | |
629 | default: | |
630 | WRONG_PARAM_COUNT; | |
631 | } | |
632 | ||
633 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
634 | ||
635 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
636 | ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 0); | |
637 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
638 | ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 0); | |
639 | } else { | |
640 | zval copy; | |
641 | zend_make_printable_zval(keys, ©); | |
642 | ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 0); | |
643 | zval_dtor(©); | |
644 | } | |
645 | ||
646 | RETURN_BOOL(ret); | |
647 | } | |
648 | /* }}} */ | |
649 | ||
650 | /** {{{ proto public Yac::__set(string $name, mixed $value) | |
651 | */ | |
652 | PHP_METHOD(yac, __set) { | |
653 | zend_string *key; | |
654 | zval *prefix, *value, rv; | |
655 | ||
656 | if (!YAC_G(enable)) { | |
657 | RETURN_FALSE; | |
658 | } | |
659 | ||
660 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) { | |
661 | return; | |
662 | } | |
663 | ||
664 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
665 | ||
666 | yac_add_impl(Z_STR_P(prefix), key, value, 0, 0); | |
667 | } | |
668 | /* }}} */ | |
669 | ||
670 | /** {{{ proto public Yac::get(mixed $keys[, int &$cas]) | |
671 | */ | |
672 | PHP_METHOD(yac, get) { | |
673 | uint32_t lcas = 0; | |
674 | zval rv, *ret, *keys, *prefix, *cas = NULL; | |
675 | ||
676 | if (!YAC_G(enable)) { | |
677 | RETURN_FALSE; | |
678 | } | |
679 | ||
680 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) { | |
681 | return; | |
682 | } | |
683 | ||
684 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
685 | ||
686 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
687 | ret = yac_get_multi_impl(Z_STR_P(prefix), keys, cas, return_value); | |
688 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
689 | ret = yac_get_impl(Z_STR_P(prefix), Z_STR_P(keys), &lcas, return_value); | |
690 | } else { | |
691 | zval copy; | |
692 | zend_make_printable_zval(keys, ©); | |
693 | ret = yac_get_impl(Z_STR_P(prefix), Z_STR(copy), &lcas, return_value); | |
694 | zval_dtor(©); | |
695 | } | |
696 | ||
697 | if (ret == NULL) { | |
698 | RETURN_FALSE; | |
699 | } | |
700 | } | |
701 | /* }}} */ | |
702 | ||
703 | /** {{{ proto public Yac::__get(string $name) | |
704 | */ | |
705 | PHP_METHOD(yac, __get) { | |
706 | zval *prefix, rv; | |
707 | zend_string *key; | |
708 | uint32_t lcas = 0; | |
709 | ||
710 | if (!YAC_G(enable)) { | |
711 | RETURN_FALSE; | |
712 | } | |
713 | ||
714 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) { | |
715 | return; | |
716 | } | |
717 | ||
718 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
719 | ||
720 | if (yac_get_impl(Z_STR_P(prefix), key, &lcas, return_value) == NULL) { | |
721 | RETURN_FALSE; | |
722 | } | |
723 | } | |
724 | /* }}} */ | |
725 | ||
726 | /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0]) | |
727 | */ | |
728 | PHP_METHOD(yac, delete) { | |
729 | long time = 0; | |
730 | zval *keys, *prefix, rv; | |
731 | char *sprefix = NULL; | |
732 | uint32_t prefix_len = 0; | |
733 | ||
734 | if (!YAC_G(enable)) { | |
735 | RETURN_FALSE; | |
736 | } | |
737 | ||
738 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) { | |
739 | return; | |
740 | } | |
741 | ||
742 | prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv); | |
743 | sprefix = Z_STRVAL_P(prefix); | |
744 | prefix_len = Z_STRLEN_P(prefix); | |
745 | ||
746 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
747 | yac_delete_multi_impl(sprefix, prefix_len, keys, time); | |
748 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
749 | yac_delete_impl(sprefix, prefix_len, Z_STRVAL_P(keys), Z_STRLEN_P(keys), time); | |
750 | } else { | |
751 | zval copy; | |
752 | zend_make_printable_zval(keys, ©); | |
753 | yac_delete_impl(sprefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), time); | |
754 | zval_dtor(©); | |
755 | } | |
756 | ||
757 | RETURN_TRUE; | |
758 | } | |
759 | /* }}} */ | |
760 | ||
761 | /** {{{ proto public Yac::flush(void) | |
762 | */ | |
763 | PHP_METHOD(yac, flush) { | |
764 | ||
765 | if (!YAC_G(enable)) { | |
766 | RETURN_FALSE; | |
767 | } | |
768 | ||
769 | yac_storage_flush(); | |
770 | ||
771 | RETURN_TRUE; | |
772 | } | |
773 | /* }}} */ | |
774 | ||
775 | /** {{{ proto public Yac::info(void) | |
776 | */ | |
777 | PHP_METHOD(yac, info) { | |
778 | yac_storage_info *inf; | |
779 | ||
780 | if (!YAC_G(enable)) { | |
781 | RETURN_FALSE; | |
782 | } | |
783 | ||
784 | inf = yac_storage_get_info(); | |
785 | ||
786 | array_init(return_value); | |
787 | ||
788 | add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize); | |
789 | add_assoc_long(return_value, "slots_memory_size", inf->k_msize); | |
790 | add_assoc_long(return_value, "values_memory_size", inf->v_msize); | |
791 | add_assoc_long(return_value, "segment_size", inf->segment_size); | |
792 | add_assoc_long(return_value, "segment_num", inf->segments_num); | |
793 | add_assoc_long(return_value, "miss", inf->miss); | |
794 | add_assoc_long(return_value, "hits", inf->hits); | |
795 | add_assoc_long(return_value, "fails", inf->fails); | |
796 | add_assoc_long(return_value, "kicks", inf->kicks); | |
797 | add_assoc_long(return_value, "recycles", inf->recycles); | |
798 | add_assoc_long(return_value, "slots_size", inf->slots_size); | |
799 | add_assoc_long(return_value, "slots_used", inf->slots_num); | |
800 | ||
801 | yac_storage_free_info(inf); | |
802 | } | |
803 | /* }}} */ | |
804 | ||
805 | /** {{{ proto public Yac::dump(int $limit) | |
806 | */ | |
807 | PHP_METHOD(yac, dump) { | |
808 | long limit = 100; | |
809 | yac_item_list *list, *l; | |
810 | ||
811 | if (!YAC_G(enable)) { | |
812 | RETURN_FALSE; | |
813 | } | |
814 | ||
815 | array_init(return_value); | |
816 | ||
817 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) { | |
818 | return; | |
819 | } | |
820 | ||
821 | list = l = yac_storage_dump(limit); | |
822 | for (; l; l = l->next) { | |
823 | zval item; | |
824 | array_init(&item); | |
825 | add_assoc_long(&item, "index", l->index); | |
826 | add_assoc_long(&item, "hash", l->h); | |
827 | add_assoc_long(&item, "crc", l->crc); | |
828 | add_assoc_long(&item, "ttl", l->ttl); | |
829 | add_assoc_long(&item, "k_len", l->k_len); | |
830 | add_assoc_long(&item, "v_len", l->v_len); | |
831 | add_assoc_long(&item, "size", l->size); | |
832 | add_assoc_string(&item, "key", (char*)l->key); | |
833 | add_next_index_zval(return_value, &item); | |
834 | } | |
835 | ||
836 | yac_storage_free_list(list); | |
837 | return; | |
838 | } | |
839 | /* }}} */ | |
840 | ||
841 | #if 0 | |
842 | only OO-style APIs is supported now | |
843 | /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl]) | |
844 | */ | |
845 | PHP_FUNCTION(yac_add) | |
846 | { | |
847 | PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
848 | } | |
849 | /* }}} */ | |
850 | ||
851 | /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl]) | |
852 | */ | |
853 | PHP_FUNCTION(yac_set) | |
854 | { | |
855 | PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
856 | } | |
857 | /* }}} */ | |
858 | ||
859 | /* {{{ proto bool yac_get(mixed $keys[, int &$cas]) | |
860 | */ | |
861 | PHP_FUNCTION(yac_get) | |
862 | { | |
863 | PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
864 | } | |
865 | /* }}} */ | |
866 | ||
867 | /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0]) | |
868 | */ | |
869 | PHP_FUNCTION(yac_delete) | |
870 | { | |
871 | PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
872 | } | |
873 | /* }}} */ | |
874 | ||
875 | /* {{{ proto bool yac_flush(void) | |
876 | */ | |
877 | PHP_FUNCTION(yac_flush) | |
878 | { | |
879 | PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
880 | } | |
881 | /* }}} */ | |
882 | ||
883 | /* {{{ proto bool yac_info(void) | |
884 | */ | |
885 | PHP_FUNCTION(yac_info) | |
886 | { | |
887 | PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
888 | } | |
889 | /* }}} */ | |
890 | ||
891 | /* {{{ yac_functions[] */ | |
892 | zend_function_entry yac_functions[] = { | |
893 | PHP_FE(yac_add, arginfo_yac_add) | |
894 | PHP_FE(yac_set, arginfo_yac_add) | |
895 | PHP_FE(yac_get, arginfo_yac_get) | |
896 | PHP_FE(yac_delete, arginfo_yac_delete) | |
897 | PHP_FE(yac_flush, arginfo_yac_void) | |
898 | PHP_FE(yac_info, arginfo_yac_void) | |
899 | {NULL, NULL} | |
900 | }; | |
901 | /* }}} */ | |
902 | #endif | |
903 | ||
904 | /** {{{ yac_methods | |
905 | */ | |
906 | zend_function_entry yac_methods[] = { | |
907 | PHP_ME(yac, __construct, arginfo_yac_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) | |
908 | PHP_ME(yac, add, arginfo_yac_add, ZEND_ACC_PUBLIC) | |
909 | PHP_ME(yac, set, arginfo_yac_add, ZEND_ACC_PUBLIC) | |
910 | PHP_ME(yac, __set, arginfo_yac_setter, ZEND_ACC_PUBLIC) | |
911 | PHP_ME(yac, get, arginfo_yac_get, ZEND_ACC_PUBLIC) | |
912 | PHP_ME(yac, __get, arginfo_yac_getter, ZEND_ACC_PUBLIC) | |
913 | PHP_ME(yac, delete, arginfo_yac_delete, ZEND_ACC_PUBLIC) | |
914 | PHP_ME(yac, flush, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
915 | PHP_ME(yac, info, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
916 | PHP_ME(yac, dump, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
917 | {NULL, NULL, NULL} | |
918 | }; | |
919 | /* }}} */ | |
920 | ||
921 | /* {{{ PHP_GINIT_FUNCTION | |
922 | */ | |
923 | PHP_GINIT_FUNCTION(yac) | |
924 | { | |
925 | yac_globals->enable = 1; | |
926 | yac_globals->k_msize = (4 * 1024 * 1024); | |
927 | yac_globals->v_msize = (64 * 1024 * 1024); | |
928 | yac_globals->debug = 0; | |
929 | yac_globals->compress_threshold = -1; | |
930 | yac_globals->enable_cli = 0; | |
931 | #ifdef PHP_WIN32 | |
932 | yac_globals->mmap_base = NULL; | |
933 | #endif | |
934 | } | |
935 | /* }}} */ | |
936 | ||
937 | /* {{{ PHP_MINIT_FUNCTION | |
938 | */ | |
939 | PHP_MINIT_FUNCTION(yac) | |
940 | { | |
941 | char *msg; | |
942 | zend_class_entry ce; | |
943 | ||
944 | REGISTER_INI_ENTRIES(); | |
945 | ||
946 | if(!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) { | |
947 | YAC_G(enable) = 0; | |
948 | } | |
949 | ||
950 | if (YAC_G(enable)) { | |
951 | if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) { | |
952 | php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno)); | |
953 | return FAILURE; | |
954 | } | |
955 | } | |
956 | ||
957 | REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS); | |
958 | REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS); | |
959 | REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS); | |
960 | REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS); | |
961 | #if ENABLE_MSGPACK | |
962 | REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "MSGPACK", sizeof("MSGPACK") -1, CONST_PERSISTENT | CONST_CS); | |
963 | #else | |
964 | REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "PHP", sizeof("PHP") -1, CONST_PERSISTENT | CONST_CS); | |
965 | #endif | |
966 | ||
967 | INIT_CLASS_ENTRY(ce, "Yac", yac_methods); | |
968 | yac_class_ce = zend_register_internal_class(&ce); | |
969 | zend_declare_property_stringl(yac_class_ce, ZEND_STRS(YAC_CLASS_PROPERTY_PREFIX) - 1, "", 0, ZEND_ACC_PROTECTED); | |
970 | ||
971 | return SUCCESS; | |
972 | } | |
973 | /* }}} */ | |
974 | ||
975 | /* {{{ PHP_MSHUTDOWN_FUNCTION | |
976 | */ | |
977 | PHP_MSHUTDOWN_FUNCTION(yac) | |
978 | { | |
979 | UNREGISTER_INI_ENTRIES(); | |
980 | if (YAC_G(enable)) { | |
981 | yac_storage_shutdown(); | |
982 | } | |
983 | return SUCCESS; | |
984 | } | |
985 | /* }}} */ | |
986 | ||
987 | /* {{{ PHP_MINFO_FUNCTION | |
988 | */ | |
989 | PHP_MINFO_FUNCTION(yac) | |
990 | { | |
991 | php_info_print_table_start(); | |
992 | php_info_print_table_header(2, "yac support", "enabled"); | |
993 | php_info_print_table_row(2, "Version", PHP_YAC_VERSION); | |
994 | php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name()); | |
995 | #if ENABLE_MSGPACK | |
996 | php_info_print_table_row(2, "Serializer", "msgpack"); | |
997 | #else | |
998 | php_info_print_table_row(2, "Serializer", "php"); | |
999 | #endif | |
1000 | php_info_print_table_end(); | |
1001 | ||
1002 | DISPLAY_INI_ENTRIES(); | |
1003 | ||
1004 | if (YAC_G(enable)) { | |
1005 | char buf[64]; | |
1006 | yac_storage_info *inf; | |
1007 | inf = yac_storage_get_info(); | |
1008 | ||
1009 | php_info_print_table_start(); | |
1010 | php_info_print_table_colspan_header(2, "Cache info"); | |
1011 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize); | |
1012 | php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf); | |
1013 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize); | |
1014 | php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf); | |
1015 | snprintf(buf, sizeof(buf), "%ld", inf->v_msize); | |
1016 | php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf); | |
1017 | snprintf(buf, sizeof(buf), "%d", inf->segment_size); | |
1018 | php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf); | |
1019 | snprintf(buf, sizeof(buf), "%ld", inf->segments_num); | |
1020 | php_info_print_table_row(2, "Number of Segments (segment_num)", buf); | |
1021 | snprintf(buf, sizeof(buf), "%ld", inf->slots_size); | |
1022 | php_info_print_table_row(2, "Total Slots Number(slots_size)", buf); | |
1023 | snprintf(buf, sizeof(buf), "%ld", inf->slots_num); | |
1024 | php_info_print_table_row(2, "Total Used Slots(slots_num)", buf); | |
1025 | php_info_print_table_end(); | |
1026 | ||
1027 | yac_storage_free_info(inf); | |
1028 | } | |
1029 | } | |
1030 | /* }}} */ | |
1031 | ||
1032 | #ifdef COMPILE_DL_YAC | |
1033 | ZEND_GET_MODULE(yac) | |
1034 | #endif | |
1035 | ||
1036 | /* {{{ yac_module_entry | |
1037 | */ | |
1038 | zend_module_entry yac_module_entry = { | |
1039 | STANDARD_MODULE_HEADER, | |
1040 | "yac", | |
1041 | NULL, /* yac_functions, */ | |
1042 | PHP_MINIT(yac), | |
1043 | PHP_MSHUTDOWN(yac), | |
1044 | NULL, | |
1045 | NULL, | |
1046 | PHP_MINFO(yac), | |
1047 | PHP_YAC_VERSION, | |
1048 | PHP_MODULE_GLOBALS(yac), | |
1049 | PHP_GINIT(yac), | |
1050 | NULL, | |
1051 | NULL, | |
1052 | STANDARD_MODULE_PROPERTIES_EX | |
1053 | }; | |
1054 | /* }}} */ | |
1055 | ||
1056 | /* | |
1057 | * Local variables: | |
1058 | * tab-width: 4 | |
1059 | * c-basic-offset: 4 | |
1060 | * End: | |
1061 | * vim600: noet sw=4 ts=4 fdm=marker | |
1062 | * vim<600: noet sw=4 ts=4 | |
1063 | */ |
0 | -------------------------------------------------------------------- | |
1 | The PHP License, version 3.01 | |
2 | Copyright (c) 1999 - 2011 The PHP Group. All rights reserved. | |
3 | -------------------------------------------------------------------- | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, is permitted provided that the following conditions | |
7 | are met: | |
8 | ||
9 | 1. Redistributions of source code must retain the above copyright | |
10 | notice, this list of conditions and the following disclaimer. | |
11 | ||
12 | 2. Redistributions in binary form must reproduce the above copyright | |
13 | notice, this list of conditions and the following disclaimer in | |
14 | the documentation and/or other materials provided with the | |
15 | distribution. | |
16 | ||
17 | 3. The name "PHP" must not be used to endorse or promote products | |
18 | derived from this software without prior written permission. For | |
19 | written permission, please contact group@php.net. | |
20 | ||
21 | 4. Products derived from this software may not be called "PHP", nor | |
22 | may "PHP" appear in their name, without prior written permission | |
23 | from group@php.net. You may indicate that your software works in | |
24 | conjunction with PHP by saying "Foo for PHP" instead of calling | |
25 | it "PHP Foo" or "phpfoo" | |
26 | ||
27 | 5. The PHP Group may publish revised and/or new versions of the | |
28 | license from time to time. Each version will be given a | |
29 | distinguishing version number. | |
30 | Once covered code has been published under a particular version | |
31 | of the license, you may always continue to use it under the terms | |
32 | of that version. You may also choose to use such covered code | |
33 | under the terms of any subsequent version of the license | |
34 | published by the PHP Group. No one other than the PHP Group has | |
35 | the right to modify the terms applicable to covered code created | |
36 | under this License. | |
37 | ||
38 | 6. Redistributions of any form whatsoever must retain the following | |
39 | acknowledgment: | |
40 | "This product includes PHP software, freely available from | |
41 | <http://www.php.net/software/>". | |
42 | ||
43 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND | |
44 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
45 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
46 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP | |
47 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
48 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
49 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
50 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
52 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
53 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
54 | OF THE POSSIBILITY OF SUCH DAMAGE. | |
55 | ||
56 | -------------------------------------------------------------------- | |
57 | ||
58 | This software consists of voluntary contributions made by many | |
59 | individuals on behalf of the PHP Group. | |
60 | ||
61 | The PHP Group can be contacted via Email at group@php.net. | |
62 | ||
63 | For more information on the PHP Group and the PHP project, | |
64 | please see <http://www.php.net>. | |
65 | ||
66 | PHP includes the Zend Engine, freely available at | |
67 | <http://www.zend.com>. |
0 | FastLZ - lightning-fast lossless compression library | |
1 | ||
2 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
3 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | of this software and associated documentation files (the "Software"), to deal | |
8 | in the Software without restriction, including without limitation the rights | |
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | copies of the Software, and to permit persons to whom the Software is | |
11 | furnished to do so, subject to the following conditions: | |
12 | ||
13 | The above copyright notice and this permission notice shall be included in | |
14 | all copies or substantial portions of the Software. | |
15 | ||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | THE SOFTWARE. | |
23 |
0 | FastLZ - lightning-fast lossless compression library | |
1 | ||
2 | Author: Ariya Hidayat | |
3 | Official website: http://fastlz.org | |
4 | ||
5 | FastLZ is distributed using the MIT license, see file LICENSE | |
6 | for details. | |
7 | ||
8 | FastLZ consists of two files: fastlz.h and fastlz.c. Just add these | |
9 | files to your project in order to use FastLZ. For information on | |
10 | compression and decompression routines, see fastlz.h. | |
11 | ||
12 | A simple file compressor called 6pack is included as an example | |
13 | on how to use FastLZ. The corresponding decompressor is 6unpack. | |
14 | ||
15 | To compile using GCC: | |
16 | ||
17 | gcc -o 6pack 6pack.c fastlz.c | |
18 | gcc -o 6unpack 6unpack.c fastlz.c | |
19 | ||
20 | To compile using MinGW: | |
21 | ||
22 | mingw32-gcc -o 6pack 6pack.c fastlz.c | |
23 | mingw32-gcc -o 6unpack 6unpack.c fastlz.c | |
24 | ||
25 | To compile using Microsoft Visual C++: | |
26 | ||
27 | cl 6pack.c fastlz.c | |
28 | cl 6unpack.c fastlz.c | |
29 | ||
30 | To compile using Borland C++: | |
31 | ||
32 | bcc32 6pack.c fastlz.c | |
33 | bcc32 6unpack.c fastlz.c | |
34 | ||
35 | To compile using OpenWatcom C/C++: | |
36 | ||
37 | cl386 6pack.c fastlz.c | |
38 | cl386 6unpack.c fastlz.c | |
39 | ||
40 | To compile using Intel C++ compiler for Windows: | |
41 | ||
42 | icl 6pack.c fastlz.c | |
43 | icl 6unpack.c fastlz.c | |
44 | ||
45 | To compile using Intel C++ compiler for Linux: | |
46 | ||
47 | icc -o 6pack 6pack.c fastlz.c | |
48 | icc -o 6unpack 6unpack.c fastlz.c | |
49 | ||
50 | To compile 6pack using LCC-Win32: | |
51 | ||
52 | lc 6pack.c fastlz.c | |
53 | lc 6unpack.c fastlz.c | |
54 | ||
55 | To compile 6pack using Pelles C: | |
56 | ||
57 | pocc 6pack.c | |
58 | pocc 6unpack.c | |
59 | pocc fastlz.c | |
60 | polink 6pack.obj fastlz.obj | |
61 | polink 6unpack.obj fastlz.obj | |
62 | ||
63 | For speed optimization, always use proper compile flags for optimization options. | |
64 | Typical compiler flags are given below: | |
65 | ||
66 | * GCC (pre 4.2): -march=pentium -O3 -fomit-frame-pointer -mtune=pentium | |
67 | * GCC 4.2 or later: -march=pentium -O3 -fomit-frame-pointer -mtune=generic | |
68 | * Digital Mars C/C++: -o+all -5 | |
69 | * Intel C++ (Windows): /O3 /Qipo | |
70 | * Intel C++ (Linux): -O2 -march=pentium -mtune=pentium | |
71 | * Borland C++: -O2 -5 | |
72 | * LCC-Win32: -O | |
73 | * Pelles C: /O2 | |
74 |
0 | /* | |
1 | FastLZ - lightning-fast lossless compression library | |
2 | ||
3 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
5 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
6 | ||
7 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | of this software and associated documentation files (the "Software"), to deal | |
9 | in the Software without restriction, including without limitation the rights | |
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | copies of the Software, and to permit persons to whom the Software is | |
12 | furnished to do so, subject to the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included in | |
15 | all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) | |
27 | ||
28 | /* | |
29 | * Always check for bound when decompressing. | |
30 | * Generally it is best to leave it defined. | |
31 | */ | |
32 | #define FASTLZ_SAFE | |
33 | ||
34 | /* | |
35 | * Give hints to the compiler for branch prediction optimization. | |
36 | */ | |
37 | #if defined(__GNUC__) && (__GNUC__ > 2) | |
38 | #define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) | |
39 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) | |
40 | #else | |
41 | #define FASTLZ_EXPECT_CONDITIONAL(c) (c) | |
42 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) | |
43 | #endif | |
44 | ||
45 | /* | |
46 | * Use inlined functions for supported systems. | |
47 | */ | |
48 | #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) | |
49 | #define FASTLZ_INLINE inline | |
50 | #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) | |
51 | #define FASTLZ_INLINE __inline | |
52 | #else | |
53 | #define FASTLZ_INLINE | |
54 | #endif | |
55 | ||
56 | /* | |
57 | * Prevent accessing more than 8-bit at once, except on x86 architectures. | |
58 | */ | |
59 | #if !defined(FASTLZ_STRICT_ALIGN) | |
60 | #define FASTLZ_STRICT_ALIGN | |
61 | #if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ | |
62 | #undef FASTLZ_STRICT_ALIGN | |
63 | #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ | |
64 | #undef FASTLZ_STRICT_ALIGN | |
65 | #elif defined(_M_IX86) /* Intel, MSVC */ | |
66 | #undef FASTLZ_STRICT_ALIGN | |
67 | #elif defined(__386) | |
68 | #undef FASTLZ_STRICT_ALIGN | |
69 | #elif defined(_X86_) /* MinGW */ | |
70 | #undef FASTLZ_STRICT_ALIGN | |
71 | #elif defined(__I86__) /* Digital Mars */ | |
72 | #undef FASTLZ_STRICT_ALIGN | |
73 | #endif | |
74 | #endif | |
75 | ||
76 | /* | |
77 | * FIXME: use preprocessor magic to set this on different platforms! | |
78 | */ | |
79 | typedef unsigned char flzuint8; | |
80 | typedef unsigned short flzuint16; | |
81 | typedef unsigned int flzuint32; | |
82 | ||
83 | /* prototypes */ | |
84 | int fastlz_compress(const void* input, int length, void* output); | |
85 | int fastlz_compress_level(int level, const void* input, int length, void* output); | |
86 | int fastlz_decompress(const void* input, int length, void* output, int maxout); | |
87 | ||
88 | #define MAX_COPY 32 | |
89 | #define MAX_LEN 264 /* 256 + 8 */ | |
90 | #define MAX_DISTANCE 8192 | |
91 | ||
92 | #if !defined(FASTLZ_STRICT_ALIGN) | |
93 | #define FASTLZ_READU16(p) *((const flzuint16*)(p)) | |
94 | #else | |
95 | #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) | |
96 | #endif | |
97 | ||
98 | #define HASH_LOG 13 | |
99 | #define HASH_SIZE (1<< HASH_LOG) | |
100 | #define HASH_MASK (HASH_SIZE-1) | |
101 | #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } | |
102 | ||
103 | #undef FASTLZ_LEVEL | |
104 | #define FASTLZ_LEVEL 1 | |
105 | ||
106 | #undef FASTLZ_COMPRESSOR | |
107 | #undef FASTLZ_DECOMPRESSOR | |
108 | #define FASTLZ_COMPRESSOR fastlz1_compress | |
109 | #define FASTLZ_DECOMPRESSOR fastlz1_decompress | |
110 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); | |
111 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); | |
112 | #include "fastlz.c" | |
113 | ||
114 | #undef FASTLZ_LEVEL | |
115 | #define FASTLZ_LEVEL 2 | |
116 | ||
117 | #undef MAX_DISTANCE | |
118 | #define MAX_DISTANCE 8191 | |
119 | #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) | |
120 | ||
121 | #undef FASTLZ_COMPRESSOR | |
122 | #undef FASTLZ_DECOMPRESSOR | |
123 | #define FASTLZ_COMPRESSOR fastlz2_compress | |
124 | #define FASTLZ_DECOMPRESSOR fastlz2_decompress | |
125 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); | |
126 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); | |
127 | #include "fastlz.c" | |
128 | ||
129 | int fastlz_compress(const void* input, int length, void* output) | |
130 | { | |
131 | /* for short block, choose fastlz1 */ | |
132 | if(length < 65536) | |
133 | return fastlz1_compress(input, length, output); | |
134 | ||
135 | /* else... */ | |
136 | return fastlz2_compress(input, length, output); | |
137 | } | |
138 | ||
139 | int fastlz_decompress(const void* input, int length, void* output, int maxout) | |
140 | { | |
141 | /* magic identifier for compression level */ | |
142 | int level = ((*(const flzuint8*)input) >> 5) + 1; | |
143 | ||
144 | if(level == 1) | |
145 | return fastlz1_decompress(input, length, output, maxout); | |
146 | if(level == 2) | |
147 | return fastlz2_decompress(input, length, output, maxout); | |
148 | ||
149 | /* unknown level, trigger error */ | |
150 | return 0; | |
151 | } | |
152 | ||
153 | int fastlz_compress_level(int level, const void* input, int length, void* output) | |
154 | { | |
155 | if(level == 1) | |
156 | return fastlz1_compress(input, length, output); | |
157 | if(level == 2) | |
158 | return fastlz2_compress(input, length, output); | |
159 | ||
160 | return 0; | |
161 | } | |
162 | ||
163 | #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ | |
164 | ||
165 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) | |
166 | { | |
167 | const flzuint8* ip = (const flzuint8*) input; | |
168 | const flzuint8* ip_bound = ip + length - 2; | |
169 | const flzuint8* ip_limit = ip + length - 12; | |
170 | flzuint8* op = (flzuint8*) output; | |
171 | ||
172 | const flzuint8* htab[HASH_SIZE]; | |
173 | const flzuint8** hslot; | |
174 | flzuint32 hval; | |
175 | ||
176 | flzuint32 copy; | |
177 | ||
178 | /* sanity check */ | |
179 | if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) | |
180 | { | |
181 | if(length) | |
182 | { | |
183 | /* create literal copy only */ | |
184 | *op++ = length-1; | |
185 | ip_bound++; | |
186 | while(ip <= ip_bound) | |
187 | *op++ = *ip++; | |
188 | return length+1; | |
189 | } | |
190 | else | |
191 | return 0; | |
192 | } | |
193 | ||
194 | /* initializes hash table */ | |
195 | for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) | |
196 | *hslot = ip; | |
197 | ||
198 | /* we start with literal copy */ | |
199 | copy = 2; | |
200 | *op++ = MAX_COPY-1; | |
201 | *op++ = *ip++; | |
202 | *op++ = *ip++; | |
203 | ||
204 | /* main loop */ | |
205 | while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) | |
206 | { | |
207 | const flzuint8* ref; | |
208 | flzuint32 distance; | |
209 | ||
210 | /* minimum match length */ | |
211 | flzuint32 len = 3; | |
212 | ||
213 | /* comparison starting-point */ | |
214 | const flzuint8* anchor = ip; | |
215 | ||
216 | /* check for a run */ | |
217 | #if FASTLZ_LEVEL==2 | |
218 | if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) | |
219 | { | |
220 | distance = 1; | |
221 | ip += 3; | |
222 | ref = anchor - 1 + 3; | |
223 | goto match; | |
224 | } | |
225 | #endif | |
226 | ||
227 | /* find potential match */ | |
228 | HASH_FUNCTION(hval,ip); | |
229 | hslot = htab + hval; | |
230 | ref = htab[hval]; | |
231 | ||
232 | /* calculate distance to the match */ | |
233 | distance = anchor - ref; | |
234 | ||
235 | /* update hash table */ | |
236 | *hslot = anchor; | |
237 | ||
238 | /* is this a match? check the first 3 bytes */ | |
239 | if(distance==0 || | |
240 | #if FASTLZ_LEVEL==1 | |
241 | (distance >= MAX_DISTANCE) || | |
242 | #else | |
243 | (distance >= MAX_FARDISTANCE) || | |
244 | #endif | |
245 | *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) | |
246 | goto literal; | |
247 | ||
248 | #if FASTLZ_LEVEL==2 | |
249 | /* far, needs at least 5-byte match */ | |
250 | if(distance >= MAX_DISTANCE) | |
251 | { | |
252 | if(*ip++ != *ref++ || *ip++!= *ref++) | |
253 | goto literal; | |
254 | len += 2; | |
255 | } | |
256 | ||
257 | match: | |
258 | #endif | |
259 | ||
260 | /* last matched byte */ | |
261 | ip = anchor + len; | |
262 | ||
263 | /* distance is biased */ | |
264 | distance--; | |
265 | ||
266 | if(!distance) | |
267 | { | |
268 | /* zero distance means a run */ | |
269 | flzuint8 x = ip[-1]; | |
270 | while(ip < ip_bound) | |
271 | if(*ref++ != x) break; else ip++; | |
272 | } | |
273 | else | |
274 | for(;;) | |
275 | { | |
276 | /* safe because the outer check against ip limit */ | |
277 | if(*ref++ != *ip++) break; | |
278 | if(*ref++ != *ip++) break; | |
279 | if(*ref++ != *ip++) break; | |
280 | if(*ref++ != *ip++) break; | |
281 | if(*ref++ != *ip++) break; | |
282 | if(*ref++ != *ip++) break; | |
283 | if(*ref++ != *ip++) break; | |
284 | if(*ref++ != *ip++) break; | |
285 | while(ip < ip_bound) | |
286 | if(*ref++ != *ip++) break; | |
287 | break; | |
288 | } | |
289 | ||
290 | /* if we have copied something, adjust the copy count */ | |
291 | if(copy) | |
292 | /* copy is biased, '0' means 1 byte copy */ | |
293 | *(op-copy-1) = copy-1; | |
294 | else | |
295 | /* back, to overwrite the copy count */ | |
296 | op--; | |
297 | ||
298 | /* reset literal counter */ | |
299 | copy = 0; | |
300 | ||
301 | /* length is biased, '1' means a match of 3 bytes */ | |
302 | ip -= 3; | |
303 | len = ip - anchor; | |
304 | ||
305 | /* encode the match */ | |
306 | #if FASTLZ_LEVEL==2 | |
307 | if(distance < MAX_DISTANCE) | |
308 | { | |
309 | if(len < 7) | |
310 | { | |
311 | *op++ = (len << 5) + (distance >> 8); | |
312 | *op++ = (distance & 255); | |
313 | } | |
314 | else | |
315 | { | |
316 | *op++ = (7 << 5) + (distance >> 8); | |
317 | for(len-=7; len >= 255; len-= 255) | |
318 | *op++ = 255; | |
319 | *op++ = len; | |
320 | *op++ = (distance & 255); | |
321 | } | |
322 | } | |
323 | else | |
324 | { | |
325 | /* far away, but not yet in the another galaxy... */ | |
326 | if(len < 7) | |
327 | { | |
328 | distance -= MAX_DISTANCE; | |
329 | *op++ = (len << 5) + 31; | |
330 | *op++ = 255; | |
331 | *op++ = distance >> 8; | |
332 | *op++ = distance & 255; | |
333 | } | |
334 | else | |
335 | { | |
336 | distance -= MAX_DISTANCE; | |
337 | *op++ = (7 << 5) + 31; | |
338 | for(len-=7; len >= 255; len-= 255) | |
339 | *op++ = 255; | |
340 | *op++ = len; | |
341 | *op++ = 255; | |
342 | *op++ = distance >> 8; | |
343 | *op++ = distance & 255; | |
344 | } | |
345 | } | |
346 | #else | |
347 | ||
348 | if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) | |
349 | while(len > MAX_LEN-2) | |
350 | { | |
351 | *op++ = (7 << 5) + (distance >> 8); | |
352 | *op++ = MAX_LEN - 2 - 7 -2; | |
353 | *op++ = (distance & 255); | |
354 | len -= MAX_LEN-2; | |
355 | } | |
356 | ||
357 | if(len < 7) | |
358 | { | |
359 | *op++ = (len << 5) + (distance >> 8); | |
360 | *op++ = (distance & 255); | |
361 | } | |
362 | else | |
363 | { | |
364 | *op++ = (7 << 5) + (distance >> 8); | |
365 | *op++ = len - 7; | |
366 | *op++ = (distance & 255); | |
367 | } | |
368 | #endif | |
369 | ||
370 | /* update the hash at match boundary */ | |
371 | HASH_FUNCTION(hval,ip); | |
372 | htab[hval] = ip++; | |
373 | HASH_FUNCTION(hval,ip); | |
374 | htab[hval] = ip++; | |
375 | ||
376 | /* assuming literal copy */ | |
377 | *op++ = MAX_COPY-1; | |
378 | ||
379 | continue; | |
380 | ||
381 | literal: | |
382 | *op++ = *anchor++; | |
383 | ip = anchor; | |
384 | copy++; | |
385 | if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) | |
386 | { | |
387 | copy = 0; | |
388 | *op++ = MAX_COPY-1; | |
389 | } | |
390 | } | |
391 | ||
392 | /* left-over as literal copy */ | |
393 | ip_bound++; | |
394 | while(ip <= ip_bound) | |
395 | { | |
396 | *op++ = *ip++; | |
397 | copy++; | |
398 | if(copy == MAX_COPY) | |
399 | { | |
400 | copy = 0; | |
401 | *op++ = MAX_COPY-1; | |
402 | } | |
403 | } | |
404 | ||
405 | /* if we have copied something, adjust the copy length */ | |
406 | if(copy) | |
407 | *(op-copy-1) = copy-1; | |
408 | else | |
409 | op--; | |
410 | ||
411 | #if FASTLZ_LEVEL==2 | |
412 | /* marker for fastlz2 */ | |
413 | *(flzuint8*)output |= (1 << 5); | |
414 | #endif | |
415 | ||
416 | return op - (flzuint8*)output; | |
417 | } | |
418 | ||
419 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) | |
420 | { | |
421 | const flzuint8* ip = (const flzuint8*) input; | |
422 | const flzuint8* ip_limit = ip + length; | |
423 | flzuint8* op = (flzuint8*) output; | |
424 | flzuint8* op_limit = op + maxout; | |
425 | flzuint32 ctrl = (*ip++) & 31; | |
426 | int loop = 1; | |
427 | ||
428 | do | |
429 | { | |
430 | const flzuint8* ref = op; | |
431 | flzuint32 len = ctrl >> 5; | |
432 | flzuint32 ofs = (ctrl & 31) << 8; | |
433 | ||
434 | if(ctrl >= 32) | |
435 | { | |
436 | #if FASTLZ_LEVEL==2 | |
437 | flzuint8 code; | |
438 | #endif | |
439 | len--; | |
440 | ref -= ofs; | |
441 | if (len == 7-1) | |
442 | #if FASTLZ_LEVEL==1 | |
443 | len += *ip++; | |
444 | ref -= *ip++; | |
445 | #else | |
446 | do | |
447 | { | |
448 | code = *ip++; | |
449 | len += code; | |
450 | } while (code==255); | |
451 | code = *ip++; | |
452 | ref -= code; | |
453 | ||
454 | /* match from 16-bit distance */ | |
455 | if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) | |
456 | if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) | |
457 | { | |
458 | ofs = (*ip++) << 8; | |
459 | ofs += *ip++; | |
460 | ref = op - ofs - MAX_DISTANCE; | |
461 | } | |
462 | #endif | |
463 | ||
464 | #ifdef FASTLZ_SAFE | |
465 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) | |
466 | return 0; | |
467 | ||
468 | if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) | |
469 | return 0; | |
470 | #endif | |
471 | ||
472 | if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) | |
473 | ctrl = *ip++; | |
474 | else | |
475 | loop = 0; | |
476 | ||
477 | if(ref == op) | |
478 | { | |
479 | /* optimize copy for a run */ | |
480 | flzuint8 b = ref[-1]; | |
481 | *op++ = b; | |
482 | *op++ = b; | |
483 | *op++ = b; | |
484 | for(; len; --len) | |
485 | *op++ = b; | |
486 | } | |
487 | else | |
488 | { | |
489 | #if !defined(FASTLZ_STRICT_ALIGN) | |
490 | const flzuint16* p; | |
491 | flzuint16* q; | |
492 | #endif | |
493 | /* copy from reference */ | |
494 | ref--; | |
495 | *op++ = *ref++; | |
496 | *op++ = *ref++; | |
497 | *op++ = *ref++; | |
498 | ||
499 | #if !defined(FASTLZ_STRICT_ALIGN) | |
500 | /* copy a byte, so that now it's word aligned */ | |
501 | if(len & 1) | |
502 | { | |
503 | *op++ = *ref++; | |
504 | len--; | |
505 | } | |
506 | ||
507 | /* copy 16-bit at once */ | |
508 | q = (flzuint16*) op; | |
509 | op += len; | |
510 | p = (const flzuint16*) ref; | |
511 | for(len>>=1; len > 4; len-=4) | |
512 | { | |
513 | *q++ = *p++; | |
514 | *q++ = *p++; | |
515 | *q++ = *p++; | |
516 | *q++ = *p++; | |
517 | } | |
518 | for(; len; --len) | |
519 | *q++ = *p++; | |
520 | #else | |
521 | for(; len; --len) | |
522 | *op++ = *ref++; | |
523 | #endif | |
524 | } | |
525 | } | |
526 | else | |
527 | { | |
528 | ctrl++; | |
529 | #ifdef FASTLZ_SAFE | |
530 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) | |
531 | return 0; | |
532 | if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) | |
533 | return 0; | |
534 | #endif | |
535 | ||
536 | *op++ = *ip++; | |
537 | for(--ctrl; ctrl; ctrl--) | |
538 | *op++ = *ip++; | |
539 | ||
540 | loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); | |
541 | if(loop) | |
542 | ctrl = *ip++; | |
543 | } | |
544 | } | |
545 | while(FASTLZ_EXPECT_CONDITIONAL(loop)); | |
546 | ||
547 | return op - (flzuint8*)output; | |
548 | } | |
549 | ||
550 | #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ |
0 | /* | |
1 | FastLZ - lightning-fast lossless compression library | |
2 | ||
3 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) | |
4 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) | |
5 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) | |
6 | ||
7 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | of this software and associated documentation files (the "Software"), to deal | |
9 | in the Software without restriction, including without limitation the rights | |
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | copies of the Software, and to permit persons to whom the Software is | |
12 | furnished to do so, subject to the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included in | |
15 | all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #ifndef FASTLZ_H | |
27 | #define FASTLZ_H | |
28 | ||
29 | #define FASTLZ_VERSION 0x000100 | |
30 | ||
31 | #define FASTLZ_VERSION_MAJOR 0 | |
32 | #define FASTLZ_VERSION_MINOR 0 | |
33 | #define FASTLZ_VERSION_REVISION 0 | |
34 | ||
35 | #define FASTLZ_VERSION_STRING "0.1.0" | |
36 | ||
37 | #if defined (__cplusplus) | |
38 | extern "C" { | |
39 | #endif | |
40 | ||
41 | /** | |
42 | Compress a block of data in the input buffer and returns the size of | |
43 | compressed block. The size of input buffer is specified by length. The | |
44 | minimum input buffer size is 16. | |
45 | ||
46 | The output buffer must be at least 5% larger than the input buffer | |
47 | and can not be smaller than 66 bytes. | |
48 | ||
49 | If the input is not compressible, the return value might be larger than | |
50 | length (input buffer size). | |
51 | ||
52 | The input buffer and the output buffer can not overlap. | |
53 | */ | |
54 | ||
55 | int fastlz_compress(const void* input, int length, void* output); | |
56 | ||
57 | /** | |
58 | Decompress a block of compressed data and returns the size of the | |
59 | decompressed block. If error occurs, e.g. the compressed data is | |
60 | corrupted or the output buffer is not large enough, then 0 (zero) | |
61 | will be returned instead. | |
62 | ||
63 | The input buffer and the output buffer can not overlap. | |
64 | ||
65 | Decompression is memory safe and guaranteed not to write the output buffer | |
66 | more than what is specified in maxout. | |
67 | */ | |
68 | ||
69 | int fastlz_decompress(const void* input, int length, void* output, int maxout); | |
70 | ||
71 | /** | |
72 | Compress a block of data in the input buffer and returns the size of | |
73 | compressed block. The size of input buffer is specified by length. The | |
74 | minimum input buffer size is 16. | |
75 | ||
76 | The output buffer must be at least 5% larger than the input buffer | |
77 | and can not be smaller than 66 bytes. | |
78 | ||
79 | If the input is not compressible, the return value might be larger than | |
80 | length (input buffer size). | |
81 | ||
82 | The input buffer and the output buffer can not overlap. | |
83 | ||
84 | Compression level can be specified in parameter level. At the moment, | |
85 | only level 1 and level 2 are supported. | |
86 | Level 1 is the fastest compression and generally useful for short data. | |
87 | Level 2 is slightly slower but it gives better compression ratio. | |
88 | ||
89 | Note that the compressed data, regardless of the level, can always be | |
90 | decompressed using the function fastlz_decompress above. | |
91 | */ | |
92 | ||
93 | int fastlz_compress_level(int level, const void* input, int length, void* output); | |
94 | ||
95 | #if defined (__cplusplus) | |
96 | } | |
97 | #endif | |
98 | ||
99 | #endif /* FASTLZ_H */ |
0 | dnl $Id$ | |
1 | dnl config.m4 for extension yac | |
2 | ||
3 | PHP_ARG_ENABLE(yac, whether to enable yac support, | |
4 | [ --enable-yac Enable yac support]) | |
5 | ||
6 | PHP_ARG_WITH(system-fastlz, whether to use system FastLZ library, | |
7 | [ --with-system-fastlz Use system FastLZ library], no, no) | |
8 | ||
9 | PHP_ARG_ENABLE(json, whether to use igbinary as serializer, | |
10 | [ --enable-json Use igbinary as serializer], no, no) | |
11 | ||
12 | PHP_ARG_ENABLE(msgpack, whether to use msgpack as serializer, | |
13 | [ --enable-msgpack Use Messagepack as serializer], no, no) | |
14 | ||
15 | PHP_ARG_ENABLE(igbinary, whether to use igbinary as serializer, | |
16 | [ --enable-igbinary Use igbinary as serializer], no, no) | |
17 | ||
18 | dnl copied from Zend Optimizer Plus | |
19 | AC_MSG_CHECKING(for sysvipc shared memory support) | |
20 | AC_TRY_RUN([ | |
21 | #include <sys/types.h> | |
22 | #include <sys/wait.h> | |
23 | #include <sys/ipc.h> | |
24 | #include <sys/shm.h> | |
25 | #include <unistd.h> | |
26 | #include <string.h> | |
27 | ||
28 | int main() { | |
29 | pid_t pid; | |
30 | int status; | |
31 | int ipc_id; | |
32 | char *shm; | |
33 | struct shmid_ds shmbuf; | |
34 | ||
35 | ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W)); | |
36 | if (ipc_id == -1) { | |
37 | return 1; | |
38 | } | |
39 | ||
40 | shm = shmat(ipc_id, NULL, 0); | |
41 | if (shm == (void *)-1) { | |
42 | shmctl(ipc_id, IPC_RMID, NULL); | |
43 | return 2; | |
44 | } | |
45 | ||
46 | if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) { | |
47 | shmdt(shm); | |
48 | shmctl(ipc_id, IPC_RMID, NULL); | |
49 | return 3; | |
50 | } | |
51 | ||
52 | shmbuf.shm_perm.uid = getuid(); | |
53 | shmbuf.shm_perm.gid = getgid(); | |
54 | shmbuf.shm_perm.mode = 0600; | |
55 | ||
56 | if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) { | |
57 | shmdt(shm); | |
58 | shmctl(ipc_id, IPC_RMID, NULL); | |
59 | return 4; | |
60 | } | |
61 | ||
62 | shmctl(ipc_id, IPC_RMID, NULL); | |
63 | ||
64 | strcpy(shm, "hello"); | |
65 | ||
66 | pid = fork(); | |
67 | if (pid < 0) { | |
68 | return 5; | |
69 | } else if (pid == 0) { | |
70 | strcpy(shm, "bye"); | |
71 | return 6; | |
72 | } | |
73 | if (wait(&status) != pid) { | |
74 | return 7; | |
75 | } | |
76 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
77 | return 8; | |
78 | } | |
79 | if (strcmp(shm, "bye") != 0) { | |
80 | return 9; | |
81 | } | |
82 | return 0; | |
83 | } | |
84 | ],dnl | |
85 | AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support]) | |
86 | msg=yes,msg=no,msg=no) | |
87 | AC_MSG_RESULT([$msg]) | |
88 | ||
89 | AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support) | |
90 | AC_TRY_RUN([ | |
91 | #include <sys/types.h> | |
92 | #include <sys/wait.h> | |
93 | #include <sys/mman.h> | |
94 | #include <unistd.h> | |
95 | #include <string.h> | |
96 | ||
97 | #ifndef MAP_ANON | |
98 | # ifdef MAP_ANONYMOUS | |
99 | # define MAP_ANON MAP_ANONYMOUS | |
100 | # endif | |
101 | #endif | |
102 | #ifndef MAP_FAILED | |
103 | # define MAP_FAILED ((void*)-1) | |
104 | #endif | |
105 | ||
106 | int main() { | |
107 | pid_t pid; | |
108 | int status; | |
109 | char *shm; | |
110 | ||
111 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); | |
112 | if (shm == MAP_FAILED) { | |
113 | return 1; | |
114 | } | |
115 | ||
116 | strcpy(shm, "hello"); | |
117 | ||
118 | pid = fork(); | |
119 | if (pid < 0) { | |
120 | return 5; | |
121 | } else if (pid == 0) { | |
122 | strcpy(shm, "bye"); | |
123 | return 6; | |
124 | } | |
125 | if (wait(&status) != pid) { | |
126 | return 7; | |
127 | } | |
128 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
129 | return 8; | |
130 | } | |
131 | if (strcmp(shm, "bye") != 0) { | |
132 | return 9; | |
133 | } | |
134 | return 0; | |
135 | } | |
136 | ],dnl | |
137 | AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support]) | |
138 | msg=yes,msg=no,msg=no) | |
139 | AC_MSG_RESULT([$msg]) | |
140 | ||
141 | AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support) | |
142 | AC_TRY_RUN([ | |
143 | #include <sys/types.h> | |
144 | #include <sys/wait.h> | |
145 | #include <sys/mman.h> | |
146 | #include <sys/stat.h> | |
147 | #include <fcntl.h> | |
148 | #include <unistd.h> | |
149 | #include <string.h> | |
150 | ||
151 | #ifndef MAP_FAILED | |
152 | # define MAP_FAILED ((void*)-1) | |
153 | #endif | |
154 | ||
155 | int main() { | |
156 | pid_t pid; | |
157 | int status; | |
158 | int fd; | |
159 | char *shm; | |
160 | ||
161 | fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); | |
162 | if (fd == -1) { | |
163 | return 1; | |
164 | } | |
165 | ||
166 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | |
167 | if (shm == MAP_FAILED) { | |
168 | return 2; | |
169 | } | |
170 | ||
171 | strcpy(shm, "hello"); | |
172 | ||
173 | pid = fork(); | |
174 | if (pid < 0) { | |
175 | return 5; | |
176 | } else if (pid == 0) { | |
177 | strcpy(shm, "bye"); | |
178 | return 6; | |
179 | } | |
180 | if (wait(&status) != pid) { | |
181 | return 7; | |
182 | } | |
183 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { | |
184 | return 8; | |
185 | } | |
186 | if (strcmp(shm, "bye") != 0) { | |
187 | return 9; | |
188 | } | |
189 | return 0; | |
190 | } | |
191 | ],dnl | |
192 | AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support]) | |
193 | msg=yes,msg=no,msg=no) | |
194 | AC_MSG_RESULT([$msg]) | |
195 | ||
196 | if test "$PHP_MSGPACK" != "no"; then | |
197 | AC_DEFINE(YAC_ENABLE_MSGPACK, 1, [enable msgpack packager]) | |
198 | ifdef([PHP_ADD_EXTENSION_DEP], | |
199 | [ | |
200 | PHP_ADD_EXTENSION_DEP(yac, msgpack, true) | |
201 | ]) | |
202 | fi | |
203 | ||
204 | if test "$PHP_IGBINARY" != "no"; then | |
205 | AC_DEFINE(YAC_ENABLE_IGBINARY, 1, [enable igbinary packager]) | |
206 | ifdef([PHP_ADD_EXTENSION_DEP], | |
207 | [ | |
208 | PHP_ADD_EXTENSION_DEP(yac, igbinary, true) | |
209 | ]) | |
210 | fi | |
211 | ||
212 | if test "$PHP_JSON" != "no"; then | |
213 | AC_DEFINE(YAC_ENABLE_JSON, 1, [enable json packager]) | |
214 | ifdef([PHP_ADD_EXTENSION_DEP], | |
215 | [ | |
216 | PHP_ADD_EXTENSION_DEP(yac, json, true) | |
217 | ]) | |
218 | fi | |
219 | ||
220 | ifdef([PHP_CHECK_CPU_SUPPORTS], | |
221 | [ | |
222 | if test -x "$PHP_CONFIG"; then | |
223 | php_vernum=`$PHP_CONFIG --vernum` | |
224 | if test $php_vernum -ge 70300; then | |
225 | AC_CHECK_HEADERS([nmmintrin.h]) | |
226 | PHP_CHECK_CPU_SUPPORTS([sse4.2]) | |
227 | dnl Tricky way to remove unintentionally defines | |
228 | if test -e "confdefs.h"; then | |
229 | sed -i "/PHP_HAVE_/d" confdefs.h | |
230 | fi | |
231 | AC_MSG_CHECKING([for crc32 instruction supports]) | |
232 | if test $have_ext_instructions -eq 1; then | |
233 | AC_DEFINE([HAVE_SSE_CRC32], 1, [define if you have sse4.2 crc32 instruction support]) | |
234 | CFLAGS="$CFLAGS -msse4.2" | |
235 | AC_MSG_RESULT([yes]) | |
236 | else | |
237 | AC_MSG_RESULT([no]) | |
238 | fi | |
239 | fi | |
240 | fi | |
241 | ], []) | |
242 | ||
243 | AC_DEFUN([YAC_BUILTIN_ATOMIC], | |
244 | [ | |
245 | AC_MSG_CHECKING([for __sync_bool_compare_and_swap supports]) | |
246 | AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[ | |
247 | int variable = 1; | |
248 | return (__sync_bool_compare_and_swap(&variable, 1, 2) | |
249 | && __sync_add_and_fetch(&variable, 1)) ? 1 : 0; | |
250 | ]])], [ | |
251 | AC_MSG_RESULT([yes]) | |
252 | AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o.]) | |
253 | ], [ | |
254 | AC_MSG_RESULT([no]) | |
255 | ]) | |
256 | ]) | |
257 | ||
258 | YAC_BUILTIN_ATOMIC | |
259 | ||
260 | YAC_FILES="yac.c storage/yac_storage.c storage/allocator/yac_allocator.c storage/allocator/allocators/shm.c storage/allocator/allocators/mmap.c serializer/php.c serializer/msgpack.c serializer/igbinary.c serializer/json.c" | |
261 | if test "$PHP_SYSTEM_FASTLZ" != "no"; then | |
262 | AC_CHECK_HEADERS([fastlz.h]) | |
263 | PHP_CHECK_LIBRARY(fastlz, fastlz_compress, | |
264 | [PHP_ADD_LIBRARY(fastlz, 1, YAC_SHARED_LIBADD)], | |
265 | [AC_MSG_ERROR(FastLZ library not found)]) | |
266 | else | |
267 | YAC_FILES="${YAC_FILES} compressor/fastlz/fastlz.c" | |
268 | fi | |
269 | ||
270 | if test "$PHP_YAC" != "no"; then | |
271 | PHP_SUBST(YAC_SHARED_LIBADD) | |
272 | PHP_NEW_EXTENSION(yac, ${YAC_FILES}, $ext_shared) | |
273 | PHP_ADD_BUILD_DIR([$ext_builddir/storage]) | |
274 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator]) | |
275 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator/allocators]) | |
276 | PHP_ADD_BUILD_DIR([$ext_builddir/serializer]) | |
277 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor]) | |
278 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor/fastlz]) | |
279 | fi |
0 | // $Id$ | |
1 | // vim:ft=javascript | |
2 | ||
3 | ARG_ENABLE("yac", "enable yac support", "no"); | |
4 | ||
5 | if (PHP_YAC != "no") { | |
6 | if( CHECK_HEADER_ADD_INCLUDE("fastlz.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\compressor\\fastlz") && | |
7 | CHECK_HEADER_ADD_INCLUDE("yac_serializer.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\serializer") && | |
8 | CHECK_HEADER_ADD_INCLUDE("yac_storage.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage") && | |
9 | CHECK_HEADER_ADD_INCLUDE("yac_allocator.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage\\allocator")) { | |
10 | ||
11 | EXTENSION("yac", "yac.c"); | |
12 | ||
13 | ADD_SOURCES(configure_module_dirname + "\\compressor\\fastlz", "fastlz.c", "yac"); | |
14 | ADD_SOURCES(configure_module_dirname + "\\serializer", "php.c", "yac"); | |
15 | ADD_SOURCES(configure_module_dirname + "\\storage", "yac_storage.c", "yac"); | |
16 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator", "yac_allocator.c", "yac"); | |
17 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator\\allocators", "createfilemapping.c", "yac"); | |
18 | ||
19 | AC_DEFINE('HAVE_YAC', 1, 'Have yac library'); | |
20 | ||
21 | ADD_FLAG("CFLAGS_YAC", ' /I "' + configure_module_dirname + '" '); | |
22 | ||
23 | } else { | |
24 | WARNING("yac not enabled, headers not found"); | |
25 | } | |
26 | } | |
27 |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef PHP_YAC_H | |
21 | #define PHP_YAC_H | |
22 | ||
23 | extern zend_module_entry yac_module_entry; | |
24 | #define phpext_yac_ptr &yac_module_entry | |
25 | ||
26 | #ifdef PHP_WIN32 | |
27 | #define PHP_YAC_API __declspec(dllexport) | |
28 | #else | |
29 | #define PHP_YAC_API | |
30 | #endif | |
31 | ||
32 | #ifdef ZTS | |
33 | #include "TSRM.h" | |
34 | #endif | |
35 | ||
36 | #define PHP_YAC_VERSION "2.2.1" | |
37 | ||
38 | #if PHP_VERSION_ID < 70400 | |
39 | #define YAC_WHANDLER void | |
40 | #define YAC_WHANDLER_RET(zv) return | |
41 | #else | |
42 | #define YAC_WHANDLER zval * | |
43 | #define YAC_WHANDLER_RET(zv) return zv | |
44 | #endif | |
45 | ||
46 | #define YAC_CLASS_PROPERTY_PREFIX "_prefix" | |
47 | #define YAC_ENTRY_COMPRESSED 0x0020 | |
48 | #define YAC_ENTRY_TYPE_MASK 0x1f | |
49 | #define YAC_ENTRY_ORIG_LEN_SHIT 6 | |
50 | #define YAC_ENTRY_MAX_ORIG_LEN ((1U << ((sizeof(int)*8 - YAC_ENTRY_ORIG_LEN_SHIT))) - 1) | |
51 | #define YAC_MIN_COMPRESS_THRESHOLD 1024 | |
52 | ||
53 | #define YAC_SERIALIZER_PHP 0 | |
54 | #define YAC_SERIALIZER_JSON 1 | |
55 | #define YAC_SERIALIZER_MSGPACK 2 | |
56 | #define YAC_SERIALIZER_IGBINARY 3 | |
57 | ||
58 | ZEND_BEGIN_MODULE_GLOBALS(yac) | |
59 | zend_bool enable; | |
60 | zend_bool debug; | |
61 | size_t k_msize; | |
62 | size_t v_msize; | |
63 | zend_ulong compress_threshold; | |
64 | zend_bool enable_cli; | |
65 | char *serializer; | |
66 | #ifdef PHP_WIN32 | |
67 | char *mmap_base; | |
68 | #endif | |
69 | ZEND_END_MODULE_GLOBALS(yac) | |
70 | ||
71 | PHP_MINIT_FUNCTION(yac); | |
72 | PHP_MSHUTDOWN_FUNCTION(yac); | |
73 | PHP_RINIT_FUNCTION(yac); | |
74 | PHP_RSHUTDOWN_FUNCTION(yac); | |
75 | PHP_MINFO_FUNCTION(yac); | |
76 | ||
77 | ZEND_EXTERN_MODULE_GLOBALS(yac); | |
78 | #define YAC_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(yac, v) | |
79 | ||
80 | #endif /* PHP_YAC_H */ | |
81 | /* | |
82 | * Local variables: | |
83 | * tab-width: 4 | |
84 | * c-basic-offset: 4 | |
85 | * End: | |
86 | * vim600: noet sw=4 ts=4 fdm=marker | |
87 | * vim<600: noet sw=4 ts=4 | |
88 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | | Remi Collet <remi@php.net> | | |
16 | +----------------------------------------------------------------------+ | |
17 | */ | |
18 | ||
19 | #ifdef HAVE_CONFIG_H | |
20 | #include "config.h" | |
21 | #endif | |
22 | ||
23 | #ifdef YAC_ENABLE_IGBINARY | |
24 | ||
25 | #include "php.h" | |
26 | #include "ext/igbinary/igbinary.h" | |
27 | #include "zend_smart_str.h" /* for smart_str */ | |
28 | ||
29 | #include "yac_serializer.h" | |
30 | ||
31 | int yac_serializer_igbinary_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
32 | uint8_t *ret; | |
33 | size_t ret_len; | |
34 | ||
35 | if (igbinary_serialize(&ret, &ret_len, pzval) == 0) { | |
36 | smart_str_appendl(buf, (const char *)ret, ret_len); | |
37 | efree(ret); | |
38 | return 1; | |
39 | } | |
40 | return 0; | |
41 | } /* }}} */ | |
42 | ||
43 | zval * yac_serializer_igbinary_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
44 | ||
45 | ZVAL_NULL(rv); | |
46 | igbinary_unserialize((uint8_t *)content, len, rv); | |
47 | return rv; | |
48 | } /* }}} */ | |
49 | ||
50 | #endif | |
51 | ||
52 | /* | |
53 | * Local variables: | |
54 | * tab-width: 4 | |
55 | * c-basic-offset: 4 | |
56 | * End: | |
57 | * vim600: noet sw=4 ts=4 fdm=marker | |
58 | * vim<600: noet sw=4 ts=4 | |
59 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifdef HAVE_CONFIG_H | |
21 | #include "config.h" | |
22 | #endif | |
23 | ||
24 | #if YAC_ENABLE_JSON | |
25 | ||
26 | #include "php.h" | |
27 | #include "ext/json/php_json.h" | |
28 | #include "zend_smart_str.h" /* for smart_str */ | |
29 | ||
30 | #include "yac_serializer.h" | |
31 | ||
32 | int yac_serializer_json_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
33 | #if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3)) | |
34 | php_json_encode(buf, pzval); | |
35 | #else | |
36 | php_json_encode(buf, pzval, 0); /* options */ | |
37 | #endif | |
38 | ||
39 | return 1; | |
40 | } /* }}} */ | |
41 | ||
42 | zval* yac_serializer_json_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
43 | ZVAL_NULL(rv); | |
44 | php_json_decode(rv, content, len, 1, 512); | |
45 | ||
46 | return rv; | |
47 | } /* }}} */ | |
48 | ||
49 | #endif | |
50 | ||
51 | /* | |
52 | * Local variables: | |
53 | * tab-width: 4 | |
54 | * c-basic-offset: 4 | |
55 | * End: | |
56 | * vim600: noet sw=4 ts=4 fdm=marker | |
57 | * vim<600: noet sw=4 ts=4 | |
58 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yar - Light, concurrent RPC framework | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2012-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | | Zhenyu Zhang <zhangzhenyu@php.net> | | |
16 | +----------------------------------------------------------------------+ | |
17 | */ | |
18 | ||
19 | /* $Id$ */ | |
20 | ||
21 | #ifdef HAVE_CONFIG_H | |
22 | #include "config.h" | |
23 | #endif | |
24 | ||
25 | #ifdef YAC_ENABLE_MSGPACK | |
26 | ||
27 | #include "php.h" | |
28 | #include "ext/msgpack/php_msgpack.h" | |
29 | #include "zend_smart_str.h" /* for smart_str */ | |
30 | ||
31 | #include "yac_serializer.h" | |
32 | ||
33 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
34 | php_msgpack_serialize(buf, pzval); | |
35 | return 1; | |
36 | } /* }}} */ | |
37 | ||
38 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
39 | ZVAL_NULL(rv); | |
40 | php_msgpack_unserialize(rv, content, len); | |
41 | return rv; | |
42 | } /* }}} */ | |
43 | ||
44 | #endif | |
45 | ||
46 | /* | |
47 | * Local variables: | |
48 | * tab-width: 4 | |
49 | * c-basic-offset: 4 | |
50 | * End: | |
51 | * vim600: noet sw=4 ts=4 fdm=marker | |
52 | * vim<600: noet sw=4 ts=4 | |
53 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifdef HAVE_CONFIG_H | |
21 | #include "config.h" | |
22 | #endif | |
23 | ||
24 | #include "php.h" | |
25 | #include "ext/standard/php_var.h" /* for serialize */ | |
26 | #include "zend_smart_str.h" | |
27 | ||
28 | #include "yac_serializer.h" | |
29 | ||
30 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ { | |
31 | php_serialize_data_t var_hash; | |
32 | ||
33 | PHP_VAR_SERIALIZE_INIT(var_hash); | |
34 | php_var_serialize(buf, pzval, &var_hash); | |
35 | PHP_VAR_SERIALIZE_DESTROY(var_hash); | |
36 | ||
37 | return 1; | |
38 | } /* }}} */ | |
39 | ||
40 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ { | |
41 | const unsigned char *p; | |
42 | php_unserialize_data_t var_hash; | |
43 | p = (const unsigned char*)content; | |
44 | ||
45 | ZVAL_FALSE(rv); | |
46 | PHP_VAR_UNSERIALIZE_INIT(var_hash); | |
47 | if (!php_var_unserialize(rv, &p, p + len, &var_hash)) { | |
48 | zval_ptr_dtor(rv); | |
49 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
50 | /* spprintf(msg, 0, "unpack error at offset %ld of %ld bytes", (long)((char*)p - content), len); */ | |
51 | return NULL; | |
52 | } | |
53 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
54 | ||
55 | return rv; | |
56 | } /* }}} */ | |
57 | ||
58 | /* | |
59 | * Local variables: | |
60 | * tab-width: 4 | |
61 | * c-basic-offset: 4 | |
62 | * End: | |
63 | * vim600: noet sw=4 ts=4 fdm=marker | |
64 | * vim<600: noet sw=4 ts=4 | |
65 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef YAC_SERIALIZER_H | |
21 | #define YAC_SERIALIZER_H | |
22 | ||
23 | typedef int (*yac_serializer_t)(zval*, smart_str*, char**); | |
24 | typedef zval* (*yac_unserializer_t)(char *, size_t, char**, zval*); | |
25 | ||
26 | #ifdef YAC_ENABLE_MSGPACK | |
27 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg); | |
28 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv); | |
29 | #endif | |
30 | ||
31 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg); | |
32 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv); | |
33 | ||
34 | #ifdef YAC_ENABLE_IGBINARY | |
35 | int yac_serializer_igbinary_pack(zval *pzval, smart_str *buf, char **msg); | |
36 | zval * yac_serializer_igbinary_unpack(char *content, size_t len, char **msg, zval *rv); | |
37 | #endif | |
38 | ||
39 | #ifdef YAC_ENABLE_JSON | |
40 | int yac_serializer_json_pack(zval *pzval, smart_str *buf, char **msg); | |
41 | zval * yac_serializer_json_unpack(char *content, size_t len, char **msg, zval *rv); | |
42 | #endif | |
43 | ||
44 | #endif /* YAC_SERIALIZER_H */ | |
45 | ||
46 | /* | |
47 | * Local variables: | |
48 | * tab-width: 4 | |
49 | * c-basic-offset: 4 | |
50 | * End: | |
51 | * vim600: noet sw=4 ts=4 fdm=marker | |
52 | * vim<600: noet sw=4 ts=4 | |
53 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | | Dmitry Stogov <dmitry@zend.com> | | |
16 | | Wei Dai <demon@php.net> | | |
17 | +----------------------------------------------------------------------+ | |
18 | */ | |
19 | ||
20 | #include "php.h" | |
21 | ||
22 | #include "php_yac.h" | |
23 | #include "storage/yac_storage.h" | |
24 | #include "storage/allocator/yac_allocator.h" | |
25 | ||
26 | #include <stdio.h> | |
27 | #include <windows.h> | |
28 | #include <Lmcons.h> | |
29 | ||
30 | #define ACCEL_FILEMAP_NAME "Yac.SharedMemoryArea" | |
31 | #define ACCEL_FILEMAP_BASE "Yac.MemoryBase" | |
32 | #define MAX_MAP_RETRIES 25 | |
33 | ||
34 | static HANDLE memfile = NULL; | |
35 | static void *mapping_base; | |
36 | ||
37 | typedef struct { | |
38 | yac_shared_segment common; | |
39 | unsigned long size; | |
40 | } yac_shared_segment_create_file; | |
41 | ||
42 | #ifdef USE_FILE_MAPPING | |
43 | static char *create_name_with_username(char *name) /* {{{ */ { | |
44 | static char newname[MAXPATHLEN + UNLEN + 4]; | |
45 | char uname[UNLEN + 1]; | |
46 | DWORD unsize = UNLEN; | |
47 | ||
48 | GetUserName(uname, &unsize); | |
49 | snprintf(newname, sizeof(newname) - 1, "%s@%s", name, uname); | |
50 | return newname; | |
51 | } | |
52 | /* }}} */ | |
53 | ||
54 | static char *get_mmap_base_file(void) /* {{{ */ { | |
55 | static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@")]; | |
56 | char uname[UNLEN + 1]; | |
57 | DWORD unsize = UNLEN; | |
58 | int l; | |
59 | ||
60 | GetTempPath(MAXPATHLEN, windir); | |
61 | GetUserName(uname, &unsize); | |
62 | l = strlen(windir); | |
63 | snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s", ACCEL_FILEMAP_BASE, uname); | |
64 | return windir; | |
65 | } | |
66 | /* }}} */ | |
67 | ||
68 | static int yac_shared_alloc_reattach(size_t requested_size, char **error_in) /* {{{ */ { | |
69 | void *wanted_mapping_base; | |
70 | char *mmap_base_file = get_mmap_base_file(); | |
71 | FILE *fp = fopen(mmap_base_file, "r"); | |
72 | MEMORY_BASIC_INFORMATION info; | |
73 | ||
74 | if (!fp) { | |
75 | *error_in="fopen"; | |
76 | return ALLOC_FAILURE; | |
77 | } | |
78 | ||
79 | if (!fscanf(fp, "%p", &wanted_mapping_base)) { | |
80 | *error_in="read mapping base"; | |
81 | fclose(fp); | |
82 | return ALLOC_FAILURE; | |
83 | } | |
84 | fclose(fp); | |
85 | ||
86 | /* Check if the requested address space is free */ | |
87 | if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0) { | |
88 | *error_in="VirtualQuery"; | |
89 | return ALLOC_FAILURE; | |
90 | } | |
91 | ||
92 | if (info.State != MEM_FREE) { | |
93 | *error_in="info.State"; | |
94 | return ALLOC_FAILURE; | |
95 | } | |
96 | ||
97 | if (info.RegionSize < requested_size) { | |
98 | *error_in="info.RegionSize"; | |
99 | return ALLOC_FAILURE; | |
100 | } | |
101 | ||
102 | mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base); | |
103 | ||
104 | if (mapping_base == NULL) { | |
105 | return ALLOC_FAIL_MAPPING; | |
106 | } | |
107 | ||
108 | return SUCCESSFULLY_REATTACHED; | |
109 | } | |
110 | /* }}} */ | |
111 | ||
112 | static int create_segments(unsigned long k_size, unsigned long v_size, yac_shared_segment_create_file **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
113 | int ret; | |
114 | unsigned long allocate_size, occupied_size = 0; | |
115 | unsigned int i, segment_size, segments_num = 1024, is_reattach = 0; | |
116 | int map_retries = 0; | |
117 | yac_shared_segment_create_file first_segment; | |
118 | void *default_mapping_base_set[] = {0, 0}; | |
119 | /* TODO: | |
120 | improve fixed addresses on x64. It still makes no sense to do it as Windows addresses are virtual per se and can or should be randomized anyway | |
121 | through Address Space Layout Radomization (ASLR). We can still let the OS do its job and be sure that each process gets the same address if | |
122 | desired. Not done yet, @zend refused but did not remember the exact reason, pls add info here if one of you know why :) | |
123 | */ | |
124 | #if defined(_WIN64) | |
125 | void *vista_mapping_base_set[] = { (void *) 0x0000100000000000, (void *) 0x0000200000000000, (void *) 0x0000300000000000, (void *) 0x0000700000000000, 0 }; | |
126 | #else | |
127 | void *vista_mapping_base_set[] = { (void *) 0x20000000, (void *) 0x21000000, (void *) 0x30000000, (void *) 0x31000000, (void *) 0x50000000, 0 }; | |
128 | #endif | |
129 | void **wanted_mapping_base = default_mapping_base_set; | |
130 | ||
131 | ||
132 | k_size = YAC_SMM_ALIGNED_SIZE(k_size); | |
133 | v_size = YAC_SMM_ALIGNED_SIZE(v_size); | |
134 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
135 | segments_num >>= 1; | |
136 | } | |
137 | ||
138 | segment_size = v_size / segments_num; | |
139 | ++segments_num; | |
140 | ||
141 | allocate_size = k_size + v_size; | |
142 | ||
143 | /* Mapping retries: When Apache2 restarts, the parent process startup routine | |
144 | can be called before the child process is killed. In this case, the map will fail | |
145 | and we have to sleep some time (until the child releases the mapping object) and retry.*/ | |
146 | do { | |
147 | memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME)); | |
148 | if (memfile == NULL) { | |
149 | break; | |
150 | } | |
151 | ||
152 | ret = yac_shared_alloc_reattach((size_t)k_size, error_in); | |
153 | if (ret == ALLOC_FAIL_MAPPING) { | |
154 | /* Mapping failed, wait for mapping object to get freed and retry */ | |
155 | CloseHandle(memfile); | |
156 | memfile = NULL; | |
157 | Sleep(1000 * (map_retries + 1)); | |
158 | } else if (ret == SUCCESSFULLY_REATTACHED) { | |
159 | is_reattach = 1; | |
160 | break; | |
161 | } else { | |
162 | return ret; | |
163 | } | |
164 | } while (++map_retries < MAX_MAP_RETRIES); | |
165 | ||
166 | if (map_retries == MAX_MAP_RETRIES) { | |
167 | *error_in = "OpenFileMapping"; | |
168 | return 0; | |
169 | } | |
170 | ||
171 | *shared_segments_p = (yac_shared_segment_create_file *)calloc(1, segments_num * sizeof(yac_shared_segment_create_file)); | |
172 | if(!*shared_segments_p) { | |
173 | *error_in = "calloc"; | |
174 | return 0; | |
175 | } | |
176 | *shared_segments_count = segments_num; | |
177 | ||
178 | /* Starting from windows Vista, heap randomization occurs which might cause our mapping base to | |
179 | be taken (fail to map). So under Vista, we try to map into a hard coded predefined addresses | |
180 | in high memory. */ | |
181 | if (!YAC_G(mmap_base) || !*YAC_G(mmap_base)) { | |
182 | do { | |
183 | OSVERSIONINFOEX osvi; | |
184 | SYSTEM_INFO si; | |
185 | ||
186 | ZeroMemory(&si, sizeof(SYSTEM_INFO)); | |
187 | ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | |
188 | ||
189 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
190 | ||
191 | if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) { | |
192 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
193 | if (!GetVersionEx((OSVERSIONINFO *)&osvi)) { | |
194 | break; | |
195 | } | |
196 | } | |
197 | ||
198 | GetSystemInfo(&si); | |
199 | ||
200 | /* Are we running Vista ? */ | |
201 | if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6) { | |
202 | wanted_mapping_base = vista_mapping_base_set; | |
203 | } | |
204 | } while (0); | |
205 | } else { | |
206 | char *s = YAC_G(mmap_base); | |
207 | ||
208 | /* skip leading 0x, %p assumes hexdeciaml format anyway */ | |
209 | if (*s == '0' && *(s + 1) == 'x') { | |
210 | s += 2; | |
211 | } | |
212 | if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) { | |
213 | *error_in = "mapping"; | |
214 | return 0; | |
215 | } | |
216 | } | |
217 | ||
218 | if (is_reattach == 0) { | |
219 | memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, allocate_size, create_name_with_username(ACCEL_FILEMAP_NAME)); | |
220 | if (memfile == NULL) { | |
221 | *error_in = "CreateFileMapping"; | |
222 | return 0; | |
223 | } | |
224 | ||
225 | do { | |
226 | first_segment.common.p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base); | |
227 | if (wanted_mapping_base == NULL) { | |
228 | break; | |
229 | } | |
230 | *wanted_mapping_base++; | |
231 | } while (!mapping_base); | |
232 | } | |
233 | ||
234 | if(mapping_base == NULL) { | |
235 | *error_in = "MapViewOfFileEx"; | |
236 | return 0; | |
237 | } else { | |
238 | char *mmap_base_file = get_mmap_base_file(); | |
239 | FILE *fp = fopen(mmap_base_file, "w"); | |
240 | if (!fp) { | |
241 | *error_in = "get_mmap_base_file"; | |
242 | return 0; | |
243 | } | |
244 | fprintf(fp, "%p", mapping_base); | |
245 | fclose(fp); | |
246 | } | |
247 | ||
248 | first_segment.common.p = mapping_base; | |
249 | first_segment.size = allocate_size; | |
250 | first_segment.common.size = k_size; | |
251 | first_segment.common.pos = 0; | |
252 | ||
253 | (*shared_segments_p)[0] = first_segment; | |
254 | ||
255 | occupied_size = k_size; | |
256 | for (i = 1; i < segments_num; i++) { | |
257 | (*shared_segments_p)[i].size = 0; | |
258 | (*shared_segments_p)[i].common.pos = 0; | |
259 | (*shared_segments_p)[i].common.p = (void *)((char *)first_segment.common.p + occupied_size); | |
260 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) { | |
261 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
262 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size); | |
263 | } else { | |
264 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size); | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | return 1; | |
270 | } | |
271 | /* }}} */ | |
272 | ||
273 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ { | |
274 | if (!shared_segment->size && mapping_base) { | |
275 | UnmapViewOfFile(mapping_base); | |
276 | CloseHandle(memfile); | |
277 | } | |
278 | return 0; | |
279 | } | |
280 | /* }}} */ | |
281 | ||
282 | static unsigned long segment_type_size(void) /* {{{ */ { | |
283 | return sizeof(yac_shared_segment_create_file); | |
284 | } | |
285 | /* }}} */ | |
286 | ||
287 | yac_shared_memory_handlers yac_alloc_create_file_handlers = /* {{{ */ { | |
288 | (create_segments_t)create_segments, | |
289 | detach_segment, | |
290 | segment_type_size | |
291 | }; | |
292 | /* }}} */ | |
293 | #endif /* USE_CREATE_FILE */ | |
294 | ||
295 | /* | |
296 | * Local variables: | |
297 | * tab-width: 4 | |
298 | * c-basic-offset: 4 | |
299 | * End: | |
300 | * vim600: noet sw=4 ts=4 fdm=marker | |
301 | * vim<600: noet sw=4 ts=4 | |
302 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include "storage/yac_storage.h" | |
19 | #include "storage/allocator/yac_allocator.h" | |
20 | ||
21 | #ifdef USE_MMAP | |
22 | ||
23 | #include <sys/types.h> | |
24 | #include <sys/stat.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <sys/mman.h> | |
28 | ||
29 | #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) | |
30 | # define MAP_ANONYMOUS MAP_ANON | |
31 | #endif | |
32 | ||
33 | #ifndef MAP_FAILED | |
34 | #define MAP_FAILED (void *)-1 | |
35 | #endif | |
36 | ||
37 | typedef struct { | |
38 | yac_shared_segment common; | |
39 | unsigned long size; | |
40 | } yac_shared_segment_mmap; | |
41 | ||
42 | static int create_segments(unsigned long k_size, unsigned long v_size, yac_shared_segment_mmap **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
43 | unsigned long allocate_size, occupied_size = 0; | |
44 | unsigned int i, segment_size, segments_num = 1024; | |
45 | yac_shared_segment_mmap first_segment; | |
46 | ||
47 | k_size = YAC_SMM_ALIGNED_SIZE(k_size); | |
48 | v_size = YAC_SMM_ALIGNED_SIZE(v_size); | |
49 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
50 | segments_num >>= 1; | |
51 | } | |
52 | ||
53 | segment_size = v_size / segments_num; | |
54 | ++segments_num; | |
55 | ||
56 | allocate_size = k_size + v_size; | |
57 | ||
58 | first_segment.common.p = mmap(0, allocate_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); | |
59 | if (first_segment.common.p == MAP_FAILED) { | |
60 | *error_in = "mmap"; | |
61 | return 0; | |
62 | } | |
63 | first_segment.size = allocate_size; | |
64 | first_segment.common.size = k_size; | |
65 | first_segment.common.pos = 0; | |
66 | ||
67 | *shared_segments_p = (yac_shared_segment_mmap *)calloc(1, segments_num * sizeof(yac_shared_segment_mmap)); | |
68 | if (!*shared_segments_p) { | |
69 | munmap(first_segment.common.p, first_segment.size); | |
70 | *error_in = "calloc"; | |
71 | return 0; | |
72 | } else { | |
73 | *shared_segments_p[0] = first_segment; | |
74 | } | |
75 | *shared_segments_count = segments_num; | |
76 | ||
77 | occupied_size = k_size; | |
78 | for (i = 1; i < segments_num; i++) { | |
79 | (*shared_segments_p)[i].size = 0; | |
80 | (*shared_segments_p)[i].common.pos = 0; | |
81 | (*shared_segments_p)[i].common.p = first_segment.common.p + occupied_size; | |
82 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) { | |
83 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
84 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size); | |
85 | } else { | |
86 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size); | |
87 | break; | |
88 | } | |
89 | } | |
90 | ||
91 | return 1; | |
92 | } | |
93 | /* }}} */ | |
94 | ||
95 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ { | |
96 | if (shared_segment->size) { | |
97 | munmap(shared_segment->p, shared_segment->size); | |
98 | } | |
99 | return 0; | |
100 | } | |
101 | /* }}} */ | |
102 | ||
103 | static unsigned long segment_type_size(void) /* {{{ */ { | |
104 | return sizeof(yac_shared_segment_mmap); | |
105 | } | |
106 | /* }}} */ | |
107 | ||
108 | yac_shared_memory_handlers yac_alloc_mmap_handlers = /* {{{ */ { | |
109 | (create_segments_t)create_segments, | |
110 | detach_segment, | |
111 | segment_type_size | |
112 | }; | |
113 | /* }}} */ | |
114 | ||
115 | #endif /* USE_MMAP */ | |
116 | ||
117 | /* | |
118 | * Local variables: | |
119 | * tab-width: 4 | |
120 | * c-basic-offset: 4 | |
121 | * End: | |
122 | * vim600: noet sw=4 ts=4 fdm=marker | |
123 | * vim<600: noet sw=4 ts=4 | |
124 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include "storage/yac_storage.h" | |
19 | #include "storage/allocator/yac_allocator.h" | |
20 | ||
21 | #ifdef USE_SHM | |
22 | ||
23 | #if defined(__FreeBSD__) | |
24 | # include <machine/param.h> | |
25 | #endif | |
26 | #include <sys/types.h> | |
27 | #include <sys/shm.h> | |
28 | #include <sys/ipc.h> | |
29 | #include <dirent.h> | |
30 | #include <signal.h> | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <unistd.h> | |
34 | #include <errno.h> | |
35 | ||
36 | #include <sys/stat.h> | |
37 | #include <fcntl.h> | |
38 | ||
39 | typedef struct { | |
40 | yac_shared_segment common; | |
41 | int shm_id; | |
42 | } yac_shared_segment_shm; | |
43 | ||
44 | static int create_segments(size_t k_size, size_t v_size, yac_shared_segment_shm **shared_segments_p, int *shared_segments_count, char **error_in) /* {{{ */ { | |
45 | struct shmid_ds sds; | |
46 | int shm_id, shmget_flags; | |
47 | yac_shared_segment_shm *shared_segments, first_segment; | |
48 | unsigned int i, j, allocate_size, allocated_num, segments_num, segment_size; | |
49 | ||
50 | shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; | |
51 | segments_num = 1024; | |
52 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) { | |
53 | segments_num >>= 1; | |
54 | } | |
55 | segment_size = v_size / segments_num; | |
56 | allocate_size = YAC_SMM_SEGMENT_MAX_SIZE; | |
57 | ||
58 | while ((shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags)) < 0) { | |
59 | allocate_size >>= 1; | |
60 | } | |
61 | ||
62 | if (shm_id < 0) { | |
63 | /* this should never happen */ | |
64 | *error_in = "shmget"; | |
65 | return 0; | |
66 | } | |
67 | ||
68 | if (allocate_size < YAC_SMM_SEGMENT_MIN_SIZE) { | |
69 | /* this should never happen */ | |
70 | *error_in = "shmget"; | |
71 | return 0; | |
72 | } | |
73 | ||
74 | if (k_size <= allocate_size) { | |
75 | first_segment.shm_id = shm_id; | |
76 | first_segment.common.pos = 0; | |
77 | first_segment.common.size = allocate_size; | |
78 | first_segment.common.p = shmat(shm_id, NULL, 0); | |
79 | shmctl(shm_id, IPC_RMID, &sds); | |
80 | if (first_segment.common.p == (void *)-1) { | |
81 | *error_in = "shmat"; | |
82 | return 0; | |
83 | } | |
84 | } else { | |
85 | shmctl(shm_id, IPC_RMID, &sds); | |
86 | *error_in = "shmget"; | |
87 | return 0; | |
88 | } | |
89 | ||
90 | allocated_num = (v_size % allocate_size)? (v_size / allocate_size) + 1 : (v_size / allocate_size); | |
91 | shared_segments = (yac_shared_segment_shm *)calloc(1, (allocated_num) * sizeof(yac_shared_segment_shm)); | |
92 | if (!shared_segments) { | |
93 | *error_in = "calloc"; | |
94 | return 0; | |
95 | } | |
96 | ||
97 | for (i = 0; i < allocated_num; i ++) { | |
98 | shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags); | |
99 | if (shm_id == -1) { | |
100 | *error_in = "shmget"; | |
101 | for (j = 0; j < i; j++) { | |
102 | shmdt(shared_segments[j].common.p); | |
103 | } | |
104 | free(shared_segments); | |
105 | return 0; | |
106 | } | |
107 | shared_segments[i].shm_id = shm_id; | |
108 | shared_segments[i].common.pos = 0; | |
109 | shared_segments[i].common.size = allocate_size; | |
110 | shared_segments[i].common.p = shmat(shm_id, NULL, 0); | |
111 | shmctl(shm_id, IPC_RMID, &sds); | |
112 | if (shared_segments[i].common.p == (void *)-1) { | |
113 | *error_in = "shmat"; | |
114 | for (j = 0; j < i; j++) { | |
115 | shmdt(shared_segments[j].common.p); | |
116 | } | |
117 | free(shared_segments); | |
118 | return 0; | |
119 | } | |
120 | } | |
121 | ||
122 | ++segments_num; | |
123 | *shared_segments_p = (yac_shared_segment_shm *)calloc(1, segments_num * sizeof(yac_shared_segment_shm)); | |
124 | if (!*shared_segments_p) { | |
125 | free(shared_segments); | |
126 | *error_in = "calloc"; | |
127 | return 0; | |
128 | } else { | |
129 | *shared_segments_p[0] = first_segment; | |
130 | } | |
131 | *shared_segments_count = segments_num; | |
132 | ||
133 | j = 0; | |
134 | for (i = 1; i < segments_num; i++) { | |
135 | if (shared_segments[j].common.pos == 0) { | |
136 | (*shared_segments_p)[i].shm_id = shared_segments[j].shm_id; | |
137 | } | |
138 | ||
139 | if ((shared_segments[j].common.size - shared_segments[j].common.pos) >= (2 * YAC_SMM_ALIGNED_SIZE(segment_size))) { | |
140 | (*shared_segments_p)[i].common.pos = 0; | |
141 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size); | |
142 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); | |
143 | shared_segments[j].common.pos += YAC_SMM_ALIGNED_SIZE(segment_size); | |
144 | } else { | |
145 | (*shared_segments_p)[i].common.pos = 0; | |
146 | (*shared_segments_p)[i].common.size = shared_segments[j].common.size - shared_segments[j].common.pos; | |
147 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos); | |
148 | j++; | |
149 | } | |
150 | } | |
151 | ||
152 | free(shared_segments); | |
153 | ||
154 | return 1; | |
155 | } | |
156 | /* }}} */ | |
157 | ||
158 | static int detach_segment(yac_shared_segment_shm *shared_segment) /* {{{ */ { | |
159 | if (shared_segment->shm_id) { | |
160 | shmdt(shared_segment->common.p); | |
161 | } | |
162 | return 1; | |
163 | } | |
164 | /* }}} */ | |
165 | ||
166 | static size_t segment_type_size(void) /* {{{ */ { | |
167 | return sizeof(yac_shared_segment_shm); | |
168 | } | |
169 | /* }}} */ | |
170 | ||
171 | yac_shared_memory_handlers yac_alloc_shm_handlers = /* {{{ */ { | |
172 | (create_segments_t)create_segments, | |
173 | (detach_segment_t)detach_segment, | |
174 | segment_type_size | |
175 | }; | |
176 | /* }}} */ | |
177 | ||
178 | #endif /* USE_SHM */ | |
179 | ||
180 | /* | |
181 | * Local variables: | |
182 | * tab-width: 4 | |
183 | * c-basic-offset: 4 | |
184 | * End: | |
185 | * vim600: noet sw=4 ts=4 fdm=marker | |
186 | * vim<600: noet sw=4 ts=4 | |
187 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #include <errno.h> | |
19 | #include <time.h> | |
20 | #include <sys/types.h> | |
21 | ||
22 | #include "php.h" | |
23 | #include "storage/yac_storage.h" | |
24 | #include "yac_allocator.h" | |
25 | ||
26 | int yac_allocator_startup(unsigned long k_size, unsigned long size, char **msg) /* {{{ */ { | |
27 | char *p; | |
28 | yac_shared_segment *segments = NULL; | |
29 | int i, segments_num, segments_array_size, segment_size; | |
30 | const yac_shared_memory_handlers *he; | |
31 | ||
32 | if ((he = &yac_shared_memory_handler)) { | |
33 | int ret = he->create_segments(k_size, size, &segments, &segments_num, msg); | |
34 | ||
35 | if (!ret) { | |
36 | if (segments) { | |
37 | int i; | |
38 | for (i = 0; i < segments_num; i++) { | |
39 | if (segments[i].p && segments[i].p != (void *)-1) { | |
40 | he->detach_segment(&segments[i]); | |
41 | } | |
42 | } | |
43 | free(segments); | |
44 | } | |
45 | return 0; | |
46 | } | |
47 | } else { | |
48 | return 0; | |
49 | } | |
50 | ||
51 | segment_size = he->segment_type_size(); | |
52 | segments_array_size = (segments_num - 1) * segment_size; | |
53 | ||
54 | yac_storage = segments[0].p; | |
55 | memcpy(&YAC_SG(first_seg), (char *)(&segments[0]), segment_size); | |
56 | ||
57 | YAC_SG(segments_num) = segments_num - 1; | |
58 | YAC_SG(segments_num_mask) = YAC_SG(segments_num) - 1; | |
59 | YAC_SG(segments) = (yac_shared_segment **)((char *)yac_storage + YAC_SMM_ALIGNED_SIZE(sizeof(yac_storage_globals) + segment_size - sizeof(yac_shared_segment))); | |
60 | ||
61 | p = (char *)YAC_SG(segments) + (sizeof(void *) * YAC_SG(segments_num)); | |
62 | memcpy(p, (char *)segments + segment_size, segments_array_size); | |
63 | for (i = 0; i < YAC_SG(segments_num); i++) { | |
64 | YAC_SG(segments)[i] = (yac_shared_segment *)p; | |
65 | p += segment_size; | |
66 | } | |
67 | YAC_SG(slots) = (yac_kv_key *)((char *)YAC_SG(segments) | |
68 | + (YAC_SG(segments_num) * sizeof(void *)) + YAC_SMM_ALIGNED_SIZE(segments_array_size)); | |
69 | ||
70 | free(segments); | |
71 | ||
72 | return 1; | |
73 | } | |
74 | /* }}} */ | |
75 | ||
76 | void yac_allocator_shutdown(void) /* {{{ */ { | |
77 | yac_shared_segment **segments; | |
78 | const yac_shared_memory_handlers *he; | |
79 | ||
80 | segments = YAC_SG(segments); | |
81 | if (segments) { | |
82 | if ((he = &yac_shared_memory_handler)) { | |
83 | int i = 0; | |
84 | for (i = 0; i < YAC_SG(segments_num); i++) { | |
85 | he->detach_segment(segments[i]); | |
86 | } | |
87 | he->detach_segment(&YAC_SG(first_seg)); | |
88 | } | |
89 | } | |
90 | } | |
91 | /* }}} */ | |
92 | ||
93 | static inline void *yac_allocator_alloc_algo2(unsigned long size, int hash) /* {{{ */ { | |
94 | yac_shared_segment *segment; | |
95 | unsigned int seg_size, retry, pos, current; | |
96 | ||
97 | current = hash & YAC_SG(segments_num_mask); | |
98 | /* do we really need lock here? it depends the real life exam */ | |
99 | retry = 3; | |
100 | do_retry: | |
101 | segment = YAC_SG(segments)[current]; | |
102 | seg_size = segment->size; | |
103 | pos = segment->pos; | |
104 | if ((seg_size - pos) >= size) { | |
105 | do_alloc: | |
106 | pos += size; | |
107 | segment->pos = pos; | |
108 | if (segment->pos == pos) { | |
109 | return (void *)((char *)segment->p + (pos - size)); | |
110 | } else if (retry--) { | |
111 | goto do_retry; | |
112 | } | |
113 | return NULL; | |
114 | } else { | |
115 | int i, max; | |
116 | max = (YAC_SG(segments_num) > 4)? 4 : YAC_SG(segments_num); | |
117 | for (i = 1; i < max; i++) { | |
118 | segment = YAC_SG(segments)[(current + i) & YAC_SG(segments_num_mask)]; | |
119 | seg_size = segment->size; | |
120 | pos = segment->pos; | |
121 | if ((seg_size - pos) >= size) { | |
122 | current = (current + i) & YAC_SG(segments_num_mask); | |
123 | goto do_alloc; | |
124 | } | |
125 | } | |
126 | segment->pos = 0; | |
127 | pos = 0; | |
128 | ++YAC_SG(recycles); | |
129 | goto do_alloc; | |
130 | } | |
131 | } | |
132 | /* }}} */ | |
133 | ||
134 | #if 0 | |
135 | static inline void *yac_allocator_alloc_algo1(unsigned long size) /* {{{ */ { | |
136 | int i, j, picked_seg, atime; | |
137 | picked_seg = (YAC_SG(current_seg) + 1) & YAC_SG(segments_num_mask); | |
138 | ||
139 | atime = YAC_SG(segments)[picked_seg]->atime; | |
140 | for (i = 0; i < 10; i++) { | |
141 | j = (picked_seg + 1) & YAC_SG(segments_num_mask); | |
142 | if (YAC_SG(segments)[j]->atime < atime) { | |
143 | picked_seg = j; | |
144 | atime = YAC_SG(segments)[j]->atime; | |
145 | } | |
146 | } | |
147 | ||
148 | YAC_SG(current_seg) = picked_seg; | |
149 | YAC_SG(segments)[picked_seg]->pos = 0; | |
150 | return yac_allocator_alloc_algo2(size); | |
151 | } | |
152 | /* }}} */ | |
153 | #endif | |
154 | ||
155 | unsigned long yac_allocator_real_size(unsigned long size) /* {{{ */ { | |
156 | unsigned long real_size = YAC_SMM_TRUE_SIZE(size); | |
157 | ||
158 | if (real_size > YAC_SG(segments)[0]->size) { | |
159 | return 0; | |
160 | } | |
161 | ||
162 | return real_size; | |
163 | } | |
164 | /* }}} */ | |
165 | ||
166 | void * yac_allocator_raw_alloc(unsigned long real_size, int hash) /* {{{ */ { | |
167 | ||
168 | return yac_allocator_alloc_algo2(real_size, hash); | |
169 | /* | |
170 | if (YAC_SG(exhausted)) { | |
171 | return yac_allocator_alloc_algo1(real_size); | |
172 | } else { | |
173 | void *p; | |
174 | if ((p = yac_allocator_alloc_algo2(real_size))) { | |
175 | return p; | |
176 | } | |
177 | return yac_allocator_alloc_algo1(real_size); | |
178 | } | |
179 | */ | |
180 | } | |
181 | /* }}} */ | |
182 | ||
183 | #if 0 | |
184 | void yac_allocator_touch(void *p, unsigned long atime) /* {{{ */ { | |
185 | yac_shared_block_header h = *(yac_shared_block_header *)(p - sizeof(yac_shared_block_header)); | |
186 | ||
187 | if (h.seg >= YAC_SG(segments_num)) { | |
188 | return; | |
189 | } | |
190 | ||
191 | YAC_SG(segments)[h.seg]->atime = atime; | |
192 | } | |
193 | /* }}} */ | |
194 | #endif | |
195 | ||
196 | /* | |
197 | * Local variables: | |
198 | * tab-width: 4 | |
199 | * c-basic-offset: 4 | |
200 | * End: | |
201 | * vim600: noet sw=4 ts=4 fdm=marker | |
202 | * vim<600: noet sw=4 ts=4 | |
203 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Authors: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #ifndef YAC_ALLOCATOR_H | |
19 | #define YAC_ALLOCATOR_H | |
20 | ||
21 | #ifdef HAVE_CONFIG_H | |
22 | #include "config.h" | |
23 | #endif | |
24 | ||
25 | #define YAC_SMM_ALIGNMENT 8 | |
26 | #define YAC_SMM_ALIGNMENT_LOG2 3 | |
27 | #define YAC_SMM_ALIGNMENT_MASK ~(YAC_SMM_ALIGNMENT - 1) | |
28 | #define YAC_SMM_BLOCK_HEADER_SIZE YAC_SMM_ALIGNED_SIZE(sizeof(yac_shared_block_header)) | |
29 | ||
30 | #define YAC_SMM_MAIN_SEG_SIZE (4*1024*1024) | |
31 | #define YAC_SMM_SEGMENT_MAX_SIZE (32*1024*1024) | |
32 | #define YAC_SMM_SEGMENT_MIN_SIZE (4*1024*1024) | |
33 | #define YAC_SMM_MIN_BLOCK_SIZE 128 | |
34 | #define YAC_SMM_ALIGNED_SIZE(x) (((x) + YAC_SMM_ALIGNMENT - 1) & YAC_SMM_ALIGNMENT_MASK) | |
35 | #define YAC_SMM_TRUE_SIZE(x) ((x < YAC_SMM_MIN_BLOCK_SIZE)? (YAC_SMM_MIN_BLOCK_SIZE) : (YAC_SMM_ALIGNED_SIZE(x))) | |
36 | ||
37 | #ifdef PHP_WIN32 | |
38 | # define USE_FILE_MAPPING 1 | |
39 | # define inline __inline | |
40 | #elif defined(HAVE_SHM_MMAP_ANON) | |
41 | # define USE_MMAP 1 | |
42 | #elif defined(HAVE_SHM_IPC) | |
43 | # define USE_SHM 1 | |
44 | #else | |
45 | #error(no builtin shared memory supported) | |
46 | #endif | |
47 | ||
48 | #define ALLOC_FAILURE 0 | |
49 | #define ALLOC_SUCCESS 1 | |
50 | #define FAILED_REATTACHED 2 | |
51 | #define SUCCESSFULLY_REATTACHED 4 | |
52 | #define ALLOC_FAIL_MAPPING 8 | |
53 | ||
54 | typedef int (*create_segments_t)(unsigned long k_size, unsigned long v_size, yac_shared_segment **shared_segments, int *shared_segment_count, char **error_in); | |
55 | typedef int (*detach_segment_t)(yac_shared_segment *shared_segment); | |
56 | ||
57 | typedef struct { | |
58 | create_segments_t create_segments; | |
59 | detach_segment_t detach_segment; | |
60 | unsigned long (*segment_type_size)(void); | |
61 | } yac_shared_memory_handlers; | |
62 | ||
63 | typedef struct { | |
64 | const char *name; | |
65 | yac_shared_memory_handlers *handler; | |
66 | } yac_shared_memory_handler_entry; | |
67 | ||
68 | int yac_allocator_startup(unsigned long first_seg_size, unsigned long size, char **err); | |
69 | void yac_allocator_shutdown(void); | |
70 | unsigned long yac_allocator_real_size(unsigned long size); | |
71 | void *yac_allocator_raw_alloc(unsigned long real_size, int seg); | |
72 | int yac_allocator_free(void *p); | |
73 | ||
74 | static inline void * yac_allocator_alloc(unsigned long size, int seg) { | |
75 | unsigned long real_size = yac_allocator_real_size(size); | |
76 | if (!real_size) { | |
77 | return (void *)0; | |
78 | } | |
79 | return yac_allocator_raw_alloc(real_size, seg); | |
80 | } | |
81 | ||
82 | #if defined(USE_MMAP) | |
83 | extern yac_shared_memory_handlers yac_alloc_mmap_handlers; | |
84 | #define yac_shared_memory_handler yac_alloc_mmap_handlers | |
85 | #define YAC_SHARED_MEMORY_HANDLER_NAME "mmap" | |
86 | #elif defined(USE_SHM) | |
87 | extern yac_shared_memory_handlers yac_alloc_shm_handlers; | |
88 | #define yac_shared_memory_handler yac_alloc_shm_handlers | |
89 | #define YAC_SHARED_MEMORY_HANDLER_NAME "shm" | |
90 | #elif defined(USE_FILE_MAPPING) | |
91 | extern yac_shared_memory_handlers yac_alloc_create_file_handlers; | |
92 | #define yac_shared_memory_handler yac_alloc_create_file_handlers | |
93 | #define YAC_SHARED_MEMORY_HANDLER_NAME "file_mapping" | |
94 | #endif | |
95 | ||
96 | #endif /* YAC_ALLOCATOR_H */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | | John Neo <nhf0424@gmail.com> | | |
16 | +----------------------------------------------------------------------+ | |
17 | */ | |
18 | ||
19 | #ifndef YAC_ATOMIC_H | |
20 | #define YAC_ATOMIC_H | |
21 | ||
22 | #ifdef HAVE_CONFIG_H | |
23 | #include "config.h" | |
24 | #endif | |
25 | ||
26 | #if HAVE_BUILTIN_ATOMIC | |
27 | #define YAC_CAS(lock, old, set) __sync_bool_compare_and_swap(lock, old, set) | |
28 | #elif ( __amd64__ || __amd64 || __x86_64__ || __i386__ || __i386 ) | |
29 | static inline int __yac_cas(unsigned int *lock, unsigned int old, unsigned int set) { | |
30 | unsigned char res; | |
31 | ||
32 | __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" : | |
33 | "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory"); | |
34 | ||
35 | return res; | |
36 | } | |
37 | #define YAC_CAS(lock, old, set) __yac_cas(lock, old, set) | |
38 | #elif ZEND_WIN32 | |
39 | #define YAC_CAS(lock, old, set) (InterlockedCompareExchange(lock, set, old) == old) | |
40 | #else | |
41 | #undef YAC_CAS | |
42 | #warning No atomic CAS supports | |
43 | #endif | |
44 | ||
45 | #ifdef YAC_CAS | |
46 | ||
47 | #define MUT_READ 0x0 | |
48 | #define MUT_WRITE 0x1 | |
49 | #define CAS_MAX_SPIN 100 | |
50 | ||
51 | static inline int yac_mutex_write(unsigned int *me) { | |
52 | int retry = 0; | |
53 | while (!YAC_CAS(me, MUT_READ, MUT_WRITE)) { | |
54 | if (++retry == CAS_MAX_SPIN) { | |
55 | return 0; | |
56 | } | |
57 | } | |
58 | return 1; | |
59 | } | |
60 | ||
61 | static inline void yac_mutex_read(unsigned int *me) { | |
62 | *me = MUT_READ; | |
63 | } | |
64 | ||
65 | #define WRITEP(P) yac_mutex_write(&(P->mutex)) | |
66 | #define READP(P) yac_mutex_read(&(P->mutex)) | |
67 | #else | |
68 | #undef YAC_CAS | |
69 | #define WRITEP(P) (1) | |
70 | #define READP(P) | |
71 | #endif | |
72 | ||
73 | #endif |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | #ifdef HAVE_CONFIG_H | |
19 | #include "config.h" | |
20 | #endif | |
21 | ||
22 | #include "php.h" | |
23 | ||
24 | #if HAVE_SSE_CRC32 | |
25 | #include "Zend/zend_cpuinfo.h" | |
26 | #include <nmmintrin.h> | |
27 | static uint32_t crc32c_sse42(const char *dagta, unsigned int size); | |
28 | #endif | |
29 | ||
30 | #include "yac_atomic.h" | |
31 | #include "yac_storage.h" | |
32 | #include "allocator/yac_allocator.h" | |
33 | ||
34 | yac_storage_globals *yac_storage; | |
35 | ||
36 | static uint32_t (*yac_crc)(const char *data, unsigned int size); | |
37 | static uint32_t crc32(const char *dagta, unsigned int size); | |
38 | ||
39 | static inline unsigned int yac_storage_align_size(unsigned int size) /* {{{ */ { | |
40 | int bits = 0; | |
41 | while ((size = size >> 1)) { | |
42 | ++bits; | |
43 | } | |
44 | return (1 << bits); | |
45 | } | |
46 | /* }}} */ | |
47 | ||
48 | int yac_storage_startup(unsigned long fsize, unsigned long size, char **msg) /* {{{ */ { | |
49 | unsigned long real_size; | |
50 | ||
51 | if (!yac_allocator_startup(fsize, size, msg)) { | |
52 | return 0; | |
53 | } | |
54 | #if HAVE_SSE_CRC32 | |
55 | if (zend_cpu_supports_sse42()) { | |
56 | yac_crc = crc32c_sse42; | |
57 | } else | |
58 | #endif | |
59 | { | |
60 | yac_crc = crc32; | |
61 | } | |
62 | size = YAC_SG(first_seg).size - ((char *)YAC_SG(slots) - (char *)yac_storage); | |
63 | real_size = yac_storage_align_size(size / sizeof(yac_kv_key)); | |
64 | if (!((size / sizeof(yac_kv_key)) & ~(real_size << 1))) { | |
65 | real_size <<= 1; | |
66 | } | |
67 | ||
68 | YAC_SG(slots_size) = real_size; | |
69 | YAC_SG(slots_mask) = real_size - 1; | |
70 | YAC_SG(slots_num) = 0; | |
71 | YAC_SG(fails) = 0; | |
72 | YAC_SG(hits) = 0; | |
73 | YAC_SG(miss) = 0; | |
74 | YAC_SG(kicks) = 0; | |
75 | ||
76 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * real_size); | |
77 | ||
78 | return 1; | |
79 | } | |
80 | /* }}} */ | |
81 | ||
82 | void yac_storage_shutdown(void) /* {{{ */ { | |
83 | yac_allocator_shutdown(); | |
84 | } | |
85 | /* }}} */ | |
86 | ||
87 | /* {{{ MurmurHash2 (Austin Appleby) | |
88 | */ | |
89 | static inline uint64_t yac_inline_hash_func1(const char *data, unsigned int len) { | |
90 | unsigned int h, k; | |
91 | ||
92 | h = 0 ^ len; | |
93 | ||
94 | while (len >= 4) { | |
95 | k = data[0]; | |
96 | k |= data[1] << 8; | |
97 | k |= data[2] << 16; | |
98 | k |= data[3] << 24; | |
99 | ||
100 | k *= 0x5bd1e995; | |
101 | k ^= k >> 24; | |
102 | k *= 0x5bd1e995; | |
103 | ||
104 | h *= 0x5bd1e995; | |
105 | h ^= k; | |
106 | ||
107 | data += 4; | |
108 | len -= 4; | |
109 | } | |
110 | ||
111 | switch (len) { | |
112 | case 3: | |
113 | h ^= data[2] << 16; | |
114 | case 2: | |
115 | h ^= data[1] << 8; | |
116 | case 1: | |
117 | h ^= data[0]; | |
118 | h *= 0x5bd1e995; | |
119 | } | |
120 | ||
121 | h ^= h >> 13; | |
122 | h *= 0x5bd1e995; | |
123 | h ^= h >> 15; | |
124 | ||
125 | return h; | |
126 | } | |
127 | /* }}} */ | |
128 | ||
129 | /* {{{ DJBX33A (Daniel J. Bernstein, Times 33 with Addition) | |
130 | * | |
131 | * This is Daniel J. Bernstein's popular `times 33' hash function as | |
132 | * posted by him years ago on comp->lang.c. It basically uses a function | |
133 | * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best | |
134 | * known hash functions for strings. Because it is both computed very | |
135 | * fast and distributes very well. | |
136 | * | |
137 | * The magic of number 33, i.e. why it works better than many other | |
138 | * constants, prime or not, has never been adequately explained by | |
139 | * anyone. So I try an explanation: if one experimentally tests all | |
140 | * multipliers between 1 and 256 (as RSE did now) one detects that even | |
141 | * numbers are not useable at all. The remaining 128 odd numbers | |
142 | * (except for the number 1) work more or less all equally well. They | |
143 | * all distribute in an acceptable way and this way fill a hash table | |
144 | * with an average percent of approx. 86%. | |
145 | * | |
146 | * If one compares the Chi^2 values of the variants, the number 33 not | |
147 | * even has the best value. But the number 33 and a few other equally | |
148 | * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great | |
149 | * advantage to the remaining numbers in the large set of possible | |
150 | * multipliers: their multiply operation can be replaced by a faster | |
151 | * operation based on just one shift plus either a single addition | |
152 | * or subtraction operation. And because a hash function has to both | |
153 | * distribute good _and_ has to be very fast to compute, those few | |
154 | * numbers should be preferred and seems to be the reason why Daniel J. | |
155 | * Bernstein also preferred it. | |
156 | * | |
157 | * | |
158 | * -- Ralf S. Engelschall <rse@engelschall.com> | |
159 | */ | |
160 | ||
161 | static inline uint64_t yac_inline_hash_func2(const char *key, uint32_t len) { | |
162 | register uint64_t hash = 5381; | |
163 | ||
164 | /* variant with the hash unrolled eight times */ | |
165 | for (; len >= 8; len -= 8) { | |
166 | hash = ((hash << 5) + hash) + *key++; | |
167 | hash = ((hash << 5) + hash) + *key++; | |
168 | hash = ((hash << 5) + hash) + *key++; | |
169 | hash = ((hash << 5) + hash) + *key++; | |
170 | hash = ((hash << 5) + hash) + *key++; | |
171 | hash = ((hash << 5) + hash) + *key++; | |
172 | hash = ((hash << 5) + hash) + *key++; | |
173 | hash = ((hash << 5) + hash) + *key++; | |
174 | } | |
175 | switch (len) { | |
176 | case 7: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
177 | case 6: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
178 | case 5: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
179 | case 4: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
180 | case 3: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
181 | case 2: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */ | |
182 | case 1: hash = ((hash << 5) + hash) + *key++; break; | |
183 | case 0: break; | |
184 | default: break; | |
185 | } | |
186 | return hash; | |
187 | } | |
188 | /* }}} */ | |
189 | ||
190 | /* {{{ COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or | |
191 | * code or tables extracted from it, as desired without restriction. | |
192 | * | |
193 | * First, the polynomial itself and its table of feedback terms. The | |
194 | * polynomial is | |
195 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 | |
196 | * | |
197 | * Note that we take it "backwards" and put the highest-order term in | |
198 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the | |
199 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in | |
200 | * the MSB being 1 | |
201 | * | |
202 | * Note that the usual hardware shift register implementation, which | |
203 | * is what we're using (we're merely optimizing it by doing eight-bit | |
204 | * chunks at a time) shifts bits into the lowest-order term. In our | |
205 | * implementation, that means shifting towards the right. Why do we | |
206 | * do it this way? Because the calculated CRC must be transmitted in | |
207 | * order from highest-order term to lowest-order term. UARTs transmit | |
208 | * characters in order from LSB to MSB. By storing the CRC this way | |
209 | * we hand it to the UART in the order low-byte to high-byte; the UART | |
210 | * sends each low-bit to hight-bit; and the result is transmission bit | |
211 | * by bit from highest- to lowest-order term without requiring any bit | |
212 | * shuffling on our part. Reception works similarly | |
213 | * | |
214 | * The feedback terms table consists of 256, 32-bit entries. Notes | |
215 | * | |
216 | * The table can be generated at runtime if desired; code to do so | |
217 | * is shown later. It might not be obvious, but the feedback | |
218 | * terms simply represent the results of eight shift/xor opera | |
219 | * tions for all combinations of data and CRC register values | |
220 | * | |
221 | * The values must be right-shifted by eight bits by the "updcrc | |
222 | * logic; the shift must be unsigned (bring in zeroes). On some | |
223 | * hardware you could probably optimize the shift in assembler by | |
224 | * using byte-swap instructions | |
225 | * polynomial $edb88320 | |
226 | * | |
227 | * | |
228 | * CRC32 code derived from work by Gary S. Brown. | |
229 | */ | |
230 | ||
231 | static unsigned int crc32_tab[] = { | |
232 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | |
233 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | |
234 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | |
235 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | |
236 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | |
237 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | |
238 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | |
239 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | |
240 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | |
241 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | |
242 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | |
243 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | |
244 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | |
245 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | |
246 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | |
247 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | |
248 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | |
249 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | |
250 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | |
251 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | |
252 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | |
253 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | |
254 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | |
255 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | |
256 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | |
257 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | |
258 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | |
259 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | |
260 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | |
261 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | |
262 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | |
263 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | |
264 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | |
265 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | |
266 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | |
267 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | |
268 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | |
269 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | |
270 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | |
271 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | |
272 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | |
273 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | |
274 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | |
275 | }; | |
276 | ||
277 | static uint32_t crc32(const char *buf, unsigned int size) { | |
278 | const char *p; | |
279 | uint32_t crc = 0 ^ 0xFFFFFFFF; | |
280 | ||
281 | p = buf; | |
282 | while (size--) { | |
283 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); | |
284 | } | |
285 | ||
286 | return crc ^ 0xFFFFFFFF; | |
287 | } | |
288 | /* }}} */ | |
289 | ||
290 | #if HAVE_SSE_CRC32 | |
291 | static uint32_t crc32c_sse42(const char *buf, unsigned int size) /* {{{ */ { | |
292 | uint32_t crc = 0 ^ 0xFFFFFFFF; | |
293 | #if __x86_64__ | |
294 | while (size >= sizeof(uint64_t)) { | |
295 | crc = _mm_crc32_u64(crc, *(uint64_t*)buf); | |
296 | buf += sizeof(uint64_t); | |
297 | size -= sizeof(uint64_t); | |
298 | } | |
299 | #endif | |
300 | while (size >= sizeof(uint32_t)) { | |
301 | crc = _mm_crc32_u32(crc, *(uint32_t*)buf); | |
302 | buf += sizeof(uint32_t); | |
303 | size -= sizeof(uint32_t); | |
304 | } | |
305 | if (size >= sizeof(uint16_t)) { | |
306 | crc = _mm_crc32_u16(crc, *(uint16_t*)buf); | |
307 | buf += sizeof(uint16_t); | |
308 | size -= sizeof(uint16_t); | |
309 | } | |
310 | if (size) { | |
311 | crc = _mm_crc32_u8(crc, *buf); | |
312 | } | |
313 | ||
314 | return crc ^ 0xFFFFFFFF; | |
315 | } | |
316 | /* }}} */ | |
317 | #endif | |
318 | ||
319 | static inline unsigned int yac_crc32(char *data, unsigned int size) /* {{{ */ { | |
320 | if (size < YAC_FULL_CRC_THRESHOLD) { | |
321 | return yac_crc(data, size); | |
322 | } else { | |
323 | int i = 0; | |
324 | char crc_contents[YAC_FULL_CRC_THRESHOLD]; | |
325 | int head = YAC_FULL_CRC_THRESHOLD >> 2; | |
326 | int tail = YAC_FULL_CRC_THRESHOLD >> 4; | |
327 | int body = YAC_FULL_CRC_THRESHOLD - head - tail; | |
328 | char *p = data + head; | |
329 | char *q = crc_contents + head; | |
330 | int step = (size - tail - head) / body; | |
331 | ||
332 | memcpy(crc_contents, data, head); | |
333 | for (; i < body; i++, q++, p+= step) { | |
334 | *q = *p; | |
335 | } | |
336 | memcpy(q, p, tail); | |
337 | ||
338 | return yac_crc(crc_contents, YAC_FULL_CRC_THRESHOLD); | |
339 | } | |
340 | } | |
341 | /* }}} */ | |
342 | ||
343 | int yac_storage_find(const char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv) /* {{{ */ { | |
344 | uint64_t h, hash, seed; | |
345 | yac_kv_key k, *p; | |
346 | yac_kv_val v; | |
347 | ||
348 | hash = h = yac_inline_hash_func1(key, len); | |
349 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
350 | if (!WRITEP(p)) { | |
351 | ++YAC_SG(miss); | |
352 | return 0; | |
353 | } | |
354 | k = *p; | |
355 | READP(p); | |
356 | if (k.val) { | |
357 | char *s; | |
358 | uint32_t i; | |
359 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
360 | v = *(k.val); | |
361 | if (!memcmp(k.key, key, len)) { | |
362 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1); | |
363 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k)); | |
364 | do_verify: | |
365 | if (k.len != v.len) { | |
366 | USER_FREE(s); | |
367 | ++YAC_SG(miss); | |
368 | return 0; | |
369 | } | |
370 | ||
371 | if (k.ttl) { | |
372 | if (k.ttl <= tv) { | |
373 | ++YAC_SG(miss); | |
374 | USER_FREE(s); | |
375 | return 0; | |
376 | } | |
377 | } | |
378 | ||
379 | if (k.crc != yac_crc32(s, YAC_KEY_VLEN(k))) { | |
380 | USER_FREE(s); | |
381 | ++YAC_SG(miss); | |
382 | return 0; | |
383 | } | |
384 | s[YAC_KEY_VLEN(k)] = '\0'; | |
385 | k.val->atime = tv; | |
386 | *data = s; | |
387 | *size = YAC_KEY_VLEN(k); | |
388 | *flag = k.flag; | |
389 | ++YAC_SG(hits); | |
390 | return 1; | |
391 | } | |
392 | } | |
393 | ||
394 | seed = yac_inline_hash_func2(key, len); | |
395 | for (i = 0; i < 3; i++) { | |
396 | h += seed & YAC_SG(slots_mask); | |
397 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
398 | if (!WRITEP(p)) { | |
399 | ++YAC_SG(miss); | |
400 | return 0; | |
401 | } | |
402 | k = *p; | |
403 | READP(p); | |
404 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
405 | v = *(k.val); | |
406 | if (!memcmp(k.key, key, len)) { | |
407 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1); | |
408 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k)); | |
409 | goto do_verify; | |
410 | } | |
411 | } | |
412 | } | |
413 | } | |
414 | ||
415 | ++YAC_SG(miss); | |
416 | ||
417 | return 0; | |
418 | } | |
419 | /* }}} */ | |
420 | ||
421 | int yac_storage_delete(const char *key, unsigned int len, int ttl, unsigned long tv) /* {{{ */ { | |
422 | uint64_t hash, h, seed; | |
423 | yac_kv_key k, *p; | |
424 | ||
425 | hash = h = yac_inline_hash_func1(key, len); | |
426 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
427 | if (!WRITEP(p)) { | |
428 | return 0; | |
429 | } | |
430 | k = *p; | |
431 | READP(p); | |
432 | if (k.val) { | |
433 | uint32_t i; | |
434 | if (k.h == hash && YAC_KEY_KLEN(k) == len) { | |
435 | if (!memcmp((char *)k.key, key, len)) { | |
436 | if (ttl == 0) { | |
437 | p->ttl = 1; | |
438 | } else { | |
439 | p->ttl = ttl + tv; | |
440 | } | |
441 | return 1; | |
442 | } | |
443 | } | |
444 | ||
445 | seed = yac_inline_hash_func2(key, len); | |
446 | for (i = 0; i < 3; i++) { | |
447 | h += seed & YAC_SG(slots_mask); | |
448 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
449 | if (!WRITEP(p)) { | |
450 | return 0; | |
451 | } | |
452 | k = *p; | |
453 | READP(p); | |
454 | if (k.val == NULL) { | |
455 | return 1; | |
456 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
457 | p->ttl = 1; | |
458 | return 1; | |
459 | } | |
460 | } | |
461 | } | |
462 | ||
463 | return 0; | |
464 | } | |
465 | /* }}} */ | |
466 | ||
467 | int yac_storage_update(const char *key, unsigned int len, char *data, unsigned int size, unsigned int flag, int ttl, int add, unsigned long tv) /* {{{ */ { | |
468 | uint64_t hash, h; | |
469 | int idx = 0, is_valid; | |
470 | yac_kv_key *p, k, *paths[4]; | |
471 | yac_kv_val *val, *s; | |
472 | unsigned long real_size; | |
473 | ||
474 | hash = h = yac_inline_hash_func1(key, len); | |
475 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
476 | if (!WRITEP(p)) { | |
477 | return 0; | |
478 | } | |
479 | k = *p; | |
480 | READP(p); | |
481 | if (k.val) { | |
482 | /* Found the exact match */ | |
483 | if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
484 | do_update: | |
485 | is_valid = 0; | |
486 | if (k.crc == yac_crc32(k.val->data, YAC_KEY_VLEN(k))) { | |
487 | is_valid = 1; | |
488 | } | |
489 | if (add && (!k.ttl || k.ttl > tv) && is_valid) { | |
490 | return 0; | |
491 | } | |
492 | if (k.size >= size && is_valid) { | |
493 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
494 | memcpy(s->data, data, size); | |
495 | if (ttl) { | |
496 | k.ttl = (uint64_t)tv + ttl; | |
497 | } else { | |
498 | k.ttl = 0; | |
499 | } | |
500 | s->atime = tv; | |
501 | YAC_KEY_SET_LEN(*s, len, size); | |
502 | memcpy((char *)k.val, (char *)s, sizeof(yac_kv_val) + size - 1); | |
503 | k.crc = yac_crc32(s->data, size); | |
504 | k.flag = flag; | |
505 | memcpy(k.key, key, len); | |
506 | YAC_KEY_SET_LEN(k, len, size); | |
507 | if (!WRITEP(p)) { | |
508 | USER_FREE(s); | |
509 | return 0; | |
510 | } | |
511 | *p = k; | |
512 | READP(p); | |
513 | USER_FREE(s); | |
514 | return 1; | |
515 | } else { | |
516 | uint32_t msize; | |
517 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1); | |
518 | if (!real_size) { | |
519 | ++YAC_SG(fails); | |
520 | return 0; | |
521 | } | |
522 | msize = sizeof(yac_kv_val) + size - 1; | |
523 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
524 | memcpy(s->data, data, size); | |
525 | s->atime = tv; | |
526 | YAC_KEY_SET_LEN(*s, len, size); | |
527 | val = yac_allocator_raw_alloc(real_size, (int)hash); | |
528 | if (val) { | |
529 | memcpy((char *)val, (char *)s, msize); | |
530 | if (ttl) { | |
531 | k.ttl = tv + ttl; | |
532 | } else { | |
533 | k.ttl = 0; | |
534 | } | |
535 | k.crc = yac_crc32(s->data, size); | |
536 | k.val = val; | |
537 | k.flag = flag; | |
538 | k.size = real_size; | |
539 | memcpy(k.key, key, len); | |
540 | YAC_KEY_SET_LEN(k, len, size); | |
541 | if (!WRITEP(p)) { | |
542 | USER_FREE(s); | |
543 | return 0; | |
544 | } | |
545 | *p = k; | |
546 | READP(p); | |
547 | USER_FREE(s); | |
548 | return 1; | |
549 | } | |
550 | ++YAC_SG(fails); | |
551 | USER_FREE(s); | |
552 | return 0; | |
553 | } | |
554 | } else { | |
555 | uint32_t i; | |
556 | uint64_t seed, max_atime; | |
557 | ||
558 | seed = yac_inline_hash_func2(key, len); | |
559 | for (i = 0; i < 3; i++) { | |
560 | h += seed & YAC_SG(slots_mask); | |
561 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]); | |
562 | if (!WRITEP(p)) { | |
563 | return 0; | |
564 | } | |
565 | k = *p; | |
566 | READP(p); | |
567 | if (k.val == NULL) { | |
568 | goto do_add; | |
569 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) { | |
570 | /* Found the exact match */ | |
571 | goto do_update; | |
572 | } | |
573 | } | |
574 | ||
575 | --idx; | |
576 | max_atime = paths[idx]->val->atime; | |
577 | for (i = 0; i < idx; i++) { | |
578 | if ((paths[i]->ttl && paths[i]->ttl <= tv) || paths[i]->len != paths[i]->val->len) { | |
579 | p = paths[i]; | |
580 | goto do_add; | |
581 | } else if (paths[i]->val->atime < max_atime) { | |
582 | max_atime = paths[i]->val->atime; | |
583 | p = paths[i]; | |
584 | } | |
585 | } | |
586 | if (!WRITEP(p)) { | |
587 | return 0; | |
588 | } | |
589 | k = *p; | |
590 | READP(p); | |
591 | ++YAC_SG(kicks); | |
592 | k.h = hash; | |
593 | ||
594 | goto do_update; | |
595 | } | |
596 | } else { | |
597 | do_add: | |
598 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1); | |
599 | if (!real_size) { | |
600 | ++YAC_SG(fails); | |
601 | return 0; | |
602 | } | |
603 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1); | |
604 | memcpy(s->data, data, size); | |
605 | s->atime = tv; | |
606 | YAC_KEY_SET_LEN(*s, len, size); | |
607 | val = yac_allocator_raw_alloc(real_size, (int)hash); | |
608 | if (val) { | |
609 | memcpy((char *)val, (char *)s, sizeof(yac_kv_val) + size - 1); | |
610 | if (p->val == NULL) { | |
611 | ++YAC_SG(slots_num); | |
612 | } | |
613 | k.h = hash; | |
614 | k.val = val; | |
615 | k.flag = flag; | |
616 | k.size = real_size; | |
617 | k.crc = yac_crc32(s->data, size); | |
618 | memcpy(k.key, key, len); | |
619 | YAC_KEY_SET_LEN(k, len, size); | |
620 | if (ttl) { | |
621 | k.ttl = tv + ttl; | |
622 | } else { | |
623 | k.ttl = 0; | |
624 | } | |
625 | if (!WRITEP(p)) { | |
626 | USER_FREE(s); | |
627 | return 0; | |
628 | } | |
629 | *p = k; | |
630 | READP(p); | |
631 | USER_FREE(s); | |
632 | return 1; | |
633 | } | |
634 | ++YAC_SG(fails); | |
635 | USER_FREE(s); | |
636 | } | |
637 | return 0; | |
638 | } | |
639 | /* }}} */ | |
640 | ||
641 | void yac_storage_flush(void) /* {{{ */ { | |
642 | YAC_SG(slots_num) = 0; | |
643 | ||
644 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * YAC_SG(slots_size)); | |
645 | } | |
646 | /* }}} */ | |
647 | ||
648 | yac_storage_info * yac_storage_get_info(void) /* {{{ */ { | |
649 | yac_storage_info *info = USER_ALLOC(sizeof(yac_storage_info)); | |
650 | ||
651 | info->k_msize = (unsigned long)YAC_SG(first_seg).size; | |
652 | info->v_msize = (unsigned long)YAC_SG(segments)[0]->size * (unsigned long)YAC_SG(segments_num); | |
653 | info->segment_size = YAC_SG(segments)[0]->size; | |
654 | info->segments_num = YAC_SG(segments_num); | |
655 | info->hits = YAC_SG(hits); | |
656 | info->miss = YAC_SG(miss); | |
657 | info->fails = YAC_SG(fails); | |
658 | info->kicks = YAC_SG(kicks); | |
659 | info->recycles = YAC_SG(recycles); | |
660 | info->slots_size = YAC_SG(slots_size); | |
661 | info->slots_num = YAC_SG(slots_num); | |
662 | ||
663 | return info; | |
664 | } | |
665 | /* }}} */ | |
666 | ||
667 | void yac_storage_free_info(yac_storage_info *info) /* {{{ */ { | |
668 | USER_FREE(info); | |
669 | } | |
670 | /* }}} */ | |
671 | ||
672 | yac_item_list * yac_storage_dump(unsigned int limit) /* {{{ */ { | |
673 | yac_kv_key k; | |
674 | yac_item_list *item, *list = NULL; | |
675 | ||
676 | if (YAC_SG(slots_num)) { | |
677 | unsigned int i = 0, n = 0; | |
678 | for (; i<YAC_SG(slots_size) && n < YAC_SG(slots_num) && n < limit; i++) { | |
679 | k = YAC_SG(slots)[i]; | |
680 | if (k.val) { | |
681 | item = USER_ALLOC(sizeof(yac_item_list)); | |
682 | item->index = i; | |
683 | item->h = k.h; | |
684 | item->crc = k.crc; | |
685 | item->ttl = k.ttl; | |
686 | item->k_len = YAC_KEY_KLEN(k); | |
687 | item->v_len = YAC_KEY_VLEN(k); | |
688 | item->flag = k.flag; | |
689 | item->size = k.size; | |
690 | memcpy(item->key, k.key, YAC_STORAGE_MAX_KEY_LEN); | |
691 | item->next = list; | |
692 | list = item; | |
693 | ++n; | |
694 | } | |
695 | } | |
696 | } | |
697 | ||
698 | return list; | |
699 | } | |
700 | /* }}} */ | |
701 | ||
702 | void yac_storage_free_list(yac_item_list *list) /* {{{ */ { | |
703 | yac_item_list *l; | |
704 | while (list) { | |
705 | l = list; | |
706 | list = list->next; | |
707 | USER_FREE(l); | |
708 | } | |
709 | } | |
710 | /* }}} */ | |
711 | ||
712 | const char * yac_storage_shared_memory_name(void) /* {{{ */ { | |
713 | return YAC_SHARED_MEMORY_HANDLER_NAME; | |
714 | } | |
715 | /* }}} */ | |
716 | ||
717 | /* | |
718 | * Local variables: | |
719 | * tab-width: 4 | |
720 | * c-basic-offset: 4 | |
721 | * End: | |
722 | * vim600: noet sw=4 ts=4 fdm=marker | |
723 | * vim<600: noet sw=4 ts=4 | |
724 | */ |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifndef YAC_STORAGE_H | |
21 | #define YAC_STORAGE_H | |
22 | ||
23 | #define YAC_STORAGE_MAX_ENTRY_LEN (1 << 20) | |
24 | #define YAC_STORAGE_MAX_KEY_LEN (48) | |
25 | #define YAC_STORAGE_FACTOR (1.25) | |
26 | #define YAC_KEY_KLEN_MASK (255) | |
27 | #define YAC_KEY_VLEN_BITS (8) | |
28 | #define YAC_KEY_KLEN(k) ((k).len & YAC_KEY_KLEN_MASK) | |
29 | #define YAC_KEY_VLEN(k) ((k).len >> YAC_KEY_VLEN_BITS) | |
30 | #define YAC_KEY_SET_LEN(k, kl, vl) ((k).len = (vl << YAC_KEY_VLEN_BITS) | (kl & YAC_KEY_KLEN_MASK)) | |
31 | #define YAC_FULL_CRC_THRESHOLD 256 | |
32 | ||
33 | #define USER_ALLOC emalloc | |
34 | #define USER_FREE efree | |
35 | ||
36 | typedef struct { | |
37 | unsigned long atime; | |
38 | unsigned int len; | |
39 | char data[1]; | |
40 | } yac_kv_val; | |
41 | ||
42 | typedef struct { | |
43 | unsigned long h; | |
44 | unsigned int crc; | |
45 | unsigned int ttl; | |
46 | unsigned int len; | |
47 | unsigned int flag; | |
48 | unsigned int size; | |
49 | unsigned int mutex; | |
50 | yac_kv_val *val; | |
51 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN]; | |
52 | } yac_kv_key; | |
53 | ||
54 | typedef struct _yac_item_list { | |
55 | unsigned int index; | |
56 | unsigned long h; | |
57 | unsigned long crc; | |
58 | unsigned int ttl; | |
59 | unsigned int k_len; | |
60 | unsigned int v_len; | |
61 | unsigned int flag; | |
62 | unsigned int size; | |
63 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN]; | |
64 | struct _yac_item_list *next; | |
65 | } yac_item_list; | |
66 | ||
67 | typedef struct { | |
68 | volatile unsigned int pos; | |
69 | unsigned int size; | |
70 | void *p; | |
71 | } yac_shared_segment; | |
72 | ||
73 | typedef struct { | |
74 | unsigned long k_msize; | |
75 | unsigned long v_msize; | |
76 | unsigned int segments_num; | |
77 | unsigned int segment_size; | |
78 | unsigned int slots_num; | |
79 | unsigned int slots_size; | |
80 | unsigned int miss; | |
81 | unsigned int fails; | |
82 | unsigned int kicks; | |
83 | unsigned int recycles; | |
84 | unsigned long hits; | |
85 | } yac_storage_info; | |
86 | ||
87 | typedef struct { | |
88 | yac_kv_key *slots; | |
89 | unsigned int slots_mask; | |
90 | unsigned int slots_num; | |
91 | unsigned int slots_size; | |
92 | unsigned int miss; | |
93 | unsigned int fails; | |
94 | unsigned int kicks; | |
95 | unsigned int recycles; | |
96 | unsigned long hits; | |
97 | yac_shared_segment **segments; | |
98 | unsigned int segments_num; | |
99 | unsigned int segments_num_mask; | |
100 | yac_shared_segment first_seg; | |
101 | } yac_storage_globals; | |
102 | ||
103 | extern yac_storage_globals *yac_storage; | |
104 | ||
105 | #define YAC_SG(element) (yac_storage->element) | |
106 | ||
107 | int yac_storage_startup(unsigned long first_size, unsigned long size, char **err); | |
108 | void yac_storage_shutdown(void); | |
109 | int yac_storage_find(const char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv); | |
110 | int yac_storage_update(const char *key, unsigned int len, char *data, unsigned int size, unsigned int falg, int ttl, int add, unsigned long tv); | |
111 | int yac_storage_delete(const char *key, unsigned int len, int ttl, unsigned long tv); | |
112 | void yac_storage_flush(void); | |
113 | const char * yac_storage_shared_memory_name(void); | |
114 | yac_storage_info * yac_storage_get_info(void); | |
115 | void yac_storage_free_info(yac_storage_info *info); | |
116 | yac_item_list * yac_storage_dump(unsigned int limit); | |
117 | void yac_storage_free_list(yac_item_list *list); | |
118 | #define yac_storage_exists(ht, key, len) yac_storage_find(ht, key, len, NULL) | |
119 | ||
120 | #endif /* YAC_STORAGE_H */ | |
121 | ||
122 | /* | |
123 | * Local variables: | |
124 | * tab-width: 4 | |
125 | * c-basic-offset: 4 | |
126 | * End: | |
127 | * vim600: noet sw=4 ts=4 fdm=marker | |
128 | * vim<600: noet sw=4 ts=4 | |
129 | */ |
0 | --TEST-- | |
1 | Check for yac presence | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --FILE-- | |
5 | <?php | |
6 | echo "yac extension is available"; | |
7 | /* | |
8 | you can add regression tests for your extension here | |
9 | ||
10 | the output of your test code has to be equal to the | |
11 | text in the --EXPECT-- section below for the tests | |
12 | to pass, differences between the output and the | |
13 | expected text are interpreted as failure | |
14 | ||
15 | see php5/README.TESTING for further information on | |
16 | writing regression tests | |
17 | */ | |
18 | ?> | |
19 | --EXPECT-- | |
20 | yac extension is available |
0 | --TEST-- | |
1 | Check for yac basic functions | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | yac.serializer=php | |
10 | --FILE-- | |
11 | <?php | |
12 | $yac = new Yac(); | |
13 | ||
14 | var_dump(YAC_SERIALIZER == YAC_SERIALIZER_PHP); | |
15 | ||
16 | $key = "foo"; | |
17 | $value = "dummy"; | |
18 | ||
19 | var_dump($yac->set($key, $value)); | |
20 | var_dump($yac->get($key)); | |
21 | ||
22 | $value = NULL; | |
23 | var_dump($yac->set($key, $value)); | |
24 | var_dump($yac->get($key)); | |
25 | ||
26 | $value = TRUE; | |
27 | var_dump($yac->set($key, $value)); | |
28 | var_dump($yac->get($key)); | |
29 | ||
30 | $value = FALSE; | |
31 | var_dump($yac->set($key, $value)); | |
32 | var_dump($yac->get($key)); | |
33 | ||
34 | $value = range(1, 5); | |
35 | var_dump($yac->set($key, $value)); | |
36 | var_dump($yac->get($key)); | |
37 | ||
38 | $value = 9234324; | |
39 | var_dump($yac->set($key, $value)); | |
40 | var_dump($yac->get($key)); | |
41 | ||
42 | $value = 9234324.123456; | |
43 | var_dump($yac->set($key, $value)); | |
44 | var_dump($yac->get($key)); | |
45 | ||
46 | $value = new StdClass();; | |
47 | var_dump($yac->set($key, $value)); | |
48 | var_dump($yac->get($key)); | |
49 | ||
50 | $value = fopen("php://input", "r"); | |
51 | var_dump($yac->set($key, $value)); | |
52 | ||
53 | $value = range(1, 5); | |
54 | var_dump($yac->set($key, $value)); | |
55 | var_dump($yac->delete($key)); | |
56 | var_dump($yac->get($key)); | |
57 | ||
58 | ?> | |
59 | --EXPECTF-- | |
60 | bool(true) | |
61 | bool(true) | |
62 | string(5) "dummy" | |
63 | bool(true) | |
64 | NULL | |
65 | bool(true) | |
66 | bool(true) | |
67 | bool(true) | |
68 | bool(false) | |
69 | bool(true) | |
70 | array(5) { | |
71 | [0]=> | |
72 | int(1) | |
73 | [1]=> | |
74 | int(2) | |
75 | [2]=> | |
76 | int(3) | |
77 | [3]=> | |
78 | int(4) | |
79 | [4]=> | |
80 | int(5) | |
81 | } | |
82 | bool(true) | |
83 | int(9234324) | |
84 | bool(true) | |
85 | float(9234324.123456) | |
86 | bool(true) | |
87 | object(stdClass)#3 (0) { | |
88 | } | |
89 | ||
90 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s002.php on line %d | |
91 | bool(false) | |
92 | bool(true) | |
93 | bool(true) | |
94 | bool(false) |
0 | --TEST-- | |
1 | Check for yac errors | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = str_repeat("k", YAC_MAX_KEY_LEN - 1); | |
14 | $value = NULL; | |
15 | ||
16 | var_dump($yac->set($key, $value)); | |
17 | var_dump($yac->get($key)); | |
18 | ||
19 | $key = str_repeat("k", YAC_MAX_KEY_LEN); | |
20 | var_dump($yac->set($key, $value)); | |
21 | var_dump($yac->get($key)); | |
22 | ||
23 | $key = str_repeat("k", YAC_MAX_KEY_LEN + 1); | |
24 | var_dump($yac->set($key, $value)); | |
25 | var_dump($yac->get($key)); | |
26 | ||
27 | $yac = new Yac("dummy"); | |
28 | var_dump($yac->set($key, $value)); | |
29 | var_dump($yac->get($key)); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | NULL | |
34 | bool(true) | |
35 | NULL | |
36 | ||
37 | Warning: Yac::set(): Key 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d | |
38 | bool(false) | |
39 | ||
40 | Warning: Yac::get(): Key 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d | |
41 | bool(false) | |
42 | ||
43 | Warning: Yac::set(): Key 'dummykkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d | |
44 | bool(false) | |
45 | ||
46 | Warning: Yac::get(): Key 'dummykkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d | |
47 | bool(false) | |
48 |
0 | --TEST-- | |
1 | Check for yac ttl | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = "foo"; | |
14 | $value = "dummy"; | |
15 | ||
16 | var_dump($yac->set($key, $value, 1)); | |
17 | var_dump($yac->get($key)); | |
18 | sleep(1); | |
19 | var_dump($yac->get($key)); | |
20 | ||
21 | var_dump($yac->set($key, $value)); | |
22 | var_dump($yac->get($key)); | |
23 | var_dump($yac->delete($key, 1)); | |
24 | var_dump($yac->get($key)); | |
25 | sleep(1); | |
26 | var_dump($yac->get($key)); | |
27 | ||
28 | ?> | |
29 | --EXPECTF-- | |
30 | bool(true) | |
31 | string(5) "dummy" | |
32 | bool(false) | |
33 | bool(true) | |
34 | string(5) "dummy" | |
35 | bool(true) | |
36 | string(5) "dummy" | |
37 | bool(false) |
0 | --TEST-- | |
1 | Check for yac non-string key | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = md5(12345); | |
14 | $value = "dummy"; | |
15 | ||
16 | var_dump($yac->set($key, $value, 1)); | |
17 | var_dump($yac->get($key)); | |
18 | ||
19 | $key = 12345.12345; | |
20 | var_dump($yac->set($key, $value, 1)); | |
21 | var_dump($yac->get($key)); | |
22 | ||
23 | $key = range(1, 2); | |
24 | var_dump($yac->set($key, $value, 1)); | |
25 | var_dump($yac->get($key)); | |
26 | ||
27 | $key = new StdClass(); | |
28 | var_dump($yac->set($key, $value, 1)); | |
29 | var_dump($yac->get($key)); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | string(5) "dummy" | |
34 | bool(true) | |
35 | string(5) "dummy" | |
36 | bool(true) | |
37 | array(2) { | |
38 | [1]=> | |
39 | int(2) | |
40 | [2]=> | |
41 | bool(false) | |
42 | } | |
43 | ||
44 | %s error:%sObject of class stdClass could not be converted to string in %s005.php%A |
0 | --TEST-- | |
1 | Check for yac multi set/get | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | ||
12 | $yac = new Yac(); | |
13 | ||
14 | for ($i = 0; $i<1000; $i++) { | |
15 | $key = "xxx" . rand(1, 100000); | |
16 | $value = str_repeat("a", rand(1, 100000)); | |
17 | ||
18 | if (!$yac->set($key, $value)) { | |
19 | var_dump($key, $value); | |
20 | var_dump("write " . $i); | |
21 | } | |
22 | ||
23 | if ($value != ($new = $yac->get($key))) { | |
24 | var_dump($new); | |
25 | var_dump("read " . $i); | |
26 | } | |
27 | } | |
28 | ||
29 | var_dump($i); | |
30 | --EXPECTF-- | |
31 | int(1000) |
0 | --TEST-- | |
1 | Check for yac info | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | ||
12 | $yac = new Yac(); | |
13 | ||
14 | for ($i = 0; $i<1000; $i++) { | |
15 | $key = "xxx" . rand(1, 1000); | |
16 | $value = str_repeat("a", rand(1, 100000)); | |
17 | ||
18 | if (!$yac->set($key, $value)) { | |
19 | var_dump($key, $value); | |
20 | var_dump("write " . $i); | |
21 | } | |
22 | ||
23 | if ($value != ($new = $yac->get($key))) { | |
24 | var_dump($new); | |
25 | var_dump("read " . $i); | |
26 | } | |
27 | } | |
28 | ||
29 | $info = $yac->info(); | |
30 | var_dump($info['slots_used'] <= 1000); | |
31 | var_dump($info['hits']); | |
32 | var_dump($info['miss']); | |
33 | var_dump($info['fails']); | |
34 | var_dump($info['kicks']); | |
35 | --EXPECTF-- | |
36 | bool(true) | |
37 | int(1000) | |
38 | int(0) | |
39 | int(0) | |
40 | int(0) |
0 | --TEST-- | |
1 | Check for yac prefix | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac("dummy_"); | |
12 | $yac2 = new Yac(); | |
13 | ||
14 | $key = "bar"; | |
15 | $value = true; | |
16 | ||
17 | $yac->set($key, $value); | |
18 | var_dump($yac->get($key)); //true | |
19 | var_dump($yac2->get($key)); //false | |
20 | var_dump($yac2->get("dummy_" . $key)); //true | |
21 | ||
22 | $yac2->delete($key); //fail | |
23 | var_dump($yac->get($key)); //true | |
24 | ||
25 | $yac->delete($key); //okey | |
26 | var_dump($yac->get($key)); //false | |
27 | ||
28 | $yac->set($key, $value); | |
29 | $yac2->delete("dummy_" . $key); //okey | |
30 | var_dump($yac->get($key)); //false | |
31 | ?> | |
32 | --EXPECTF-- | |
33 | bool(true) | |
34 | bool(false) | |
35 | bool(true) | |
36 | bool(true) | |
37 | bool(false) | |
38 | bool(false) |
0 | --TEST-- | |
1 | Check for yac multi ops | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $values = array(); | |
14 | $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; | |
15 | for ($i = 0; $i < 100; $i++) { | |
16 | $key = substr(str_shuffle($chars), 0, rand(16, 32)); | |
17 | $value = md5($key . rand(1, 10000)); | |
18 | $values[$key] = $value; | |
19 | } | |
20 | ||
21 | $numbers = count($values); | |
22 | ||
23 | var_dump($yac->set($values)); | |
24 | ||
25 | $keys = array_keys($values); | |
26 | $ret = $yac->get($keys); | |
27 | var_dump(count(array_filter($ret)) == $numbers); | |
28 | ||
29 | $disable = array_slice($keys, 0, -10); | |
30 | $yac->delete($disable); | |
31 | ||
32 | $ret = $yac->get($keys); | |
33 | var_dump(count(array_filter($ret)) == 10); | |
34 | ?> | |
35 | --EXPECTF-- | |
36 | bool(true) | |
37 | bool(true) | |
38 | bool(true) |
0 | --TEST-- | |
1 | Check for yac::flush | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $values = array(); | |
14 | $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; | |
15 | for ($i = 0; $i < 100; $i++) { | |
16 | $key = substr(str_shuffle($chars), 0, rand(16, 32)); | |
17 | $value = md5($key . rand(1, 10000)); | |
18 | $values[$key] = $value; | |
19 | } | |
20 | ||
21 | $numbers = count($values); | |
22 | ||
23 | var_dump($yac->set($values)); | |
24 | ||
25 | $yac->flush(); | |
26 | ||
27 | var_dump($yac->get($key)); | |
28 | $info = $yac->info(); | |
29 | var_dump($info['slots_used']); | |
30 | ?> | |
31 | --EXPECTF-- | |
32 | bool(true) | |
33 | bool(false) | |
34 | int(0) |
0 | --TEST-- | |
1 | Check for yac::add | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | ||
13 | $key = "dummy"; | |
14 | $value = "foo"; | |
15 | var_dump($yac->add($key, $value)); // true | |
16 | var_dump($yac->add($key, $value)); // false | |
17 | var_dump($yac->set($key, $value)); // true | |
18 | var_dump($yac->get($key)); // foo | |
19 | var_dump($yac->delete($key)); // true | |
20 | $value = "bar"; | |
21 | var_dump($yac->add($key, $value, 1)); //true | |
22 | var_dump($yac->add($key, $value, 1)); //false | |
23 | var_dump($yac->get($key)); //bar | |
24 | sleep(1); | |
25 | var_dump($yac->add($key, $value)); //true | |
26 | ||
27 | ?> | |
28 | --EXPECTF-- | |
29 | bool(true) | |
30 | bool(false) | |
31 | bool(true) | |
32 | string(3) "foo" | |
33 | bool(true) | |
34 | bool(true) | |
35 | bool(false) | |
36 | string(3) "bar" | |
37 | bool(true) |
0 | --TEST-- | |
1 | Check for functional apis | |
2 | --SKIPIF-- | |
3 | <?php | |
4 | if (!extension_loaded("yac")) print "skip"; | |
5 | print "skip Functional style APIs are not enabled"; | |
6 | ?> | |
7 | --INI-- | |
8 | yac.enable=1 | |
9 | yac.enable_cli=1 | |
10 | yac.keys_memory_size=4M | |
11 | yac.values_memory_size=32M | |
12 | --FILE-- | |
13 | <?php | |
14 | $key = "dummy"; | |
15 | $value = "foo"; | |
16 | var_dump(yac_set($key, $value)); //true | |
17 | var_dump(yac_add($key, $value)); //false | |
18 | var_dump(yac_get($key)); //foo | |
19 | var_dump(yac_delete($key)); //true | |
20 | var_dump(yac_set($key, $value)); //true | |
21 | var_dump(yac_flush()); //true | |
22 | $info = yac_info(); | |
23 | var_dump($info['slots_used']); //0 | |
24 | ?> | |
25 | --EXPECTF-- | |
26 | bool(true) | |
27 | bool(false) | |
28 | string(3) "foo" | |
29 | bool(true) | |
30 | bool(true) | |
31 | bool(true) | |
32 | int(0) |
0 | --TEST-- | |
1 | Check for ttl bug | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | $yac->set('test', 1, 1); | |
13 | sleep(2); | |
14 | var_dump($yac->get('test')); | |
15 | ?> | |
16 | --EXPECTF-- | |
17 | bool(false) |
0 | --TEST-- | |
1 | Check for ttl bug | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | yac.compress_threshold=1024 | |
10 | --FILE-- | |
11 | <?php | |
12 | error_reporting(E_ALL); | |
13 | $yac = new Yac(); | |
14 | ||
15 | for($i = 0; $i<100; $i++) { | |
16 | $value[] = ($i + 100000)."sdfsfsfsfs"; | |
17 | } | |
18 | ||
19 | $yac->set('test', $value); | |
20 | ||
21 | echo count($yac->get('test')); | |
22 | ?> | |
23 | --EXPECTF-- | |
24 | 100 |
0 | --TEST-- | |
1 | Check for Yac::dump | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | yac.compress_threshold=1024 | |
10 | --FILE-- | |
11 | <?php | |
12 | $yac = new Yac(); | |
13 | ||
14 | for ($i = 0; $i<100; $i++) { | |
15 | $yac->set("key". $i, "kjslkdfkldasjkf"); | |
16 | } | |
17 | for ($i = 0; $i<100; $i++) { | |
18 | $yac->set("key". $i, "kjslkdfkldasjkf"); | |
19 | } | |
20 | ||
21 | var_dump(count($yac->dump(1000))); | |
22 | --EXPECTF-- | |
23 | int(100) |
0 | --TEST-- | |
1 | Check for Yac setter/getter | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | yac.compress_threshold=1024 | |
10 | --FILE-- | |
11 | <?php | |
12 | $yac = new Yac("prefix"); | |
13 | ||
14 | $yac->name = "test"; | |
15 | ||
16 | var_dump($yac->name); | |
17 | var_dump($yac->get("name")); | |
18 | ?> | |
19 | --EXPECTF-- | |
20 | string(4) "test" | |
21 | string(4) "test" |
0 | --TEST-- | |
1 | Check for mutiple process | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (!extension_loaded("pcntl")) print "skip need pcntl"; ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | yac.compress_threshold=1024 | |
11 | --FILE-- | |
12 | <?php | |
13 | $yac = new Yac(); | |
14 | ||
15 | if (($pid = pcntl_fork())) { | |
16 | while(!$yac->set("parent", "FIN")); | |
17 | while (!($msg = $yac->get("child"))); | |
18 | echo "MSG From Child:", $msg,"\n"; | |
19 | while(!($yac->set("parent", "BYE"))); | |
20 | pcntl_wait($status); | |
21 | echo "Parent exiting\n"; | |
22 | } else { | |
23 | while(!($msg = $yac->get("parent"))); | |
24 | echo "MSG From Parent:" , $msg, "\n"; | |
25 | while(!($yac->set("child", "ACK"))); | |
26 | while(($msg = $yac->get("parent")) != "BYE"); | |
27 | echo "Child exiting\n"; | |
28 | } | |
29 | ?> | |
30 | --EXPECT-- | |
31 | MSG From Parent:FIN | |
32 | MSG From Child:ACK | |
33 | Child exiting | |
34 | Parent exiting |
0 | --TEST-- | |
1 | Check for yac with json serializer | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (!defined("YAC_SERIALIZER_JSON")) die ("skip need --enable-json"); ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | yac.serializer=json | |
11 | --FILE-- | |
12 | <?php | |
13 | $yac = new Yac(); | |
14 | ||
15 | var_dump(YAC_SERIALIZER == YAC_SERIALIZER_JSON); | |
16 | $key = "foo"; | |
17 | $value = "dummy"; | |
18 | ||
19 | var_dump($yac->set($key, $value)); | |
20 | var_dump($yac->get($key)); | |
21 | ||
22 | $value = NULL; | |
23 | var_dump($yac->set($key, $value)); | |
24 | var_dump($yac->get($key)); | |
25 | ||
26 | $value = TRUE; | |
27 | var_dump($yac->set($key, $value)); | |
28 | var_dump($yac->get($key)); | |
29 | ||
30 | $value = FALSE; | |
31 | var_dump($yac->set($key, $value)); | |
32 | var_dump($yac->get($key)); | |
33 | ||
34 | $value = range(1, 5); | |
35 | var_dump($yac->set($key, $value)); | |
36 | var_dump($yac->get($key)); | |
37 | ||
38 | $value = 9234324; | |
39 | var_dump($yac->set($key, $value)); | |
40 | var_dump($yac->get($key)); | |
41 | ||
42 | $value = 9234324.123456; | |
43 | var_dump($yac->set($key, $value)); | |
44 | var_dump($yac->get($key)); | |
45 | ||
46 | $value = new StdClass();; | |
47 | var_dump($yac->set($key, $value)); | |
48 | var_dump($yac->get($key)); | |
49 | ||
50 | $value = fopen("php://input", "r"); | |
51 | var_dump($yac->set($key, $value)); | |
52 | ||
53 | $value = range(1, 5); | |
54 | var_dump($yac->set($key, $value)); | |
55 | var_dump($yac->delete($key)); | |
56 | var_dump($yac->get($key)); | |
57 | ||
58 | ?> | |
59 | --EXPECTF-- | |
60 | bool(true) | |
61 | bool(true) | |
62 | string(5) "dummy" | |
63 | bool(true) | |
64 | NULL | |
65 | bool(true) | |
66 | bool(true) | |
67 | bool(true) | |
68 | bool(false) | |
69 | bool(true) | |
70 | array(5) { | |
71 | [0]=> | |
72 | int(1) | |
73 | [1]=> | |
74 | int(2) | |
75 | [2]=> | |
76 | int(3) | |
77 | [3]=> | |
78 | int(4) | |
79 | [4]=> | |
80 | int(5) | |
81 | } | |
82 | bool(true) | |
83 | int(9234324) | |
84 | bool(true) | |
85 | float(9234324.123456) | |
86 | bool(true) | |
87 | array(0) { | |
88 | } | |
89 | ||
90 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s018.php on line %d | |
91 | bool(false) | |
92 | bool(true) | |
93 | bool(true) | |
94 | bool(false) |
0 | --TEST-- | |
1 | Check for yac with msgpack serializer | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (!defined("YAC_SERIALIZER_MSGPACK")) die ("skip need --enable-msgpack"); ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | yac.serializer=msgpack | |
11 | --FILE-- | |
12 | <?php | |
13 | $yac = new Yac(); | |
14 | ||
15 | var_dump(YAC_SERIALIZER == YAC_SERIALIZER_MSGPACK); | |
16 | $key = "foo"; | |
17 | $value = "dummy"; | |
18 | ||
19 | var_dump($yac->set($key, $value)); | |
20 | var_dump($yac->get($key)); | |
21 | ||
22 | $value = NULL; | |
23 | var_dump($yac->set($key, $value)); | |
24 | var_dump($yac->get($key)); | |
25 | ||
26 | $value = TRUE; | |
27 | var_dump($yac->set($key, $value)); | |
28 | var_dump($yac->get($key)); | |
29 | ||
30 | $value = FALSE; | |
31 | var_dump($yac->set($key, $value)); | |
32 | var_dump($yac->get($key)); | |
33 | ||
34 | $value = range(1, 5); | |
35 | var_dump($yac->set($key, $value)); | |
36 | var_dump($yac->get($key)); | |
37 | ||
38 | $value = 9234324; | |
39 | var_dump($yac->set($key, $value)); | |
40 | var_dump($yac->get($key)); | |
41 | ||
42 | $value = 9234324.123456; | |
43 | var_dump($yac->set($key, $value)); | |
44 | var_dump($yac->get($key)); | |
45 | ||
46 | $value = new StdClass();; | |
47 | var_dump($yac->set($key, $value)); | |
48 | var_dump($yac->get($key)); | |
49 | ||
50 | $value = fopen("php://input", "r"); | |
51 | var_dump($yac->set($key, $value)); | |
52 | ||
53 | $value = range(1, 5); | |
54 | var_dump($yac->set($key, $value)); | |
55 | var_dump($yac->delete($key)); | |
56 | var_dump($yac->get($key)); | |
57 | ||
58 | ?> | |
59 | --EXPECTF-- | |
60 | bool(true) | |
61 | bool(true) | |
62 | string(5) "dummy" | |
63 | bool(true) | |
64 | NULL | |
65 | bool(true) | |
66 | bool(true) | |
67 | bool(true) | |
68 | bool(false) | |
69 | bool(true) | |
70 | array(5) { | |
71 | [0]=> | |
72 | int(1) | |
73 | [1]=> | |
74 | int(2) | |
75 | [2]=> | |
76 | int(3) | |
77 | [3]=> | |
78 | int(4) | |
79 | [4]=> | |
80 | int(5) | |
81 | } | |
82 | bool(true) | |
83 | int(9234324) | |
84 | bool(true) | |
85 | float(9234324.123456) | |
86 | bool(true) | |
87 | object(stdClass)#%d (0) { | |
88 | } | |
89 | ||
90 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s019.php on line %d | |
91 | bool(false) | |
92 | bool(true) | |
93 | bool(true) | |
94 | bool(false) |
0 | --TEST-- | |
1 | Check for yac with igbinary serializer | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | <?php if (!defined("YAC_SERIALIZER_IGBINARY")) die ("skip need --enable-igbinary"); ?> | |
5 | --INI-- | |
6 | yac.enable=1 | |
7 | yac.enable_cli=1 | |
8 | yac.keys_memory_size=4M | |
9 | yac.values_memory_size=32M | |
10 | yac.serializer=igbinary | |
11 | --FILE-- | |
12 | <?php | |
13 | $yac = new Yac(); | |
14 | ||
15 | var_dump(YAC_SERIALIZER == YAC_SERIALIZER_IGBINARY); | |
16 | $key = "foo"; | |
17 | $value = "dummy"; | |
18 | ||
19 | var_dump($yac->set($key, $value)); | |
20 | var_dump($yac->get($key)); | |
21 | ||
22 | $value = NULL; | |
23 | var_dump($yac->set($key, $value)); | |
24 | var_dump($yac->get($key)); | |
25 | ||
26 | $value = TRUE; | |
27 | var_dump($yac->set($key, $value)); | |
28 | var_dump($yac->get($key)); | |
29 | ||
30 | $value = FALSE; | |
31 | var_dump($yac->set($key, $value)); | |
32 | var_dump($yac->get($key)); | |
33 | ||
34 | $value = range(1, 5); | |
35 | var_dump($yac->set($key, $value)); | |
36 | var_dump($yac->get($key)); | |
37 | ||
38 | $value = 9234324; | |
39 | var_dump($yac->set($key, $value)); | |
40 | var_dump($yac->get($key)); | |
41 | ||
42 | $value = 9234324.123456; | |
43 | var_dump($yac->set($key, $value)); | |
44 | var_dump($yac->get($key)); | |
45 | ||
46 | $value = new StdClass();; | |
47 | var_dump($yac->set($key, $value)); | |
48 | var_dump($yac->get($key)); | |
49 | ||
50 | $value = fopen("php://input", "r"); | |
51 | var_dump($yac->set($key, $value)); | |
52 | ||
53 | $value = range(1, 5); | |
54 | var_dump($yac->set($key, $value)); | |
55 | var_dump($yac->delete($key)); | |
56 | var_dump($yac->get($key)); | |
57 | ||
58 | ?> | |
59 | --EXPECTF-- | |
60 | bool(true) | |
61 | bool(true) | |
62 | string(5) "dummy" | |
63 | bool(true) | |
64 | NULL | |
65 | bool(true) | |
66 | bool(true) | |
67 | bool(true) | |
68 | bool(false) | |
69 | bool(true) | |
70 | array(5) { | |
71 | [0]=> | |
72 | int(1) | |
73 | [1]=> | |
74 | int(2) | |
75 | [2]=> | |
76 | int(3) | |
77 | [3]=> | |
78 | int(4) | |
79 | [4]=> | |
80 | int(5) | |
81 | } | |
82 | bool(true) | |
83 | int(9234324) | |
84 | bool(true) | |
85 | float(9234324.123456) | |
86 | bool(true) | |
87 | object(stdClass)#%d (0) { | |
88 | } | |
89 | ||
90 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s020.php on line %d | |
91 | bool(false) | |
92 | bool(true) | |
93 | bool(true) | |
94 | bool(false) |
0 | --TEST-- | |
1 | Check for yac read/write/unset property | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=4M | |
8 | yac.values_memory_size=32M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac("prefix"); | |
12 | ||
13 | $yac->value = "value"; | |
14 | ||
15 | /* can not used in writen context */ | |
16 | $yac->foo->bar = "bar"; | |
17 | ||
18 | var_dump($yac->get("value")); | |
19 | var_dump($yac->value); | |
20 | ||
21 | var_dump($yac->get("foo")); | |
22 | var_dump($yac->foo); | |
23 | ||
24 | unset($yac->value); | |
25 | var_dump($yac->get("value")); | |
26 | var_dump($yac->value); | |
27 | ?> | |
28 | --EXPECT-- | |
29 | string(5) "value" | |
30 | string(5) "value" | |
31 | bool(false) | |
32 | NULL | |
33 | bool(false) | |
34 | NULL |
0 | --TEST-- | |
1 | Check for yac::__construct with yac.enable=0 | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=0 | |
6 | --FILE-- | |
7 | <?php | |
8 | try { | |
9 | $yac = new Yac("prefix"); | |
10 | } catch (Exception $e) { | |
11 | var_dump($e->getMessage()); | |
12 | } | |
13 | ||
14 | var_dump($yac); | |
15 | ?> | |
16 | --EXPECTF-- | |
17 | string(18) "Yac is not enabled" | |
18 | ||
19 | Notice: Undefined variable: yac in %s022.php on line %d | |
20 | NULL |
0 | --TEST-- | |
1 | Check for inherit from Yac | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=0 | |
6 | --FILE-- | |
7 | <?php | |
8 | class Sub extends Yac {}; | |
9 | ?> | |
10 | --EXPECTF-- | |
11 | Fatal error: Class Sub may not inherit from final class (Yac) in %s023.php on line %d |
0 | --TEST-- | |
1 | ISSUE #12 segfault if use mmap&k_size bigger than 4M | |
2 | --SKIPIF-- | |
3 | <?php if (!extension_loaded("yac")) print "skip"; ?> | |
4 | --INI-- | |
5 | yac.enable=1 | |
6 | yac.enable_cli=1 | |
7 | yac.keys_memory_size=8M | |
8 | yac.values_memory_size=128M | |
9 | --FILE-- | |
10 | <?php | |
11 | $yac = new Yac(); | |
12 | $i = 0; | |
13 | while (true) { | |
14 | $yac->set(rand(), strval(rand()), 2); | |
15 | $i++; | |
16 | if ($i > 20000) { | |
17 | break; | |
18 | } | |
19 | } | |
20 | ?> | |
21 | OKEY | |
22 | --EXPECTF-- | |
23 | OKEY |
0 | /* | |
1 | +----------------------------------------------------------------------+ | |
2 | | Yet Another Cache | | |
3 | +----------------------------------------------------------------------+ | |
4 | | Copyright (c) 2013-2013 The PHP Group | | |
5 | +----------------------------------------------------------------------+ | |
6 | | This source file is subject to version 3.01 of the PHP license, | | |
7 | | that is bundled with this package in the file LICENSE, and is | | |
8 | | available through the world-wide-web at the following url: | | |
9 | | http://www.php.net/license/3_01.txt | | |
10 | | If you did not receive a copy of the PHP license and are unable to | | |
11 | | obtain it through the world-wide-web, please send a note to | | |
12 | | license@php.net so we can mail you a copy immediately. | | |
13 | +----------------------------------------------------------------------+ | |
14 | | Author: Xinchen Hui <laruence@php.net> | | |
15 | +----------------------------------------------------------------------+ | |
16 | */ | |
17 | ||
18 | /* $Id$ */ | |
19 | ||
20 | #ifdef HAVE_CONFIG_H | |
21 | #include "config.h" | |
22 | #endif | |
23 | ||
24 | #include <time.h> | |
25 | ||
26 | #include "php.h" | |
27 | #include "php_ini.h" | |
28 | #include "SAPI.h" | |
29 | #include "ext/standard/info.h" | |
30 | #include "Zend/zend_smart_str.h" | |
31 | #include "Zend/zend_exceptions.h" | |
32 | ||
33 | #include "php_yac.h" | |
34 | #include "storage/yac_storage.h" | |
35 | #include "serializer/yac_serializer.h" | |
36 | #ifdef HAVE_FASTLZ_H | |
37 | #include <fastlz.h> | |
38 | #else | |
39 | #include "compressor/fastlz/fastlz.h" | |
40 | #endif | |
41 | ||
42 | zend_class_entry *yac_class_ce; | |
43 | ||
44 | static zend_object_handlers yac_obj_handlers; | |
45 | ||
46 | typedef struct { | |
47 | unsigned char prefix[YAC_STORAGE_MAX_KEY_LEN]; | |
48 | uint16_t prefix_len; | |
49 | zend_object std; | |
50 | } yac_object; | |
51 | ||
52 | ZEND_DECLARE_MODULE_GLOBALS(yac); | |
53 | ||
54 | static yac_serializer_t yac_serializer; | |
55 | static yac_unserializer_t yac_unserializer; | |
56 | ||
57 | /** {{{ ARG_INFO | |
58 | */ | |
59 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_constructor, 0, 0, 0) | |
60 | ZEND_ARG_INFO(0, prefix) | |
61 | ZEND_END_ARG_INFO() | |
62 | ||
63 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_add, 0, 0, 1) | |
64 | ZEND_ARG_INFO(0, keys) | |
65 | ZEND_ARG_INFO(0, value) | |
66 | ZEND_ARG_INFO(0, ttl) | |
67 | ZEND_END_ARG_INFO() | |
68 | ||
69 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_get, 0, 0, 1) | |
70 | ZEND_ARG_INFO(0, keys) | |
71 | ZEND_END_ARG_INFO() | |
72 | ||
73 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_delete, 0, 0, 1) | |
74 | ZEND_ARG_INFO(0, keys) | |
75 | ZEND_ARG_INFO(0, ttl) | |
76 | ZEND_END_ARG_INFO() | |
77 | ||
78 | ZEND_BEGIN_ARG_INFO_EX(arginfo_yac_void, 0, 0, 0) | |
79 | ZEND_END_ARG_INFO() | |
80 | /* }}} */ | |
81 | ||
82 | static PHP_INI_MH(OnChangeKeysMemoryLimit) /* {{{ */ { | |
83 | if (new_value) { | |
84 | YAC_G(k_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
85 | } | |
86 | return SUCCESS; | |
87 | } | |
88 | /* }}} */ | |
89 | ||
90 | static PHP_INI_MH(OnChangeValsMemoryLimit) /* {{{ */ { | |
91 | if (new_value) { | |
92 | YAC_G(v_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
93 | } | |
94 | return SUCCESS; | |
95 | } | |
96 | /* }}} */ | |
97 | ||
98 | static PHP_INI_MH(OnChangeCompressThreshold) /* {{{ */ { | |
99 | if (new_value) { | |
100 | YAC_G(compress_threshold) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | |
101 | if (YAC_G(compress_threshold) < YAC_MIN_COMPRESS_THRESHOLD) { | |
102 | YAC_G(compress_threshold) = YAC_MIN_COMPRESS_THRESHOLD; | |
103 | } | |
104 | } | |
105 | return SUCCESS; | |
106 | } | |
107 | /* }}} */ | |
108 | ||
109 | /* {{{ PHP_INI | |
110 | */ | |
111 | PHP_INI_BEGIN() | |
112 | STD_PHP_INI_BOOLEAN("yac.enable", "1", PHP_INI_SYSTEM, OnUpdateBool, enable, zend_yac_globals, yac_globals) | |
113 | STD_PHP_INI_BOOLEAN("yac.debug", "0", PHP_INI_ALL, OnUpdateBool, debug, zend_yac_globals, yac_globals) | |
114 | STD_PHP_INI_ENTRY("yac.keys_memory_size", "4M", PHP_INI_SYSTEM, OnChangeKeysMemoryLimit, k_msize, zend_yac_globals, yac_globals) | |
115 | STD_PHP_INI_ENTRY("yac.values_memory_size", "64M", PHP_INI_SYSTEM, OnChangeValsMemoryLimit, v_msize, zend_yac_globals, yac_globals) | |
116 | STD_PHP_INI_ENTRY("yac.compress_threshold", "-1", PHP_INI_SYSTEM, OnChangeCompressThreshold, compress_threshold, zend_yac_globals, yac_globals) | |
117 | STD_PHP_INI_ENTRY("yac.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_yac_globals, yac_globals) | |
118 | STD_PHP_INI_ENTRY("yac.serializer", "php", PHP_INI_SYSTEM, OnUpdateString, serializer, zend_yac_globals, yac_globals) | |
119 | PHP_INI_END() | |
120 | /* }}} */ | |
121 | ||
122 | #define Z_YACOBJ_P(zv) (php_yac_fetch_object(Z_OBJ_P(zv))) | |
123 | static inline yac_object *php_yac_fetch_object(zend_object *obj) /* {{{ */ { | |
124 | return (yac_object *)((char*)(obj) - XtOffsetOf(yac_object, std)); | |
125 | } | |
126 | /* }}} */ | |
127 | ||
128 | static const char *yac_assemble_key(yac_object *yac, zend_string *name, size_t *len) /* {{{ */ { | |
129 | const char *key; | |
130 | ||
131 | if ((ZSTR_LEN(name) + yac->prefix_len) > YAC_STORAGE_MAX_KEY_LEN) { | |
132 | php_error_docref(NULL, E_WARNING, | |
133 | "Key '%.*s%s' exceed max key length '%d' bytes", | |
134 | yac->prefix_len, yac->prefix, ZSTR_VAL(name), YAC_STORAGE_MAX_KEY_LEN); | |
135 | return NULL; | |
136 | } | |
137 | ||
138 | if (yac->prefix_len) { | |
139 | memcpy(yac->prefix + yac->prefix_len, ZSTR_VAL(name), ZSTR_LEN(name)); | |
140 | key = (const char*)yac->prefix; | |
141 | *len = yac->prefix_len + ZSTR_LEN(name); | |
142 | } else { | |
143 | key = ZSTR_VAL(name); | |
144 | *len = ZSTR_LEN(name); | |
145 | } | |
146 | ||
147 | return key; | |
148 | } | |
149 | /* }}} */ | |
150 | ||
151 | static int yac_add_impl(yac_object *yac, zend_string *name, zval *value, int ttl, int add) /* {{{ */ { | |
152 | int ret = 0, flag = Z_TYPE_P(value); | |
153 | char *msg; | |
154 | time_t tv; | |
155 | const char *key; | |
156 | size_t key_len; | |
157 | ||
158 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) { | |
159 | return ret; | |
160 | } | |
161 | ||
162 | tv = time(NULL); | |
163 | switch (Z_TYPE_P(value)) { | |
164 | case IS_NULL: | |
165 | case IS_TRUE: | |
166 | case IS_FALSE: | |
167 | ret = yac_storage_update(key, key_len, (char *)&flag, sizeof(int), flag, ttl, add, tv); | |
168 | break; | |
169 | case IS_LONG: | |
170 | ret = yac_storage_update(key, key_len, (char *)&Z_LVAL_P(value), sizeof(long), flag, ttl, add, tv); | |
171 | break; | |
172 | case IS_DOUBLE: | |
173 | ret = yac_storage_update(key, key_len, (char *)&Z_DVAL_P(value), sizeof(double), flag, ttl, add, tv); | |
174 | break; | |
175 | case IS_STRING: | |
176 | #ifdef IS_CONSTANT | |
177 | case IS_CONSTANT: | |
178 | #endif | |
179 | { | |
180 | if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) { | |
181 | int compressed_len; | |
182 | char *compressed; | |
183 | ||
184 | /* if longer than this, then we can not stored the length in flag */ | |
185 | if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) { | |
186 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value)); | |
187 | return ret; | |
188 | } | |
189 | ||
190 | compressed = emalloc(Z_STRLEN_P(value) * 1.05); | |
191 | compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed); | |
192 | if (!compressed_len || compressed_len > Z_STRLEN_P(value)) { | |
193 | php_error_docref(NULL, E_WARNING, "Compression failed"); | |
194 | efree(compressed); | |
195 | return ret; | |
196 | } | |
197 | ||
198 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
199 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value)); | |
200 | efree(compressed); | |
201 | return ret; | |
202 | } | |
203 | ||
204 | flag |= YAC_ENTRY_COMPRESSED; | |
205 | flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT); | |
206 | ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv); | |
207 | efree(compressed); | |
208 | } else { | |
209 | ret = yac_storage_update(key, key_len, Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv); | |
210 | } | |
211 | } | |
212 | break; | |
213 | case IS_ARRAY: | |
214 | #ifdef IS_CONSTANT_ARRAY | |
215 | case IS_CONSTANT_ARRAY: | |
216 | #endif | |
217 | case IS_OBJECT: | |
218 | { | |
219 | smart_str buf = {0}; | |
220 | ||
221 | if (yac_serializer(value, &buf, &msg)) { | |
222 | if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
223 | int compressed_len; | |
224 | char *compressed; | |
225 | ||
226 | if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) { | |
227 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored"); | |
228 | return ret; | |
229 | } | |
230 | ||
231 | compressed = emalloc(buf.s->len * 1.05); | |
232 | compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed); | |
233 | if (!compressed_len || compressed_len > buf.s->len) { | |
234 | php_error_docref(NULL, E_WARNING, "Compression failed"); | |
235 | efree(compressed); | |
236 | return ret; | |
237 | } | |
238 | ||
239 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) { | |
240 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored"); | |
241 | efree(compressed); | |
242 | return ret; | |
243 | } | |
244 | ||
245 | flag |= YAC_ENTRY_COMPRESSED; | |
246 | flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT); | |
247 | ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv); | |
248 | efree(compressed); | |
249 | } else { | |
250 | ret = yac_storage_update(key, key_len, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv); | |
251 | } | |
252 | smart_str_free(&buf); | |
253 | } else { | |
254 | php_error_docref(NULL, E_WARNING, "Serialization failed"); | |
255 | smart_str_free(&buf); | |
256 | } | |
257 | } | |
258 | break; | |
259 | case IS_RESOURCE: | |
260 | php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored"); | |
261 | break; | |
262 | default: | |
263 | php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag); | |
264 | break; | |
265 | } | |
266 | ||
267 | return ret; | |
268 | } | |
269 | /* }}} */ | |
270 | ||
271 | static int yac_add_multi_impl(yac_object *yac, zval *kvs, int ttl, int add) /* {{{ */ { | |
272 | HashTable *ht = Z_ARRVAL_P(kvs); | |
273 | zend_string *key; | |
274 | zend_ulong idx; | |
275 | zval *value; | |
276 | ||
277 | ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) { | |
278 | uint32_t should_free = 0; | |
279 | if (!key) { | |
280 | key = strpprintf(0, "%lu", idx); | |
281 | should_free = 1; | |
282 | } | |
283 | if (yac_add_impl(yac, key, value, ttl, add)) { | |
284 | if (should_free) { | |
285 | zend_string_release(key); | |
286 | } | |
287 | continue; | |
288 | } else { | |
289 | if (should_free) { | |
290 | zend_string_release(key); | |
291 | } | |
292 | return 0; | |
293 | } | |
294 | } ZEND_HASH_FOREACH_END(); | |
295 | ||
296 | return 1; | |
297 | } | |
298 | /* }}} */ | |
299 | ||
300 | static zval* yac_get_impl(yac_object *yac, zend_string *name, uint32_t *cas, zval *rv) /* {{{ */ { | |
301 | uint32_t flag, size = 0; | |
302 | char *data, *msg; | |
303 | time_t tv; | |
304 | const char *key; | |
305 | size_t key_len; | |
306 | ||
307 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) { | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | tv = time(NULL); | |
312 | if (yac_storage_find(key, key_len, &data, &size, &flag, (int *)cas, tv)) { | |
313 | switch ((flag & YAC_ENTRY_TYPE_MASK)) { | |
314 | case IS_NULL: | |
315 | if (size == sizeof(int)) { | |
316 | ZVAL_NULL(rv); | |
317 | } | |
318 | efree(data); | |
319 | break; | |
320 | case IS_TRUE: | |
321 | if (size == sizeof(int)) { | |
322 | ZVAL_TRUE(rv); | |
323 | } | |
324 | efree(data); | |
325 | break; | |
326 | case IS_FALSE: | |
327 | if (size == sizeof(int)) { | |
328 | ZVAL_FALSE(rv); | |
329 | } | |
330 | efree(data); | |
331 | break; | |
332 | case IS_LONG: | |
333 | if (size == sizeof(long)) { | |
334 | ZVAL_LONG(rv, *(long*)data); | |
335 | } | |
336 | efree(data); | |
337 | break; | |
338 | case IS_DOUBLE: | |
339 | if (size == sizeof(double)) { | |
340 | ZVAL_DOUBLE(rv, *(double*)data); | |
341 | } | |
342 | efree(data); | |
343 | break; | |
344 | case IS_STRING: | |
345 | #ifdef IS_CONSTANT | |
346 | case IS_CONSTANT: | |
347 | #endif | |
348 | { | |
349 | if ((flag & YAC_ENTRY_COMPRESSED)) { | |
350 | size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT); | |
351 | char *origin = emalloc(orig_len + 1); | |
352 | uint32_t length; | |
353 | length = fastlz_decompress(data, size, origin, orig_len); | |
354 | if (!length) { | |
355 | php_error_docref(NULL, E_WARNING, "Decompression failed"); | |
356 | efree(data); | |
357 | efree(origin); | |
358 | return NULL; | |
359 | } | |
360 | ZVAL_STRINGL(rv, origin, length); | |
361 | efree(origin); | |
362 | efree(data); | |
363 | } else { | |
364 | ZVAL_STRINGL(rv, data, size); | |
365 | efree(data); | |
366 | } | |
367 | } | |
368 | break; | |
369 | case IS_ARRAY: | |
370 | #ifdef IS_CONSTANT_ARRAY | |
371 | case IS_CONSTANT_ARRAY: | |
372 | #endif | |
373 | case IS_OBJECT: | |
374 | { | |
375 | if ((flag & YAC_ENTRY_COMPRESSED)) { | |
376 | size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT); | |
377 | char *origin = emalloc(orig_len + 1); | |
378 | length = fastlz_decompress(data, size, origin, orig_len); | |
379 | if (!length) { | |
380 | php_error_docref(NULL, E_WARNING, "Decompression failed"); | |
381 | efree(data); | |
382 | efree(origin); | |
383 | return NULL; | |
384 | } | |
385 | efree(data); | |
386 | data = origin; | |
387 | size = length; | |
388 | } | |
389 | rv = yac_unserializer(data, size, &msg, rv); | |
390 | efree(data); | |
391 | } | |
392 | break; | |
393 | default: | |
394 | php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag); | |
395 | rv = NULL; | |
396 | break; | |
397 | } | |
398 | } else { | |
399 | rv = NULL; | |
400 | } | |
401 | ||
402 | return rv; | |
403 | } | |
404 | /* }}} */ | |
405 | ||
406 | static zval* yac_get_multi_impl(yac_object *yac, zval *keys, zval *cas, zval *rv) /* {{{ */ { | |
407 | zval *value; | |
408 | HashTable *ht = Z_ARRVAL_P(keys); | |
409 | ||
410 | array_init(rv); | |
411 | ||
412 | ZEND_HASH_FOREACH_VAL(ht, value) { | |
413 | uint32_t lcas = 0; | |
414 | zval *v, tmp; | |
415 | ||
416 | switch (Z_TYPE_P(value)) { | |
417 | case IS_STRING: | |
418 | if ((v = yac_get_impl(yac, Z_STR_P(value), &lcas, &tmp))) { | |
419 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v); | |
420 | } else { | |
421 | ZVAL_FALSE(&tmp); | |
422 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp); | |
423 | } | |
424 | continue; | |
425 | default: | |
426 | { | |
427 | zend_string *key = zval_get_string(value); | |
428 | if ((v = yac_get_impl(yac, key, &lcas, &tmp))) { | |
429 | zend_symtable_update(Z_ARRVAL_P(rv), key, v); | |
430 | } else { | |
431 | ZVAL_FALSE(&tmp); | |
432 | zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp); | |
433 | } | |
434 | zend_string_release(key); | |
435 | } | |
436 | continue; | |
437 | } | |
438 | } ZEND_HASH_FOREACH_END(); | |
439 | ||
440 | return rv; | |
441 | } | |
442 | /* }}} */ | |
443 | ||
444 | static int yac_delete_impl(yac_object *yac, zend_string *name, int ttl) /* {{{ */ { | |
445 | time_t tv = 0; | |
446 | const char *key; | |
447 | size_t key_len; | |
448 | ||
449 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) { | |
450 | return 0; | |
451 | } | |
452 | ||
453 | if (ttl) { | |
454 | tv = (zend_ulong)time(NULL); | |
455 | } | |
456 | ||
457 | return yac_storage_delete(key, key_len, ttl, tv); | |
458 | } | |
459 | /* }}} */ | |
460 | ||
461 | static int yac_delete_multi_impl(yac_object *yac, zval *keys, int ttl) /* {{{ */ { | |
462 | HashTable *ht = Z_ARRVAL_P(keys); | |
463 | int ret = 1; | |
464 | zval *value; | |
465 | ||
466 | ZEND_HASH_FOREACH_VAL(ht, value) { | |
467 | switch (Z_TYPE_P(value)) { | |
468 | case IS_STRING: | |
469 | ret = ret & yac_delete_impl(yac, Z_STR_P(value), ttl); | |
470 | continue; | |
471 | default: | |
472 | { | |
473 | zend_string *key = zval_get_string(value); | |
474 | ret = ret & yac_delete_impl(yac, key, ttl); | |
475 | zend_string_release(key); | |
476 | } | |
477 | continue; | |
478 | } | |
479 | } ZEND_HASH_FOREACH_END(); | |
480 | ||
481 | return ret; | |
482 | } | |
483 | /* }}} */ | |
484 | ||
485 | static zend_object *yac_object_new(zend_class_entry *ce) /* {{{ */ { | |
486 | yac_object *yac = emalloc(sizeof(yac_object) + zend_object_properties_size(ce)); | |
487 | ||
488 | if (!YAC_G(enable)) { | |
489 | zend_throw_exception(NULL, "Yac is not enabled", 0); | |
490 | } | |
491 | ||
492 | zend_object_std_init(&yac->std, ce); | |
493 | yac->std.handlers = &yac_obj_handlers; | |
494 | yac->prefix_len = 0; | |
495 | ||
496 | ||
497 | return &yac->std; | |
498 | } | |
499 | /* }}} */ | |
500 | ||
501 | static void yac_object_free(zend_object *object) /* {{{ */ { | |
502 | zend_object_std_dtor(object); | |
503 | } | |
504 | /* }}} */ | |
505 | ||
506 | static zval* yac_read_property_ptr(zval *zobj, zval *name, int type, void **cache_slot) /* {{{ */ { | |
507 | return &EG(error_zval); | |
508 | } | |
509 | /* }}} */ | |
510 | ||
511 | static zval* yac_read_property(zval *zobj, zval *name, int type, void **cache_slot, zval *rv) /* {{{ */ { | |
512 | if (UNEXPECTED(type == BP_VAR_RW||type == BP_VAR_W)) { | |
513 | return &EG(error_zval); | |
514 | } | |
515 | ||
516 | if (yac_get_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), NULL, rv)) { | |
517 | return rv; | |
518 | } | |
519 | ||
520 | return &EG(uninitialized_zval); | |
521 | } | |
522 | /* }}} */ | |
523 | ||
524 | static YAC_WHANDLER yac_write_property(zval *zobj, zval *name, zval *value, void **cache_slot) /* {{{ */ { | |
525 | yac_add_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), value, 0, 0); | |
526 | Z_TRY_ADDREF_P(value); | |
527 | ||
528 | YAC_WHANDLER_RET(value); | |
529 | } | |
530 | /* }}} */ | |
531 | ||
532 | static void yac_unset_property(zval *zobj, zval *name, void **cache_slot) /* {{{ */ { | |
533 | yac_delete_impl(Z_YACOBJ_P(zobj), Z_STR_P(name), 0); | |
534 | } | |
535 | /* }}} */ | |
536 | ||
537 | /** {{{ proto public Yac::__construct([string $prefix]) | |
538 | */ | |
539 | PHP_METHOD(yac, __construct) { | |
540 | zend_string *prefix = NULL; | |
541 | ||
542 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) { | |
543 | return; | |
544 | } | |
545 | ||
546 | if (prefix && ZSTR_LEN(prefix)) { | |
547 | yac_object *yac; | |
548 | if (ZSTR_LEN(prefix) > YAC_STORAGE_MAX_KEY_LEN) { | |
549 | zend_throw_exception_ex(NULL, 0, | |
550 | "Prefix '%s' exceed max key length '%d' bytes", ZSTR_VAL(prefix), YAC_STORAGE_MAX_KEY_LEN); | |
551 | return; | |
552 | } | |
553 | yac = Z_YACOBJ_P(getThis()); | |
554 | yac->prefix_len = ZSTR_LEN(prefix); | |
555 | memcpy(yac->prefix, ZSTR_VAL(prefix), ZSTR_LEN(prefix)); | |
556 | } | |
557 | } | |
558 | /* }}} */ | |
559 | ||
560 | /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl]) | |
561 | */ | |
562 | PHP_METHOD(yac, add) { | |
563 | zend_long ttl = 0; | |
564 | zval *keys, *value = NULL; | |
565 | int ret; | |
566 | ||
567 | switch (ZEND_NUM_ARGS()) { | |
568 | case 1: | |
569 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) { | |
570 | return; | |
571 | } | |
572 | break; | |
573 | case 2: | |
574 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) { | |
575 | return; | |
576 | } | |
577 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
578 | if (Z_TYPE_P(value) == IS_LONG) { | |
579 | ttl = Z_LVAL_P(value); | |
580 | value = NULL; | |
581 | } else { | |
582 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer"); | |
583 | return; | |
584 | } | |
585 | } | |
586 | break; | |
587 | case 3: | |
588 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) { | |
589 | return; | |
590 | } | |
591 | break; | |
592 | default: | |
593 | WRONG_PARAM_COUNT; | |
594 | } | |
595 | ||
596 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
597 | ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 1); | |
598 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
599 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 1); | |
600 | } else { | |
601 | zend_string *key = zval_get_string(keys); | |
602 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 1); | |
603 | zend_string_release(key); | |
604 | } | |
605 | ||
606 | RETURN_BOOL(ret); | |
607 | } | |
608 | /* }}} */ | |
609 | ||
610 | /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl]) | |
611 | */ | |
612 | PHP_METHOD(yac, set) { | |
613 | zend_long ttl = 0; | |
614 | zval *keys, *value = NULL; | |
615 | int ret; | |
616 | ||
617 | switch (ZEND_NUM_ARGS()) { | |
618 | case 1: | |
619 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) { | |
620 | return; | |
621 | } | |
622 | break; | |
623 | case 2: | |
624 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) { | |
625 | return; | |
626 | } | |
627 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
628 | if (Z_TYPE_P(value) == IS_LONG) { | |
629 | ttl = Z_LVAL_P(value); | |
630 | value = NULL; | |
631 | } else { | |
632 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer"); | |
633 | return; | |
634 | } | |
635 | } | |
636 | break; | |
637 | case 3: | |
638 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) { | |
639 | return; | |
640 | } | |
641 | break; | |
642 | default: | |
643 | WRONG_PARAM_COUNT; | |
644 | } | |
645 | ||
646 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
647 | ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 0); | |
648 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
649 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 0); | |
650 | } else { | |
651 | zend_string *key = zval_get_string(keys); | |
652 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 0); | |
653 | zend_string_release(key); | |
654 | } | |
655 | ||
656 | RETURN_BOOL(ret); | |
657 | } | |
658 | /* }}} */ | |
659 | ||
660 | /** {{{ proto public Yac::get(mixed $keys[, int &$cas]) | |
661 | */ | |
662 | PHP_METHOD(yac, get) { | |
663 | uint32_t lcas = 0; | |
664 | zval *ret, *keys, *cas = NULL; | |
665 | ||
666 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) { | |
667 | return; | |
668 | } | |
669 | ||
670 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
671 | ret = yac_get_multi_impl(Z_YACOBJ_P(getThis()), keys, cas, return_value); | |
672 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
673 | ret = yac_get_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), &lcas, return_value); | |
674 | } else { | |
675 | zend_string *key = zval_get_string(keys); | |
676 | ret = yac_get_impl(Z_YACOBJ_P(getThis()), key, &lcas, return_value); | |
677 | zend_string_release(key); | |
678 | } | |
679 | ||
680 | if (ret == NULL) { | |
681 | RETURN_FALSE; | |
682 | } | |
683 | } | |
684 | /* }}} */ | |
685 | ||
686 | /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0]) | |
687 | */ | |
688 | PHP_METHOD(yac, delete) { | |
689 | zend_long time = 0; | |
690 | zval *keys; | |
691 | int ret; | |
692 | ||
693 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) { | |
694 | return; | |
695 | } | |
696 | ||
697 | if (Z_TYPE_P(keys) == IS_ARRAY) { | |
698 | ret = yac_delete_multi_impl(Z_YACOBJ_P(getThis()), keys, time); | |
699 | } else if (Z_TYPE_P(keys) == IS_STRING) { | |
700 | ret = yac_delete_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), time); | |
701 | } else { | |
702 | zend_string *key = zval_get_string(keys); | |
703 | ret = yac_delete_impl(Z_YACOBJ_P(getThis()), key, time); | |
704 | zend_string_release(key); | |
705 | } | |
706 | ||
707 | RETURN_BOOL(ret); | |
708 | } | |
709 | /* }}} */ | |
710 | ||
711 | /** {{{ proto public Yac::flush(void) | |
712 | */ | |
713 | PHP_METHOD(yac, flush) { | |
714 | ||
715 | yac_storage_flush(); | |
716 | ||
717 | RETURN_TRUE; | |
718 | } | |
719 | /* }}} */ | |
720 | ||
721 | /** {{{ proto public Yac::info(void) | |
722 | */ | |
723 | PHP_METHOD(yac, info) { | |
724 | yac_storage_info *inf; | |
725 | ||
726 | inf = yac_storage_get_info(); | |
727 | ||
728 | array_init(return_value); | |
729 | ||
730 | add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize); | |
731 | add_assoc_long(return_value, "slots_memory_size", inf->k_msize); | |
732 | add_assoc_long(return_value, "values_memory_size", inf->v_msize); | |
733 | add_assoc_long(return_value, "segment_size", inf->segment_size); | |
734 | add_assoc_long(return_value, "segment_num", inf->segments_num); | |
735 | add_assoc_long(return_value, "miss", inf->miss); | |
736 | add_assoc_long(return_value, "hits", inf->hits); | |
737 | add_assoc_long(return_value, "fails", inf->fails); | |
738 | add_assoc_long(return_value, "kicks", inf->kicks); | |
739 | add_assoc_long(return_value, "recycles", inf->recycles); | |
740 | add_assoc_long(return_value, "slots_size", inf->slots_size); | |
741 | add_assoc_long(return_value, "slots_used", inf->slots_num); | |
742 | ||
743 | yac_storage_free_info(inf); | |
744 | return; | |
745 | } | |
746 | /* }}} */ | |
747 | ||
748 | /** {{{ proto public Yac::dump(int $limit) | |
749 | */ | |
750 | PHP_METHOD(yac, dump) { | |
751 | long limit = 100; | |
752 | yac_item_list *list, *l; | |
753 | ||
754 | array_init(return_value); | |
755 | ||
756 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) { | |
757 | return; | |
758 | } | |
759 | ||
760 | list = l = yac_storage_dump(limit); | |
761 | for (; l; l = l->next) { | |
762 | zval item; | |
763 | array_init(&item); | |
764 | add_assoc_long(&item, "index", l->index); | |
765 | add_assoc_long(&item, "hash", l->h); | |
766 | add_assoc_long(&item, "crc", l->crc); | |
767 | add_assoc_long(&item, "ttl", l->ttl); | |
768 | add_assoc_long(&item, "k_len", l->k_len); | |
769 | add_assoc_long(&item, "v_len", l->v_len); | |
770 | add_assoc_long(&item, "size", l->size); | |
771 | add_assoc_string(&item, "key", (char*)l->key); | |
772 | add_next_index_zval(return_value, &item); | |
773 | } | |
774 | ||
775 | yac_storage_free_list(list); | |
776 | return; | |
777 | } | |
778 | /* }}} */ | |
779 | ||
780 | #if 0 | |
781 | only OO-style APIs is supported now | |
782 | /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl]) | |
783 | */ | |
784 | PHP_FUNCTION(yac_add) | |
785 | { | |
786 | PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
787 | } | |
788 | /* }}} */ | |
789 | ||
790 | /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl]) | |
791 | */ | |
792 | PHP_FUNCTION(yac_set) | |
793 | { | |
794 | PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
795 | } | |
796 | /* }}} */ | |
797 | ||
798 | /* {{{ proto bool yac_get(mixed $keys[, int &$cas]) | |
799 | */ | |
800 | PHP_FUNCTION(yac_get) | |
801 | { | |
802 | PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
803 | } | |
804 | /* }}} */ | |
805 | ||
806 | /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0]) | |
807 | */ | |
808 | PHP_FUNCTION(yac_delete) | |
809 | { | |
810 | PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
811 | } | |
812 | /* }}} */ | |
813 | ||
814 | /* {{{ proto bool yac_flush(void) | |
815 | */ | |
816 | PHP_FUNCTION(yac_flush) | |
817 | { | |
818 | PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
819 | } | |
820 | /* }}} */ | |
821 | ||
822 | /* {{{ proto bool yac_info(void) | |
823 | */ | |
824 | PHP_FUNCTION(yac_info) | |
825 | { | |
826 | PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU); | |
827 | } | |
828 | /* }}} */ | |
829 | ||
830 | /* {{{ yac_functions[] */ | |
831 | zend_function_entry yac_functions[] = { | |
832 | PHP_FE(yac_add, arginfo_yac_add) | |
833 | PHP_FE(yac_set, arginfo_yac_add) | |
834 | PHP_FE(yac_get, arginfo_yac_get) | |
835 | PHP_FE(yac_delete, arginfo_yac_delete) | |
836 | PHP_FE(yac_flush, arginfo_yac_void) | |
837 | PHP_FE(yac_info, arginfo_yac_void) | |
838 | {NULL, NULL} | |
839 | }; | |
840 | /* }}} */ | |
841 | #endif | |
842 | ||
843 | /** {{{ yac_methods | |
844 | */ | |
845 | zend_function_entry yac_methods[] = { | |
846 | PHP_ME(yac, __construct, arginfo_yac_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) | |
847 | PHP_ME(yac, add, arginfo_yac_add, ZEND_ACC_PUBLIC) | |
848 | PHP_ME(yac, set, arginfo_yac_add, ZEND_ACC_PUBLIC) | |
849 | PHP_ME(yac, get, arginfo_yac_get, ZEND_ACC_PUBLIC) | |
850 | PHP_ME(yac, delete, arginfo_yac_delete, ZEND_ACC_PUBLIC) | |
851 | PHP_ME(yac, flush, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
852 | PHP_ME(yac, info, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
853 | PHP_ME(yac, dump, arginfo_yac_void, ZEND_ACC_PUBLIC) | |
854 | {NULL, NULL, NULL} | |
855 | }; | |
856 | /* }}} */ | |
857 | ||
858 | /* {{{ PHP_GINIT_FUNCTION | |
859 | */ | |
860 | PHP_GINIT_FUNCTION(yac) | |
861 | { | |
862 | yac_globals->enable = 1; | |
863 | yac_globals->k_msize = (4 * 1024 * 1024); | |
864 | yac_globals->v_msize = (64 * 1024 * 1024); | |
865 | yac_globals->debug = 0; | |
866 | yac_globals->compress_threshold = -1; | |
867 | yac_globals->enable_cli = 0; | |
868 | #ifdef PHP_WIN32 | |
869 | yac_globals->mmap_base = NULL; | |
870 | #endif | |
871 | } | |
872 | /* }}} */ | |
873 | ||
874 | /* {{{ PHP_MINIT_FUNCTION | |
875 | */ | |
876 | PHP_MINIT_FUNCTION(yac) | |
877 | { | |
878 | char *msg; | |
879 | zend_class_entry ce; | |
880 | ||
881 | REGISTER_INI_ENTRIES(); | |
882 | ||
883 | if (!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) { | |
884 | YAC_G(enable) = 0; | |
885 | } | |
886 | ||
887 | if (YAC_G(enable)) { | |
888 | if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) { | |
889 | php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno)); | |
890 | return FAILURE; | |
891 | } | |
892 | } | |
893 | ||
894 | REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS); | |
895 | REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS); | |
896 | REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS); | |
897 | REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS); | |
898 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_PHP", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS); | |
899 | #if YAC_ENABLE_MSGPACK | |
900 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_MSGPACK", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS); | |
901 | #endif | |
902 | #if YAC_ENABLE_IGBINARY | |
903 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_IGBINARY", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS); | |
904 | #endif | |
905 | #if YAC_ENABLE_JSON | |
906 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_JSON", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS); | |
907 | #endif | |
908 | ||
909 | #if YAC_ENABLE_MSGPACK | |
910 | if (strcmp(YAC_G(serializer), "msgpack") == 0) { | |
911 | yac_serializer = yac_serializer_msgpack_pack; | |
912 | yac_unserializer = yac_serializer_msgpack_unpack; | |
913 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS); | |
914 | } else | |
915 | #endif | |
916 | #if YAC_ENABLE_IGBINARY | |
917 | if (strcmp(YAC_G(serializer), "igbinary") == 0) { | |
918 | yac_serializer = yac_serializer_igbinary_pack; | |
919 | yac_unserializer = yac_serializer_igbinary_unpack; | |
920 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS); | |
921 | } else | |
922 | #endif | |
923 | #if YAC_ENABLE_JSON | |
924 | if (strcmp(YAC_G(serializer), "json") == 0) { | |
925 | yac_serializer = yac_serializer_json_pack; | |
926 | yac_unserializer = yac_serializer_json_unpack; | |
927 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS); | |
928 | } else | |
929 | #endif | |
930 | { | |
931 | yac_serializer = yac_serializer_php_pack; | |
932 | yac_unserializer = yac_serializer_php_unpack; | |
933 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS); | |
934 | } | |
935 | ||
936 | INIT_CLASS_ENTRY(ce, "Yac", yac_methods); | |
937 | yac_class_ce = zend_register_internal_class(&ce); | |
938 | yac_class_ce->ce_flags |= ZEND_ACC_FINAL; | |
939 | yac_class_ce->create_object = yac_object_new; | |
940 | ||
941 | memcpy(&yac_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); | |
942 | yac_obj_handlers.offset = XtOffsetOf(yac_object, std); | |
943 | yac_obj_handlers.free_obj = yac_object_free; | |
944 | if (YAC_G(enable)) { | |
945 | yac_obj_handlers.read_property = yac_read_property; | |
946 | yac_obj_handlers.write_property = yac_write_property; | |
947 | yac_obj_handlers.unset_property = yac_unset_property; | |
948 | yac_obj_handlers.get_property_ptr_ptr = yac_read_property_ptr; | |
949 | } | |
950 | ||
951 | return SUCCESS; | |
952 | } | |
953 | /* }}} */ | |
954 | ||
955 | /* {{{ PHP_MSHUTDOWN_FUNCTION | |
956 | */ | |
957 | PHP_MSHUTDOWN_FUNCTION(yac) | |
958 | { | |
959 | UNREGISTER_INI_ENTRIES(); | |
960 | if (YAC_G(enable)) { | |
961 | yac_storage_shutdown(); | |
962 | } | |
963 | return SUCCESS; | |
964 | } | |
965 | /* }}} */ | |
966 | ||
967 | /* {{{ PHP_MINFO_FUNCTION | |
968 | */ | |
969 | PHP_MINFO_FUNCTION(yac) | |
970 | { | |
971 | smart_str names = {0,}; | |
972 | ||
973 | php_info_print_table_start(); | |
974 | php_info_print_table_header(2, "yac support", "enabled"); | |
975 | php_info_print_table_row(2, "Version", PHP_YAC_VERSION); | |
976 | php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name()); | |
977 | ||
978 | smart_str_appends(&names, "php"); | |
979 | #if YAC_ENABLE_MSGPACK | |
980 | smart_str_appends(&names, ", msgpack"); | |
981 | #endif | |
982 | #if YAC_ENABLE_IGBINARY | |
983 | smart_str_appends(&names, ", igbinary"); | |
984 | #endif | |
985 | #if YAC_ENABLE_JSON | |
986 | smart_str_appends(&names, ", json"); | |
987 | #endif | |
988 | php_info_print_table_row(2, "Serializer", ZSTR_VAL(names.s)); | |
989 | smart_str_free(&names); | |
990 | ||
991 | php_info_print_table_end(); | |
992 | ||
993 | DISPLAY_INI_ENTRIES(); | |
994 | ||
995 | if (YAC_G(enable)) { | |
996 | char buf[64]; | |
997 | yac_storage_info *inf; | |
998 | inf = yac_storage_get_info(); | |
999 | ||
1000 | php_info_print_table_start(); | |
1001 | php_info_print_table_colspan_header(2, "Cache info"); | |
1002 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize); | |
1003 | php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf); | |
1004 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize); | |
1005 | php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf); | |
1006 | snprintf(buf, sizeof(buf), "%ld", inf->v_msize); | |
1007 | php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf); | |
1008 | snprintf(buf, sizeof(buf), "%d", inf->segment_size); | |
1009 | php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf); | |
1010 | snprintf(buf, sizeof(buf), "%d", inf->segments_num); | |
1011 | php_info_print_table_row(2, "Number of Segments (segment_num)", buf); | |
1012 | snprintf(buf, sizeof(buf), "%d", inf->slots_size); | |
1013 | php_info_print_table_row(2, "Total Slots Number(slots_size)", buf); | |
1014 | snprintf(buf, sizeof(buf), "%d", inf->slots_num); | |
1015 | php_info_print_table_row(2, "Total Used Slots(slots_num)", buf); | |
1016 | php_info_print_table_end(); | |
1017 | ||
1018 | yac_storage_free_info(inf); | |
1019 | } | |
1020 | } | |
1021 | /* }}} */ | |
1022 | ||
1023 | #ifdef COMPILE_DL_YAC | |
1024 | ZEND_GET_MODULE(yac) | |
1025 | #endif | |
1026 | ||
1027 | static zend_module_dep yac_module_deps[] = { | |
1028 | #if YAC_ENABLE_MSGPACK | |
1029 | ZEND_MOD_REQUIRED("msgpack") | |
1030 | #endif | |
1031 | #if YAC_ENABLE_IGBINARY | |
1032 | ZEND_MOD_REQUIRED("igbinary") | |
1033 | #endif | |
1034 | #if YAC_ENABLE_JSON | |
1035 | ZEND_MOD_REQUIRED("json") | |
1036 | #endif | |
1037 | {NULL, NULL, NULL, 0} | |
1038 | }; | |
1039 | ||
1040 | /* {{{ yac_module_entry | |
1041 | */ | |
1042 | zend_module_entry yac_module_entry = { | |
1043 | STANDARD_MODULE_HEADER_EX, | |
1044 | NULL, | |
1045 | yac_module_deps, | |
1046 | "yac", | |
1047 | NULL, /* yac_functions, */ | |
1048 | PHP_MINIT(yac), | |
1049 | PHP_MSHUTDOWN(yac), | |
1050 | NULL, | |
1051 | NULL, | |
1052 | PHP_MINFO(yac), | |
1053 | PHP_YAC_VERSION, | |
1054 | PHP_MODULE_GLOBALS(yac), | |
1055 | PHP_GINIT(yac), | |
1056 | NULL, | |
1057 | NULL, | |
1058 | STANDARD_MODULE_PROPERTIES_EX | |
1059 | }; | |
1060 | /* }}} */ | |
1061 | ||
1062 | /* | |
1063 | * Local variables: | |
1064 | * tab-width: 4 | |
1065 | * c-basic-offset: 4 | |
1066 | * End: | |
1067 | * vim600: noet sw=4 ts=4 fdm=marker | |
1068 | * vim<600: noet sw=4 ts=4 | |
1069 | */ | |
1070 |