使用Booksleeve和Redis进行检查和设置(CAS)操作

时间:2012-08-01 19:24:09

标签: database redis booksleeve

书架是否支持CAS操作(即Redis WATCH命令)?例如,如何实现类似下面的内容?

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

当多个线程尝试使用相同的数据修改同一个对象时,我需要这样做以避免竞争条件。

1 个答案:

答案 0 :(得分:2)

目前在nuget,我不这么认为。因为BookSleeve 通常打算用作多路复用器,这使得“监视”无法使用。我可以添加它,你必须在操作期间限制使用到一个调用者(每个BookSleeve连接)。

has now changed;如果我们想手动实现INCR(根据您的示例),我们可以使用:

// note this could be null if the old key didn't exist
var oldVal = await connection.Strings.GetInt64(db, key);

var newVal = (oldVal ?? 0) + 1;
using (var tran = connection.CreateTransaction())
{
    // check hasn't changed (this handles the WATCH, a checked GET,
    // and an UNWATCH if necessary); note tat conditions are not sent
    // until the Execute is called
    tran.AddCondition(Condition.KeyEquals(db, key, oldVal));

    // apply changes to perform assuming the conditions succeed
    tran.Strings.Set(db, key, newVal); // the SET

    // note that Execute includes the MULTI/EXEC, assuming the conditions pass
    if (!await tran.Execute()) return null; // aborted; either a pre-condition
                                         // failed, or a WATCH-key was changed
    return newVal; // successfully incremented
}

显然你可能希望在重复(在理智的限制内)循环中执行它,这样如果它因WATCH而中止,你就从头开始重做。

这与您的示例略有不同,因为它实际上是这样(假设在初始GET和第二个GET之间没有更改值):

val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
MULTI
SET mykey $newval
EXEC

如果EXECWATCH之间的值已更改,则EXEC仍然可以报告取消;或者(如果 在两个GET之间发生了):

val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
UNWATCH

差异是另一个GET,但这是它可以与多路复用器一起使用的唯一方式 - 即,Execute被优化为可靠快速,因此它不会影响其他来电者。