使用程序存储器恢复更改

时间:2012-09-23 02:44:47

标签: memory logic linear procedural

是否可以通过使用某些逻辑路径的方式存储集合的所有更改 - 更改发生时 - 以便可以通过“退回”来还原更改?我假设某些事情需要在变化发生时进行映射,因此恢复它们的过程最终将是线性的。

对任何不连贯的道歉,这不适用于任何特定语言。相反,这是一个内存问题 - 即一组(例如可能是某些用户输入的存储)有限大小的连续变化(例如,在任何给定时间任何金额)时间 - 对于它可以改变的程度没有限制)在程序上进行映射,以便假定新的 - 未来 - 更改是先前更改的结果(在第二个,镜像存储中,可用于将集合的状态一直恢复到其初始状态)

1 个答案:

答案 0 :(得分:1)

您可能希望查看一些功能数据结构。功能语言(如Erlang)可以轻松回滚到早期状态,因为总是在新数据结构上进行更改而不是改变现有数据结构。虽然这个功能可以在内部重复使用,但Erlang编程通常会在"过程的顶级使用它。因此,在任何类型的失败中,它只是通过抛出异常(在非函数语言中,使用可变数据结构,您能够抛出异常)中止处理以及整体上的所有更改中止,但恢复原件将是你的程序的工作,而不是运行时的工作)。这是Erlang声誉良好的原因之一。

这种函数式编程风格中的一些有用地应用于非函数语言,特别是使用不可变数据结构,例如不可变集,列表或树。

关于不可变集,例如,可以设计一个面向功能的数据结构,其中修改总是在给定一些更改和现有集(由添加和删除组成的更改集)的情况下生成新集。你可以把旧套装留在周围供参考(由任何人);具有自动垃圾收集功能的语言在不再使用(引用)时回收旧语言。

您可以将id或标记放入您的集合数据结构中,这样您就可以进行一些内省,以查看某人拥有的数据结构ID。您还可以捕获生成每个新版本的基础的id;这给你一些历史或血统。

如果需要,您还可以捕获对新数据结构中的整个旧数据结构的引用,或者,可以在生成它们时维护所有集合的全局列表。但是,如果您这样做,您将不得不承担更多的存储管理责任,因为自动收集器可能无法在没有其他帮助的情况下找到任何未使用的(未引用的)垃圾。

数据库设计在其事务控制器中执行此操作。出于您的问题的目的,您可以将数据库视为美化集。您可以将MVCC(多版本并发控制)作为一个在文献中写得相当好的例子。这种技术保留了(临时)数据结构的旧快照版本,这意味着突变似乎总是出现在新版本的数据中。保留旧快照,直到没有活动事务引用它为止;然后被丢弃。当两个同时运行的事务都修改数据库时,它们每个都基于相同的当前和最新数据集获得新版本。 (事务控制器确切地知道每个事务所基于的版本,尽管事务的客户端没有看到版本信息。)假设两个并发事务都选择提交他们的更改,那么事务中的版本控制控制器识别出第二个提交者正在尝试提交一个不是第一个提交者的逻辑继承者的更改集(因为我们上面假设的两个更改集都基于相同的早期版本)。如果可能的话,事务控制器将合并这些更改,就像第二个提交者实际上正在处理第一个提交者提交的另一个更新的版本一样。 (对于何时可能有不同的定义,MVCC表示当没有写入冲突时,这是一个不太完美的答案,但速度快且可扩展。)但如果不可能,它将中止第二个提交者事务和通知其第二个提交者(如果他们愿意,他们有机会从较新的基地重试他们的交易)。在幕后,并发事务中的各种快照版本可能会共享大量数据(首先查询一些特定于事务的更改集),以便使快照便宜。通常没有提供API来访问旧版本,因此在此域中,事务控制器知道当事务退出时,他们使用的原始快照版本也可以(引用计数和)退役。

这样做的另一个方面是使用Append-Only-Files。记录是记录变化的一种方式;一些数据库100%基于面向日志的设计。

BerkeleyDB有一个很好的日志结构。虽然主要用于恢复,但它确实包含所有历史记录,因此您可以从日志中重新创建数据库(直到清除日志为止,在这种情况下您还应该归档数据库)。有些人必须决定何时可以启动新的日志文件,何时可以清除旧的日志文件,这样做是为了节省空间。

这些数据库技术也可以应用于内存中。 (当然,没有什么是免费的;)

无论如何,是的,有些领域已经完成。

  1. 通过简单地保留旧副本,不可变数据结构有助于保存历史记录;更改总是转到新副本。 (效率技术可以使它不像听起来那么糟糕。)
  2. 我可以帮助理解血统而不必持有所有旧拷贝。
  3. 如果您确实希望保留所有旧版本,则必须查看您的域设计,以了解何时/如何/如何/是否可以访问旧数据结构,并着眼于如何最终回收它们。如果有的话,你很可能不得不参与定义如何发布它们。或者他们如何为后代存档,但代价是以后访问速度较慢。