-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
WATCH accounts for modifications by its own connection #734
Comments
At this point I'd say misleading documentation, as the behaviour probably was always that every key modification counts. |
After some research I see why the docs mention "other clients":
In other words, the docs should say that EXEC will fail in all cases when the key is modified unless it was done by the same client inside the watched multi/exec block. This might be expected behaviour but why changes before MULTI are treated like a change by another client? I'd say they should be ignored likewise. |
To summarize my previous post, I'm testing php-redis extension (https://github.com/phpredis/phpredis): function testWatchChangeBySelfBeforeMulti() {
$redis = new Redis;
$redis->connect('127.0.0.1');
$redis->delete('o');
$redis->watch('o');
$redis->set('o', 1);
$redis->multi();
$redis->get('o');
// This fails.
$this->assertTrue(is_array( $redis->exec() ));
}
function testWatchChangeBySelfAfterMulti() {
$redis = new Redis;
$redis->connect('127.0.0.1');
$redis->delete('o');
$redis->watch('o');
$redis->multi();
$redis->set('o', 1);
$redis->get('o');
$this->assertTrue(is_array( $redis->exec() ));
}
function testWatchChangeByOtherBeforeMulti() {
$redis = new Redis;
$redis->connect('127.0.0.1');
$redis2 = new Redis;
$redis2->connect('127.0.0.1');
$redis->delete('o');
$redis->watch('o');
$redis2->set('o', 1);
$redis->multi();
$redis->get('o');
$this->assertFalse($redis->exec());
}
function testWatchChangeByOtherAfterMulti() {
$redis = new Redis;
$redis->connect('127.0.0.1');
$redis2 = new Redis;
$redis2->connect('127.0.0.1');
$redis->delete('o');
$redis->watch('o');
$redis->multi();
$redis2->set('o', 1);
$redis->get('o');
$this->assertFalse($redis->exec());
} |
|
Then just need to correct the docs. Send you a pull request? |
@badboy any reason why my pull request is untouched? |
Puh, for some reason I failed to review it. I'm sorry for that. Will do it later today. |
* Clarified when WATCH doesn't abort EXEC #734 WATCH accounts for modifications by its own connection * Update transactions.md
… attempt with delay on lock acquisition nickelser#4 In Redis, calling SET within a WATCH/UNWATCH block but no inside a MULTI/EXEC block will [cause the EXEC to fail the transaction](redis/redis-doc#734). This, along with the call to next after #initial_set in #acquire_lock is causing the initial acquisition to take two passes and thus wait for up to :acquisition_delay before getting the lock. Memcached looks like it will have the same problem as the call to SET without the CAS during #initial_set is going to cause the SET with CAS to fail (return EXISTS).
…k acquisition The call to `#initial_set` in `#retry` and `#acquire_lock` is followed by `next` which leads to a second pass through the `#retry_with_timeout` loop and a sleep call for up to `:acquisition_delay`. This delay isn't necessary if the value can be set without a race condition. Removing the `next` call causes the client to continue to retry because the transaction has been changed outside the transaction boundary: In Redis, calling `SET` within a `WATCH`/`UNWATCH` block but not inside a `MULTI`/`EXEC` block will [cause the EXEC to fail the transaction](redis/redis-doc#734), so the first `#set` call fails and it requires a second pass. To resolve this I changed `#initial_set` to call `#set` within a `MULTI` block so that it would be inside the transaction. In Memcache the call to `SET` without the `CAS` during `#initial_set` is going to cause the `SET` with `CAS` to fail (return `EXISTS`), and resulting in a second pass. To resolve this I changed `#initial_set` to use `SET` with `CAS` and return the CAS value to be used in the subsequent `#set` call that stores the lock token.
Documentation about Redis transactions (http://redis.io/topics/transactions) says this:
The above suggests that it doesn't matter who changes the watched key(s) - the same client (that has watched them) or another client.
But the docs have also this fragment:
This explicitly says that WATCH will ignore changes by the same client but doesn't say who is that other client.
I have tried this (single session - single "client"?):
is this a bug in WATCH or the documentation is misleading? Should we remove this "only if no other client" reference from the docs?
The text was updated successfully, but these errors were encountered: