ZODB:到event.savepoint写入数据的位置?

时间:2013-10-31 15:44:04

标签: python transactions zodb

根据ZODB documentation

  

保存点允许数据管理器将工作保存到其存储而无需提交完整的事务。“”保存点对于释放内存也很有用,否则这些内存将用于保持事务的整个状态。

根据非常有启发性的文章When to commit data in ZODB(Martijn Pieters):

  

...在整个交易期间,您可以要求将数据临时存储在磁盘上。   [...]
  保存点的一个作用是调用ZODB缓存的垃圾收集,这意味着当前未使用的任何数据都将从内存中删除。

问题是,我需要在一个事务中存储大量项目,如下所示:

for i, item in enumerate(aLotOfItems):
    database[i]=item
    if i % 10000 ==0:
        transaction.savepoint(True)
transaction.commit()

我希望transaction.savepoint的工作方式与bsddb3.db.Db.sync相同。调用Db.sync()时,将刷新数据库,您可以观察它。但是当设置保存点时,显然数据库和tmp文件都不会增长或者大小不变transaction.commit()

我真的很困惑:

  • 设置保存点后实际发生了什么?

  • 与提交/刷新数据库有什么不同?

  • 如果“要临时存储在磁盘上的数据”,保存点在哪里写入数据?

  • 我可以依靠保存点来实现“免费记忆”吗?

2 个答案:

答案 0 :(得分:7)

保存点的原始主要用途是能够回滚事务的部分

假设您想接受大量日志条目,但需要将这些条目批量处理到数据库中:

for batch in per_batch(log_entries):
    sp = transaction.savepoint()
    try:
        process_batch(batch)
    except BatchFailedException:
        sp.rollback()
        transaction.commit()
        raise

现在交易已经提交,除了最后一批已经回滚。

这是使用保存点的原始原因。设置保存点具有触发ZODB缓存垃圾收集运行的副作用。

ZODB拥有最近访问过的对象的缓存。这包括在当前事务中实际不会更改的对象;您只是从数据库中检索它们,使用它们的数据,然后停止直接引用它们。 ZODB存储对象图;一个对象引用其他对象,而这些对象又引用其他对象。如果这些对象从Persistent基类继承,则每个对象都是单独的ZODB记录。遍历图形时,这些对象都被加载到内存中。

GC运行再次从内存中清除,只要它们没有更改。再次遍历对象图将再次将它们加载到内存中,但在保存点期间清除它们可以节省内存。

保存点数据本身存储在TmpStorage目录中TEMP文件的磁盘上。这使用tempfile.TemporaryFile()对象,出于安全原因,该对象是在 unlinked 状态下创建的;文件存在,但目录条目在创建时立即清除。因此,无法从ZODB流程外部看到此文件。

完整提交将数据移动到实际的ZODB数据库中并完成事务。

答案 1 :(得分:0)

保存点的主要用途是释放内存并将事务相关数据从内存存储到磁盘 - 尤其是对于大型事务和大量修改过的数据。