Pull connectins from the pool when doing queries in a thread
mysql-python (and all mysql drivers I can find) have a threadsafety
value of 1 (see PEP-249) which makes it unsafe to use the same
connection from more than one thread.
Trivia in particular used to do this extensively, which is what prompted
https://gitlab.com/rizon/mysql-python/commit/
c09cfd229176bd280bfb0384aaed7d07c42bbc0a,
however this fix is not correct because both mysql_query and
mysql_store_result both need to be called in the mutex lock, which this
doesn't do. However this fixes segfaults from causing libmysqlclient
going multithreaded, so it works well enough in production.
user: adam
passwd: moo
db: pypsd
-sock: /var/lib/mysql/mysql.sock
[ctcp]
nick: py-ctcp
user=config.get('database', 'user'),
passwd=config.get('database', 'passwd'),
db=config.get('database', 'db'),
- unix_socket=config.get('database', 'sock')
)
dbx.autocommit(True) # no need to have transactions
dbp = dbx.cursor()
import ConfigParser
import codecs
from istring import istring
-import MySQLdb as db
import logging
import logging.handlers
+import pool
config = ConfigParser.ConfigParser()
config.readfp(codecs.open("config.ini", "r"))
if anope_major not in [1, 2]:
raise Exception('Unknown anope major version %s' % anope_major)
-dbx = db.connect(
- host=config.get('database', 'host'),
- user=config.get('database', 'user'),
- passwd=config.get('database', 'passwd'),
- db=config.get('database', 'db'),
- unix_socket=config.get('database','sock')
-)
-dbx.ping(True)
-dbx.autocommit(True) #no need to have transactions
+dbpool = pool.DBPool(config)
+dbx = dbpool.get_connection()
logfile = config.get('logging', 'logfile')
loglevel = getattr(logging, config.get('logging', 'level').upper())
from datetime import datetime, timedelta
from xml.parsers.expat import ExpatError
+import core
from pseudoclient.cmd_manager import *
from utils import *
from internets_utils import *
def get_citystate_from_zipcode(self, zipcode):
"""Return [city,state] for the given U.S. zip code (if database has been imported)"""
try:
- self.dbp.execute("SELECT city, state FROM zipcode_citystate WHERE zipcode=%s", [int(zipcode)])
- city, state = self.dbp.fetchone()
- return city, state
+ con = core.dbpool.get_connection()
+ try:
+ cursor = con.cursor()
+ cursor.execute("SELECT city, state FROM zipcode_citystate WHERE zipcode=%s", [int(zipcode)])
+ city, state = cursor.fetchone()
+ return city, state
+ finally:
+ core.dbpool.put_connection(con)
except:
return None
self.logchan = config.get('control', 'channel')
self.log = logging.getLogger(__name__)
self.config = config
- self.dbp = dbx.cursor()
+ self.dbp = dbx.cursor() # do these have to be closed?
def start(self):
pass
--- /dev/null
+import threading
+import MySQLdb as db
+
+class DBPool(object):
+ _lock = threading.RLock()
+ _connections = []
+
+ def __init__(self, conf):
+ self.config = conf
+ self.add_connection()
+
+ def add_connection(self):
+ con = db.connect(
+ host=self.config.get('database', 'host'),
+ user=self.config.get('database', 'user'),
+ passwd=self.config.get('database', 'passwd'),
+ db=self.config.get('database', 'db'),
+ )
+ con.ping(True)
+ con.autocommit(True) #no need to have transactions
+
+ with self._lock:
+ self._connections.append(con)
+
+ def get_connection(self):
+ with self._lock:
+ if len(self._connections) == 0:
+ self.add_connection()
+ return self._connections.pop()
+
+ def put_connection(self, con):
+ with self._lock:
+ if con not in self._connections:
+ self._connections.append(con)
+
+
import threading
-import MySQLdb as db
+import core
class Subsystem(object):
#--------------------------------------------------------------#
self.reload()
def db_open(self):
- self.conn = db.connect(
- host=self.module.config.get('database', 'host'),
- user=self.module.config.get('database', 'user'),
- passwd=self.module.config.get('database', 'passwd'),
- db=self.module.config.get('database', 'db'),
- unix_socket=self.module.config.get('database','sock')
- )
- self.conn.ping(True)
- self.conn.autocommit(True)
+ self.conn = core.dbpool.get_connection()
self.cursor = self.conn.cursor()
def db_close(self):
self.cursor = None
if self.conn != None:
- self.conn.close()
+ core.dbpool.put_connection(self.conn)
self.conn = None
def reload(self):