php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #57924 apc_add() deletes value on second call
Submitted: 2007-11-21 13:20 UTC Modified: 2008-03-06 20:51 UTC
From: mahono@php.net Assigned:
Status: Closed Package: APC (PECL)
PHP Version: Irrelevant OS: Linux
Private report: No CVE-ID: None
 [2007-11-21 13:20 UTC] mahono@php.net
Description:
------------
Tested with PHP 5.2.4 (not in the select list):

If I call apc_add() the first time everything is fine.
After the second call the cache entry is gone.



Reproduce code:
---------------
$e = apc_add('test', 'foo', 1000);
var_dump($e);
$r = apc_fetch('test');
var_dump($r);

$d = apc_add('test', 'bar', 1000);
var_dump($d);
$f = apc_fetch('test');
var_dump($f);


Expected result:
----------------
bool(true)
string(3) "foo"
bool(false)
string(3) "foo"


Actual result:
--------------
bool(true)
string(3) "foo"
bool(false)
bool(false)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-11-25 21:11 UTC] shire@php.net
I can't reproduce with the code you've given (I get the correct results).  I am working on a bug that will possibly cause this behavior if your cache is full.  Can you verify that you have cache space available in your cache for this value?  Does the value disappear using apc_store instead of apc_add?
 [2007-12-18 21:30 UTC] Ninzya at inbox dot lv
I have just faced the same bug. Cache is completely empty, APC is enabled, after apache restart apc_add() still continues to delete value on second call.

This code:
var_dump( apc_add( '_lock', 15));
var_dump( apc_add( '_lock', 15));
var_dump( apc_add( '_lock', 15));
var_dump( apc_add( '_lock', 15));
var_dump( apc_add( '_lock', 15));
apc_delete( '_lock');

Produces this:
bool(true) bool(false) bool(true) bool(false) bool(true) 

This code:
var_dump( apc_add( '_lock', 1));
var_dump( $x =apc_fetch( '_lock'));
var_dump( apc_store( '_lock', 2));
var_dump( $x =apc_fetch( '_lock'));
var_dump( apc_store( '_lock', 3));
var_dump( $x =apc_fetch( '_lock'));
var_dump( apc_add( '_lock', 4));
var_dump( $x =apc_fetch( '_lock'));
var_dump( apc_add( '_lock', 5));
var_dump( $x =apc_fetch( '_lock'));
apc_delete( '_lock');

Produces this:
bool(true) int(1) bool(true) int(2) bool(true) int(3) bool(false) bool(false) bool(true) int(5) 

[apc]
apc.enabled = 1
apc.shm_segments = 1 
apc.shm_size = 256 
apc.optimization = 0
apc.num_files_hint = 1000 
apc.ttl = 0 
apc.gc_ttl = 3600 
apc.cache_by_default = On 
apc.slam_defense = 0 
apc.file_update_protection = 2 
apc.enable_cli = 0 
apc.stat = 1

Because of this bug, i cannot use locking i designed for my app. For a very long time i could not understand why the following code does not work correctly:

function apc_lock() {
  global  $_APCLocked,
          $_APCLockTime;
  while( apc_add( '_lock', $_APCLockTime =microtime( true)) ===false)
    usleep( 500);
  $_APCLocked =true;
}

function apc_unlock() {
  global  $_APCLocked,
          $_APCLockTime;
  if( $_APCLocked)// did we lock the cache?
    if( apc_fetch( '_lock') ===$_APCLockTime)// is our key still in cache?
      apc_delete( '_lock');// delete lock
  // set flag that we didn't lock the cache
  $_APCLocked =false;
}

apc_lock();
$x =(int)apc_fetch( 'x');
apc_store( 'x', ++$x);
$fp =fopen( 'x.txt', 'a');
fputs( $fp, $x ."\r\n");
fclose( $fp);
apc_unlock();

Expected output in 'x.txt' at parallel requests to script:
1
2
3
4
5
6
7
...
 [2008-03-06 18:11 UTC] erlend at ringstad dot no
I also hit this one today.

apc_add incremented the 'expunges' counter for each run. This is with one segment of 200MB shm of which 90% was free at the time.

This was APC-3.0.16

While looking at this code in php_apc.c (int _apc_store):

    if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) {
        APCG(mem_size_ptr) = NULL;
        apc_cache_free_entry(entry);
        apc_cache_expunge(apc_cache,t);
        apc_cache_expunge(apc_user_cache,t);
        HANDLE_UNBLOCK_INTERRUPTIONS();
        return 0;
    }

It seems to me that a return 0 from 'apc_cache_user_insert' (which is correct if the key is set and valid) would always execute the expunge code?

A simple patch might be:

    if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) {
        APCG(mem_size_ptr) = NULL;
        if (!exclusive) {
            apc_cache_free_entry(entry);
            apc_cache_expunge(apc_cache,t);
            apc_cache_expunge(apc_user_cache,t);
        }
        HANDLE_UNBLOCK_INTERRUPTIONS();
        return 0;
    }
 [2008-03-06 20:51 UTC] shire@php.net
This bug has been fixed in CVS.

In case this was a documentation problem, the fix will show up at the
end of next Sunday (CET) on pecl.php.net.

In case this was a pecl.php.net website problem, the change will show
up on the website in short time.
 
Thank you for the report, and for helping us make PECL better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 20:01:29 2024 UTC