Commit 7cba67db authored by Alain Takoudjou's avatar Alain Takoudjou

slapos.grid.promise: prevent json file corruption while updating data

history and statistics files are sometimes corrupted because of invalid json
We now use json.dump to write the entire file at once. Probably this will consume
more resources.
parent 1386dba9
...@@ -41,6 +41,7 @@ import traceback ...@@ -41,6 +41,7 @@ import traceback
import psutil import psutil
import inspect import inspect
import hashlib import hashlib
import errno
from datetime import datetime from datetime import datetime
from multiprocessing import Process, Queue as MQueue from multiprocessing import Process, Queue as MQueue
from six.moves import queue, reload_module from six.moves import queue, reload_module
...@@ -458,12 +459,20 @@ class PromiseLauncher(object): ...@@ -458,12 +459,20 @@ class PromiseLauncher(object):
state_dict.pop('path', '') state_dict.pop('path', '')
state_dict.pop('type', '') state_dict.pop('type', '')
state_dict["status"] = "ERROR" if result.item.hasFailed() else "OK" state_dict["status"] = "ERROR" if result.item.hasFailed() else "OK"
history_dict = {
"date": time.time(),
"data": [state_dict]
}
if not os.path.exists(history_file) or not os.stat(history_file).st_size: try:
with open(history_file, 'w') as f: with open(history_file) as f:
f.write("""{ history_dict = json.load(f)
"date": %s, except OSError as e:
"data": %s}""" % (time.time(), json.dumps([state_dict]))) if e.errno != errno.ENOENT:
raise
except ValueError:
# Broken json, use default history_dict
pass
else: else:
previous_state_list = previous_state_dict.get(result.name, None) previous_state_list = previous_state_dict.get(result.name, None)
if previous_state_list is not None: if previous_state_list is not None:
...@@ -473,36 +482,38 @@ class PromiseLauncher(object): ...@@ -473,36 +482,38 @@ class PromiseLauncher(object):
current_sum == checksum: current_sum == checksum:
# Only save the changes and not the same info # Only save the changes and not the same info
return return
state_dict.pop('title', '') state_dict.pop('title', '')
state_dict.pop('name', '') state_dict.pop('name', '')
with open (history_file, mode="r+") as f: history_dict['data'].append(state_dict)
f.seek(0,2)
f.seek(f.tell() -2) with open (history_file, mode="w") as f:
f.write('%s}' % ',{}]'.format(json.dumps(state_dict))) json.dump(history_dict, f)
def _saveStatisticsData(self, stat_file_path, date, success, error): def _saveStatisticsData(self, stat_file_path, date, success, error):
# csv-like document for success/error statictics # csv-like document for success/error statictics
if not os.path.exists(stat_file_path) or os.stat(stat_file_path).st_size == 0: stat_dict = {
with open(stat_file_path, 'w') as fstat: "date": time.time(),
fstat.write("""{ "data": ["Date, Success, Error, Warning"]
"date": %s, }
"data": ["Date, Success, Error, Warning"]}""" % time.time()) try:
with open(stat_file_path) as f:
stat_dict = json.load(f)
except OSError as e:
if e.errno != errno.ENOENT:
raise
except ValueError:
# Broken json, we use default
pass
current_state = '%s, %s, %s, %s' % ( current_state = '%s, %s, %s, %s' % (
date, date,
success, success,
error, error,
'') '')
stat_dict['data'].append(current_state)
# append to file with open (stat_file_path, mode="w") as f:
# XXX this is bad, it is getting everywhere. json.dump(stat_dict, f)
if current_state:
with open (stat_file_path, mode="r+") as fstat:
fstat.seek(0,2)
position = fstat.tell() -2
fstat.seek(position)
fstat.write('%s}' % ',"{}"]'.format(current_state))
def _loadPromiseResult(self, promise_title): def _loadPromiseResult(self, promise_title):
promise_output_file = os.path.join( promise_output_file = os.path.join(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment