mongodb复制集合以避免缺少事务

时间:2013-01-04 18:25:58

标签: mongodb

我有一个带有集合cA,cB和cC的数据库。我需要以事务方式每5分钟更新一次数据库(cB是cA和cC的n-m关系)。由于模拟transactions with mongo似乎并不容易,我可以在开始上传过程之前创建cA,cB和cC的快照(db.cA.copyTo(“cA_snapshot”))并翻转阅读查询在执行插入时的快照上。不幸的是,集合大小总计超过8Gb并且正在进行集合。复制似乎需要太长时间。

那么,有没有办法通过日记实现这一目标?假设我在启动时花费一次创建集合的快照。之后,我可以手动重播cA_snapshot上cA的日记项吗?

谢谢

1 个答案:

答案 0 :(得分:0)

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

简短版本:您创建'locks'集合。在更新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);