##// END OF EJS Templates
Fallback to :memory: on repeated failure to load history...
Min RK -
Show More
@@ -16,7 +16,6 b' except ImportError:'
16 from pysqlite2 import dbapi2 as sqlite3
16 from pysqlite2 import dbapi2 as sqlite3
17 except ImportError:
17 except ImportError:
18 sqlite3 = None
18 sqlite3 = None
19 import sys
20 import threading
19 import threading
21
20
22 from traitlets.config.configurable import LoggingConfigurable
21 from traitlets.config.configurable import LoggingConfigurable
@@ -81,18 +80,29 b' def catch_corrupt_db(f, self, *a, **kw):'
81 try:
80 try:
82 return f(self, *a, **kw)
81 return f(self, *a, **kw)
83 except (DatabaseError, OperationalError) as e:
82 except (DatabaseError, OperationalError) as e:
84 if os.path.isfile(self.hist_file):
83 self._corrupt_db_counter += 1
85 # Try to move the file out of the way
84 self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
86 base,ext = os.path.splitext(self.hist_file)
85 if self.hist_file != ':memory:':
87 newpath = base + '-corrupt' + ext
86 if self._corrupt_db_counter > self._corrupt_db_limit:
88 os.rename(self.hist_file, newpath)
87 self.hist_file = ':memory:'
89 print("ERROR! History file wasn't a valid SQLite database (%s)." % e,
88 self.log.error("Failed to load history too many times, history will not be saved.")
90 "It was moved to %s" % newpath, "and a new file created.", file=sys.stderr)
89 elif os.path.isfile(self.hist_file):
90 # Try to move the file out of the way
91 base,ext = os.path.splitext(self.hist_file)
92 now = datetime.datetime.now().isoformat().replace(':', '.')
93 newpath = base + '-corrupt-' + now + ext
94 # don't clobber previous corrupt backups
95 for i in range(100):
96 if not os.path.isfile(newpath):
97 break
98 else:
99 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
100 os.rename(self.hist_file, newpath)
101 self.log.error("History file was moved to %s and a new file created.", newpath)
91 self.init_db()
102 self.init_db()
92 return []
103 return []
93
94 else:
104 else:
95 # The hist_file is probably :memory: or something else.
105 # Failed with :memory:, something serious is wrong
96 raise
106 raise
97
107
98 class HistoryAccessorBase(LoggingConfigurable):
108 class HistoryAccessorBase(LoggingConfigurable):
@@ -118,6 +128,11 b' class HistoryAccessor(HistoryAccessorBase):'
118 This is intended for use by standalone history tools. IPython shells use
128 This is intended for use by standalone history tools. IPython shells use
119 HistoryManager, below, which is a subclass of this."""
129 HistoryManager, below, which is a subclass of this."""
120
130
131 # counter for init_db retries, so we don't keep trying over and over
132 _corrupt_db_counter = 0
133 # after two failures, fallback on :memory:
134 _corrupt_db_limit = 2
135
121 # String holding the path to the history file
136 # String holding the path to the history file
122 hist_file = Unicode(config=True,
137 hist_file = Unicode(config=True,
123 help="""Path to file to use for SQLite history database.
138 help="""Path to file to use for SQLite history database.
@@ -231,6 +246,8 b' class HistoryAccessor(HistoryAccessorBase):'
231 (session integer, line integer, output text,
246 (session integer, line integer, output text,
232 PRIMARY KEY (session, line))""")
247 PRIMARY KEY (session, line))""")
233 self.db.commit()
248 self.db.commit()
249 # success! reset corrupt db count
250 self._corrupt_db_counter = 0
234
251
235 def writeout_cache(self):
252 def writeout_cache(self):
236 """Overridden by HistoryManager to dump the cache before certain
253 """Overridden by HistoryManager to dump the cache before certain
General Comments 0
You need to be logged in to leave comments. Login now