Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable30] feat: add negative compare-and-delete to imemcache #47398

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions lib/private/Memcache/CADTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,21 @@ public function cad($key, $old) {
return false;
}
}

public function ncad(string $key, mixed $old): bool {
//no native cad, emulate with locking
if ($this->add($key . '_lock', true)) {
$value = $this->get($key);
if ($value !== null && $value !== $old) {
$this->remove($key);
$this->remove($key . '_lock');
return true;
} else {
$this->remove($key . '_lock');
return false;
}
} else {
return false;
}
}
}
11 changes: 11 additions & 0 deletions lib/private/Memcache/LoggerWrapperCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,17 @@ public function cad($key, $old) {
return $this->wrappedCache->cad($key, $old);
}

/** @inheritDoc */
public function ncad(string $key, mixed $old): bool {
file_put_contents(
$this->logFile,
$this->getNameSpace() . '::ncad::' . $key . "\n",
FILE_APPEND
);

return $this->wrappedCache->cad($key, $old);
}

/** @inheritDoc */
public function setTTL(string $key, int $ttl) {
$this->wrappedCache->setTTL($key, $ttl);
Expand Down
5 changes: 5 additions & 0 deletions lib/private/Memcache/NullCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public function cad($key, $old) {
return true;
}

public function ncad(string $key, mixed $old): bool {
return true;
}


public function clear($prefix = '') {
return true;
}
Expand Down
12 changes: 12 additions & 0 deletions lib/private/Memcache/ProfilerWrapperCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ public function cad($key, $old) {
return $ret;
}

/** @inheritDoc */
public function ncad(string $key, mixed $old): bool {
$start = microtime(true);
$ret = $this->wrappedCache->ncad($key, $old);
$this->data['queries'][] = [
'start' => $start,
'end' => microtime(true),
'op' => $this->getPrefix() . '::ncad::' . $key,
];
return $ret;
}

/** @inheritDoc */
public function setTTL(string $key, int $ttl) {
$this->wrappedCache->setTTL($key, $ttl);
Expand Down
10 changes: 10 additions & 0 deletions lib/private/Memcache/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class Redis extends Cache implements IMemcacheTTL {
'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end',
'cf0e94b2e9ffc7e04395cf88f7583fc309985910',
],
'ncad' => [
'if redis.call("get", KEYS[1]) ~= ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end',
'75526f8048b13ce94a41b58eee59c664b4990ab2',
],
'caSetTtl' => [
'if redis.call("get", KEYS[1]) == ARGV[1] then redis.call("expire", KEYS[1], ARGV[2]) return 1 else return 0 end',
'fa4acbc946d23ef41d7d3910880b60e6e4972d72',
Expand Down Expand Up @@ -164,6 +168,12 @@ public function cad($key, $old) {
return $this->evalLua('cad', [$key], [$old]) > 0;
}

public function ncad(string $key, mixed $old): bool {
$old = self::encodeValue($old);

return $this->evalLua('ncad', [$key], [$old]) > 0;
}

public function setTTL($key, $ttl) {
if ($ttl === 0) {
// having infinite TTL can lead to leaked keys as the prefix changes with version upgrades
Expand Down
20 changes: 18 additions & 2 deletions lib/public/IMemcache.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,37 @@ public function dec($key, $step = 1);
/**
* Compare and set
*
* Set $key to $new only if it's current value is $new
*
* @param string $key
* @param mixed $old
* @param mixed $new
* @return bool
* @return bool true if the value was successfully set or false if $key wasn't set to $old
* @since 8.1.0
*/
public function cas($key, $old, $new);

/**
* Compare and delete
*
* Delete $key if the stored value is equal to $old
*
* @param string $key
* @param mixed $old
* @return bool
* @return bool true if the value was successfully deleted or false if $key wasn't set to $old
* @since 8.1.0
*/
public function cad($key, $old);

/**
* Negative compare and delete
*
* Delete $key if the stored value is not equal to $old
*
* @param string $key
* @param mixed $old
* @return bool true if the value was successfully deleted or false if $key was set to $old or is not set
* @since 30.0.0
*/
public function ncad(string $key, mixed $old): bool;
}
23 changes: 23 additions & 0 deletions tests/lib/Memcache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public function testCasChanged() {
$this->assertEquals('bar1', $this->instance->get('foo'));
}

public function testCasNotSet() {
$this->assertFalse($this->instance->cas('foo', 'bar', 'asd'));
}

public function testCadNotChanged() {
$this->instance->set('foo', 'bar');
$this->assertTrue($this->instance->cad('foo', 'bar'));
Expand All @@ -121,6 +125,25 @@ public function testCadChanged() {
$this->assertTrue($this->instance->hasKey('foo'));
}

public function testCadNotSet() {
$this->assertFalse($this->instance->cad('foo', 'bar'));
}

public function testNcadNotChanged() {
$this->instance->set('foo', 'bar');
$this->assertFalse($this->instance->ncad('foo', 'bar'));
$this->assertTrue($this->instance->hasKey('foo'));
}

public function testNcadChanged() {
$this->instance->set('foo', 'bar1');
$this->assertTrue($this->instance->ncad('foo', 'bar'));
$this->assertFalse($this->instance->hasKey('foo'));
}

public function testNcadNotSet() {
$this->assertFalse($this->instance->ncad('foo', 'bar'));
}

protected function tearDown(): void {
if ($this->instance) {
Expand Down
Loading