├── .appveyor.yml
├── .github
└── workflows
│ └── integrate.yml
├── .gitignore
├── CREDITS
├── EXPERIMENTAL
├── LICENSE
├── README.md
├── compressor
└── fastlz
│ ├── LICENSE
│ ├── README.TXT
│ ├── fastlz.c
│ └── fastlz.h
├── config.m4
├── config.w32
├── package.xml
├── php_yac.h
├── serializer
├── igbinary.c
├── json.c
├── msgpack.c
├── php.c
└── yac_serializer.h
├── storage
├── allocator
│ ├── allocators
│ │ ├── createfilemapping.c
│ │ ├── mmap.c
│ │ └── shm.c
│ ├── yac_allocator.c
│ └── yac_allocator.h
├── yac_atomic.h
├── yac_storage.c
└── yac_storage.h
├── tests
├── 001.phpt
├── 002.phpt
├── 003.phpt
├── 004.phpt
├── 005.phpt
├── 006.phpt
├── 007.phpt
├── 008.phpt
├── 009.phpt
├── 010.phpt
├── 011.phpt
├── 012.phpt
├── 013.phpt
├── 014.phpt
├── 015.phpt
├── 016.phpt
├── 017.phpt
├── 018.phpt
├── 019.phpt
├── 020.phpt
├── 021.phpt
├── 022.phpt
├── 023.phpt
├── issue012.phpt
└── yac_conflict.php
├── travis
└── compile.sh
├── yac.c
├── yac.php
├── yac.stub.php
├── yac_arginfo.h
└── yac_legacy_arginfo.h
/.appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2015
2 | version: '{branch}.{build}'
3 |
4 | clone_folder: c:\projects\yac
5 |
6 | install:
7 | ps: |
8 | if (-not (Test-Path c:\build-cache)) {
9 | mkdir c:\build-cache
10 | }
11 | $bname = 'php-sdk-' + $env:BIN_SDK_VER + '.zip'
12 | if (-not (Test-Path c:\build-cache\$bname)) {
13 | Invoke-WebRequest "https://github.com/microsoft/php-sdk-binary-tools/archive/$bname" -OutFile "c:\build-cache\$bname"
14 | }
15 | $dname0 = 'php-sdk-binary-tools-php-sdk-' + $env:BIN_SDK_VER
16 | $dname1 = 'php-sdk-' + $env:BIN_SDK_VER
17 | if (-not (Test-Path c:\build-cache\$dname1)) {
18 | 7z x c:\build-cache\$bname -oc:\build-cache
19 | move c:\build-cache\$dname0 c:\build-cache\$dname1
20 | }
21 |
22 | cache:
23 | - c:\build-cache -> .appveyor.yml
24 |
25 | environment:
26 | BIN_SDK_VER: 2.2.0
27 | matrix:
28 | - PHP_VER: 8.0.0
29 | ARCH: x64
30 | TS: 1
31 | VC: vs16
32 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
33 | - PHP_VER: 8.0.0
34 | ARCH: x64
35 | TS: 0
36 | VC: vs16
37 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
38 | - PHP_VER: 8.0.0
39 | ARCH: x86
40 | TS: 1
41 | VC: vs16
42 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
43 | - PHP_VER: 8.0.0
44 | ARCH: x86
45 | TS: 0
46 | VC: vs16
47 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
48 | - PHP_VER: 7.4.0
49 | ARCH: x64
50 | TS: 1
51 | VC: vc15
52 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
53 | - PHP_VER: 7.4.0
54 | ARCH: x64
55 | TS: 0
56 | VC: vc15
57 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
58 | - PHP_VER: 7.3.13
59 | ARCH: x64
60 | TS: 1
61 | VC: vc15
62 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
63 | - PHP_VER: 7.3.13
64 | ARCH: x64
65 | TS: 0
66 | VC: vc15
67 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
68 | - PHP_VER: 7.2.26
69 | ARCH: x64
70 | TS: 1
71 | VC: vc15
72 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
73 | - PHP_VER: 7.2.26
74 | ARCH: x64
75 | TS: 0
76 | VC: vc15
77 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
78 | - PHP_VER: 7.1.33
79 | ARCH: x64
80 | TS: 1
81 | VC: vc14
82 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
83 | - PHP_VER: 7.1.33
84 | ARCH: x64
85 | TS: 0
86 | VC: vc14
87 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
88 |
89 | build_script:
90 | ps: |
91 | $ts_part = ''
92 | if ('0' -eq $env:TS) { $ts_part = '-nts' }
93 | $bname = 'php-devel-pack-' + $env:PHP_VER + $ts_part + '-Win32-' + $env:VC.toUpper() + '-' + $env:ARCH + '.zip'
94 | if (-not (Test-Path c:\build-cache\$bname)) {
95 | Invoke-WebRequest "http://windows.php.net/downloads/releases/archives/$bname" -OutFile "c:\build-cache\$bname"
96 | if (-not (Test-Path c:\build-cache\$bname)) {
97 | Invoke-WebRequest "http://windows.php.net/downloads/releases/$bname" -OutFile "c:\build-cache\$bname"
98 | }
99 | }
100 | $dname0 = 'php-' + $env:PHP_VER + '-devel-' + $env:VC.toUpper() + '-' + $env:ARCH
101 | $dname1 = 'php-' + $env:PHP_VER + $ts_part + '-devel-' + $env:VC.toUpper() + '-' + $env:ARCH
102 | if (-not (Test-Path c:\build-cache\$dname1)) {
103 | 7z x c:\build-cache\$bname -oc:\build-cache
104 | if ($dname0 -ne $dname1) {
105 | move c:\build-cache\$dname0 c:\build-cache\$dname1
106 | }
107 | }
108 | cd c:\projects\yac
109 | $env:PATH = 'c:\build-cache\' + $dname1 + ';' + $env:PATH
110 | #echo "@echo off" | Out-File -Encoding "ASCII" task.bat
111 | #echo "" | Out-File -Encoding "ASCII" -Append task.bat
112 | echo "" | Out-File -Encoding "ASCII" task.bat
113 | echo "call phpize 2>&1" | Out-File -Encoding "ASCII" -Append task.bat
114 | echo "call configure --enable-yac --enable-debug-pack 2>&1" | Out-File -Encoding "ASCII" -Append task.bat
115 | echo "nmake /nologo 2>&1" | Out-File -Encoding "ASCII" -Append task.bat
116 | echo "exit %errorlevel%" | Out-File -Encoding "ASCII" -Append task.bat
117 | $here = (Get-Item -Path "." -Verbose).FullName
118 | $runner = 'c:\build-cache\php-sdk-' + $env:BIN_SDK_VER + '\phpsdk' + '-' + $env:VC + '-' + $env:ARCH + '.bat'
119 | $task = $here + '\task.bat'
120 | & $runner -t $task
121 |
122 | after_build:
123 | ps: |
124 | $ts_part = ''
125 | if ('0' -eq $env:TS) { $ts_part = '-nts' }
126 | $arch_part = ''
127 | if ('x64' -eq $env:ARCH) { $arch_part = '-x86_64' }
128 | if ($env:APPVEYOR_REPO_TAG -eq "true") {
129 | $bname = 'php_yac-' + $env:APPVEYOR_REPO_TAG_NAME + '-' + $env:PHP_VER.substring(0, 3) + '-' + $env:VC + $ts_part + $arch_part
130 | } else {
131 | #$bname = 'php_yac-' + $env:APPVEYOR_REPO_COMMIT.substring(0, 8) + '-' + $env:PHP_VER.substring(0, 3) + '-' + $env:VC + $ts_part + $arch_part
132 | $bname = 'php_yac' + '-' + $env:PHP_VER.substring(0, 3) + '-' + $env:VC + $ts_part + $arch_part
133 | }
134 | $zip_bname = $bname + '.zip'
135 | $dll_bname = $bname + '.dll'
136 |
137 | $dir = 'c:\projects\yac\';
138 | if ('x64' -eq $env:ARCH) { $dir = $dir + 'x64\' }
139 | $dir = $dir + 'Release'
140 | if ('1' -eq $env:TS) { $dir = $dir + '_TS' }
141 |
142 | cp $dir\php_yac.dll $dir\$dll_bname
143 | & 7z a c:\$zip_bname $dir\$dll_bname $dir\php_yac.pdb c:\projects\yac\LICENSE
144 | Push-AppveyorArtifact c:\$zip_bname
145 |
146 | test_script:
147 | ps: |
148 | $ts_part = ''
149 | if ('0' -eq $env:TS) { $ts_part = '-nts' }
150 | $bname = 'php-' + $env:PHP_VER + $ts_part + '-Win32-' + $env:VC.toUpper() + '-' + $env:ARCH + '.zip'
151 | if (-not (Test-Path c:\build-cache\$bname)) {
152 | Invoke-WebRequest "http://windows.php.net/downloads/releases/archives/$bname" -OutFile "c:\build-cache\$bname"
153 | if (-not (Test-Path c:\build-cache\$bname)) {
154 | Invoke-WebRequest "http://windows.php.net/downloads/releases/$bname" -OutFile "c:\build-cache\$bname"
155 | }
156 | }
157 | $dname = 'php-' + $env:PHP_VER + $ts_part + '-' + $env:VC.toUpper() + '-' + $env:ARCH
158 | if (-not (Test-Path c:\build-cache\$dname)) {
159 | 7z x c:\build-cache\$bname -oc:\build-cache\$dname
160 | }
161 |
162 | $dir = 'c:\projects\yac\';
163 | if ('x64' -eq $env:ARCH) { $dir = $dir + 'x64\' }
164 | $dir = $dir + 'Release'
165 | if ('1' -eq $env:TS) { $dir = $dir + '_TS' }
166 |
167 | $yac_dll_opt = '-d extension=' + $dir + '\php_yac.dll'
168 |
169 |
170 | cd c:\projects\yac
171 | mkdir c:\tests_tmp
172 | echo "" | Out-File -Encoding "ASCII" task.bat
173 | echo "set REPORT_EXIT_STATUS=1" | Out-File -Encoding "ASCII" -Append task.bat
174 | $cmd = 'call configure --enable-yac --with-prefix=c:\build-cache\' + $dname + " 2>&1"
175 | echo $cmd | Out-File -Encoding "ASCII" -Append task.bat
176 |
177 | $opts = 'set TEST_PHP_ARGS=-n -d foo=yes'
178 | if ('yes' -eq $env:OPCACHE) { $opts = $opts + ' -d zend_extension=c:\build-cache\' + $dname + '\ext\php_opcache.dll -d opcache.enabled=1 -d opcache.enable_cli=1' }
179 | $opts = $opts + ' ' + $yac_dll_opt
180 | echo $opts | Out-File -Encoding "ASCII" -Append task.bat
181 |
182 | $php = "c:\\build-cache\\" + $dname + '\php.exe'
183 | $test_php_exec = "set TEST_PHP_EXECUTABLE=" + $php
184 | echo $test_php_exec | Out-File -Encoding "ASCII" -Append task.bat
185 | $tcmd = $php + ' run-tests.php -q --offline --show-diff --set-timeout 120 -g FAIL,XFAIL,BORK,WARN,LEAK,SKIP --temp-source c:\tests_tmp --temp-target c:\tests_tmp -p c:\build-cache\' + $dname + '\php.exe'
186 | echo $tcmd | Out-File -Encoding "ASCII" -Append task.bat
187 | echo "exit %errorlevel%" | Out-File -Encoding "ASCII" -Append task.bat
188 |
189 | $here = (Get-Item -Path "." -Verbose).FullName
190 | $runner = 'c:\build-cache\php-sdk-' + $env:BIN_SDK_VER + '\phpsdk' + '-' + $env:VC + '-' + $env:ARCH + '.bat'
191 | $task = $here + '\task.bat'
192 | & $runner -t $task
193 |
--------------------------------------------------------------------------------
/.github/workflows/integrate.yml:
--------------------------------------------------------------------------------
1 | name: integrate
2 | on:
3 | push:
4 | branches: [ master ]
5 | pull_request:
6 | branches: [ master ]
7 |
8 | jobs:
9 | matrix:
10 | name: "PHP"
11 | runs-on: ubuntu-20.04
12 | strategy:
13 | matrix:
14 | PHP: ["7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"]
15 | ZTS: ["no"]
16 | include:
17 | - PHP: "8.3"
18 | ZTS: "yes"
19 | OS: "ubuntu-latest"
20 | env:
21 | PHP: ${{ matrix.PHP }}
22 | GITHUB: "yes"
23 | enable_debug: "yes"
24 | enable_session: "yes"
25 | enable_maintainer_zts: ${{ matrix.ZTS }}
26 | TEST_PHP_ARGS : "--show-diff"
27 | REPORT_EXIT_STATUS: "yes"
28 | NO_INTERACTION: "yes"
29 | steps:
30 | - name: Checkout
31 | uses: actions/checkout@v4
32 | with:
33 | submodules: true
34 | - name: Setup
35 | uses: shivammathur/setup-php@v2
36 | with:
37 | php-version: ${{ matrix.PHP }}
38 | - name: Install
39 | run: |
40 | sudo apt-get install -y re2c
41 | - name: Prepare
42 | run: |
43 | phpize
44 | - name: Build
45 | run: |
46 | ./configure
47 | - name: Make
48 | run: |
49 | make
50 | - name: Test
51 | run: |
52 | make test
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.lo
4 |
5 | # Libraries
6 | *.lib
7 | *.a
8 | *.la
9 |
10 | # Shared objects (inc. Windows DLLs)
11 | *.dll
12 | *.so
13 | *.so.*
14 | *.dylib
15 |
16 | # Executables
17 | *.exe
18 | *.out
19 | *.app
20 |
21 |
22 | # autotools
23 | .deps
24 | .libs
25 | config.cache
26 | config.guess
27 | config.h
28 | config.h.in
29 | config.h.in~
30 | config.log
31 | config.nice
32 | config.status
33 | config.sub
34 | configure
35 | configure.in
36 | configure.ac
37 | conftest
38 | conftest.c
39 | Makefile
40 | Makefile.fragments
41 | Makefile.global
42 | Makefile.objects
43 | acinclude.m4
44 | aclocal.m4
45 | autom4te.cache
46 | build
47 | install-sh
48 | libtool
49 | ltmain.sh
50 | ltmain.sh.backup
51 | missing
52 | mkinstalldirs
53 | modules
54 | run-tests.php
55 | run-tests.log
56 | tmp-php.ini
57 |
58 | # Archives
59 | yac-*.tgz
60 |
--------------------------------------------------------------------------------
/CREDITS:
--------------------------------------------------------------------------------
1 | yac
2 |
3 | Xinchen Hui
4 | Wei Dai
5 |
--------------------------------------------------------------------------------
/EXPERIMENTAL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laruence/yac/52dad3b2e65ccc3c40565bf22422ee3aad659c17/EXPERIMENTAL
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------
2 | The PHP License, version 3.01
3 | Copyright (c) 1999 - 2011 The PHP Group. All rights reserved.
4 | --------------------------------------------------------------------
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, is permitted provided that the following conditions
8 | are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | 2. Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 |
18 | 3. The name "PHP" must not be used to endorse or promote products
19 | derived from this software without prior written permission. For
20 | written permission, please contact group@php.net.
21 |
22 | 4. Products derived from this software may not be called "PHP", nor
23 | may "PHP" appear in their name, without prior written permission
24 | from group@php.net. You may indicate that your software works in
25 | conjunction with PHP by saying "Foo for PHP" instead of calling
26 | it "PHP Foo" or "phpfoo"
27 |
28 | 5. The PHP Group may publish revised and/or new versions of the
29 | license from time to time. Each version will be given a
30 | distinguishing version number.
31 | Once covered code has been published under a particular version
32 | of the license, you may always continue to use it under the terms
33 | of that version. You may also choose to use such covered code
34 | under the terms of any subsequent version of the license
35 | published by the PHP Group. No one other than the PHP Group has
36 | the right to modify the terms applicable to covered code created
37 | under this License.
38 |
39 | 6. Redistributions of any form whatsoever must retain the following
40 | acknowledgment:
41 | "This product includes PHP software, freely available from
42 | ".
43 |
44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55 | OF THE POSSIBILITY OF SUCH DAMAGE.
56 |
57 | --------------------------------------------------------------------
58 |
59 | This software consists of voluntary contributions made by many
60 | individuals on behalf of the PHP Group.
61 |
62 | The PHP Group can be contacted via Email at group@php.net.
63 |
64 | For more information on the PHP Group and the PHP project,
65 | please see .
66 |
67 | PHP includes the Zend Engine, freely available at
68 | .
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Yac - Yet Another Cache
2 | [](https://ci.appveyor.com/project/laruence/yac/branch/master) [](https://github.com/laruence/yac/actions?query=workflow%3Aintegrate)
3 |
4 | Yac is a shared and lockless memory user data cache for PHP.
5 |
6 | it can be used to replace APC or local memcached.
7 |
8 | ## Requirement
9 |
10 | - PHP 7 +
11 |
12 | ### Install
13 |
14 | ```
15 | $/path/to/phpize
16 | $./configure --with-php-config=/path/to/php-config
17 | $make && make install
18 | ```
19 |
20 | ## Note
21 |
22 | 1. Yac is a lockless cache, you should try to avoid or reduce the probability of multiple processes set one same key
23 | 2. Yac use partial crc, you'd better re-arrange your cache content, place the most important(mutable) bytes at the head or tail
24 |
25 | ## Restrictions
26 |
27 | 1. Cache key cannot be longer than 48 (YAC_MAX_KEY_LEN) bytes
28 | 2. Cache Value cannot be longer than 64M (YAC_MAX_VALUE_RAW_LEN) bytes
29 | 3. Cache Value after compressed cannot be longer than 1M (YAC_MAX_VALUE_COMPRESSED_LEN) bytes
30 |
31 | ## InIs
32 | ````
33 | yac.enable = 1
34 |
35 | yac.keys_memory_size = 4M ; 4M can get 30K key slots, 32M can get 100K key slots
36 |
37 | yac.values_memory_size = 64M
38 |
39 | yac.compress_threshold = -1
40 |
41 | yac.enable_cli = 0 ; whether enable yac with cli, default 0
42 |
43 | yac.serializer = php ; since yac 2.2.0 , specific seralizer yac used
44 | could be json(--enable-json), msgpack(--enable-msgpack) or igbinary(--enable-igbinary)
45 | ````
46 | ## Constants
47 | ````
48 | YAC_VERSION
49 |
50 | YAC_MAX_KEY_LEN = 48 ; if your key is longer than this, maybe you can use md5 result as the key
51 |
52 | YAC_MAX_VALUE_RAW_LEN = 64M
53 |
54 | YAC_MAX_VALUE_COMPRESSED_LEN = 1M
55 |
56 | YAC_SERIALIZER_PHP = 0 ; since yac-2.2.0
57 |
58 | YAC_SERIALIZER_JSON = 1 ; since yac-2.2.0
59 |
60 | YAC_SERIALIZER_MSGPACK = 2 ; since yac-2.2.0
61 |
62 | YAC_SERIALIZER_IGBINARY = 3 ; since yac-2.2.0
63 |
64 | YAC_SERIALIZER ; serializer according to yac.serializer, default is YAC_SERIALIZER_PHP
65 | ````
66 | ## Methods
67 |
68 | ### Yac::\_\_construct
69 |
70 | ```php
71 | Yac::__construct([string $prefix = ""])
72 | ```
73 |
74 | Constructor of Yac, you can specify a prefix which will used to prepend to any keys when doing set/get/delete
75 |
76 | ```php
77 |
80 | ```
81 |
82 | ### Yac::set
83 |
84 | ```php
85 | Yac::set($key, $value[, $ttl = 0])
86 | Yac::set(array $kvs[, $ttl = 0])
87 | ```
88 |
89 | Store a value into Yac cache, keys are cache-unique, so storing a second value with the same key will overwrite the original value.
90 |
91 | Return true on success, return false on error (Like no memory, can not obtain cas write right)
92 | ```php
93 | set("foo", "bar");
96 | $yac->set(
97 | array(
98 | "dummy" => "foo",
99 | "dummy2" => "foo",
100 | )
101 | );
102 | ?>
103 | ```
104 | #### Note:
105 | As Yac 2.1, Store may failure if cas competition fails, you may need to do:
106 | ```php
107 | while (!($yac->set("important", "value")));
108 | ```
109 | if you need the value to be stored properly.
110 |
111 | ### Yac::get
112 |
113 | ```
114 | Yac::get(array|string $key[, &$cas = NULL])
115 | ```
116 |
117 | Fetches a stored variable from the cache. If an array is passed then each element is fetched and returned.
118 |
119 | Return the value on success, return false on error(Like no memory, can not obtain cas write right)
120 | ```php
121 | set("foo", "bar");
124 | $yac->set(
125 | array(
126 | "dummy" => "foo",
127 | "dummy2" => "foo",
128 | )
129 | );
130 | $yac->get("dummy");
131 | $yac->get(array("dummy", "dummy2"));
132 | ?>
133 | ```
134 |
135 | ### Yac::delete
136 |
137 | ```
138 | Yac::delete(array|string $keys[, $delay=0])
139 | ```
140 |
141 | Removes a stored variable from the cache. If delay is specified, then the value will be deleted after \$delay seconds.
142 |
143 | ### Yac::flush
144 |
145 | ```
146 | Yac::flush()
147 | ```
148 |
149 | Immediately invalidates all existing items. it doesn't actually free any resources, it only marks all the items as invalid.
150 |
151 | ### Yac::info
152 |
153 | ```
154 | Yac::info(void)
155 | ```
156 |
157 | Get cache info
158 |
159 | ```php
160 | info());
163 | /* will return an array like:
164 | array(11) {
165 | ["memory_size"]=> int(541065216)
166 | ["slots_memory_size"]=> int(4194304)
167 | ["values_memory_size"]=> int(536870912)
168 | ["segment_size"]=> int(4194304)
169 | ["segment_num"]=> int(128)
170 | ["miss"]=> int(0)
171 | ["hits"]=> int(955)
172 | ["fails"]=> int(0)
173 | ["kicks"]=> int(0)
174 | ["slots_size"]=> int(32768)
175 | ["slots_used"]=> int(955)
176 | }
177 | */
178 | ```
179 |
--------------------------------------------------------------------------------
/compressor/fastlz/LICENSE:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/compressor/fastlz/README.TXT:
--------------------------------------------------------------------------------
1 | FastLZ - lightning-fast lossless compression library
2 |
3 | Author: Ariya Hidayat
4 | Official website: http://fastlz.org
5 |
6 | FastLZ is distributed using the MIT license, see file LICENSE
7 | for details.
8 |
9 | FastLZ consists of two files: fastlz.h and fastlz.c. Just add these
10 | files to your project in order to use FastLZ. For information on
11 | compression and decompression routines, see fastlz.h.
12 |
13 | A simple file compressor called 6pack is included as an example
14 | on how to use FastLZ. The corresponding decompressor is 6unpack.
15 |
16 | To compile using GCC:
17 |
18 | gcc -o 6pack 6pack.c fastlz.c
19 | gcc -o 6unpack 6unpack.c fastlz.c
20 |
21 | To compile using MinGW:
22 |
23 | mingw32-gcc -o 6pack 6pack.c fastlz.c
24 | mingw32-gcc -o 6unpack 6unpack.c fastlz.c
25 |
26 | To compile using Microsoft Visual C++:
27 |
28 | cl 6pack.c fastlz.c
29 | cl 6unpack.c fastlz.c
30 |
31 | To compile using Borland C++:
32 |
33 | bcc32 6pack.c fastlz.c
34 | bcc32 6unpack.c fastlz.c
35 |
36 | To compile using OpenWatcom C/C++:
37 |
38 | cl386 6pack.c fastlz.c
39 | cl386 6unpack.c fastlz.c
40 |
41 | To compile using Intel C++ compiler for Windows:
42 |
43 | icl 6pack.c fastlz.c
44 | icl 6unpack.c fastlz.c
45 |
46 | To compile using Intel C++ compiler for Linux:
47 |
48 | icc -o 6pack 6pack.c fastlz.c
49 | icc -o 6unpack 6unpack.c fastlz.c
50 |
51 | To compile 6pack using LCC-Win32:
52 |
53 | lc 6pack.c fastlz.c
54 | lc 6unpack.c fastlz.c
55 |
56 | To compile 6pack using Pelles C:
57 |
58 | pocc 6pack.c
59 | pocc 6unpack.c
60 | pocc fastlz.c
61 | polink 6pack.obj fastlz.obj
62 | polink 6unpack.obj fastlz.obj
63 |
64 | For speed optimization, always use proper compile flags for optimization options.
65 | Typical compiler flags are given below:
66 |
67 | * GCC (pre 4.2): -march=pentium -O3 -fomit-frame-pointer -mtune=pentium
68 | * GCC 4.2 or later: -march=pentium -O3 -fomit-frame-pointer -mtune=generic
69 | * Digital Mars C/C++: -o+all -5
70 | * Intel C++ (Windows): /O3 /Qipo
71 | * Intel C++ (Linux): -O2 -march=pentium -mtune=pentium
72 | * Borland C++: -O2 -5
73 | * LCC-Win32: -O
74 | * Pelles C: /O2
75 |
76 |
--------------------------------------------------------------------------------
/compressor/fastlz/fastlz.c:
--------------------------------------------------------------------------------
1 | /*
2 | FastLZ - lightning-fast lossless compression library
3 |
4 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
5 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
6 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 | */
26 |
27 | #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
28 |
29 | /*
30 | * Always check for bound when decompressing.
31 | * Generally it is best to leave it defined.
32 | */
33 | #define FASTLZ_SAFE
34 |
35 | /*
36 | * Give hints to the compiler for branch prediction optimization.
37 | */
38 | #if defined(__GNUC__) && (__GNUC__ > 2)
39 | #define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
40 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
41 | #else
42 | #define FASTLZ_EXPECT_CONDITIONAL(c) (c)
43 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
44 | #endif
45 |
46 | /*
47 | * Use inlined functions for supported systems.
48 | */
49 | #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
50 | #define FASTLZ_INLINE inline
51 | #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
52 | #define FASTLZ_INLINE __inline
53 | #else
54 | #define FASTLZ_INLINE
55 | #endif
56 |
57 | /*
58 | * Prevent accessing more than 8-bit at once, except on x86 architectures.
59 | */
60 | #if !defined(FASTLZ_STRICT_ALIGN)
61 | #define FASTLZ_STRICT_ALIGN
62 | #if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
63 | #undef FASTLZ_STRICT_ALIGN
64 | #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
65 | #undef FASTLZ_STRICT_ALIGN
66 | #elif defined(_M_IX86) /* Intel, MSVC */
67 | #undef FASTLZ_STRICT_ALIGN
68 | #elif defined(__386)
69 | #undef FASTLZ_STRICT_ALIGN
70 | #elif defined(_X86_) /* MinGW */
71 | #undef FASTLZ_STRICT_ALIGN
72 | #elif defined(__I86__) /* Digital Mars */
73 | #undef FASTLZ_STRICT_ALIGN
74 | #endif
75 | #endif
76 |
77 | /*
78 | * FIXME: use preprocessor magic to set this on different platforms!
79 | */
80 | typedef unsigned char flzuint8;
81 | typedef unsigned short flzuint16;
82 | typedef unsigned int flzuint32;
83 |
84 | /* prototypes */
85 | int fastlz_compress(const void* input, int length, void* output);
86 | int fastlz_compress_level(int level, const void* input, int length, void* output);
87 | int fastlz_decompress(const void* input, int length, void* output, int maxout);
88 |
89 | #define MAX_COPY 32
90 | #define MAX_LEN 264 /* 256 + 8 */
91 | #define MAX_DISTANCE 8192
92 |
93 | #if !defined(FASTLZ_STRICT_ALIGN)
94 | #define FASTLZ_READU16(p) *((const flzuint16*)(p))
95 | #else
96 | #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
97 | #endif
98 |
99 | #define HASH_LOG 13
100 | #define HASH_SIZE (1<< HASH_LOG)
101 | #define HASH_MASK (HASH_SIZE-1)
102 | #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
103 |
104 | #undef FASTLZ_LEVEL
105 | #define FASTLZ_LEVEL 1
106 |
107 | #undef FASTLZ_COMPRESSOR
108 | #undef FASTLZ_DECOMPRESSOR
109 | #define FASTLZ_COMPRESSOR fastlz1_compress
110 | #define FASTLZ_DECOMPRESSOR fastlz1_decompress
111 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
112 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
113 | #include "fastlz.c"
114 |
115 | #undef FASTLZ_LEVEL
116 | #define FASTLZ_LEVEL 2
117 |
118 | #undef MAX_DISTANCE
119 | #define MAX_DISTANCE 8191
120 | #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
121 |
122 | #undef FASTLZ_COMPRESSOR
123 | #undef FASTLZ_DECOMPRESSOR
124 | #define FASTLZ_COMPRESSOR fastlz2_compress
125 | #define FASTLZ_DECOMPRESSOR fastlz2_decompress
126 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
127 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
128 | #include "fastlz.c"
129 |
130 | int fastlz_compress(const void* input, int length, void* output)
131 | {
132 | /* for short block, choose fastlz1 */
133 | if(length < 65536)
134 | return fastlz1_compress(input, length, output);
135 |
136 | /* else... */
137 | return fastlz2_compress(input, length, output);
138 | }
139 |
140 | int fastlz_decompress(const void* input, int length, void* output, int maxout)
141 | {
142 | /* magic identifier for compression level */
143 | int level = ((*(const flzuint8*)input) >> 5) + 1;
144 |
145 | if(level == 1)
146 | return fastlz1_decompress(input, length, output, maxout);
147 | if(level == 2)
148 | return fastlz2_decompress(input, length, output, maxout);
149 |
150 | /* unknown level, trigger error */
151 | return 0;
152 | }
153 |
154 | int fastlz_compress_level(int level, const void* input, int length, void* output)
155 | {
156 | if(level == 1)
157 | return fastlz1_compress(input, length, output);
158 | if(level == 2)
159 | return fastlz2_compress(input, length, output);
160 |
161 | return 0;
162 | }
163 |
164 | #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
165 |
166 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
167 | {
168 | const flzuint8* ip = (const flzuint8*) input;
169 | const flzuint8* ip_bound = ip + length - 2;
170 | const flzuint8* ip_limit = ip + length - 12;
171 | flzuint8* op = (flzuint8*) output;
172 |
173 | const flzuint8* htab[HASH_SIZE];
174 | const flzuint8** hslot;
175 | flzuint32 hval;
176 |
177 | flzuint32 copy;
178 |
179 | /* sanity check */
180 | if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
181 | {
182 | if(length)
183 | {
184 | /* create literal copy only */
185 | *op++ = length-1;
186 | ip_bound++;
187 | while(ip <= ip_bound)
188 | *op++ = *ip++;
189 | return length+1;
190 | }
191 | else
192 | return 0;
193 | }
194 |
195 | /* initializes hash table */
196 | for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
197 | *hslot = ip;
198 |
199 | /* we start with literal copy */
200 | copy = 2;
201 | *op++ = MAX_COPY-1;
202 | *op++ = *ip++;
203 | *op++ = *ip++;
204 |
205 | /* main loop */
206 | while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
207 | {
208 | const flzuint8* ref;
209 | flzuint32 distance;
210 |
211 | /* minimum match length */
212 | flzuint32 len = 3;
213 |
214 | /* comparison starting-point */
215 | const flzuint8* anchor = ip;
216 |
217 | /* check for a run */
218 | #if FASTLZ_LEVEL==2
219 | if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
220 | {
221 | distance = 1;
222 | ip += 3;
223 | ref = anchor - 1 + 3;
224 | goto match;
225 | }
226 | #endif
227 |
228 | /* find potential match */
229 | HASH_FUNCTION(hval,ip);
230 | hslot = htab + hval;
231 | ref = htab[hval];
232 |
233 | /* calculate distance to the match */
234 | distance = anchor - ref;
235 |
236 | /* update hash table */
237 | *hslot = anchor;
238 |
239 | /* is this a match? check the first 3 bytes */
240 | if(distance==0 ||
241 | #if FASTLZ_LEVEL==1
242 | (distance >= MAX_DISTANCE) ||
243 | #else
244 | (distance >= MAX_FARDISTANCE) ||
245 | #endif
246 | *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
247 | goto literal;
248 |
249 | #if FASTLZ_LEVEL==2
250 | /* far, needs at least 5-byte match */
251 | if(distance >= MAX_DISTANCE)
252 | {
253 | if(*ip++ != *ref++ || *ip++!= *ref++)
254 | goto literal;
255 | len += 2;
256 | }
257 |
258 | match:
259 | #endif
260 |
261 | /* last matched byte */
262 | ip = anchor + len;
263 |
264 | /* distance is biased */
265 | distance--;
266 |
267 | if(!distance)
268 | {
269 | /* zero distance means a run */
270 | flzuint8 x = ip[-1];
271 | while(ip < ip_bound)
272 | if(*ref++ != x) break; else ip++;
273 | }
274 | else
275 | for(;;)
276 | {
277 | /* safe because the outer check against ip limit */
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 | if(*ref++ != *ip++) break;
286 | while(ip < ip_bound)
287 | if(*ref++ != *ip++) break;
288 | break;
289 | }
290 |
291 | /* if we have copied something, adjust the copy count */
292 | if(copy)
293 | /* copy is biased, '0' means 1 byte copy */
294 | *(op-copy-1) = copy-1;
295 | else
296 | /* back, to overwrite the copy count */
297 | op--;
298 |
299 | /* reset literal counter */
300 | copy = 0;
301 |
302 | /* length is biased, '1' means a match of 3 bytes */
303 | ip -= 3;
304 | len = ip - anchor;
305 |
306 | /* encode the match */
307 | #if FASTLZ_LEVEL==2
308 | if(distance < MAX_DISTANCE)
309 | {
310 | if(len < 7)
311 | {
312 | *op++ = (len << 5) + (distance >> 8);
313 | *op++ = (distance & 255);
314 | }
315 | else
316 | {
317 | *op++ = (7 << 5) + (distance >> 8);
318 | for(len-=7; len >= 255; len-= 255)
319 | *op++ = 255;
320 | *op++ = len;
321 | *op++ = (distance & 255);
322 | }
323 | }
324 | else
325 | {
326 | /* far away, but not yet in the another galaxy... */
327 | if(len < 7)
328 | {
329 | distance -= MAX_DISTANCE;
330 | *op++ = (len << 5) + 31;
331 | *op++ = 255;
332 | *op++ = distance >> 8;
333 | *op++ = distance & 255;
334 | }
335 | else
336 | {
337 | distance -= MAX_DISTANCE;
338 | *op++ = (7 << 5) + 31;
339 | for(len-=7; len >= 255; len-= 255)
340 | *op++ = 255;
341 | *op++ = len;
342 | *op++ = 255;
343 | *op++ = distance >> 8;
344 | *op++ = distance & 255;
345 | }
346 | }
347 | #else
348 |
349 | if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
350 | while(len > MAX_LEN-2)
351 | {
352 | *op++ = (7 << 5) + (distance >> 8);
353 | *op++ = MAX_LEN - 2 - 7 -2;
354 | *op++ = (distance & 255);
355 | len -= MAX_LEN-2;
356 | }
357 |
358 | if(len < 7)
359 | {
360 | *op++ = (len << 5) + (distance >> 8);
361 | *op++ = (distance & 255);
362 | }
363 | else
364 | {
365 | *op++ = (7 << 5) + (distance >> 8);
366 | *op++ = len - 7;
367 | *op++ = (distance & 255);
368 | }
369 | #endif
370 |
371 | /* update the hash at match boundary */
372 | HASH_FUNCTION(hval,ip);
373 | htab[hval] = ip++;
374 | HASH_FUNCTION(hval,ip);
375 | htab[hval] = ip++;
376 |
377 | /* assuming literal copy */
378 | *op++ = MAX_COPY-1;
379 |
380 | continue;
381 |
382 | literal:
383 | *op++ = *anchor++;
384 | ip = anchor;
385 | copy++;
386 | if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
387 | {
388 | copy = 0;
389 | *op++ = MAX_COPY-1;
390 | }
391 | }
392 |
393 | /* left-over as literal copy */
394 | ip_bound++;
395 | while(ip <= ip_bound)
396 | {
397 | *op++ = *ip++;
398 | copy++;
399 | if(copy == MAX_COPY)
400 | {
401 | copy = 0;
402 | *op++ = MAX_COPY-1;
403 | }
404 | }
405 |
406 | /* if we have copied something, adjust the copy length */
407 | if(copy)
408 | *(op-copy-1) = copy-1;
409 | else
410 | op--;
411 |
412 | #if FASTLZ_LEVEL==2
413 | /* marker for fastlz2 */
414 | *(flzuint8*)output |= (1 << 5);
415 | #endif
416 |
417 | return op - (flzuint8*)output;
418 | }
419 |
420 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
421 | {
422 | const flzuint8* ip = (const flzuint8*) input;
423 | const flzuint8* ip_limit = ip + length;
424 | flzuint8* op = (flzuint8*) output;
425 | flzuint8* op_limit = op + maxout;
426 | flzuint32 ctrl = (*ip++) & 31;
427 | int loop = 1;
428 |
429 | do
430 | {
431 | const flzuint8* ref = op;
432 | flzuint32 len = ctrl >> 5;
433 | flzuint32 ofs = (ctrl & 31) << 8;
434 |
435 | if(ctrl >= 32)
436 | {
437 | #if FASTLZ_LEVEL==2
438 | flzuint8 code;
439 | #endif
440 | len--;
441 | ref -= ofs;
442 | if (len == 7-1)
443 | #if FASTLZ_LEVEL==1
444 | len += *ip++;
445 | ref -= *ip++;
446 | #else
447 | do
448 | {
449 | code = *ip++;
450 | len += code;
451 | } while (code==255);
452 | code = *ip++;
453 | ref -= code;
454 |
455 | /* match from 16-bit distance */
456 | if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
457 | if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
458 | {
459 | ofs = (*ip++) << 8;
460 | ofs += *ip++;
461 | ref = op - ofs - MAX_DISTANCE;
462 | }
463 | #endif
464 |
465 | #ifdef FASTLZ_SAFE
466 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
467 | return 0;
468 |
469 | if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
470 | return 0;
471 | #endif
472 |
473 | if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
474 | ctrl = *ip++;
475 | else
476 | loop = 0;
477 |
478 | if(ref == op)
479 | {
480 | /* optimize copy for a run */
481 | flzuint8 b = ref[-1];
482 | *op++ = b;
483 | *op++ = b;
484 | *op++ = b;
485 | for(; len; --len)
486 | *op++ = b;
487 | }
488 | else
489 | {
490 | #if !defined(FASTLZ_STRICT_ALIGN)
491 | const flzuint16* p;
492 | flzuint16* q;
493 | #endif
494 | /* copy from reference */
495 | ref--;
496 | *op++ = *ref++;
497 | *op++ = *ref++;
498 | *op++ = *ref++;
499 |
500 | #if !defined(FASTLZ_STRICT_ALIGN)
501 | /* copy a byte, so that now it's word aligned */
502 | if(len & 1)
503 | {
504 | *op++ = *ref++;
505 | len--;
506 | }
507 |
508 | /* copy 16-bit at once */
509 | q = (flzuint16*) op;
510 | op += len;
511 | p = (const flzuint16*) ref;
512 | for(len>>=1; len > 4; len-=4)
513 | {
514 | *q++ = *p++;
515 | *q++ = *p++;
516 | *q++ = *p++;
517 | *q++ = *p++;
518 | }
519 | for(; len; --len)
520 | *q++ = *p++;
521 | #else
522 | for(; len; --len)
523 | *op++ = *ref++;
524 | #endif
525 | }
526 | }
527 | else
528 | {
529 | ctrl++;
530 | #ifdef FASTLZ_SAFE
531 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
532 | return 0;
533 | if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
534 | return 0;
535 | #endif
536 |
537 | *op++ = *ip++;
538 | for(--ctrl; ctrl; ctrl--)
539 | *op++ = *ip++;
540 |
541 | loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
542 | if(loop)
543 | ctrl = *ip++;
544 | }
545 | }
546 | while(FASTLZ_EXPECT_CONDITIONAL(loop));
547 |
548 | return op - (flzuint8*)output;
549 | }
550 |
551 | #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
552 |
--------------------------------------------------------------------------------
/compressor/fastlz/fastlz.h:
--------------------------------------------------------------------------------
1 | /*
2 | FastLZ - lightning-fast lossless compression library
3 |
4 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
5 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
6 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 | */
26 |
27 | #ifndef FASTLZ_H
28 | #define FASTLZ_H
29 |
30 | #define FASTLZ_VERSION 0x000100
31 |
32 | #define FASTLZ_VERSION_MAJOR 0
33 | #define FASTLZ_VERSION_MINOR 0
34 | #define FASTLZ_VERSION_REVISION 0
35 |
36 | #define FASTLZ_VERSION_STRING "0.1.0"
37 |
38 | #if defined (__cplusplus)
39 | extern "C" {
40 | #endif
41 |
42 | /**
43 | Compress a block of data in the input buffer and returns the size of
44 | compressed block. The size of input buffer is specified by length. The
45 | minimum input buffer size is 16.
46 |
47 | The output buffer must be at least 5% larger than the input buffer
48 | and can not be smaller than 66 bytes.
49 |
50 | If the input is not compressible, the return value might be larger than
51 | length (input buffer size).
52 |
53 | The input buffer and the output buffer can not overlap.
54 | */
55 |
56 | int fastlz_compress(const void* input, int length, void* output);
57 |
58 | /**
59 | Decompress a block of compressed data and returns the size of the
60 | decompressed block. If error occurs, e.g. the compressed data is
61 | corrupted or the output buffer is not large enough, then 0 (zero)
62 | will be returned instead.
63 |
64 | The input buffer and the output buffer can not overlap.
65 |
66 | Decompression is memory safe and guaranteed not to write the output buffer
67 | more than what is specified in maxout.
68 | */
69 |
70 | int fastlz_decompress(const void* input, int length, void* output, int maxout);
71 |
72 | /**
73 | Compress a block of data in the input buffer and returns the size of
74 | compressed block. The size of input buffer is specified by length. The
75 | minimum input buffer size is 16.
76 |
77 | The output buffer must be at least 5% larger than the input buffer
78 | and can not be smaller than 66 bytes.
79 |
80 | If the input is not compressible, the return value might be larger than
81 | length (input buffer size).
82 |
83 | The input buffer and the output buffer can not overlap.
84 |
85 | Compression level can be specified in parameter level. At the moment,
86 | only level 1 and level 2 are supported.
87 | Level 1 is the fastest compression and generally useful for short data.
88 | Level 2 is slightly slower but it gives better compression ratio.
89 |
90 | Note that the compressed data, regardless of the level, can always be
91 | decompressed using the function fastlz_decompress above.
92 | */
93 |
94 | int fastlz_compress_level(int level, const void* input, int length, void* output);
95 |
96 | #if defined (__cplusplus)
97 | }
98 | #endif
99 |
100 | #endif /* FASTLZ_H */
101 |
--------------------------------------------------------------------------------
/config.m4:
--------------------------------------------------------------------------------
1 | dnl $Id$
2 | dnl config.m4 for extension yac
3 |
4 | PHP_ARG_ENABLE(yac, whether to enable yac support,
5 | [ --enable-yac Enable yac support])
6 |
7 | PHP_ARG_WITH(system-fastlz, whether to use system FastLZ library,
8 | [ --with-system-fastlz Use system FastLZ library], no, no)
9 |
10 | PHP_ARG_ENABLE(json, whether to use igbinary as serializer,
11 | [ --enable-json Use igbinary as serializer], no, no)
12 |
13 | PHP_ARG_ENABLE(msgpack, whether to use msgpack as serializer,
14 | [ --enable-msgpack Use Messagepack as serializer], no, no)
15 |
16 | PHP_ARG_ENABLE(igbinary, whether to use igbinary as serializer,
17 | [ --enable-igbinary Use igbinary as serializer], no, no)
18 |
19 | dnl copied from Zend Optimizer Plus
20 | AC_MSG_CHECKING(for sysvipc shared memory support)
21 | AC_TRY_RUN([
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | int main() {
30 | pid_t pid;
31 | int status;
32 | int ipc_id;
33 | char *shm;
34 | struct shmid_ds shmbuf;
35 |
36 | ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W));
37 | if (ipc_id == -1) {
38 | return 1;
39 | }
40 |
41 | shm = shmat(ipc_id, NULL, 0);
42 | if (shm == (void *)-1) {
43 | shmctl(ipc_id, IPC_RMID, NULL);
44 | return 2;
45 | }
46 |
47 | if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) {
48 | shmdt(shm);
49 | shmctl(ipc_id, IPC_RMID, NULL);
50 | return 3;
51 | }
52 |
53 | shmbuf.shm_perm.uid = getuid();
54 | shmbuf.shm_perm.gid = getgid();
55 | shmbuf.shm_perm.mode = 0600;
56 |
57 | if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) {
58 | shmdt(shm);
59 | shmctl(ipc_id, IPC_RMID, NULL);
60 | return 4;
61 | }
62 |
63 | shmctl(ipc_id, IPC_RMID, NULL);
64 |
65 | strcpy(shm, "hello");
66 |
67 | pid = fork();
68 | if (pid < 0) {
69 | return 5;
70 | } else if (pid == 0) {
71 | strcpy(shm, "bye");
72 | return 6;
73 | }
74 | if (wait(&status) != pid) {
75 | return 7;
76 | }
77 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
78 | return 8;
79 | }
80 | if (strcmp(shm, "bye") != 0) {
81 | return 9;
82 | }
83 | return 0;
84 | }
85 | ],dnl
86 | AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support])
87 | msg=yes,msg=no,msg=no)
88 | AC_MSG_RESULT([$msg])
89 |
90 | AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support)
91 | AC_TRY_RUN([
92 | #include
93 | #include
94 | #include
95 | #include
96 | #include
97 |
98 | #ifndef MAP_ANON
99 | # ifdef MAP_ANONYMOUS
100 | # define MAP_ANON MAP_ANONYMOUS
101 | # endif
102 | #endif
103 | #ifndef MAP_FAILED
104 | # define MAP_FAILED ((void*)-1)
105 | #endif
106 |
107 | int main() {
108 | pid_t pid;
109 | int status;
110 | char *shm;
111 |
112 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
113 | if (shm == MAP_FAILED) {
114 | return 1;
115 | }
116 |
117 | strcpy(shm, "hello");
118 |
119 | pid = fork();
120 | if (pid < 0) {
121 | return 5;
122 | } else if (pid == 0) {
123 | strcpy(shm, "bye");
124 | return 6;
125 | }
126 | if (wait(&status) != pid) {
127 | return 7;
128 | }
129 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
130 | return 8;
131 | }
132 | if (strcmp(shm, "bye") != 0) {
133 | return 9;
134 | }
135 | return 0;
136 | }
137 | ],dnl
138 | AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support])
139 | msg=yes,msg=no,msg=no)
140 | AC_MSG_RESULT([$msg])
141 |
142 | AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support)
143 | AC_TRY_RUN([
144 | #include
145 | #include
146 | #include
147 | #include
148 | #include
149 | #include
150 | #include
151 |
152 | #ifndef MAP_FAILED
153 | # define MAP_FAILED ((void*)-1)
154 | #endif
155 |
156 | int main() {
157 | pid_t pid;
158 | int status;
159 | int fd;
160 | char *shm;
161 |
162 | fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
163 | if (fd == -1) {
164 | return 1;
165 | }
166 |
167 | shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
168 | if (shm == MAP_FAILED) {
169 | return 2;
170 | }
171 |
172 | strcpy(shm, "hello");
173 |
174 | pid = fork();
175 | if (pid < 0) {
176 | return 5;
177 | } else if (pid == 0) {
178 | strcpy(shm, "bye");
179 | return 6;
180 | }
181 | if (wait(&status) != pid) {
182 | return 7;
183 | }
184 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
185 | return 8;
186 | }
187 | if (strcmp(shm, "bye") != 0) {
188 | return 9;
189 | }
190 | return 0;
191 | }
192 | ],dnl
193 | AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support])
194 | msg=yes,msg=no,msg=no)
195 | AC_MSG_RESULT([$msg])
196 |
197 | if test "$PHP_MSGPACK" != "no"; then
198 | AC_DEFINE(YAC_ENABLE_MSGPACK, 1, [enable msgpack packager])
199 | ifdef([PHP_ADD_EXTENSION_DEP],
200 | [
201 | PHP_ADD_EXTENSION_DEP(yac, msgpack, true)
202 | ])
203 | fi
204 |
205 | if test "$PHP_IGBINARY" != "no"; then
206 | AC_DEFINE(YAC_ENABLE_IGBINARY, 1, [enable igbinary packager])
207 | ifdef([PHP_ADD_EXTENSION_DEP],
208 | [
209 | PHP_ADD_EXTENSION_DEP(yac, igbinary, true)
210 | ])
211 | fi
212 |
213 | if test "$PHP_JSON" != "no"; then
214 | AC_DEFINE(YAC_ENABLE_JSON, 1, [enable json packager])
215 | ifdef([PHP_ADD_EXTENSION_DEP],
216 | [
217 | PHP_ADD_EXTENSION_DEP(yac, json, true)
218 | ])
219 | fi
220 |
221 | ifdef([PHP_CHECK_CPU_SUPPORTS],
222 | [
223 | if test -x "$PHP_CONFIG"; then
224 | php_vernum=`$PHP_CONFIG --vernum`
225 | if test $php_vernum -ge 70300; then
226 | AC_CHECK_HEADERS([nmmintrin.h])
227 | PHP_CHECK_CPU_SUPPORTS([sse4.2])
228 | dnl Tricky way to remove unintentionally defines
229 | if test -e "confdefs.h"; then
230 | sed -i "/PHP_HAVE_/d" confdefs.h
231 | fi
232 | AC_MSG_CHECKING([for crc32 instruction supports])
233 | if test $have_ext_instructions -eq 1; then
234 | AC_DEFINE([HAVE_SSE_CRC32], 1, [define if you have sse4.2 crc32 instruction support])
235 | CFLAGS="$CFLAGS -msse4.2"
236 | AC_MSG_RESULT([yes])
237 | else
238 | AC_MSG_RESULT([no])
239 | fi
240 | fi
241 | fi
242 | ], [])
243 |
244 | AC_DEFUN([YAC_BUILTIN_ATOMIC],
245 | [
246 | AC_MSG_CHECKING([for __sync_bool_compare_and_swap supports])
247 | AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
248 | int variable = 1;
249 | return (__sync_bool_compare_and_swap(&variable, 1, 2)
250 | && __sync_add_and_fetch(&variable, 1)) ? 1 : 0;
251 | ]])], [
252 | AC_MSG_RESULT([yes])
253 | AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o.])
254 | ], [
255 | AC_MSG_RESULT([no])
256 | ])
257 | ])
258 |
259 | YAC_BUILTIN_ATOMIC
260 |
261 | YAC_FILES="yac.c storage/yac_storage.c storage/allocator/yac_allocator.c storage/allocator/allocators/shm.c storage/allocator/allocators/mmap.c serializer/php.c serializer/msgpack.c serializer/igbinary.c serializer/json.c"
262 | if test "$PHP_SYSTEM_FASTLZ" != "no"; then
263 | AC_CHECK_HEADERS([fastlz.h])
264 | PHP_CHECK_LIBRARY(fastlz, fastlz_compress,
265 | [PHP_ADD_LIBRARY(fastlz, 1, YAC_SHARED_LIBADD)],
266 | [AC_MSG_ERROR(FastLZ library not found)])
267 | else
268 | YAC_FILES="${YAC_FILES} compressor/fastlz/fastlz.c"
269 | fi
270 |
271 | if test "$PHP_YAC" != "no"; then
272 | PHP_SUBST(YAC_SHARED_LIBADD)
273 | PHP_NEW_EXTENSION(yac, ${YAC_FILES}, $ext_shared)
274 | PHP_ADD_BUILD_DIR([$ext_builddir/storage])
275 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator])
276 | PHP_ADD_BUILD_DIR([$ext_builddir/storage/allocator/allocators])
277 | PHP_ADD_BUILD_DIR([$ext_builddir/serializer])
278 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor])
279 | PHP_ADD_BUILD_DIR([$ext_builddir/compressor/fastlz])
280 | fi
281 |
--------------------------------------------------------------------------------
/config.w32:
--------------------------------------------------------------------------------
1 | // $Id$
2 | // vim:ft=javascript
3 |
4 | ARG_ENABLE("yac", "enable yac support", "no");
5 |
6 | if (PHP_YAC != "no") {
7 | if( CHECK_HEADER_ADD_INCLUDE("fastlz.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\compressor\\fastlz") &&
8 | CHECK_HEADER_ADD_INCLUDE("yac_serializer.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\serializer") &&
9 | CHECK_HEADER_ADD_INCLUDE("yac_storage.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage") &&
10 | CHECK_HEADER_ADD_INCLUDE("yac_allocator.h", "CFLAGS_YAC", PHP_YAC + ";" + configure_module_dirname + "\\storage\\allocator")) {
11 |
12 | EXTENSION("yac", "yac.c");
13 |
14 | ADD_SOURCES(configure_module_dirname + "\\compressor\\fastlz", "fastlz.c", "yac");
15 | ADD_SOURCES(configure_module_dirname + "\\serializer", "php.c", "yac");
16 | ADD_SOURCES(configure_module_dirname + "\\storage", "yac_storage.c", "yac");
17 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator", "yac_allocator.c", "yac");
18 | ADD_SOURCES(configure_module_dirname + "\\storage\\allocator\\allocators", "createfilemapping.c", "yac");
19 |
20 | AC_DEFINE('HAVE_YAC', 1, 'Have yac library');
21 |
22 | ADD_FLAG("CFLAGS_YAC", ' /I "' + configure_module_dirname + '" ');
23 |
24 | } else {
25 | WARNING("yac not enabled, headers not found");
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | yac
4 | pecl.php.net
5 | lockless user data cache
6 |
7 | yac is a fast, lock-free, shared memory user data cache for PHP. it can be used to replace APC or local memcached.
8 |
9 |
10 | Xinchen Hui
11 | laruence
12 | laruence@php.net
13 | yes
14 |
15 | 2021-12-18
16 |
17 |
18 | 2.3.1
19 | 2.3.1
20 |
21 |
22 | stable
23 | stable
24 |
25 | PHP
26 |
27 | - PHP8.1 Supports
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | 7.0.0
100 |
101 |
102 | 1.4.0
103 |
104 |
105 |
106 | yac
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | 2021-12-18
115 |
116 | 2.3.1
117 | 2.3.1
118 |
119 |
120 | stable
121 | stable
122 |
123 | PHP License
124 |
125 | - PHP8.1 Supports
126 |
127 |
128 |
129 |
130 | 2021-01-06
131 |
132 | 2.3.0
133 | 2.3.0
134 |
135 |
136 | stable
137 | stable
138 |
139 | PHP License
140 |
141 | - PHP8 Supported
142 |
143 |
144 |
145 | 2020-03-31
146 |
147 | 2.2.1
148 | 2.2.1
149 |
150 |
151 | stable
152 | stable
153 |
154 | PHP License
155 |
156 | - Refactor key manipulation, avoding memory allocation
157 | - Refactor Yac::__set/__get by using native objects_handler
158 |
159 |
160 |
161 | 2020-03-31
162 |
163 | 2.2.0
164 | 2.2.0
165 |
166 |
167 | stable
168 | stable
169 |
170 | PHP License
171 |
172 | - Added json serializer
173 | - Added igbinary serializer
174 | - change yac.serilalizer to string, "php", "json" etc
175 |
176 |
177 |
178 | 2020-03-27
179 |
180 | 2.1.2
181 | 2.1.2
182 |
183 |
184 | stable
185 | stable
186 |
187 | PHP License
188 |
189 | - Fixed compiler warning of redefinition of macros
190 | - Fixed crc32c only pick the first byte
191 | - Also use crc32_u32 in 64 bits
192 |
193 |
194 |
195 | 2020-03-25
196 |
197 | 2.1.1
198 | 2.1.1
199 |
200 |
201 | stable
202 | stable
203 |
204 | PHP License
205 |
206 | - Fixed Build in 32bits
207 |
208 |
209 |
210 | 2020-03-25
211 |
212 | 2.1.0
213 | 2.1.0
214 |
215 |
216 | stable
217 | stable
218 |
219 | PHP License
220 |
221 | - Implemnented CAS based lock-free protection
222 | - Use SSE4.2 _mm_crc32 instead of normal crc32 to make speedup
223 | - Some optimization to avoding memory usage
224 |
225 |
226 |
227 | 2020-03-19
228 |
229 | 2.0.4
230 | 2.0.4
231 |
232 |
233 | beta
234 | beta
235 |
236 | PHP License
237 |
238 | - Fixed PHP-7.4 windows build
239 |
240 |
241 |
242 | 2020-01-06
243 |
244 | 2.0.3
245 | 2.0.3
246 |
247 |
248 | beta
249 | beta
250 |
251 | PHP License
252 |
253 | - Fixed PHP-7.4 Compatiblity
254 |
255 |
256 |
257 | 2017-07-27
258 |
259 | 2.0.2
260 | 2.0.2
261 |
262 |
263 | beta
264 | beta
265 |
266 | PHP License
267 |
268 | - Fixed PHP-7.2 Compatiblity
269 |
270 |
271 |
272 | 2016-07-02
273 |
274 | 2.0.1
275 | 2.0.1
276 |
277 |
278 | beta
279 | beta
280 |
281 | PHP License
282 |
283 | - Fixed issue #63 (include smart_str.h)
284 |
285 |
286 |
287 | 2015-10-27
288 |
289 | 2.0.0
290 | 2.0.0
291 |
292 |
293 | beta
294 | beta
295 |
296 | PHP License
297 |
298 | - Release yac for PHP7
299 |
300 |
301 |
302 | 2014-10-22
303 |
304 | 0.9.2
305 | 0.9.2
306 |
307 |
308 | beta
309 | beta
310 |
311 | PHP License
312 |
313 | - Add --with-system-fastlz option
314 |
315 |
316 |
317 | 2014-07-25
318 |
319 | 0.9.1
320 | 0.9.1
321 |
322 |
323 | beta
324 | beta
325 |
326 | PHP License
327 |
328 | - Try to fix windows build
329 |
330 |
331 |
332 | 2014-07-24
333 |
334 | 0.9.0
335 | 0.9.0
336 |
337 |
338 | beta
339 | beta
340 |
341 | PHP License
342 |
343 | - first release
344 |
345 |
346 |
347 |
348 |
351 |
--------------------------------------------------------------------------------
/php_yac.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifndef PHP_YAC_H
22 | #define PHP_YAC_H
23 |
24 | extern zend_module_entry yac_module_entry;
25 | #define phpext_yac_ptr &yac_module_entry
26 |
27 | #ifdef PHP_WIN32
28 | #define PHP_YAC_API __declspec(dllexport)
29 | #else
30 | #define PHP_YAC_API
31 | #endif
32 |
33 | #ifdef ZTS
34 | #include "TSRM.h"
35 | #endif
36 |
37 | #define PHP_YAC_VERSION "2.3.2-dev"
38 |
39 | #if PHP_VERSION_ID < 70400
40 | #define YAC_WHANDLER void
41 | #define YAC_WHANDLER_RET(zv) return
42 | #else
43 | #define YAC_WHANDLER zval *
44 | #define YAC_WHANDLER_RET(zv) return zv
45 | #endif
46 |
47 | #define YAC_CLASS_PROPERTY_PREFIX "_prefix"
48 | #define YAC_ENTRY_COMPRESSED 0x0020
49 | #define YAC_ENTRY_TYPE_MASK 0x1f
50 | #define YAC_ENTRY_ORIG_LEN_SHIT 6
51 | #define YAC_ENTRY_MAX_ORIG_LEN ((1U << ((sizeof(int)*8 - YAC_ENTRY_ORIG_LEN_SHIT))) - 1)
52 | #define YAC_MIN_COMPRESS_THRESHOLD 1024
53 |
54 | #define YAC_SERIALIZER_PHP 0
55 | #define YAC_SERIALIZER_JSON 1
56 | #define YAC_SERIALIZER_MSGPACK 2
57 | #define YAC_SERIALIZER_IGBINARY 3
58 |
59 | ZEND_BEGIN_MODULE_GLOBALS(yac)
60 | zend_bool enable;
61 | zend_bool debug;
62 | size_t k_msize;
63 | size_t v_msize;
64 | zend_ulong compress_threshold;
65 | zend_bool enable_cli;
66 | char *serializer;
67 | #ifdef PHP_WIN32
68 | char *mmap_base;
69 | #endif
70 | ZEND_END_MODULE_GLOBALS(yac)
71 |
72 | PHP_MINIT_FUNCTION(yac);
73 | PHP_MSHUTDOWN_FUNCTION(yac);
74 | PHP_RINIT_FUNCTION(yac);
75 | PHP_RSHUTDOWN_FUNCTION(yac);
76 | PHP_MINFO_FUNCTION(yac);
77 |
78 | ZEND_EXTERN_MODULE_GLOBALS(yac);
79 | #define YAC_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(yac, v)
80 |
81 | #endif /* PHP_YAC_H */
82 | /*
83 | * Local variables:
84 | * tab-width: 4
85 | * c-basic-offset: 4
86 | * End:
87 | * vim600: noet sw=4 ts=4 fdm=marker
88 | * vim<600: noet sw=4 ts=4
89 | */
90 |
--------------------------------------------------------------------------------
/serializer/igbinary.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | | Remi Collet |
17 | +----------------------------------------------------------------------+
18 | */
19 |
20 | #ifdef HAVE_CONFIG_H
21 | #include "config.h"
22 | #endif
23 |
24 | #ifdef YAC_ENABLE_IGBINARY
25 |
26 | #include "php.h"
27 | #include "ext/igbinary/igbinary.h"
28 | #include "zend_smart_str.h" /* for smart_str */
29 |
30 | #include "yac_serializer.h"
31 |
32 | int yac_serializer_igbinary_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ {
33 | uint8_t *ret;
34 | size_t ret_len;
35 |
36 | if (igbinary_serialize(&ret, &ret_len, pzval) == 0) {
37 | smart_str_appendl(buf, (const char *)ret, ret_len);
38 | efree(ret);
39 | return 1;
40 | }
41 | return 0;
42 | } /* }}} */
43 |
44 | zval * yac_serializer_igbinary_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ {
45 |
46 | ZVAL_NULL(rv);
47 | igbinary_unserialize((uint8_t *)content, len, rv);
48 | return rv;
49 | } /* }}} */
50 |
51 | #endif
52 |
53 | /*
54 | * Local variables:
55 | * tab-width: 4
56 | * c-basic-offset: 4
57 | * End:
58 | * vim600: noet sw=4 ts=4 fdm=marker
59 | * vim<600: noet sw=4 ts=4
60 | */
61 |
--------------------------------------------------------------------------------
/serializer/json.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifdef HAVE_CONFIG_H
22 | #include "config.h"
23 | #endif
24 |
25 | #if YAC_ENABLE_JSON
26 |
27 | #include "php.h"
28 | #include "ext/json/php_json.h"
29 | #include "zend_smart_str.h" /* for smart_str */
30 |
31 | #include "yac_serializer.h"
32 |
33 | int yac_serializer_json_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ {
34 | #if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3))
35 | php_json_encode(buf, pzval);
36 | #else
37 | php_json_encode(buf, pzval, 0); /* options */
38 | #endif
39 |
40 | return 1;
41 | } /* }}} */
42 |
43 | zval* yac_serializer_json_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ {
44 | ZVAL_NULL(rv);
45 | php_json_decode(rv, content, len, 1, 512);
46 |
47 | return rv;
48 | } /* }}} */
49 |
50 | #endif
51 |
52 | /*
53 | * Local variables:
54 | * tab-width: 4
55 | * c-basic-offset: 4
56 | * End:
57 | * vim600: noet sw=4 ts=4 fdm=marker
58 | * vim<600: noet sw=4 ts=4
59 | */
60 |
--------------------------------------------------------------------------------
/serializer/msgpack.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yar - Light, concurrent RPC framework |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2012-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | | Zhenyu Zhang |
17 | +----------------------------------------------------------------------+
18 | */
19 |
20 | /* $Id$ */
21 |
22 | #ifdef HAVE_CONFIG_H
23 | #include "config.h"
24 | #endif
25 |
26 | #ifdef YAC_ENABLE_MSGPACK
27 |
28 | #include "php.h"
29 | #include "ext/msgpack/php_msgpack.h"
30 | #include "zend_smart_str.h" /* for smart_str */
31 |
32 | #include "yac_serializer.h"
33 |
34 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ {
35 | php_msgpack_serialize(buf, pzval);
36 | return 1;
37 | } /* }}} */
38 |
39 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ {
40 | ZVAL_NULL(rv);
41 | php_msgpack_unserialize(rv, content, len);
42 | return rv;
43 | } /* }}} */
44 |
45 | #endif
46 |
47 | /*
48 | * Local variables:
49 | * tab-width: 4
50 | * c-basic-offset: 4
51 | * End:
52 | * vim600: noet sw=4 ts=4 fdm=marker
53 | * vim<600: noet sw=4 ts=4
54 | */
55 |
--------------------------------------------------------------------------------
/serializer/php.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifdef HAVE_CONFIG_H
22 | #include "config.h"
23 | #endif
24 |
25 | #include "php.h"
26 | #include "ext/standard/php_var.h" /* for serialize */
27 | #include "zend_smart_str.h"
28 |
29 | #include "yac_serializer.h"
30 |
31 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg) /* {{{ */ {
32 | php_serialize_data_t var_hash;
33 |
34 | PHP_VAR_SERIALIZE_INIT(var_hash);
35 | php_var_serialize(buf, pzval, &var_hash);
36 | PHP_VAR_SERIALIZE_DESTROY(var_hash);
37 |
38 | return 1;
39 | } /* }}} */
40 |
41 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv) /* {{{ */ {
42 | const unsigned char *p;
43 | php_unserialize_data_t var_hash;
44 | p = (const unsigned char*)content;
45 |
46 | ZVAL_FALSE(rv);
47 | PHP_VAR_UNSERIALIZE_INIT(var_hash);
48 | if (!php_var_unserialize(rv, &p, p + len, &var_hash)) {
49 | zval_ptr_dtor(rv);
50 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
51 | /* spprintf(msg, 0, "unpack error at offset %ld of %ld bytes", (long)((char*)p - content), len); */
52 | return NULL;
53 | }
54 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
55 |
56 | return rv;
57 | } /* }}} */
58 |
59 | /*
60 | * Local variables:
61 | * tab-width: 4
62 | * c-basic-offset: 4
63 | * End:
64 | * vim600: noet sw=4 ts=4 fdm=marker
65 | * vim<600: noet sw=4 ts=4
66 | */
67 |
--------------------------------------------------------------------------------
/serializer/yac_serializer.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifndef YAC_SERIALIZER_H
22 | #define YAC_SERIALIZER_H
23 |
24 | typedef int (*yac_serializer_t)(zval*, smart_str*, char**);
25 | typedef zval* (*yac_unserializer_t)(char *, size_t, char**, zval*);
26 |
27 | #ifdef YAC_ENABLE_MSGPACK
28 | int yac_serializer_msgpack_pack(zval *pzval, smart_str *buf, char **msg);
29 | zval * yac_serializer_msgpack_unpack(char *content, size_t len, char **msg, zval *rv);
30 | #endif
31 |
32 | int yac_serializer_php_pack(zval *pzval, smart_str *buf, char **msg);
33 | zval * yac_serializer_php_unpack(char *content, size_t len, char **msg, zval *rv);
34 |
35 | #ifdef YAC_ENABLE_IGBINARY
36 | int yac_serializer_igbinary_pack(zval *pzval, smart_str *buf, char **msg);
37 | zval * yac_serializer_igbinary_unpack(char *content, size_t len, char **msg, zval *rv);
38 | #endif
39 |
40 | #ifdef YAC_ENABLE_JSON
41 | int yac_serializer_json_pack(zval *pzval, smart_str *buf, char **msg);
42 | zval * yac_serializer_json_unpack(char *content, size_t len, char **msg, zval *rv);
43 | #endif
44 |
45 | #endif /* YAC_SERIALIZER_H */
46 |
47 | /*
48 | * Local variables:
49 | * tab-width: 4
50 | * c-basic-offset: 4
51 | * End:
52 | * vim600: noet sw=4 ts=4 fdm=marker
53 | * vim<600: noet sw=4 ts=4
54 | */
55 |
--------------------------------------------------------------------------------
/storage/allocator/allocators/createfilemapping.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Authors: Xinchen Hui |
16 | | Dmitry Stogov |
17 | | Wei Dai |
18 | +----------------------------------------------------------------------+
19 | */
20 |
21 | #include "php.h"
22 |
23 | #include "php_yac.h"
24 | #include "storage/yac_storage.h"
25 | #include "storage/allocator/yac_allocator.h"
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #define ACCEL_FILEMAP_NAME "Yac.SharedMemoryArea"
32 | #define ACCEL_FILEMAP_BASE "Yac.MemoryBase"
33 | #define MAX_MAP_RETRIES 25
34 |
35 | static HANDLE memfile = NULL;
36 | static void *mapping_base;
37 |
38 | typedef struct {
39 | yac_shared_segment common;
40 | unsigned long size;
41 | } yac_shared_segment_create_file;
42 |
43 | #ifdef USE_FILE_MAPPING
44 | static char *create_name_with_username(char *name) /* {{{ */ {
45 | static char newname[MAXPATHLEN + UNLEN + 4];
46 | char uname[UNLEN + 1];
47 | DWORD unsize = UNLEN;
48 |
49 | GetUserName(uname, &unsize);
50 | snprintf(newname, sizeof(newname) - 1, "%s@%s", name, uname);
51 | return newname;
52 | }
53 | /* }}} */
54 |
55 | static char *get_mmap_base_file(void) /* {{{ */ {
56 | static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@")];
57 | char uname[UNLEN + 1];
58 | DWORD unsize = UNLEN;
59 | int l;
60 |
61 | GetTempPath(MAXPATHLEN, windir);
62 | GetUserName(uname, &unsize);
63 | l = strlen(windir);
64 | snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s", ACCEL_FILEMAP_BASE, uname);
65 | return windir;
66 | }
67 | /* }}} */
68 |
69 | static int yac_shared_alloc_reattach(size_t requested_size, char **error_in) /* {{{ */ {
70 | void *wanted_mapping_base;
71 | char *mmap_base_file = get_mmap_base_file();
72 | FILE *fp = fopen(mmap_base_file, "r");
73 | MEMORY_BASIC_INFORMATION info;
74 |
75 | if (!fp) {
76 | *error_in="fopen";
77 | return ALLOC_FAILURE;
78 | }
79 |
80 | if (!fscanf(fp, "%p", &wanted_mapping_base)) {
81 | *error_in="read mapping base";
82 | fclose(fp);
83 | return ALLOC_FAILURE;
84 | }
85 | fclose(fp);
86 |
87 | /* Check if the requested address space is free */
88 | if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0) {
89 | *error_in="VirtualQuery";
90 | return ALLOC_FAILURE;
91 | }
92 |
93 | if (info.State != MEM_FREE) {
94 | *error_in="info.State";
95 | return ALLOC_FAILURE;
96 | }
97 |
98 | if (info.RegionSize < requested_size) {
99 | *error_in="info.RegionSize";
100 | return ALLOC_FAILURE;
101 | }
102 |
103 | mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base);
104 |
105 | if (mapping_base == NULL) {
106 | return ALLOC_FAIL_MAPPING;
107 | }
108 |
109 | return SUCCESSFULLY_REATTACHED;
110 | }
111 | /* }}} */
112 |
113 | 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) /* {{{ */ {
114 | int ret;
115 | unsigned long allocate_size, occupied_size = 0;
116 | unsigned int i, segment_size, segments_num = 1024, is_reattach = 0;
117 | int map_retries = 0;
118 | yac_shared_segment_create_file first_segment;
119 | void *default_mapping_base_set[] = {0, 0};
120 | /* TODO:
121 | 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
122 | 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
123 | desired. Not done yet, @zend refused but did not remember the exact reason, pls add info here if one of you know why :)
124 | */
125 | #if defined(_WIN64)
126 | void *vista_mapping_base_set[] = { (void *) 0x0000100000000000, (void *) 0x0000200000000000, (void *) 0x0000300000000000, (void *) 0x0000700000000000, 0 };
127 | #else
128 | void *vista_mapping_base_set[] = { (void *) 0x20000000, (void *) 0x21000000, (void *) 0x30000000, (void *) 0x31000000, (void *) 0x50000000, 0 };
129 | #endif
130 | void **wanted_mapping_base = default_mapping_base_set;
131 |
132 |
133 | k_size = YAC_SMM_ALIGNED_SIZE(k_size);
134 | v_size = YAC_SMM_ALIGNED_SIZE(v_size);
135 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) {
136 | segments_num >>= 1;
137 | }
138 |
139 | segment_size = v_size / segments_num;
140 | ++segments_num;
141 |
142 | allocate_size = k_size + v_size;
143 |
144 | /* Mapping retries: When Apache2 restarts, the parent process startup routine
145 | can be called before the child process is killed. In this case, the map will fail
146 | and we have to sleep some time (until the child releases the mapping object) and retry.*/
147 | do {
148 | memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME));
149 | if (memfile == NULL) {
150 | break;
151 | }
152 |
153 | ret = yac_shared_alloc_reattach((size_t)k_size, error_in);
154 | if (ret == ALLOC_FAIL_MAPPING) {
155 | /* Mapping failed, wait for mapping object to get freed and retry */
156 | CloseHandle(memfile);
157 | memfile = NULL;
158 | Sleep(1000 * (map_retries + 1));
159 | } else if (ret == SUCCESSFULLY_REATTACHED) {
160 | is_reattach = 1;
161 | break;
162 | } else {
163 | return ret;
164 | }
165 | } while (++map_retries < MAX_MAP_RETRIES);
166 |
167 | if (map_retries == MAX_MAP_RETRIES) {
168 | *error_in = "OpenFileMapping";
169 | return 0;
170 | }
171 |
172 | *shared_segments_p = (yac_shared_segment_create_file *)calloc(1, segments_num * sizeof(yac_shared_segment_create_file));
173 | if(!*shared_segments_p) {
174 | *error_in = "calloc";
175 | return 0;
176 | }
177 | *shared_segments_count = segments_num;
178 |
179 | /* Starting from windows Vista, heap randomization occurs which might cause our mapping base to
180 | be taken (fail to map). So under Vista, we try to map into a hard coded predefined addresses
181 | in high memory. */
182 | if (!YAC_G(mmap_base) || !*YAC_G(mmap_base)) {
183 | do {
184 | OSVERSIONINFOEX osvi;
185 | SYSTEM_INFO si;
186 |
187 | ZeroMemory(&si, sizeof(SYSTEM_INFO));
188 | ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
189 |
190 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
191 |
192 | if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) {
193 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
194 | if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
195 | break;
196 | }
197 | }
198 |
199 | GetSystemInfo(&si);
200 |
201 | /* Are we running Vista ? */
202 | if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6) {
203 | wanted_mapping_base = vista_mapping_base_set;
204 | }
205 | } while (0);
206 | } else {
207 | char *s = YAC_G(mmap_base);
208 |
209 | /* skip leading 0x, %p assumes hexdeciaml format anyway */
210 | if (*s == '0' && *(s + 1) == 'x') {
211 | s += 2;
212 | }
213 | if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) {
214 | *error_in = "mapping";
215 | return 0;
216 | }
217 | }
218 |
219 | if (is_reattach == 0) {
220 | memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, allocate_size, create_name_with_username(ACCEL_FILEMAP_NAME));
221 | if (memfile == NULL) {
222 | *error_in = "CreateFileMapping";
223 | return 0;
224 | }
225 |
226 | do {
227 | first_segment.common.p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base);
228 | if (wanted_mapping_base == NULL) {
229 | break;
230 | }
231 | *wanted_mapping_base++;
232 | } while (!mapping_base);
233 | }
234 |
235 | if(mapping_base == NULL) {
236 | *error_in = "MapViewOfFileEx";
237 | return 0;
238 | } else {
239 | char *mmap_base_file = get_mmap_base_file();
240 | FILE *fp = fopen(mmap_base_file, "w");
241 | if (!fp) {
242 | *error_in = "get_mmap_base_file";
243 | return 0;
244 | }
245 | fprintf(fp, "%p", mapping_base);
246 | fclose(fp);
247 | }
248 |
249 | first_segment.common.p = mapping_base;
250 | first_segment.size = allocate_size;
251 | first_segment.common.size = k_size;
252 | first_segment.common.pos = 0;
253 |
254 | (*shared_segments_p)[0] = first_segment;
255 |
256 | occupied_size = k_size;
257 | for (i = 1; i < segments_num; i++) {
258 | (*shared_segments_p)[i].size = 0;
259 | (*shared_segments_p)[i].common.pos = 0;
260 | (*shared_segments_p)[i].common.p = (void *)((char *)first_segment.common.p + occupied_size);
261 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) {
262 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size);
263 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size);
264 | } else {
265 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size);
266 | break;
267 | }
268 | }
269 |
270 | return 1;
271 | }
272 | /* }}} */
273 |
274 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ {
275 | if (!shared_segment->size && mapping_base) {
276 | UnmapViewOfFile(mapping_base);
277 | CloseHandle(memfile);
278 | }
279 | return 0;
280 | }
281 | /* }}} */
282 |
283 | static unsigned long segment_type_size(void) /* {{{ */ {
284 | return sizeof(yac_shared_segment_create_file);
285 | }
286 | /* }}} */
287 |
288 | yac_shared_memory_handlers yac_alloc_create_file_handlers = /* {{{ */ {
289 | (create_segments_t)create_segments,
290 | detach_segment,
291 | segment_type_size
292 | };
293 | /* }}} */
294 | #endif /* USE_CREATE_FILE */
295 |
296 | /*
297 | * Local variables:
298 | * tab-width: 4
299 | * c-basic-offset: 4
300 | * End:
301 | * vim600: noet sw=4 ts=4 fdm=marker
302 | * vim<600: noet sw=4 ts=4
303 | */
304 |
--------------------------------------------------------------------------------
/storage/allocator/allocators/mmap.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Authors: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | #include "storage/yac_storage.h"
20 | #include "storage/allocator/yac_allocator.h"
21 |
22 | #ifdef USE_MMAP
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
31 | # define MAP_ANONYMOUS MAP_ANON
32 | #endif
33 |
34 | #ifndef MAP_FAILED
35 | #define MAP_FAILED (void *)-1
36 | #endif
37 |
38 | typedef struct {
39 | yac_shared_segment common;
40 | unsigned long size;
41 | } yac_shared_segment_mmap;
42 |
43 | 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) /* {{{ */ {
44 | unsigned long allocate_size, occupied_size = 0;
45 | unsigned int i, segment_size, segments_num = 1024;
46 | yac_shared_segment_mmap first_segment;
47 |
48 | k_size = YAC_SMM_ALIGNED_SIZE(k_size);
49 | v_size = YAC_SMM_ALIGNED_SIZE(v_size);
50 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) {
51 | segments_num >>= 1;
52 | }
53 |
54 | segment_size = v_size / segments_num;
55 | ++segments_num;
56 |
57 | allocate_size = k_size + v_size;
58 |
59 | first_segment.common.p = mmap(0, allocate_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
60 | if (first_segment.common.p == MAP_FAILED) {
61 | *error_in = "mmap";
62 | return 0;
63 | }
64 | first_segment.size = allocate_size;
65 | first_segment.common.size = k_size;
66 | first_segment.common.pos = 0;
67 |
68 | *shared_segments_p = (yac_shared_segment_mmap *)calloc(1, segments_num * sizeof(yac_shared_segment_mmap));
69 | if (!*shared_segments_p) {
70 | munmap(first_segment.common.p, first_segment.size);
71 | *error_in = "calloc";
72 | return 0;
73 | } else {
74 | *shared_segments_p[0] = first_segment;
75 | }
76 | *shared_segments_count = segments_num;
77 |
78 | occupied_size = k_size;
79 | for (i = 1; i < segments_num; i++) {
80 | (*shared_segments_p)[i].size = 0;
81 | (*shared_segments_p)[i].common.pos = 0;
82 | (*shared_segments_p)[i].common.p = first_segment.common.p + occupied_size;
83 | if ((allocate_size - occupied_size) >= YAC_SMM_ALIGNED_SIZE(segment_size)) {
84 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size);
85 | occupied_size += YAC_SMM_ALIGNED_SIZE(segment_size);
86 | } else {
87 | (*shared_segments_p)[i].common.size = (allocate_size - occupied_size);
88 | break;
89 | }
90 | }
91 |
92 | return 1;
93 | }
94 | /* }}} */
95 |
96 | static int detach_segment(yac_shared_segment *shared_segment) /* {{{ */ {
97 | if (shared_segment->size) {
98 | munmap(shared_segment->p, shared_segment->size);
99 | }
100 | return 0;
101 | }
102 | /* }}} */
103 |
104 | static unsigned long segment_type_size(void) /* {{{ */ {
105 | return sizeof(yac_shared_segment_mmap);
106 | }
107 | /* }}} */
108 |
109 | yac_shared_memory_handlers yac_alloc_mmap_handlers = /* {{{ */ {
110 | (create_segments_t)create_segments,
111 | detach_segment,
112 | segment_type_size
113 | };
114 | /* }}} */
115 |
116 | #endif /* USE_MMAP */
117 |
118 | /*
119 | * Local variables:
120 | * tab-width: 4
121 | * c-basic-offset: 4
122 | * End:
123 | * vim600: noet sw=4 ts=4 fdm=marker
124 | * vim<600: noet sw=4 ts=4
125 | */
126 |
--------------------------------------------------------------------------------
/storage/allocator/allocators/shm.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Authors: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | #include "storage/yac_storage.h"
20 | #include "storage/allocator/yac_allocator.h"
21 |
22 | #ifdef USE_SHM
23 |
24 | #if defined(__FreeBSD__)
25 | # include
26 | #endif
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include
38 | #include
39 |
40 | typedef struct {
41 | yac_shared_segment common;
42 | int shm_id;
43 | } yac_shared_segment_shm;
44 |
45 | 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) /* {{{ */ {
46 | struct shmid_ds sds;
47 | int shm_id, shmget_flags;
48 | yac_shared_segment_shm *shared_segments, first_segment;
49 | unsigned int i, j, allocate_size, allocated_num, segments_num, segment_size;
50 |
51 | shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL;
52 | segments_num = 1024;
53 | while ((v_size / segments_num) < YAC_SMM_SEGMENT_MIN_SIZE) {
54 | segments_num >>= 1;
55 | }
56 | segment_size = v_size / segments_num;
57 | allocate_size = YAC_SMM_SEGMENT_MAX_SIZE;
58 |
59 | while ((shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags)) < 0) {
60 | allocate_size >>= 1;
61 | }
62 |
63 | if (shm_id < 0) {
64 | /* this should never happen */
65 | *error_in = "shmget";
66 | return 0;
67 | }
68 |
69 | if (allocate_size < YAC_SMM_SEGMENT_MIN_SIZE) {
70 | /* this should never happen */
71 | *error_in = "shmget";
72 | return 0;
73 | }
74 |
75 | if (k_size <= allocate_size) {
76 | first_segment.shm_id = shm_id;
77 | first_segment.common.pos = 0;
78 | first_segment.common.size = allocate_size;
79 | first_segment.common.p = shmat(shm_id, NULL, 0);
80 | shmctl(shm_id, IPC_RMID, &sds);
81 | if (first_segment.common.p == (void *)-1) {
82 | *error_in = "shmat";
83 | return 0;
84 | }
85 | } else {
86 | shmctl(shm_id, IPC_RMID, &sds);
87 | *error_in = "shmget";
88 | return 0;
89 | }
90 |
91 | allocated_num = (v_size % allocate_size)? (v_size / allocate_size) + 1 : (v_size / allocate_size);
92 | shared_segments = (yac_shared_segment_shm *)calloc(1, (allocated_num) * sizeof(yac_shared_segment_shm));
93 | if (!shared_segments) {
94 | *error_in = "calloc";
95 | return 0;
96 | }
97 |
98 | for (i = 0; i < allocated_num; i ++) {
99 | shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags);
100 | if (shm_id == -1) {
101 | *error_in = "shmget";
102 | for (j = 0; j < i; j++) {
103 | shmdt(shared_segments[j].common.p);
104 | }
105 | free(shared_segments);
106 | return 0;
107 | }
108 | shared_segments[i].shm_id = shm_id;
109 | shared_segments[i].common.pos = 0;
110 | shared_segments[i].common.size = allocate_size;
111 | shared_segments[i].common.p = shmat(shm_id, NULL, 0);
112 | shmctl(shm_id, IPC_RMID, &sds);
113 | if (shared_segments[i].common.p == (void *)-1) {
114 | *error_in = "shmat";
115 | for (j = 0; j < i; j++) {
116 | shmdt(shared_segments[j].common.p);
117 | }
118 | free(shared_segments);
119 | return 0;
120 | }
121 | }
122 |
123 | ++segments_num;
124 | *shared_segments_p = (yac_shared_segment_shm *)calloc(1, segments_num * sizeof(yac_shared_segment_shm));
125 | if (!*shared_segments_p) {
126 | free(shared_segments);
127 | *error_in = "calloc";
128 | return 0;
129 | } else {
130 | *shared_segments_p[0] = first_segment;
131 | }
132 | *shared_segments_count = segments_num;
133 |
134 | j = 0;
135 | for (i = 1; i < segments_num; i++) {
136 | if (shared_segments[j].common.pos == 0) {
137 | (*shared_segments_p)[i].shm_id = shared_segments[j].shm_id;
138 | }
139 |
140 | if ((shared_segments[j].common.size - shared_segments[j].common.pos) >= (2 * YAC_SMM_ALIGNED_SIZE(segment_size))) {
141 | (*shared_segments_p)[i].common.pos = 0;
142 | (*shared_segments_p)[i].common.size = YAC_SMM_ALIGNED_SIZE(segment_size);
143 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos);
144 | shared_segments[j].common.pos += YAC_SMM_ALIGNED_SIZE(segment_size);
145 | } else {
146 | (*shared_segments_p)[i].common.pos = 0;
147 | (*shared_segments_p)[i].common.size = shared_segments[j].common.size - shared_segments[j].common.pos;
148 | (*shared_segments_p)[i].common.p = shared_segments[j].common.p + YAC_SMM_ALIGNED_SIZE(shared_segments[j].common.pos);
149 | j++;
150 | }
151 | }
152 |
153 | free(shared_segments);
154 |
155 | return 1;
156 | }
157 | /* }}} */
158 |
159 | static int detach_segment(yac_shared_segment_shm *shared_segment) /* {{{ */ {
160 | if (shared_segment->shm_id) {
161 | shmdt(shared_segment->common.p);
162 | }
163 | return 1;
164 | }
165 | /* }}} */
166 |
167 | static size_t segment_type_size(void) /* {{{ */ {
168 | return sizeof(yac_shared_segment_shm);
169 | }
170 | /* }}} */
171 |
172 | yac_shared_memory_handlers yac_alloc_shm_handlers = /* {{{ */ {
173 | (create_segments_t)create_segments,
174 | (detach_segment_t)detach_segment,
175 | segment_type_size
176 | };
177 | /* }}} */
178 |
179 | #endif /* USE_SHM */
180 |
181 | /*
182 | * Local variables:
183 | * tab-width: 4
184 | * c-basic-offset: 4
185 | * End:
186 | * vim600: noet sw=4 ts=4 fdm=marker
187 | * vim<600: noet sw=4 ts=4
188 | */
189 |
--------------------------------------------------------------------------------
/storage/allocator/yac_allocator.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Authors: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "php.h"
24 | #include "storage/yac_storage.h"
25 | #include "yac_allocator.h"
26 |
27 | int yac_allocator_startup(unsigned long k_size, unsigned long size, char **msg) /* {{{ */ {
28 | char *p;
29 | yac_shared_segment *segments = NULL;
30 | int i, segments_num, segments_array_size, segment_size;
31 | const yac_shared_memory_handlers *he;
32 |
33 | if ((he = &yac_shared_memory_handler)) {
34 | int ret = he->create_segments(k_size, size, &segments, &segments_num, msg);
35 |
36 | if (!ret) {
37 | if (segments) {
38 | int i;
39 | for (i = 0; i < segments_num; i++) {
40 | if (segments[i].p && segments[i].p != (void *)-1) {
41 | he->detach_segment(&segments[i]);
42 | }
43 | }
44 | free(segments);
45 | }
46 | return 0;
47 | }
48 | } else {
49 | return 0;
50 | }
51 |
52 | segment_size = he->segment_type_size();
53 | segments_array_size = (segments_num - 1) * segment_size;
54 |
55 | yac_storage = segments[0].p;
56 | memcpy(&YAC_SG(first_seg), (char *)(&segments[0]), segment_size);
57 |
58 | YAC_SG(segments_num) = segments_num - 1;
59 | YAC_SG(segments_num_mask) = YAC_SG(segments_num) - 1;
60 | YAC_SG(segments) = (yac_shared_segment **)((char *)yac_storage + YAC_SMM_ALIGNED_SIZE(sizeof(yac_storage_globals) + segment_size - sizeof(yac_shared_segment)));
61 |
62 | p = (char *)YAC_SG(segments) + (sizeof(void *) * YAC_SG(segments_num));
63 | memcpy(p, (char *)segments + segment_size, segments_array_size);
64 | for (i = 0; i < YAC_SG(segments_num); i++) {
65 | YAC_SG(segments)[i] = (yac_shared_segment *)p;
66 | p += segment_size;
67 | }
68 | YAC_SG(slots) = (yac_kv_key *)((char *)YAC_SG(segments)
69 | + (YAC_SG(segments_num) * sizeof(void *)) + YAC_SMM_ALIGNED_SIZE(segments_array_size));
70 |
71 | free(segments);
72 |
73 | return 1;
74 | }
75 | /* }}} */
76 |
77 | void yac_allocator_shutdown(void) /* {{{ */ {
78 | yac_shared_segment **segments;
79 | const yac_shared_memory_handlers *he;
80 |
81 | segments = YAC_SG(segments);
82 | if (segments) {
83 | if ((he = &yac_shared_memory_handler)) {
84 | int i = 0;
85 | for (i = 0; i < YAC_SG(segments_num); i++) {
86 | he->detach_segment(segments[i]);
87 | }
88 | he->detach_segment(&YAC_SG(first_seg));
89 | }
90 | }
91 | }
92 | /* }}} */
93 |
94 | static inline void *yac_allocator_alloc_algo2(unsigned long size, int hash) /* {{{ */ {
95 | yac_shared_segment *segment;
96 | unsigned int seg_size, retry, pos, current;
97 |
98 | current = hash & YAC_SG(segments_num_mask);
99 | /* do we really need lock here? it depends the real life exam */
100 | retry = 3;
101 | do_retry:
102 | segment = YAC_SG(segments)[current];
103 | seg_size = segment->size;
104 | pos = segment->pos;
105 | if ((seg_size - pos) >= size) {
106 | do_alloc:
107 | pos += size;
108 | segment->pos = pos;
109 | if (segment->pos == pos) {
110 | return (void *)((char *)segment->p + (pos - size));
111 | } else if (retry--) {
112 | goto do_retry;
113 | }
114 | return NULL;
115 | } else {
116 | int i, max;
117 | max = (YAC_SG(segments_num) > 4)? 4 : YAC_SG(segments_num);
118 | for (i = 1; i < max; i++) {
119 | segment = YAC_SG(segments)[(current + i) & YAC_SG(segments_num_mask)];
120 | seg_size = segment->size;
121 | pos = segment->pos;
122 | if ((seg_size - pos) >= size) {
123 | current = (current + i) & YAC_SG(segments_num_mask);
124 | goto do_alloc;
125 | }
126 | }
127 | segment->pos = 0;
128 | pos = 0;
129 | ++YAC_SG(recycles);
130 | goto do_alloc;
131 | }
132 | }
133 | /* }}} */
134 |
135 | #if 0
136 | static inline void *yac_allocator_alloc_algo1(unsigned long size) /* {{{ */ {
137 | int i, j, picked_seg, atime;
138 | picked_seg = (YAC_SG(current_seg) + 1) & YAC_SG(segments_num_mask);
139 |
140 | atime = YAC_SG(segments)[picked_seg]->atime;
141 | for (i = 0; i < 10; i++) {
142 | j = (picked_seg + 1) & YAC_SG(segments_num_mask);
143 | if (YAC_SG(segments)[j]->atime < atime) {
144 | picked_seg = j;
145 | atime = YAC_SG(segments)[j]->atime;
146 | }
147 | }
148 |
149 | YAC_SG(current_seg) = picked_seg;
150 | YAC_SG(segments)[picked_seg]->pos = 0;
151 | return yac_allocator_alloc_algo2(size);
152 | }
153 | /* }}} */
154 | #endif
155 |
156 | unsigned long yac_allocator_real_size(unsigned long size) /* {{{ */ {
157 | unsigned long real_size = YAC_SMM_TRUE_SIZE(size);
158 |
159 | if (real_size > YAC_SG(segments)[0]->size) {
160 | return 0;
161 | }
162 |
163 | return real_size;
164 | }
165 | /* }}} */
166 |
167 | void * yac_allocator_raw_alloc(unsigned long real_size, int hash) /* {{{ */ {
168 |
169 | return yac_allocator_alloc_algo2(real_size, hash);
170 | /*
171 | if (YAC_SG(exhausted)) {
172 | return yac_allocator_alloc_algo1(real_size);
173 | } else {
174 | void *p;
175 | if ((p = yac_allocator_alloc_algo2(real_size))) {
176 | return p;
177 | }
178 | return yac_allocator_alloc_algo1(real_size);
179 | }
180 | */
181 | }
182 | /* }}} */
183 |
184 | #if 0
185 | void yac_allocator_touch(void *p, unsigned long atime) /* {{{ */ {
186 | yac_shared_block_header h = *(yac_shared_block_header *)(p - sizeof(yac_shared_block_header));
187 |
188 | if (h.seg >= YAC_SG(segments_num)) {
189 | return;
190 | }
191 |
192 | YAC_SG(segments)[h.seg]->atime = atime;
193 | }
194 | /* }}} */
195 | #endif
196 |
197 | /*
198 | * Local variables:
199 | * tab-width: 4
200 | * c-basic-offset: 4
201 | * End:
202 | * vim600: noet sw=4 ts=4 fdm=marker
203 | * vim<600: noet sw=4 ts=4
204 | */
205 |
--------------------------------------------------------------------------------
/storage/allocator/yac_allocator.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Authors: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | #ifndef YAC_ALLOCATOR_H
20 | #define YAC_ALLOCATOR_H
21 |
22 | #ifdef HAVE_CONFIG_H
23 | #include "config.h"
24 | #endif
25 |
26 | #define YAC_SMM_ALIGNMENT 8
27 | #define YAC_SMM_ALIGNMENT_LOG2 3
28 | #define YAC_SMM_ALIGNMENT_MASK ~(YAC_SMM_ALIGNMENT - 1)
29 | #define YAC_SMM_BLOCK_HEADER_SIZE YAC_SMM_ALIGNED_SIZE(sizeof(yac_shared_block_header))
30 |
31 | #define YAC_SMM_MAIN_SEG_SIZE (4*1024*1024)
32 | #define YAC_SMM_SEGMENT_MAX_SIZE (32*1024*1024)
33 | #define YAC_SMM_SEGMENT_MIN_SIZE (4*1024*1024)
34 | #define YAC_SMM_MIN_BLOCK_SIZE 128
35 | #define YAC_SMM_ALIGNED_SIZE(x) (((x) + YAC_SMM_ALIGNMENT - 1) & YAC_SMM_ALIGNMENT_MASK)
36 | #define YAC_SMM_TRUE_SIZE(x) ((x < YAC_SMM_MIN_BLOCK_SIZE)? (YAC_SMM_MIN_BLOCK_SIZE) : (YAC_SMM_ALIGNED_SIZE(x)))
37 |
38 | #ifdef PHP_WIN32
39 | # define USE_FILE_MAPPING 1
40 | # define inline __inline
41 | #elif defined(HAVE_SHM_MMAP_ANON)
42 | # define USE_MMAP 1
43 | #elif defined(HAVE_SHM_IPC)
44 | # define USE_SHM 1
45 | #else
46 | #error(no builtin shared memory supported)
47 | #endif
48 |
49 | #define ALLOC_FAILURE 0
50 | #define ALLOC_SUCCESS 1
51 | #define FAILED_REATTACHED 2
52 | #define SUCCESSFULLY_REATTACHED 4
53 | #define ALLOC_FAIL_MAPPING 8
54 |
55 | 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);
56 | typedef int (*detach_segment_t)(yac_shared_segment *shared_segment);
57 |
58 | typedef struct {
59 | create_segments_t create_segments;
60 | detach_segment_t detach_segment;
61 | unsigned long (*segment_type_size)(void);
62 | } yac_shared_memory_handlers;
63 |
64 | typedef struct {
65 | const char *name;
66 | yac_shared_memory_handlers *handler;
67 | } yac_shared_memory_handler_entry;
68 |
69 | int yac_allocator_startup(unsigned long first_seg_size, unsigned long size, char **err);
70 | void yac_allocator_shutdown(void);
71 | unsigned long yac_allocator_real_size(unsigned long size);
72 | void *yac_allocator_raw_alloc(unsigned long real_size, int seg);
73 | int yac_allocator_free(void *p);
74 |
75 | static inline void * yac_allocator_alloc(unsigned long size, int seg) {
76 | unsigned long real_size = yac_allocator_real_size(size);
77 | if (!real_size) {
78 | return (void *)0;
79 | }
80 | return yac_allocator_raw_alloc(real_size, seg);
81 | }
82 |
83 | #if defined(USE_MMAP)
84 | extern yac_shared_memory_handlers yac_alloc_mmap_handlers;
85 | #define yac_shared_memory_handler yac_alloc_mmap_handlers
86 | #define YAC_SHARED_MEMORY_HANDLER_NAME "mmap"
87 | #elif defined(USE_SHM)
88 | extern yac_shared_memory_handlers yac_alloc_shm_handlers;
89 | #define yac_shared_memory_handler yac_alloc_shm_handlers
90 | #define YAC_SHARED_MEMORY_HANDLER_NAME "shm"
91 | #elif defined(USE_FILE_MAPPING)
92 | extern yac_shared_memory_handlers yac_alloc_create_file_handlers;
93 | #define yac_shared_memory_handler yac_alloc_create_file_handlers
94 | #define YAC_SHARED_MEMORY_HANDLER_NAME "file_mapping"
95 | #endif
96 |
97 | #endif /* YAC_ALLOCATOR_H */
98 |
--------------------------------------------------------------------------------
/storage/yac_atomic.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | | John Neo |
17 | +----------------------------------------------------------------------+
18 | */
19 |
20 | #ifndef YAC_ATOMIC_H
21 | #define YAC_ATOMIC_H
22 |
23 | #ifdef HAVE_CONFIG_H
24 | #include "config.h"
25 | #endif
26 |
27 | #if HAVE_BUILTIN_ATOMIC
28 | #define YAC_CAS(lock, old, set) __sync_bool_compare_and_swap(lock, old, set)
29 | #elif ( __amd64__ || __amd64 || __x86_64__ || __i386__ || __i386 )
30 | static inline int __yac_cas(unsigned int *lock, unsigned int old, unsigned int set) {
31 | unsigned char res;
32 |
33 | __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" :
34 | "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
35 |
36 | return res;
37 | }
38 | #define YAC_CAS(lock, old, set) __yac_cas(lock, old, set)
39 | #elif ZEND_WIN32
40 | #define YAC_CAS(lock, old, set) (InterlockedCompareExchange(lock, set, old) == old)
41 | #else
42 | #undef YAC_CAS
43 | #warning No atomic CAS supports
44 | #endif
45 |
46 | #ifdef YAC_CAS
47 |
48 | #define MUT_READ 0x0
49 | #define MUT_WRITE 0x1
50 | #define CAS_MAX_SPIN 100
51 |
52 | static inline int yac_mutex_write(unsigned int *me) {
53 | int retry = 0;
54 | while (!YAC_CAS(me, MUT_READ, MUT_WRITE)) {
55 | if (++retry == CAS_MAX_SPIN) {
56 | return 0;
57 | }
58 | }
59 | return 1;
60 | }
61 |
62 | static inline void yac_mutex_read(unsigned int *me) {
63 | *me = MUT_READ;
64 | }
65 |
66 | #define WRITEP(P) yac_mutex_write(&(P->mutex))
67 | #define READP(P) yac_mutex_read(&(P->mutex))
68 | #else
69 | #undef YAC_CAS
70 | #define WRITEP(P) (1)
71 | #define READP(P)
72 | #endif
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/storage/yac_storage.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | #ifdef HAVE_CONFIG_H
20 | #include "config.h"
21 | #endif
22 |
23 | #include "php.h"
24 |
25 | #if HAVE_SSE_CRC32
26 | #include "Zend/zend_cpuinfo.h"
27 | #include
28 | static uint32_t crc32c_sse42(const char *dagta, unsigned int size);
29 | #endif
30 |
31 | #include "yac_atomic.h"
32 | #include "yac_storage.h"
33 | #include "allocator/yac_allocator.h"
34 |
35 | yac_storage_globals *yac_storage;
36 |
37 | static uint32_t (*yac_crc)(const char *data, unsigned int size);
38 | static uint32_t crc32(const char *dagta, unsigned int size);
39 |
40 | static inline unsigned int yac_storage_align_size(unsigned int size) /* {{{ */ {
41 | int bits = 0;
42 | while ((size = size >> 1)) {
43 | ++bits;
44 | }
45 | return (1 << bits);
46 | }
47 | /* }}} */
48 |
49 | int yac_storage_startup(unsigned long fsize, unsigned long size, char **msg) /* {{{ */ {
50 | unsigned long real_size;
51 |
52 | if (!yac_allocator_startup(fsize, size, msg)) {
53 | return 0;
54 | }
55 | #if HAVE_SSE_CRC32
56 | if (zend_cpu_supports_sse42()) {
57 | yac_crc = crc32c_sse42;
58 | } else
59 | #endif
60 | {
61 | yac_crc = crc32;
62 | }
63 | size = YAC_SG(first_seg).size - ((char *)YAC_SG(slots) - (char *)yac_storage);
64 | real_size = yac_storage_align_size(size / sizeof(yac_kv_key));
65 | if (!((size / sizeof(yac_kv_key)) & ~(real_size << 1))) {
66 | real_size <<= 1;
67 | }
68 |
69 | YAC_SG(slots_size) = real_size;
70 | YAC_SG(slots_mask) = real_size - 1;
71 | YAC_SG(slots_num) = 0;
72 | YAC_SG(fails) = 0;
73 | YAC_SG(hits) = 0;
74 | YAC_SG(miss) = 0;
75 | YAC_SG(kicks) = 0;
76 |
77 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * real_size);
78 |
79 | return 1;
80 | }
81 | /* }}} */
82 |
83 | void yac_storage_shutdown(void) /* {{{ */ {
84 | yac_allocator_shutdown();
85 | }
86 | /* }}} */
87 |
88 | /* {{{ MurmurHash2 (Austin Appleby)
89 | */
90 | static inline uint64_t yac_inline_hash_func1(const char *data, unsigned int len) {
91 | unsigned int h, k;
92 |
93 | h = 0 ^ len;
94 |
95 | while (len >= 4) {
96 | k = data[0];
97 | k |= data[1] << 8;
98 | k |= data[2] << 16;
99 | k |= data[3] << 24;
100 |
101 | k *= 0x5bd1e995;
102 | k ^= k >> 24;
103 | k *= 0x5bd1e995;
104 |
105 | h *= 0x5bd1e995;
106 | h ^= k;
107 |
108 | data += 4;
109 | len -= 4;
110 | }
111 |
112 | switch (len) {
113 | case 3:
114 | h ^= data[2] << 16;
115 | case 2:
116 | h ^= data[1] << 8;
117 | case 1:
118 | h ^= data[0];
119 | h *= 0x5bd1e995;
120 | }
121 |
122 | h ^= h >> 13;
123 | h *= 0x5bd1e995;
124 | h ^= h >> 15;
125 |
126 | return h;
127 | }
128 | /* }}} */
129 |
130 | /* {{{ DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
131 | *
132 | * This is Daniel J. Bernstein's popular `times 33' hash function as
133 | * posted by him years ago on comp->lang.c. It basically uses a function
134 | * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
135 | * known hash functions for strings. Because it is both computed very
136 | * fast and distributes very well.
137 | *
138 | * The magic of number 33, i.e. why it works better than many other
139 | * constants, prime or not, has never been adequately explained by
140 | * anyone. So I try an explanation: if one experimentally tests all
141 | * multipliers between 1 and 256 (as RSE did now) one detects that even
142 | * numbers are not useable at all. The remaining 128 odd numbers
143 | * (except for the number 1) work more or less all equally well. They
144 | * all distribute in an acceptable way and this way fill a hash table
145 | * with an average percent of approx. 86%.
146 | *
147 | * If one compares the Chi^2 values of the variants, the number 33 not
148 | * even has the best value. But the number 33 and a few other equally
149 | * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
150 | * advantage to the remaining numbers in the large set of possible
151 | * multipliers: their multiply operation can be replaced by a faster
152 | * operation based on just one shift plus either a single addition
153 | * or subtraction operation. And because a hash function has to both
154 | * distribute good _and_ has to be very fast to compute, those few
155 | * numbers should be preferred and seems to be the reason why Daniel J.
156 | * Bernstein also preferred it.
157 | *
158 | *
159 | * -- Ralf S. Engelschall
160 | */
161 |
162 | static inline uint64_t yac_inline_hash_func2(const char *key, uint32_t len) {
163 | register uint64_t hash = 5381;
164 |
165 | /* variant with the hash unrolled eight times */
166 | for (; len >= 8; len -= 8) {
167 | hash = ((hash << 5) + hash) + *key++;
168 | hash = ((hash << 5) + hash) + *key++;
169 | hash = ((hash << 5) + hash) + *key++;
170 | hash = ((hash << 5) + hash) + *key++;
171 | hash = ((hash << 5) + hash) + *key++;
172 | hash = ((hash << 5) + hash) + *key++;
173 | hash = ((hash << 5) + hash) + *key++;
174 | hash = ((hash << 5) + hash) + *key++;
175 | }
176 | switch (len) {
177 | case 7: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
178 | case 6: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
179 | case 5: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
180 | case 4: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
181 | case 3: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
182 | case 2: hash = ((hash << 5) + hash) + *key++; /* fallthrough... */
183 | case 1: hash = ((hash << 5) + hash) + *key++; break;
184 | case 0: break;
185 | default: break;
186 | }
187 | return hash;
188 | }
189 | /* }}} */
190 |
191 | /* {{{ COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
192 | * code or tables extracted from it, as desired without restriction.
193 | *
194 | * First, the polynomial itself and its table of feedback terms. The
195 | * polynomial is
196 | * 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
197 | *
198 | * Note that we take it "backwards" and put the highest-order term in
199 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the
200 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in
201 | * the MSB being 1
202 | *
203 | * Note that the usual hardware shift register implementation, which
204 | * is what we're using (we're merely optimizing it by doing eight-bit
205 | * chunks at a time) shifts bits into the lowest-order term. In our
206 | * implementation, that means shifting towards the right. Why do we
207 | * do it this way? Because the calculated CRC must be transmitted in
208 | * order from highest-order term to lowest-order term. UARTs transmit
209 | * characters in order from LSB to MSB. By storing the CRC this way
210 | * we hand it to the UART in the order low-byte to high-byte; the UART
211 | * sends each low-bit to high-bit; and the result is transmission bit
212 | * by bit from highest- to lowest-order term without requiring any bit
213 | * shuffling on our part. Reception works similarly
214 | *
215 | * The feedback terms table consists of 256, 32-bit entries. Notes
216 | *
217 | * The table can be generated at runtime if desired; code to do so
218 | * is shown later. It might not be obvious, but the feedback
219 | * terms simply represent the results of eight shift/xor opera
220 | * tions for all combinations of data and CRC register values
221 | *
222 | * The values must be right-shifted by eight bits by the "updcrc
223 | * logic; the shift must be unsigned (bring in zeroes). On some
224 | * hardware you could probably optimize the shift in assembler by
225 | * using byte-swap instructions
226 | * polynomial $edb88320
227 | *
228 | *
229 | * CRC32 code derived from work by Gary S. Brown.
230 | */
231 |
232 | static unsigned int crc32_tab[] = {
233 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
234 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
235 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
236 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
237 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
238 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
239 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
240 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
241 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
242 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
243 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
244 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
245 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
246 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
247 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
248 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
249 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
250 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
251 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
252 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
253 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
254 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
255 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
256 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
257 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
258 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
259 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
260 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
261 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
262 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
263 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
264 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
265 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
266 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
267 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
268 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
269 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
270 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
271 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
272 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
273 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
274 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
275 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
276 | };
277 |
278 | static uint32_t crc32(const char *buf, unsigned int size) {
279 | const char *p;
280 | uint32_t crc = 0 ^ 0xFFFFFFFF;
281 |
282 | p = buf;
283 | while (size--) {
284 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
285 | }
286 |
287 | return crc ^ 0xFFFFFFFF;
288 | }
289 | /* }}} */
290 |
291 | #if HAVE_SSE_CRC32
292 | static uint32_t crc32c_sse42(const char *buf, unsigned int size) /* {{{ */ {
293 | uint32_t crc = 0 ^ 0xFFFFFFFF;
294 | #if __x86_64__
295 | while (size >= sizeof(uint64_t)) {
296 | crc = _mm_crc32_u64(crc, *(uint64_t*)buf);
297 | buf += sizeof(uint64_t);
298 | size -= sizeof(uint64_t);
299 | }
300 | #endif
301 | while (size >= sizeof(uint32_t)) {
302 | crc = _mm_crc32_u32(crc, *(uint32_t*)buf);
303 | buf += sizeof(uint32_t);
304 | size -= sizeof(uint32_t);
305 | }
306 | if (size >= sizeof(uint16_t)) {
307 | crc = _mm_crc32_u16(crc, *(uint16_t*)buf);
308 | buf += sizeof(uint16_t);
309 | size -= sizeof(uint16_t);
310 | }
311 | if (size) {
312 | crc = _mm_crc32_u8(crc, *buf);
313 | }
314 |
315 | return crc ^ 0xFFFFFFFF;
316 | }
317 | /* }}} */
318 | #endif
319 |
320 | static inline unsigned int yac_crc32(char *data, unsigned int size) /* {{{ */ {
321 | if (size < YAC_FULL_CRC_THRESHOLD) {
322 | return yac_crc(data, size);
323 | } else {
324 | int i = 0;
325 | char crc_contents[YAC_FULL_CRC_THRESHOLD];
326 | int head = YAC_FULL_CRC_THRESHOLD >> 2;
327 | int tail = YAC_FULL_CRC_THRESHOLD >> 4;
328 | int body = YAC_FULL_CRC_THRESHOLD - head - tail;
329 | char *p = data + head;
330 | char *q = crc_contents + head;
331 | int step = (size - tail - head) / body;
332 |
333 | memcpy(crc_contents, data, head);
334 | for (; i < body; i++, q++, p+= step) {
335 | *q = *p;
336 | }
337 | memcpy(q, p, tail);
338 |
339 | return yac_crc(crc_contents, YAC_FULL_CRC_THRESHOLD);
340 | }
341 | }
342 | /* }}} */
343 |
344 | int yac_storage_find(const char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv) /* {{{ */ {
345 | uint64_t h, hash, seed;
346 | yac_kv_key k, *p;
347 | yac_kv_val v;
348 |
349 | hash = h = yac_inline_hash_func1(key, len);
350 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
351 | if (!WRITEP(p)) {
352 | ++YAC_SG(miss);
353 | return 0;
354 | }
355 | k = *p;
356 | READP(p);
357 | if (k.val) {
358 | char *s;
359 | uint32_t i;
360 | if (k.h == hash && YAC_KEY_KLEN(k) == len) {
361 | v = *(k.val);
362 | if (!memcmp(k.key, key, len)) {
363 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1);
364 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k));
365 | do_verify:
366 | if (k.len != v.len) {
367 | USER_FREE(s);
368 | ++YAC_SG(miss);
369 | return 0;
370 | }
371 |
372 | if (k.ttl) {
373 | if (k.ttl <= tv) {
374 | ++YAC_SG(miss);
375 | USER_FREE(s);
376 | return 0;
377 | }
378 | }
379 |
380 | if (k.crc != yac_crc32(s, YAC_KEY_VLEN(k))) {
381 | USER_FREE(s);
382 | ++YAC_SG(miss);
383 | return 0;
384 | }
385 | s[YAC_KEY_VLEN(k)] = '\0';
386 | k.val->atime = tv;
387 | *data = s;
388 | *size = YAC_KEY_VLEN(k);
389 | *flag = k.flag;
390 | ++YAC_SG(hits);
391 | return 1;
392 | }
393 | }
394 |
395 | seed = yac_inline_hash_func2(key, len);
396 | for (i = 0; i < 3; i++) {
397 | h += seed & YAC_SG(slots_mask);
398 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
399 | if (!WRITEP(p)) {
400 | ++YAC_SG(miss);
401 | return 0;
402 | }
403 | k = *p;
404 | READP(p);
405 | if (k.h == hash && YAC_KEY_KLEN(k) == len) {
406 | v = *(k.val);
407 | if (!memcmp(k.key, key, len)) {
408 | s = USER_ALLOC(YAC_KEY_VLEN(k) + 1);
409 | memcpy(s, (char *)k.val->data, YAC_KEY_VLEN(k));
410 | goto do_verify;
411 | }
412 | }
413 | }
414 | }
415 |
416 | ++YAC_SG(miss);
417 |
418 | return 0;
419 | }
420 | /* }}} */
421 |
422 | int yac_storage_delete(const char *key, unsigned int len, int ttl, unsigned long tv) /* {{{ */ {
423 | uint64_t hash, h, seed;
424 | yac_kv_key k, *p;
425 |
426 | hash = h = yac_inline_hash_func1(key, len);
427 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
428 | if (!WRITEP(p)) {
429 | return 0;
430 | }
431 | k = *p;
432 | READP(p);
433 | if (k.val) {
434 | uint32_t i;
435 | if (k.h == hash && YAC_KEY_KLEN(k) == len) {
436 | if (!memcmp((char *)k.key, key, len)) {
437 | if (ttl == 0) {
438 | p->ttl = 1;
439 | } else {
440 | p->ttl = ttl + tv;
441 | }
442 | return 1;
443 | }
444 | }
445 |
446 | seed = yac_inline_hash_func2(key, len);
447 | for (i = 0; i < 3; i++) {
448 | h += seed & YAC_SG(slots_mask);
449 | p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
450 | if (!WRITEP(p)) {
451 | return 0;
452 | }
453 | k = *p;
454 | READP(p);
455 | if (k.val == NULL) {
456 | return 1;
457 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) {
458 | p->ttl = 1;
459 | return 1;
460 | }
461 | }
462 | }
463 |
464 | return 0;
465 | }
466 | /* }}} */
467 |
468 | int yac_storage_update(const char *key, unsigned int len, char *data, unsigned int size, unsigned int flag, int ttl, int add, unsigned long tv) /* {{{ */ {
469 | uint64_t hash, h;
470 | int idx = 0, is_valid;
471 | yac_kv_key *p, k, *paths[4];
472 | yac_kv_val *val, *s;
473 | unsigned long real_size;
474 |
475 | hash = h = yac_inline_hash_func1(key, len);
476 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
477 | if (!WRITEP(p)) {
478 | return 0;
479 | }
480 | k = *p;
481 | READP(p);
482 | if (k.val) {
483 | /* Found the exact match */
484 | if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) {
485 | do_update:
486 | is_valid = 0;
487 | if (k.crc == yac_crc32(k.val->data, YAC_KEY_VLEN(k))) {
488 | is_valid = 1;
489 | }
490 | if (add && (!k.ttl || k.ttl > tv) && is_valid) {
491 | return 0;
492 | }
493 | if (k.size >= size && is_valid) {
494 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1);
495 | memcpy(s->data, data, size);
496 | if (ttl) {
497 | k.ttl = (uint64_t)tv + ttl;
498 | } else {
499 | k.ttl = 0;
500 | }
501 | s->atime = tv;
502 | YAC_KEY_SET_LEN(*s, len, size);
503 | memcpy((char *)k.val, (char *)s, sizeof(yac_kv_val) + size - 1);
504 | k.crc = yac_crc32(s->data, size);
505 | k.flag = flag;
506 | memcpy(k.key, key, len);
507 | YAC_KEY_SET_LEN(k, len, size);
508 | if (!WRITEP(p)) {
509 | USER_FREE(s);
510 | return 0;
511 | }
512 | *p = k;
513 | READP(p);
514 | USER_FREE(s);
515 | return 1;
516 | } else {
517 | uint32_t msize;
518 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1);
519 | if (!real_size) {
520 | ++YAC_SG(fails);
521 | return 0;
522 | }
523 | msize = sizeof(yac_kv_val) + size - 1;
524 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1);
525 | memcpy(s->data, data, size);
526 | s->atime = tv;
527 | YAC_KEY_SET_LEN(*s, len, size);
528 | val = yac_allocator_raw_alloc(real_size, (int)hash);
529 | if (val) {
530 | memcpy((char *)val, (char *)s, msize);
531 | if (ttl) {
532 | k.ttl = tv + ttl;
533 | } else {
534 | k.ttl = 0;
535 | }
536 | k.crc = yac_crc32(s->data, size);
537 | k.val = val;
538 | k.flag = flag;
539 | k.size = real_size;
540 | memcpy(k.key, key, len);
541 | YAC_KEY_SET_LEN(k, len, size);
542 | if (!WRITEP(p)) {
543 | USER_FREE(s);
544 | return 0;
545 | }
546 | *p = k;
547 | READP(p);
548 | USER_FREE(s);
549 | return 1;
550 | }
551 | ++YAC_SG(fails);
552 | USER_FREE(s);
553 | return 0;
554 | }
555 | } else {
556 | uint32_t i;
557 | uint64_t seed, max_atime;
558 |
559 | seed = yac_inline_hash_func2(key, len);
560 | for (i = 0; i < 3; i++) {
561 | h += seed & YAC_SG(slots_mask);
562 | paths[idx++] = p = &(YAC_SG(slots)[h & YAC_SG(slots_mask)]);
563 | if (!WRITEP(p)) {
564 | return 0;
565 | }
566 | k = *p;
567 | READP(p);
568 | if (k.val == NULL) {
569 | goto do_add;
570 | } else if (k.h == hash && YAC_KEY_KLEN(k) == len && !memcmp((char *)k.key, key, len)) {
571 | /* Found the exact match */
572 | goto do_update;
573 | }
574 | }
575 |
576 | --idx;
577 | max_atime = paths[idx]->val->atime;
578 | for (i = 0; i < idx; i++) {
579 | if ((paths[i]->ttl && paths[i]->ttl <= tv) || paths[i]->len != paths[i]->val->len) {
580 | p = paths[i];
581 | goto do_add;
582 | } else if (paths[i]->val->atime < max_atime) {
583 | max_atime = paths[i]->val->atime;
584 | p = paths[i];
585 | }
586 | }
587 | if (!WRITEP(p)) {
588 | return 0;
589 | }
590 | k = *p;
591 | READP(p);
592 | ++YAC_SG(kicks);
593 | k.h = hash;
594 |
595 | goto do_update;
596 | }
597 | } else {
598 | do_add:
599 | real_size = yac_allocator_real_size(sizeof(yac_kv_val) + (size * YAC_STORAGE_FACTOR) - 1);
600 | if (!real_size) {
601 | ++YAC_SG(fails);
602 | return 0;
603 | }
604 | s = USER_ALLOC(sizeof(yac_kv_val) + size - 1);
605 | memcpy(s->data, data, size);
606 | s->atime = tv;
607 | YAC_KEY_SET_LEN(*s, len, size);
608 | val = yac_allocator_raw_alloc(real_size, (int)hash);
609 | if (val) {
610 | memcpy((char *)val, (char *)s, sizeof(yac_kv_val) + size - 1);
611 | if (p->val == NULL) {
612 | ++YAC_SG(slots_num);
613 | }
614 | k.h = hash;
615 | k.val = val;
616 | k.flag = flag;
617 | k.size = real_size;
618 | k.crc = yac_crc32(s->data, size);
619 | memcpy(k.key, key, len);
620 | YAC_KEY_SET_LEN(k, len, size);
621 | if (ttl) {
622 | k.ttl = tv + ttl;
623 | } else {
624 | k.ttl = 0;
625 | }
626 | if (!WRITEP(p)) {
627 | USER_FREE(s);
628 | return 0;
629 | }
630 | *p = k;
631 | READP(p);
632 | USER_FREE(s);
633 | return 1;
634 | }
635 | ++YAC_SG(fails);
636 | USER_FREE(s);
637 | }
638 | return 0;
639 | }
640 | /* }}} */
641 |
642 | void yac_storage_flush(void) /* {{{ */ {
643 | YAC_SG(slots_num) = 0;
644 |
645 | memset((char *)YAC_SG(slots), 0, sizeof(yac_kv_key) * YAC_SG(slots_size));
646 | }
647 | /* }}} */
648 |
649 | yac_storage_info * yac_storage_get_info(void) /* {{{ */ {
650 | yac_storage_info *info = USER_ALLOC(sizeof(yac_storage_info));
651 |
652 | info->k_msize = (unsigned long)YAC_SG(first_seg).size;
653 | info->v_msize = (unsigned long)YAC_SG(segments)[0]->size * (unsigned long)YAC_SG(segments_num);
654 | info->segment_size = YAC_SG(segments)[0]->size;
655 | info->segments_num = YAC_SG(segments_num);
656 | info->hits = YAC_SG(hits);
657 | info->miss = YAC_SG(miss);
658 | info->fails = YAC_SG(fails);
659 | info->kicks = YAC_SG(kicks);
660 | info->recycles = YAC_SG(recycles);
661 | info->slots_size = YAC_SG(slots_size);
662 | info->slots_num = YAC_SG(slots_num);
663 |
664 | return info;
665 | }
666 | /* }}} */
667 |
668 | void yac_storage_free_info(yac_storage_info *info) /* {{{ */ {
669 | USER_FREE(info);
670 | }
671 | /* }}} */
672 |
673 | yac_item_list * yac_storage_dump(unsigned int limit) /* {{{ */ {
674 | yac_kv_key k;
675 | yac_item_list *item, *list = NULL;
676 |
677 | if (YAC_SG(slots_num)) {
678 | unsigned int i = 0, n = 0;
679 | for (; iindex = i;
684 | item->h = k.h;
685 | item->crc = k.crc;
686 | item->ttl = k.ttl;
687 | item->k_len = YAC_KEY_KLEN(k);
688 | item->v_len = YAC_KEY_VLEN(k);
689 | item->flag = k.flag;
690 | item->size = k.size;
691 | memcpy(item->key, k.key, YAC_STORAGE_MAX_KEY_LEN);
692 | item->next = list;
693 | list = item;
694 | ++n;
695 | }
696 | }
697 | }
698 |
699 | return list;
700 | }
701 | /* }}} */
702 |
703 | void yac_storage_free_list(yac_item_list *list) /* {{{ */ {
704 | yac_item_list *l;
705 | while (list) {
706 | l = list;
707 | list = list->next;
708 | USER_FREE(l);
709 | }
710 | }
711 | /* }}} */
712 |
713 | const char * yac_storage_shared_memory_name(void) /* {{{ */ {
714 | return YAC_SHARED_MEMORY_HANDLER_NAME;
715 | }
716 | /* }}} */
717 |
718 | /*
719 | * Local variables:
720 | * tab-width: 4
721 | * c-basic-offset: 4
722 | * End:
723 | * vim600: noet sw=4 ts=4 fdm=marker
724 | * vim<600: noet sw=4 ts=4
725 | */
726 |
--------------------------------------------------------------------------------
/storage/yac_storage.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifndef YAC_STORAGE_H
22 | #define YAC_STORAGE_H
23 |
24 | #define YAC_STORAGE_MAX_ENTRY_LEN (1 << 20)
25 | #define YAC_STORAGE_MAX_KEY_LEN (48)
26 | #define YAC_STORAGE_FACTOR (1.25)
27 | #define YAC_KEY_KLEN_MASK (255)
28 | #define YAC_KEY_VLEN_BITS (8)
29 | #define YAC_KEY_KLEN(k) ((k).len & YAC_KEY_KLEN_MASK)
30 | #define YAC_KEY_VLEN(k) ((k).len >> YAC_KEY_VLEN_BITS)
31 | #define YAC_KEY_SET_LEN(k, kl, vl) ((k).len = (vl << YAC_KEY_VLEN_BITS) | (kl & YAC_KEY_KLEN_MASK))
32 | #define YAC_FULL_CRC_THRESHOLD 256
33 |
34 | #define USER_ALLOC emalloc
35 | #define USER_FREE efree
36 |
37 | typedef struct {
38 | unsigned long atime;
39 | unsigned int len;
40 | char data[1];
41 | } yac_kv_val;
42 |
43 | typedef struct {
44 | unsigned long h;
45 | unsigned int crc;
46 | unsigned int ttl;
47 | unsigned int len;
48 | unsigned int flag;
49 | unsigned int size;
50 | unsigned int mutex;
51 | yac_kv_val *val;
52 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN];
53 | } yac_kv_key;
54 |
55 | typedef struct _yac_item_list {
56 | unsigned int index;
57 | unsigned long h;
58 | unsigned long crc;
59 | unsigned int ttl;
60 | unsigned int k_len;
61 | unsigned int v_len;
62 | unsigned int flag;
63 | unsigned int size;
64 | unsigned char key[YAC_STORAGE_MAX_KEY_LEN];
65 | struct _yac_item_list *next;
66 | } yac_item_list;
67 |
68 | typedef struct {
69 | volatile unsigned int pos;
70 | unsigned int size;
71 | void *p;
72 | } yac_shared_segment;
73 |
74 | typedef struct {
75 | unsigned long k_msize;
76 | unsigned long v_msize;
77 | unsigned int segments_num;
78 | unsigned int segment_size;
79 | unsigned int slots_num;
80 | unsigned int slots_size;
81 | unsigned int miss;
82 | unsigned int fails;
83 | unsigned int kicks;
84 | unsigned int recycles;
85 | unsigned long hits;
86 | } yac_storage_info;
87 |
88 | typedef struct {
89 | yac_kv_key *slots;
90 | unsigned int slots_mask;
91 | unsigned int slots_num;
92 | unsigned int slots_size;
93 | unsigned int miss;
94 | unsigned int fails;
95 | unsigned int kicks;
96 | unsigned int recycles;
97 | unsigned long hits;
98 | yac_shared_segment **segments;
99 | unsigned int segments_num;
100 | unsigned int segments_num_mask;
101 | yac_shared_segment first_seg;
102 | } yac_storage_globals;
103 |
104 | extern yac_storage_globals *yac_storage;
105 |
106 | #define YAC_SG(element) (yac_storage->element)
107 |
108 | int yac_storage_startup(unsigned long first_size, unsigned long size, char **err);
109 | void yac_storage_shutdown(void);
110 | int yac_storage_find(const char *key, unsigned int len, char **data, unsigned int *size, unsigned int *flag, int *cas, unsigned long tv);
111 | int yac_storage_update(const char *key, unsigned int len, char *data, unsigned int size, unsigned int falg, int ttl, int add, unsigned long tv);
112 | int yac_storage_delete(const char *key, unsigned int len, int ttl, unsigned long tv);
113 | void yac_storage_flush(void);
114 | const char * yac_storage_shared_memory_name(void);
115 | yac_storage_info * yac_storage_get_info(void);
116 | void yac_storage_free_info(yac_storage_info *info);
117 | yac_item_list * yac_storage_dump(unsigned int limit);
118 | void yac_storage_free_list(yac_item_list *list);
119 | #define yac_storage_exists(ht, key, len) yac_storage_find(ht, key, len, NULL)
120 |
121 | #endif /* YAC_STORAGE_H */
122 |
123 | /*
124 | * Local variables:
125 | * tab-width: 4
126 | * c-basic-offset: 4
127 | * End:
128 | * vim600: noet sw=4 ts=4 fdm=marker
129 | * vim<600: noet sw=4 ts=4
130 | */
131 |
--------------------------------------------------------------------------------
/tests/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac presence
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
20 | --EXPECT--
21 | yac extension is available
22 |
--------------------------------------------------------------------------------
/tests/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac basic functions
3 | --SKIPIF--
4 |
5 | --INI--
6 | yac.enable=1
7 | yac.enable_cli=1
8 | yac.keys_memory_size=4M
9 | yac.values_memory_size=32M
10 | yac.serializer=php
11 | --FILE--
12 | set($key, $value));
21 | var_dump($yac->get($key));
22 |
23 | $value = NULL;
24 | var_dump($yac->set($key, $value));
25 | var_dump($yac->get($key));
26 |
27 | $value = TRUE;
28 | var_dump($yac->set($key, $value));
29 | var_dump($yac->get($key));
30 |
31 | $value = FALSE;
32 | var_dump($yac->set($key, $value));
33 | var_dump($yac->get($key));
34 |
35 | $value = range(1, 5);
36 | var_dump($yac->set($key, $value));
37 | var_dump($yac->get($key));
38 |
39 | $value = 9234324;
40 | var_dump($yac->set($key, $value));
41 | var_dump($yac->get($key));
42 |
43 | $value = 9234324.123456;
44 | var_dump($yac->set($key, $value));
45 | var_dump($yac->get($key));
46 |
47 | $value = new StdClass();;
48 | var_dump($yac->set($key, $value));
49 | var_dump($yac->get($key));
50 |
51 | $value = fopen("php://input", "r");
52 | var_dump($yac->set($key, $value));
53 |
54 | $value = range(1, 5);
55 | var_dump($yac->set($key, $value));
56 | var_dump($yac->delete($key));
57 | var_dump($yac->get($key));
58 |
59 | ?>
60 | --EXPECTF--
61 | bool(true)
62 | bool(true)
63 | string(5) "dummy"
64 | bool(true)
65 | NULL
66 | bool(true)
67 | bool(true)
68 | bool(true)
69 | bool(false)
70 | bool(true)
71 | array(5) {
72 | [0]=>
73 | int(1)
74 | [1]=>
75 | int(2)
76 | [2]=>
77 | int(3)
78 | [3]=>
79 | int(4)
80 | [4]=>
81 | int(5)
82 | }
83 | bool(true)
84 | int(9234324)
85 | bool(true)
86 | float(9234324.123456)
87 | bool(true)
88 | object(stdClass)#3 (0) {
89 | }
90 |
91 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s002.php on line %d
92 | bool(false)
93 | bool(true)
94 | bool(true)
95 | bool(false)
96 |
--------------------------------------------------------------------------------
/tests/003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac errors
3 | --SKIPIF--
4 |
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 | set($key, $value));
18 | var_dump($yac->get($key));
19 |
20 | $key = str_repeat("k", YAC_MAX_KEY_LEN);
21 | var_dump($yac->set($key, $value));
22 | var_dump($yac->get($key));
23 |
24 | $key = str_repeat("k", YAC_MAX_KEY_LEN + 1);
25 | var_dump($yac->set($key, $value));
26 | var_dump($yac->get($key));
27 |
28 | $yac = new Yac("dummy");
29 | var_dump($yac->set($key, $value));
30 | var_dump($yac->get($key));
31 | ?>
32 | --EXPECTF--
33 | bool(true)
34 | NULL
35 | bool(true)
36 | NULL
37 |
38 | Warning: Yac::set(): Key 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d
39 | bool(false)
40 |
41 | Warning: Yac::get(): Key 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d
42 | bool(false)
43 |
44 | Warning: Yac::set(): Key 'dummykkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d
45 | bool(false)
46 |
47 | Warning: Yac::get(): Key 'dummykkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' exceed max key length '48' bytes in %s003.php on line %d
48 | bool(false)
49 |
50 |
--------------------------------------------------------------------------------
/tests/004.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac ttl
3 | --SKIPIF--
4 |
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 | set($key, $value, 1));
18 | var_dump($yac->get($key));
19 | sleep(1);
20 | var_dump($yac->get($key));
21 |
22 | var_dump($yac->set($key, $value));
23 | var_dump($yac->get($key));
24 | var_dump($yac->delete($key, 1));
25 | var_dump($yac->get($key));
26 | sleep(1);
27 | var_dump($yac->get($key));
28 |
29 | ?>
30 | --EXPECTF--
31 | bool(true)
32 | string(5) "dummy"
33 | bool(false)
34 | bool(true)
35 | string(5) "dummy"
36 | bool(true)
37 | string(5) "dummy"
38 | bool(false)
39 |
--------------------------------------------------------------------------------
/tests/005.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac non-string key
3 | --SKIPIF--
4 |
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 | set($key, $value, 1));
18 | var_dump($yac->get($key));
19 |
20 | $key = 12345.12345;
21 | var_dump($yac->set($key, $value, 1));
22 | var_dump($yac->get($key));
23 |
24 | $key = range(1, 2);
25 | var_dump($yac->set($key, $value, 1));
26 | var_dump($yac->get($key));
27 |
28 | $key = new StdClass();
29 | var_dump($yac->set($key, $value, 1));
30 | var_dump($yac->get($key));
31 | ?>
32 | --EXPECTF--
33 | bool(true)
34 | string(5) "dummy"
35 | bool(true)
36 | string(5) "dummy"
37 | bool(true)
38 | array(2) {
39 | [1]=>
40 | int(2)
41 | [2]=>
42 | bool(false)
43 | }
44 |
45 | %s error:%sObject of class stdClass could not be converted to string in %s005.php%A
46 |
--------------------------------------------------------------------------------
/tests/006.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac multi set/get
3 | --SKIPIF--
4 |
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 | set($key, $value)) {
20 | var_dump($key, $value);
21 | var_dump("write " . $i);
22 | }
23 |
24 | if ($value != ($new = $yac->get($key))) {
25 | var_dump($new);
26 | var_dump("read " . $i);
27 | }
28 | }
29 |
30 | var_dump($i);
31 | --EXPECTF--
32 | int(1000)
33 |
--------------------------------------------------------------------------------
/tests/007.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac info
3 | --SKIPIF--
4 |
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 | set($key, $value)) {
20 | var_dump($key, $value);
21 | var_dump("write " . $i);
22 | }
23 |
24 | if ($value != ($new = $yac->get($key))) {
25 | var_dump($new);
26 | var_dump("read " . $i);
27 | }
28 | }
29 |
30 | $info = $yac->info();
31 | var_dump($info['slots_used'] <= 1000);
32 | var_dump($info['hits']);
33 | var_dump($info['miss']);
34 | var_dump($info['fails']);
35 | var_dump($info['kicks']);
36 | --EXPECTF--
37 | bool(true)
38 | int(1000)
39 | int(0)
40 | int(0)
41 | int(0)
42 |
--------------------------------------------------------------------------------
/tests/008.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac prefix
3 | --SKIPIF--
4 |
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 | set($key, $value);
19 | var_dump($yac->get($key)); //true
20 | var_dump($yac2->get($key)); //false
21 | var_dump($yac2->get("dummy_" . $key)); //true
22 |
23 | $yac2->delete($key); //fail
24 | var_dump($yac->get($key)); //true
25 |
26 | $yac->delete($key); //okey
27 | var_dump($yac->get($key)); //false
28 |
29 | $yac->set($key, $value);
30 | $yac2->delete("dummy_" . $key); //okey
31 | var_dump($yac->get($key)); //false
32 | ?>
33 | --EXPECTF--
34 | bool(true)
35 | bool(false)
36 | bool(true)
37 | bool(true)
38 | bool(false)
39 | bool(false)
40 |
--------------------------------------------------------------------------------
/tests/009.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac multi ops
3 | --SKIPIF--
4 |
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 | set($values));
25 |
26 | $keys = array_keys($values);
27 | $ret = $yac->get($keys);
28 | var_dump(count(array_filter($ret)) == $numbers);
29 |
30 | $disable = array_slice($keys, 0, -10);
31 | $yac->delete($disable);
32 |
33 | $ret = $yac->get($keys);
34 | var_dump(count(array_filter($ret)) == 10);
35 | ?>
36 | --EXPECTF--
37 | bool(true)
38 | bool(true)
39 | bool(true)
40 |
--------------------------------------------------------------------------------
/tests/010.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac::flush
3 | --SKIPIF--
4 |
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 | set($values));
25 |
26 | $yac->flush();
27 |
28 | var_dump($yac->get($key));
29 | $info = $yac->info();
30 | var_dump($info['slots_used']);
31 | ?>
32 | --EXPECTF--
33 | bool(true)
34 | bool(false)
35 | int(0)
36 |
--------------------------------------------------------------------------------
/tests/011.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac::add
3 | --SKIPIF--
4 |
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 | add($key, $value)); // true
17 | var_dump($yac->add($key, $value)); // false
18 | var_dump($yac->set($key, $value)); // true
19 | var_dump($yac->get($key)); // foo
20 | var_dump($yac->delete($key)); // true
21 | $value = "bar";
22 | var_dump($yac->add($key, $value, 1)); //true
23 | var_dump($yac->add($key, $value, 1)); //false
24 | var_dump($yac->get($key)); //bar
25 | sleep(1);
26 | var_dump($yac->add($key, $value)); //true
27 |
28 | ?>
29 | --EXPECTF--
30 | bool(true)
31 | bool(false)
32 | bool(true)
33 | string(3) "foo"
34 | bool(true)
35 | bool(true)
36 | bool(false)
37 | string(3) "bar"
38 | bool(true)
39 |
--------------------------------------------------------------------------------
/tests/012.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for functional apis
3 | --SKIPIF--
4 |
8 | --INI--
9 | yac.enable=1
10 | yac.enable_cli=1
11 | yac.keys_memory_size=4M
12 | yac.values_memory_size=32M
13 | --FILE--
14 |
26 | --EXPECTF--
27 | bool(true)
28 | bool(false)
29 | string(3) "foo"
30 | bool(true)
31 | bool(true)
32 | bool(true)
33 | int(0)
34 |
--------------------------------------------------------------------------------
/tests/013.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for ttl bug
3 | --SKIPIF--
4 |
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 | set('test', 1, 1);
14 | sleep(2);
15 | var_dump($yac->get('test'));
16 | ?>
17 | --EXPECTF--
18 | bool(false)
19 |
--------------------------------------------------------------------------------
/tests/014.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for ttl bug
3 | --SKIPIF--
4 |
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 | set('test', $value);
21 |
22 | echo count($yac->get('test'));
23 | ?>
24 | --EXPECTF--
25 | 100
26 |
--------------------------------------------------------------------------------
/tests/015.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for Yac::dump
3 | --SKIPIF--
4 |
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 | set("key". $i, "kjslkdfkldasjkf");
17 | }
18 | for ($i = 0; $i<100; $i++) {
19 | $yac->set("key". $i, "kjslkdfkldasjkf");
20 | }
21 |
22 | var_dump(count($yac->dump(1000)));
23 | --EXPECTF--
24 | int(100)
25 |
--------------------------------------------------------------------------------
/tests/016.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for Yac setter/getter
3 | --SKIPIF--
4 |
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 | name = "test";
16 |
17 | var_dump($yac->name);
18 | var_dump($yac->get("name"));
19 | ?>
20 | --EXPECTF--
21 | string(4) "test"
22 | string(4) "test"
23 |
--------------------------------------------------------------------------------
/tests/017.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for mutiple process
3 | --SKIPIF--
4 |
5 |
6 | --INI--
7 | yac.enable=1
8 | yac.enable_cli=1
9 | yac.keys_memory_size=4M
10 | yac.values_memory_size=32M
11 | yac.compress_threshold=1024
12 | --FILE--
13 | set("parent", "FIN"));
18 | while (!($msg = $yac->get("child")));
19 | echo "MSG From Child:", $msg,"\n";
20 | while(!($yac->set("parent", "BYE")));
21 | pcntl_wait($status);
22 | echo "Parent exiting\n";
23 | } else {
24 | while(!($msg = $yac->get("parent")));
25 | echo "MSG From Parent:" , $msg, "\n";
26 | while(!($yac->set("child", "ACK")));
27 | while(($msg = $yac->get("parent")) != "BYE");
28 | echo "Child exiting\n";
29 | }
30 | ?>
31 | --EXPECT--
32 | MSG From Parent:FIN
33 | MSG From Child:ACK
34 | Child exiting
35 | Parent exiting
36 |
--------------------------------------------------------------------------------
/tests/018.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac with json serializer
3 | --SKIPIF--
4 |
5 |
6 | --INI--
7 | yac.enable=1
8 | yac.enable_cli=1
9 | yac.keys_memory_size=4M
10 | yac.values_memory_size=32M
11 | yac.serializer=json
12 | --FILE--
13 | set($key, $value));
21 | var_dump($yac->get($key));
22 |
23 | $value = NULL;
24 | var_dump($yac->set($key, $value));
25 | var_dump($yac->get($key));
26 |
27 | $value = TRUE;
28 | var_dump($yac->set($key, $value));
29 | var_dump($yac->get($key));
30 |
31 | $value = FALSE;
32 | var_dump($yac->set($key, $value));
33 | var_dump($yac->get($key));
34 |
35 | $value = range(1, 5);
36 | var_dump($yac->set($key, $value));
37 | var_dump($yac->get($key));
38 |
39 | $value = 9234324;
40 | var_dump($yac->set($key, $value));
41 | var_dump($yac->get($key));
42 |
43 | $value = 9234324.123456;
44 | var_dump($yac->set($key, $value));
45 | var_dump($yac->get($key));
46 |
47 | $value = new StdClass();;
48 | var_dump($yac->set($key, $value));
49 | var_dump($yac->get($key));
50 |
51 | $value = fopen("php://input", "r");
52 | var_dump($yac->set($key, $value));
53 |
54 | $value = range(1, 5);
55 | var_dump($yac->set($key, $value));
56 | var_dump($yac->delete($key));
57 | var_dump($yac->get($key));
58 |
59 | ?>
60 | --EXPECTF--
61 | bool(true)
62 | bool(true)
63 | string(5) "dummy"
64 | bool(true)
65 | NULL
66 | bool(true)
67 | bool(true)
68 | bool(true)
69 | bool(false)
70 | bool(true)
71 | array(5) {
72 | [0]=>
73 | int(1)
74 | [1]=>
75 | int(2)
76 | [2]=>
77 | int(3)
78 | [3]=>
79 | int(4)
80 | [4]=>
81 | int(5)
82 | }
83 | bool(true)
84 | int(9234324)
85 | bool(true)
86 | float(9234324.123456)
87 | bool(true)
88 | array(0) {
89 | }
90 |
91 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s018.php on line %d
92 | bool(false)
93 | bool(true)
94 | bool(true)
95 | bool(false)
96 |
--------------------------------------------------------------------------------
/tests/019.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac with msgpack serializer
3 | --SKIPIF--
4 |
5 |
6 | --INI--
7 | yac.enable=1
8 | yac.enable_cli=1
9 | yac.keys_memory_size=4M
10 | yac.values_memory_size=32M
11 | yac.serializer=msgpack
12 | --FILE--
13 | set($key, $value));
21 | var_dump($yac->get($key));
22 |
23 | $value = NULL;
24 | var_dump($yac->set($key, $value));
25 | var_dump($yac->get($key));
26 |
27 | $value = TRUE;
28 | var_dump($yac->set($key, $value));
29 | var_dump($yac->get($key));
30 |
31 | $value = FALSE;
32 | var_dump($yac->set($key, $value));
33 | var_dump($yac->get($key));
34 |
35 | $value = range(1, 5);
36 | var_dump($yac->set($key, $value));
37 | var_dump($yac->get($key));
38 |
39 | $value = 9234324;
40 | var_dump($yac->set($key, $value));
41 | var_dump($yac->get($key));
42 |
43 | $value = 9234324.123456;
44 | var_dump($yac->set($key, $value));
45 | var_dump($yac->get($key));
46 |
47 | $value = new StdClass();;
48 | var_dump($yac->set($key, $value));
49 | var_dump($yac->get($key));
50 |
51 | $value = fopen("php://input", "r");
52 | var_dump($yac->set($key, $value));
53 |
54 | $value = range(1, 5);
55 | var_dump($yac->set($key, $value));
56 | var_dump($yac->delete($key));
57 | var_dump($yac->get($key));
58 |
59 | ?>
60 | --EXPECTF--
61 | bool(true)
62 | bool(true)
63 | string(5) "dummy"
64 | bool(true)
65 | NULL
66 | bool(true)
67 | bool(true)
68 | bool(true)
69 | bool(false)
70 | bool(true)
71 | array(5) {
72 | [0]=>
73 | int(1)
74 | [1]=>
75 | int(2)
76 | [2]=>
77 | int(3)
78 | [3]=>
79 | int(4)
80 | [4]=>
81 | int(5)
82 | }
83 | bool(true)
84 | int(9234324)
85 | bool(true)
86 | float(9234324.123456)
87 | bool(true)
88 | object(stdClass)#%d (0) {
89 | }
90 |
91 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s019.php on line %d
92 | bool(false)
93 | bool(true)
94 | bool(true)
95 | bool(false)
96 |
--------------------------------------------------------------------------------
/tests/020.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac with igbinary serializer
3 | --SKIPIF--
4 |
5 |
6 | --INI--
7 | yac.enable=1
8 | yac.enable_cli=1
9 | yac.keys_memory_size=4M
10 | yac.values_memory_size=32M
11 | yac.serializer=igbinary
12 | --FILE--
13 | set($key, $value));
21 | var_dump($yac->get($key));
22 |
23 | $value = NULL;
24 | var_dump($yac->set($key, $value));
25 | var_dump($yac->get($key));
26 |
27 | $value = TRUE;
28 | var_dump($yac->set($key, $value));
29 | var_dump($yac->get($key));
30 |
31 | $value = FALSE;
32 | var_dump($yac->set($key, $value));
33 | var_dump($yac->get($key));
34 |
35 | $value = range(1, 5);
36 | var_dump($yac->set($key, $value));
37 | var_dump($yac->get($key));
38 |
39 | $value = 9234324;
40 | var_dump($yac->set($key, $value));
41 | var_dump($yac->get($key));
42 |
43 | $value = 9234324.123456;
44 | var_dump($yac->set($key, $value));
45 | var_dump($yac->get($key));
46 |
47 | $value = new StdClass();;
48 | var_dump($yac->set($key, $value));
49 | var_dump($yac->get($key));
50 |
51 | $value = fopen("php://input", "r");
52 | var_dump($yac->set($key, $value));
53 |
54 | $value = range(1, 5);
55 | var_dump($yac->set($key, $value));
56 | var_dump($yac->delete($key));
57 | var_dump($yac->get($key));
58 |
59 | ?>
60 | --EXPECTF--
61 | bool(true)
62 | bool(true)
63 | string(5) "dummy"
64 | bool(true)
65 | NULL
66 | bool(true)
67 | bool(true)
68 | bool(true)
69 | bool(false)
70 | bool(true)
71 | array(5) {
72 | [0]=>
73 | int(1)
74 | [1]=>
75 | int(2)
76 | [2]=>
77 | int(3)
78 | [3]=>
79 | int(4)
80 | [4]=>
81 | int(5)
82 | }
83 | bool(true)
84 | int(9234324)
85 | bool(true)
86 | float(9234324.123456)
87 | bool(true)
88 | object(stdClass)#%d (0) {
89 | }
90 |
91 | Warning: Yac::set(): Type 'IS_RESOURCE' cannot be stored in %s020.php on line %d
92 | bool(false)
93 | bool(true)
94 | bool(true)
95 | bool(false)
96 |
--------------------------------------------------------------------------------
/tests/021.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac read/write/unset property
3 | --SKIPIF--
4 |
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 | value = "value";
15 |
16 | /* can not used in writen context */
17 | try {
18 | $yac->foo->bar = "bar";
19 | } catch (Exception $e) {};
20 |
21 | var_dump($yac->get("value"));
22 | var_dump($yac->value);
23 |
24 | var_dump($yac->get("foo"));
25 | var_dump($yac->foo);
26 |
27 | unset($yac->value);
28 | var_dump($yac->get("value"));
29 | var_dump($yac->value);
30 | ?>
31 | --EXPECT--
32 | string(5) "value"
33 | string(5) "value"
34 | bool(false)
35 | NULL
36 | bool(false)
37 | NULL
38 |
--------------------------------------------------------------------------------
/tests/022.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for yac::__construct with yac.enable=0
3 | --SKIPIF--
4 |
5 | --INI--
6 | yac.enable=0
7 | --FILE--
8 | getMessage());
13 | }
14 |
15 | @var_dump($yac);
16 | ?>
17 | --EXPECTF--
18 | string(18) "Yac is not enabled"
19 | NULL
20 |
--------------------------------------------------------------------------------
/tests/023.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for inherit from Yac
3 | --SKIPIF--
4 |
7 | --INI--
8 | yac.enable=0
9 | --FILE--
10 |
13 | --EXPECTF--
14 | Fatal error: Class Sub %s final class %s
15 |
--------------------------------------------------------------------------------
/tests/issue012.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | ISSUE #12 segfault if use mmap&k_size bigger than 4M
3 | --SKIPIF--
4 |
5 | --INI--
6 | yac.enable=1
7 | yac.enable_cli=1
8 | yac.keys_memory_size=8M
9 | yac.values_memory_size=128M
10 | --FILE--
11 | set(rand(), strval(rand()), 2);
16 | $i++;
17 | if ($i > 20000) {
18 | break;
19 | }
20 | }
21 | ?>
22 | OKEY
23 | --EXPECTF--
24 | OKEY
25 |
--------------------------------------------------------------------------------
/tests/yac_conflict.php:
--------------------------------------------------------------------------------
1 | 128M => 128M
5 | * yac.values_memory_size => 1G => 1G
6 | * and put this under document root, run with ab -c 100
7 | */
8 |
9 | $loop_count = 100;
10 | $yac = new Yac("yac_test");
11 |
12 | for ($i=0; $i<$loop_count; $i++) {
13 | $n = mt_rand(1, 100000000);
14 | $key = "key-" . $n;
15 | $value = array_fill(0, 100, $n);
16 | if (!($yac->set($key, $value))) {
17 | error_log("Set error: ". "key=". $key);
18 | }
19 | $testvalue = $yac->get($key);
20 | if ($testvalue === false) {
21 | /* this is not error */
22 | error_log("yac warning: ". "key=". $key. " Not_found\n");
23 | } else if ($testvalue !== $value) {
24 | error_log("yac error: ". "key=". $key. " Changed. <" . var_export($testvalue, 1) . "> should be <". var_export($value, 1) .">\n");
25 | }
26 | }
27 | ?>
28 |
--------------------------------------------------------------------------------
/travis/compile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | phpize && ./configure && make
3 |
--------------------------------------------------------------------------------
/yac.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Yet Another Cache |
4 | +----------------------------------------------------------------------+
5 | | Copyright (c) 2013-2013 The PHP Group |
6 | +----------------------------------------------------------------------+
7 | | This source file is subject to version 3.01 of the PHP license, |
8 | | that is bundled with this package in the file LICENSE, and is |
9 | | available through the world-wide-web at the following url: |
10 | | http://www.php.net/license/3_01.txt |
11 | | If you did not receive a copy of the PHP license and are unable to |
12 | | obtain it through the world-wide-web, please send a note to |
13 | | license@php.net so we can mail you a copy immediately. |
14 | +----------------------------------------------------------------------+
15 | | Author: Xinchen Hui |
16 | +----------------------------------------------------------------------+
17 | */
18 |
19 | /* $Id$ */
20 |
21 | #ifdef HAVE_CONFIG_H
22 | #include "config.h"
23 | #endif
24 |
25 | #include
26 |
27 | #include "php.h"
28 | #include "php_ini.h"
29 | #include "SAPI.h"
30 | #include "ext/standard/info.h"
31 | #include "Zend/zend_smart_str.h"
32 | #include "Zend/zend_exceptions.h"
33 |
34 | #include "php_yac.h"
35 | #if PHP_MAJOR_VERSION > 7
36 | #include "yac_arginfo.h"
37 | #else
38 | #include "yac_legacy_arginfo.h"
39 | #endif
40 | #include "storage/yac_storage.h"
41 | #include "serializer/yac_serializer.h"
42 | #ifdef HAVE_FASTLZ_H
43 | #include
44 | #else
45 | #include "compressor/fastlz/fastlz.h"
46 | #endif
47 |
48 | zend_class_entry *yac_class_ce;
49 |
50 | static zend_object_handlers yac_obj_handlers;
51 |
52 | typedef struct {
53 | unsigned char prefix[YAC_STORAGE_MAX_KEY_LEN];
54 | uint16_t prefix_len;
55 | zend_object std;
56 | } yac_object;
57 |
58 | ZEND_DECLARE_MODULE_GLOBALS(yac);
59 |
60 | static yac_serializer_t yac_serializer;
61 | static yac_unserializer_t yac_unserializer;
62 |
63 | static PHP_INI_MH(OnChangeKeysMemoryLimit) /* {{{ */ {
64 | if (new_value) {
65 | YAC_G(k_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
66 | }
67 | return SUCCESS;
68 | }
69 | /* }}} */
70 |
71 | static PHP_INI_MH(OnChangeValsMemoryLimit) /* {{{ */ {
72 | if (new_value) {
73 | YAC_G(v_msize) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
74 | }
75 | return SUCCESS;
76 | }
77 | /* }}} */
78 |
79 | static PHP_INI_MH(OnChangeCompressThreshold) /* {{{ */ {
80 | if (new_value) {
81 | YAC_G(compress_threshold) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
82 | if (YAC_G(compress_threshold) < YAC_MIN_COMPRESS_THRESHOLD) {
83 | YAC_G(compress_threshold) = YAC_MIN_COMPRESS_THRESHOLD;
84 | }
85 | }
86 | return SUCCESS;
87 | }
88 | /* }}} */
89 |
90 | /* {{{ PHP_INI
91 | */
92 | PHP_INI_BEGIN()
93 | STD_PHP_INI_BOOLEAN("yac.enable", "1", PHP_INI_SYSTEM, OnUpdateBool, enable, zend_yac_globals, yac_globals)
94 | STD_PHP_INI_BOOLEAN("yac.debug", "0", PHP_INI_ALL, OnUpdateBool, debug, zend_yac_globals, yac_globals)
95 | STD_PHP_INI_ENTRY("yac.keys_memory_size", "4M", PHP_INI_SYSTEM, OnChangeKeysMemoryLimit, k_msize, zend_yac_globals, yac_globals)
96 | STD_PHP_INI_ENTRY("yac.values_memory_size", "64M", PHP_INI_SYSTEM, OnChangeValsMemoryLimit, v_msize, zend_yac_globals, yac_globals)
97 | STD_PHP_INI_ENTRY("yac.compress_threshold", "-1", PHP_INI_SYSTEM, OnChangeCompressThreshold, compress_threshold, zend_yac_globals, yac_globals)
98 | STD_PHP_INI_ENTRY("yac.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_yac_globals, yac_globals)
99 | STD_PHP_INI_ENTRY("yac.serializer", "php", PHP_INI_SYSTEM, OnUpdateString, serializer, zend_yac_globals, yac_globals)
100 | PHP_INI_END()
101 | /* }}} */
102 |
103 | #define Z_YACOBJ_P(zv) (php_yac_fetch_object(Z_OBJ_P(zv)))
104 | static inline yac_object *php_yac_fetch_object(zend_object *obj) /* {{{ */ {
105 | return (yac_object *)((char*)(obj) - XtOffsetOf(yac_object, std));
106 | }
107 | /* }}} */
108 |
109 | static const char *yac_assemble_key(yac_object *yac, zend_string *name, size_t *len) /* {{{ */ {
110 | const char *key;
111 |
112 | if ((ZSTR_LEN(name) + yac->prefix_len) > YAC_STORAGE_MAX_KEY_LEN) {
113 | php_error_docref(NULL, E_WARNING,
114 | "Key '%.*s%s' exceed max key length '%d' bytes",
115 | yac->prefix_len, yac->prefix, ZSTR_VAL(name), YAC_STORAGE_MAX_KEY_LEN);
116 | return NULL;
117 | }
118 |
119 | if (yac->prefix_len) {
120 | memcpy(yac->prefix + yac->prefix_len, ZSTR_VAL(name), ZSTR_LEN(name));
121 | key = (const char*)yac->prefix;
122 | *len = yac->prefix_len + ZSTR_LEN(name);
123 | } else {
124 | key = ZSTR_VAL(name);
125 | *len = ZSTR_LEN(name);
126 | }
127 |
128 | return key;
129 | }
130 | /* }}} */
131 |
132 | static int yac_add_impl(yac_object *yac, zend_string *name, zval *value, int ttl, int add) /* {{{ */ {
133 | int ret = 0, flag = Z_TYPE_P(value);
134 | char *msg;
135 | time_t tv;
136 | const char *key;
137 | size_t key_len;
138 |
139 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
140 | return ret;
141 | }
142 |
143 | tv = time(NULL);
144 | switch (Z_TYPE_P(value)) {
145 | case IS_NULL:
146 | case IS_TRUE:
147 | case IS_FALSE:
148 | ret = yac_storage_update(key, key_len, (char *)&flag, sizeof(int), flag, ttl, add, tv);
149 | break;
150 | case IS_LONG:
151 | ret = yac_storage_update(key, key_len, (char *)&Z_LVAL_P(value), sizeof(long), flag, ttl, add, tv);
152 | break;
153 | case IS_DOUBLE:
154 | ret = yac_storage_update(key, key_len, (char *)&Z_DVAL_P(value), sizeof(double), flag, ttl, add, tv);
155 | break;
156 | case IS_STRING:
157 | #ifdef IS_CONSTANT
158 | case IS_CONSTANT:
159 | #endif
160 | {
161 | if (Z_STRLEN_P(value) > YAC_G(compress_threshold) || Z_STRLEN_P(value) > YAC_STORAGE_MAX_ENTRY_LEN) {
162 | int compressed_len;
163 | char *compressed;
164 |
165 | /* if longer than this, then we can not stored the length in flag */
166 | if (Z_STRLEN_P(value) > YAC_ENTRY_MAX_ORIG_LEN) {
167 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value));
168 | return ret;
169 | }
170 |
171 | compressed = emalloc(Z_STRLEN_P(value) * 1.05);
172 | compressed_len = fastlz_compress(Z_STRVAL_P(value), Z_STRLEN_P(value), compressed);
173 | if (!compressed_len || compressed_len > Z_STRLEN_P(value)) {
174 | php_error_docref(NULL, E_WARNING, "Compression failed");
175 | efree(compressed);
176 | return ret;
177 | }
178 |
179 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
180 | php_error_docref(NULL, E_WARNING, "Value is too long(%ld bytes) to be stored", Z_STRLEN_P(value));
181 | efree(compressed);
182 | return ret;
183 | }
184 |
185 | flag |= YAC_ENTRY_COMPRESSED;
186 | flag |= (Z_STRLEN_P(value) << YAC_ENTRY_ORIG_LEN_SHIT);
187 | ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv);
188 | efree(compressed);
189 | } else {
190 | ret = yac_storage_update(key, key_len, Z_STRVAL_P(value), Z_STRLEN_P(value), flag, ttl, add, tv);
191 | }
192 | }
193 | break;
194 | case IS_ARRAY:
195 | #ifdef IS_CONSTANT_ARRAY
196 | case IS_CONSTANT_ARRAY:
197 | #endif
198 | case IS_OBJECT:
199 | {
200 | smart_str buf = {0};
201 |
202 | if (yac_serializer(value, &buf, &msg)) {
203 | if (buf.s->len > YAC_G(compress_threshold) || buf.s->len > YAC_STORAGE_MAX_ENTRY_LEN) {
204 | int compressed_len;
205 | char *compressed;
206 |
207 | if (buf.s->len > YAC_ENTRY_MAX_ORIG_LEN) {
208 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
209 | return ret;
210 | }
211 |
212 | compressed = emalloc(buf.s->len * 1.05);
213 | compressed_len = fastlz_compress(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), compressed);
214 | if (!compressed_len || compressed_len > buf.s->len) {
215 | php_error_docref(NULL, E_WARNING, "Compression failed");
216 | efree(compressed);
217 | return ret;
218 | }
219 |
220 | if (compressed_len > YAC_STORAGE_MAX_ENTRY_LEN) {
221 | php_error_docref(NULL, E_WARNING, "Value is too big to be stored");
222 | efree(compressed);
223 | return ret;
224 | }
225 |
226 | flag |= YAC_ENTRY_COMPRESSED;
227 | flag |= (buf.s->len << YAC_ENTRY_ORIG_LEN_SHIT);
228 | ret = yac_storage_update(key, key_len, compressed, compressed_len, flag, ttl, add, tv);
229 | efree(compressed);
230 | } else {
231 | ret = yac_storage_update(key, key_len, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), flag, ttl, add, tv);
232 | }
233 | smart_str_free(&buf);
234 | } else {
235 | php_error_docref(NULL, E_WARNING, "Serialization failed");
236 | smart_str_free(&buf);
237 | }
238 | }
239 | break;
240 | case IS_RESOURCE:
241 | php_error_docref(NULL, E_WARNING, "Type 'IS_RESOURCE' cannot be stored");
242 | break;
243 | default:
244 | php_error_docref(NULL, E_WARNING, "Unsupported valued type to be stored '%d'", flag);
245 | break;
246 | }
247 |
248 | return ret;
249 | }
250 | /* }}} */
251 |
252 | static int yac_add_multi_impl(yac_object *yac, zval *kvs, int ttl, int add) /* {{{ */ {
253 | HashTable *ht = Z_ARRVAL_P(kvs);
254 | zend_string *key;
255 | zend_ulong idx;
256 | zval *value;
257 |
258 | ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, value) {
259 | uint32_t should_free = 0;
260 | if (!key) {
261 | key = strpprintf(0, "%lu", idx);
262 | should_free = 1;
263 | }
264 | if (yac_add_impl(yac, key, value, ttl, add)) {
265 | if (should_free) {
266 | zend_string_release(key);
267 | }
268 | continue;
269 | } else {
270 | if (should_free) {
271 | zend_string_release(key);
272 | }
273 | return 0;
274 | }
275 | } ZEND_HASH_FOREACH_END();
276 |
277 | return 1;
278 | }
279 | /* }}} */
280 |
281 | static zval* yac_get_impl(yac_object *yac, zend_string *name, uint32_t *cas, zval *rv) /* {{{ */ {
282 | uint32_t flag, size = 0;
283 | char *data, *msg;
284 | time_t tv;
285 | const char *key;
286 | size_t key_len;
287 |
288 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
289 | return NULL;
290 | }
291 |
292 | tv = time(NULL);
293 | if (yac_storage_find(key, key_len, &data, &size, &flag, (int *)cas, tv)) {
294 | switch ((flag & YAC_ENTRY_TYPE_MASK)) {
295 | case IS_NULL:
296 | if (size == sizeof(int)) {
297 | ZVAL_NULL(rv);
298 | }
299 | efree(data);
300 | break;
301 | case IS_TRUE:
302 | if (size == sizeof(int)) {
303 | ZVAL_TRUE(rv);
304 | }
305 | efree(data);
306 | break;
307 | case IS_FALSE:
308 | if (size == sizeof(int)) {
309 | ZVAL_FALSE(rv);
310 | }
311 | efree(data);
312 | break;
313 | case IS_LONG:
314 | if (size == sizeof(long)) {
315 | ZVAL_LONG(rv, *(long*)data);
316 | }
317 | efree(data);
318 | break;
319 | case IS_DOUBLE:
320 | if (size == sizeof(double)) {
321 | ZVAL_DOUBLE(rv, *(double*)data);
322 | }
323 | efree(data);
324 | break;
325 | case IS_STRING:
326 | #ifdef IS_CONSTANT
327 | case IS_CONSTANT:
328 | #endif
329 | {
330 | if ((flag & YAC_ENTRY_COMPRESSED)) {
331 | size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
332 | char *origin = emalloc(orig_len + 1);
333 | uint32_t length;
334 | length = fastlz_decompress(data, size, origin, orig_len);
335 | if (!length) {
336 | php_error_docref(NULL, E_WARNING, "Decompression failed");
337 | efree(data);
338 | efree(origin);
339 | return NULL;
340 | }
341 | ZVAL_STRINGL(rv, origin, length);
342 | efree(origin);
343 | efree(data);
344 | } else {
345 | ZVAL_STRINGL(rv, data, size);
346 | efree(data);
347 | }
348 | }
349 | break;
350 | case IS_ARRAY:
351 | #ifdef IS_CONSTANT_ARRAY
352 | case IS_CONSTANT_ARRAY:
353 | #endif
354 | case IS_OBJECT:
355 | {
356 | if ((flag & YAC_ENTRY_COMPRESSED)) {
357 | size_t length, orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT);
358 | char *origin = emalloc(orig_len + 1);
359 | length = fastlz_decompress(data, size, origin, orig_len);
360 | if (!length) {
361 | php_error_docref(NULL, E_WARNING, "Decompression failed");
362 | efree(data);
363 | efree(origin);
364 | return NULL;
365 | }
366 | efree(data);
367 | data = origin;
368 | size = length;
369 | }
370 | rv = yac_unserializer(data, size, &msg, rv);
371 | efree(data);
372 | }
373 | break;
374 | default:
375 | php_error_docref(NULL, E_WARNING, "Unexpected valued type '%d'", flag);
376 | rv = NULL;
377 | break;
378 | }
379 | } else {
380 | rv = NULL;
381 | }
382 |
383 | return rv;
384 | }
385 | /* }}} */
386 |
387 | static zval* yac_get_multi_impl(yac_object *yac, zval *keys, zval *cas, zval *rv) /* {{{ */ {
388 | zval *value;
389 | HashTable *ht = Z_ARRVAL_P(keys);
390 |
391 | array_init(rv);
392 |
393 | ZEND_HASH_FOREACH_VAL(ht, value) {
394 | uint32_t lcas = 0;
395 | zval *v, tmp;
396 |
397 | switch (Z_TYPE_P(value)) {
398 | case IS_STRING:
399 | if ((v = yac_get_impl(yac, Z_STR_P(value), &lcas, &tmp))) {
400 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), v);
401 | } else {
402 | ZVAL_FALSE(&tmp);
403 | zend_symtable_update(Z_ARRVAL_P(rv), Z_STR_P(value), &tmp);
404 | }
405 | continue;
406 | default:
407 | {
408 | zend_string *key = zval_get_string(value);
409 | if ((v = yac_get_impl(yac, key, &lcas, &tmp))) {
410 | zend_symtable_update(Z_ARRVAL_P(rv), key, v);
411 | } else {
412 | ZVAL_FALSE(&tmp);
413 | zend_symtable_update(Z_ARRVAL_P(rv), key, &tmp);
414 | }
415 | zend_string_release(key);
416 | }
417 | continue;
418 | }
419 | } ZEND_HASH_FOREACH_END();
420 |
421 | return rv;
422 | }
423 | /* }}} */
424 |
425 | static int yac_delete_impl(yac_object *yac, zend_string *name, int ttl) /* {{{ */ {
426 | time_t tv = 0;
427 | const char *key;
428 | size_t key_len;
429 |
430 | if ((key = yac_assemble_key(yac, name, &key_len)) == NULL) {
431 | return 0;
432 | }
433 |
434 | if (ttl) {
435 | tv = (zend_ulong)time(NULL);
436 | }
437 |
438 | return yac_storage_delete(key, key_len, ttl, tv);
439 | }
440 | /* }}} */
441 |
442 | static int yac_delete_multi_impl(yac_object *yac, zval *keys, int ttl) /* {{{ */ {
443 | HashTable *ht = Z_ARRVAL_P(keys);
444 | int ret = 1;
445 | zval *value;
446 |
447 | ZEND_HASH_FOREACH_VAL(ht, value) {
448 | switch (Z_TYPE_P(value)) {
449 | case IS_STRING:
450 | ret = ret & yac_delete_impl(yac, Z_STR_P(value), ttl);
451 | continue;
452 | default:
453 | {
454 | zend_string *key = zval_get_string(value);
455 | ret = ret & yac_delete_impl(yac, key, ttl);
456 | zend_string_release(key);
457 | }
458 | continue;
459 | }
460 | } ZEND_HASH_FOREACH_END();
461 |
462 | return ret;
463 | }
464 | /* }}} */
465 |
466 | static zend_object *yac_object_new(zend_class_entry *ce) /* {{{ */ {
467 | yac_object *yac = emalloc(sizeof(yac_object) + zend_object_properties_size(ce));
468 |
469 | zend_object_std_init(&yac->std, ce);
470 | yac->std.handlers = &yac_obj_handlers;
471 | yac->prefix_len = 0;
472 |
473 |
474 | return &yac->std;
475 | }
476 | /* }}} */
477 |
478 | static void yac_object_free(zend_object *object) /* {{{ */ {
479 | zend_object_std_dtor(object);
480 | }
481 | /* }}} */
482 |
483 | static zval* yac_read_property_ptr(void *zobj, void *name, int type, void **cache_slot) /* {{{ */ {
484 | zend_string *member;
485 | #if PHP_VERSION_ID < 80000
486 | member = Z_STR_P((zval*)name);
487 | #else
488 | member = (zend_string*)name;
489 | #endif
490 | zend_throw_exception_ex(NULL, 0, "Retrieval of Yac->%s for modification is unsupported", ZSTR_VAL(member));
491 | return &EG(error_zval);
492 | }
493 | /* }}} */
494 |
495 | static zval* yac_read_property(void /* for PHP8 compatibility */ *zobj, void *name, int type, void **cache_slot, zval *rv) /* {{{ */ {
496 | yac_object *yac;
497 | zend_string *member;
498 |
499 | if (UNEXPECTED(type == BP_VAR_RW||type == BP_VAR_W)) {
500 | return &EG(error_zval);
501 | }
502 | #if PHP_VERSION_ID < 80000
503 | yac = Z_YACOBJ_P((zval*)zobj);
504 | member = Z_STR_P((zval*)name);
505 | #else
506 | yac = php_yac_fetch_object((zend_object*)zobj);
507 | member = (zend_string*)name;
508 | #endif
509 |
510 | if (yac_get_impl(yac, member, NULL, rv)) {
511 | return rv;
512 | }
513 |
514 | return &EG(uninitialized_zval);
515 | }
516 | /* }}} */
517 |
518 | static YAC_WHANDLER yac_write_property(void *zobj, void *name, zval *value, void **cache_slot) /* {{{ */ {
519 | yac_object *yac;
520 | zend_string *member;
521 |
522 | #if PHP_VERSION_ID < 80000
523 | yac = Z_YACOBJ_P((zval*)zobj);
524 | member = Z_STR_P((zval*)name);
525 | #else
526 | yac = php_yac_fetch_object((zend_object*)zobj);
527 | member = (zend_string*)name;
528 | #endif
529 |
530 | yac_add_impl(yac, member, value, 0, 0);
531 | Z_TRY_ADDREF_P(value);
532 |
533 | YAC_WHANDLER_RET(value);
534 | }
535 | /* }}} */
536 |
537 | static void yac_unset_property(void *zobj, void *name, void **cache_slot) /* {{{ */ {
538 | yac_object *yac;
539 | zend_string *member;
540 |
541 | #if PHP_VERSION_ID < 80000
542 | yac = Z_YACOBJ_P((zval*)zobj);
543 | member = Z_STR_P((zval*)name);
544 | #else
545 | yac = php_yac_fetch_object((zend_object*)zobj);
546 | member = (zend_string*)name;
547 | #endif
548 |
549 | yac_delete_impl(yac, member, 0);
550 | }
551 | /* }}} */
552 |
553 | /** {{{ proto public Yac::__construct([string $prefix])
554 | */
555 | PHP_METHOD(yac, __construct) {
556 | zend_string *prefix = NULL;
557 |
558 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) {
559 | return;
560 | }
561 |
562 | if (!YAC_G(enable)) {
563 | zend_throw_exception(NULL, "Yac is not enabled", 0);
564 | }
565 |
566 | if (prefix && ZSTR_LEN(prefix)) {
567 | yac_object *yac;
568 | if (ZSTR_LEN(prefix) > YAC_STORAGE_MAX_KEY_LEN) {
569 | zend_throw_exception_ex(NULL, 0,
570 | "Prefix '%s' exceed max key length '%d' bytes", ZSTR_VAL(prefix), YAC_STORAGE_MAX_KEY_LEN);
571 | return;
572 | }
573 | yac = Z_YACOBJ_P(getThis());
574 | yac->prefix_len = ZSTR_LEN(prefix);
575 | memcpy(yac->prefix, ZSTR_VAL(prefix), ZSTR_LEN(prefix));
576 | }
577 | }
578 | /* }}} */
579 |
580 | /** {{{ proto public Yac::add(mixed $keys, mixed $value[, int $ttl])
581 | */
582 | PHP_METHOD(yac, add) {
583 | zend_long ttl = 0;
584 | zval *keys, *value = NULL;
585 | int ret;
586 |
587 | switch (ZEND_NUM_ARGS()) {
588 | case 1:
589 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
590 | return;
591 | }
592 | break;
593 | case 2:
594 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
595 | return;
596 | }
597 | if (Z_TYPE_P(keys) == IS_ARRAY) {
598 | if (Z_TYPE_P(value) == IS_LONG) {
599 | ttl = Z_LVAL_P(value);
600 | value = NULL;
601 | } else {
602 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
603 | return;
604 | }
605 | }
606 | break;
607 | case 3:
608 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
609 | return;
610 | }
611 | break;
612 | default:
613 | WRONG_PARAM_COUNT;
614 | }
615 |
616 | if (Z_TYPE_P(keys) == IS_ARRAY) {
617 | ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 1);
618 | } else if (Z_TYPE_P(keys) == IS_STRING) {
619 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 1);
620 | } else {
621 | zend_string *key = zval_get_string(keys);
622 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 1);
623 | zend_string_release(key);
624 | }
625 |
626 | RETURN_BOOL(ret);
627 | }
628 | /* }}} */
629 |
630 | /** {{{ proto public Yac::set(mixed $keys, mixed $value[, int $ttl])
631 | */
632 | PHP_METHOD(yac, set) {
633 | zend_long ttl = 0;
634 | zval *keys, *value = NULL;
635 | int ret;
636 |
637 | switch (ZEND_NUM_ARGS()) {
638 | case 1:
639 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &keys) == FAILURE) {
640 | return;
641 | }
642 | break;
643 | case 2:
644 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &keys, &value) == FAILURE) {
645 | return;
646 | }
647 | if (Z_TYPE_P(keys) == IS_ARRAY) {
648 | if (Z_TYPE_P(value) == IS_LONG) {
649 | ttl = Z_LVAL_P(value);
650 | value = NULL;
651 | } else {
652 | php_error_docref(NULL, E_WARNING, "ttl parameter must be an integer");
653 | return;
654 | }
655 | }
656 | break;
657 | case 3:
658 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzl", &keys, &value, &ttl) == FAILURE) {
659 | return;
660 | }
661 | break;
662 | default:
663 | WRONG_PARAM_COUNT;
664 | }
665 |
666 | if (Z_TYPE_P(keys) == IS_ARRAY) {
667 | ret = yac_add_multi_impl(Z_YACOBJ_P(getThis()), keys, ttl, 0);
668 | } else if (Z_TYPE_P(keys) == IS_STRING) {
669 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), value, ttl, 0);
670 | } else {
671 | zend_string *key = zval_get_string(keys);
672 | ret = yac_add_impl(Z_YACOBJ_P(getThis()), key, value, ttl, 0);
673 | zend_string_release(key);
674 | }
675 |
676 | RETURN_BOOL(ret);
677 | }
678 | /* }}} */
679 |
680 | /** {{{ proto public Yac::get(mixed $keys[, int &$cas])
681 | */
682 | PHP_METHOD(yac, get) {
683 | uint32_t lcas = 0;
684 | zval *ret, *keys, *cas = NULL;
685 |
686 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &keys, &cas) == FAILURE) {
687 | return;
688 | }
689 |
690 | if (Z_TYPE_P(keys) == IS_ARRAY) {
691 | ret = yac_get_multi_impl(Z_YACOBJ_P(getThis()), keys, cas, return_value);
692 | } else if (Z_TYPE_P(keys) == IS_STRING) {
693 | ret = yac_get_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), &lcas, return_value);
694 | } else {
695 | zend_string *key = zval_get_string(keys);
696 | ret = yac_get_impl(Z_YACOBJ_P(getThis()), key, &lcas, return_value);
697 | zend_string_release(key);
698 | }
699 |
700 | if (ret == NULL) {
701 | RETURN_FALSE;
702 | }
703 | }
704 | /* }}} */
705 |
706 | /** {{{ proto public Yac::delete(mixed $key[, int $delay = 0])
707 | */
708 | PHP_METHOD(yac, delete) {
709 | zend_long time = 0;
710 | zval *keys;
711 | int ret;
712 |
713 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &keys, &time) == FAILURE) {
714 | return;
715 | }
716 |
717 | if (Z_TYPE_P(keys) == IS_ARRAY) {
718 | ret = yac_delete_multi_impl(Z_YACOBJ_P(getThis()), keys, time);
719 | } else if (Z_TYPE_P(keys) == IS_STRING) {
720 | ret = yac_delete_impl(Z_YACOBJ_P(getThis()), Z_STR_P(keys), time);
721 | } else {
722 | zend_string *key = zval_get_string(keys);
723 | ret = yac_delete_impl(Z_YACOBJ_P(getThis()), key, time);
724 | zend_string_release(key);
725 | }
726 |
727 | RETURN_BOOL(ret);
728 | }
729 | /* }}} */
730 |
731 | /** {{{ proto public Yac::flush(void)
732 | */
733 | PHP_METHOD(yac, flush) {
734 |
735 | yac_storage_flush();
736 |
737 | RETURN_TRUE;
738 | }
739 | /* }}} */
740 |
741 | /** {{{ proto public Yac::info(void)
742 | */
743 | PHP_METHOD(yac, info) {
744 | yac_storage_info *inf;
745 |
746 | inf = yac_storage_get_info();
747 |
748 | array_init(return_value);
749 |
750 | add_assoc_long(return_value, "memory_size", inf->k_msize + inf->v_msize);
751 | add_assoc_long(return_value, "slots_memory_size", inf->k_msize);
752 | add_assoc_long(return_value, "values_memory_size", inf->v_msize);
753 | add_assoc_long(return_value, "segment_size", inf->segment_size);
754 | add_assoc_long(return_value, "segment_num", inf->segments_num);
755 | add_assoc_long(return_value, "miss", inf->miss);
756 | add_assoc_long(return_value, "hits", inf->hits);
757 | add_assoc_long(return_value, "fails", inf->fails);
758 | add_assoc_long(return_value, "kicks", inf->kicks);
759 | add_assoc_long(return_value, "recycles", inf->recycles);
760 | add_assoc_long(return_value, "slots_size", inf->slots_size);
761 | add_assoc_long(return_value, "slots_used", inf->slots_num);
762 |
763 | yac_storage_free_info(inf);
764 | return;
765 | }
766 | /* }}} */
767 |
768 | /** {{{ proto public Yac::dump(int $limit)
769 | */
770 | PHP_METHOD(yac, dump) {
771 | long limit = 100;
772 | yac_item_list *list, *l;
773 |
774 | array_init(return_value);
775 |
776 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limit) == FAILURE) {
777 | return;
778 | }
779 |
780 | list = l = yac_storage_dump(limit);
781 | for (; l; l = l->next) {
782 | zval item;
783 | array_init(&item);
784 | add_assoc_long(&item, "index", l->index);
785 | add_assoc_long(&item, "hash", l->h);
786 | add_assoc_long(&item, "crc", l->crc);
787 | add_assoc_long(&item, "ttl", l->ttl);
788 | add_assoc_long(&item, "k_len", l->k_len);
789 | add_assoc_long(&item, "v_len", l->v_len);
790 | add_assoc_long(&item, "size", l->size);
791 | add_assoc_string(&item, "key", (char*)l->key);
792 | add_next_index_zval(return_value, &item);
793 | }
794 |
795 | yac_storage_free_list(list);
796 | return;
797 | }
798 | /* }}} */
799 |
800 | #if 0
801 | only OO-style APIs is supported now
802 | /* {{{{ proto bool yac_add(mixed $keys, mixed $value[, int $ttl])
803 | */
804 | PHP_FUNCTION(yac_add)
805 | {
806 | PHP_MN(yac_add)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
807 | }
808 | /* }}} */
809 |
810 | /* {{{ proto bool yac_set(mixed $keys, mixed $value[, int $ttl])
811 | */
812 | PHP_FUNCTION(yac_set)
813 | {
814 | PHP_MN(yac_set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
815 | }
816 | /* }}} */
817 |
818 | /* {{{ proto bool yac_get(mixed $keys[, int &$cas])
819 | */
820 | PHP_FUNCTION(yac_get)
821 | {
822 | PHP_MN(yac_get)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
823 | }
824 | /* }}} */
825 |
826 | /* {{{ proto bool yac_delete(mixed $keys[, int $delay = 0])
827 | */
828 | PHP_FUNCTION(yac_delete)
829 | {
830 | PHP_MN(yac_delete)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
831 | }
832 | /* }}} */
833 |
834 | /* {{{ proto bool yac_flush(void)
835 | */
836 | PHP_FUNCTION(yac_flush)
837 | {
838 | PHP_MN(yac_flush)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
839 | }
840 | /* }}} */
841 |
842 | /* {{{ proto bool yac_info(void)
843 | */
844 | PHP_FUNCTION(yac_info)
845 | {
846 | PHP_MN(yac_info)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
847 | }
848 | /* }}} */
849 |
850 | /* {{{ yac_functions[] */
851 | zend_function_entry yac_functions[] = {
852 | PHP_FE(yac_add, arginfo_yac_add)
853 | PHP_FE(yac_set, arginfo_yac_add)
854 | PHP_FE(yac_get, arginfo_yac_get)
855 | PHP_FE(yac_delete, arginfo_yac_delete)
856 | PHP_FE(yac_flush, arginfo_yac_void)
857 | PHP_FE(yac_info, arginfo_yac_void)
858 | {NULL, NULL}
859 | };
860 | /* }}} */
861 | #endif
862 |
863 | /** {{{ yac_methods
864 | */
865 | zend_function_entry yac_methods[] = {
866 | PHP_ME(yac, __construct, arginfo_class_Yac___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
867 | PHP_ME(yac, add, arginfo_class_Yac_add, ZEND_ACC_PUBLIC)
868 | PHP_ME(yac, set, arginfo_class_Yac_set, ZEND_ACC_PUBLIC)
869 | PHP_ME(yac, get, arginfo_class_Yac_get, ZEND_ACC_PUBLIC)
870 | PHP_ME(yac, delete, arginfo_class_Yac_delete, ZEND_ACC_PUBLIC)
871 | PHP_ME(yac, flush, arginfo_class_Yac_flush, ZEND_ACC_PUBLIC)
872 | PHP_ME(yac, info, arginfo_class_Yac_info, ZEND_ACC_PUBLIC)
873 | PHP_ME(yac, dump, arginfo_class_Yac_dump, ZEND_ACC_PUBLIC)
874 | {NULL, NULL, NULL}
875 | };
876 | /* }}} */
877 |
878 | /* {{{ PHP_GINIT_FUNCTION
879 | */
880 | PHP_GINIT_FUNCTION(yac)
881 | {
882 | yac_globals->enable = 1;
883 | yac_globals->k_msize = (4 * 1024 * 1024);
884 | yac_globals->v_msize = (64 * 1024 * 1024);
885 | yac_globals->debug = 0;
886 | yac_globals->compress_threshold = -1;
887 | yac_globals->enable_cli = 0;
888 | #ifdef PHP_WIN32
889 | yac_globals->mmap_base = NULL;
890 | #endif
891 | }
892 | /* }}} */
893 |
894 | /* {{{ PHP_MINIT_FUNCTION
895 | */
896 | PHP_MINIT_FUNCTION(yac)
897 | {
898 | char *msg;
899 | zend_class_entry ce;
900 |
901 | REGISTER_INI_ENTRIES();
902 |
903 | if (!YAC_G(enable_cli) && !strcmp(sapi_module.name, "cli")) {
904 | YAC_G(enable) = 0;
905 | }
906 |
907 | if (YAC_G(enable)) {
908 | if (!yac_storage_startup(YAC_G(k_msize), YAC_G(v_msize), &msg)) {
909 | php_error(E_ERROR, "Shared memory allocator startup failed at '%s': %s", msg, strerror(errno));
910 | return FAILURE;
911 | }
912 | }
913 |
914 | REGISTER_STRINGL_CONSTANT("YAC_VERSION", PHP_YAC_VERSION, sizeof(PHP_YAC_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
915 | REGISTER_LONG_CONSTANT("YAC_MAX_KEY_LEN", YAC_STORAGE_MAX_KEY_LEN, CONST_PERSISTENT | CONST_CS);
916 | REGISTER_LONG_CONSTANT("YAC_MAX_VALUE_RAW_LEN", YAC_ENTRY_MAX_ORIG_LEN, CONST_PERSISTENT | CONST_CS);
917 | REGISTER_LONG_CONSTANT("YAC_MAX_RAW_COMPRESSED_LEN", YAC_STORAGE_MAX_ENTRY_LEN, CONST_PERSISTENT | CONST_CS);
918 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_PHP", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS);
919 | #if YAC_ENABLE_MSGPACK
920 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_MSGPACK", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS);
921 | #endif
922 | #if YAC_ENABLE_IGBINARY
923 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_IGBINARY", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS);
924 | #endif
925 | #if YAC_ENABLE_JSON
926 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER_JSON", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS);
927 | #endif
928 |
929 | #if YAC_ENABLE_MSGPACK
930 | if (strcmp(YAC_G(serializer), "msgpack") == 0) {
931 | yac_serializer = yac_serializer_msgpack_pack;
932 | yac_unserializer = yac_serializer_msgpack_unpack;
933 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_MSGPACK, CONST_PERSISTENT | CONST_CS);
934 | } else
935 | #endif
936 | #if YAC_ENABLE_IGBINARY
937 | if (strcmp(YAC_G(serializer), "igbinary") == 0) {
938 | yac_serializer = yac_serializer_igbinary_pack;
939 | yac_unserializer = yac_serializer_igbinary_unpack;
940 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_IGBINARY, CONST_PERSISTENT | CONST_CS);
941 | } else
942 | #endif
943 | #if YAC_ENABLE_JSON
944 | if (strcmp(YAC_G(serializer), "json") == 0) {
945 | yac_serializer = yac_serializer_json_pack;
946 | yac_unserializer = yac_serializer_json_unpack;
947 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_JSON, CONST_PERSISTENT | CONST_CS);
948 | } else
949 | #endif
950 | {
951 | yac_serializer = yac_serializer_php_pack;
952 | yac_unserializer = yac_serializer_php_unpack;
953 | REGISTER_LONG_CONSTANT("YAC_SERIALIZER", YAC_SERIALIZER_PHP, CONST_PERSISTENT | CONST_CS);
954 | }
955 |
956 | INIT_CLASS_ENTRY(ce, "Yac", yac_methods);
957 | yac_class_ce = zend_register_internal_class(&ce);
958 | yac_class_ce->ce_flags |= ZEND_ACC_FINAL;
959 | yac_class_ce->create_object = yac_object_new;
960 |
961 | memcpy(&yac_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
962 | yac_obj_handlers.offset = XtOffsetOf(yac_object, std);
963 | yac_obj_handlers.free_obj = yac_object_free;
964 | if (YAC_G(enable)) {
965 | yac_obj_handlers.read_property = (zend_object_read_property_t)yac_read_property;
966 | yac_obj_handlers.write_property = (zend_object_write_property_t)yac_write_property;
967 | yac_obj_handlers.unset_property = (zend_object_unset_property_t)yac_unset_property;
968 | yac_obj_handlers.get_property_ptr_ptr = (zend_object_get_property_ptr_ptr_t)yac_read_property_ptr;
969 | }
970 |
971 | return SUCCESS;
972 | }
973 | /* }}} */
974 |
975 | /* {{{ PHP_MSHUTDOWN_FUNCTION
976 | */
977 | PHP_MSHUTDOWN_FUNCTION(yac)
978 | {
979 | UNREGISTER_INI_ENTRIES();
980 | if (YAC_G(enable)) {
981 | yac_storage_shutdown();
982 | }
983 | return SUCCESS;
984 | }
985 | /* }}} */
986 |
987 | /* {{{ PHP_MINFO_FUNCTION
988 | */
989 | PHP_MINFO_FUNCTION(yac)
990 | {
991 | smart_str names = {0,};
992 |
993 | php_info_print_table_start();
994 | php_info_print_table_header(2, "yac support", "enabled");
995 | php_info_print_table_row(2, "Version", PHP_YAC_VERSION);
996 | php_info_print_table_row(2, "Shared Memory", yac_storage_shared_memory_name());
997 |
998 | smart_str_appends(&names, "php");
999 | #if YAC_ENABLE_MSGPACK
1000 | smart_str_appends(&names, ", msgpack");
1001 | #endif
1002 | #if YAC_ENABLE_IGBINARY
1003 | smart_str_appends(&names, ", igbinary");
1004 | #endif
1005 | #if YAC_ENABLE_JSON
1006 | smart_str_appends(&names, ", json");
1007 | #endif
1008 | php_info_print_table_row(2, "Serializer", ZSTR_VAL(names.s));
1009 | smart_str_free(&names);
1010 |
1011 | php_info_print_table_end();
1012 |
1013 | DISPLAY_INI_ENTRIES();
1014 |
1015 | if (YAC_G(enable)) {
1016 | char buf[64];
1017 | yac_storage_info *inf;
1018 | inf = yac_storage_get_info();
1019 |
1020 | php_info_print_table_start();
1021 | php_info_print_table_colspan_header(2, "Cache info");
1022 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize + inf->v_msize);
1023 | php_info_print_table_row(2, "Total Shared Memory Usage(memory_size)", buf);
1024 | snprintf(buf, sizeof(buf), "%ld", inf->k_msize);
1025 | php_info_print_table_row(2, "Total Shared Memory Usage for keys(keys_memory_size)", buf);
1026 | snprintf(buf, sizeof(buf), "%ld", inf->v_msize);
1027 | php_info_print_table_row(2, "Total Shared Memory Usage for values(values_memory_size)", buf);
1028 | snprintf(buf, sizeof(buf), "%d", inf->segment_size);
1029 | php_info_print_table_row(2, "Size of Shared Memory Segment(segment_size)", buf);
1030 | snprintf(buf, sizeof(buf), "%d", inf->segments_num);
1031 | php_info_print_table_row(2, "Number of Segments (segment_num)", buf);
1032 | snprintf(buf, sizeof(buf), "%d", inf->slots_size);
1033 | php_info_print_table_row(2, "Total Slots Number(slots_size)", buf);
1034 | snprintf(buf, sizeof(buf), "%d", inf->slots_num);
1035 | php_info_print_table_row(2, "Total Used Slots(slots_num)", buf);
1036 | php_info_print_table_end();
1037 |
1038 | yac_storage_free_info(inf);
1039 | }
1040 | }
1041 | /* }}} */
1042 |
1043 | #ifdef COMPILE_DL_YAC
1044 | ZEND_GET_MODULE(yac)
1045 | #endif
1046 |
1047 | static zend_module_dep yac_module_deps[] = {
1048 | #if YAC_ENABLE_MSGPACK
1049 | ZEND_MOD_REQUIRED("msgpack")
1050 | #endif
1051 | #if YAC_ENABLE_IGBINARY
1052 | ZEND_MOD_REQUIRED("igbinary")
1053 | #endif
1054 | #if YAC_ENABLE_JSON
1055 | ZEND_MOD_REQUIRED("json")
1056 | #endif
1057 | {NULL, NULL, NULL, 0}
1058 | };
1059 |
1060 | /* {{{ yac_module_entry
1061 | */
1062 | zend_module_entry yac_module_entry = {
1063 | STANDARD_MODULE_HEADER_EX,
1064 | NULL,
1065 | yac_module_deps,
1066 | "yac",
1067 | NULL, /* yac_functions, */
1068 | PHP_MINIT(yac),
1069 | PHP_MSHUTDOWN(yac),
1070 | NULL,
1071 | NULL,
1072 | PHP_MINFO(yac),
1073 | PHP_YAC_VERSION,
1074 | PHP_MODULE_GLOBALS(yac),
1075 | PHP_GINIT(yac),
1076 | NULL,
1077 | NULL,
1078 | STANDARD_MODULE_PROPERTIES_EX
1079 | };
1080 | /* }}} */
1081 |
1082 | /*
1083 | * Local variables:
1084 | * tab-width: 4
1085 | * c-basic-offset: 4
1086 | * End:
1087 | * vim600: noet sw=4 ts=4 fdm=marker
1088 | * vim<600: noet sw=4 ts=4
1089 | */
1090 |
1091 |
--------------------------------------------------------------------------------
/yac.php:
--------------------------------------------------------------------------------
1 | ";
3 |
4 | if(!extension_loaded('yac')) {
5 | dl('yac.' . PHP_SHLIB_SUFFIX);
6 | }
7 | $module = 'yac';
8 | $functions = get_extension_funcs($module);
9 | echo "Functions available in the test extension:$br\n";
10 | foreach($functions as $func) {
11 | echo $func."$br\n";
12 | }
13 | echo "$br\n";
14 | $function = 'confirm_' . $module . '_compiled';
15 | if (extension_loaded($module)) {
16 | $str = $function($module);
17 | } else {
18 | $str = "Module $module is not compiled into PHP";
19 | }
20 | echo "$str\n";
21 | ?>
22 |
--------------------------------------------------------------------------------
/yac.stub.php:
--------------------------------------------------------------------------------
1 |