gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

CAS実装……の前提のお話

ふと、色々と紆余曲折があった末として「MagicWeaponのdata_clumpで、cas形式の楽観的ロック、実装してみようかしらん?」というような発想がありまして。
その前提として「cas tokenど〜やって実装しよう?」から、比較的現実的な可能性があるあたりを妄想して、その辺の実装の欠片を思いついたので、おおむね、メモ用途でw


端的には「bigint(8byte) unsigned相当の整数」をランダムで持たせたら、大体、トークン足りえるんじゃないかなぁ? と、妄想をしまして。
8byteなら、index切っても、メモリ空間の圧迫が「そんなもんだろう」程度、だろうし。
渡し方については……MySQLであれば……二種類あるなぁ。

mysql> SELECT CAST(0xffffffffffffffff AS UNSIGNED);
+--------------------------------------+
| CAST(0xffffffffffffffff AS UNSIGNED) |
+--------------------------------------+
| 18446744073709551615 |
+--------------------------------------+

mysql> SELECT CONV('ffffffffffffffff', 16, 10);
+----------------------------------+
| CONV('ffffffffffffffff', 16, 10) |
+----------------------------------+
| 18446744073709551615 |
+----------------------------------+


………ん?

mysql> SELECT CAST('0xffffffffffffffff' AS UNSIGNED);
+----------------------------------------+
| CAST('0xffffffffffffffff' AS UNSIGNED) |
+----------------------------------------+
| 0 |
+----------------------------------------+

あぁ文字列にすると駄目なのか。
って事は、CONV関数だな。こっちなら「文字列」として渡せる。
まぁ、MySQLに方法があるんだ、ほかのRDBでもあるだろうw(ざつ)


んで。
だとするとあとは「8byte整数相当の値をランダムにとってくる」と、なんとなく行けるっぽくて。
後は「重複しねぇよなぁ」を、雑にテストしてみるとよいんじゃなかろうか、って思う。


Linux的に手っ取り早いのは /dev/urandom デバイスでしょ、ってんで、確認かねて、以下のコードを動かしてみた。

<?php

$data = [];
for($i = 0; $i < 100000; ++$i) {
    $h = bin2hex(file_get_contents('/dev/urandom', false, NULL, 0, 8));
    if (false === isset($data[$h])) {
        $data[$h] = 1;
    } else {
        echo "ng... \n";
    }
}

重複が発生したら教えてくれる、的な子。
とりあえず10万回。
……ま〜ま〜時間かかるのな。ほんのわずかにびっくりしたおw


何度か動かしてみましたが、(おおよそ予想通り)一度もぶつからなかったので。
多分、いけるんじゃないかなぁ、的な。


どこかで、気が向いたり体力が向いたりしたら、CASを実際に実装してみませう。
って事で、とりあえず「実装するために一番重要な部分」を、軽くテストしてみました。


突っ込みなどあったら歓迎いたしますので、是非。