Codebase list php-yac / 477098c
Imported Upstream version 2.0.1+0.9.2 Ondřej Surý 7 years ago
74 changed file(s) with 4806 addition(s) and 4790 deletion(s). Raw diff Collapse all Expand all
0 <?xml version="1.0" encoding="UTF-8"?>
1 <package packagerversion="1.9.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
2 <name>yac</name>
3 <channel>pecl.php.net</channel>
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&apos;d better make sure that your product is not very sensitive to that.</description>
8 <lead>
9 <name>Xinchen Hui</name>
10 <user>laruence</user>
11 <email>laruence@php.net</email>
12 <active>yes</active>
13 </lead>
14 <lead>
15 <name>Wei Dai</name>
16 <user>Demon</user>
17 <email>zxcvdavid@gmail.com</email>
18 <active>yes</active>
19 </lead>
20 <date>2016-07-02</date>
21 <time>07:02:18</time>
22 <version>
23 <release>2.0.1</release>
24 <api>2.0.1</api>
25 </version>
26 <stability>
27 <release>beta</release>
28 <api>beta</api>
29 </stability>
30 <license uri="http://www.php.net/license">PHP</license>
31 <notes>
32 - Fixed issue #63 (include smart_str.h)
33 </notes>
34 <contents>
35 <dir name="/">
36 <file md5sum="3b66d8c8e7316c67f7c5cd90821a53e2" name="storage/allocator/allocators/createfilemapping.c" role="src" />
37 <file md5sum="ba23da7a1141b5b0b1222641f9948d46" name="storage/allocator/allocators/mmap.c" role="src" />
38 <file md5sum="d719e0643e649a89ad307ee41b82e0fd" name="storage/allocator/allocators/shm.c" role="src" />
39 <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="bdfa646f9b8aa5c9157f7e9d4db2d8aa" name="storage/yac_storage.c" role="src" />
43 <file md5sum="543b3b1b8571c4b9c02eafee4a6f3fa3" name="compressor/fastlz/LICENSE" role="doc" />
44 <file md5sum="fa4d2340c50946340603066b02f7e6dd" name="compressor/fastlz/README.TXT" role="doc" />
45 <file md5sum="d49275e3dcc1d23d6ce0041648be8e14" name="compressor/fastlz/fastlz.h" role="src" />
46 <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" />
50 <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" />
53 <file md5sum="69b6eab19f3e907097fd41ec6dfc024a" name="tests/004.phpt" role="test" />
54 <file md5sum="bf0340a9a20b5fe5dc300f3ec907a2dc" name="tests/005.phpt" role="test" />
55 <file md5sum="44354a5ac454a1bce3b00d8f5f9d6c4c" name="tests/006.phpt" role="test" />
56 <file md5sum="10ec3265916ceaeb4cdd56efce701eb0" name="tests/007.phpt" role="test" />
57 <file md5sum="f567e7205b3eb0ea757cb09dcd55cc7e" name="tests/008.phpt" role="test" />
58 <file md5sum="c9000c4ff1b00520cfb14c0e45508b30" name="tests/009.phpt" role="test" />
59 <file md5sum="1bf41dadf4a96d8730d37d89fb8257a6" name="tests/010.phpt" role="test" />
60 <file md5sum="0f47511cd434d57d01f78ad8a65a13cb" name="tests/011.phpt" role="test" />
61 <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" />
65 <file md5sum="4c4242640be3dfdccf4b46600dbe3682" name="tests/issue012.phpt" role="test" />
66 <file md5sum="ac36c858a802d2d8c791b4de479adb59" name="config.w32" role="src" />
67 <file md5sum="dd34a70236f008af999de817b93a5e3a" name="LICENSE" role="doc" />
68 <file md5sum="e4313698b2307a62bdbac09fd596ae53" name="CREDITS" role="doc" />
69 <file md5sum="89e004fcd6284ae53be768a0cca690e0" name="config.m4" role="src" />
70 <file md5sum="a0ca2d5cbb6c4cb8817b47c3cf59f5a6" name="yac.c" role="src" />
71 <file md5sum="00eddd25a9ebba01e1a9100f4d8a8573" name="php_yac.h" role="src" />
72 </dir>
73 </contents>
74 <dependencies>
75 <required>
76 <php>
77 <min>7.0.0</min>
78 </php>
79 <pearinstaller>
80 <min>1.4.0</min>
81 </pearinstaller>
82 </required>
83 </dependencies>
84 <providesextension>yac</providesextension>
85 <extsrcrelease />
86 <changelog>
87 <release>
88 <date>2016-07-02</date>
89 <version>
90 <release>2.0.1</release>
91 <api>2.0.1</api>
92 </version>
93 <stability>
94 <release>beta</release>
95 <api>beta</api>
96 </stability>
97 <license uri="http://www.php.net/license">PHP License</license>
98 <notes>
99 - Fixed issue #63 (include smart_str.h)
100 </notes>
101 </release>
102 <release>
103 <date>2015-10-27</date>
104 <version>
105 <release>2.0.0</release>
106 <api>2.0.0</api>
107 </version>
108 <stability>
109 <release>beta</release>
110 <api>beta</api>
111 </stability>
112 <license uri="http://www.php.net/license">PHP License</license>
113 <notes>
114 - Release yac for PHP7
115 </notes>
116 </release>
117 <release>
118 <date>2014-10-22</date>
119 <version>
120 <release>0.9.2</release>
121 <api>0.9.2</api>
122 </version>
123 <stability>
124 <release>beta</release>
125 <api>beta</api>
126 </stability>
127 <license uri="http://www.php.net/license">PHP License</license>
128 <notes>
129 - Add --with-system-fastlz option
130 </notes>
131 </release>
132 <release>
133 <date>2014-07-25</date>
134 <version>
135 <release>0.9.1</release>
136 <api>0.9.1</api>
137 </version>
138 <stability>
139 <release>beta</release>
140 <api>beta</api>
141 </stability>
142 <license uri="http://www.php.net/license">PHP License</license>
143 <notes>
144 - Try to fix windows build
145 </notes>
146 </release>
147 <release>
148 <date>2014-07-24</date>
149 <version>
150 <release>0.9.0</release>
151 <api>0.9.0</api>
152 </version>
153 <stability>
154 <release>beta</release>
155 <api>beta</api>
156 </stability>
157 <license uri="http://www.php.net/license">PHP License</license>
158 <notes>
159 - first release
160 </notes>
161 </release>
162 </changelog>
163 </package>
+0
-149
package.xml less more
0 <?xml version="1.0" encoding="UTF-8"?>
1 <package packagerversion="1.9.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
2 <name>yac</name>
3 <channel>pecl.php.net</channel>
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&apos;d better make sure that your product is not very sensitive to that.</description>
8 <lead>
9 <name>Xinchen Hui</name>
10 <user>laruence</user>
11 <email>laruence@php.net</email>
12 <active>yes</active>
13 </lead>
14 <lead>
15 <name>Wei Dai</name>
16 <user>Demon</user>
17 <email>zxcvdavid@gmail.com</email>
18 <active>yes</active>
19 </lead>
20 <date>2015-10-27</date>
21 <time>11:01:50</time>
22 <version>
23 <release>2.0.0</release>
24 <api>2.0.0</api>
25 </version>
26 <stability>
27 <release>beta</release>
28 <api>beta</api>
29 </stability>
30 <license uri="http://www.php.net/license">PHP</license>
31 <notes>
32 - Release yac for PHP7
33 </notes>
34 <contents>
35 <dir name="/">
36 <file md5sum="3b66d8c8e7316c67f7c5cd90821a53e2" name="storage/allocator/allocators/createfilemapping.c" role="src" />
37 <file md5sum="ba23da7a1141b5b0b1222641f9948d46" name="storage/allocator/allocators/mmap.c" role="src" />
38 <file md5sum="d719e0643e649a89ad307ee41b82e0fd" name="storage/allocator/allocators/shm.c" role="src" />
39 <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="bdfa646f9b8aa5c9157f7e9d4db2d8aa" name="storage/yac_storage.c" role="src" />
43 <file md5sum="543b3b1b8571c4b9c02eafee4a6f3fa3" name="compressor/fastlz/LICENSE" role="doc" />
44 <file md5sum="fa4d2340c50946340603066b02f7e6dd" name="compressor/fastlz/README.TXT" role="doc" />
45 <file md5sum="d49275e3dcc1d23d6ce0041648be8e14" name="compressor/fastlz/fastlz.h" role="src" />
46 <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="351b75236d1b9fb37c36db1657d96270" name="serializer/msgpack.c" role="src" />
50 <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" />
53 <file md5sum="69b6eab19f3e907097fd41ec6dfc024a" name="tests/004.phpt" role="test" />
54 <file md5sum="bf0340a9a20b5fe5dc300f3ec907a2dc" name="tests/005.phpt" role="test" />
55 <file md5sum="44354a5ac454a1bce3b00d8f5f9d6c4c" name="tests/006.phpt" role="test" />
56 <file md5sum="10ec3265916ceaeb4cdd56efce701eb0" name="tests/007.phpt" role="test" />
57 <file md5sum="f567e7205b3eb0ea757cb09dcd55cc7e" name="tests/008.phpt" role="test" />
58 <file md5sum="c9000c4ff1b00520cfb14c0e45508b30" name="tests/009.phpt" role="test" />
59 <file md5sum="1bf41dadf4a96d8730d37d89fb8257a6" name="tests/010.phpt" role="test" />
60 <file md5sum="0f47511cd434d57d01f78ad8a65a13cb" name="tests/011.phpt" role="test" />
61 <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" />
65 <file md5sum="4c4242640be3dfdccf4b46600dbe3682" name="tests/issue012.phpt" role="test" />
66 <file md5sum="ac36c858a802d2d8c791b4de479adb59" name="config.w32" role="src" />
67 <file md5sum="dd34a70236f008af999de817b93a5e3a" name="LICENSE" role="doc" />
68 <file md5sum="e4313698b2307a62bdbac09fd596ae53" name="CREDITS" role="doc" />
69 <file md5sum="74d418b88383de544b1dde3b172fa1ae" name="config.m4" role="src" />
70 <file md5sum="a0ca2d5cbb6c4cb8817b47c3cf59f5a6" name="yac.c" role="src" />
71 <file md5sum="90c212a3ab8c2ddbca07445df9ed4c02" name="php_yac.h" role="src" />
72 </dir>
73 </contents>
74 <dependencies>
75 <required>
76 <php>
77 <min>7.0.0</min>
78 </php>
79 <pearinstaller>
80 <min>1.4.0</min>
81 </pearinstaller>
82 </required>
83 </dependencies>
84 <providesextension>yac</providesextension>
85 <extsrcrelease />
86 <changelog>
87 <release>
88 <date>2015-10-27</date>
89 <version>
90 <release>2.0.0</release>
91 <api>2.0.0</api>
92 </version>
93 <stability>
94 <release>beta</release>
95 <api>beta</api>
96 </stability>
97 <license uri="http://www.php.net/license">PHP License</license>
98 <notes>
99 - Release yac for PHP7
100 </notes>
101 </release>
102 <release>
103 <date>2014-10-22</date>
104 <version>
105 <release>0.9.2</release>
106 <api>0.9.2</api>
107 </version>
108 <stability>
109 <release>beta</release>
110 <api>beta</api>
111 </stability>
112 <license uri="http://www.php.net/license">PHP License</license>
113 <notes>
114 - Add --with-system-fastlz option
115 </notes>
116 </release>
117 <release>
118 <date>2014-07-25</date>
119 <version>
120 <release>0.9.1</release>
121 <api>0.9.1</api>
122 </version>
123 <stability>
124 <release>beta</release>
125 <api>beta</api>
126 </stability>
127 <license uri="http://www.php.net/license">PHP License</license>
128 <notes>
129 - Try to fix windows build
130 </notes>
131 </release>
132 <release>
133 <date>2014-07-24</date>
134 <version>
135 <release>0.9.0</release>
136 <api>0.9.0</api>
137 </version>
138 <stability>
139 <release>beta</release>
140 <api>beta</api>
141 </stability>
142 <license uri="http://www.php.net/license">PHP License</license>
143 <notes>
144 - first release
145 </notes>
146 </release>
147 </changelog>
148 </package>
+0
-4
yac-2.0.0/CREDITS less more
0 yac
1
2 Xinchen Hui
3 Wei Dai
+0
-68
yac-2.0.0/LICENSE less more
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
-24
yac-2.0.0/compressor/fastlz/LICENSE less more
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
-75
yac-2.0.0/compressor/fastlz/README.TXT less more
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
-551
yac-2.0.0/compressor/fastlz/fastlz.c less more
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
-100
yac-2.0.0/compressor/fastlz/fastlz.h less more
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
-217
yac-2.0.0/config.m4 less more
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, wheter to use system FastLZ bibrary,
7 [ --with-system-fastlz Use system FastLZ bibrary], 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 fi
+0
-28
yac-2.0.0/config.w32 less more
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
-80
yac-2.0.0/php_yac.h less more
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.0"
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 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
-56
yac-2.0.0/serializer/msgpack.c less more
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 "ext/standard/php_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
-70
yac-2.0.0/serializer/php.c less more
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
-41
yac-2.0.0/serializer/yac_serializer.h less more
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
-303
yac-2.0.0/storage/allocator/allocators/createfilemapping.c less more
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
-125
yac-2.0.0/storage/allocator/allocators/mmap.c less more
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
-188
yac-2.0.0/storage/allocator/allocators/shm.c less more
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
-207
yac-2.0.0/storage/allocator/yac_allocator.c less more
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
-97
yac-2.0.0/storage/allocator/yac_allocator.h less more
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
-629
yac-2.0.0/storage/yac_storage.c less more
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 ulong 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 ulong yac_inline_hash_func2(char *key, uint len) {
142 register ulong 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 ulong 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 uint 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 ulong 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 uint 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 ulong 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 = (ulong)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 uint 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 uint i;
473 ulong 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
-129
yac-2.0.0/storage/yac_storage.h less more
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
-21
yac-2.0.0/tests/001.phpt less more
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
-92
yac-2.0.0/tests/002.phpt less more
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
-48
yac-2.0.0/tests/003.phpt less more
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
-38
yac-2.0.0/tests/004.phpt less more
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
-45
yac-2.0.0/tests/005.phpt less more
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 Catchable fatal error: Object of class stdClass could not be converted to string in %s005.php on line %d
+0
-32
yac-2.0.0/tests/006.phpt less more
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
-41
yac-2.0.0/tests/007.phpt less more
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
-39
yac-2.0.0/tests/008.phpt less more
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
-39
yac-2.0.0/tests/009.phpt less more
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
-35
yac-2.0.0/tests/010.phpt less more
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
-38
yac-2.0.0/tests/011.phpt less more
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
-33
yac-2.0.0/tests/012.phpt less more
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
-16
yac-2.0.0/tests/013.phpt less more
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
-26
yac-2.0.0/tests/014.phpt less more
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
-22
yac-2.0.0/tests/015.phpt less more
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
-24
yac-2.0.0/tests/issue012.phpt less more
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
-1060
yac-2.0.0/yac.c less more
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 case IS_CONSTANT:
150 {
151 if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) {
152 int compressed_len;
153 char *compressed;
154
155 /* if longer than this, then we can not stored the length in flag */
156 if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) {
157 php_error_docref(NULL, E_WARNING, "Value is too long(%d bytes) to be stored", Z_STRLEN_P(value));
158 if (prefix->len) {
159 zend_string_release(prefix_key);
160 }
161 return ret;
162 }
163
164 compressed = emalloc(Z_STRLEN_P(value) * 1.05);
165 compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed);
166 if (!compressed_len || compressed_len > Z_STRLEN_P(value)) {
167 php_error_docref(NULL, E_WARNING, "Compression failed");
168 efree(compressed);
169 if (prefix->len) {
170 zend_string_release(prefix_key);
171 }
172 return ret;
173 }
174
175 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
176 php_error_docref(NULL, E_WARNING, "Value is too long(%d bytes) to be stored", Z_STRLEN_P(value));
177 efree(compressed);
178 if (prefix->len) {
179 zend_string_release(prefix_key);
180 }
181 return ret;
182 }
183
184 flag |= YAC_ENTRY_COMPRESSED;
185 flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT);
186 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv);
187 efree(compressed);
188 } else {
189 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv);
190 }
191 }
192 break;
193 case IS_ARRAY:
194 #ifdef IS_CONSTANT_ARRAY
195 case IS_CONSTANT_ARRAY:
196 #endif
197 case IS_OBJECT:
198 {
199 smart_str buf = {0};
200 #if ENABLE_MSGPACK
201 if (yac_serializer_msgpack_pack(value, &buf, &msg))
202 #else
203
204 if (yac_serializer_php_pack(value, &buf, &msg))
205 #endif
206 {
207 if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) {
208 int compressed_len;
209 char *compressed;
210
211 if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) {
212 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
213 if (prefix->len) {
214 zend_string_release(prefix_key);
215 }
216 return ret;
217 }
218
219 compressed = emalloc(buf.s->len * 1.05);
220 compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed);
221 if (!compressed_len || compressed_len > buf.s->len) {
222 php_error_docref(NULL, E_WARNING, "Compression failed");
223 efree(compressed);
224 if (prefix->len) {
225 zend_string_release(prefix_key);
226 }
227 return ret;
228 }
229
230 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
231 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
232 efree(compressed);
233 if (prefix->len) {
234 zend_string_release(prefix_key);
235 }
236 return ret;
237 }
238
239 flag |= YAC_ENTRY_COMPRESSED;
240 flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT);
241 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv);
242 efree(compressed);
243 } else {
244 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv);
245 }
246 smart_str_free(&buf);
247 } else {
248 php_error_docref(NULL, E_WARNING, "Serialization failed");
249 smart_str_free(&buf);
250 }
251 }
252 break;
253 case IS_RESOURCE:
254 php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored");
255 break;
256 default:
257 php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag);
258 break;
259 }
260
261 if (prefix->len) {
262 zend_string_release(prefix_key);
263 }
264
265 return ret;
266 }
267 /* }}} */
268
269 static int yac_add_multi_impl(zend_string *prefix, zval *kvs, int ttl, int add) /* {{{ */ {
270 HashTable *ht = Z_ARRVAL_P(kvs);
271 zend_string *key;
272 zend_ulong idx;
273 zval *value;
274
275 ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) {
276 uint32_t should_free = 0;
277 if (!key) {
278 key = strpprintf(0, "%lu", idx);
279 should_free = 1;
280 }
281 if (yac_add_impl(prefix, key, value, ttl, add)) {
282 if (should_free) {
283 zend_string_release(key);
284 }
285 continue;
286 } else {
287 if (should_free) {
288 zend_string_release(key);
289 }
290 return 0;
291 }
292 } ZEND_HASH_FOREACH_END();
293
294 return 1;
295 }
296 /* }}} */
297
298 static zval * yac_get_impl(zend_string *prefix, zend_string *key, uint32_t *cas, zval *rv) /* {{{ */ {
299 uint32_t flag, size = 0;
300 char *data, *msg;
301 time_t tv;
302 zend_string *prefix_key;
303
304 if ((ZSTR_LEN(key) + prefix->len) > YAC_STORAGE_MAX_KEY_LEN) {
305 php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes",
306 prefix->len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN);
307 return NULL;
308 }
309
310 if (prefix->len) {
311 prefix_key = strpprintf(YAC_STORAGE_MAX_KEY_LEN, "%s%s", ZSTR_VAL(prefix), ZSTR_VAL(key));
312 key = prefix_key;
313 }
314
315 tv = time(NULL);
316 if (yac_storage_find(ZSTR_VAL(key), ZSTR_LEN(key), &data, &size, &flag, (int *)cas, tv)) {
317 switch ((flag & YAC_ENTRY_TYPE_MASK)) {
318 case IS_NULL:
319 if (size == sizeof(int)) {
320 ZVAL_NULL(rv);
321 }
322 efree(data);
323 break;
324 case IS_TRUE:
325 if (size == sizeof(int)) {
326 ZVAL_TRUE(rv);
327 }
328 efree(data);
329 break;
330 case IS_FALSE:
331 if (size == sizeof(int)) {
332 ZVAL_FALSE(rv);
333 }
334 efree(data);
335 break;
336 case IS_LONG:
337 if (size == sizeof(long)) {
338 ZVAL_LONG(rv, *(long*)data);
339 }
340 efree(data);
341 break;
342 case IS_DOUBLE:
343 if (size == sizeof(double)) {
344 ZVAL_DOUBLE(rv, *(double*)data);
345 }
346 efree(data);
347 break;
348 case IS_STRING:
349 case IS_CONSTANT:
350 {
351 if ((flag & YAC_ENTRY_COMPRESSED)) {
352 size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
353 char *origin = emalloc(orig_len + 1);
354 uint32_t length;
355 length = fastlz_decompress(data, size, origin, orig_len);
356 if (!length) {
357 php_error_docref(NULL, E_WARNING, "Decompression failed");
358 efree(data);
359 efree(origin);
360 if (prefix->len) {
361 zend_string_release(prefix_key);
362 }
363 return NULL;
364 }
365 ZVAL_STRINGL(rv, origin, length);
366 efree(origin);
367 efree(data);
368 } else {
369 ZVAL_STRINGL(rv, data, size);
370 efree(data);
371 }
372 }
373 break;
374 case IS_ARRAY:
375 #ifdef IS_CONSTANT_ARRAY
376 case IS_CONSTANT_ARRAY:
377 #endif
378 case IS_OBJECT:
379 {
380 if ((flag & YAC_ENTRY_COMPRESSED)) {
381 size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
382 char *origin = emalloc(orig_len + 1);
383 length = fastlz_decompress(data, size, origin, orig_len);
384 if (!length) {
385 php_error_docref(NULL, E_WARNING, "Decompression failed");
386 efree(data);
387 efree(origin);
388 if (prefix->len) {
389 zend_string_release(prefix_key);
390 }
391 return NULL;
392 }
393 efree(data);
394 data = origin;
395 size = length;
396 }
397 #if ENABLE_MSGPACK
398 rv = yac_serializer_msgpack_unpack(data, size, &msg, rv);
399 #else
400 rv = yac_serializer_php_unpack(data, size, &msg, rv);
401 #endif
402 if (!rv) {
403 php_error_docref(NULL, E_WARNING, "Unserialization failed");
404 }
405 efree(data);
406 }
407 break;
408 default:
409 php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag);
410 rv = NULL;
411 break;
412 }
413 } else {
414 rv = NULL;
415 }
416
417 if (prefix->len) {
418 zend_string_release(prefix_key);
419 }
420
421 return rv;
422 }
423 /* }}} */
424
425 static zval * yac_get_multi_impl(zend_string *prefix, zval *keys, zval *cas, zval *rv) /* {{{ */ {
426 zval *value;
427 HashTable *ht = Z_ARRVAL_P(keys);
428
429 array_init(rv);
430
431 ZEND_HASH_FOREACH_VAL(ht, value) {
432 uint32_t lcas = 0;
433 zval *v, tmp_rv;
434
435 ZVAL_UNDEF(&tmp_rv);
436
437 switch (Z_TYPE_P(value)) {
438 case IS_STRING:
439 if ((v = yac_get_impl(prefix, Z_STR_P(value), &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) {
440 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v);
441 } else {
442 ZVAL_FALSE(&tmp_rv);
443 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp_rv);
444 }
445 continue;
446 default:
447 {
448 zend_string *key = zval_get_string(value);
449 if ((v = yac_get_impl(prefix, key, &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) {
450 zend_symtable_update(Z_ARRVAL_P(rv), key, v);
451 } else {
452 ZVAL_FALSE(&tmp_rv);
453 zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp_rv);
454 }
455 zend_string_release(key);
456 }
457 continue;
458 }
459 } ZEND_HASH_FOREACH_END();
460
461 return rv;
462 }
463 /* }}} */
464
465 void yac_delete_impl(char *prefix, uint32_t prefix_len, char *key, uint32_t len, int ttl) /* {{{ */ {
466 char buf[YAC_STORAGE_MAX_KEY_LEN];
467 time_t tv = 0;
468
469 if ((len + prefix_len) > YAC_STORAGE_MAX_KEY_LEN) {
470 php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes",
471 prefix_len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN);
472 return;
473 }
474
475 if (prefix_len) {
476 len = snprintf(buf, sizeof(buf), "%s%s", prefix, key);
477 key = (char *)buf;
478 }
479
480 if (ttl) {
481 tv = (ulong)time(NULL);
482 }
483
484 yac_storage_delete(key, len, ttl, tv);
485 }
486 /* }}} */
487
488 static void yac_delete_multi_impl(char *prefix, uint32_t prefix_len, zval *keys, int ttl) /* {{{ */ {
489 HashTable *ht = Z_ARRVAL_P(keys);
490 zval *value;
491
492 ZEND_HASH_FOREACH_VAL(ht, value) {
493 switch (Z_TYPE_P(value)) {
494 case IS_STRING:
495 yac_delete_impl(prefix, prefix_len, Z_STRVAL_P(value), Z_STRLEN_P(value), ttl);
496 continue;
497 default:
498 {
499 zval copy;
500 zend_make_printable_zval(value, &copy);
501 yac_delete_impl(prefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), ttl);
502 zval_dtor(&copy);
503 }
504 continue;
505 }
506 } ZEND_HASH_FOREACH_END();
507 }
508 /* }}} */
509
510 /** {{{ proto public Yac::__construct([string $prefix])
511 */
512 PHP_METHOD(yac, __construct) {
513 zend_string *prefix = NULL;
514
515 if (!YAC_G(enable)) {
516 return;
517 }
518
519 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) {
520 return;
521 }
522
523 if (!prefix) {
524 return;
525 }
526
527 zend_update_property_str(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), prefix);
528
529 }
530 /* }}} */
531
532 /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl])
533 */
534 PHP_METHOD(yac, add) {
535 long ttl = 0;
536 zval rv, *keys, *prefix, *value = NULL;
537 uint32_t ret;
538
539 if (!YAC_G(enable)) {
540 RETURN_FALSE;
541 }
542
543 switch (ZEND_NUM_ARGS()) {
544 case 1:
545 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
546 return;
547 }
548 break;
549 case 2:
550 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
551 return;
552 }
553 if (Z_TYPE_P(keys) == IS_ARRAY) {
554 if (Z_TYPE_P(value) == IS_LONG) {
555 ttl = Z_LVAL_P(value);
556 value = NULL;
557 } else {
558 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
559 return;
560 }
561 }
562 break;
563 case 3:
564 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
565 return;
566 }
567 break;
568 default:
569 WRONG_PARAM_COUNT;
570 }
571
572 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
573
574 if (Z_TYPE_P(keys) == IS_ARRAY) {
575 ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 1);
576 } else if (Z_TYPE_P(keys) == IS_STRING) {
577 ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 1);
578 } else {
579 zval copy;
580 zend_make_printable_zval(keys, &copy);
581 ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 1);
582 zval_dtor(&copy);
583 }
584
585 RETURN_BOOL(ret);
586 }
587 /* }}} */
588
589 /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl])
590 */
591 PHP_METHOD(yac, set) {
592 long ttl = 0;
593 zval rv, *keys, *prefix, *value = NULL;
594 uint32_t ret;
595
596 if (!YAC_G(enable)) {
597 RETURN_FALSE;
598 }
599
600 switch (ZEND_NUM_ARGS()) {
601 case 1:
602 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
603 return;
604 }
605 break;
606 case 2:
607 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
608 return;
609 }
610 if (Z_TYPE_P(keys) == IS_ARRAY) {
611 if (Z_TYPE_P(value) == IS_LONG) {
612 ttl = Z_LVAL_P(value);
613 value = NULL;
614 } else {
615 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
616 return;
617 }
618 }
619 break;
620 case 3:
621 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
622 return;
623 }
624 break;
625 default:
626 WRONG_PARAM_COUNT;
627 }
628
629 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
630
631 if (Z_TYPE_P(keys) == IS_ARRAY) {
632 ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 0);
633 } else if (Z_TYPE_P(keys) == IS_STRING) {
634 ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 0);
635 } else {
636 zval copy;
637 zend_make_printable_zval(keys, &copy);
638 ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 0);
639 zval_dtor(&copy);
640 }
641
642 RETURN_BOOL(ret);
643 }
644 /* }}} */
645
646 /** {{{ proto public Yac::__set(string $name, mixed $value)
647 */
648 PHP_METHOD(yac, __set) {
649 zend_string *key;
650 zval *prefix, *value, rv;
651
652 if (!YAC_G(enable)) {
653 RETURN_FALSE;
654 }
655
656 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) {
657 return;
658 }
659
660 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
661
662 yac_add_impl(Z_STR_P(prefix), key, value, 0, 0);
663 }
664 /* }}} */
665
666 /** {{{ proto public Yac::get(mixed $keys[, int &$cas])
667 */
668 PHP_METHOD(yac, get) {
669 uint32_t lcas = 0;
670 zval rv, *ret, *keys, *prefix, *cas = NULL;
671
672 if (!YAC_G(enable)) {
673 RETURN_FALSE;
674 }
675
676 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) {
677 return;
678 }
679
680 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
681
682 if (Z_TYPE_P(keys) == IS_ARRAY) {
683 ret = yac_get_multi_impl(Z_STR_P(prefix), keys, cas, return_value);
684 } else if (Z_TYPE_P(keys) == IS_STRING) {
685 ret = yac_get_impl(Z_STR_P(prefix), Z_STR_P(keys), &lcas, return_value);
686 } else {
687 zval copy;
688 zend_make_printable_zval(keys, &copy);
689 ret = yac_get_impl(Z_STR_P(prefix), Z_STR(copy), &lcas, return_value);
690 zval_dtor(&copy);
691 }
692
693 if (ret == NULL) {
694 RETURN_FALSE;
695 }
696 }
697 /* }}} */
698
699 /** {{{ proto public Yac::__get(string $name)
700 */
701 PHP_METHOD(yac, __get) {
702 zval *prefix, rv;
703 zend_string *key;
704 uint32_t lcas = 0;
705
706 if (!YAC_G(enable)) {
707 RETURN_FALSE;
708 }
709
710 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
711 return;
712 }
713
714 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
715
716 if (yac_get_impl(Z_STR_P(prefix), key, &lcas, return_value) == NULL) {
717 RETURN_FALSE;
718 }
719 }
720 /* }}} */
721
722 /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0])
723 */
724 PHP_METHOD(yac, delete) {
725 long time = 0;
726 zval *keys, *prefix, rv;
727 char *sprefix = NULL;
728 uint32_t prefix_len = 0;
729
730 if (!YAC_G(enable)) {
731 RETURN_FALSE;
732 }
733
734 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) {
735 return;
736 }
737
738 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
739 sprefix = Z_STRVAL_P(prefix);
740 prefix_len = Z_STRLEN_P(prefix);
741
742 if (Z_TYPE_P(keys) == IS_ARRAY) {
743 yac_delete_multi_impl(sprefix, prefix_len, keys, time);
744 } else if (Z_TYPE_P(keys) == IS_STRING) {
745 yac_delete_impl(sprefix, prefix_len, Z_STRVAL_P(keys), Z_STRLEN_P(keys), time);
746 } else {
747 zval copy;
748 zend_make_printable_zval(keys, &copy);
749 yac_delete_impl(sprefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), time);
750 zval_dtor(&copy);
751 }
752
753 RETURN_TRUE;
754 }
755 /* }}} */
756
757 /** {{{ proto public Yac::flush(void)
758 */
759 PHP_METHOD(yac, flush) {
760
761 if (!YAC_G(enable)) {
762 RETURN_FALSE;
763 }
764
765 yac_storage_flush();
766
767 RETURN_TRUE;
768 }
769 /* }}} */
770
771 /** {{{ proto public Yac::info(void)
772 */
773 PHP_METHOD(yac, info) {
774 yac_storage_info *inf;
775
776 if (!YAC_G(enable)) {
777 RETURN_FALSE;
778 }
779
780 inf = yac_storage_get_info();
781
782 array_init(return_value);
783
784 add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize);
785 add_assoc_long(return_value, "slots_memory_size", inf->k_msize);
786 add_assoc_long(return_value, "values_memory_size", inf->v_msize);
787 add_assoc_long(return_value, "segment_size", inf->segment_size);
788 add_assoc_long(return_value, "segment_num", inf->segments_num);
789 add_assoc_long(return_value, "miss", inf->miss);
790 add_assoc_long(return_value, "hits", inf->hits);
791 add_assoc_long(return_value, "fails", inf->fails);
792 add_assoc_long(return_value, "kicks", inf->kicks);
793 add_assoc_long(return_value, "recycles", inf->recycles);
794 add_assoc_long(return_value, "slots_size", inf->slots_size);
795 add_assoc_long(return_value, "slots_used", inf->slots_num);
796
797 yac_storage_free_info(inf);
798 }
799 /* }}} */
800
801 /** {{{ proto public Yac::dump(int $limit)
802 */
803 PHP_METHOD(yac, dump) {
804 long limit = 100;
805 yac_item_list *list, *l;
806
807 if (!YAC_G(enable)) {
808 RETURN_FALSE;
809 }
810
811 array_init(return_value);
812
813 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) {
814 return;
815 }
816
817 list = l = yac_storage_dump(limit);
818 for (; l; l = l->next) {
819 zval item;
820 array_init(&item);
821 add_assoc_long(&item, "index", l->index);
822 add_assoc_long(&item, "hash", l->h);
823 add_assoc_long(&item, "crc", l->crc);
824 add_assoc_long(&item, "ttl", l->ttl);
825 add_assoc_long(&item, "k_len", l->k_len);
826 add_assoc_long(&item, "v_len", l->v_len);
827 add_assoc_long(&item, "size", l->size);
828 add_assoc_string(&item, "key", (char*)l->key);
829 add_next_index_zval(return_value, &item);
830 }
831
832 yac_storage_free_list(list);
833 return;
834 }
835 /* }}} */
836
837 #if 0
838 only OO-style APIs is supported now
839 /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl])
840 */
841 PHP_FUNCTION(yac_add)
842 {
843 PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
844 }
845 /* }}} */
846
847 /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl])
848 */
849 PHP_FUNCTION(yac_set)
850 {
851 PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
852 }
853 /* }}} */
854
855 /* {{{ proto bool yac_get(mixed $keys[, int &$cas])
856 */
857 PHP_FUNCTION(yac_get)
858 {
859 PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
860 }
861 /* }}} */
862
863 /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0])
864 */
865 PHP_FUNCTION(yac_delete)
866 {
867 PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
868 }
869 /* }}} */
870
871 /* {{{ proto bool yac_flush(void)
872 */
873 PHP_FUNCTION(yac_flush)
874 {
875 PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
876 }
877 /* }}} */
878
879 /* {{{ proto bool yac_info(void)
880 */
881 PHP_FUNCTION(yac_info)
882 {
883 PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
884 }
885 /* }}} */
886
887 /* {{{ yac_functions[] */
888 zend_function_entry yac_functions[] = {
889 PHP_FE(yac_add, arginfo_yac_add)
890 PHP_FE(yac_set, arginfo_yac_add)
891 PHP_FE(yac_get, arginfo_yac_get)
892 PHP_FE(yac_delete, arginfo_yac_delete)
893 PHP_FE(yac_flush, arginfo_yac_void)
894 PHP_FE(yac_info, arginfo_yac_void)
895 {NULL, NULL}
896 };
897 /* }}} */
898 #endif
899
900 /** {{{ yac_methods
901 */
902 zend_function_entry yac_methods[] = {
903 PHP_ME(yac, __construct, arginfo_yac_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
904 PHP_ME(yac, add, arginfo_yac_add, ZEND_ACC_PUBLIC)
905 PHP_ME(yac, set, arginfo_yac_add, ZEND_ACC_PUBLIC)
906 PHP_ME(yac, __set, arginfo_yac_setter, ZEND_ACC_PUBLIC)
907 PHP_ME(yac, get, arginfo_yac_get, ZEND_ACC_PUBLIC)
908 PHP_ME(yac, __get, arginfo_yac_getter, ZEND_ACC_PUBLIC)
909 PHP_ME(yac, delete, arginfo_yac_delete, ZEND_ACC_PUBLIC)
910 PHP_ME(yac, flush, arginfo_yac_void, ZEND_ACC_PUBLIC)
911 PHP_ME(yac, info, arginfo_yac_void, ZEND_ACC_PUBLIC)
912 PHP_ME(yac, dump, arginfo_yac_void, ZEND_ACC_PUBLIC)
913 {NULL, NULL, NULL}
914 };
915 /* }}} */
916
917 /* {{{ PHP_GINIT_FUNCTION
918 */
919 PHP_GINIT_FUNCTION(yac)
920 {
921 yac_globals->enable = 1;
922 yac_globals->k_msize = (4 * 1024 * 1024);
923 yac_globals->v_msize = (64 * 1024 * 1024);
924 yac_globals->debug = 0;
925 yac_globals->compress_threshold = -1;
926 yac_globals->enable_cli = 0;
927 #ifdef PHP_WIN32
928 yac_globals->mmap_base = NULL;
929 #endif
930 }
931 /* }}} */
932
933 /* {{{ PHP_MINIT_FUNCTION
934 */
935 PHP_MINIT_FUNCTION(yac)
936 {
937 char *msg;
938 zend_class_entry ce;
939
940 REGISTER_INI_ENTRIES();
941
942 if(!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) {
943 YAC_G(enable) = 0;
944 }
945
946 if (YAC_G(enable)) {
947 if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) {
948 php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno));
949 return FAILURE;
950 }
951 }
952
953 REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
954 REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS);
955 REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS);
956 REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS);
957 #if ENABLE_MSGPACK
958 REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "PHP", sizeof("MSGPACK") -1, CONST_PERSISTENT | CONST_CS);
959 #else
960 REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "PHP", sizeof("PHP") -1, CONST_PERSISTENT | CONST_CS);
961 #endif
962
963 INIT_CLASS_ENTRY(ce, "Yac", yac_methods);
964 yac_class_ce = zend_register_internal_class(&ce);
965 zend_declare_property_stringl(yac_class_ce, ZEND_STRS(YAC_CLASS_PROPERTY_PREFIX) - 1, "", 0, ZEND_ACC_PROTECTED);
966
967 return SUCCESS;
968 }
969 /* }}} */
970
971 /* {{{ PHP_MSHUTDOWN_FUNCTION
972 */
973 PHP_MSHUTDOWN_FUNCTION(yac)
974 {
975 UNREGISTER_INI_ENTRIES();
976 if (YAC_G(enable)) {
977 yac_storage_shutdown();
978 }
979 return SUCCESS;
980 }
981 /* }}} */
982
983 /* {{{ PHP_MINFO_FUNCTION
984 */
985 PHP_MINFO_FUNCTION(yac)
986 {
987 php_info_print_table_start();
988 php_info_print_table_header(2, "yac support", "enabled");
989 php_info_print_table_row(2, "Version", PHP_YAC_VERSION);
990 php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name());
991 #if ENABLE_MSGPACK
992 php_info_print_table_row(2, "Serializer", "msgpack");
993 #else
994 php_info_print_table_row(2, "Serializer", "php");
995 #endif
996 php_info_print_table_end();
997
998 DISPLAY_INI_ENTRIES();
999
1000 if (YAC_G(enable)) {
1001 char buf[64];
1002 yac_storage_info *inf;
1003 inf = yac_storage_get_info();
1004
1005 php_info_print_table_start();
1006 php_info_print_table_colspan_header(2, "Cache info");
1007 snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize);
1008 php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf);
1009 snprintf(buf, sizeof(buf), "%ld", inf->k_msize);
1010 php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf);
1011 snprintf(buf, sizeof(buf), "%ld", inf->v_msize);
1012 php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf);
1013 snprintf(buf, sizeof(buf), "%ld", inf->segment_size);
1014 php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf);
1015 snprintf(buf, sizeof(buf), "%ld", inf->segments_num);
1016 php_info_print_table_row(2, "Number of Segments (segment_num)", buf);
1017 snprintf(buf, sizeof(buf), "%ld", inf->slots_size);
1018 php_info_print_table_row(2, "Total Slots Number(slots_size)", buf);
1019 snprintf(buf, sizeof(buf), "%ld", inf->slots_num);
1020 php_info_print_table_row(2, "Total Used Slots(slots_num)", buf);
1021 php_info_print_table_end();
1022
1023 yac_storage_free_info(inf);
1024 }
1025 }
1026 /* }}} */
1027
1028 #ifdef COMPILE_DL_YAC
1029 ZEND_GET_MODULE(yac)
1030 #endif
1031
1032 /* {{{ yac_module_entry
1033 */
1034 zend_module_entry yac_module_entry = {
1035 STANDARD_MODULE_HEADER,
1036 "yac",
1037 NULL, /* yac_functions, */
1038 PHP_MINIT(yac),
1039 PHP_MSHUTDOWN(yac),
1040 NULL,
1041 NULL,
1042 PHP_MINFO(yac),
1043 PHP_YAC_VERSION,
1044 PHP_MODULE_GLOBALS(yac),
1045 PHP_GINIT(yac),
1046 NULL,
1047 NULL,
1048 STANDARD_MODULE_PROPERTIES_EX
1049 };
1050 /* }}} */
1051
1052 /*
1053 * Local variables:
1054 * tab-width: 4
1055 * c-basic-offset: 4
1056 * End:
1057 * vim600: noet sw=4 ts=4 fdm=marker
1058 * vim<600: noet sw=4 ts=4
1059 */
0 yac
1
2 Xinchen Hui
3 Wei Dai
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, wheter to use system FastLZ bibrary,
7 [ --with-system-fastlz Use system FastLZ bibrary], 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.1"
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 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 ulong 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 ulong yac_inline_hash_func2(char *key, uint len) {
142 register ulong 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 ulong 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 uint 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 ulong 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 uint 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 ulong 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 = (ulong)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 uint 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 uint i;
473 ulong 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 Catchable fatal error: Object of class stdClass could not be converted to string in %s005.php on line %d
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 case IS_CONSTANT:
150 {
151 if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) {
152 int compressed_len;
153 char *compressed;
154
155 /* if longer than this, then we can not stored the length in flag */
156 if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) {
157 php_error_docref(NULL, E_WARNING, "Value is too long(%d bytes) to be stored", Z_STRLEN_P(value));
158 if (prefix->len) {
159 zend_string_release(prefix_key);
160 }
161 return ret;
162 }
163
164 compressed = emalloc(Z_STRLEN_P(value) * 1.05);
165 compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed);
166 if (!compressed_len || compressed_len > Z_STRLEN_P(value)) {
167 php_error_docref(NULL, E_WARNING, "Compression failed");
168 efree(compressed);
169 if (prefix->len) {
170 zend_string_release(prefix_key);
171 }
172 return ret;
173 }
174
175 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
176 php_error_docref(NULL, E_WARNING, "Value is too long(%d bytes) to be stored", Z_STRLEN_P(value));
177 efree(compressed);
178 if (prefix->len) {
179 zend_string_release(prefix_key);
180 }
181 return ret;
182 }
183
184 flag |= YAC_ENTRY_COMPRESSED;
185 flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT);
186 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv);
187 efree(compressed);
188 } else {
189 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv);
190 }
191 }
192 break;
193 case IS_ARRAY:
194 #ifdef IS_CONSTANT_ARRAY
195 case IS_CONSTANT_ARRAY:
196 #endif
197 case IS_OBJECT:
198 {
199 smart_str buf = {0};
200 #if ENABLE_MSGPACK
201 if (yac_serializer_msgpack_pack(value, &buf, &msg))
202 #else
203
204 if (yac_serializer_php_pack(value, &buf, &msg))
205 #endif
206 {
207 if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) {
208 int compressed_len;
209 char *compressed;
210
211 if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) {
212 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
213 if (prefix->len) {
214 zend_string_release(prefix_key);
215 }
216 return ret;
217 }
218
219 compressed = emalloc(buf.s->len * 1.05);
220 compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed);
221 if (!compressed_len || compressed_len > buf.s->len) {
222 php_error_docref(NULL, E_WARNING, "Compression failed");
223 efree(compressed);
224 if (prefix->len) {
225 zend_string_release(prefix_key);
226 }
227 return ret;
228 }
229
230 if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
231 php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
232 efree(compressed);
233 if (prefix->len) {
234 zend_string_release(prefix_key);
235 }
236 return ret;
237 }
238
239 flag |= YAC_ENTRY_COMPRESSED;
240 flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT);
241 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), compressed, compressed_len, flag, ttl, add, tv);
242 efree(compressed);
243 } else {
244 ret = yac_storage_update(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv);
245 }
246 smart_str_free(&buf);
247 } else {
248 php_error_docref(NULL, E_WARNING, "Serialization failed");
249 smart_str_free(&buf);
250 }
251 }
252 break;
253 case IS_RESOURCE:
254 php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored");
255 break;
256 default:
257 php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag);
258 break;
259 }
260
261 if (prefix->len) {
262 zend_string_release(prefix_key);
263 }
264
265 return ret;
266 }
267 /* }}} */
268
269 static int yac_add_multi_impl(zend_string *prefix, zval *kvs, int ttl, int add) /* {{{ */ {
270 HashTable *ht = Z_ARRVAL_P(kvs);
271 zend_string *key;
272 zend_ulong idx;
273 zval *value;
274
275 ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) {
276 uint32_t should_free = 0;
277 if (!key) {
278 key = strpprintf(0, "%lu", idx);
279 should_free = 1;
280 }
281 if (yac_add_impl(prefix, key, value, ttl, add)) {
282 if (should_free) {
283 zend_string_release(key);
284 }
285 continue;
286 } else {
287 if (should_free) {
288 zend_string_release(key);
289 }
290 return 0;
291 }
292 } ZEND_HASH_FOREACH_END();
293
294 return 1;
295 }
296 /* }}} */
297
298 static zval * yac_get_impl(zend_string *prefix, zend_string *key, uint32_t *cas, zval *rv) /* {{{ */ {
299 uint32_t flag, size = 0;
300 char *data, *msg;
301 time_t tv;
302 zend_string *prefix_key;
303
304 if ((ZSTR_LEN(key) + prefix->len) > YAC_STORAGE_MAX_KEY_LEN) {
305 php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes",
306 prefix->len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN);
307 return NULL;
308 }
309
310 if (prefix->len) {
311 prefix_key = strpprintf(YAC_STORAGE_MAX_KEY_LEN, "%s%s", ZSTR_VAL(prefix), ZSTR_VAL(key));
312 key = prefix_key;
313 }
314
315 tv = time(NULL);
316 if (yac_storage_find(ZSTR_VAL(key), ZSTR_LEN(key), &data, &size, &flag, (int *)cas, tv)) {
317 switch ((flag & YAC_ENTRY_TYPE_MASK)) {
318 case IS_NULL:
319 if (size == sizeof(int)) {
320 ZVAL_NULL(rv);
321 }
322 efree(data);
323 break;
324 case IS_TRUE:
325 if (size == sizeof(int)) {
326 ZVAL_TRUE(rv);
327 }
328 efree(data);
329 break;
330 case IS_FALSE:
331 if (size == sizeof(int)) {
332 ZVAL_FALSE(rv);
333 }
334 efree(data);
335 break;
336 case IS_LONG:
337 if (size == sizeof(long)) {
338 ZVAL_LONG(rv, *(long*)data);
339 }
340 efree(data);
341 break;
342 case IS_DOUBLE:
343 if (size == sizeof(double)) {
344 ZVAL_DOUBLE(rv, *(double*)data);
345 }
346 efree(data);
347 break;
348 case IS_STRING:
349 case IS_CONSTANT:
350 {
351 if ((flag & YAC_ENTRY_COMPRESSED)) {
352 size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
353 char *origin = emalloc(orig_len + 1);
354 uint32_t length;
355 length = fastlz_decompress(data, size, origin, orig_len);
356 if (!length) {
357 php_error_docref(NULL, E_WARNING, "Decompression failed");
358 efree(data);
359 efree(origin);
360 if (prefix->len) {
361 zend_string_release(prefix_key);
362 }
363 return NULL;
364 }
365 ZVAL_STRINGL(rv, origin, length);
366 efree(origin);
367 efree(data);
368 } else {
369 ZVAL_STRINGL(rv, data, size);
370 efree(data);
371 }
372 }
373 break;
374 case IS_ARRAY:
375 #ifdef IS_CONSTANT_ARRAY
376 case IS_CONSTANT_ARRAY:
377 #endif
378 case IS_OBJECT:
379 {
380 if ((flag & YAC_ENTRY_COMPRESSED)) {
381 size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
382 char *origin = emalloc(orig_len + 1);
383 length = fastlz_decompress(data, size, origin, orig_len);
384 if (!length) {
385 php_error_docref(NULL, E_WARNING, "Decompression failed");
386 efree(data);
387 efree(origin);
388 if (prefix->len) {
389 zend_string_release(prefix_key);
390 }
391 return NULL;
392 }
393 efree(data);
394 data = origin;
395 size = length;
396 }
397 #if ENABLE_MSGPACK
398 rv = yac_serializer_msgpack_unpack(data, size, &msg, rv);
399 #else
400 rv = yac_serializer_php_unpack(data, size, &msg, rv);
401 #endif
402 if (!rv) {
403 php_error_docref(NULL, E_WARNING, "Unserialization failed");
404 }
405 efree(data);
406 }
407 break;
408 default:
409 php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag);
410 rv = NULL;
411 break;
412 }
413 } else {
414 rv = NULL;
415 }
416
417 if (prefix->len) {
418 zend_string_release(prefix_key);
419 }
420
421 return rv;
422 }
423 /* }}} */
424
425 static zval * yac_get_multi_impl(zend_string *prefix, zval *keys, zval *cas, zval *rv) /* {{{ */ {
426 zval *value;
427 HashTable *ht = Z_ARRVAL_P(keys);
428
429 array_init(rv);
430
431 ZEND_HASH_FOREACH_VAL(ht, value) {
432 uint32_t lcas = 0;
433 zval *v, tmp_rv;
434
435 ZVAL_UNDEF(&tmp_rv);
436
437 switch (Z_TYPE_P(value)) {
438 case IS_STRING:
439 if ((v = yac_get_impl(prefix, Z_STR_P(value), &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) {
440 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v);
441 } else {
442 ZVAL_FALSE(&tmp_rv);
443 zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp_rv);
444 }
445 continue;
446 default:
447 {
448 zend_string *key = zval_get_string(value);
449 if ((v = yac_get_impl(prefix, key, &lcas, &tmp_rv)) && !Z_ISUNDEF(tmp_rv)) {
450 zend_symtable_update(Z_ARRVAL_P(rv), key, v);
451 } else {
452 ZVAL_FALSE(&tmp_rv);
453 zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp_rv);
454 }
455 zend_string_release(key);
456 }
457 continue;
458 }
459 } ZEND_HASH_FOREACH_END();
460
461 return rv;
462 }
463 /* }}} */
464
465 void yac_delete_impl(char *prefix, uint32_t prefix_len, char *key, uint32_t len, int ttl) /* {{{ */ {
466 char buf[YAC_STORAGE_MAX_KEY_LEN];
467 time_t tv = 0;
468
469 if ((len + prefix_len) > YAC_STORAGE_MAX_KEY_LEN) {
470 php_error_docref(NULL, E_WARNING, "Key%s can not be longer than %d bytes",
471 prefix_len? "(include prefix)" : "", YAC_STORAGE_MAX_KEY_LEN);
472 return;
473 }
474
475 if (prefix_len) {
476 len = snprintf(buf, sizeof(buf), "%s%s", prefix, key);
477 key = (char *)buf;
478 }
479
480 if (ttl) {
481 tv = (ulong)time(NULL);
482 }
483
484 yac_storage_delete(key, len, ttl, tv);
485 }
486 /* }}} */
487
488 static void yac_delete_multi_impl(char *prefix, uint32_t prefix_len, zval *keys, int ttl) /* {{{ */ {
489 HashTable *ht = Z_ARRVAL_P(keys);
490 zval *value;
491
492 ZEND_HASH_FOREACH_VAL(ht, value) {
493 switch (Z_TYPE_P(value)) {
494 case IS_STRING:
495 yac_delete_impl(prefix, prefix_len, Z_STRVAL_P(value), Z_STRLEN_P(value), ttl);
496 continue;
497 default:
498 {
499 zval copy;
500 zend_make_printable_zval(value, &copy);
501 yac_delete_impl(prefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), ttl);
502 zval_dtor(&copy);
503 }
504 continue;
505 }
506 } ZEND_HASH_FOREACH_END();
507 }
508 /* }}} */
509
510 /** {{{ proto public Yac::__construct([string $prefix])
511 */
512 PHP_METHOD(yac, __construct) {
513 zend_string *prefix = NULL;
514
515 if (!YAC_G(enable)) {
516 return;
517 }
518
519 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) {
520 return;
521 }
522
523 if (!prefix) {
524 return;
525 }
526
527 zend_update_property_str(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), prefix);
528
529 }
530 /* }}} */
531
532 /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl])
533 */
534 PHP_METHOD(yac, add) {
535 long ttl = 0;
536 zval rv, *keys, *prefix, *value = NULL;
537 uint32_t ret;
538
539 if (!YAC_G(enable)) {
540 RETURN_FALSE;
541 }
542
543 switch (ZEND_NUM_ARGS()) {
544 case 1:
545 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
546 return;
547 }
548 break;
549 case 2:
550 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
551 return;
552 }
553 if (Z_TYPE_P(keys) == IS_ARRAY) {
554 if (Z_TYPE_P(value) == IS_LONG) {
555 ttl = Z_LVAL_P(value);
556 value = NULL;
557 } else {
558 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
559 return;
560 }
561 }
562 break;
563 case 3:
564 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
565 return;
566 }
567 break;
568 default:
569 WRONG_PARAM_COUNT;
570 }
571
572 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
573
574 if (Z_TYPE_P(keys) == IS_ARRAY) {
575 ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 1);
576 } else if (Z_TYPE_P(keys) == IS_STRING) {
577 ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 1);
578 } else {
579 zval copy;
580 zend_make_printable_zval(keys, &copy);
581 ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 1);
582 zval_dtor(&copy);
583 }
584
585 RETURN_BOOL(ret);
586 }
587 /* }}} */
588
589 /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl])
590 */
591 PHP_METHOD(yac, set) {
592 long ttl = 0;
593 zval rv, *keys, *prefix, *value = NULL;
594 uint32_t ret;
595
596 if (!YAC_G(enable)) {
597 RETURN_FALSE;
598 }
599
600 switch (ZEND_NUM_ARGS()) {
601 case 1:
602 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
603 return;
604 }
605 break;
606 case 2:
607 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
608 return;
609 }
610 if (Z_TYPE_P(keys) == IS_ARRAY) {
611 if (Z_TYPE_P(value) == IS_LONG) {
612 ttl = Z_LVAL_P(value);
613 value = NULL;
614 } else {
615 php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
616 return;
617 }
618 }
619 break;
620 case 3:
621 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
622 return;
623 }
624 break;
625 default:
626 WRONG_PARAM_COUNT;
627 }
628
629 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
630
631 if (Z_TYPE_P(keys) == IS_ARRAY) {
632 ret = yac_add_multi_impl(Z_STR_P(prefix), keys, ttl, 0);
633 } else if (Z_TYPE_P(keys) == IS_STRING) {
634 ret = yac_add_impl(Z_STR_P(prefix), Z_STR_P(keys), value, ttl, 0);
635 } else {
636 zval copy;
637 zend_make_printable_zval(keys, &copy);
638 ret = yac_add_impl(Z_STR_P(prefix), Z_STR(copy), value, ttl, 0);
639 zval_dtor(&copy);
640 }
641
642 RETURN_BOOL(ret);
643 }
644 /* }}} */
645
646 /** {{{ proto public Yac::__set(string $name, mixed $value)
647 */
648 PHP_METHOD(yac, __set) {
649 zend_string *key;
650 zval *prefix, *value, rv;
651
652 if (!YAC_G(enable)) {
653 RETURN_FALSE;
654 }
655
656 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) {
657 return;
658 }
659
660 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
661
662 yac_add_impl(Z_STR_P(prefix), key, value, 0, 0);
663 }
664 /* }}} */
665
666 /** {{{ proto public Yac::get(mixed $keys[, int &$cas])
667 */
668 PHP_METHOD(yac, get) {
669 uint32_t lcas = 0;
670 zval rv, *ret, *keys, *prefix, *cas = NULL;
671
672 if (!YAC_G(enable)) {
673 RETURN_FALSE;
674 }
675
676 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) {
677 return;
678 }
679
680 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
681
682 if (Z_TYPE_P(keys) == IS_ARRAY) {
683 ret = yac_get_multi_impl(Z_STR_P(prefix), keys, cas, return_value);
684 } else if (Z_TYPE_P(keys) == IS_STRING) {
685 ret = yac_get_impl(Z_STR_P(prefix), Z_STR_P(keys), &lcas, return_value);
686 } else {
687 zval copy;
688 zend_make_printable_zval(keys, &copy);
689 ret = yac_get_impl(Z_STR_P(prefix), Z_STR(copy), &lcas, return_value);
690 zval_dtor(&copy);
691 }
692
693 if (ret == NULL) {
694 RETURN_FALSE;
695 }
696 }
697 /* }}} */
698
699 /** {{{ proto public Yac::__get(string $name)
700 */
701 PHP_METHOD(yac, __get) {
702 zval *prefix, rv;
703 zend_string *key;
704 uint32_t lcas = 0;
705
706 if (!YAC_G(enable)) {
707 RETURN_FALSE;
708 }
709
710 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
711 return;
712 }
713
714 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
715
716 if (yac_get_impl(Z_STR_P(prefix), key, &lcas, return_value) == NULL) {
717 RETURN_FALSE;
718 }
719 }
720 /* }}} */
721
722 /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0])
723 */
724 PHP_METHOD(yac, delete) {
725 long time = 0;
726 zval *keys, *prefix, rv;
727 char *sprefix = NULL;
728 uint32_t prefix_len = 0;
729
730 if (!YAC_G(enable)) {
731 RETURN_FALSE;
732 }
733
734 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) {
735 return;
736 }
737
738 prefix = zend_read_property(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), 0, &rv);
739 sprefix = Z_STRVAL_P(prefix);
740 prefix_len = Z_STRLEN_P(prefix);
741
742 if (Z_TYPE_P(keys) == IS_ARRAY) {
743 yac_delete_multi_impl(sprefix, prefix_len, keys, time);
744 } else if (Z_TYPE_P(keys) == IS_STRING) {
745 yac_delete_impl(sprefix, prefix_len, Z_STRVAL_P(keys), Z_STRLEN_P(keys), time);
746 } else {
747 zval copy;
748 zend_make_printable_zval(keys, &copy);
749 yac_delete_impl(sprefix, prefix_len, Z_STRVAL(copy), Z_STRLEN(copy), time);
750 zval_dtor(&copy);
751 }
752
753 RETURN_TRUE;
754 }
755 /* }}} */
756
757 /** {{{ proto public Yac::flush(void)
758 */
759 PHP_METHOD(yac, flush) {
760
761 if (!YAC_G(enable)) {
762 RETURN_FALSE;
763 }
764
765 yac_storage_flush();
766
767 RETURN_TRUE;
768 }
769 /* }}} */
770
771 /** {{{ proto public Yac::info(void)
772 */
773 PHP_METHOD(yac, info) {
774 yac_storage_info *inf;
775
776 if (!YAC_G(enable)) {
777 RETURN_FALSE;
778 }
779
780 inf = yac_storage_get_info();
781
782 array_init(return_value);
783
784 add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize);
785 add_assoc_long(return_value, "slots_memory_size", inf->k_msize);
786 add_assoc_long(return_value, "values_memory_size", inf->v_msize);
787 add_assoc_long(return_value, "segment_size", inf->segment_size);
788 add_assoc_long(return_value, "segment_num", inf->segments_num);
789 add_assoc_long(return_value, "miss", inf->miss);
790 add_assoc_long(return_value, "hits", inf->hits);
791 add_assoc_long(return_value, "fails", inf->fails);
792 add_assoc_long(return_value, "kicks", inf->kicks);
793 add_assoc_long(return_value, "recycles", inf->recycles);
794 add_assoc_long(return_value, "slots_size", inf->slots_size);
795 add_assoc_long(return_value, "slots_used", inf->slots_num);
796
797 yac_storage_free_info(inf);
798 }
799 /* }}} */
800
801 /** {{{ proto public Yac::dump(int $limit)
802 */
803 PHP_METHOD(yac, dump) {
804 long limit = 100;
805 yac_item_list *list, *l;
806
807 if (!YAC_G(enable)) {
808 RETURN_FALSE;
809 }
810
811 array_init(return_value);
812
813 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) {
814 return;
815 }
816
817 list = l = yac_storage_dump(limit);
818 for (; l; l = l->next) {
819 zval item;
820 array_init(&item);
821 add_assoc_long(&item, "index", l->index);
822 add_assoc_long(&item, "hash", l->h);
823 add_assoc_long(&item, "crc", l->crc);
824 add_assoc_long(&item, "ttl", l->ttl);
825 add_assoc_long(&item, "k_len", l->k_len);
826 add_assoc_long(&item, "v_len", l->v_len);
827 add_assoc_long(&item, "size", l->size);
828 add_assoc_string(&item, "key", (char*)l->key);
829 add_next_index_zval(return_value, &item);
830 }
831
832 yac_storage_free_list(list);
833 return;
834 }
835 /* }}} */
836
837 #if 0
838 only OO-style APIs is supported now
839 /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl])
840 */
841 PHP_FUNCTION(yac_add)
842 {
843 PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
844 }
845 /* }}} */
846
847 /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl])
848 */
849 PHP_FUNCTION(yac_set)
850 {
851 PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
852 }
853 /* }}} */
854
855 /* {{{ proto bool yac_get(mixed $keys[, int &$cas])
856 */
857 PHP_FUNCTION(yac_get)
858 {
859 PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
860 }
861 /* }}} */
862
863 /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0])
864 */
865 PHP_FUNCTION(yac_delete)
866 {
867 PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
868 }
869 /* }}} */
870
871 /* {{{ proto bool yac_flush(void)
872 */
873 PHP_FUNCTION(yac_flush)
874 {
875 PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
876 }
877 /* }}} */
878
879 /* {{{ proto bool yac_info(void)
880 */
881 PHP_FUNCTION(yac_info)
882 {
883 PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
884 }
885 /* }}} */
886
887 /* {{{ yac_functions[] */
888 zend_function_entry yac_functions[] = {
889 PHP_FE(yac_add, arginfo_yac_add)
890 PHP_FE(yac_set, arginfo_yac_add)
891 PHP_FE(yac_get, arginfo_yac_get)
892 PHP_FE(yac_delete, arginfo_yac_delete)
893 PHP_FE(yac_flush, arginfo_yac_void)
894 PHP_FE(yac_info, arginfo_yac_void)
895 {NULL, NULL}
896 };
897 /* }}} */
898 #endif
899
900 /** {{{ yac_methods
901 */
902 zend_function_entry yac_methods[] = {
903 PHP_ME(yac, __construct, arginfo_yac_constructor, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
904 PHP_ME(yac, add, arginfo_yac_add, ZEND_ACC_PUBLIC)
905 PHP_ME(yac, set, arginfo_yac_add, ZEND_ACC_PUBLIC)
906 PHP_ME(yac, __set, arginfo_yac_setter, ZEND_ACC_PUBLIC)
907 PHP_ME(yac, get, arginfo_yac_get, ZEND_ACC_PUBLIC)
908 PHP_ME(yac, __get, arginfo_yac_getter, ZEND_ACC_PUBLIC)
909 PHP_ME(yac, delete, arginfo_yac_delete, ZEND_ACC_PUBLIC)
910 PHP_ME(yac, flush, arginfo_yac_void, ZEND_ACC_PUBLIC)
911 PHP_ME(yac, info, arginfo_yac_void, ZEND_ACC_PUBLIC)
912 PHP_ME(yac, dump, arginfo_yac_void, ZEND_ACC_PUBLIC)
913 {NULL, NULL, NULL}
914 };
915 /* }}} */
916
917 /* {{{ PHP_GINIT_FUNCTION
918 */
919 PHP_GINIT_FUNCTION(yac)
920 {
921 yac_globals->enable = 1;
922 yac_globals->k_msize = (4 * 1024 * 1024);
923 yac_globals->v_msize = (64 * 1024 * 1024);
924 yac_globals->debug = 0;
925 yac_globals->compress_threshold = -1;
926 yac_globals->enable_cli = 0;
927 #ifdef PHP_WIN32
928 yac_globals->mmap_base = NULL;
929 #endif
930 }
931 /* }}} */
932
933 /* {{{ PHP_MINIT_FUNCTION
934 */
935 PHP_MINIT_FUNCTION(yac)
936 {
937 char *msg;
938 zend_class_entry ce;
939
940 REGISTER_INI_ENTRIES();
941
942 if(!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) {
943 YAC_G(enable) = 0;
944 }
945
946 if (YAC_G(enable)) {
947 if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) {
948 php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno));
949 return FAILURE;
950 }
951 }
952
953 REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
954 REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS);
955 REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS);
956 REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS);
957 #if ENABLE_MSGPACK
958 REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "PHP", sizeof("MSGPACK") -1, CONST_PERSISTENT | CONST_CS);
959 #else
960 REGISTER_STRINGL_CONSTANT("YAC_SERIALIZER", "PHP", sizeof("PHP") -1, CONST_PERSISTENT | CONST_CS);
961 #endif
962
963 INIT_CLASS_ENTRY(ce, "Yac", yac_methods);
964 yac_class_ce = zend_register_internal_class(&ce);
965 zend_declare_property_stringl(yac_class_ce, ZEND_STRS(YAC_CLASS_PROPERTY_PREFIX) - 1, "", 0, ZEND_ACC_PROTECTED);
966
967 return SUCCESS;
968 }
969 /* }}} */
970
971 /* {{{ PHP_MSHUTDOWN_FUNCTION
972 */
973 PHP_MSHUTDOWN_FUNCTION(yac)
974 {
975 UNREGISTER_INI_ENTRIES();
976 if (YAC_G(enable)) {
977 yac_storage_shutdown();
978 }
979 return SUCCESS;
980 }
981 /* }}} */
982
983 /* {{{ PHP_MINFO_FUNCTION
984 */
985 PHP_MINFO_FUNCTION(yac)
986 {
987 php_info_print_table_start();
988 php_info_print_table_header(2, "yac support", "enabled");
989 php_info_print_table_row(2, "Version", PHP_YAC_VERSION);
990 php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name());
991 #if ENABLE_MSGPACK
992 php_info_print_table_row(2, "Serializer", "msgpack");
993 #else
994 php_info_print_table_row(2, "Serializer", "php");
995 #endif
996 php_info_print_table_end();
997
998 DISPLAY_INI_ENTRIES();
999
1000 if (YAC_G(enable)) {
1001 char buf[64];
1002 yac_storage_info *inf;
1003 inf = yac_storage_get_info();
1004
1005 php_info_print_table_start();
1006 php_info_print_table_colspan_header(2, "Cache info");
1007 snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize);
1008 php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf);
1009 snprintf(buf, sizeof(buf), "%ld", inf->k_msize);
1010 php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf);
1011 snprintf(buf, sizeof(buf), "%ld", inf->v_msize);
1012 php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf);
1013 snprintf(buf, sizeof(buf), "%ld", inf->segment_size);
1014 php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf);
1015 snprintf(buf, sizeof(buf), "%ld", inf->segments_num);
1016 php_info_print_table_row(2, "Number of Segments (segment_num)", buf);
1017 snprintf(buf, sizeof(buf), "%ld", inf->slots_size);
1018 php_info_print_table_row(2, "Total Slots Number(slots_size)", buf);
1019 snprintf(buf, sizeof(buf), "%ld", inf->slots_num);
1020 php_info_print_table_row(2, "Total Used Slots(slots_num)", buf);
1021 php_info_print_table_end();
1022
1023 yac_storage_free_info(inf);
1024 }
1025 }
1026 /* }}} */
1027
1028 #ifdef COMPILE_DL_YAC
1029 ZEND_GET_MODULE(yac)
1030 #endif
1031
1032 /* {{{ yac_module_entry
1033 */
1034 zend_module_entry yac_module_entry = {
1035 STANDARD_MODULE_HEADER,
1036 "yac",
1037 NULL, /* yac_functions, */
1038 PHP_MINIT(yac),
1039 PHP_MSHUTDOWN(yac),
1040 NULL,
1041 NULL,
1042 PHP_MINFO(yac),
1043 PHP_YAC_VERSION,
1044 PHP_MODULE_GLOBALS(yac),
1045 PHP_GINIT(yac),
1046 NULL,
1047 NULL,
1048 STANDARD_MODULE_PROPERTIES_EX
1049 };
1050 /* }}} */
1051
1052 /*
1053 * Local variables:
1054 * tab-width: 4
1055 * c-basic-offset: 4
1056 * End:
1057 * vim600: noet sw=4 ts=4 fdm=marker
1058 * vim<600: noet sw=4 ts=4
1059 */