Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Unified Diff: commit-queue/commit_queue.py

Issue 24434003: CQ: add landmines to delete database after unclean shutdown (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: commit-queue/commit_queue.py
===================================================================
--- commit-queue/commit_queue.py (revision 225230)
+++ commit-queue/commit_queue.py (working copy)
@@ -12,8 +12,10 @@
import logging.handlers
import optparse
import os
+import shutil
import signal
import sys
+import tempfile
import time
import find_depot_tools # pylint: disable=W0611
@@ -123,6 +125,26 @@
logging.getLogger().addHandler(logging_rotating_file)
+class SignalInterrupt(Exception):
+ """Exception that indicates being interrupted by a caught signal."""
+
+ def __init__(self, signal_set=None, *args, **kwargs):
+ super(SignalInterrupt, self).__init__(*args, **kwargs)
+ self.signal_set = signal_set
+
+
+def SaveDatabaseCopyForDebugging(db_path):
+ """Saves database file for debugging. Returns name of the saved file."""
+ with tempfile.NamedTemporaryFile(
+ dir=os.path.dirname(db_path),
+ prefix='db.debug.',
+ suffix='.json',
+ delete=False) as tmp_file:
+ with open(db_path) as db_file:
+ shutil.copyfileobj(db_file, tmp_file)
+ return tmp_file.name
+
+
def main():
parser = optparse.OptionParser(
description=sys.modules['__main__'].__doc__)
@@ -235,13 +257,31 @@
print 'Using read-only chromium-status interface'
pc.context.status = async_push.AsyncPushStore()
+ landmine_path = os.path.join(work_dir,
+ pc.context.checkout.project_name + '.landmine')
db_path = os.path.join(work_dir, pc.context.checkout.project_name + '.json')
if os.path.isfile(db_path):
- try:
- pc.load(db_path)
- except ValueError:
+ if os.path.isfile(landmine_path):
+ debugging_path = SaveDatabaseCopyForDebugging(db_path)
os.remove(db_path)
+ logging.warning(('Deleting database because previous shutdown '
+ 'was unclean. The copy of the database is saved '
+ 'as %s.') % debugging_path)
+ else:
+ try:
+ pc.load(db_path)
+ except ValueError as e:
+ debugging_path = SaveDatabaseCopyForDebugging(db_path)
+ os.remove(db_path)
+ logging.warning(('Failed to parse database (%r), deleting it. '
+ 'The copy of the database is saved as %s.') %
+ (e, debugging_path))
+ raise e
+ # Create a file to indicate unclean shutdown.
+ with open(landmine_path, 'w'):
+ pass
+
sig_handler.installHandlers(
signal.SIGINT,
signal.SIGHUP
@@ -254,6 +294,7 @@
pc.look_for_new_pending_commit()
pc.update_status()
print(str(pc.queue))
+ os.remove(landmine_path)
return 0
now = time.time()
@@ -268,7 +309,7 @@
pc.update_status()
pc.scan_results()
if sig_handler.getTriggeredSignals():
- raise KeyboardInterrupt()
+ raise SignalInterrupt(signal_set=sig_handler.getTriggeredSignals())
# Save the db at each loop. The db can easily be in the 1mb range so
# it's slowing down the CQ a tad but it in the 100ms range even for that
# size.
@@ -293,7 +334,7 @@
while True:
# Abort if any signals are set
if sig_handler.getTriggeredSignals():
- raise KeyboardInterrupt()
+ raise SignalInterrupt(signal_set=sig_handler.getTriggeredSignals())
delay = next_loop - now
if delay <= 0:
break
@@ -314,13 +355,32 @@
pc.save(db_path)
pc.close()
logging.warning('db save successful.')
- except KeyboardInterrupt as e:
- print 'Bye bye'
+ except SignalInterrupt:
+ # This is considered a clean shutdown: we only throw this exception
+ # from selected places in the code where the database should be
+ # in a known and consistent state.
+ os.remove(landmine_path)
+
+ print 'Bye bye (SignalInterrupt)'
# 23 is an arbitrary value to signal loop.sh that it must stop looping.
return 23
+ except KeyboardInterrupt:
+ # This is actually an unclean shutdown. Do not remove the landmine file.
+ # One example of this is user hitting ctrl-c twice at an arbitrary point
+ # inside the CQ loop. There are no guarantees about consistent state
+ # of the database then.
+
+ print 'Bye bye (KeyboardInterrupt - this is considered unclean shutdown)'
+ # 23 is an arbitrary value to signal loop.sh that it must stop looping.
+ return 23
except errors.ConfigurationError as e:
parser.error(str(e))
return 1
+
+ # CQ generally doesn't exit by itself, but if we ever get here, it looks
+ # like a clean shutdown so remove the landmine file.
+ # TODO(phajdan.jr): Do we ever get here?
+ os.remove(landmine_path)
return 0
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698