-1

コレクションcA、cB、およびcCを持つデータベースを持っています。5 分ごとにデータベースをトランザクション的に更新する必要があります (cB は cA と cC の nm 関係です)。mongo でトランザクションをエミュレートするのは簡単ではないように思われるので、アップロード プロセスを開始する前に cA、cB、および cC のスナップショット (db.cA.copyTo("cA_snapshot")) を作成し、読み取りクエリを挿入中のスナップショット。残念ながら、コレクションのサイズは合計で 8Gb を超え、collection.copyTo の実行には時間がかかりすぎるようです。

では、ジャーナリングを使用してこれを達成する方法はありますか? 起動時にコレクションのスナップショットを作成するためのコストを負担するとします。その後、cA_snapshot で cA のジャーナリング アイテムを手動で再生できますか?

ありがとう

4

1 に答える 1

0

「結合テーブル」を更新している間、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);
于 2013-01-08T00:26:47.487 に答える