php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #58172 apc_add() deletes variables on second call
Submitted: 2008-04-21 17:47 UTC Modified: 2008-06-26 08:18 UTC
From: dmitrij at stepanov dot lv Assigned:
Status: Closed Package: APC (PECL)
PHP Version: 5.2.5 OS: Windows XP
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: dmitrij at stepanov dot lv
New email:
PHP Version: OS:

 

 [2008-04-21 17:47 UTC] dmitrij at stepanov dot lv
Description:
------------
A couple of months ago i had to write a server-local RAM cache with PHP to store and cache information within one web server (one apache process). I did a lot of benchmarks and tests on different kind of caches available for php and APC seemed to fit the best for my needs. One of the functionalities i had to have is the cache locking by concurrent requests, so that only one request processing thread at a time could access cache. This can be done (according to documentation at http://www.php.net/manual/en/function.apc-add.php) using apc_add() function to create entries exclusively.

See the following code:

function TryLock() {
  return apc_add( '_lock', 1, 0);
}
funciton Unlock() {
 apc_delete( '_lock');
}
while( !TryLock())
 usleep( 10);
... // do something with cache
Unlock();

Imagine two threads executing this code. The thread, which first gets apc_add() returned true, acquires lock and gains control over the cache, until that thread calls Unlock() (deletes the '_lock' key).
The problem is that on my configuration - WINDOWS XP, Apache 2.2.4.0, PHP 5.2.5.5, APC 5.2.5.5, this mechanism does not work, because the second call to apc_add with key '_lock' forces this entry to be deleted from cache. The bug is: the second call of two calls to apc_add() with equal key parameter force the entry to be deleted from cache.. I have tested this code on Linux, and it works as expected.

Reproduce code:
---------------
var_dump( apc_add( '_lock', 1, 0));
$info =apc_cache_info( 'user'); var_dump( $info['cache_list']);
var_dump( apc_add( '_lock', 1, 0));
$info =apc_cache_info( 'user'); var_dump( $info['cache_list']);
var_dump( apc_add( '_lock', 1, 0));
$info =apc_cache_info( 'user'); var_dump( $info['cache_list']);
var_dump( apc_add( '_lock', 1, 0));
$info =apc_cache_info( 'user'); var_dump( $info['cache_list']);

Expected result:
----------------
bool(true)
array(1) {
  [0]=>
  array(10) {
    ["info"]=>
    string(5) "_lock"
    ["ttl"]=>
    int(0)
    ["type"]=>
    string(4) "user"

    ["num_hits"]=>
    int(0)
    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>
    int(1208725222)
    ["deletion_time"]=>
    int(0)

    ["access_time"]=>
    int(1208725222)
    ["ref_count"]=>
    int(0)
    ["mem_size"]=>
    int(96)
  }
}
bool(false)
array(1) {
  [0]=>
  array(10) {

    ["info"]=>
    string(5) "_lock"
    ["ttl"]=>
    int(0)
    ["type"]=>
    string(4) "user"
    ["num_hits"]=>
    int(0)

    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>
    int(1208725222)
    ["deletion_time"]=>
    int(0)
    ["access_time"]=>
    int(1208725222)

    ["ref_count"]=>
    int(0)
    ["mem_size"]=>
    int(96)
  }
}
bool(false)
array(1) {
  [0]=>
  array(10) {
    ["info"]=>
    string(5) "_lock"

    ["ttl"]=>
    int(0)
    ["type"]=>
    string(4) "user"
    ["num_hits"]=>
    int(0)
    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>

    int(1208725222)
    ["deletion_time"]=>
    int(0)
    ["access_time"]=>
    int(1208725222)
    ["ref_count"]=>
    int(0)
    ["mem_size"]=>

    int(96)
  }
}
bool(false)
array(1) {
  [0]=>
  array(10) {
    ["info"]=>
    string(5) "_lock"
    ["ttl"]=>
    int(0)
    ["type"]=>

    string(4) "user"
    ["num_hits"]=>
    int(0)
    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>
    int(1208725222)
    ["deletion_time"]=>

    int(0)
    ["access_time"]=>
    int(1208725222)
    ["ref_count"]=>
    int(0)
    ["mem_size"]=>
    int(96)
  }
}

Actual result:
--------------
bool(true)
array(1) {
  [0]=>
  array(10) {
    ["info"]=>
    string(5) "_lock"
    ["ttl"]=>
    int(0)
    ["type"]=>

    string(4) "user"
    ["num_hits"]=>
    int(0)
    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>
    int(1208725222)
    ["deletion_time"]=>

    int(0)
    ["access_time"]=>
    int(1208725222)
    ["ref_count"]=>
    int(0)
    ["mem_size"]=>
    int(96)
  }
}
bool(false)
array(0) {
}

bool(true)
array(1) {
  [0]=>
  array(10) {
    ["info"]=>
    string(5) "_lock"
    ["ttl"]=>
    int(0)
    ["type"]=>
    string(4) "user"

    ["num_hits"]=>
    int(0)
    ["mtime"]=>
    int(1208725222)
    ["creation_time"]=>
    int(1208725222)
    ["deletion_time"]=>
    int(0)

    ["access_time"]=>
    int(1208725222)
    ["ref_count"]=>
    int(0)
    ["mem_size"]=>
    int(96)
  }
}
bool(false)
array(0) {
}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-04-23 12:01 UTC] daniz at rocketmail dot com
Hopefully this bug is something similar to my problem at http://pecl.php.net/bugs/bug.php?id=13558 regarding the lock of add/delete. There is surely something wrong with the code, I just had a problem reproducing it in a closed environment.
 [2008-04-23 14:07 UTC] gopalv82 at yahoo dot com
Same as http://pecl.php.net/bugs/bug.php?id=12499 ?

We reverted that patch for 3.0.18 because it was suspected of breaking code, but the CVS HEAD (i.e the php5+ only branch) retains the expunge fixes.
 [2008-06-26 08:18 UTC] gopalv82 at yahoo dot com
Fixed in apc-3.1.x-dev branch.

Please check out CVS HEAD to test it.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Jul 09 13:01:36 2025 UTC