[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kajongg/sid] src: Ruleset: better SQL. Query: Do not repeat on failure.
From:       Wolfgang Rohdewald <wolfgang () rohdewald ! de>
Date:       2013-10-31 21:21:08
Message-ID: E1Vbzfw-0002lj-La () scm ! kde ! org
[Download RAW message or body]

Git commit afeebc695ed4f5c8b798f80230855206574a0984 by Wolfgang Rohdewald.
Committed on 30/10/2013 at 11:57.
Pushed by wrohdewald into branch 'sid'.

Ruleset: better SQL. Query: Do not repeat on failure.

- if the hash already exists in DB, use its rulesetId

- if getting a rulesetId fails because of concurrent clients, repeat the entire \
transaction and not the single Query

- use only one big SQL statement for writing all rules. This is much faster.

- editing a rule: Do not delete/insert but update

M  +28   -29   src/query.py
M  +27   -18   src/rule.py
M  +1    -1    src/util.py

http://commits.kde.org/kajongg/afeebc695ed4f5c8b798f80230855206574a0984

diff --git a/src/query.py b/src/query.py
index a05f8e7..91abdec 100644
--- a/src/query.py
+++ b/src/query.py
@@ -23,13 +23,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA \
02110-1301, USA.  
 """
 
-import os, sys, time, datetime, traceback, random
+import os, sys, datetime, traceback, random
 from collections import defaultdict
 from PyQt4.QtCore import QVariant, QString
-from util import logInfo, logWarning, logException, logDebug, appdataDir, m18ncE, \
xToUtf8 +from util import logInfo, logWarning, logException, logError, logDebug, \
appdataDir, m18ncE, xToUtf8  from common import Options, Internal, Debug, IntDict
 from PyQt4.QtSql import QSqlQuery, QSqlDatabase, QSql
 
+class QueryException(Exception):
+    """as the name says"""
+    def __init__(self, msg):
+        Exception.__init__(self, msg)
 
 class DBHandle(QSqlDatabase):
     """a handle with our preferred configuration"""
@@ -407,7 +411,7 @@ class Query(object):
 
     localServerName = m18ncE('kajongg name for local game server', 'Local Game')
 
-    def __init__(self, cmdList, args=None, dbHandle=None, silent=False, \
mayFail=False): +    def __init__(self, cmdList, args=None, dbHandle=None, \
                silent=False, mayFail=False, failSilent=False):
         """we take a list of sql statements. Only the last one is allowed to be
         a select statement.
         Do prepared queries by passing a single query statement in cmdList
@@ -426,39 +430,34 @@ class Query(object):
             cmdList = list([cmdList])
         self.cmdList = cmdList
         for cmd in cmdList:
-            retryCount = 0
-            while retryCount < 100:
-                self.lastError = None
-                if preparedQuery:
-                    self.query.prepare(cmd)
-                    if not isinstance(args[0], list):
-                        args = list([args])
-                    for dataSet in args:
-                        if not silent:
-                            _, utf8Args = xToUtf8(u'', dataSet)
-                            logDebug("{cmd} [{args}]".format(cmd=cmd, args=", \
                ".join(utf8Args)))
-                        for value in dataSet:
-                            self.query.addBindValue(QVariant(value))
-                        self.success = self.query.exec_()
-                        if not self.success:
-                            break
-                else:
+            self.lastError = None
+            if preparedQuery:
+                self.query.prepare(cmd)
+                if not isinstance(args[0], list):
+                    args = list([args])
+                for dataSet in args:
                     if not silent:
-                        logDebug('%s %s' % (self.dbHandle.name, cmd))
-                    self.success = self.query.exec_(cmd)
-                if self.success or self.query.lastError().number() not in (5, 6):
-                    # 5: database locked, 6: table locked. Where can we get symbols \
                for this?
-                    break
-                time.sleep(0.1)
-                retryCount += 1
+                        _, utf8Args = xToUtf8(u'', dataSet)
+                        logDebug("{cmd} [{args}]".format(cmd=cmd, args=", \
".join(utf8Args))) +                    for value in dataSet:
+                        self.query.addBindValue(QVariant(value))
+                    self.success = self.query.exec_()
+                    if not self.success:
+                        break
+            else:
+                if not silent:
+                    logDebug('%s %s' % (self.dbHandle.name, cmd))
+                self.success = self.query.exec_(cmd)
             if not self.success:
                 self.lastError = unicode(self.query.lastError().text())
                 self.msg = 'ERROR in %s: %s' % (self.dbHandle.databaseName(), \
self.lastError)  if mayFail:
-                    if not silent:
+                    if not failSilent:
                         logDebug(self.msg)
                 else:
-                    logException(self.msg)
+                    if not failSilent:
+                        logError(self.msg)
+                    raise QueryException(self.msg)
                 return
         self.records = None
         self.fields = None
diff --git a/src/rule.py b/src/rule.py
index 7d496ba..35a672e 100644
--- a/src/rule.py
+++ b/src/rule.py
@@ -27,7 +27,7 @@ from hashlib import md5
 from PyQt4.QtCore import QVariant
 
 from util import m18n, m18nc, m18nE, english, logException
-from query import Query, Transaction
+from query import Query, QueryException, Transaction
 
 import rulecode
 
@@ -573,30 +573,39 @@ into a situation where you have to pay a penalty"""))
         """update rule in database"""
         self.__hash = None  # invalidate, will be recomputed when needed
         with Transaction():
-            Query("DELETE FROM rule WHERE ruleset=? and name=?", \
                list([self.rulesetId, english(rule.name)]))
-            self.saveRule(rule)
+            record = self.ruleRecord(rule)
+            Query("UPDATE rule SET name=?, definition=?, points=?, doubles=?, \
limits=?, parameter=? " +                  "WHERE ruleset=? AND list=? AND \
position=?", +                  record[3:] + record[:3])
             Query("UPDATE ruleset SET hash=? WHERE id=?", list([self.hash, \
self.rulesetId]))  
-    def saveRule(self, rule):
-        """save only rule in database"""
-        Query('INSERT INTO rule(ruleset, list, position, name, definition, '
-                'points, doubles, limits, parameter)'
-                ' VALUES(?,?,?,?,?,?,?,?,?)',
-                self.ruleRecord(rule))
-
     def save(self, minus=False):
         """save the ruleset to the database.
-        It always gets a new id, as it does not yet exist in database.
+        If it does not yet exist in database, give it a new id
         If the name already exists in the database, also give it a new name"""
-        assert self.rulesetId == 0, self
-        with Transaction():
-            self.rulesetId, self.name = self._newKey(minus)
-            Query('INSERT INTO ruleset(id,name,hash,description) VALUES(?,?,?,?)',
-                list([self.rulesetId, english(self.name), self.hash, \
self.description])) +        for _ in range(10):
+            try:
+                qData = Query("select id from ruleset where hash=?", \
list([self.hash])).records +                if qData:
+                    # is already in database
+                    self.rulesetId = qData[0][0]
+                    return
+                with Transaction():
+                    self.rulesetId, self.name = self._newKey(minus)
+                    Query('INSERT INTO ruleset(id,name,hash,description) \
VALUES(?,?,?,?)', +                        list([self.rulesetId, english(self.name), \
self.hash, self.description]), +                        failSilent=True)
+                    cmd = 'INSERT INTO rule(ruleset, list, position, name, \
definition, ' \ +                            'points, doubles, limits, parameter) \
VALUES {}'.format( +                            ', '.join(['(?,?,?,?,?,?,?,?,?)'] * \
len(self.allRules))) +                    args = sum((list(self.ruleRecord(x)) for x \
in self.allRules), []) +                    Query(cmd, args)
+            except QueryException:
+                pass
+            else:
+                break
         # do not put this into the transaction, keep it as short as possible. \
                sqlite3/Qt
         # has problems if two processes are trying to do the same here (kajonggtest)
-        for rule in self.allRules:
-            self.saveRule(rule)
 
     @staticmethod
     def availableRulesets():
diff --git a/src/util.py b/src/util.py
index 14f39f6..8f17c81 100644
--- a/src/util.py
+++ b/src/util.py
@@ -227,7 +227,7 @@ def logWarning(msg, withGamePrefix=True):
 
 def logException(exception, withGamePrefix=True):
     """logs error message and re-raises exception"""
-    logMessage(exception, logging.ERROR, True, showStack=True, \
withGamePrefix=withGamePrefix) +    logError(exception, \
withGamePrefix=withGamePrefix)  if isinstance(exception, (str, unicode)):
         msg = exception.encode('utf-8', 'replace')
         exception = Exception(msg)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic