今日は良い感じ、私はそれだけでロックを作成するためにも、リモートで可能ではないことを言って他のすべてのポスターをdownvoteはありませんカッサンドラのクラスターだけです。私はLamportのベーカリーアルゴリズム¹を実装しましたが、うまく動作します。動物園、ケージ、メモ帳などの他の奇妙なものは必要ありません。
代わりに、少なくともQUORUMの一貫性で読み書きを取得できる限り、貧しい人のマルチプロセス/マルチコンピュータロックメカニズムを実装できます。これは、このアルゴリズムを適切に実装するためには本当に必要なものです。 (QUORUMレベルは、必要なロックのタイプによって異なります:ローカル、ラック、フルネットワーク)
私の実装はlibQtCassandra(C++)のバージョン0.4.7になります。私はすでにテストしており、完全にロックしています。私がテストしたいものがいくつかあります。今ではハードコーディングされている一連のパラメータを定義させることができます。しかし、このメカニズムは完全に機能します。
このスレッドを見つけたら、何かが間違っていると思っていました。私はさらにいくつかを検索し、以下に述べるApacheのページを見つけました。ページはそれほど先進的ではありませんが、彼らのMoinMoinはディスカッション・ページを提供していません...とにかく、言及する価値があったと思います。うまくいけば、人々はPHP、Ruby、Javaなどのあらゆる種類の言語でそのロック機構を実装し始めるでしょう。
出典:http://wiki.apache.org/cassandra/Locking
以下は、私は私のバージョンを実装し、多かれ少なかれ方法ですhttp://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
を¹しました。これは単純な概要です。結果のコードをテストしながら(実際のコードではRAIIを使用し、TTLの上にタイムアウト機能を追加しています)、いくつかの機能拡張を行ったので、もう少し更新する必要があります。最終バージョンはlibQtCassandra libraryにあります。
// lock "object_name"
void lock(QString object_name)
{
QString locks = context->lockTableName();
QString hosts_key = context->lockHostsKey();
QString host_name = context->lockHostName();
int host = table[locks][hosts_key][host_name];
pid_t pid = getpid();
// get the next available ticket
table[locks]["entering::" + object_name][host + "/" + pid] = true;
int my_ticket(0);
QCassandraCells tickets(table[locks]["tickets::" + object_name]);
foreach(tickets as t)
{
// we assume that t.name is the column name
// and t.value is its value
if(t.value > my_ticket)
{
my_ticket = t.value;
}
}
++my_ticket; // add 1, since we want the next ticket
table[locks]["tickets::" + object_name][my_ticket + "/" + host + "/" + pid] = 1;
// not entering anymore, by deleting the cell we also release the row
// once all the processes are done with that object_name
table[locks]["entering::" + object_name].dropCell(host + "/" + pid);
// here we wait on all the other processes still entering at this
// point; if entering more or less at the same time we cannot
// guarantee that their ticket number will be larger, it may instead
// be equal; however, anyone entering later will always have a larger
// ticket number so we won't have to wait for them they will have to wait
// on us instead; note that we load the list of "entering" once;
// then we just check whether the column still exists; it is enough
QCassandraCells entering(table[locks]["entering::" + object_name]);
foreach(entering as e)
{
while(table[locks]["entering::" + object_name].exists(e))
{
sleep();
}
}
// now check whether any other process was there before us, if
// so sleep a bit and try again; in our case we only need to check
// for the processes registered for that one lock and not all the
// processes (which could be 1 million on a large system!);
// like with the entering vector we really only need to read the
// list of tickets once and then check when they get deleted
// (unfortunately we can only do a poll on this one too...);
// we exit the foreach() loop once our ticket is proved to be the
// smallest or no more tickets needs to be checked; when ticket
// numbers are equal, then we use our host numbers, the smaller
// is picked; when host numbers are equal (two processes on the
// same host fighting for the lock), then we use the processes
// pid since these are unique on a system, again the smallest wins.
tickets = table[locks]["tickets::" + object_name];
foreach(tickets as t)
{
// do we have a smaller ticket?
// note: the t.host and t.pid come from the column key
if(t.value > my_ticket
|| (t.value == my_ticket && t.host > host)
|| (t.value == my_ticket && t.host == host && t.pid >= pid))
{
// do not wait on larger tickets, just ignore them
continue;
}
// not smaller, wait for the ticket to go away
while(table[locks]["tickets::" + object_name].exists(t.name))
{
sleep();
}
// that ticket was released, we may have priority now
// check the next ticket
}
}
// unlock "object_name"
void unlock(QString object_name)
{
// release our ticket
QString locks = context->lockTableName();
QString hosts_key = context->lockHostsKey();
QString host_name = context->lockHostName();
int host = table[locks][hosts_key][host_name];
pid_t pid = getpid();
table[locks]["tickets::" + object_name].dropCell(host + "/" + pid);
}
// sample process using the lock/unlock
void SomeProcess(QString object_name)
{
while(true)
{
[...]
// non-critical section...
lock(object_name);
// The critical section code goes here...
unlock(object_name);
// non-critical section...
[...]
}
}
ありがとう - これは私がそれを期待してきた方法です。他の誰かがそれを確認することもできますか?私は101%確信しています:) –
あなたはもちろん、書き込みの束をして、あなたの制約に違反していないかどうかを確認することができます。しかし、それがあなたに役立つかどうかはわかりません。 –
セオドアは正しいです。通常、一意性が必要な場合は、一意性を保証するUUIDまたは詳細の組み合わせを使用する必要があります。 –