2012-05-28 47 views
-2

我想更新在mongodb的一些数据,我的逻辑如下:如何避免mongodb的竞态条件

#find the specific document with "md5,time,size", 
if collection.find({"src_md5":file_md5,"src_time":file_time,"src_size":file_size}).count() == 0: 
    #if not found 
    # find the idx,if idx is not yet exist,set idx equa 1 

    if collection.find({},{"idx":1}).count() == 0: 
     idx = 1 

    #if idx is alread there, sort idx and get the biggest idx 
    else: 
     idx = collection.find({},{"idx":1}).sort('idx',-1).limit(5)[0]['idx'] 
     idx = idx + 1 

     #insert the info with idx 
     if not self.insertFileInfo(collection,file_obj,file_md5,file_time,file_size,long(idx)): 
      return None 
#if the specific document with "md5,time,size" is found 
else: 
#just get the idx with the specific md5 
    idx = collection.find({"src_md5":file_md5,"src_time":file_time,"src_size":file_size},{"idx":1})[0]['idx'] 
    return None 

我将在4台机,这意味着4个过程将几乎更新mongodb的运行上面的代码同时,我如何确保操作的原子性? 我的架构条记录是

{"src_md5":"djapijfdakfiwqjfkasdj","src_size":2376498,"src_time":1338179291,"idx":1} 
{"src_md5":"jdfipajkoijjipjefjidwpj","src_size":234876323,"src_time":1338123873,"idx":2} 
{"src_md5":"djapojfkdasxkjipkjkf","src_size":3829874,"src_time":1338127634,"idx":3} 

它不是一个简单的自动递增键,它应该是MD5,大小,时间的变化增加,shuld和他们一起插入,作为记录。 我在{“src_md5”,“src_time”,“src_size”}上创建一个复合唯一索引,并在{“idx”}上创建一个唯一索引,但在插入新信息之前,我应该获得idx alread exists,然后增加它。 有两种情况: 1,IDX与特定的MD5,大小,时间,如果是已经存在,只是返回IDX 2,如果不存在,增加IDX 1

+0

看起来您的代码在所有路径上都返回无。这是一个错字吗? –

+0

是文档中唯一字段的那四个字段?某些文件的这些属性是否具有其他属性(如文件名或类似内容?) –

回答

1

类似的问题在此讨论question

你想要做的就像是有一个独特的单调递增的键,你会保留在它自己的收集和增量使用$ inc如链接问题中所述。

这将确保您永远不会尝试使用相同的idx两次。现在仍然有可能两个线程尝试插入(md5,size,time)与两个不同idx键的新组合,但第二个线程会失败,因为您拥有的唯一索引(md5,size,time) 。

现在存在的唯一竞争条件是当第二个线程由于唯一索引而无法插入时,您将以未使用的idx值结束(即每次发生这种情况时,增加idx值将跳过一个)。它对你有多大的问题?如果大,您必须强制在应用程序代码中加锁,或者您可以更改架构的结构来处理这种情况。