##// END OF EJS Templates
Add error handling so SQLite history can recover from corrupt databases and session/line number collisions.
Thomas Kluyver -
Show More
@@ -98,7 +98,15 b' class HistoryManager(Configurable):'
98 else:
98 else:
99 histfname = 'history'
99 histfname = 'history'
100 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
100 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
101 self.init_db()
101 try:
102 self.init_db()
103 except sqlite3.DatabaseError:
104 newpath = os.path.join(self.shell.ipython_dir, "hist-corrupt.sqlite")
105 os.rename(self.hist_file, newpath)
106 print("ERROR! History file wasn't a valid SQLite database.",
107 "It was moved to %s" % newpath, "and a new file created.")
108 self.init_db()
109
102 self.new_session()
110 self.new_session()
103
111
104 self._i00, self._i, self._ii, self._iii = '','','',''
112 self._i00, self._i, self._ii, self._iii = '','','',''
@@ -357,8 +365,7 b' class HistoryManager(Configurable):'
357 self.input_hist_parsed.append(source)
365 self.input_hist_parsed.append(source)
358 self.input_hist_raw.append(source_raw)
366 self.input_hist_raw.append(source_raw)
359
367
360 self.db_input_cache.append((self.session_number, line_num,
368 self.db_input_cache.append((line_num, source, source_raw))
361 source, source_raw))
362 # Trigger to flush cache and write to DB.
369 # Trigger to flush cache and write to DB.
363 if len(self.db_input_cache) >= self.db_cache_size:
370 if len(self.db_input_cache) >= self.db_cache_size:
364 self.writeout_cache()
371 self.writeout_cache()
@@ -390,22 +397,46 b' class HistoryManager(Configurable):'
390 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
397 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
391 return
398 return
392 output = json.dumps(self.output_hist_reprs[line_num])
399 output = json.dumps(self.output_hist_reprs[line_num])
393 db_row = (self.session_number, line_num, output)
394 if self.db_cache_size > 1:
395 self.db_output_cache.append(db_row)
396 else:
397 with self.db:
398 self.db.execute("INSERT INTO output_history VALUES (?,?,?)", db_row)
399
400
401 self.db_output_cache.append((line_num, output))
402 if self.db_cache_size <= 1:
403 self.writeout_cache()
404
405 def _writeout_input_cache(self):
406 for line in self.db_input_cache:
407 with self.db:
408 self.db.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
409 (self.session_number,)+line)
410
411 def _writeout_output_cache(self):
412 for line in self.db_output_cache:
413 with self.db:
414 self.db.execute("INSERT INTO output_history VALUES (?, ?, ?)",
415 (self.session_number,)+line)
416
400 def writeout_cache(self):
417 def writeout_cache(self):
401 #print(self.db_input_cache)
418 """Write any entries in the cache to the database."""
402 with self.db:
419 try:
403 self.db.executemany("INSERT INTO history VALUES (?, ?, ?, ?)",
420 self._writeout_input_cache()
404 self.db_input_cache)
421 except sqlite3.IntegrityError:
405 self.db.executemany("INSERT INTO output_history VALUES (?, ?, ?)",
422 self.new_session()
406 self.db_output_cache)
423 print("ERROR! Session/line number was not unique in",
407 self.db_input_cache = []
424 "database. History logging moved to new session",
408 self.db_output_cache = []
425 self.session_number)
426 try: # Try writing to the new session. If this fails, don't recurse
427 self.writeout_cache()
428 except sqlite3.IntegrityError:
429 pass
430 finally:
431 self.db_input_cache = []
432
433 try:
434 self._writeout_output_cache()
435 except sqlite3.IntegrityError:
436 print("!! Session/line number for output was not unique",
437 "in database. Output will not be stored.")
438 finally:
439 self.db_output_cache = []
409
440
410
441
411 # To match, e.g. ~5/8-~2/3
442 # To match, e.g. ~5/8-~2/3
General Comments 0
You need to be logged in to leave comments. Login now