├── .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 | [![Build status](https://ci.appveyor.com/api/projects/status/6bu09pw8ukyx61m2/branch/master?svg=true)](https://ci.appveyor.com/project/laruence/yac/branch/master) [![Build Status](https://github.com/laruence/yac/workflows/integrate/badge.svg)](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 |