「結合テーブル」を更新している間、3 つのコレクションすべてに対するすべての更新をロックしたい場合は、アプリケーション レベルのロックを使用してこれを実装できます。
短いバージョン: 「ロック」コレクションを作成します。すべてのクライアントは、3 つのコレクション cA、cB、または cC のいずれかを更新する前に、「書き込みロック」を取得する必要があります。これは、'locks' コレクション内のドキュメントを更新することによって行われます。バッチ更新を実行する準備ができたら、「書き込みロック」を取得し、更新を実行して、ロックを解放します。
ロックを実装する簡単なコード例を次に示します。このコードにはいくつかの制限があることに注意してください。
- デッドロックの検出または防止はありません
- ロック タイムアウトはありません
- ロックされたリソースを再ロックしようとすると、以前にロックが正常に取得されていたとしても、常に失敗します。
これらの制限の修正は、読者の課題として残されています。
XDB = db.mylocks;
/*
* Set up the locking collection
*/
function setup_locking( res_name ) {
var doc = { _id: res_name, state: "UNLOCKED", locker: null };
// upsert to create document if it does not exist
XDB.update( {id: res_name}, doc, true );
}
/*
* Lock the resource named 'res_name' by process named 'proc'
*
* Returns 'true' if resource was acquired, 'false' if it was not acquired
*/
function lockit( res_name, proc ) {
/*
* 1) Change state to LOCKED if & only if it was previously UNLOCKED
*/
ret = XDB.findAndModify( {
query: { _id:res_name, state:"UNLOCKED" } ,
update: {"$set": { state:"LOCKED", locker: proc } },
fields: { state:1, locker:1 },
new: true
}
);
/*
* Return 'true' if this process acquired this resource
*/
if ( ret && (ret.state == "LOCKED") && (ret.locker == proc) )return true;
/*
* 2) Failed to acquire this resource
*/
return false;
}
/*
* Unlock the resource named 'res_name' previously held by 'proc'
*/
function unlockit( res_name, proc ) {
// Unlock resource if this process had previously acquired it
XDB.findAndModify( {
query: { _id:res_name, locker: proc, state:"LOCKED" } ,
update: {"$set": { state:"UNLOCKED", locker: null } },
}
);
}
/*
* Check to see if resource 'res_name' is currently held by 'proc'
*/
function has_lock( res_name, proc ) {
res = XDB.findOne({_id: res_name, locker:proc} );
if (res == null) return false;
return true;
}
XDB.drop();
setup_locking('collectionA');
result = lockit( 'collectionA', 'app1');
print("1: result =", result);
result = lockit( 'collectionA', 'app2');
print("2: result =", result);
result = lockit( 'collectionA', 'app1');
print("3a: result =", result);
result = has_lock( 'collectionA', 'app1');
print("3b: result =", result);
result = has_lock( 'collectionA', 'app2');
print("3c: result =", result);
unlockit( 'collectionA', 'app1');
result = lockit( 'collectionA', 'app2');
print("4: result =", result);