Implement atomic updates for SQL tables to ensure we get the whole
of a job, or nothing ... rather than partial corruption.

From: Jeremy Orlow <jorlow@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@787 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/tko/db.py b/tko/db.py
index a4d2bc6..5e6cc29 100644
--- a/tko/db.py
+++ b/tko/db.py
@@ -1,13 +1,14 @@
 import MySQLdb, re, os, sys, types
 
 class db:
-	def __init__(self, debug = False):
+	def __init__(self, debug = False, autocommit=True):
 		self.debug = debug
+		self.autocommit = autocommit
 
 		path = os.path.dirname(os.path.abspath(sys.argv[0]))
 		try:
 			file = os.path.join(path, '.database')
-			db_prefs = open(path, 'r')
+			db_prefs = open(file, 'r')
 			host = db_prefs.readline().rstrip()
 			database = db_prefs.readline().rstrip()
 		except:
@@ -22,7 +23,7 @@
 		except:	
 			try:
 				file = os.path.join(path, '.unpriv_login')
-				login = open(path, 'r')
+				login = open(file, 'r')
 				user = login.readline().rstrip()
 				password = login.readline().rstrip()
 			except:
@@ -53,6 +54,10 @@
 			sys.stderr.write('SQL: ' + str(value) + '\n')
 
 
+	def commit(self):
+		self.con.commit()
+
+
 	def select(self, fields, table, where, distinct = False):
 		"""\
 			select fields from table where {dictionary}
@@ -86,13 +91,15 @@
 		return self.cur.fetchall()
 
 
-	def insert(self, table, data):
+	def insert(self, table, data, commit = None):
 		"""\
 			'insert into table (keys) values (%s ... %s)', values
 
 			data:
 				dictionary of fields and data
 		"""
+		if commit == None:
+			commit = self.autocommit
 		fields = data.keys()
 		refs = ['%s' for field in fields]
 		values = [data[field] for field in fields]
@@ -101,16 +108,19 @@
 
 		self.dprint('%s %s' % (cmd,values))
 		self.cur.execute(cmd, values)
-		self.con.commit()
+		if commit:
+			self.con.commit()
 
 
-	def update(self, table, data, where):
+	def update(self, table, data, where, commit = None):
 		"""\
 			'update table set data values (%s ... %s) where ...'
 
 			data:
 				dictionary of fields and data
 		"""
+		if commit == None:
+			commit = self.autocommit
 		cmd = 'update %s ' % table
 		fields = data.keys()
 		data_refs = [field + '=%s' for field in fields]
@@ -123,26 +133,30 @@
 
 		print '%s %s' % (cmd, data_values + where_values)
 		self.cur.execute(cmd, data_values + where_values)
-		self.con.commit()
+		if commit:
+			self.con.commit()
 
 
-	def insert_job(self, tag, job):
+	def insert_job(self, tag, job, commit = None):
 		job.machine_idx = self.lookup_machine(job.machine)
 		if not job.machine_idx:
-			job.machine_idx = self.insert_machine(job.machine)
-		self.insert('jobs', {'tag':tag, 'machine_idx':job.machine_idx})
+			job.machine_idx = self.insert_machine(job.machine,
+		                                              commit=commit)
+		self.insert('jobs',
+		            {'tag':tag,
+		             'machine_idx':job.machine_idx},
+                            commit=commit)
 		job.index = self.find_job(tag)
 		for test in job.tests:
-			self.insert_test(job, test)
+			self.insert_test(job, test, commit=commit)
 
-
-	def insert_test(self, job, test):
-		kver = self.insert_kernel(test.kernel)
+	def insert_test(self, job, test, commit = None):
+		kver = self.insert_kernel(test.kernel, commit=commit)
 		data = {'job_idx':job.index, 'test':test.testname,
 			'subdir':test.subdir, 'kernel_idx':kver,
 			'status':self.status_idx[test.status],
 			'reason':test.reason, 'machine_idx':job.machine_idx }
-		self.insert('tests', data)
+		self.insert('tests', data, commit=commit)
 		test_idx = self.find_test(job.index, test.subdir)
 		data = { 'test_idx':test_idx }
 
@@ -151,7 +165,9 @@
 			for key in i.keyval:
 				data['attribute'] = key
 				data['value'] = i.keyval[key]
-				self.insert('iteration_result', data)
+				self.insert('iteration_result',
+                                            data,
+                                            commit=commit)
 
 
 	def read_machine_map(self):
@@ -161,15 +177,17 @@
 			self.machine_group[machine] = group
 
 
-	def insert_machine(self, hostname, group = None):
+	def insert_machine(self, hostname, group = None, commit = None):
 		if self.machine_map and not self.machine_group:
 			self.read_machine_map()
 
 		if not group:
 			group = self.machine_group.get(hostname, hostname)
 				
-		self.insert('machines', { 'hostname' : hostname ,
-					  'machine_group' : group })
+		self.insert('machines',
+                            { 'hostname' : hostname ,
+		              'machine_group' : group },
+		            commit=commit)
 		return self.lookup_machine(hostname)
 
 
@@ -191,27 +209,31 @@
 			return None
 
 
-	def insert_kernel(self, kernel):
+	def insert_kernel(self, kernel, commit = None):
 		kver = self.lookup_kernel(kernel)
 		if kver:
 			return kver
-		self.insert('kernels', {'base':kernel.base,
-					'kernel_hash':kernel.kernel_hash,
-					'printable':kernel.base})
+		self.insert('kernels',
+                            {'base':kernel.base,
+		             'kernel_hash':kernel.kernel_hash,
+		             'printable':kernel.base},
+		            commit=commit)
 		# WARNING - incorrectly shoving base into printable here.
 		kver = self.lookup_kernel(kernel)
 		for patch in kernel.patches:
-			self.insert_patch(kver, patch)
+			self.insert_patch(kver, patch, commit=commit)
 		return kver
 
 
-	def insert_patch(self, kver, patch):
+	def insert_patch(self, kver, patch, commit = None):
 		print patch.reference
 		name = os.path.basename(patch.reference)[:80]
-		self.insert('patches', {'kernel_idx': kver, 
-					'name':name,
-					'url':patch.reference, 
-					'hash':patch.hash})
+		self.insert('patches',
+                            {'kernel_idx': kver, 
+		             'name':name,
+		             'url':patch.reference, 
+		             'hash':patch.hash},
+                            commit=commit)
 
 
 	def find_test(self, job_idx, subdir):