CakeFest 2024: The Official CakePHP Conference

Memcached::cas

(PECL memcached >= 0.1.0)

Memcached::casアイテムを比較して入れ替える

説明

public Memcached::cas(
    string|int|float $cas_token,
    string $key,
    mixed $value,
    int $expiration = 0
): bool

Memcached::cas() は「チェックして設定」という操作を行います。 アイテムが格納されるのは、クライアントが最後にアイテムを取得して以降に 他のクライアントによるそのアイテムの更新がなかった場合のみです。 チェックは cas_token パラメータを使用して行います。 これは一意な 64 ビットの値で、既存のアイテムに対して memcache が割り当てます。 このトークンを取得する方法については Memcached::get*() メソッドのドキュメントを参照ください。 PHP の integer 型の範囲を超えるため、トークンは float 型であらわされることに注意しましょう。

パラメータ

cas_token

既存のアイテムに割り当てたれた一意な値。memcache が生成します。

key

値の格納先のキー。

value

格納する値。

expiration

期限切れとなるまでの時間。デフォルトは 0。詳細な情報は有効期限 を参照ください。

戻り値

成功した場合に true を、失敗した場合に false を返します。 格納しようとしているアイテムが最後の取得以降に更新されている場合、 Memcached::getResultCode()Memcached::RES_DATA_EXISTS を返します。

例1 Memcached::cas() の例

<?php
$m
= new Memcached();
$m->addServer('localhost', 11211);

do {
/* IP リストとそのトークンを取得します */
$ips = $m->get('ip_block', null, $cas);
/* リストが存在しない場合はまず作成してからアトミック名追加を行います。
誰かがすでに追加している場合は失敗します */
if ($m->getResultCode() == Memcached::RES_NOTFOUND) {
$ips = array($_SERVER['REMOTE_ADDR']);
$m->add('ip_block', $ips);
/* それ以外の場合は、IP をリストに追加して、トークンによる「比較して入れ替え」
方式で格納します。だれかがリストを更新している場合は失敗します */
} else {
$ips[] = $_SERVER['REMOTE_ADDR'];
$m->cas($cas, 'ip_block', $ips);
}
} while (
$m->getResultCode() != Memcached::RES_SUCCESS);

?>

参考

add a note

User Contributed Notes 4 notes

up
2
abodera at gmail dot com
13 years ago
Watch out!

When using binary protocol, the expected result after cas() is 21 (Memcached::RES_END).

For example, to make the above example #1 work with binary protocol, use the following:
<?php
$m
= new Memcached();
$m->addServer('localhost', 11211);
$m->setOption(Memcached::OPT_BINARY_PROTOCOL,true)

// [...]

} else {
$ips[] = $_SERVER['REMOTE_ADDR'];
$m->cas($cas, 'ip_block', $ips);
}
} while (
$m->getResultCode() != Memcached::RES_END);
?>
up
2
sparcbr at gmail dot com
7 years ago
Do not check command success in a while loop with something like


$memCached->getResultCode() != Memcached::RES_SUCCESS

Memcached::RES_SERVER_ERROR or anything like this and your script will loop forev
up
1
Haravikk
6 years ago
I'm not sure whether this remains true in the newer versions of the Memcached module (v3.0 onwards) but in the version shipped with PHP 5.6 the return value and result code when using this method with OPT_BINARY_PROTOCOL enabled are entirely useless.

Setting a value successful may return true, with a result code of RES_END, but it may also return true with a result code of RES_SUCCESS.

However, *unsuccessfully* setting a value likewise seems to return true and RES_SUCCESS, effectively rendering this function's return value useless with the binary protocol enabled as it is impossible to distinguish success from failure.

If you need to rely on the return value of this method then I strongly recommend disabling the binary protocol under PHP 5.6, as in its current state the common memcached module is too broken otherwise for CAS usage.

Hopefully someone else can weigh in on whether this is still broken in newer versions or not.
up
1
php at sergentet dot fr
6 years ago
To prevent a perpetual loop on any Memcached error, you can add a simple counter :

$security_count = 0;

do {
//[]....
$security_loop++
if ($security_loop > 10) {
break; //( or return "your return value" on a function )
}
} while ($m->getResultCode() != Memcached::RES_SUCCESS);
To Top