Commit 3cfb601a authored by Vincent Pelletier's avatar Vincent Pelletier

Implement a method to reconnect automaticaly under some conditions.

Use the new method everywhere instead of directly calling database's query method.
Add a "ping" query at request begining to offer transactionnal use a reconnection opportunity.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@13704 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent e5b8c0ce
...@@ -270,9 +270,7 @@ class DB(TM): ...@@ -270,9 +270,7 @@ class DB(TM):
_care=('TABLE', 'VIEW')): _care=('TABLE', 'VIEW')):
r=[] r=[]
a=r.append a=r.append
db = self._getConnection() result = self._query("SHOW TABLES")
db.query("SHOW TABLES")
result = db.store_result()
row = result.fetch_row(1) row = result.fetch_row(1)
while row: while row:
a({'TABLE_NAME': row[0][0], 'TABLE_TYPE': 'TABLE'}) a({'TABLE_NAME': row[0][0], 'TABLE_TYPE': 'TABLE'})
...@@ -282,9 +280,7 @@ class DB(TM): ...@@ -282,9 +280,7 @@ class DB(TM):
def columns(self, table_name): def columns(self, table_name):
from string import join from string import join
try: try:
db = self._getConnection() c = self._query('SHOW COLUMNS FROM %s' % table_name)
db.query('SHOW COLUMNS FROM %s' % table_name)
c = db.store_result()
except: except:
return () return ()
r=[] r=[]
...@@ -324,35 +320,50 @@ class DB(TM): ...@@ -324,35 +320,50 @@ class DB(TM):
r.append(info) r.append(info)
return r return r
def _query(self, query, force_reconnect=False):
"""
Send a to MySQL server.
It reconnects automaticaly if needed and the following conditions are
met:
- It has not just tried to reconnect (ie, this function will not
attemp to connect twice per call).
- This conection is not transactionnal and has set not MySQL locks,
because they are bound to the connection. This check can be
overridden by passing force_reconnect with True value.
"""
db = self._getConnection()
try:
db.query(query)
except OperationalError, m:
if ((not force_reconnect) and \
(self._mysql_lock or self._transactions)) or \
m[0] not in hosed_connection:
raise
# Hm. maybe the db is hosed. Let's restart it.
self._forceReconnection()
db.query(query)
return db.store_result()
def query(self,query_string, max_rows=1000): def query(self,query_string, max_rows=1000):
self._use_TM and self._register() self._use_TM and self._register()
desc=None desc=None
result=() result=()
db = self._getConnection() for qs in filter(None, map(strip,split(query_string, '\0'))):
try: qtype = upper(split(qs, None, 1)[0])
if 1: if qtype == "SELECT" and max_rows:
for qs in filter(None, map(strip,split(query_string, '\0'))): qs = "%s LIMIT %d" % (qs,max_rows)
qtype = upper(split(qs, None, 1)[0]) r=0
if qtype == "SELECT" and max_rows: c = self._query(qs)
qs = "%s LIMIT %d" % (qs,max_rows) if desc is not None:
r=0 if c and (c.describe() != desc):
db.query(qs) raise 'Query Error', (
c=db.store_result() 'Multiple select schema are not allowed'
if desc is not None: )
if c and (c.describe() != desc): if c:
raise 'Query Error', ( desc=c.describe()
'Multiple select schema are not allowed' result=c.fetch_row(max_rows)
) else:
if c: desc=None
desc=c.describe()
result=c.fetch_row(max_rows)
else:
desc=None
except OperationalError, m:
if m[0] not in hosed_connection: raise
# Hm. maybe the db is hosed. Let's restart it.
self._forceReconnection()
return self.query(query_string, max_rows)
if desc is None: return (),() if desc is None: return (),()
...@@ -373,13 +384,12 @@ class DB(TM): ...@@ -373,13 +384,12 @@ class DB(TM):
def _begin(self, *ignored): def _begin(self, *ignored):
try: try:
db = self._getConnection() # Ping the database to reconnect if connection was closed.
self._query("SELECT 1", force_reconnect=True)
if self._transactions: if self._transactions:
db.query("BEGIN") self._query("BEGIN")
db.store_result()
if self._mysql_lock: if self._mysql_lock:
db.query("SELECT GET_LOCK('%s',0)" % self._mysql_lock) self._query("SELECT GET_LOCK('%s',0)" % self._mysql_lock)
db.store_result()
except: except:
LOG('ZMySQLDA', ERROR, "exception during _begin", LOG('ZMySQLDA', ERROR, "exception during _begin",
error=sys.exc_info()) error=sys.exc_info())
...@@ -390,25 +400,19 @@ class DB(TM): ...@@ -390,25 +400,19 @@ class DB(TM):
if self._getFinishedOrAborted(): if self._getFinishedOrAborted():
return return
self._setFinishedOrAborted(True) self._setFinishedOrAborted(True)
db = self._getConnection()
if self._mysql_lock: if self._mysql_lock:
db.query("SELECT RELEASE_LOCK('%s')" % self._mysql_lock) self._query("SELECT RELEASE_LOCK('%s')" % self._mysql_lock)
db.store_result()
if self._transactions: if self._transactions:
db.query("COMMIT") self._query("COMMIT")
db.store_result()
def _abort(self, *ignored): def _abort(self, *ignored):
if self._getFinishedOrAborted(): if self._getFinishedOrAborted():
return return
self._setFinishedOrAborted(True) self._setFinishedOrAborted(True)
db = self._getConnection()
if self._mysql_lock: if self._mysql_lock:
db.query("SELECT RELEASE_LOCK('%s')" % self._mysql_lock) self._query("SELECT RELEASE_LOCK('%s')" % self._mysql_lock)
db.store_result()
if self._transactions: if self._transactions:
db.query("ROLLBACK") self._query("ROLLBACK")
db.store_result()
else: else:
LOG('ZMySQLDA', ERROR, "aborting when non-transactional") LOG('ZMySQLDA', ERROR, "aborting when non-transactional")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment