-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

如果您愿意在更新“连接表”时锁定所有三个集合的所有更新,则可以使用应用程序级锁定来实现这一点。

简短版本:您创建一个“锁”集合。在更新三个集合 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 回答