[Cache] fix LockRegistry

This commit is contained in:
Nicolas Grekas 2019-03-14 22:54:25 +01:00
parent 8907650424
commit f49df4ab05
2 changed files with 26 additions and 11 deletions

View File

@ -23,7 +23,7 @@ use Symfony\Contracts\Cache\ItemInterface;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class LockRegistry
final class LockRegistry
{
private static $openedFiles = [];
private static $lockedFiles = [];
@ -74,7 +74,7 @@ class LockRegistry
return $previousFiles;
}
public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool)
public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null)
{
$key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1;
@ -88,7 +88,18 @@ class LockRegistry
if (flock($lock, LOCK_EX | LOCK_NB)) {
self::$lockedFiles[$key] = true;
return $callback($item, $save);
$value = $callback($item, $save);
if ($save) {
if ($setMetadata) {
$setMetadata($item);
}
$pool->save($item->set($value));
$save = false;
}
return $value;
}
// if we failed the race, retry locking in blocking mode to wait for the winner
flock($lock, LOCK_SH);
@ -125,6 +136,6 @@ class LockRegistry
restore_error_handler();
}
self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r');
return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r');
}
}

View File

@ -40,7 +40,7 @@ trait ContractsTrait
public function setCallbackWrapper(?callable $callbackWrapper): callable
{
$previousWrapper = $this->callbackWrapper;
$this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool) {
$this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata) {
return $callback($item, $save);
};
@ -56,17 +56,19 @@ trait ContractsTrait
static $setMetadata;
$setMetadata = $setMetadata ?? \Closure::bind(
function (AdapterInterface $pool, ItemInterface $item, float $startTime) {
function (CacheItem $item, float $startTime, ?array &$metadata) {
if ($item->expiry > $endTime = microtime(true)) {
$item->newMetadata[ItemInterface::METADATA_EXPIRY] = $item->expiry;
$item->newMetadata[ItemInterface::METADATA_CTIME] = 1000 * (int) ($endTime - $startTime);
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
$item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = 1000 * (int) ($endTime - $startTime);
} else {
unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]);
}
},
null,
CacheItem::class
);
return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata) {
return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) {
// don't wrap nor save recursive calls
if (null === $callbackWrapper = $this->callbackWrapper) {
$value = $callback($item, $save);
@ -78,8 +80,10 @@ trait ContractsTrait
$startTime = microtime(true);
try {
$value = $callbackWrapper($callback, $item, $save, $pool);
$setMetadata($pool, $item, $startTime);
$value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);
});
$setMetadata($item, $startTime, $metadata);
return $value;
} finally {