package.xml 0000664 0001750 0001750 00000073707 14523735540 012177 0 ustar nikic nikic
"; \$a = \$_SESSION['lalala']; print_r(\$a); } else { echo "no session yet, first run\n"; } // another file // class A and B use autoload \$b = new B(); \$a = new A(); \$a->b = \$b; \$_SESSION['lalala'] = \$a; session_write_close(); FL; $args = array( 'apc.enabled=1', 'apc.cache_by_default=1', 'apc.enable_cli=1', 'session.gc_probability=0', ); server_start($file, $args); $sid = md5(uniqid("call me maybe", true)); for ($i = 0; $i < 10; $i++) { $send = "GET / HTTP/1.1\n" . "Host: " . PHP_CLI_SERVER_HOSTNAME . "\n" . "Cookie: PHPSESSID=$sid;" . "\r\n\r\n"; for ($j = 0; $j < $num_servers; $j++) { run_test(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$j, $send); } } echo 'done'; --EXPECT-- no session yet, first runA Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) )A Object ( [b] => B Object ( [var] => 1 ) ) done apcu-5.1.23/tests/bug76145.phpt 0000664 0001750 0001750 00000001566 14523735540 014753 0 ustar nikic nikic --TEST-- Bug #76145: Data corruption reading from APCu while unserializing --INI-- apc.enabled=1 apc.enable_cli=1 error_reporting=E_ALL&~E_DEPRECATED --FILE-- session = apcu_fetch('session'); } public function serialize() { return ''; } } // Create array representing a session associated with a user // account that is enabled but has not been authenticated. $session = ['user' => ['enabled' => True], 'authenticated' => False]; $session['user']['authenticated'] = &$session['authenticated']; apcu_store('session', $session); // After serializing / deserializing, session checks out as authenticated. print unserialize(serialize(new Session())) -> session['authenticated'] === True ? 'Authenticated.' : 'Not Authenticated.'; ?> --EXPECT-- Not Authenticated. apcu-5.1.23/tests/get_included_files_inc1.inc 0000664 0001750 0001750 00000000034 14523735540 020074 0 ustar nikic nikic apcu-5.1.23/tests/get_included_files_inc2.inc 0000664 0001750 0001750 00000000127 14523735540 020100 0 ustar nikic nikic apcu-5.1.23/tests/get_included_files_inc3.inc 0000664 0001750 0001750 00000000127 14523735540 020101 0 ustar nikic nikic apcu-5.1.23/tests/ghbug176.phpt 0000664 0001750 0001750 00000001715 14523735540 015115 0 ustar nikic nikic --TEST-- APC: GH Bug #176 preload_path segfaults with bad data --SKIPIF-- --CONFLICTS-- server --FILE-- --EXPECT-- bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) done apcu-5.1.23/tests/ghbug168.phpt 0000664 0001750 0001750 00000000725 14523735540 015116 0 ustar nikic nikic --TEST-- gh bug #168 --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- string(1) "B" } string(1) "A" array(1) { [0]=> string(1) "B" } string(1) "A" apcu-5.1.23/tests/ghbug185.phpt 0000664 0001750 0001750 00000002174 14523735540 015115 0 ustar nikic nikic --TEST-- APC: GH Bug #185 memory corruption --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- counterName = $value; } public function getCounters($name) { $rex = '/^' . preg_quote($name) . '\./'; $counters = array(); foreach (new \APCuIterator($rex) as $counter) { $counters[$counter['key']] = $counter['value']; } return $counters; } public function add($key, $data, $ttl = 0) { $ret = apcu_store($key, $data, $ttl); if (true !== $ret) { throw new \UnexpectedValueException("apc_store call failed"); } return $ret; } } $myapc = new MyApc(); var_dump($counterName = uniqid()); var_dump($myapc->setCounterName($counterName)); var_dump($myapc->add($counterName.'.test', 1)); var_dump($results = $myapc->getCounters($counterName)); ?> Done --EXPECTF-- string(%d) "%s" NULL bool(true) array(1) { ["%s.test"]=> int(1) } Done apcu-5.1.23/tests/ghbug247.phpt 0000664 0001750 0001750 00000000504 14523735540 015107 0 ustar nikic nikic --TEST-- GH Bug #247: when a NUL char is used as key, apcu_fetch(array) truncates the key --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- 'foo')); var_dump(apcu_fetch(array("a\0b"))["a\0b"]); ?> --EXPECT-- string(3) "foo" apcu-5.1.23/tests/ghbug248.phpt 0000664 0001750 0001750 00000005651 14523735540 015120 0 ustar nikic nikic --TEST-- GH Bug #248: apcu_fetch may return values causing zend_mm_corruption or segfaults when custom serializer is used --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --FILE-- 2, 'construct' => ['a'], 'x1' => 'y', 'x2' => 'y', 'x3' => 'y', 'x4' => 'y', 'x5' => 'y', 'x6' => 0, ]; } class MyClass { private $_params; public function __construct($params) { var_dump($params); $this->_params = $params; var_dump($params); $this->_params['ids'] = [4]; $this->_params['loadValue'] = 'x'; unset($this->_params['params']); } } function setup() { apcu_delete('mytestkey'); apcu_store('mytestkey', build_array()); } function test_apcu_fetch() { // Or store second? $value = apcu_fetch('mytestkey'); echo "Fetching the value initially stored into apcu:\n"; var_dump($value); echo "Done dumping initial fetch\n\n"; new MyClass($value); echo "\$value was passed by value, not reference. After instantiating class, the array \$value gets modified\n"; var_dump($value); echo "\nAnd calling apcu_fetch again, the original data is preserved (8 keys, params=2)\n"; var_dump(apcu_fetch('mytestkey')); } setup(); test_apcu_fetch(); ?> --EXPECT-- Fetching the value initially stored into apcu: array(8) { ["params"]=> int(2) ["construct"]=> array(1) { [0]=> string(1) "a" } ["x1"]=> string(1) "y" ["x2"]=> string(1) "y" ["x3"]=> string(1) "y" ["x4"]=> string(1) "y" ["x5"]=> string(1) "y" ["x6"]=> int(0) } Done dumping initial fetch array(8) { ["params"]=> int(2) ["construct"]=> array(1) { [0]=> string(1) "a" } ["x1"]=> string(1) "y" ["x2"]=> string(1) "y" ["x3"]=> string(1) "y" ["x4"]=> string(1) "y" ["x5"]=> string(1) "y" ["x6"]=> int(0) } array(8) { ["params"]=> int(2) ["construct"]=> array(1) { [0]=> string(1) "a" } ["x1"]=> string(1) "y" ["x2"]=> string(1) "y" ["x3"]=> string(1) "y" ["x4"]=> string(1) "y" ["x5"]=> string(1) "y" ["x6"]=> int(0) } $value was passed by value, not reference. After instantiating class, the array $value gets modified array(8) { ["params"]=> int(2) ["construct"]=> array(1) { [0]=> string(1) "a" } ["x1"]=> string(1) "y" ["x2"]=> string(1) "y" ["x3"]=> string(1) "y" ["x4"]=> string(1) "y" ["x5"]=> string(1) "y" ["x6"]=> int(0) } And calling apcu_fetch again, the original data is preserved (8 keys, params=2) array(8) { ["params"]=> int(2) ["construct"]=> array(1) { [0]=> string(1) "a" } ["x1"]=> string(1) "y" ["x2"]=> string(1) "y" ["x3"]=> string(1) "y" ["x4"]=> string(1) "y" ["x5"]=> string(1) "y" ["x6"]=> int(0) } apcu-5.1.23/tests/ghbug335-fail.phpt 0000664 0001750 0001750 00000001250 14523735540 016015 0 ustar nikic nikic --TEST-- GH Bug #335: APCu stampede protection is broken --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.slam_defense=0 --FILE-- --EXPECT-- Stampede protection doesn't work apcu-5.1.23/tests/ghbug335.phpt 0000664 0001750 0001750 00000001241 14523735540 015104 0 ustar nikic nikic --TEST-- GH Bug #335: APCu stampede protection is broken --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.slam_defense=1 --FILE-- --EXPECT-- Stampede protection works apcu-5.1.23/tests/iterator_001.phpt 0000664 0001750 0001750 00000003351 14523735540 015772 0 ustar nikic nikic --TEST-- APC: APCIterator general --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $keys[$key] = $value['key']; } ksort($keys); var_dump($keys); ?> ===DONE=== --EXPECT-- array(41) { ["key0"]=> string(4) "key0" ["key1"]=> string(4) "key1" ["key10"]=> string(5) "key10" ["key11"]=> string(5) "key11" ["key12"]=> string(5) "key12" ["key13"]=> string(5) "key13" ["key14"]=> string(5) "key14" ["key15"]=> string(5) "key15" ["key16"]=> string(5) "key16" ["key17"]=> string(5) "key17" ["key18"]=> string(5) "key18" ["key19"]=> string(5) "key19" ["key2"]=> string(4) "key2" ["key20"]=> string(5) "key20" ["key21"]=> string(5) "key21" ["key22"]=> string(5) "key22" ["key23"]=> string(5) "key23" ["key24"]=> string(5) "key24" ["key25"]=> string(5) "key25" ["key26"]=> string(5) "key26" ["key27"]=> string(5) "key27" ["key28"]=> string(5) "key28" ["key29"]=> string(5) "key29" ["key3"]=> string(4) "key3" ["key30"]=> string(5) "key30" ["key31"]=> string(5) "key31" ["key32"]=> string(5) "key32" ["key33"]=> string(5) "key33" ["key34"]=> string(5) "key34" ["key35"]=> string(5) "key35" ["key36"]=> string(5) "key36" ["key37"]=> string(5) "key37" ["key38"]=> string(5) "key38" ["key39"]=> string(5) "key39" ["key4"]=> string(4) "key4" ["key40"]=> string(5) "key40" ["key5"]=> string(4) "key5" ["key6"]=> string(4) "key6" ["key7"]=> string(4) "key7" ["key8"]=> string(4) "key8" ["key9"]=> string(4) "key9" } ===DONE=== apcu-5.1.23/tests/iterator_002.phpt 0000664 0001750 0001750 00000001035 14523735540 015770 0 ustar nikic nikic --TEST-- APC: APCIterator regex --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $vals[$key] = $value['key']; } ksort($vals); var_dump($vals); ?> ===DONE=== --EXPECT-- array(4) { ["key10"]=> string(5) "key10" ["key20"]=> string(5) "key20" ["key30"]=> string(5) "key30" ["key40"]=> string(5) "key40" } ===DONE=== apcu-5.1.23/tests/iterator_003.phpt 0000664 0001750 0001750 00000003402 14523735540 015771 0 ustar nikic nikic --TEST-- APC: APCIterator chunk size --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $vals[$key] = $value['key']; } ksort($vals); var_dump($vals); ?> ===DONE=== --EXPECT-- array(41) { ["key0"]=> string(4) "key0" ["key1"]=> string(4) "key1" ["key10"]=> string(5) "key10" ["key11"]=> string(5) "key11" ["key12"]=> string(5) "key12" ["key13"]=> string(5) "key13" ["key14"]=> string(5) "key14" ["key15"]=> string(5) "key15" ["key16"]=> string(5) "key16" ["key17"]=> string(5) "key17" ["key18"]=> string(5) "key18" ["key19"]=> string(5) "key19" ["key2"]=> string(4) "key2" ["key20"]=> string(5) "key20" ["key21"]=> string(5) "key21" ["key22"]=> string(5) "key22" ["key23"]=> string(5) "key23" ["key24"]=> string(5) "key24" ["key25"]=> string(5) "key25" ["key26"]=> string(5) "key26" ["key27"]=> string(5) "key27" ["key28"]=> string(5) "key28" ["key29"]=> string(5) "key29" ["key3"]=> string(4) "key3" ["key30"]=> string(5) "key30" ["key31"]=> string(5) "key31" ["key32"]=> string(5) "key32" ["key33"]=> string(5) "key33" ["key34"]=> string(5) "key34" ["key35"]=> string(5) "key35" ["key36"]=> string(5) "key36" ["key37"]=> string(5) "key37" ["key38"]=> string(5) "key38" ["key39"]=> string(5) "key39" ["key4"]=> string(4) "key4" ["key40"]=> string(5) "key40" ["key5"]=> string(4) "key5" ["key6"]=> string(4) "key6" ["key7"]=> string(4) "key7" ["key8"]=> string(4) "key8" ["key9"]=> string(4) "key9" } ===DONE=== apcu-5.1.23/tests/iterator_004.phpt 0000664 0001750 0001750 00000001122 14523735540 015767 0 ustar nikic nikic --TEST-- APC: APCIterator regex & chunk size & list --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $vals[$key] = $value['key']; } ksort($vals); var_dump($vals); ?> ===DONE=== --EXPECT-- array(4) { ["key10"]=> string(5) "key10" ["key20"]=> string(5) "key20" ["key30"]=> string(5) "key30" ["key40"]=> string(5) "key40" } ===DONE=== apcu-5.1.23/tests/iterator_005.phpt 0000664 0001750 0001750 00000003436 14523735540 016002 0 ustar nikic nikic --TEST-- APC: APCIterator delete --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $vals[$key] = $value['key']; } foreach($it2 as $key=>$value) { $vals2[$key] = $value['key']; } ksort($vals2); var_dump($vals); var_dump($vals2); ?> ===DONE=== --EXPECT-- array(0) { } array(37) { ["key0"]=> string(4) "key0" ["key1"]=> string(4) "key1" ["key11"]=> string(5) "key11" ["key12"]=> string(5) "key12" ["key13"]=> string(5) "key13" ["key14"]=> string(5) "key14" ["key15"]=> string(5) "key15" ["key16"]=> string(5) "key16" ["key17"]=> string(5) "key17" ["key18"]=> string(5) "key18" ["key19"]=> string(5) "key19" ["key2"]=> string(4) "key2" ["key21"]=> string(5) "key21" ["key22"]=> string(5) "key22" ["key23"]=> string(5) "key23" ["key24"]=> string(5) "key24" ["key25"]=> string(5) "key25" ["key26"]=> string(5) "key26" ["key27"]=> string(5) "key27" ["key28"]=> string(5) "key28" ["key29"]=> string(5) "key29" ["key3"]=> string(4) "key3" ["key31"]=> string(5) "key31" ["key32"]=> string(5) "key32" ["key33"]=> string(5) "key33" ["key34"]=> string(5) "key34" ["key35"]=> string(5) "key35" ["key36"]=> string(5) "key36" ["key37"]=> string(5) "key37" ["key38"]=> string(5) "key38" ["key39"]=> string(5) "key39" ["key4"]=> string(4) "key4" ["key5"]=> string(4) "key5" ["key6"]=> string(4) "key6" ["key7"]=> string(4) "key7" ["key8"]=> string(4) "key8" ["key9"]=> string(4) "key9" } ===DONE=== apcu-5.1.23/tests/iterator_006.phpt 0000664 0001750 0001750 00000041031 14523735540 015774 0 ustar nikic nikic --TEST-- APC: APCIterator formats --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.user_entries_hint=4096 --FILE-- $format) { $it_array[$idx] = new APCuIterator(NULL, $format); } for($i = 0; $i < 11; $i++) { apcu_store("key$i", "value$i"); } foreach ($it_array as $idx => $it) { print_it($it, $idx); } function print_it($it, $idx) { echo "IT #$idx\n"; echo "============================\n"; foreach ($it as $key=>$value) { var_dump($key); var_dump($value); } echo "============================\n\n"; } ?> ===DONE=== --EXPECTF-- IT #0 ============================ string(4) "key0" array(1) { ["key"]=> string(4) "key0" } string(4) "key1" array(1) { ["key"]=> string(4) "key1" } string(4) "key2" array(1) { ["key"]=> string(4) "key2" } string(4) "key3" array(1) { ["key"]=> string(4) "key3" } string(4) "key4" array(1) { ["key"]=> string(4) "key4" } string(4) "key5" array(1) { ["key"]=> string(4) "key5" } string(4) "key6" array(1) { ["key"]=> string(4) "key6" } string(4) "key7" array(1) { ["key"]=> string(4) "key7" } string(4) "key8" array(1) { ["key"]=> string(4) "key8" } string(4) "key9" array(1) { ["key"]=> string(4) "key9" } string(5) "key10" array(1) { ["key"]=> string(5) "key10" } ============================ IT #1 ============================ string(4) "key0" array(1) { ["value"]=> string(6) "value0" } string(4) "key1" array(1) { ["value"]=> string(6) "value1" } string(4) "key2" array(1) { ["value"]=> string(6) "value2" } string(4) "key3" array(1) { ["value"]=> string(6) "value3" } string(4) "key4" array(1) { ["value"]=> string(6) "value4" } string(4) "key5" array(1) { ["value"]=> string(6) "value5" } string(4) "key6" array(1) { ["value"]=> string(6) "value6" } string(4) "key7" array(1) { ["value"]=> string(6) "value7" } string(4) "key8" array(1) { ["value"]=> string(6) "value8" } string(4) "key9" array(1) { ["value"]=> string(6) "value9" } string(5) "key10" array(1) { ["value"]=> string(7) "value10" } ============================ IT #2 ============================ string(4) "key0" array(1) { ["num_hits"]=> int(0) } string(4) "key1" array(1) { ["num_hits"]=> int(0) } string(4) "key2" array(1) { ["num_hits"]=> int(0) } string(4) "key3" array(1) { ["num_hits"]=> int(0) } string(4) "key4" array(1) { ["num_hits"]=> int(0) } string(4) "key5" array(1) { ["num_hits"]=> int(0) } string(4) "key6" array(1) { ["num_hits"]=> int(0) } string(4) "key7" array(1) { ["num_hits"]=> int(0) } string(4) "key8" array(1) { ["num_hits"]=> int(0) } string(4) "key9" array(1) { ["num_hits"]=> int(0) } string(5) "key10" array(1) { ["num_hits"]=> int(0) } ============================ IT #3 ============================ string(4) "key0" array(1) { ["mtime"]=> int(%d) } string(4) "key1" array(1) { ["mtime"]=> int(%d) } string(4) "key2" array(1) { ["mtime"]=> int(%d) } string(4) "key3" array(1) { ["mtime"]=> int(%d) } string(4) "key4" array(1) { ["mtime"]=> int(%d) } string(4) "key5" array(1) { ["mtime"]=> int(%d) } string(4) "key6" array(1) { ["mtime"]=> int(%d) } string(4) "key7" array(1) { ["mtime"]=> int(%d) } string(4) "key8" array(1) { ["mtime"]=> int(%d) } string(4) "key9" array(1) { ["mtime"]=> int(%d) } string(5) "key10" array(1) { ["mtime"]=> int(%d) } ============================ IT #4 ============================ string(4) "key0" array(1) { ["creation_time"]=> int(%d) } string(4) "key1" array(1) { ["creation_time"]=> int(%d) } string(4) "key2" array(1) { ["creation_time"]=> int(%d) } string(4) "key3" array(1) { ["creation_time"]=> int(%d) } string(4) "key4" array(1) { ["creation_time"]=> int(%d) } string(4) "key5" array(1) { ["creation_time"]=> int(%d) } string(4) "key6" array(1) { ["creation_time"]=> int(%d) } string(4) "key7" array(1) { ["creation_time"]=> int(%d) } string(4) "key8" array(1) { ["creation_time"]=> int(%d) } string(4) "key9" array(1) { ["creation_time"]=> int(%d) } string(5) "key10" array(1) { ["creation_time"]=> int(%d) } ============================ IT #5 ============================ string(4) "key0" array(1) { ["deletion_time"]=> int(0) } string(4) "key1" array(1) { ["deletion_time"]=> int(0) } string(4) "key2" array(1) { ["deletion_time"]=> int(0) } string(4) "key3" array(1) { ["deletion_time"]=> int(0) } string(4) "key4" array(1) { ["deletion_time"]=> int(0) } string(4) "key5" array(1) { ["deletion_time"]=> int(0) } string(4) "key6" array(1) { ["deletion_time"]=> int(0) } string(4) "key7" array(1) { ["deletion_time"]=> int(0) } string(4) "key8" array(1) { ["deletion_time"]=> int(0) } string(4) "key9" array(1) { ["deletion_time"]=> int(0) } string(5) "key10" array(1) { ["deletion_time"]=> int(0) } ============================ IT #6 ============================ string(4) "key0" array(1) { ["access_time"]=> int(%d) } string(4) "key1" array(1) { ["access_time"]=> int(%d) } string(4) "key2" array(1) { ["access_time"]=> int(%d) } string(4) "key3" array(1) { ["access_time"]=> int(%d) } string(4) "key4" array(1) { ["access_time"]=> int(%d) } string(4) "key5" array(1) { ["access_time"]=> int(%d) } string(4) "key6" array(1) { ["access_time"]=> int(%d) } string(4) "key7" array(1) { ["access_time"]=> int(%d) } string(4) "key8" array(1) { ["access_time"]=> int(%d) } string(4) "key9" array(1) { ["access_time"]=> int(%d) } string(5) "key10" array(1) { ["access_time"]=> int(%d) } ============================ IT #7 ============================ string(4) "key0" array(1) { ["ref_count"]=> int(0) } string(4) "key1" array(1) { ["ref_count"]=> int(0) } string(4) "key2" array(1) { ["ref_count"]=> int(0) } string(4) "key3" array(1) { ["ref_count"]=> int(0) } string(4) "key4" array(1) { ["ref_count"]=> int(0) } string(4) "key5" array(1) { ["ref_count"]=> int(0) } string(4) "key6" array(1) { ["ref_count"]=> int(0) } string(4) "key7" array(1) { ["ref_count"]=> int(0) } string(4) "key8" array(1) { ["ref_count"]=> int(0) } string(4) "key9" array(1) { ["ref_count"]=> int(0) } string(5) "key10" array(1) { ["ref_count"]=> int(0) } ============================ IT #8 ============================ string(4) "key0" array(1) { ["mem_size"]=> int(%d) } string(4) "key1" array(1) { ["mem_size"]=> int(%d) } string(4) "key2" array(1) { ["mem_size"]=> int(%d) } string(4) "key3" array(1) { ["mem_size"]=> int(%d) } string(4) "key4" array(1) { ["mem_size"]=> int(%d) } string(4) "key5" array(1) { ["mem_size"]=> int(%d) } string(4) "key6" array(1) { ["mem_size"]=> int(%d) } string(4) "key7" array(1) { ["mem_size"]=> int(%d) } string(4) "key8" array(1) { ["mem_size"]=> int(%d) } string(4) "key9" array(1) { ["mem_size"]=> int(%d) } string(5) "key10" array(1) { ["mem_size"]=> int(%d) } ============================ IT #9 ============================ string(4) "key0" array(1) { ["ttl"]=> int(0) } string(4) "key1" array(1) { ["ttl"]=> int(0) } string(4) "key2" array(1) { ["ttl"]=> int(0) } string(4) "key3" array(1) { ["ttl"]=> int(0) } string(4) "key4" array(1) { ["ttl"]=> int(0) } string(4) "key5" array(1) { ["ttl"]=> int(0) } string(4) "key6" array(1) { ["ttl"]=> int(0) } string(4) "key7" array(1) { ["ttl"]=> int(0) } string(4) "key8" array(1) { ["ttl"]=> int(0) } string(4) "key9" array(1) { ["ttl"]=> int(0) } string(5) "key10" array(1) { ["ttl"]=> int(0) } ============================ IT #10 ============================ string(4) "key0" array(0) { } string(4) "key1" array(0) { } string(4) "key2" array(0) { } string(4) "key3" array(0) { } string(4) "key4" array(0) { } string(4) "key5" array(0) { } string(4) "key6" array(0) { } string(4) "key7" array(0) { } string(4) "key8" array(0) { } string(4) "key9" array(0) { } string(5) "key10" array(0) { } ============================ IT #11 ============================ string(4) "key0" array(10) { ["key"]=> string(4) "key0" ["value"]=> string(6) "value0" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key1" array(10) { ["key"]=> string(4) "key1" ["value"]=> string(6) "value1" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key2" array(10) { ["key"]=> string(4) "key2" ["value"]=> string(6) "value2" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key3" array(10) { ["key"]=> string(4) "key3" ["value"]=> string(6) "value3" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key4" array(10) { ["key"]=> string(4) "key4" ["value"]=> string(6) "value4" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key5" array(10) { ["key"]=> string(4) "key5" ["value"]=> string(6) "value5" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key6" array(10) { ["key"]=> string(4) "key6" ["value"]=> string(6) "value6" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key7" array(10) { ["key"]=> string(4) "key7" ["value"]=> string(6) "value7" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key8" array(10) { ["key"]=> string(4) "key8" ["value"]=> string(6) "value8" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(4) "key9" array(10) { ["key"]=> string(4) "key9" ["value"]=> string(6) "value9" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } string(5) "key10" array(10) { ["key"]=> string(5) "key10" ["value"]=> string(7) "value10" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } ============================ IT #12 ============================ string(4) "key0" array(9) { ["key"]=> string(4) "key0" ["value"]=> string(6) "value0" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key1" array(9) { ["key"]=> string(4) "key1" ["value"]=> string(6) "value1" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key2" array(9) { ["key"]=> string(4) "key2" ["value"]=> string(6) "value2" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key3" array(9) { ["key"]=> string(4) "key3" ["value"]=> string(6) "value3" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key4" array(9) { ["key"]=> string(4) "key4" ["value"]=> string(6) "value4" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key5" array(9) { ["key"]=> string(4) "key5" ["value"]=> string(6) "value5" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key6" array(9) { ["key"]=> string(4) "key6" ["value"]=> string(6) "value6" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key7" array(9) { ["key"]=> string(4) "key7" ["value"]=> string(6) "value7" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key8" array(9) { ["key"]=> string(4) "key8" ["value"]=> string(6) "value8" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key9" array(9) { ["key"]=> string(4) "key9" ["value"]=> string(6) "value9" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } string(5) "key10" array(9) { ["key"]=> string(5) "key10" ["value"]=> string(7) "value10" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) } ============================ IT #13 ============================ string(4) "key0" array(3) { ["key"]=> string(4) "key0" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key1" array(3) { ["key"]=> string(4) "key1" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key2" array(3) { ["key"]=> string(4) "key2" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key3" array(3) { ["key"]=> string(4) "key3" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key4" array(3) { ["key"]=> string(4) "key4" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key5" array(3) { ["key"]=> string(4) "key5" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key6" array(3) { ["key"]=> string(4) "key6" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key7" array(3) { ["key"]=> string(4) "key7" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key8" array(3) { ["key"]=> string(4) "key8" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(4) "key9" array(3) { ["key"]=> string(4) "key9" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } string(5) "key10" array(3) { ["key"]=> string(5) "key10" ["num_hits"]=> int(0) ["mem_size"]=> int(%d) } ============================ ===DONE=== apcu-5.1.23/tests/iterator_007.phpt 0000664 0001750 0001750 00000002567 14523735540 016010 0 ustar nikic nikic --TEST-- APC: APCIterator Overwriting the ctor --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- rewind(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->current(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->key(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->next(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->valid(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->getTotalHits(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->getTotalSize(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { $obj->getTotalCount(); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { apcu_delete($obj); } catch (Error $e) { echo $e->getMessage(), "\n"; } ?> --EXPECT-- Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator Trying to use uninitialized APCUIterator apcu-5.1.23/tests/iterator_008.phpt 0000664 0001750 0001750 00000001000 14523735540 015766 0 ustar nikic nikic --TEST-- APC: APCIterator array --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- $value) { $vals[$key] = $value['key']; } ksort($vals); var_dump($vals); ?> ===DONE=== --EXPECT-- array(3) { ["key1"]=> string(4) "key1" ["key7"]=> string(4) "key7" ["key9"]=> string(4) "key9" } ===DONE=== apcu-5.1.23/tests/iterator_009.phpt 0000664 0001750 0001750 00000000576 14523735540 016010 0 ustar nikic nikic --TEST-- APC: APCIterator key invalidated between key() calls --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- rewind(); var_dump($it->key()); apcu_delete("foo"); apcu_store("bar", 0); var_dump($it->key()); ?> --EXPECT-- string(3) "foo" string(3) "foo" apcu-5.1.23/tests/iterator_010.phpt 0000664 0001750 0001750 00000001656 14523735540 016000 0 ustar nikic nikic --TEST-- APC: APCIterator shows entries older than global TTL --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.ttl=1 --FILE-- getTotalCount()}\n\n"; } apcu_store("no_ttl", "a"); apcu_store("ttl", "a", 3); echo "Initial state:\n"; printInfo(); echo "T+2:\n"; apcu_inc_request_time(2); printInfo(); echo "T+4:\n"; apcu_inc_request_time(2); printInfo(); ?> --EXPECT-- Initial state: array(2) { [0]=> string(6) "no_ttl" [1]=> string(3) "ttl" } Total: 2 T+2: array(2) { [0]=> string(6) "no_ttl" [1]=> string(3) "ttl" } Total: 2 T+4: array(1) { [0]=> string(6) "no_ttl" } Total: 1 apcu-5.1.23/tests/iterator_011.phpt 0000664 0001750 0001750 00000001231 14523735540 015766 0 ustar nikic nikic --TEST-- APCUIterator key() and current() on invalid iterator --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- key()); var_dump($it->current()); $it->next(); try { var_dump($it->key()); } catch (Error $e) { echo $e->getMessage(), "\n"; } try { var_dump($it->current()); } catch (Error $e) { echo $e->getMessage(), "\n"; } ?> --EXPECT-- string(4) "key1" array(1) { ["value"]=> string(6) "value1" } Cannot call key() on invalid iterator Cannot call current() on invalid iterator apcu-5.1.23/tests/not_enough_shm.phpt 0000664 0001750 0001750 00000000511 14523735540 016570 0 ustar nikic nikic --TEST-- Error if cache structures cannot be allocated in SHM --INI-- apc.enabled=1 apc.enable_cli=1 apc.shm_size=1M apc.entries_hint=1000000 --FILE-- Irrelevant --EXPECTF-- %A: Unable to allocate %d bytes of shared memory for cache structures. Either apc.shm_size is too small or apc.entries_hint too large in Unknown on line 0 apcu-5.1.23/tests/server_test.inc 0000664 0001750 0001750 00000010337 14523735540 015726 0 ustar nikic nikic STDIN, 1 => STDOUT, 2 => STDERR, ); if (!$php_args) { $ext = (substr(PHP_OS, 0, 3) == 'WIN') ? 'php_apcu.dll' : 'apcu.so'; if (substr(PHP_OS, 0, 3) == 'WIN') { $part0 = 8 == PHP_INT_SIZE ? "x64" : ""; $part1 = ZEND_DEBUG_BUILD ? "Debug" : "Release"; $part1 = PHP_ZTS ? ($part1 . "_TS") : $part1; $php_args = "-d extension_dir=$doc_root/../$part0/$part1"; } else { $php_args = "-d extension_dir=$doc_root/../modules"; } $php_args = "$php_args -d extension=$ext"; } if ($php_opts) { $php_args = "$php_args -d " . implode(' -d ', $php_opts);; } if (substr(PHP_OS, 0, 3) == 'WIN') { $cmd = "{$php_executable} -n $php_args -t {$doc_root} -S $host:$port"; if (!$no_router) { $cmd .= " {$router}"; } $descriptorspec[2] = array('pipe', 'w'); $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, $doc_root, NULL, array("bypass_shell" => true, "suppress_errors" => true)); } else { $cmd = "exec {$php_executable} -n $php_args -t {$doc_root} -S $host:$port"; if (!$no_router) { $cmd .= " {$doc_root}/{$router}"; } $cmd .= " 2>/dev/null"; $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root); } // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' // it might not be listening yet...need to wait until fsockopen() call returns // Let this wait for up to 10 seconds to avoid spurious failures with valgrind. $i = 0; while (($i++ < 100) && !connection_test($host, $port)) { usleep(100000); } return $handle; } function server_start($code = 'echo "Hello world";', $php_opts = array(), $no_router = FALSE) { global $doc_root, $router, $handles, $ports, $num_servers; if ($code) { file_put_contents($doc_root . '/' . $router, ''); } for ($i = 0; $i < $num_servers; $i++) { $h = server_start_one(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$i, $code, $php_opts, $no_router); $handles[] = $h; } register_shutdown_function( function($handles) use($router) { foreach ($handles as $handle) { proc_terminate($handle); } @unlink(__DIR__ . "/{$router}"); }, $handles ); // don't bother sleeping, server is already up // server can take a variable amount of time to be up, so just sleeping a guessed amount of time // does not work. this is why tests sometimes pass and sometimes fail. to get a reliable pass // sleeping doesn't work. } function get_response($fp, $data_only = true) { $s = ''; while (!feof($fp)) { $s .= fgets($fp); } if ($data_only) { $parts = explode("\r\n\r\n", $s); $s = $parts[1]; } return $s; } function connection_test($host, $port) { $port = intval($port)?:80; $fp = @fsockopen($host, $port, $errno, $errstr, 10); if (!$fp) { return false; } $send = "GET / HTTP/1.1\nHost: {$host}\r\n\r\n"; /* will not out here, just test if the connection has worked*/ if(@fwrite($fp, $send)) { get_response($fp); fclose($fp); return true; } @fclose($fp); return false; } function run_test_simple($request_uri = NULL) { global $num_servers; $send = "GET /" . $request_uri ." HTTP/1.1\nHost: " . PHP_CLI_SERVER_HOSTNAME . "\r\n\r\n"; for ($i = 0; $i < $num_servers; $i++) { run_test(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$i, $send); } } function run_test($host, $port, $send) { $fp = fsockopen($host, $port, $errno, $errstr, 10); if (!$fp) { die(sprintf("connect failed errno=%d errstr='%s'", $errno, $errstr)); } if(fwrite($fp, $send)) { echo get_response($fp); } fclose($fp); } apcu-5.1.23/tests/skipif.inc 0000664 0001750 0001750 00000000117 14523735540 014641 0 ustar nikic nikic apcu-5.1.23/tests/sma001.phpt 0000664 0001750 0001750 00000001077 14523735540 014565 0 ustar nikic nikic --TEST-- Test SMA behavior #1 --INI-- apc.enabled=1 apc.enable_cli=1 apc.shm_size=16M --FILE-- ===DONE=== --EXPECT-- ===DONE=== apcu-5.1.23/tests/typed_prop.phpt 0000664 0001750 0001750 00000001246 14523735540 015747 0 ustar nikic nikic --TEST-- Success parameters should respect property types --SKIPIF-- =') or die('skip Requires PHP >= 7.4'); ?> --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- bool); var_dump($test->bool); try { apcu_fetch('foo', $test->array); } catch (Error $e) { echo $e->getMessage(), "\n"; } var_dump($test->array); ?> --EXPECTF-- bool(true) Cannot assign %s to reference held by property Test::$array of type array array(0) { } apcu-5.1.23/tests/data/abc.data 0000664 0001750 0001750 00000000013 14523735540 015145 0 ustar nikic nikic s:3:"123"; apcu-5.1.23/tests/bad/abc.data 0000664 0001750 0001750 00000000011 14523735540 014760 0 ustar nikic nikic s:3:"123 apcu-5.1.23/apc_api.h 0000664 0001750 0001750 00000002355 14523735540 013272 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APCu | +----------------------------------------------------------------------+ | Copyright (c) 2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Joe Watkins| +----------------------------------------------------------------------+ */ #ifndef APC_API_H #define APC_API_H #include "apc.h" #include "apc_lock.h" #include "apc_sma.h" #include "apc_cache.h" #endif apcu-5.1.23/apc_arginfo.h 0000664 0001750 0001750 00000000161 14523735540 014137 0 ustar nikic nikic #if PHP_VERSION_ID < 80000 # include "php_apc_legacy_arginfo.h" #else # error Not supported on PHP >= 8.0 #endif apcu-5.1.23/php_apc.stub.php 0000664 0001750 0001750 00000002415 14523735540 014621 0 ustar nikic nikic | | George Schlossnagle | | Rasmus Lerdorf | | Arun C. Murthy | | Gopal Vijayaraghavan | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc.h" #include "apc_cache.h" #include "apc_globals.h" #include "php.h" /* {{{ console display functions */ #define APC_PRINT_FUNCTION(name, verbosity) \ void apc_##name(const char *format, ...) \ { \ va_list args; \ \ va_start(args, format); \ php_verror(NULL, "", verbosity, format, args); \ va_end(args); \ } APC_PRINT_FUNCTION(error, E_ERROR) APC_PRINT_FUNCTION(warning, E_WARNING) APC_PRINT_FUNCTION(notice, E_NOTICE) #ifdef APC_DEBUG APC_PRINT_FUNCTION(debug, E_NOTICE) #else void apc_debug(const char *format, ...) {} #endif /* }}} */ /* {{{ apc_flip_hash */ HashTable* apc_flip_hash(HashTable *hash) { zval data, *entry; HashTable *new_hash; if(hash == NULL) return hash; ZVAL_LONG(&data, 1); ALLOC_HASHTABLE(new_hash); zend_hash_init(new_hash, zend_hash_num_elements(hash), NULL, ZVAL_PTR_DTOR, 0); ZEND_HASH_FOREACH_VAL(hash, entry) { ZVAL_DEREF(entry); if (Z_TYPE_P(entry) == IS_STRING) { zend_hash_update(new_hash, Z_STR_P(entry), &data); } else { zend_hash_index_update(new_hash, Z_LVAL_P(entry), &data); } } ZEND_HASH_FOREACH_END(); return new_hash; } /* }}} */ /* * Serializer API */ #define APC_MAX_SERIALIZERS 16 /* pointer to the list of serializers */ static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}}; /* }}} */ /* {{{ apc_register_serializer */ PHP_APCU_API int _apc_register_serializer( const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config) { int i; apc_serializer_t *serializer; for(i = 0; i < APC_MAX_SERIALIZERS; i++) { serializer = &apc_serializers[i]; if(!serializer->name) { /* empty entry */ serializer->name = name; serializer->serialize = serialize; serializer->unserialize = unserialize; serializer->config = config; if (i < APC_MAX_SERIALIZERS - 1) { apc_serializers[i+1].name = NULL; } return 1; } } return 0; } /* }}} */ /* {{{ apc_get_serializers */ PHP_APCU_API apc_serializer_t* apc_get_serializers() { return &(apc_serializers[0]); } /* }}} */ /* {{{ apc_find_serializer */ PHP_APCU_API apc_serializer_t* apc_find_serializer(const char* name) { int i; apc_serializer_t *serializer; for(i = 0; i < APC_MAX_SERIALIZERS; i++) { serializer = &apc_serializers[i]; if(serializer->name && (strcmp(serializer->name, name) == 0)) { return serializer; } } return NULL; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_cache.c 0000664 0001750 0001750 00000076527 14523735540 013573 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http:www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | Rasmus Lerdorf | | Arun C. Murthy | | Gopal Vijayaraghavan | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc_cache.h" #include "apc_sma.h" #include "apc_globals.h" #include "apc_strings.h" #include "apc_time.h" #include "php_scandir.h" #include "SAPI.h" #include "TSRM.h" #include "php_main.h" #include "ext/standard/md5.h" #include "ext/standard/php_var.h" #include "zend_smart_str.h" #if PHP_VERSION_ID < 70300 # define GC_SET_REFCOUNT(ref, rc) (GC_REFCOUNT(ref) = (rc)) # define GC_ADDREF(ref) GC_REFCOUNT(ref)++ #endif /* If recursive mutexes are used, there is no distinction between read and write locks. * As such, if we acquire a read-lock, it's really a write-lock and we are free to perform * increments without atomics. */ #ifdef APC_LOCK_RECURSIVE # define ATOMIC_INC_RLOCKED(a) (a)++ #else # define ATOMIC_INC_RLOCKED(a) ATOMIC_INC(a) #endif /* Defined in apc_persist.c */ apc_cache_entry_t *apc_persist( apc_sma_t *sma, apc_serializer_t *serializer, const apc_cache_entry_t *orig_entry); zend_bool apc_unpersist(zval *dst, const zval *value, apc_serializer_t *serializer); /* {{{ make_prime */ static int const primes[] = { 257, /* 256 */ 521, /* 512 */ 1031, /* 1024 */ 2053, /* 2048 */ 3079, /* 3072 */ 4099, /* 4096 */ 5147, /* 5120 */ 6151, /* 6144 */ 7177, /* 7168 */ 8209, /* 8192 */ 9221, /* 9216 */ 10243, /* 10240 */ 11273, /* 11264 */ 12289, /* 12288 */ 13313, /* 13312 */ 14341, /* 14336 */ 15361, /* 15360 */ 16411, /* 16384 */ 17417, /* 17408 */ 18433, /* 18432 */ 19457, /* 19456 */ 20483, /* 20480 */ 30727, /* 30720 */ 40961, /* 40960 */ 61441, /* 61440 */ 81929, /* 81920 */ 122887,/* 122880 */ 163841,/* 163840 */ 245771,/* 245760 */ 327689,/* 327680 */ 491527,/* 491520 */ 655373,/* 655360 */ 983063,/* 983040 */ 1310627,/* 1310720 */ 1474489,/* 1474560 */ 1965983,/* 1966080 */ 2621347,/* 2621440 */ 3276719,/* 3276800 */ 3932063,/* 3932160 */ 4587431,/* 4587520 */ 5242801,/* 5242880 */ 6553511,/* 6553600 */ 7864243,/* 7864320 */ 8847271,/* 8847360 */ 9830321,/* 9830400 */ 10485667,/* 10485760 */ 0 /* sentinel */ }; static int make_prime(int n) { int *k = (int*)primes; while(*k) { if((*k) > n) return *k; k++; } return *(k-1); } /* }}} */ static inline void free_entry(apc_cache_t *cache, apc_cache_entry_t *entry) { apc_sma_free(cache->sma, entry); } /* {{{ apc_cache_hash_slot Note: These calculations can and should be done outside of a lock */ static inline void apc_cache_hash_slot( apc_cache_t* cache, zend_string *key, zend_ulong* hash, size_t* slot) { *hash = ZSTR_HASH(key); *slot = *hash % cache->nslots; } /* }}} */ static inline zend_bool apc_entry_key_equals(const apc_cache_entry_t *entry, zend_string *key, zend_ulong hash) { return ZSTR_H(entry->key) == hash && ZSTR_LEN(entry->key) == ZSTR_LEN(key) && memcmp(ZSTR_VAL(entry->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0; } /* An entry is hard expired if the creation time if older than the per-entry TTL. * Hard expired entries must be treated indentially to non-existent entries. */ static zend_bool apc_cache_entry_hard_expired(apc_cache_entry_t *entry, time_t t) { return entry->ttl && (time_t) (entry->ctime + entry->ttl) < t; } /* An entry is soft expired if no per-entry TTL is set, a global cache TTL is set, * and the access time of the entry is older than the global TTL. Soft expired entries * are accessible by lookup operation, but may be removed from the cache at any time. */ static zend_bool apc_cache_entry_soft_expired( apc_cache_t *cache, apc_cache_entry_t *entry, time_t t) { return !entry->ttl && cache->ttl && (time_t) (entry->atime + cache->ttl) < t; } static zend_bool apc_cache_entry_expired( apc_cache_t *cache, apc_cache_entry_t *entry, time_t t) { return apc_cache_entry_hard_expired(entry, t) || apc_cache_entry_soft_expired(cache, entry, t); } /* {{{ apc_cache_wlocked_remove_entry */ static void apc_cache_wlocked_remove_entry(apc_cache_t *cache, apc_cache_entry_t **entry) { apc_cache_entry_t *dead = *entry; /* think here is safer */ *entry = (*entry)->next; /* adjust header info */ if (cache->header->mem_size) cache->header->mem_size -= dead->mem_size; if (cache->header->nentries) cache->header->nentries--; /* remove if there are no references */ if (dead->ref_count <= 0) { free_entry(cache, dead); } else { /* add to gc if there are still refs */ dead->next = cache->header->gc; dead->dtime = time(0); cache->header->gc = dead; } } /* }}} */ /* {{{ apc_cache_wlocked_gc */ static void apc_cache_wlocked_gc(apc_cache_t* cache) { /* This function scans the list of removed cache entries and deletes any * entry whose reference count is zero or that has been on the gc * list for more than cache->gc_ttl seconds * (we issue a warning in the latter case). */ if (!cache->header->gc) { return; } { apc_cache_entry_t **entry = &cache->header->gc; time_t now = time(0); while (*entry != NULL) { time_t gc_sec = cache->gc_ttl ? (now - (*entry)->dtime) : 0; if (!(*entry)->ref_count || gc_sec > (time_t)cache->gc_ttl) { apc_cache_entry_t *dead = *entry; /* good ol' whining */ if (dead->ref_count > 0) { apc_debug( "GC cache entry '%s' was on gc-list for %ld seconds", ZSTR_VAL(dead->key), gc_sec ); } /* set next entry */ *entry = (*entry)->next; /* free entry */ free_entry(cache, dead); } else { entry = &(*entry)->next; } } } } /* }}} */ /* {{{ php serializer */ PHP_APCU_API int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS) { smart_str strbuf = {0}; php_serialize_data_t var_hash; /* Lock in case apcu is accessed inside Serializer::serialize() */ BG(serialize_lock)++; PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&strbuf, (zval*) value, &var_hash); PHP_VAR_SERIALIZE_DESTROY(var_hash); BG(serialize_lock)--; if (EG(exception)) { smart_str_free(&strbuf); strbuf.s = NULL; } if (strbuf.s != NULL) { *buf = (unsigned char *)estrndup(ZSTR_VAL(strbuf.s), ZSTR_LEN(strbuf.s)); if (*buf == NULL) return 0; *buf_len = ZSTR_LEN(strbuf.s); smart_str_free(&strbuf); return 1; } return 0; } /* }}} */ /* {{{ php unserializer */ PHP_APCU_API int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS) { const unsigned char *tmp = buf; php_unserialize_data_t var_hash; int result; /* Lock in case apcu is accessed inside Serializer::unserialize() */ BG(serialize_lock)++; PHP_VAR_UNSERIALIZE_INIT(var_hash); result = php_var_unserialize(value, &tmp, buf + buf_len, &var_hash); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); BG(serialize_lock)--; if (!result) { php_error_docref(NULL, E_NOTICE, "Error at offset %ld of %ld bytes", (zend_long)(tmp - buf), (zend_long)buf_len); ZVAL_NULL(value); return 0; } return 1; } /* }}} */ /* {{{ apc_cache_create */ PHP_APCU_API apc_cache_t* apc_cache_create(apc_sma_t* sma, apc_serializer_t* serializer, zend_long size_hint, zend_long gc_ttl, zend_long ttl, zend_long smart, zend_bool defend) { apc_cache_t* cache; zend_long cache_size; size_t nslots; /* calculate number of slots */ nslots = make_prime(size_hint > 0 ? size_hint : 2000); /* allocate pointer by normal means */ cache = pemalloc(sizeof(apc_cache_t), 1); /* calculate cache size for shm allocation */ cache_size = sizeof(apc_cache_header_t) + nslots*sizeof(apc_cache_entry_t *); /* allocate shm */ cache->shmaddr = apc_sma_malloc(sma, cache_size); if (!cache->shmaddr) { zend_error_noreturn(E_CORE_ERROR, "Unable to allocate " ZEND_LONG_FMT " bytes of shared memory for cache structures. Either apc.shm_size is too small or apc.entries_hint too large", cache_size); return NULL; } /* zero cache header and hash slots */ memset(cache->shmaddr, 0, cache_size); /* set default header */ cache->header = (apc_cache_header_t*) cache->shmaddr; cache->header->nhits = 0; cache->header->nmisses = 0; cache->header->nentries = 0; cache->header->nexpunges = 0; cache->header->gc = NULL; cache->header->stime = time(NULL); cache->header->state = 0; /* set cache options */ cache->slots = (apc_cache_entry_t **) (((char*) cache->shmaddr) + sizeof(apc_cache_header_t)); cache->sma = sma; cache->serializer = serializer; cache->nslots = nslots; cache->gc_ttl = gc_ttl; cache->ttl = ttl; cache->smart = smart; cache->defend = defend; /* header lock */ CREATE_LOCK(&cache->header->lock); return cache; } /* }}} */ static inline zend_bool apc_cache_wlocked_insert( apc_cache_t *cache, apc_cache_entry_t *new_entry, zend_bool exclusive) { zend_string *key = new_entry->key; time_t t = new_entry->ctime; /* process deleted list */ apc_cache_wlocked_gc(cache); /* make the insertion */ { apc_cache_entry_t **entry; zend_ulong h; size_t s; /* calculate hash and entry */ apc_cache_hash_slot(cache, key, &h, &s); entry = &cache->slots[s]; while (*entry) { /* check for a match by hash and string */ if (apc_entry_key_equals(*entry, key, h)) { /* * At this point we have found the user cache entry. If we are doing * an exclusive insert (apc_add) we are going to bail right away if * the user entry already exists and is hard expired. */ if (exclusive && !apc_cache_entry_hard_expired(*entry, t)) { return 0; } apc_cache_wlocked_remove_entry(cache, entry); break; } /* * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of * entry entries so we don't always have to skip past a bunch of stale entries. */ if (apc_cache_entry_expired(cache, *entry, t)) { apc_cache_wlocked_remove_entry(cache, entry); continue; } /* set next entry */ entry = &(*entry)->next; } /* link in new entry */ new_entry->next = *entry; *entry = new_entry; cache->header->mem_size += new_entry->mem_size; cache->header->nentries++; cache->header->ninserts++; } return 1; } static void apc_cache_init_entry( apc_cache_entry_t *entry, zend_string *key, const zval* val, const int32_t ttl, time_t t); /* TODO This function may lead to a deadlock on expunge */ static inline zend_bool apc_cache_store_internal( apc_cache_t *cache, zend_string *key, const zval *val, const int32_t ttl, const zend_bool exclusive) { apc_cache_entry_t tmp_entry, *entry; time_t t = apc_time(); if (apc_cache_defense(cache, key, t)) { return 0; } /* initialize the entry for insertion */ apc_cache_init_entry(&tmp_entry, key, val, ttl, t); entry = apc_persist(cache->sma, cache->serializer, &tmp_entry); if (!entry) { return 0; } /* execute an insertion */ if (!apc_cache_wlocked_insert(cache, entry, exclusive)) { free_entry(cache, entry); return 0; } return 1; } /* Find entry, without updating stat counters or access time */ static inline apc_cache_entry_t *apc_cache_rlocked_find_nostat( apc_cache_t *cache, zend_string *key, time_t t) { apc_cache_entry_t *entry; zend_ulong h; size_t s; /* calculate hash and slot */ apc_cache_hash_slot(cache, key, &h, &s); entry = cache->slots[s]; while (entry) { /* check for a matching key by has and identifier */ if (apc_entry_key_equals(entry, key, h)) { /* Check to make sure this entry isn't expired by a hard TTL */ if (apc_cache_entry_hard_expired(entry, t)) { break; } return entry; } entry = entry->next; } return NULL; } /* Find entry, updating stat counters and access time */ static inline apc_cache_entry_t *apc_cache_rlocked_find( apc_cache_t *cache, zend_string *key, time_t t) { apc_cache_entry_t *entry; zend_ulong h; size_t s; /* calculate hash and slot */ apc_cache_hash_slot(cache, key, &h, &s); entry = cache->slots[s]; while (entry) { /* check for a matching key by has and identifier */ if (apc_entry_key_equals(entry, key, h)) { /* Check to make sure this entry isn't expired by a hard TTL */ if (apc_cache_entry_hard_expired(entry, t)) { break; } ATOMIC_INC_RLOCKED(cache->header->nhits); ATOMIC_INC_RLOCKED(entry->nhits); entry->atime = t; return entry; } entry = entry->next; } ATOMIC_INC_RLOCKED(cache->header->nmisses); return NULL; } static inline apc_cache_entry_t *apc_cache_rlocked_find_incref( apc_cache_t *cache, zend_string *key, time_t t) { apc_cache_entry_t *entry = apc_cache_rlocked_find(cache, key, t); if (!entry) { return NULL; } ATOMIC_INC_RLOCKED(entry->ref_count); return entry; } /* {{{ apc_cache_store */ PHP_APCU_API zend_bool apc_cache_store( apc_cache_t* cache, zend_string *key, const zval *val, const int32_t ttl, const zend_bool exclusive) { apc_cache_entry_t tmp_entry, *entry; time_t t = apc_time(); zend_bool ret = 0; if (!cache) { return 0; } /* run cache defense */ if (apc_cache_defense(cache, key, t)) { return 0; } /* initialize the entry for insertion */ apc_cache_init_entry(&tmp_entry, key, val, ttl, t); entry = apc_persist(cache->sma, cache->serializer, &tmp_entry); if (!entry) { return 0; } /* execute an insertion */ if (!apc_cache_wlock(cache)) { free_entry(cache, entry); return 0; } php_apc_try { ret = apc_cache_wlocked_insert(cache, entry, exclusive); } php_apc_finally { apc_cache_wunlock(cache); } php_apc_end_try(); if (!ret) { free_entry(cache, entry); } return ret; } /* }}} */ #ifndef ZTS /* {{{ data_unserialize */ static zval data_unserialize(const char *filename) { zval retval; zend_long len = 0; zend_stat_t sb; char *contents, *tmp; FILE *fp; php_unserialize_data_t var_hash = {0,}; if(VCWD_STAT(filename, &sb) == -1) { return EG(uninitialized_zval); } fp = fopen(filename, "rb"); len = sizeof(char)*sb.st_size; tmp = contents = malloc(len); if(!contents) { fclose(fp); return EG(uninitialized_zval); } if(fread(contents, 1, len, fp) < 1) { fclose(fp); free(contents); return EG(uninitialized_zval); } ZVAL_UNDEF(&retval); PHP_VAR_UNSERIALIZE_INIT(var_hash); /* I wish I could use json */ if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash)) { fclose(fp); free(contents); return EG(uninitialized_zval); } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); free(contents); fclose(fp); return retval; } static int apc_load_data(apc_cache_t* cache, const char *data_file) { char *p; char key[MAXPATHLEN] = {0,}; size_t key_len; zval data; p = strrchr(data_file, DEFAULT_SLASH); if(p && p[1]) { strlcpy(key, p+1, sizeof(key)); p = strrchr(key, '.'); if(p) { p[0] = '\0'; key_len = strlen(key); data = data_unserialize(data_file); if(Z_TYPE(data) != IS_UNDEF) { zend_string *name = zend_string_init(key, key_len, 0); apc_cache_store( cache, name, &data, 0, 1); zend_string_release(name); zval_dtor(&data); } return 1; } } return 0; } #endif /* {{{ apc_cache_preload shall load the prepared data files in path into the specified cache */ PHP_APCU_API zend_bool apc_cache_preload(apc_cache_t* cache, const char *path) { #ifndef ZTS zend_bool result = 0; char file[MAXPATHLEN]={0,}; int ndir, i; char *p = NULL; struct dirent **namelist = NULL; if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0) { for (i = 0; i < ndir; i++) { /* check for extension */ if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".data"))) { free(namelist[i]); continue; } snprintf(file, MAXPATHLEN, "%s%c%s", path, DEFAULT_SLASH, namelist[i]->d_name); if(apc_load_data(cache, file)) { result = 1; } free(namelist[i]); } free(namelist); } return result; #else apc_error("Cannot load data from apc.preload_path=%s in thread-safe mode", path); return 0; #endif } /* }}} */ /* {{{ apc_cache_entry_release */ PHP_APCU_API void apc_cache_entry_release(apc_cache_t *cache, apc_cache_entry_t *entry) { ATOMIC_DEC(entry->ref_count); } /* }}} */ /* {{{ apc_cache_detach */ PHP_APCU_API void apc_cache_detach(apc_cache_t *cache) { /* Important: This function should not clean up anything that's in shared memory, * only detach our process-local use of it. In particular locks cannot be destroyed * here. */ if (!cache) { return; } free(cache); } /* }}} */ /* {{{ apc_cache_wlocked_real_expunge */ static void apc_cache_wlocked_real_expunge(apc_cache_t* cache) { size_t i; /* increment counter */ cache->header->nexpunges++; /* expunge */ for (i = 0; i < cache->nslots; i++) { apc_cache_entry_t **entry = &cache->slots[i]; while (*entry) { apc_cache_wlocked_remove_entry(cache, entry); } } /* set new time so counters make sense */ cache->header->stime = apc_time(); /* reset counters */ cache->header->ninserts = 0; cache->header->nentries = 0; cache->header->nhits = 0; cache->header->nmisses = 0; /* resets lastkey */ memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t)); } /* }}} */ /* {{{ apc_cache_clear */ PHP_APCU_API void apc_cache_clear(apc_cache_t* cache) { if (!cache) { return; } if (!apc_cache_wlock(cache)) { return; } /* expunge cache */ apc_cache_wlocked_real_expunge(cache); /* set info */ cache->header->stime = apc_time(); cache->header->nexpunges = 0; apc_cache_wunlock(cache); } /* }}} */ /* {{{ apc_cache_default_expunge */ PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size) { time_t t; size_t suitable = 0L; size_t available = 0L; if (!cache) { return; } /* apc_time() depends on globals, don't read it if there's no cache. This may happen if SHM * is too small and the initial cache creation during MINIT triggers an expunge. */ t = apc_time(); /* get the lock for header */ if (!apc_cache_wlock(cache)) { return; } /* make suitable selection */ suitable = (cache->smart > 0L) ? (size_t) (cache->smart * size) : (size_t) (cache->sma->size/2); /* gc */ apc_cache_wlocked_gc(cache); /* get available */ available = apc_sma_get_avail_mem(cache->sma); /* perform expunge processing */ if (!cache->ttl) { /* check it is necessary to expunge */ if (available < suitable) { apc_cache_wlocked_real_expunge(cache); } } else { /* check that expunge is necessary */ if (available < suitable) { size_t i; /* look for junk */ for (i = 0; i < cache->nslots; i++) { apc_cache_entry_t **entry = &cache->slots[i]; while (*entry) { if (apc_cache_entry_expired(cache, *entry, t)) { apc_cache_wlocked_remove_entry(cache, entry); continue; } /* grab next entry */ entry = &(*entry)->next; } } /* if the cache now has space, then reset last key */ if (apc_sma_get_avail_size(cache->sma, size)) { /* wipe lastkey */ memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t)); } else { /* with not enough space left in cache, we are forced to expunge */ apc_cache_wlocked_real_expunge(cache); } } } apc_cache_wunlock(cache); } /* }}} */ /* {{{ apc_cache_find */ PHP_APCU_API apc_cache_entry_t *apc_cache_find(apc_cache_t* cache, zend_string *key, time_t t) { apc_cache_entry_t *entry; if (!cache) { return NULL; } if (!apc_cache_rlock(cache)) { return NULL; } entry = apc_cache_rlocked_find_incref(cache, key, t); apc_cache_runlock(cache); return entry; } /* }}} */ /* {{{ apc_cache_fetch */ PHP_APCU_API zend_bool apc_cache_fetch(apc_cache_t* cache, zend_string *key, time_t t, zval *dst) { apc_cache_entry_t *entry; zend_bool retval = 0; if (!cache) { return 0; } if (!apc_cache_rlock(cache)) { return 0; } entry = apc_cache_rlocked_find_incref(cache, key, t); apc_cache_runlock(cache); if (!entry) { return 0; } php_apc_try { retval = apc_cache_entry_fetch_zval(cache, entry, dst); } php_apc_finally { apc_cache_entry_release(cache, entry); } php_apc_end_try(); return retval; } /* }}} */ /* {{{ apc_cache_exists */ PHP_APCU_API zend_bool apc_cache_exists(apc_cache_t* cache, zend_string *key, time_t t) { apc_cache_entry_t *entry; if (!cache) { return 0; } if (!apc_cache_rlock(cache)) { return 0; } entry = apc_cache_rlocked_find_nostat(cache, key, t); apc_cache_runlock(cache); return entry != NULL; } /* }}} */ /* {{{ apc_cache_update */ PHP_APCU_API zend_bool apc_cache_update( apc_cache_t *cache, zend_string *key, apc_cache_updater_t updater, void *data, zend_bool insert_if_not_found, zend_long ttl) { apc_cache_entry_t *entry; zend_bool retval = 0; time_t t = apc_time(); if (!cache) { return 0; } retry_update: if (!apc_cache_wlock(cache)) { return 0; } entry = apc_cache_rlocked_find_nostat(cache, key, t); if (entry) { /* Only allow changes to simple values */ if (Z_TYPE(entry->val) < IS_STRING) { retval = updater(cache, entry, data); entry->mtime = t; } apc_cache_wunlock(cache); return retval; } apc_cache_wunlock(cache); if (insert_if_not_found) { /* Failed to find matching entry. Add key with value 0 and run the updater again. */ zval val; ZVAL_LONG(&val, 0); /* We do not check the return value of the exclusive-store (add), as the entry might have * been added between the cache unlock and the store call. In this case we just want to * update the entry created by a different process. */ apc_cache_store(cache, key, &val, ttl, 1); /* Only attempt to perform insertion once. */ insert_if_not_found = 0; goto retry_update; } return 0; } /* }}} */ /* {{{ apc_cache_atomic_update_long */ PHP_APCU_API zend_bool apc_cache_atomic_update_long( apc_cache_t *cache, zend_string *key, apc_cache_atomic_updater_t updater, void *data, zend_bool insert_if_not_found, zend_long ttl) { apc_cache_entry_t *entry; zend_bool retval = 0; time_t t = apc_time(); if (!cache) { return 0; } retry_update: if (!apc_cache_rlock(cache)) { return 0; } entry = apc_cache_rlocked_find_nostat(cache, key, t); if (entry) { /* Only supports integers */ if (Z_TYPE(entry->val) == IS_LONG) { retval = updater(cache, &Z_LVAL(entry->val), data); entry->mtime = t; } apc_cache_runlock(cache); return retval; } apc_cache_runlock(cache); if (insert_if_not_found) { /* Failed to find matching entry. Add key with value 0 and run the updater again. */ zval val; ZVAL_LONG(&val, 0); /* We do not check the return value of the exclusive-store (add), as the entry might have * been added between the cache unlock and the store call. In this case we just want to * update the entry created by a different process. */ apc_cache_store(cache, key, &val, ttl, 1); /* Only attempt to perform insertion once. */ insert_if_not_found = 0; goto retry_update; } return 0; } /* }}} */ /* {{{ apc_cache_delete */ PHP_APCU_API zend_bool apc_cache_delete(apc_cache_t *cache, zend_string *key) { apc_cache_entry_t **entry; zend_ulong h; size_t s; if (!cache) { return 0; } /* calculate hash and slot */ apc_cache_hash_slot(cache, key, &h, &s); if (!apc_cache_wlock(cache)) { return 0; } /* find head */ entry = &cache->slots[s]; while (*entry) { /* check for a match by hash and identifier */ if (apc_entry_key_equals(*entry, key, h)) { /* executing removal */ apc_cache_wlocked_remove_entry(cache, entry); apc_cache_wunlock(cache); return 1; } entry = &(*entry)->next; } apc_cache_wunlock(cache); return 0; } /* }}} */ /* {{{ apc_cache_entry_fetch_zval */ PHP_APCU_API zend_bool apc_cache_entry_fetch_zval( apc_cache_t *cache, apc_cache_entry_t *entry, zval *dst) { return apc_unpersist(dst, &entry->val, cache->serializer); } /* }}} */ /* {{{ apc_cache_make_entry */ static void apc_cache_init_entry( apc_cache_entry_t *entry, zend_string *key, const zval *val, const int32_t ttl, time_t t) { entry->ttl = ttl; entry->key = key; ZVAL_COPY_VALUE(&entry->val, val); entry->next = NULL; entry->ref_count = 0; entry->mem_size = 0; entry->nhits = 0; entry->ctime = t; entry->mtime = t; entry->atime = t; entry->dtime = 0; } /* }}} */ static inline void array_add_long(zval *array, zend_string *key, zend_long lval) { zval zv; ZVAL_LONG(&zv, lval); zend_hash_add_new(Z_ARRVAL_P(array), key, &zv); } static inline void array_add_double(zval *array, zend_string *key, double dval) { zval zv; ZVAL_DOUBLE(&zv, dval); zend_hash_add_new(Z_ARRVAL_P(array), key, &zv); } /* {{{ apc_cache_link_info */ static zval apc_cache_link_info(apc_cache_t *cache, apc_cache_entry_t *p) { zval link, zv; array_init(&link); ZVAL_STR(&zv, zend_string_dup(p->key, 0)); zend_hash_add_new(Z_ARRVAL(link), apc_str_info, &zv); array_add_long(&link, apc_str_ttl, p->ttl); array_add_double(&link, apc_str_num_hits, (double) p->nhits); array_add_long(&link, apc_str_mtime, p->mtime); array_add_long(&link, apc_str_creation_time, p->ctime); array_add_long(&link, apc_str_deletion_time, p->dtime); array_add_long(&link, apc_str_access_time, p->atime); array_add_long(&link, apc_str_ref_count, p->ref_count); array_add_long(&link, apc_str_mem_size, p->mem_size); return link; } /* }}} */ /* {{{ apc_cache_info */ PHP_APCU_API zend_bool apc_cache_info(zval *info, apc_cache_t *cache, zend_bool limited) { zval list; zval gc; zval slots; apc_cache_entry_t *p; zend_ulong j; ZVAL_NULL(info); if (!cache) { return 0; } if (!apc_cache_rlock(cache)) { return 0; } php_apc_try { array_init(info); add_assoc_long(info, "num_slots", cache->nslots); array_add_long(info, apc_str_ttl, cache->ttl); array_add_double(info, apc_str_num_hits, (double) cache->header->nhits); add_assoc_double(info, "num_misses", (double) cache->header->nmisses); add_assoc_double(info, "num_inserts", (double) cache->header->ninserts); add_assoc_long(info, "num_entries", cache->header->nentries); add_assoc_double(info, "expunges", (double) cache->header->nexpunges); add_assoc_long(info, "start_time", cache->header->stime); array_add_double(info, apc_str_mem_size, (double) cache->header->mem_size); #if APC_MMAP add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1); #else add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1); #endif if (!limited) { size_t i; /* For each hashtable slot */ array_init(&list); array_init(&slots); for (i = 0; i < cache->nslots; i++) { p = cache->slots[i]; j = 0; for (; p != NULL; p = p->next) { zval link = apc_cache_link_info(cache, p); add_next_index_zval(&list, &link); j++; } if (j != 0) { add_index_long(&slots, (zend_ulong)i, j); } } /* For each slot pending deletion */ array_init(&gc); for (p = cache->header->gc; p != NULL; p = p->next) { zval link = apc_cache_link_info(cache, p); add_next_index_zval(&gc, &link); } add_assoc_zval(info, "cache_list", &list); add_assoc_zval(info, "deleted_list", &gc); add_assoc_zval(info, "slot_distribution", &slots); } } php_apc_finally { apc_cache_runlock(cache); } php_apc_end_try(); return 1; } /* }}} */ /* fetches information about the key provided */ PHP_APCU_API void apc_cache_stat(apc_cache_t *cache, zend_string *key, zval *stat) { zend_ulong h; size_t s; ZVAL_NULL(stat); if (!cache) { return; } /* calculate hash and slot */ apc_cache_hash_slot(cache, key, &h, &s); if (!apc_cache_rlock(cache)) { return; } php_apc_try { /* find head */ apc_cache_entry_t *entry = cache->slots[s]; while (entry) { /* check for a matching key by has and identifier */ if (apc_entry_key_equals(entry, key, h)) { array_init(stat); array_add_long(stat, apc_str_hits, entry->nhits); array_add_long(stat, apc_str_access_time, entry->atime); array_add_long(stat, apc_str_mtime, entry->mtime); array_add_long(stat, apc_str_creation_time, entry->ctime); array_add_long(stat, apc_str_deletion_time, entry->dtime); array_add_long(stat, apc_str_ttl, entry->ttl); array_add_long(stat, apc_str_refs, entry->ref_count); break; } /* next */ entry = entry->next; } } php_apc_finally { apc_cache_runlock(cache); } php_apc_end_try(); } /* {{{ apc_cache_defense */ PHP_APCU_API zend_bool apc_cache_defense(apc_cache_t *cache, zend_string *key, time_t t) { /* only continue if slam defense is enabled */ if (cache->defend) { /* for copy of locking key struct */ apc_cache_slam_key_t *last = &cache->header->lastkey; pid_t owner_pid = getpid(); #ifdef ZTS void ***owner_thread = TSRMLS_CACHE; #endif /* check the hash and length match */ /* check the time (last second considered slam) and context */ if (last->hash == ZSTR_HASH(key) && last->len == ZSTR_LEN(key) && last->mtime == t && (last->owner_pid != owner_pid #if ZTS || last->owner_thread != owner_thread #endif ) ) { /* potential cache slam */ return 1; } /* sets enough information for an educated guess, but is not exact */ last->hash = ZSTR_HASH(key); last->len = ZSTR_LEN(key); last->mtime = t; last->owner_pid = owner_pid; #ifdef ZTS last->owner_thread = owner_thread; #endif } return 0; } /* }}} */ /* {{{ apc_cache_serializer */ PHP_APCU_API void apc_cache_serializer(apc_cache_t* cache, const char* name) { if (cache && !cache->serializer) { cache->serializer = apc_find_serializer(name); } } /* }}} */ PHP_APCU_API void apc_cache_entry(apc_cache_t *cache, zend_string *key, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_long ttl, zend_long now, zval *return_value) {/*{{{*/ apc_cache_entry_t *entry = NULL; if (!cache) { return; } if (!apc_cache_wlock(cache)) { return; } APCG(entry_level)++; php_apc_try { entry = apc_cache_rlocked_find_incref(cache, key, now); if (!entry) { int result; zval params[1]; ZVAL_STR_COPY(¶ms[0], key); fci->retval = return_value; fci->param_count = 1; fci->params = params; result = zend_call_function(fci, fcc); zval_ptr_dtor(¶ms[0]); if (result == SUCCESS && !EG(exception)) { apc_cache_store_internal( cache, key, return_value, (uint32_t) ttl, 1); } } else { apc_cache_entry_fetch_zval(cache, entry, return_value); apc_cache_entry_release(cache, entry); } } php_apc_finally { APCG(entry_level)--; apc_cache_wunlock(cache); } php_apc_end_try(); } /*}}}*/ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_cache.h 0000664 0001750 0001750 00000032033 14523735540 013560 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_CACHE_H #define APC_CACHE_H #include "apc.h" #include "apc_sma.h" #include "apc_lock.h" #include "apc_globals.h" #include "TSRM.h" typedef struct apc_cache_slam_key_t apc_cache_slam_key_t; struct apc_cache_slam_key_t { zend_ulong hash; /* hash of the key */ size_t len; /* length of the key */ time_t mtime; /* creation time of this key */ pid_t owner_pid; /* the pid that created this key */ #ifdef ZTS void ***owner_thread; /* TSRMLS cache of thread that created this key */ #endif }; /* {{{ struct definition: apc_cache_entry_t */ typedef struct apc_cache_entry_t apc_cache_entry_t; struct apc_cache_entry_t { zend_string *key; /* entry key */ zval val; /* the zval copied at store time */ apc_cache_entry_t *next; /* next entry in linked list */ zend_long ttl; /* the ttl on this specific entry */ zend_long ref_count; /* the reference count of this entry */ zend_long nhits; /* number of hits to this entry */ time_t ctime; /* time entry was initialized */ time_t mtime; /* the mtime of this cached entry */ time_t dtime; /* time entry was removed from cache */ time_t atime; /* time entry was last accessed */ zend_long mem_size; /* memory used */ }; /* }}} */ /* {{{ struct definition: apc_cache_header_t Any values that must be shared among processes should go in here. */ typedef struct _apc_cache_header_t { apc_lock_t lock; /* header lock */ zend_long nhits; /* hit count */ zend_long nmisses; /* miss count */ zend_long ninserts; /* insert count */ zend_long nexpunges; /* expunge count */ zend_long nentries; /* entry count */ zend_long mem_size; /* used */ time_t stime; /* start time */ unsigned short state; /* cache state */ apc_cache_slam_key_t lastkey; /* last key inserted (not necessarily without error) */ apc_cache_entry_t *gc; /* gc list */ } apc_cache_header_t; /* }}} */ /* {{{ struct definition: apc_cache_t */ typedef struct _apc_cache_t { void* shmaddr; /* process (local) address of shared cache */ apc_cache_header_t* header; /* cache header (stored in SHM) */ apc_cache_entry_t** slots; /* array of cache slots (stored in SHM) */ apc_sma_t* sma; /* shared memory allocator */ apc_serializer_t* serializer; /* serializer */ size_t nslots; /* number of slots in cache */ zend_long gc_ttl; /* maximum time on GC list for a entry */ zend_long ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ zend_long smart; /* smart parameter for gc */ zend_bool defend; /* defense parameter for runtime */ } apc_cache_t; /* }}} */ /* {{{ typedef: apc_cache_updater_t */ typedef zend_bool (*apc_cache_updater_t)(apc_cache_t*, apc_cache_entry_t*, void* data); /* }}} */ /* {{{ typedef: apc_cache_atomic_updater_t */ typedef zend_bool (*apc_cache_atomic_updater_t)(apc_cache_t*, zend_long*, void* data); /* }}} */ /* * apc_cache_create creates the shared memory cache. * * This function should be called once per process per cache * * serializer for APCu is set by globals on MINIT and ensured with apc_cache_serializer * during execution. Using apc_cache_serializer avoids race conditions between MINIT/RINIT of * APCU and the third party serializer. API users can choose to leave this null to use default * PHP serializers, or search the list of serializers for the preferred serializer * * size_hint is a "hint" at the total number entries that will be expected. * It determines the physical size of the hash table. Passing 0 for * this argument will use a reasonable default value * * gc_ttl is the maximum time a cache entry may speed on the garbage * collection list. This is basically a work around for the inherent * unreliability of our reference counting mechanism (see apc_cache_release). * * ttl is the maximum time a cache entry can idle in a slot in case the slot * is needed. This helps in cleaning up the cache and ensuring that entries * hit frequently stay cached and ones not hit very often eventually disappear. * * for an explanation of smart, see apc_cache_default_expunge * * defend enables/disables slam defense for this particular cache */ PHP_APCU_API apc_cache_t* apc_cache_create( apc_sma_t* sma, apc_serializer_t* serializer, zend_long size_hint, zend_long gc_ttl, zend_long ttl, zend_long smart, zend_bool defend); /* * apc_cache_preload preloads the data at path into the specified cache */ PHP_APCU_API zend_bool apc_cache_preload(apc_cache_t* cache, const char* path); /* * apc_cache_detach detaches from the shared memory cache and cleans up * local allocations. Under apache, this function can be safely called by * the child processes when they exit. */ PHP_APCU_API void apc_cache_detach(apc_cache_t* cache); /* * apc_cache_clear empties a cache. This can safely be called at any time. */ PHP_APCU_API void apc_cache_clear(apc_cache_t* cache); /* * apc_cache_store creates key, entry and context in which to make an insertion of val into the specified cache */ PHP_APCU_API zend_bool apc_cache_store( apc_cache_t* cache, zend_string *key, const zval *val, const int32_t ttl, const zend_bool exclusive); /* * apc_cache_update updates an entry in place. The updater function must not bailout. * The update is performed under write-lock and doesn't have to be atomic. */ PHP_APCU_API zend_bool apc_cache_update( apc_cache_t *cache, zend_string *key, apc_cache_updater_t updater, void *data, zend_bool insert_if_not_found, zend_long ttl); /* * apc_cache_atomic_update_long updates an integer entry in place. The updater function must * perform the update atomically, as the update is performed under read-lock. */ PHP_APCU_API zend_bool apc_cache_atomic_update_long( apc_cache_t *cache, zend_string *key, apc_cache_atomic_updater_t updater, void *data, zend_bool insert_if_not_found, zend_long ttl); /* * apc_cache_find searches for a cache entry by its hashed identifier, * and returns a pointer to the entry if found, NULL otherwise. * */ PHP_APCU_API apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, zend_string *key, time_t t); /* * apc_cache_fetch fetches an entry from the cache directly into dst * */ PHP_APCU_API zend_bool apc_cache_fetch(apc_cache_t* cache, zend_string *key, time_t t, zval *dst); /* * apc_cache_exists searches for a cache entry by its hashed identifier, * and returns whether the entry exists. */ PHP_APCU_API zend_bool apc_cache_exists(apc_cache_t* cache, zend_string *key, time_t t); /* * apc_cache_delete and apc_cache_delete finds an entry in the cache and deletes it. */ PHP_APCU_API zend_bool apc_cache_delete(apc_cache_t* cache, zend_string *key); /* apc_cache_fetch_zval copies a cache entry value to be usable at runtime. */ PHP_APCU_API zend_bool apc_cache_entry_fetch_zval( apc_cache_t *cache, apc_cache_entry_t *entry, zval *dst); /* * apc_cache_entry_release decrements the reference count associated with a cache * entry. Calling apc_cache_find automatically increments the reference count, * and this function must be called post-execution to return the count to its * original value. Failing to do so will prevent the entry from being * garbage-collected. * * entry is the cache entry whose ref count you want to decrement. */ PHP_APCU_API void apc_cache_entry_release(apc_cache_t *cache, apc_cache_entry_t *entry); /* fetches information about the cache provided for userland status functions */ PHP_APCU_API zend_bool apc_cache_info(zval *info, apc_cache_t *cache, zend_bool limited); /* fetches information about the key provided */ PHP_APCU_API void apc_cache_stat(apc_cache_t *cache, zend_string *key, zval *stat); /* * apc_cache_defense: guard against slamming a key * will return true if the following conditions are met: * the key provided has a matching hash and length to the last key inserted into cache * the last key has a different owner * in ZTS mode, TSRM determines owner * in non-ZTS mode, PID determines owner * Note: this function sets the owner of key during execution */ PHP_APCU_API zend_bool apc_cache_defense(apc_cache_t *cache, zend_string *key, time_t t); /* * apc_cache_serializer * sets the serializer for a cache, and by proxy contexts created for the cache * Note: this avoids race conditions between third party serializers and APCu */ PHP_APCU_API void apc_cache_serializer(apc_cache_t* cache, const char* name); /* * The remaining functions allow a third party to reimplement expunge * * Look at the source of apc_cache_default_expunge for what is expected of this function * * The default behaviour of expunge is explained below, should no combination of those options * be suitable, you will need to reimplement apc_cache_default_expunge and pass it to your * call to apc_sma_api_impl, this will replace the default functionality. * The functions below you can use during your own implementation of expunge to gain more * control over how the expunge process works ... * * Note: beware of locking (copy it exactly), setting states is also important */ /* {{{ apc_cache_default_expunge * Where smart is not set: * Where no ttl is set on cache: * 1) Perform cleanup of stale entries * 2) Expunge if available memory is less than sma->size/2 * Where ttl is set on cache: * 1) Perform cleanup of stale entries * 2) If available memory if less than the size requested, run full expunge * * Where smart is set: * Where no ttl is set on cache: * 1) Perform cleanup of stale entries * 2) Expunge is available memory is less than size * smart * Where ttl is set on cache: * 1) Perform cleanup of stale entries * 2) If available memory if less than the size requested, run full expunge * * The TTL of an entry takes precedence over the TTL of a cache */ PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size); /* * apc_cache_entry: generate and create or fetch an entry * * @see https://github.com/krakjoe/apcu/issues/142 */ PHP_APCU_API void apc_cache_entry(apc_cache_t *cache, zend_string *key, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_long ttl, zend_long now, zval *return_value); /* apcu_entry() holds a write lock on the cache while executing user code. * That code may call other apcu_* functions, which also try to acquire a * read or write lock, which would deadlock. As such, don't try to acquire a * lock if the current thread is inside apcu_entry(). * * Whether the current thread is inside apcu_entry() is tracked by APCG(entry_level). * This breaks the self-contained apc_cache_t abstraction, but is currently * necessary because the entry_level needs to be tracked per-thread, while * apc_cache_t is a per-process structure. */ static inline zend_bool apc_cache_wlock(apc_cache_t *cache) { if (!APCG(entry_level)) { return WLOCK(&cache->header->lock); } return 1; } static inline void apc_cache_wunlock(apc_cache_t *cache) { if (!APCG(entry_level)) { WUNLOCK(&cache->header->lock); } } static inline zend_bool apc_cache_rlock(apc_cache_t *cache) { if (!APCG(entry_level)) { return RLOCK(&cache->header->lock); } return 1; } static inline void apc_cache_runlock(apc_cache_t *cache) { if (!APCG(entry_level)) { RUNLOCK(&cache->header->lock); } } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_globals.h 0000664 0001750 0001750 00000007064 14523735540 014146 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | George Schlossnagle | | Rasmus Lerdorf | | Arun C. Murthy | | Gopal Vijayaraghavan | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_GLOBALS_H #define APC_GLOBALS_H #include "apc.h" ZEND_BEGIN_MODULE_GLOBALS(apcu) /* configuration parameters */ zend_bool enabled; /* if true, apc is enabled (defaults to true) */ zend_long shm_segments; /* number of shared memory segments to use */ zend_long shm_size; /* size of each shared memory segment (in MB) */ zend_long entries_hint; /* hint at the number of entries expected */ zend_long gc_ttl; /* parameter to apc_cache_create */ zend_long ttl; /* parameter to apc_cache_create */ zend_long smart; /* smart value */ #if APC_MMAP char *mmap_file_mask; /* mktemp-style file-mask to pass to mmap */ #endif /* module variables */ zend_bool initialized; /* true if module was initialized */ zend_bool enable_cli; /* Flag to override turning APC off for CLI */ zend_bool slam_defense; /* true for user cache slam defense */ char *preload_path; /* preload path */ zend_bool coredump_unmap; /* trap signals that coredump and unmap shared memory */ zend_bool use_request_time; /* use the SAPI request start time for TTL */ time_t request_time; /* cached request time */ char *serializer_name; /* the serializer config option */ /* Nesting level of apcu_entry calls. */ unsigned int entry_level; ZEND_END_MODULE_GLOBALS(apcu) /* (the following is defined in php_apc.c) */ ZEND_EXTERN_MODULE_GLOBALS(apcu) #ifdef ZTS # define APCG(v) TSRMG(apcu_globals_id, zend_apcu_globals *, v) #else # define APCG(v) (apcu_globals.v) #endif extern struct _apc_cache_t* apc_user_cache; #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc.h 0000664 0001750 0001750 00000013376 14523735540 012446 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | George Schlossnagle | | Rasmus Lerdorf | | Arun C. Murthy | | Gopal Vijayaraghavan | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_H #define APC_H /* * This module defines utilities and helper functions used elsewhere in APC. */ #ifdef PHP_WIN32 # define PHP_APCU_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_APCU_API __attribute__ ((visibility("default"))) #else # define PHP_APCU_API #endif /* Commonly needed C library headers. */ #include #include #include #include #include #include #include #include /* UNIX headers (needed for struct stat) */ #include #include #ifndef PHP_WIN32 #include #endif #ifdef HAVE_CONFIG_H #include #endif #include "php.h" #include "main/php_streams.h" /* console display functions */ PHP_APCU_API void apc_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); PHP_APCU_API void apc_warning(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); PHP_APCU_API void apc_notice(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); PHP_APCU_API void apc_debug(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); /* apc_flip_hash flips keys and values for faster searching */ PHP_APCU_API HashTable* apc_flip_hash(HashTable *hash); #if defined(__GNUC__) # define APC_UNUSED __attribute__((unused)) # define APC_USED __attribute__((used)) # define APC_ALLOC __attribute__((malloc)) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) # define APC_HOTSPOT __attribute__((hot)) # else # define APC_HOTSPOT # endif #else # define APC_UNUSED # define APC_USED # define APC_ALLOC # define APC_HOTSPOT #endif /* * Serializer API */ #define APC_SERIALIZER_ABI "0" #define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI #define APC_SERIALIZER_NAME(module) module##_apc_serializer #define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer #define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config #define APC_UNSERIALIZER_ARGS zval *value, unsigned char *buf, size_t buf_len, void *config typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS); typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS); /* {{{ struct definition: apc_serializer_t */ typedef struct apc_serializer_t { const char* name; apc_serialize_t serialize; apc_unserialize_t unserialize; void* config; } apc_serializer_t; /* }}} */ /* {{{ _apc_register_serializer registers the serializer using the given name and parameters */ PHP_APCU_API int _apc_register_serializer( const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config); /* }}} */ /* {{{ apc_get_serializers fetches the list of serializers */ PHP_APCU_API apc_serializer_t* apc_get_serializers(void); /* }}} */ /* {{{ apc_find_serializer finds a previously registered serializer by name */ PHP_APCU_API apc_serializer_t* apc_find_serializer(const char* name); /* }}} */ /* {{{ default serializers */ PHP_APCU_API int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS); PHP_APCU_API int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS); /* }}} */ #define php_apc_try \ { \ JMP_BUF *zb = EG(bailout); \ JMP_BUF ab; \ zend_bool _bailout = 0; \ \ EG(bailout) = &ab; \ if (SETJMP(ab) == SUCCESS) { #define php_apc_finally \ } else { \ _bailout = 1; \ } #define php_apc_end_try() \ EG(bailout) = zb; \ if (_bailout) { \ zend_bailout(); \ } \ } #define php_apc_try_finish() (EG(bailout) = zb) #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_iterator.c 0000664 0001750 0001750 00000040160 14523735540 014341 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Brian Shire | +----------------------------------------------------------------------+ */ #include "php_apc.h" #include "apc_iterator.h" #include "apc_cache.h" #include "apc_strings.h" #include "apc_time.h" #if PHP_VERSION_ID >= 80000 # include "apc_iterator_arginfo.h" #else # include "apc_iterator_legacy_arginfo.h" #endif #include "ext/standard/md5.h" #include "SAPI.h" #include "zend_interfaces.h" static zend_class_entry *apc_iterator_ce; zend_object_handlers apc_iterator_object_handlers; zend_class_entry* apc_iterator_get_ce(void) { return apc_iterator_ce; } #define ENSURE_INITIALIZED(iterator) \ if (!(iterator)->initialized) { \ zend_throw_error(NULL, "Trying to use uninitialized APCUIterator"); \ return; \ } /* {{{ apc_iterator_item */ static apc_iterator_item_t* apc_iterator_item_ctor( apc_iterator_t *iterator, apc_cache_entry_t *entry) { zval zv; HashTable *ht; apc_iterator_item_t *item = ecalloc(1, sizeof(apc_iterator_item_t)); array_init(&item->value); ht = Z_ARRVAL(item->value); item->key = zend_string_dup(entry->key, 0); if (APC_ITER_TYPE & iterator->format) { ZVAL_STR_COPY(&zv, apc_str_user); zend_hash_add_new(ht, apc_str_type, &zv); } if (APC_ITER_KEY & iterator->format) { ZVAL_STR_COPY(&zv, item->key); zend_hash_add_new(ht, apc_str_key, &zv); } if (APC_ITER_VALUE & iterator->format) { ZVAL_UNDEF(&zv); apc_cache_entry_fetch_zval(apc_user_cache, entry, &zv); zend_hash_add_new(ht, apc_str_value, &zv); } if (APC_ITER_NUM_HITS & iterator->format) { ZVAL_LONG(&zv, entry->nhits); zend_hash_add_new(ht, apc_str_num_hits, &zv); } if (APC_ITER_MTIME & iterator->format) { ZVAL_LONG(&zv, entry->mtime); zend_hash_add_new(ht, apc_str_mtime, &zv); } if (APC_ITER_CTIME & iterator->format) { ZVAL_LONG(&zv, entry->ctime); zend_hash_add_new(ht, apc_str_creation_time, &zv); } if (APC_ITER_DTIME & iterator->format) { ZVAL_LONG(&zv, entry->dtime); zend_hash_add_new(ht, apc_str_deletion_time, &zv); } if (APC_ITER_ATIME & iterator->format) { ZVAL_LONG(&zv, entry->atime); zend_hash_add_new(ht, apc_str_access_time, &zv); } if (APC_ITER_REFCOUNT & iterator->format) { ZVAL_LONG(&zv, entry->ref_count); zend_hash_add_new(ht, apc_str_ref_count, &zv); } if (APC_ITER_MEM_SIZE & iterator->format) { ZVAL_LONG(&zv, entry->mem_size); zend_hash_add_new(ht, apc_str_mem_size, &zv); } if (APC_ITER_TTL & iterator->format) { ZVAL_LONG(&zv, entry->ttl); zend_hash_add_new(ht, apc_str_ttl, &zv); } return item; } /* }}} */ /* {{{ apc_iterator_item_dtor */ static void apc_iterator_item_dtor(apc_iterator_item_t *item) { zend_string_release(item->key); zval_ptr_dtor(&item->value); efree(item); } /* }}} */ /* {{{ acp_iterator_free */ static void apc_iterator_free(zend_object *object) { apc_iterator_t *iterator = apc_iterator_fetch_from(object); if (iterator->initialized == 0) { zend_object_std_dtor(object); return; } while (apc_stack_size(iterator->stack) > 0) { apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); } apc_stack_destroy(iterator->stack); if (iterator->regex) { zend_string_release(iterator->regex); #if PHP_VERSION_ID >= 70300 pcre2_match_data_free(iterator->re_match_data); #endif } if (iterator->search_hash) { zend_hash_destroy(iterator->search_hash); efree(iterator->search_hash); } iterator->initialized = 0; zend_object_std_dtor(object); } /* }}} */ /* {{{ apc_iterator_create */ zend_object* apc_iterator_create(zend_class_entry *ce) { apc_iterator_t *iterator = (apc_iterator_t*) emalloc(sizeof(apc_iterator_t) + zend_object_properties_size(ce)); zend_object_std_init(&iterator->obj, ce); object_properties_init(&iterator->obj, ce); iterator->initialized = 0; iterator->stack = NULL; iterator->regex = NULL; iterator->search_hash = NULL; iterator->obj.handlers = &apc_iterator_object_handlers; return &iterator->obj; } /* }}} */ /* {{{ apc_iterator_search_match * Verify if the key matches our search parameters */ static int apc_iterator_search_match(apc_iterator_t *iterator, apc_cache_entry_t *entry) { int rval = 1; if (iterator->regex) { #if PHP_VERSION_ID >= 70300 rval = pcre2_match( php_pcre_pce_re(iterator->pce), (PCRE2_SPTR) ZSTR_VAL(entry->key), ZSTR_LEN(entry->key), 0, 0, iterator->re_match_data, php_pcre_mctx()) >= 0; #else rval = pcre_exec( iterator->pce->re, iterator->pce->extra, ZSTR_VAL(entry->key), ZSTR_LEN(entry->key), 0, 0, NULL, 0) >= 0; #endif } if (iterator->search_hash) { rval = zend_hash_exists(iterator->search_hash, entry->key); } return rval; } /* }}} */ /* {{{ apc_iterator_check_expiry */ static int apc_iterator_check_expiry(apc_cache_t* cache, apc_cache_entry_t *entry, time_t t) { if (entry->ttl) { if ((time_t) (entry->ctime + entry->ttl) < t) { return 0; } } return 1; } /* }}} */ /* {{{ apc_iterator_fetch_active */ static size_t apc_iterator_fetch_active(apc_iterator_t *iterator) { size_t count = 0; apc_iterator_item_t *item; time_t t = apc_time(); while (apc_stack_size(iterator->stack) > 0) { apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); } if (!apc_cache_rlock(apc_user_cache)) { return count; } php_apc_try { while (count <= iterator->chunk_size && iterator->slot_idx < apc_user_cache->nslots) { apc_cache_entry_t *entry = apc_user_cache->slots[iterator->slot_idx]; while (entry) { if (apc_iterator_check_expiry(apc_user_cache, entry, t)) { if (apc_iterator_search_match(iterator, entry)) { count++; item = apc_iterator_item_ctor(iterator, entry); if (item) { apc_stack_push(iterator->stack, item); } } } entry = entry->next; } iterator->slot_idx++; } } php_apc_finally { iterator->stack_idx = 0; apc_cache_runlock(apc_user_cache); } php_apc_end_try(); return count; } /* }}} */ /* {{{ apc_iterator_fetch_deleted */ static size_t apc_iterator_fetch_deleted(apc_iterator_t *iterator) { size_t count = 0; apc_iterator_item_t *item; if (!apc_cache_rlock(apc_user_cache)) { return count; } php_apc_try { apc_cache_entry_t *entry = apc_user_cache->header->gc; while (entry && count <= iterator->slot_idx) { count++; entry = entry->next; } count = 0; while (entry && count < iterator->chunk_size) { if (apc_iterator_search_match(iterator, entry)) { count++; item = apc_iterator_item_ctor(iterator, entry); if (item) { apc_stack_push(iterator->stack, item); } } entry = entry->next; } } php_apc_finally { iterator->slot_idx += count; iterator->stack_idx = 0; apc_cache_runlock(apc_user_cache); } php_apc_end_try(); return count; } /* }}} */ /* {{{ apc_iterator_totals */ static void apc_iterator_totals(apc_iterator_t *iterator) { time_t t = apc_time(); if (!apc_cache_rlock(apc_user_cache)) { return; } php_apc_try { size_t i; for (i=0; i < apc_user_cache->nslots; i++) { apc_cache_entry_t *entry = apc_user_cache->slots[i]; while (entry) { if (apc_iterator_check_expiry(apc_user_cache, entry, t)) { if (apc_iterator_search_match(iterator, entry)) { iterator->size += entry->mem_size; iterator->hits += entry->nhits; iterator->count++; } } entry = entry->next; } } } php_apc_finally { iterator->totals_flag = 1; apc_cache_runlock(apc_user_cache); } php_apc_end_try(); } /* }}} */ void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_long format, size_t chunk_size, zend_long list) { if (!APCG(enabled)) { zend_throw_error(NULL, "APC must be enabled to use APCUIterator"); return; } if (format > APC_ITER_ALL) { apc_error("APCUIterator format is invalid"); return; } if (list == APC_LIST_ACTIVE) { iterator->fetch = apc_iterator_fetch_active; } else if (list == APC_LIST_DELETED) { iterator->fetch = apc_iterator_fetch_deleted; } else { apc_warning("APCUIterator invalid list type"); return; } iterator->slot_idx = 0; iterator->stack_idx = 0; iterator->key_idx = 0; iterator->chunk_size = chunk_size == 0 ? APC_DEFAULT_CHUNK_SIZE : chunk_size; iterator->stack = apc_stack_create(chunk_size); iterator->format = format; iterator->totals_flag = 0; iterator->count = 0; iterator->size = 0; iterator->hits = 0; iterator->regex = NULL; iterator->search_hash = NULL; if (search && Z_TYPE_P(search) == IS_STRING && Z_STRLEN_P(search)) { iterator->regex = zend_string_copy(Z_STR_P(search)); iterator->pce = pcre_get_compiled_regex_cache(iterator->regex); if (!iterator->pce) { apc_error("Could not compile regular expression: %s", Z_STRVAL_P(search)); zend_string_release(iterator->regex); iterator->regex = NULL; } #if PHP_VERSION_ID >= 70300 iterator->re_match_data = pcre2_match_data_create_from_pattern( php_pcre_pce_re(iterator->pce), php_pcre_gctx()); #endif } else if (search && Z_TYPE_P(search) == IS_ARRAY) { iterator->search_hash = apc_flip_hash(Z_ARRVAL_P(search)); } iterator->initialized = 1; } PHP_METHOD(APCUIterator, __construct) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); zend_long format = APC_ITER_ALL; zend_long chunk_size = 0; zval *search = NULL; zend_long list = APC_LIST_ACTIVE; ZEND_PARSE_PARAMETERS_START(0, 4) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_EX(search, 1, 0) Z_PARAM_LONG(format) Z_PARAM_LONG(chunk_size) Z_PARAM_LONG(list) ZEND_PARSE_PARAMETERS_END(); if (chunk_size < 0) { apc_error("APCUIterator chunk size must be 0 or greater"); return; } apc_iterator_obj_init(iterator, search, format, chunk_size, list); } PHP_METHOD(APCUIterator, rewind) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); iterator->slot_idx = 0; iterator->stack_idx = 0; iterator->key_idx = 0; iterator->fetch(iterator); } PHP_METHOD(APCUIterator, valid) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (apc_stack_size(iterator->stack) == iterator->stack_idx) { iterator->fetch(iterator); } RETURN_BOOL(apc_stack_size(iterator->stack) == 0 ? 0 : 1); } PHP_METHOD(APCUIterator, current) { apc_iterator_item_t *item; apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (apc_stack_size(iterator->stack) == iterator->stack_idx) { if (iterator->fetch(iterator) == 0) { zend_throw_error(NULL, "Cannot call current() on invalid iterator"); return; } } item = apc_stack_get(iterator->stack, iterator->stack_idx); ZVAL_COPY(return_value, &item->value); } PHP_METHOD(APCUIterator, key) { apc_iterator_item_t *item; apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (apc_stack_size(iterator->stack) == iterator->stack_idx) { if (iterator->fetch(iterator) == 0) { zend_throw_error(NULL, "Cannot call key() on invalid iterator"); return; } } item = apc_stack_get(iterator->stack, iterator->stack_idx); if (item->key) { RETURN_STR_COPY(item->key); } else { RETURN_LONG(iterator->key_idx); } } PHP_METHOD(APCUIterator, next) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (apc_stack_size(iterator->stack) == 0) { return; } iterator->stack_idx++; iterator->key_idx++; } PHP_METHOD(APCUIterator, getTotalHits) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (iterator->totals_flag == 0) { apc_iterator_totals(iterator); } RETURN_LONG(iterator->hits); } /* }}} */ PHP_METHOD(APCUIterator, getTotalSize) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (iterator->totals_flag == 0) { apc_iterator_totals(iterator); } RETURN_LONG(iterator->size); } PHP_METHOD(APCUIterator, getTotalCount) { apc_iterator_t *iterator = apc_iterator_fetch(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } ENSURE_INITIALIZED(iterator); if (iterator->totals_flag == 0) { apc_iterator_totals(iterator); } RETURN_LONG(iterator->count); } /* {{{ apc_iterator_init */ int apc_iterator_init(int module_number) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "APCUIterator", class_APCUIterator_methods); apc_iterator_ce = zend_register_internal_class(&ce); apc_iterator_ce->create_object = apc_iterator_create; zend_class_implements(apc_iterator_ce, 1, zend_ce_iterator); REGISTER_LONG_CONSTANT("APC_LIST_ACTIVE", APC_LIST_ACTIVE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_LIST_DELETED", APC_LIST_DELETED, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_TYPE", APC_ITER_TYPE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_KEY", APC_ITER_KEY, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_VALUE", APC_ITER_VALUE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_NUM_HITS", APC_ITER_NUM_HITS, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_MTIME", APC_ITER_MTIME, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_CTIME", APC_ITER_CTIME, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_DTIME", APC_ITER_DTIME, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_ATIME", APC_ITER_ATIME, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_REFCOUNT", APC_ITER_REFCOUNT, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_MEM_SIZE", APC_ITER_MEM_SIZE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_TTL", APC_ITER_TTL, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_NONE", APC_ITER_NONE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("APC_ITER_ALL", APC_ITER_ALL, CONST_PERSISTENT | CONST_CS); memcpy(&apc_iterator_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); apc_iterator_object_handlers.clone_obj = NULL; apc_iterator_object_handlers.free_obj = apc_iterator_free; apc_iterator_object_handlers.offset = XtOffsetOf(apc_iterator_t, obj); return SUCCESS; } /* }}} */ int apc_iterator_shutdown(int module_number) { return SUCCESS; } /* {{{ apc_iterator_delete */ int apc_iterator_delete(zval *zobj) { apc_iterator_t *iterator; zend_class_entry *ce = Z_OBJCE_P(zobj); apc_iterator_item_t *item; if (!ce || !instanceof_function(ce, apc_iterator_ce)) { apc_error("apc_delete object argument must be instance of APCUIterator."); return 0; } iterator = apc_iterator_fetch(zobj); if (iterator->initialized == 0) { zend_throw_error(NULL, "Trying to use uninitialized APCUIterator"); return 0; } while (iterator->fetch(iterator)) { while (iterator->stack_idx < apc_stack_size(iterator->stack)) { item = apc_stack_get(iterator->stack, iterator->stack_idx++); apc_cache_delete( apc_user_cache, item->key); } } return 1; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_iterator.h 0000664 0001750 0001750 00000007446 14523735540 014360 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Brian Shire | +----------------------------------------------------------------------+ */ #ifndef APC_ITERATOR_H #define APC_ITERATOR_H #include "apc.h" #include "apc_stack.h" #include "ext/pcre/php_pcre.h" #include "zend_smart_str.h" #define APC_DEFAULT_CHUNK_SIZE 100 #define APC_LIST_ACTIVE 0x1 #define APC_LIST_DELETED 0x2 #define APC_ITER_TYPE (1 << 0) #define APC_ITER_KEY (1 << 1) #define APC_ITER_VALUE (1 << 2) #define APC_ITER_NUM_HITS (1 << 3) #define APC_ITER_MTIME (1 << 4) #define APC_ITER_CTIME (1 << 5) #define APC_ITER_DTIME (1 << 6) #define APC_ITER_ATIME (1 << 7) #define APC_ITER_REFCOUNT (1 << 8) #define APC_ITER_MEM_SIZE (1 << 9) #define APC_ITER_TTL (1 << 10) #define APC_ITER_NONE 0 #define APC_ITER_ALL (0xffffffffL) /* {{{ apc_iterator_t */ typedef struct _apc_iterator_t { short int initialized; /* sanity check in case __construct failed */ zend_long format; /* format bitmask of the return values ie: key, value, info */ size_t (*fetch)(struct _apc_iterator_t *iterator); /* fetch callback to fetch items from cache slots or lists */ size_t slot_idx; /* index to the slot array or linked list */ size_t chunk_size; /* number of entries to pull down per fetch */ apc_stack_t *stack; /* stack of entries pulled from cache */ int stack_idx; /* index into the current stack */ pcre_cache_entry *pce; /* regex filter on entry identifiers */ #if PHP_VERSION_ID >= 70300 pcre2_match_data *re_match_data; /* match data for regex */ #endif zend_string *regex; HashTable *search_hash; /* hash of keys to iterate over */ zend_long key_idx; /* incrementing index for numerical keys */ short int totals_flag; /* flag if totals have been calculated */ zend_long hits; /* hit total */ size_t size; /* size total */ zend_long count; /* count total */ zend_object obj; } apc_iterator_t; /* }}} */ #define apc_iterator_fetch_from(o) ((apc_iterator_t*)((char*)o - XtOffsetOf(apc_iterator_t, obj))) #define apc_iterator_fetch(z) apc_iterator_fetch_from(Z_OBJ_P(z)) /* {{{ apc_iterator_item */ typedef struct _apc_iterator_item_t { zend_string *key; zval value; } apc_iterator_item_t; /* }}} */ PHP_APCU_API void apc_iterator_obj_init( apc_iterator_t *iterator, zval *search, zend_long format, size_t chunk_size, zend_long list); PHP_APCU_API zend_class_entry* apc_iterator_get_ce(void); PHP_APCU_API int apc_iterator_init(int module_number); PHP_APCU_API int apc_iterator_shutdown(int module_number); extern int apc_iterator_delete(zval *key); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_iterator.stub.php 0000664 0001750 0001750 00000001173 14523735540 015663 0 ustar nikic nikic | +----------------------------------------------------------------------+ */ #ifndef HAVE_APC_LOCK_H # include "apc_lock.h" #endif /* * While locking calls should never fail, apcu checks for the success of write-lock * acquisitions, to prevent more damage when a deadlock is detected. */ #ifdef PHP_WIN32 PHP_APCU_API zend_bool apc_lock_init() { return 1; } PHP_APCU_API void apc_lock_cleanup() { } PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { return NULL != apc_windows_cs_create(lock); } static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) { apc_windows_cs_rdlock(lock); return 1; } static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) { apc_windows_cs_lock(lock); return 1; } PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { apc_windows_cs_unlock_wr(lock); return 1; } PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { apc_windows_cs_unlock_rd(lock); return 1; } PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { apc_windows_cs_destroy(lock); } #elif defined(APC_NATIVE_RWLOCK) static zend_bool apc_lock_ready = 0; static pthread_rwlockattr_t apc_lock_attr; PHP_APCU_API zend_bool apc_lock_init() { if (apc_lock_ready) { return 1; } apc_lock_ready = 1; if (pthread_rwlockattr_init(&apc_lock_attr) != SUCCESS) { return 0; } if (pthread_rwlockattr_setpshared(&apc_lock_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) { return 0; } return 1; } PHP_APCU_API void apc_lock_cleanup() { if (!apc_lock_ready) { return; } apc_lock_ready = 0; pthread_rwlockattr_destroy(&apc_lock_attr); } PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { return pthread_rwlock_init(lock, &apc_lock_attr) == SUCCESS; } static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) { return pthread_rwlock_rdlock(lock) == 0; } static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) { return pthread_rwlock_wrlock(lock) == 0; } PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { pthread_rwlock_unlock(lock); return 1; } PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { pthread_rwlock_unlock(lock); return 1; } PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { pthread_rwlock_destroy(lock); } #elif defined(APC_LOCK_RECURSIVE) static zend_bool apc_lock_ready = 0; static pthread_mutexattr_t apc_lock_attr; PHP_APCU_API zend_bool apc_lock_init() { if (apc_lock_ready) { return 1; } apc_lock_ready = 1; if (pthread_mutexattr_init(&apc_lock_attr) != SUCCESS) { return 0; } if (pthread_mutexattr_setpshared(&apc_lock_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) { return 0; } pthread_mutexattr_settype(&apc_lock_attr, PTHREAD_MUTEX_RECURSIVE); return 1; } PHP_APCU_API void apc_lock_cleanup() { if (!apc_lock_ready) { return; } apc_lock_ready = 0; pthread_mutexattr_destroy(&apc_lock_attr); } PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { pthread_mutex_init(lock, &apc_lock_attr); return 1; } static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) { return pthread_mutex_lock(lock) == 0; } static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) { return pthread_mutex_lock(lock) == 0; } PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { pthread_mutex_unlock(lock); return 1; } PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { pthread_mutex_unlock(lock); return 1; } PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { pthread_mutex_destroy(lock); } #elif defined(APC_SPIN_LOCK) static int apc_lock_try(apc_lock_t *lock) { int failed = 1; asm volatile ( "xchgl %0, 0(%1)" : "=r" (failed) : "r" (&lock->state), "0" (failed) ); return failed; } static int apc_lock_get(apc_lock_t *lock) { int failed = 1; do { failed = apc_lock_try(lock); #ifdef APC_LOCK_NICE usleep(0); #endif } while (failed); return failed; } static int apc_lock_release(apc_lock_t *lock) { int released = 0; asm volatile ( "xchg %0, 0(%1)" : "=r" (released) : "r" (&lock->state), "0" (released) ); return !released; } PHP_APCU_API zend_bool apc_lock_init() { return 0; } PHP_APCU_API void apc_lock_cleanup() { } PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { lock->state = 0; } static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) { apc_lock_get(lock); return 1; } static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) { apc_lock_get(lock); return 1; } PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { apc_lock_release(lock); return 1; } PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { apc_lock_release(lock); return 1; } PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { } #else #include #include static int apc_fcntl_call(int fd, int cmd, int type, off_t offset, int whence, off_t len) { int ret; struct flock lock; lock.l_type = type; lock.l_start = offset; lock.l_whence = whence; lock.l_len = len; lock.l_pid = 0; do { ret = fcntl(fd, cmd, &lock) ; } while(ret < 0 && errno == EINTR); return(ret); } PHP_APCU_API zend_bool apc_lock_init() { return 0; } PHP_APCU_API void apc_lock_cleanup() { } PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { char lock_path[] = "/tmp/.apc.XXXXXX"; *lock = mkstemp(lock_path); if (*lock > 0) { unlink(lock_path); return 1; } else { return 0; } } static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) { apc_fcntl_call((*lock), F_SETLKW, F_RDLCK, 0, SEEK_SET, 0); return 1; } static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) { apc_fcntl_call((*lock), F_SETLKW, F_WRLCK, 0, SEEK_SET, 0); return 1; } PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { apc_fcntl_call((*lock), F_SETLKW, F_UNLCK, 0, SEEK_SET, 0); return 1; } PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { apc_fcntl_call((*lock), F_SETLKW, F_UNLCK, 0, SEEK_SET, 0); return 1; } PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { close(*lock); } #endif /* Shared for all lock implementations */ PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock) { HANDLE_BLOCK_INTERRUPTIONS(); if (apc_lock_wlock_impl(lock)) { return 1; } HANDLE_UNBLOCK_INTERRUPTIONS(); apc_warning("Failed to acquire write lock"); return 0; } PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock) { HANDLE_BLOCK_INTERRUPTIONS(); if (apc_lock_rlock_impl(lock)) { return 1; } HANDLE_UNBLOCK_INTERRUPTIONS(); apc_warning("Failed to acquire read lock"); return 0; } apcu-5.1.23/apc_lock.h 0000664 0001750 0001750 00000010521 14523735540 013443 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APCu | +----------------------------------------------------------------------+ | Copyright (c) 2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Joe Watkins | +----------------------------------------------------------------------+ */ #ifndef APC_LOCK_H #define APC_LOCK_H /* APCu works most efficiently where there is access to native read/write locks If the current system has native rwlocks present they will be used, if they are not present, APCu will emulate their behavior with standard mutex. While APCu is emulating read/write locks, reads and writes are exclusive, additionally the write lock prefers readers, as is the default behaviour of the majority of Posix rwlock implementations */ #ifdef HAVE_CONFIG_H # include #endif #include "apc.h" #ifndef PHP_WIN32 # ifndef __USE_UNIX98 # define __USE_UNIX98 # endif # include "pthread.h" # ifndef APC_SPIN_LOCK # ifndef APC_FCNTL_LOCK # ifdef APC_NATIVE_RWLOCK typedef pthread_rwlock_t apc_lock_t; # define APC_LOCK_SHARED # else typedef pthread_mutex_t apc_lock_t; # define APC_LOCK_RECURSIVE # endif # else typedef int apc_lock_t; # define APC_LOCK_FILE # endif # else # define APC_LOCK_NICE 1 typedef struct { unsigned long state; } apc_lock_t; # endif #else /* XXX kernel lock mode only for now, compatible through all the wins, add more ifdefs for others */ # include "apc_windows_srwlock_kernel.h" typedef apc_windows_cs_rwlock_t apc_lock_t; # define APC_LOCK_SHARED #endif /* {{{ functions */ /* The following functions should be called once per process: apc_lock_init initializes attributes suitable for all locks apc_lock_cleanup destroys those attributes This saves us from having to create and destroy attributes for every lock we use at runtime */ PHP_APCU_API zend_bool apc_lock_init(void); PHP_APCU_API void apc_lock_cleanup(void); /* The following functions should be self explanitory: */ PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock); PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock); PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock); PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock); PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock); PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock); /* }}} */ /* {{{ generic locking macros */ #define CREATE_LOCK(lock) apc_lock_create(lock) #define DESTROY_LOCK(lock) apc_lock_destroy(lock) #define WLOCK(lock) apc_lock_wlock(lock) #define WUNLOCK(lock) { apc_lock_wunlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } #define RLOCK(lock) apc_lock_rlock(lock) #define RUNLOCK(lock) { apc_lock_runlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } /* }}} */ /* atomic operations */ #ifdef PHP_WIN32 # ifdef _WIN64 # define ATOMIC_INC(a) InterlockedIncrement64(&a) # define ATOMIC_DEC(a) InterlockedDecrement64(&a) # define ATOMIC_ADD(a, b) (InterlockedExchangeAdd64(&a, b) + b) # define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange64(&a, new, old) == old) # else # define ATOMIC_INC(a) InterlockedIncrement(&a) # define ATOMIC_DEC(a) InterlockedDecrement(&a) # define ATOMIC_ADD(a, b) (InterlockedExchangeAdd(&a, b) + b) # define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange(&a, new, old) == old) # endif #else # define ATOMIC_INC(a) __sync_add_and_fetch(&a, 1) # define ATOMIC_DEC(a) __sync_sub_and_fetch(&a, 1) # define ATOMIC_ADD(a, b) __sync_add_and_fetch(&a, b) # define ATOMIC_CAS(a, old, new) __sync_bool_compare_and_swap(&a, old, new) #endif #endif apcu-5.1.23/apc_mmap.c 0000664 0001750 0001750 00000010641 14523735540 013443 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc.h" #include "apc_mmap.h" #include "apc_lock.h" #if APC_MMAP #include #include #include /* * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that * tells whatever update daemons might be running to not flush dirty * vm pages to disk unless absolutely necessary. My guess is that * most systems that don't have this probably default to only synching * to disk when absolutely necessary. */ #ifndef MAP_NOSYNC #define MAP_NOSYNC 0 #endif /* support for systems where MAP_ANONYMOUS is defined but not MAP_ANON, ie: HP-UX bug #14615 */ #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) # define MAP_ANON MAP_ANONYMOUS #endif apc_segment_t apc_mmap(char *file_mask, size_t size) { apc_segment_t segment; int fd = -1; int flags = MAP_SHARED | MAP_NOSYNC; #ifdef APC_MEMPROTECT int remap = 1; #endif /* If no filename was provided, do an anonymous mmap */ if(!file_mask || (file_mask && !strlen(file_mask))) { #if !defined(MAP_ANON) zend_error_noreturn(E_CORE_ERROR, "Anonymous mmap does not appear to be available on this system (MAP_ANON/MAP_ANONYMOUS). Please see the apc.mmap_file_mask INI option."); #else fd = -1; flags = MAP_SHARED | MAP_ANON; #ifdef APC_MEMPROTECT remap = 0; #endif #endif } else if(!strcmp(file_mask,"/dev/zero")) { fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); if(fd == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: open on /dev/zero failed"); } #ifdef APC_MEMPROTECT remap = 0; /* cannot remap */ #endif } else { /* * Otherwise we do a normal filesystem mmap */ fd = mkstemp(file_mask); if(fd == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: mkstemp on %s failed", file_mask); } if (ftruncate(fd, size) < 0) { close(fd); unlink(file_mask); zend_error_noreturn(E_CORE_ERROR, "apc_mmap: ftruncate failed"); } unlink(file_mask); } segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0); segment.size = size; #ifdef APC_MEMPROTECT if(remap) { segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0); } else { segment.roaddr = NULL; } #endif if ((long)segment.shmaddr == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: Failed to mmap %zu bytes. Is your apc.shm_size too large?", size); } #ifdef MADV_HUGEPAGE /* enable transparent huge pages to reduce TLB misses (Linux only) */ madvise(segment.shmaddr, size, MADV_HUGEPAGE); #endif if (fd != -1) close(fd); return segment; } void apc_unmap(apc_segment_t *segment) { if (munmap(segment->shmaddr, segment->size) < 0) { apc_warning("apc_unmap: munmap failed"); } #ifdef APC_MEMPROTECT if (segment->roaddr && munmap(segment->roaddr, segment->size) < 0) { apc_warning("apc_unmap: munmap failed"); } #endif } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_mmap.h 0000664 0001750 0001750 00000003676 14523735540 013462 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Gopal V | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_MMAP_H #define APC_MMAP_H #include #include "apc.h" #include "apc_sma.h" /* Wrapper functions for shared memory mapped files */ #if APC_MMAP apc_segment_t apc_mmap(char *file_mask, size_t size); void apc_unmap(apc_segment_t* segment); #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_mutex.c 0000664 0001750 0001750 00000004366 14523735540 013662 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APCu | +----------------------------------------------------------------------+ | Copyright (c) 2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Fabian Franz | +----------------------------------------------------------------------+ */ #include "apc_mutex.h" #ifdef APC_HAS_PTHREAD_MUTEX static zend_bool apc_mutex_ready = 0; static pthread_mutexattr_t apc_mutex_attr; PHP_APCU_API zend_bool apc_mutex_init() { if (apc_mutex_ready) { return 1; } apc_mutex_ready = 1; if (pthread_mutexattr_init(&apc_mutex_attr) != SUCCESS) { return 0; } if (pthread_mutexattr_setpshared(&apc_mutex_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) { return 0; } return 1; } PHP_APCU_API void apc_mutex_cleanup() { if (!apc_mutex_ready) { return; } apc_mutex_ready = 0; pthread_mutexattr_destroy(&apc_mutex_attr); } PHP_APCU_API zend_bool apc_mutex_create(apc_mutex_t *lock) { pthread_mutex_init(lock, &apc_mutex_attr); return 1; } PHP_APCU_API zend_bool apc_mutex_lock(apc_mutex_t *lock) { HANDLE_BLOCK_INTERRUPTIONS(); if (pthread_mutex_lock(lock) == 0) { return 1; } HANDLE_UNBLOCK_INTERRUPTIONS(); apc_warning("Failed to acquire lock"); return 0; } PHP_APCU_API zend_bool apc_mutex_unlock(apc_mutex_t *lock) { pthread_mutex_unlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); return 1; } PHP_APCU_API void apc_mutex_destroy(apc_mutex_t *lock) { pthread_mutex_destroy(lock); } #endif apcu-5.1.23/apc_mutex.h 0000664 0001750 0001750 00000004366 14523735540 013667 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APCu | +----------------------------------------------------------------------+ | Copyright (c) 2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Joe Watkins | +----------------------------------------------------------------------+ */ #ifndef APC_MUTEX_H #define APC_MUTEX_H #include "apc.h" #ifdef APC_HAS_PTHREAD_MUTEX #include "pthread.h" typedef pthread_mutex_t apc_mutex_t; PHP_APCU_API zend_bool apc_mutex_init(void); PHP_APCU_API void apc_mutex_cleanup(void); PHP_APCU_API zend_bool apc_mutex_create(apc_mutex_t *lock); PHP_APCU_API zend_bool apc_mutex_lock(apc_mutex_t *lock); PHP_APCU_API zend_bool apc_mutex_unlock(apc_mutex_t *lock); PHP_APCU_API void apc_mutex_destroy(apc_mutex_t *lock); #define APC_MUTEX_INIT() apc_mutex_init() #define APC_MUTEX_CLEANUP() apc_mutex_cleanup() #define APC_CREATE_MUTEX(lock) apc_mutex_create(lock) #define APC_DESTROY_MUTEX(lock) apc_mutex_destroy(lock) #define APC_MUTEX_LOCK(lock) apc_mutex_lock(lock) #define APC_MUTEX_UNLOCK(lock) apc_mutex_unlock(lock) #else #include "apc_lock.h" typedef apc_lock_t apc_mutex_t; // Fallback to normal locks #define APC_MUTEX_INIT() #define APC_MUTEX_CLEANUP() #define APC_CREATE_MUTEX(lock) CREATE_LOCK(lock) #define APC_DESTROY_MUTEX(lock) DESTROY_LOCK(lock) #define APC_MUTEX_LOCK(lock) WLOCK(lock) #define APC_MUTEX_UNLOCK(lock) WUNLOCK(lock) #endif #endif apcu-5.1.23/apc_persist.c 0000664 0001750 0001750 00000047452 14523735540 014214 0 ustar nikic nikic /* +----------------------------------------------------------------------+ | APCu | +----------------------------------------------------------------------+ | Copyright (c) 2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Nikita Popov | +----------------------------------------------------------------------+ */ #include "apc.h" #include "apc_cache.h" #if PHP_VERSION_ID < 70300 # define GC_SET_REFCOUNT(ref, rc) (GC_REFCOUNT(ref) = (rc)) # define GC_ADDREF(ref) GC_REFCOUNT(ref)++ # define GC_SET_PERSISTENT_TYPE(ref, type) (GC_TYPE_INFO(ref) = type) # if PHP_VERSION_ID < 70200 # define GC_ARRAY IS_ARRAY # else # define GC_ARRAY (IS_ARRAY | (GC_COLLECTABLE << GC_FLAGS_SHIFT)) # endif #else # define GC_SET_PERSISTENT_TYPE(ref, type) \ (GC_TYPE_INFO(ref) = type | (GC_PERSISTENT << GC_FLAGS_SHIFT)) #endif #if PHP_VERSION_ID < 80000 # define GC_REFERENCE IS_REFERENCE #endif /* * PERSIST: Copy from request memory to SHM. */ typedef struct _apc_persist_context_t { /* Serializer to use */ apc_serializer_t *serializer; /* Computed size of the needed SMA allocation */ size_t size; /* Whether or not we may have to memoize refcounted addresses */ zend_bool memoization_needed; /* Whether to serialize the top-level value */ zend_bool use_serialization; /* Serialized object/array string, in case there can only be one */ unsigned char *serialized_str; size_t serialized_str_len; /* Whole SMA allocation */ char *alloc; /* Current position in allocation */ char *alloc_cur; /* HashTable storing refcounteds for which the size has already been counted. */ HashTable already_counted; /* HashTable storing already allocated refcounteds. Pointers to refcounteds are stored. */ HashTable already_allocated; } apc_persist_context_t; #define ADD_SIZE(sz) ctxt->size += ZEND_MM_ALIGNED_SIZE(sz) #define ADD_SIZE_STR(len) ADD_SIZE(_ZSTR_STRUCT_SIZE(len)) #define ALLOC(sz) apc_persist_alloc(ctxt, sz) #define COPY(val, sz) apc_persist_alloc_copy(ctxt, val, sz) static zend_bool apc_persist_calc_zval(apc_persist_context_t *ctxt, const zval *zv); static void apc_persist_copy_zval_impl(apc_persist_context_t *ctxt, zval *zv); /* Used to reduce hash collisions when using pointers in hash tables. (#175) */ static inline zend_ulong apc_shr3(zend_ulong index) { return (index >> 3) | (index << (SIZEOF_ZEND_LONG * 8 - 3)); } static inline void apc_persist_copy_zval(apc_persist_context_t *ctxt, zval *zv) { /* No data apart from the zval itself */ if (Z_TYPE_P(zv) < IS_STRING) { return; } apc_persist_copy_zval_impl(ctxt, zv); } void apc_persist_init_context(apc_persist_context_t *ctxt, apc_serializer_t *serializer) { ctxt->serializer = serializer; ctxt->size = 0; ctxt->memoization_needed = 0; ctxt->use_serialization = 0; ctxt->serialized_str = NULL; ctxt->serialized_str_len = 0; ctxt->alloc = NULL; ctxt->alloc_cur = NULL; } void apc_persist_destroy_context(apc_persist_context_t *ctxt) { if (ctxt->memoization_needed) { zend_hash_destroy(&ctxt->already_counted); zend_hash_destroy(&ctxt->already_allocated); } if (ctxt->serialized_str) { efree(ctxt->serialized_str); } } static zend_bool apc_persist_calc_memoize(apc_persist_context_t *ctxt, void *ptr) { zval tmp; zend_ulong key; if (!ctxt->memoization_needed) { return 0; } key = apc_shr3((zend_ulong)(uintptr_t) ptr); if (zend_hash_index_exists(&ctxt->already_counted, key)) { return 1; } ZVAL_NULL(&tmp); zend_hash_index_add_new(&ctxt->already_counted, key, &tmp); return 0; } static zend_bool apc_persist_calc_ht(apc_persist_context_t *ctxt, const HashTable *ht) { uint32_t idx; /* In php 7.3+, this points to the immutable zend_empty_array outside of shared memory. */ if (ht->nNumOfElements == 0) { #if PHP_VERSION_ID < 70300 ADD_SIZE(sizeof(HashTable)); #endif return 1; } ADD_SIZE(sizeof(HashTable)); /* TODO Too sparse hashtables could be compacted here */ #if PHP_VERSION_ID >= 80200 if (HT_IS_PACKED(ht)) { ADD_SIZE(HT_PACKED_USED_SIZE(ht)); for (idx = 0; idx < ht->nNumUsed; idx++) { zval *val = ht->arPacked + idx; ZEND_ASSERT(Z_TYPE_P(val) != IS_INDIRECT && "INDIRECT in packed array?"); if (!apc_persist_calc_zval(ctxt, val)) { return 0; } } } else #endif { ADD_SIZE(HT_USED_SIZE(ht)); for (idx = 0; idx < ht->nNumUsed; idx++) { Bucket *p = ht->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; /* This can only happen if $GLOBALS is placed in the cache. * Don't bother with this edge-case, fall back to serialization. */ if (Z_TYPE(p->val) == IS_INDIRECT) { ctxt->use_serialization = 1; return 0; } /* TODO These strings can be reused if (p->key && !apc_persist_calc_is_handled(ctxt, (zend_refcounted *) p->key)) { ADD_SIZE_STR(ZSTR_LEN(p->key)); }*/ if (p->key) { ADD_SIZE_STR(ZSTR_LEN(p->key)); } if (!apc_persist_calc_zval(ctxt, &p->val)) { return 0; } } } return 1; } static zend_bool apc_persist_calc_serialize(apc_persist_context_t *ctxt, const zval *zv) { unsigned char *buf = NULL; size_t buf_len = 0; apc_serialize_t serialize = APC_SERIALIZER_NAME(php); void *config = NULL; if (ctxt->serializer) { serialize = ctxt->serializer->serialize; config = ctxt->serializer->config; } if (!serialize(&buf, &buf_len, zv, config)) { return 0; } /* We only ever serialize the top-level value, memoization cannot be needed */ ZEND_ASSERT(!ctxt->memoization_needed); ctxt->serialized_str = buf; ctxt->serialized_str_len = buf_len; ADD_SIZE_STR(buf_len); return 1; } static zend_bool apc_persist_calc_zval(apc_persist_context_t *ctxt, const zval *zv) { if (Z_TYPE_P(zv) < IS_STRING) { /* No data apart from the zval itself */ return 1; } if (ctxt->use_serialization) { return apc_persist_calc_serialize(ctxt, zv); } if (apc_persist_calc_memoize(ctxt, Z_COUNTED_P(zv))) { return 1; } switch (Z_TYPE_P(zv)) { case IS_STRING: ADD_SIZE_STR(Z_STRLEN_P(zv)); return 1; case IS_ARRAY: return apc_persist_calc_ht(ctxt, Z_ARRVAL_P(zv)); case IS_REFERENCE: ADD_SIZE(sizeof(zend_reference)); return apc_persist_calc_zval(ctxt, Z_REFVAL_P(zv)); case IS_OBJECT: ctxt->use_serialization = 1; return 0; case IS_RESOURCE: apc_warning("Cannot store resources in apcu cache"); return 0; EMPTY_SWITCH_DEFAULT_CASE() } } static zend_bool apc_persist_calc(apc_persist_context_t *ctxt, const apc_cache_entry_t *entry) { ADD_SIZE(sizeof(apc_cache_entry_t)); ADD_SIZE_STR(ZSTR_LEN(entry->key)); return apc_persist_calc_zval(ctxt, &entry->val); } static inline void *apc_persist_get_already_allocated(apc_persist_context_t *ctxt, void *ptr) { if (ctxt->memoization_needed) { return zend_hash_index_find_ptr(&ctxt->already_allocated, (uintptr_t) ptr); } return NULL; } static inline void apc_persist_add_already_allocated( apc_persist_context_t *ctxt, const void *old_ptr, void *new_ptr) { if (ctxt->memoization_needed) { zend_hash_index_add_new_ptr(&ctxt->already_allocated, (uintptr_t) old_ptr, new_ptr); } } static inline void *apc_persist_alloc(apc_persist_context_t *ctxt, size_t size) { void *ptr = ctxt->alloc_cur; ctxt->alloc_cur += ZEND_MM_ALIGNED_SIZE(size); ZEND_ASSERT(ctxt->alloc_cur <= ctxt->alloc + ctxt->size); return ptr; } static inline void *apc_persist_alloc_copy( apc_persist_context_t *ctxt, const void *val, size_t size) { void *ptr = apc_persist_alloc(ctxt, size); memcpy(ptr, val, size); return ptr; } static zend_string *apc_persist_copy_cstr( apc_persist_context_t *ctxt, const char *orig_buf, size_t buf_len, zend_ulong hash) { zend_string *str = ALLOC(_ZSTR_STRUCT_SIZE(buf_len)); GC_SET_REFCOUNT(str, 1); GC_SET_PERSISTENT_TYPE(str, IS_STRING); ZSTR_H(str) = hash; ZSTR_LEN(str) = buf_len; memcpy(ZSTR_VAL(str), orig_buf, buf_len); ZSTR_VAL(str)[buf_len] = '\0'; zend_string_hash_val(str); return str; } static zend_string *apc_persist_copy_zstr_no_add( apc_persist_context_t *ctxt, const zend_string *orig_str) { return apc_persist_copy_cstr( ctxt, ZSTR_VAL(orig_str), ZSTR_LEN(orig_str), ZSTR_H(orig_str)); } static inline zend_string *apc_persist_copy_zstr( apc_persist_context_t *ctxt, const zend_string *orig_str) { zend_string *str = apc_persist_copy_zstr_no_add(ctxt, orig_str); apc_persist_add_already_allocated(ctxt, orig_str, str); return str; } static zend_reference *apc_persist_copy_ref( apc_persist_context_t *ctxt, const zend_reference *orig_ref) { zend_reference *ref = ALLOC(sizeof(zend_reference)); apc_persist_add_already_allocated(ctxt, orig_ref, ref); GC_SET_REFCOUNT(ref, 1); GC_SET_PERSISTENT_TYPE(ref, GC_REFERENCE); #if PHP_VERSION_ID >= 70400 ref->sources.ptr = NULL; #endif ZVAL_COPY_VALUE(&ref->val, &orig_ref->val); apc_persist_copy_zval(ctxt, &ref->val); return ref; } static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX}; static zend_array *apc_persist_copy_ht(apc_persist_context_t *ctxt, const HashTable *orig_ht) { #if PHP_VERSION_ID >= 70300 if (orig_ht->nNumOfElements == 0) { return (HashTable *)&zend_empty_array; } #endif HashTable *ht = COPY(orig_ht, sizeof(HashTable)); uint32_t idx; apc_persist_add_already_allocated(ctxt, orig_ht, ht); GC_SET_REFCOUNT(ht, 1); GC_SET_PERSISTENT_TYPE(ht, GC_ARRAY); /* Immutable arrays from opcache may lack a dtor and the apply protection flag. */ ht->pDestructor = ZVAL_PTR_DTOR; #if PHP_VERSION_ID < 70300 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION; #endif ht->u.flags |= HASH_FLAG_STATIC_KEYS; if (ht->nNumUsed == 0) { #if PHP_VERSION_ID >= 70400 ht->u.flags = HASH_FLAG_UNINITIALIZED; #else ht->u.flags &= ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED); #endif ht->nNextFreeElement = 0; ht->nTableMask = HT_MIN_MASK; HT_SET_DATA_ADDR(ht, &uninitialized_bucket); return ht; } ht->nNextFreeElement = 0; ht->nInternalPointer = HT_INVALID_IDX; #if PHP_VERSION_ID >= 80200 if (HT_IS_PACKED(ht)) { HT_SET_DATA_ADDR(ht, COPY(HT_GET_DATA_ADDR(ht), HT_PACKED_USED_SIZE(ht))); for (idx = 0; idx < ht->nNumUsed; idx++) { zval *val = ht->arPacked + idx; if (Z_TYPE_P(val) == IS_UNDEF) continue; if (ht->nInternalPointer == HT_INVALID_IDX) { ht->nInternalPointer = idx; } if ((zend_long) idx >= (zend_long) ht->nNextFreeElement) { ht->nNextFreeElement = idx + 1; } apc_persist_copy_zval(ctxt, val); } } else #endif { HT_SET_DATA_ADDR(ht, COPY(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht))); for (idx = 0; idx < ht->nNumUsed; idx++) { Bucket *p = ht->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; if (ht->nInternalPointer == HT_INVALID_IDX) { ht->nInternalPointer = idx; } if (p->key) { p->key = apc_persist_copy_zstr_no_add(ctxt, p->key); ht->u.flags &= ~HASH_FLAG_STATIC_KEYS; } else if ((zend_long) p->h >= (zend_long) ht->nNextFreeElement) { ht->nNextFreeElement = p->h + 1; } apc_persist_copy_zval(ctxt, &p->val); } } return ht; } static void apc_persist_copy_serialize( apc_persist_context_t *ctxt, zval *zv) { zend_string *str; zend_uchar orig_type = Z_TYPE_P(zv); ZEND_ASSERT(orig_type == IS_ARRAY || orig_type == IS_OBJECT); ZEND_ASSERT(!ctxt->memoization_needed); ZEND_ASSERT(ctxt->serialized_str); str = apc_persist_copy_cstr(ctxt, (char *) ctxt->serialized_str, ctxt->serialized_str_len, 0); /* Store as PTR type to distinguish from other strings */ ZVAL_PTR(zv, str); } static void apc_persist_copy_zval_impl(apc_persist_context_t *ctxt, zval *zv) { void *ptr; if (ctxt->use_serialization) { apc_persist_copy_serialize(ctxt, zv); return; } ptr = apc_persist_get_already_allocated(ctxt, Z_COUNTED_P(zv)); switch (Z_TYPE_P(zv)) { case IS_STRING: if (!ptr) ptr = apc_persist_copy_zstr(ctxt, Z_STR_P(zv)); ZVAL_STR(zv, ptr); return; case IS_ARRAY: if (!ptr) ptr = apc_persist_copy_ht(ctxt, Z_ARRVAL_P(zv)); ZVAL_ARR(zv, ptr); return; case IS_REFERENCE: if (!ptr) ptr = apc_persist_copy_ref(ctxt, Z_REF_P(zv)); ZVAL_REF(zv, ptr); return; EMPTY_SWITCH_DEFAULT_CASE() } } static apc_cache_entry_t *apc_persist_copy( apc_persist_context_t *ctxt, const apc_cache_entry_t *orig_entry) { apc_cache_entry_t *entry = COPY(orig_entry, sizeof(apc_cache_entry_t)); entry->key = apc_persist_copy_zstr_no_add(ctxt, entry->key); apc_persist_copy_zval(ctxt, &entry->val); return entry; } apc_cache_entry_t *apc_persist( apc_sma_t *sma, apc_serializer_t *serializer, const apc_cache_entry_t *orig_entry) { apc_persist_context_t ctxt; apc_cache_entry_t *entry; apc_persist_init_context(&ctxt, serializer); /* The top-level value should never be a reference */ ZEND_ASSERT(Z_TYPE(orig_entry->val) != IS_REFERENCE); /* If we're serializing an array using the default serializer, we will have * to keep track of potentially repeated refcounted structures. */ if (!serializer && Z_TYPE(orig_entry->val) == IS_ARRAY) { ctxt.memoization_needed = 1; zend_hash_init(&ctxt.already_counted, 0, NULL, NULL, 0); zend_hash_init(&ctxt.already_allocated, 0, NULL, NULL, 0); } /* Objects are always serialized, and arrays when a serializer is set. * Other cases are detected during apc_persist_calc(). */ if (Z_TYPE(orig_entry->val) == IS_OBJECT || (serializer && Z_TYPE(orig_entry->val) == IS_ARRAY)) { ctxt.use_serialization = 1; } if (!apc_persist_calc(&ctxt, orig_entry)) { if (!ctxt.use_serialization) { apc_persist_destroy_context(&ctxt); return NULL; } /* Try again with serialization */ apc_persist_destroy_context(&ctxt); apc_persist_init_context(&ctxt, serializer); ctxt.use_serialization = 1; if (!apc_persist_calc(&ctxt, orig_entry)) { apc_persist_destroy_context(&ctxt); return NULL; } } ctxt.alloc = ctxt.alloc_cur = apc_sma_malloc(sma, ctxt.size); if (!ctxt.alloc) { apc_persist_destroy_context(&ctxt); return NULL; } entry = apc_persist_copy(&ctxt, orig_entry); ZEND_ASSERT(ctxt.alloc_cur == ctxt.alloc + ctxt.size); entry->mem_size = ctxt.size; apc_persist_destroy_context(&ctxt); return entry; } /* * UNPERSIST: Copy from SHM to request memory. */ typedef struct _apc_unpersist_context_t { /* Whether we need to memoize already copied refcounteds. */ zend_bool memoization_needed; /* HashTable storing already copied refcounteds. */ HashTable already_copied; } apc_unpersist_context_t; static void apc_unpersist_zval_impl(apc_unpersist_context_t *ctxt, zval *zv); static inline void apc_unpersist_zval(apc_unpersist_context_t *ctxt, zval *zv) { /* No data apart from the zval itself */ if (Z_TYPE_P(zv) < IS_STRING) { return; } apc_unpersist_zval_impl(ctxt, zv); } static zend_bool apc_unpersist_serialized( zval *dst, zend_string *str, apc_serializer_t *serializer) { apc_unserialize_t unserialize = APC_UNSERIALIZER_NAME(php); void *config = NULL; if (serializer) { unserialize = serializer->unserialize; config = serializer->config; } if (unserialize(dst, (unsigned char *) ZSTR_VAL(str), ZSTR_LEN(str), config)) { return 1; } ZVAL_NULL(dst); return 0; } static inline void *apc_unpersist_get_already_copied(apc_unpersist_context_t *ctxt, void *ptr) { if (ctxt->memoization_needed) { return zend_hash_index_find_ptr(&ctxt->already_copied, apc_shr3((zend_ulong)(uintptr_t)ptr)); } return NULL; } static inline void apc_unpersist_add_already_copied( apc_unpersist_context_t *ctxt, const void *old_ptr, void *new_ptr) { if (ctxt->memoization_needed) { zend_hash_index_add_new_ptr(&ctxt->already_copied, apc_shr3((zend_ulong)(uintptr_t)old_ptr), new_ptr); } } static zend_string *apc_unpersist_zstr(apc_unpersist_context_t *ctxt, const zend_string *orig_str) { zend_string *str = zend_string_init(ZSTR_VAL(orig_str), ZSTR_LEN(orig_str), 0); ZSTR_H(str) = ZSTR_H(orig_str); apc_unpersist_add_already_copied(ctxt, orig_str, str); return str; } static zend_reference *apc_unpersist_ref( apc_unpersist_context_t *ctxt, const zend_reference *orig_ref) { zend_reference *ref = emalloc(sizeof(zend_reference)); apc_unpersist_add_already_copied(ctxt, orig_ref, ref); GC_SET_REFCOUNT(ref, 1); GC_TYPE_INFO(ref) = GC_REFERENCE; #if PHP_VERSION_ID >= 70400 ref->sources.ptr = NULL; #endif ZVAL_COPY_VALUE(&ref->val, &orig_ref->val); apc_unpersist_zval(ctxt, &ref->val); return ref; } /* Compute the size of the HashTable data to create when unpersisting. */ static zend_always_inline size_t apc_compute_ht_data_size(const HashTable *ht) { #if PHP_VERSION_ID >= 80200 if (HT_IS_PACKED(ht)) { return HT_PACKED_SIZE(ht); } #endif return HT_SIZE(ht); } static zend_array *apc_unpersist_ht( apc_unpersist_context_t *ctxt, const HashTable *orig_ht) { HashTable *ht = emalloc(sizeof(HashTable)); apc_unpersist_add_already_copied(ctxt, orig_ht, ht); memcpy(ht, orig_ht, sizeof(HashTable)); GC_TYPE_INFO(ht) = GC_ARRAY; #if PHP_VERSION_ID >= 70300 /* Caller used ZVAL_EMPTY_ARRAY and set different zval flags instead */ ZEND_ASSERT(ht->nNumOfElements > 0 && ht->nNumUsed > 0); #else if (ht->nNumUsed == 0) { HT_SET_DATA_ADDR(ht, &uninitialized_bucket); return ht; } #endif HT_SET_DATA_ADDR(ht, emalloc(apc_compute_ht_data_size(ht))); memcpy(HT_GET_DATA_ADDR(ht), HT_GET_DATA_ADDR(orig_ht), HT_HASH_SIZE(ht->nTableMask)); #if PHP_VERSION_ID >= 80200 if (HT_IS_PACKED(ht)) { zval *p = ht->arPacked, *q = orig_ht->arPacked, *p_end = p + ht->nNumUsed; for (; p < p_end; p++, q++) { *p = *q; apc_unpersist_zval(ctxt, p); } } else #endif if (ht->u.flags & HASH_FLAG_STATIC_KEYS) { Bucket *p = ht->arData, *q = orig_ht->arData, *p_end = p + ht->nNumUsed; for (; p < p_end; p++, q++) { /* No need to check for UNDEF, as unpersist_zval can be safely called on UNDEF */ *p = *q; apc_unpersist_zval(ctxt, &p->val); } } else { Bucket *p = ht->arData, *q = orig_ht->arData, *p_end = p + ht->nNumUsed; for (; p < p_end; p++, q++) { if (Z_TYPE(q->val) == IS_UNDEF) { ZVAL_UNDEF(&p->val); continue; } p->val = q->val; p->h = q->h; if (q->key) { p->key = zend_string_dup(q->key, 0); } else { p->key = NULL; } apc_unpersist_zval(ctxt, &p->val); } } return ht; } static void apc_unpersist_zval_impl(apc_unpersist_context_t *ctxt, zval *zv) { void *ptr = apc_unpersist_get_already_copied(ctxt, Z_COUNTED_P(zv)); if (ptr) { Z_COUNTED_P(zv) = ptr; Z_ADDREF_P(zv); return; } switch (Z_TYPE_P(zv)) { case IS_STRING: Z_STR_P(zv) = apc_unpersist_zstr(ctxt, Z_STR_P(zv)); return; case IS_REFERENCE: Z_REF_P(zv) = apc_unpersist_ref(ctxt, Z_REF_P(zv)); return; case IS_ARRAY: #if PHP_VERSION_ID >= 70300 if (Z_ARR_P(zv)->nNumOfElements == 0) { ZVAL_EMPTY_ARRAY(zv); /* #323 */ return; } #endif Z_ARR_P(zv) = apc_unpersist_ht(ctxt, Z_ARR_P(zv)); return; default: ZEND_ASSERT(0); return; } } zend_bool apc_unpersist(zval *dst, const zval *value, apc_serializer_t *serializer) { apc_unpersist_context_t ctxt; if (Z_TYPE_P(value) == IS_PTR) { return apc_unpersist_serialized(dst, Z_PTR_P(value), serializer); } ctxt.memoization_needed = 0; ZEND_ASSERT(Z_TYPE_P(value) != IS_REFERENCE); if (Z_TYPE_P(value) == IS_ARRAY) { ctxt.memoization_needed = 1; zend_hash_init(&ctxt.already_copied, 0, NULL, NULL, 0); } ZVAL_COPY_VALUE(dst, value); apc_unpersist_zval(&ctxt, dst); if (ctxt.memoization_needed) { zend_hash_destroy(&ctxt.already_copied); } return 1; } apcu-5.1.23/apc.php 0000664 0001750 0001750 00000125660 14523735540 013006 0 ustar nikic nikic | | Rasmus Lerdorf | | Ilia Alshanetsky | +----------------------------------------------------------------------+ All other licensing and usage conditions are those of the PHP Group. */ ////////// READ OPTIONAL CONFIGURATION FILE //////////// if (file_exists("apc.conf.php")) include("apc.conf.php"); //////////////////////////////////////////////////////// ////////// BEGIN OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////// defaults('USE_AUTHENTICATION',1); // Use (internal) authentication - best choice if // no other authentication is available // If set to 0: // There will be no further authentication. You // will have to handle this by yourself! // If set to 1: // You need to change ADMIN_PASSWORD to make // this work! defaults('ADMIN_USERNAME','apc'); // Admin Username defaults('ADMIN_PASSWORD','password'); // Admin Password - CHANGE THIS TO ENABLE!!! // (beckerr) I'm using a clear text password here, because I've no good idea how to let // users generate a md5 or crypt password in a easy way to fill it in above //defaults('DATE_FORMAT', "d.m.Y H:i:s"); // German defaults('DATE_FORMAT', 'Y/m/d H:i:s'); // US defaults('GRAPH_SIZE',200); // Image size //defaults('PROXY', 'tcp://127.0.0.1:8080'); ////////// END OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////// // "define if not defined" function defaults($d,$v) { if (!defined($d)) define($d,$v); // or just @define(...) } // rewrite $PHP_SELF to block XSS attacks // $PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],''), ENT_QUOTES, 'UTF-8') : ''; $time = time(); $host = php_uname('n'); if($host) { $host = '('.$host.')'; } if (isset($_SERVER['SERVER_ADDR'])) { $host .= ' ('.$_SERVER['SERVER_ADDR'].')'; } // operation constants define('OB_HOST_STATS',1); define('OB_USER_CACHE',2); define('OB_VERSION_CHECK',3); // check validity of input variables $vardom=array( 'OB' => '/^\d+$/', // operational mode switch 'CC' => '/^[01]$/', // clear cache requested 'DU' => '/^.*$/', // Delete User Key 'SH' => '/^[a-z0-9]+$/', // shared object description 'IMG' => '/^[123]$/', // image to generate 'LO' => '/^1$/', // login requested 'COUNT' => '/^\d+$/', // number of line displayed in list 'SCOPE' => '/^[AD]$/', // list view scope 'SORT1' => '/^[AHSMCDTZ]$/', // first sort key 'SORT2' => '/^[DA]$/', // second sort key 'AGGR' => '/^\d+$/', // aggregation by dir level 'SEARCH' => '~^[a-zA-Z0-9/_.-]*$~' // aggregation by dir level ); // cache scope $scope_list=array( 'A' => 'cache_list', 'D' => 'deleted_list' ); // handle POST and GET requests if (empty($_REQUEST)) { if (!empty($_GET) && !empty($_POST)) { $_REQUEST = array_merge($_GET, $_POST); } else if (!empty($_GET)) { $_REQUEST = $_GET; } else if (!empty($_POST)) { $_REQUEST = $_POST; } else { $_REQUEST = array(); } } // check parameter syntax foreach($vardom as $var => $dom) { if (!isset($_REQUEST[$var])) { $MYREQUEST[$var]=null; } else if (!is_array($_REQUEST[$var]) && preg_match($dom.'D',$_REQUEST[$var])) { $MYREQUEST[$var]=$_REQUEST[$var]; } else { $MYREQUEST[$var]=$_REQUEST[$var]=null; } } // check parameter semantics if (empty($MYREQUEST['SCOPE'])) $MYREQUEST['SCOPE']="A"; if (empty($MYREQUEST['SORT1'])) $MYREQUEST['SORT1']="H"; if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D"; if (empty($MYREQUEST['OB'])) $MYREQUEST['OB']=OB_HOST_STATS; if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20; if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A'; $MY_SELF= "$PHP_SELF". "?SCOPE=".$MYREQUEST['SCOPE']. "&SORT1=".$MYREQUEST['SORT1']. "&SORT2=".$MYREQUEST['SORT2']. "&COUNT=".$MYREQUEST['COUNT']; $MY_SELF_WO_SORT= "$PHP_SELF". "?SCOPE=".$MYREQUEST['SCOPE']. "&COUNT=".$MYREQUEST['COUNT']; // authentication needed? // if (!USE_AUTHENTICATION) { $AUTHENTICATED=1; } else { $AUTHENTICATED=0; if (ADMIN_PASSWORD!='password' && ($MYREQUEST['LO'] == 1 || isset($_SERVER['PHP_AUTH_USER']))) { if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME || $_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { Header("WWW-Authenticate: Basic realm=\"APC Login\""); Header("HTTP/1.0 401 Unauthorized"); echo << Rejected!
Wrong Username or Password!
Continue...