Je travaille sur un projet sur un système non fiable qui, je suppose, peut échouer à tout moment. Ce que je veux garantir, c'est que si write_state et la machine échouent au milieu de l'opération, read_state lira un état valide ou aucun état du tout. J'ai mis en place quelque chose qui, je pense, travaillera ci-dessous - je m'intéresse à la critique de cela ou à des solutions alternatives si quelqu'un en connaît une.Stockage d'état atomique en Python?
Mon idée:
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...')
.: par exemple
write_state('test_log', {'x': 5})
print get_state('test_log')
Le fichier file.close() ne doit pas appeler un fsync? Ou n'est-ce pas synchrone? – sbirch
Non. fsync signifie bloquer jusqu'à ce que cela frappe le disque. C'est cher car il tourne le disque. Il peut aussi être lent si vous avez beaucoup de données entrantes, et tout doit être écrit avant que votre fichier ne le puisse (quelle ext3 avec données = garanties commandées). fermer est bon marché et asynchrone. – Tobu
Pourquoi ne pas simplement fsync les fichiers eux-mêmes? – sbirch