1

嗨想象我有这样的代码:

0. void someFunction()
1. { 
2.  ...
3.  if(x>5)
4.    doSmth();
5. 
6.   writeDataToCard(handle, data1);
7. 
8.   writeDataToCard(handle, data2);
9.
10.  incrementDataOnCard(handle, data);
11. }

事情在后面。如果执行了第 6 步和第 8 步,然后有人说移除卡 - 那么操作 10 将不会成功完成。但这将是我系统中的一个错误。意思是如果 6 & 8 被执行,那么 10 也必须被执行。如何处理这种情况?

快速总结:我的意思是说在第 8 步之后有人可能会移除我的实体卡,这意味着永远无法到达第 10 步,这将导致我的系统出现问题。即卡片将使用不完整的数据进行初始化。

4

5 回答 5

2

您将必须创建某种协议,例如,您向卡写入要完成的操作列表:

  1. 第 6 步、第 8 步、第 10 步

当您完成任务时,您会从列表中删除该条目。

当您从磁盘重新读取数据时,您会检查列表是否有任何条目。如果是,则该操作之前未成功完成,您将恢复之前的状态。

除非您能以某种方式物理阻止用户移除卡,否则没有其他方法。

于 2013-09-30T14:53:55.797 回答
2

如果交易中断,则卡处于故障状态。你有三个选择:

  1. 没做什么。该卡处于故障状态,它将保持在那里。建议用户不要玩该卡。卡可以有资格进行完全清洁或格式化。
  2. 下次卡可用时回滚交易。您需要有关卡和/或某个中央存储库的足够信息来执行回滚。
  3. 下次卡可用时完成交易。您需要有关卡和/或某个中央存储库的足够信息来执行完成。

在所有这三种情况下,您都需要在卡上放置一个标志来表示正在进行的交易。

于 2013-09-30T15:03:36.403 回答
0

为了回答这个问题,需要更多细节。

但是,做一些假设,我会提出两种可能的解决方案(更多可能......)。我假设写操作是持久的 - 因此在卡被移除 - 重新插入后写入卡的数据仍然存在,并且您指的是卡上数据的一致性 - 而不是执行函数调用的程序的状态。还假设增量方法,对已写入的数据进行增量,并且系统必须完成此操作以保证一致性:

  1. 对于每条写入的记录,维护另一个指示记录状态的数据元素(在卡片上)。在执行 writeData 操作之前,该状态将被初始化为某种东西(比如“WRITING”状态)。在 incrementData 操作(成功!)执行后,此状态设置为“WRITTEN”。从卡中读取时 - 您首先检查此状态并忽略(或删除)未写入的记录。

  2. 另一种选择是在卡上维护两个(永久)计数器:一个计算开始写入的记录数,另一个计算结束写入的记录数。在执行写入之前增加第一个,然后在(成功)执行 incrementData 调用之后增加第二个。稍后从卡中读取时,您可以轻松检查记录是否确实有效,或者是否需要丢弃。如果书面记录以某种方式排序或索引,则此选项有效,因此您只需检查计数器即可查看哪些记录和多少记录有效。它的优点是对于任意数量的记录只需要两个计数器(与选项 1 中的每个记录的 1 个状态相比)。

在主机(软件)方面,您需要在开始写入之前检查卡是否可用(如果不存在则不要写入)。如果在 incrementData 操作之后您检测到卡已被移除,那么您需要确保在检测到卡被重新插入后或在进行另一次写入之前进行整理(移除未完成的记录、更新计数器)。为此,您需要在软件端维护状态信息。

同样,解决方案的类型(更多)取决于确切的系统和要求。

于 2013-09-30T15:18:28.363 回答
0

不就是这样吗:

  • 将数据复制到temporary_data。
  • 写入临时数据。
  • 增加临时数据。
  • 将数据重命名为 old_data。
  • 将temporary_data 重命名为数据。
  • 删除旧数据。

在两个重命名步骤中,您仍然会遇到竞争条件(如果幸运的用户移除了卡),但您可能会恢复数据或临时数据。

于 2013-09-30T15:52:20.987 回答
0

你还没有说你要增加什么(或者为什么),或者你的数据是如何构造的(大概在你写的writeDataToCard东西和你要增加的东西之间存在某种关系)。

因此,虽然可能有针对您的数据的巧妙技术,但我们没有足够的能力继续下去。以下是明显的通用技术:

  1. 可能可行的最简单的事情-全卡提交或回滚

    保留所有数据的两份副本,好的一份和的一份。最低地址的单个字节足以说明哪个是当前好的字节(它本质上是大小为 2 的数组的索引)。

    将新数据写入脏区,完成后,更新索引字节(因此交换干净和脏)。

    要么更新索引并且您的新数据一切正常,要么拔出卡并且之前的干净副本仍然处于活动状态。

    - 这很简单

    缺点- 你浪费了一半的存储空间,当你改变任何东西时,你需要将一个完整的新副本写入脏区。您没有提供足够的信息来确定这对您来说是否是个问题。

  2. ...现在使用更少的空间... -提交或回滚更小的子集

    如果您不能浪费 50% 的存储空间,请将您的数据拆分为独立的块,并独立地对每个块进行版本控制。现在你只需要足够的空间来复制你最大的单个块,但是你需要每个块的偏移量或指针而不是简单的索引。

    Pro - 仍然相当简单

    缺点- 您无法处理块之间的依赖关系,它们必须被隔离

  3. 日记

    根据 RedX 的回答,许多文件系统都使用它来保持完整性。

    Pro - 这是一种可靠的技术,您可以找到现有文件系统的文档和参考实现

    骗局-您刚刚编写了一个现代文件系统。这真的是你想要的吗?

于 2013-09-30T16:28:15.723 回答