我在做一个不可靠系统的项目,我认为它在任何时候都可能失败。我要保证的是,如果我写了_状态,而机器在操作中失败,则read_状态将读取有效状态或根本没有状态。我已经实现了一些我认为会在下面起作用的东西——我对那些批评或者其他解决方案感兴趣,如果有人知道的话。在
我的想法是:
import hashlib, cPickle, os
def write_state(logname, state):
state_string = cPickle.dumps(state, cPickle.HIGHEST_PROTOCOL)
state_string += hashlib.sha224(state_string).hexdigest()
handle = open('%s.1' % logname, 'wb')
handle.write(state_string)
handle.close()
handle = open('%s.2' % logname, 'wb')
handle.write(state_string)
handle.close()
def get_state(logname):
def read_file(name):
try:
f = open(name,'rb')
data = f.read()
f.close()
return data
except IOError:
return ''
def parse(data):
if len(data) < 56:
return (None, '', False)
hash = data[-56:]
data = data[:-56]
valid = hashlib.sha224(data).hexdigest() == hash
try:
parsed = cPickle.loads(data)
except cPickle.UnpicklingError:
parsed = None
return (parsed, valid)
data1,valid1 = parse(read_file('%s.1'%logname))
data2,valid2 = parse(read_file('%s.2'%logname))
if valid1 and valid2:
return data1
elif valid1 and not valid2:
return data1
elif valid2 and not valid1:
return data2
elif not valid1 and not valid2:
raise Exception('Theoretically, this never happens...')
例如:
^{pr2}$
我对数据库工作方式的模糊记忆是这样的。它包括三个文件。控制文件、目标数据库文件和挂起的事务日志。在
控制文件具有全局事务计数器和哈希或其他校验和。这是一个只有一个物理块大小的小文件。一个操作系统级写入。在
在目标文件中有一个全局事务计数器,其中包含实际数据,外加哈希或其他校验和。在
有一个挂起的事务日志刚刚增长,或者是一个有限大小的循环队列,或者可能会滚动。没什么大不了的。在
将所有挂起的事务记录到简单日志中。有序列号和变化的内容。
更新事务计数器,更新控制文件中的哈希。一封信,满脸通红。如果这失败了,那么一切都没有改变。如果成功,则控制文件和目标文件不匹配,表示事务已启动但尚未完成。
对目标文件执行预期的更新。查找开头并更新计数器和校验和。如果失败,则控制文件的计数器比目标文件多。目标文件已损坏。这样做时,最后记录的事务、控制文件和目标文件都同意序列号。
您可以通过重放日志来恢复,因为您知道最后一个正确的序列号。在
你的两份不起作用。文件系统可以重新排序,这样两个文件在写入磁盘之前都被截断了。在
有一些文件系统操作被保证是原子的:在另一个文件上重命名文件是一种操作,只要文件在一个地方或另一个地方。然而,就POSIX而言,它不能保证在文件内容到达磁盘之前就完成了移动,这意味着它只给您提供锁定。在
Linux文件系统已经强制要求文件内容在原子移动之前到达磁盘(但不是同步的),所以这可以满足您的需要。ext4在短时间内打破了这一假设,使得那些文件实际上更有可能变成空文件。这是widely regarded as a dick move,自那时起已被纠正。在
无论如何,正确的方法是:在同一个目录中创建临时文件(因此它在同一个文件系统中);写入新数据;fsync临时文件;将其重命名为以前的版本。这是操作系统所能保证的原子级的。它还以盘旋磁盘为代价提供了耐用性,这就是为什么应用程序开发人员不喜欢使用fsync,也不想把有问题的ext4版本列入黑名单。在
我将添加一个异端的回答:使用sqlite怎么样?或者,可能是bsddb,但是这似乎是不推荐使用的,您必须使用第三方模块。在
相关问题 更多 >
编程相关推荐