diff options
Diffstat (limited to 'lib/prserv/db.py')
-rw-r--r-- | lib/prserv/db.py | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/prserv/db.py b/lib/prserv/db.py new file mode 100644 index 000000000..bbee9316b --- /dev/null +++ b/lib/prserv/db.py @@ -0,0 +1,100 @@ +import logging +import os.path +import errno +import sys +import warnings +import sqlite3 + +try: + import sqlite3 +except ImportError: + from pysqlite2 import dbapi2 as sqlite3 + +sqlversion = sqlite3.sqlite_version_info +if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3): + raise Exception("sqlite3 version 3.3.0 or later is required.") + +class NotFoundError(StandardError): + pass + +class PRTable(): + def __init__(self,cursor,table): + self.cursor = cursor + self.table = table + + #create the table + self._execute("CREATE TABLE IF NOT EXISTS %s \ + (version TEXT NOT NULL, \ + checksum TEXT NOT NULL, \ + value INTEGER, \ + PRIMARY KEY (version,checksum));" + % table) + + def _execute(self, *query): + """Execute a query, waiting to acquire a lock if necessary""" + count = 0 + while True: + try: + return self.cursor.execute(*query) + except sqlite3.OperationalError as exc: + if 'database is locked' in str(exc) and count < 500: + count = count + 1 + continue + raise + except sqlite3.IntegrityError as exc: + print "Integrity error %s" % str(exc) + break + + def getValue(self, version, checksum): + data=self._execute("SELECT value FROM %s WHERE version=? AND checksum=?;" % self.table, + (version,checksum)) + row=data.fetchone() + if row != None: + return row[0] + else: + #no value found, try to insert + self._execute("INSERT INTO %s VALUES (?, ?, (select ifnull(max(value)+1,0) from %s where version=?));" + % (self.table,self.table), + (version,checksum,version)) + data=self._execute("SELECT value FROM %s WHERE version=? AND checksum=?;" % self.table, + (version,checksum)) + row=data.fetchone() + if row != None: + return row[0] + else: + raise NotFoundError + +class PRData(object): + """Object representing the PR database""" + def __init__(self, filename): + self.filename=os.path.abspath(filename) + #build directory hierarchy + try: + os.makedirs(os.path.dirname(self.filename)) + except OSError as e: + if e.errno != errno.EEXIST: + raise e + self.connection=sqlite3.connect(self.filename, timeout=5, + isolation_level=None) + self.cursor=self.connection.cursor() + self._tables={} + + def __del__(self): + print "PRData: closing DB %s" % self.filename + self.connection.close() + + def __getitem__(self,tblname): + if not isinstance(tblname, basestring): + raise TypeError("tblname argument must be a string, not '%s'" % + type(tblname)) + if tblname in self._tables: + return self._tables[tblname] + else: + tableobj = self._tables[tblname] = PRTable(self.cursor, tblname) + return tableobj + + def __delitem__(self, tblname): + if tblname in self._tables: + del self._tables[tblname] + logging.info("drop table %s" % (tblname)) + self.cursor.execute("DROP TABLE IF EXISTS %s;" % tblname) |