Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e66ddfb
Factored-out the state management in designated classes.
ndobromirov Dec 9, 2016
16def54
Removed excessive logic in L1 constructor. Added hard dependecies bet…
ndobromirov Dec 9, 2016
d513eaa
Added docks v1. Added null state manager implementation.
ndobromirov Dec 11, 2016
3626134
Refacrored the tests to use the new L1CacheFactory instead of directl…
ndobromirov Dec 11, 2016
3d4d54d
Improvements in StateL1Null implementaion and fixes for scrutinizer CI.
ndobromirov Dec 11, 2016
085c651
CS fixes and improvements against scrutnizer.
ndobromirov Dec 11, 2016
8b0040e
Removed dead code.
ndobromirov Dec 11, 2016
247b398
Tweak in the L1 Null caches implementation together with L1 Null stat…
ndobromirov Dec 11, 2016
341377a
Added a test for the invalid driver on the factory. Removed unused me…
ndobromirov Dec 11, 2016
c4419bd
CS fixes.
ndobromirov Dec 11, 2016
1fb9130
Inevrted === and !== checks to have constant as first argument. Refac…
ndobromirov Dec 13, 2016
cecb2a4
SQLiteL1: Determine filename based on schema definition strings (#75)
ndobromirov Dec 17, 2016
7eef3a8
Refactorin in L1 related tests. Abstracted L1 tests. Implemented Init…
ndobromirov Dec 27, 2016
3f1e10f
Moved performL1AntirollbackTest to the new L1 tests structure.
ndobromirov Dec 27, 2016
459d238
Refactored performL1FullDelete. Implemented a TODO from the APCu clas…
ndobromirov Dec 27, 2016
96f5c2b
Refactored L1 expiration tests.
ndobromirov Dec 27, 2016
83f22bd
Refacored pool and existance tests.
ndobromirov Dec 27, 2016
2bccef6
Refacored L1 hit/miss test.
ndobromirov Dec 27, 2016
0596626
Refactored the testSQLiteL1SchemaErrorHandling to be triggered for al…
ndobromirov Dec 27, 2016
006bfcb
Added key-overhead tracking tests on L1 level.
ndobromirov Dec 27, 2016
73a8a6b
Added existence and validity checks for running the APCu tests.
ndobromirov Dec 27, 2016
5ba363a
CS fixes & re-formatting.
ndobromirov Dec 27, 2016
d011c69
Fixed the CRs from review. Added tests folder under CS validation in …
ndobromirov Dec 27, 2016
60af8a8
Implemented a separate test class for the NullL1
ndobromirov Dec 27, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"squizlabs/php_codesniffer": "2.*"
},
"scripts": {
"cs": "phpcs --standard=PSR2 -n src",
"cs": "phpcs --standard=PSR2 -n src tests",
"cbf": "phpcbf --standard=PSR2 -n src",
"api": "PATH=$HOME/bin:$PATH sami.phar --ansi update sami-config.php",
"sami-install": "mkdir -p $HOME/bin && curl --output $HOME/bin/sami.phar http://get.sensiolabs.org/sami.phar && chmod +x $HOME/bin/sami.phar",
Expand Down
104 changes: 22 additions & 82 deletions src/APCuL1.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,12 @@ class APCuL1 extends L1
/** @var string */
private $localKeyPrefix;

/** @var string */
private $statusKeyHits;

/** @var string */
private $statusKeyMisses;

/** @var string */
private $statusKeyLastAppliedEventId;

public function __construct($pool = null)
public function __construct($pool, StateL1Interface $state)
{
parent::__construct($pool);
parent::__construct($pool, $state);

// Using designated variables to speed up key generation during runtime.
$this->localKeyPrefix = 'lcache' . $this->pool . ':';
$this->statusKeyHits = 'lcache_status:' . $this->pool . ':hits';
$this->statusKeyMisses = 'lcache_status:' . $this->pool . ':misses';
$this->statusKeyLastAppliedEventId = 'lcache_status:' . $this->pool . ':last_applied_event_id';
$this->localKeyPrefix = 'lcache:' . $pool . ':';
}

protected function getLocalKey($address)
Expand All @@ -38,9 +26,10 @@ public function getKeyOverhead(Address $address)
// decrementing the overhead by existing hits when an item is set. This
// would make hits cheaper but writes more expensive.

$success = null;
$apcu_key = $this->getLocalKey($address);
$overhead = apcu_fetch($apcu_key . ':overhead', $success);
if ($success) {
if (true === $success) {
return $overhead;
}
return 0;
Expand All @@ -67,9 +56,10 @@ public function setWithExpiration($event_id, Address $address, $value, $created,

// If not setting a negative cache entry, increment the key's overhead.
if (!is_null($value)) {
$overhead_success = null;
$apcu_key_overhead = $apcu_key . ':overhead';
apcu_inc($apcu_key_overhead, 1, $overhead_success);
if (!$overhead_success) {
if (false === $overhead_success) {
// @codeCoverageIgnoreStart
apcu_store($apcu_key_overhead, 1);
// @codeCoverageIgnoreEnd
Expand All @@ -81,9 +71,10 @@ public function setWithExpiration($event_id, Address $address, $value, $created,

public function isNegativeCache(Address $address)
{
$success = null;
$apcu_key = $this->getLocalKey($address);
$entry = apcu_fetch($apcu_key, $success);
return ($success && is_null($entry->value));
return (true === $success && is_null($entry->value));
}

public function getEntry(Address $address)
Expand All @@ -92,16 +83,18 @@ public function getEntry(Address $address)
$apcu_key_overhead = $apcu_key . ':overhead';

// Decrement the key's overhead.
$overhead_success = null;
apcu_dec($apcu_key_overhead, 1, $overhead_success);
if (!$overhead_success) {
if (false === $overhead_success) {
// @codeCoverageIgnoreStart
apcu_store($apcu_key_overhead, -1);
// @codeCoverageIgnoreEnd
}

$success = null;
$entry = apcu_fetch($apcu_key, $success);
// Handle failed reads.
if (!$success) {
if (false === $success) {
$this->recordMiss();
return null;
}
Expand All @@ -125,80 +118,27 @@ protected function getIterator($pattern, $format = APC_ITER_ALL)

public function delete($event_id, Address $address)
{
if ($address->isEntireCache()) {
// @TODO: Consider flushing only LCache L1 storage by using an iterator.
return apcu_clear_cache();
}
if ($address->isEntireBin()) {
$prefix = $this->getLocalKey($address);
$pattern = '/^' . preg_quote($prefix) . '.*/';
$localKey = $this->getLocalKey($address);

if ($address->isEntireCache() || $address->isEntireBin()) {
$localKey = $this->getLocalKey($address);
$pattern = '/^' . preg_quote($localKey) . '.*/';
$matching = $this->getIterator($pattern, APC_ITER_KEY);
assert(!is_null($matching), 'Iterator instantiation failed.');
foreach ($matching as $match) {
// Ignore failures of delete because the key may have been
// deleted in another process using the same APCu.
apcu_delete($match['key']);
}
if ($address->isEntireCache()) {
$this->state->clear();
}
return true;
}

$apcu_key = $this->getLocalKey($address);

// Ignore failures of delete because the key may have been
// deleted in another process using the same APCu.
apcu_delete($apcu_key);
apcu_delete($localKey);
return true;
}

protected function recordHit()
{
apcu_inc($this->statusKeyHits, 1, $success);
if (!$success) {
// @TODO: Remove this fallback when we drop APCu 4.x support.
// @codeCoverageIgnoreStart
// Ignore coverage because (1) it's tested with other code and
// (2) APCu 5.x does not use it.
apcu_store($this->statusKeyHits, 1);
// @codeCoverageIgnoreEnd
}
}

protected function recordMiss()
{
apcu_inc($this->statusKeyMisses, 1, $success);
if (!$success) {
// @TODO: Remove this fallback when we drop APCu 4.x support.
// @codeCoverageIgnoreStart
// Ignore coverage because (1) it's tested with other code and
// (2) APCu 5.x does not use it.
apcu_store($this->statusKeyMisses, 1);
// @codeCoverageIgnoreEnd
}
}

public function getHits()
{
$value = apcu_fetch($this->statusKeyHits);
return $value ? $value : 0;
}

public function getMisses()
{
$value = apcu_fetch($this->statusKeyMisses);
return $value ? $value : 0;
}

public function getLastAppliedEventID()
{
$value = apcu_fetch($this->statusKeyLastAppliedEventId);
if ($value === false) {
$value = null;
}
return $value;
}

public function setLastAppliedEventID($eid)
{
return apcu_store($this->statusKeyLastAppliedEventId, $eid);
}
}
2 changes: 1 addition & 1 deletion src/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function unserialize($serialized)
}

// @TODO: Remove check against false for PHP 7+
if ($this->key === false || $this->key === '') {
if (false === $this->key || '' === $this->key) {
$this->key = null;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/DatabaseL2.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public function getEntry(Address $address)
//$last_matching_entry = $sth->fetchObject('LCacheEntry');
$last_matching_entry = $sth->fetchObject();

if ($last_matching_entry === false) {
if (false === $last_matching_entry) {
$this->misses++;
return null;
}
Expand All @@ -176,7 +176,7 @@ public function getEntry(Address $address)
$unserialized_value = @unserialize($last_matching_entry->value);

// If unserialization failed, raise an exception.
if ($unserialized_value === false && $last_matching_entry->value !== serialize(false)) {
if (false === $unserialized_value && serialize(false) !== $last_matching_entry->value) {
throw new UnserializationException($address, $last_matching_entry->value);
}

Expand Down Expand Up @@ -364,7 +364,7 @@ public function applyEvents(L1 $l1)
return null;
}
$last_event = $sth->fetchObject();
if ($last_event === false) {
if (false === $last_event) {
$l1->setLastAppliedEventID(0);
} else {
$l1->setLastAppliedEventID($last_event->event_id);
Expand All @@ -391,7 +391,7 @@ public function applyEvents(L1 $l1)
$l1->delete($event->event_id, $address);
} else {
$unserialized_value = @unserialize($event->value);
if ($unserialized_value === false && $event->value !== serialize(false)) {
if (false === $unserialized_value && serialize(false) !== $event->value) {
// Delete the L1 entry, if any, when we fail to unserialize.
$l1->delete($event->event_id, $address);
} else {
Expand Down
54 changes: 41 additions & 13 deletions src/L1.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,33 @@ abstract class L1 extends LX
{
protected $pool;

public function __construct($pool = null)
/** @var StateL1Interface */
protected $state;

/**
* Constructor for all the L1 implementations.
*
* @param string $pool
* Pool ID to group the cache data in.
* @param \LCache\StateL1Interface $state
* State manager class. Used to collect hit/miss statistics as well as
* the ID of the last cache mutation event.
*/
public function __construct($pool, StateL1Interface $state)
{
if (!is_null($pool)) {
$this->pool = $pool;
} elseif (isset($_SERVER['SERVER_ADDR']) && isset($_SERVER['SERVER_PORT'])) {
$this->pool = $_SERVER['SERVER_ADDR'] . '-' . $_SERVER['SERVER_PORT'];
} else {
$this->pool = $this->generateUniqueID();
}
$this->pool = $pool;
$this->state = $state;
}

protected function generateUniqueID()
public function getLastAppliedEventID()
{
// @TODO: Replace with a persistent but machine-local (and unique) method.
return uniqid('', true) . '-' . mt_rand();
return $this->state->getLastAppliedEventID();
}

abstract public function getLastAppliedEventID();
abstract public function setLastAppliedEventID($event_id);
public function setLastAppliedEventID($event_id)
{
return $this->state->setLastAppliedEventID($event_id);
}

public function getPool()
{
Expand All @@ -40,4 +48,24 @@ abstract public function isNegativeCache(Address $address);
abstract public function getKeyOverhead(Address $address);
abstract public function setWithExpiration($event_id, Address $address, $value, $created, $expiration = null);
abstract public function delete($event_id, Address $address);

public function getHits()
{
return $this->state->getHits();
}

public function getMisses()
{
return $this->state->getMisses();
}

protected function recordHit()
{
$this->state->recordHit();
}

protected function recordMiss()
{
$this->state->recordMiss();
}
}
Loading