summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar mkaay <mkaay@mkaay.de> 2011-02-04 19:24:31 +0100
committerGravatar mkaay <mkaay@mkaay.de> 2011-02-04 19:24:31 +0100
commitb14e7786f249d5ec87c715fd1e3da1d496e5792b (patch)
tree5f3dc58fd03968bb8d9a49e290dbb9b219aa191f
parentbetter xmlrpc debug, database changes (diff)
downloadpyload-b14e7786f249d5ec87c715fd1e3da1d496e5792b.tar.xz
runnig gag: forget adding files to your commit
-rw-r--r--module/DatabaseBackend.py271
1 files changed, 271 insertions, 0 deletions
diff --git a/module/DatabaseBackend.py b/module/DatabaseBackend.py
new file mode 100644
index 000000000..c93479565
--- /dev/null
+++ b/module/DatabaseBackend.py
@@ -0,0 +1,271 @@
+#!/usr/bin/env python
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: RaNaN
+ @author: mkaay
+"""
+
+from threading import Lock
+from threading import Thread
+from threading import Event
+from os import remove
+from os.path import exists
+from shutil import move
+
+from Queue import Queue
+
+from traceback import print_exc
+
+try:
+ from pysqlite2 import dbapi2 as sqlite3
+except:
+ import sqlite3
+
+DB_VERSION = 4
+
+class style():
+ db = None
+
+ @classmethod
+ def setDB(cls, db):
+ cls.db = db
+
+ @classmethod
+ def inner(cls, f):
+ @staticmethod
+ def x(*args, **kwargs):
+ if cls.db:
+ return f(cls.db, *args[1:], **kwargs)
+ return x
+
+ @classmethod
+ def queue(cls, f):
+ @staticmethod
+ def x(*args, **kwargs):
+ if cls.db:
+ return cls.db.queue(f, *args, **kwargs)
+ return x
+
+ @classmethod
+ def async(cls, f):
+ @staticmethod
+ def x(*args, **kwargs):
+ if cls.db:
+ return cls.db.async(f, *args, **kwargs)
+ return x
+
+class DatabaseJob():
+ def __init__(self, f, *args, **kwargs):
+ self.done = Event()
+
+ self.f = f
+ self.args = args
+ self.kwargs = kwargs
+
+ self.result = None
+ self.exception = False
+
+ def processJob(self):
+ try:
+ self.result = self.f(*self.args, **self.kwargs)
+ except Exception, e:
+ print "Database Error @", self.f.__name__, self.args[1:], self.kwargs, e
+ print_exc()
+ self.exception = e
+ self.done.set()
+
+ def wait(self):
+ self.done.wait()
+
+class DatabaseBackend(Thread):
+ subs = []
+ def __init__(self, core):
+ Thread.__init__(self)
+ self.setDaemon(True)
+ self.core = core
+
+ self.transactionLock = Lock()
+ self.jobs = Queue()
+
+ self.setuplock = Event()
+
+ style.setDB(self)
+
+ def setup(self):
+ self.start()
+ self.setuplock.wait()
+
+ def run(self):
+ """main loop, which executes commands"""
+ convert = self._checkVersion() #returns None or current version
+
+ self.conn = sqlite3.connect("files.db")
+ self.c = self.conn.cursor() #compatibility
+
+ if convert is not None:
+ self._convertDB(convert)
+
+ self._createTables()
+ self.conn.commit()
+
+ self.setuplock.set()
+
+ while True:
+ j = self.jobs.get()
+ self.transactionLock.acquire()
+ if j == "quit":
+ break
+ j.processJob()
+ if j.exception:
+ self.conn.rollback()
+ else:
+ self.conn.commit()
+ self.transactionLock.release()
+
+ def shutdown(self):
+ self.syncSave()
+ self.jobs.put(("quit"))
+
+ def _checkVersion(self):
+ """ check db version and delete it if needed"""
+ if not exists("files.version"):
+ f = open("files.version", "wb")
+ f.write(str(DB_VERSION))
+ f.close()
+ return
+
+ f = open("files.version", "rb")
+ v = int(f.read().strip())
+ f.close()
+ if v < DB_VERSION:
+ if v < 2:
+ self.manager.core.log.warning(_("Filedatabase was deleted due to incompatible version."))
+ remove("files.version")
+ move("files.db", "files.backup.db")
+ f = open("files.version", "wb")
+ f.write(str(DB_VERSION))
+ f.close()
+ return v
+
+ def _convertDB(self, v):
+ try:
+ getattr(self, "_convertV%i" % v)()
+ except:
+ self.manager.core.log.error(_("Filedatabase could NOT be converted."))
+
+ #--convert scripts start
+
+ def _convertV2(self):
+ self.c.execute('CREATE TABLE IF NOT EXISTS "storage" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "identifier" TEXT NOT NULL, "key" TEXT NOT NULL, "value" TEXT DEFAULT "")')
+ self.manager.core.log.info(_("Database was converted from v2 to v3."))
+ self._convertV3(self)
+
+ def _convertV3(self):
+ self.c.execute('CREATE TABLE IF NOT EXISTS "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" TEXT NOT NULL, "email" TEXT DEFAULT "" NOT NULL, "password" TEXT NOT NULL, "role" INTEGER DEFAULT 0 NOT NULL, "permission" INTEGER DEFAULT 0 NOT NULL, "template" TEXT DEFAULT "default" NOT NULL)')
+ self.manager.core.log.info(_("Database was converted from v3 to v2."))
+
+ #--convert scripts end
+
+ def _createTables(self):
+ """create tables for database"""
+
+ self.c.execute('CREATE TABLE IF NOT EXISTS "packages" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" TEXT NOT NULL, "folder" TEXT, "password" TEXT DEFAULT "", "site" TEXT DEFAULT "", "queue" INTEGER DEFAULT 0 NOT NULL, "packageorder" INTEGER DEFAULT 0 NOT NULL, "priority" INTEGER DEFAULT 0 NOT NULL)')
+ self.c.execute('CREATE TABLE IF NOT EXISTS "links" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "url" TEXT NOT NULL, "name" TEXT, "size" INTEGER DEFAULT 0 NOT NULL, "status" INTEGER DEFAULT 3 NOT NULL, "plugin" TEXT DEFAULT "BasePlugin" NOT NULL, "error" TEXT DEFAULT "", "linkorder" INTEGER DEFAULT 0 NOT NULL, "package" INTEGER DEFAULT 0 NOT NULL, FOREIGN KEY(package) REFERENCES packages(id))')
+ self.c.execute('CREATE INDEX IF NOT EXISTS "pIdIndex" ON links(package)')
+ self.c.execute('CREATE TABLE IF NOT EXISTS "storage" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "identifier" TEXT NOT NULL, "key" TEXT NOT NULL, "value" TEXT DEFAULT "")')
+ self.c.execute('CREATE TABLE IF NOT EXISTS "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" TEXT NOT NULL, "email" TEXT DEFAULT "" NOT NULL, "password" TEXT NOT NULL, "role" INTEGER DEFAULT 0 NOT NULL, "permission" INTEGER DEFAULT 0 NOT NULL, "template" TEXT DEFAULT "default" NOT NULL)')
+ self.c.execute('VACUUM')
+
+ def createCursor(self):
+ return self.conn.cursor()
+
+ @style.async
+ def commit(self):
+ self.conn.commit()
+
+ @style.async
+ def rollback(self):
+ self.conn.rollback()
+
+ def async(self, f, *args, **kwargs):
+ args = (self, ) + args
+ job = DatabaseJob(f, *args, **kwargs)
+ self.jobs.put(job)
+
+ def queue(self, f, *args, **kwargs):
+ args = (self, ) + args
+ job = DatabaseJob(f, *args, **kwargs)
+ self.jobs.put(job)
+ job.wait()
+ return job.result
+
+ @classmethod
+ def registerSub(cls, klass):
+ cls.subs.append(klass)
+
+ @classmethod
+ def unregisterSub(cls, klass):
+ cls.subs.remove(klass)
+
+ def __getattr__(self, attr):
+ for sub in DatabaseBackend.subs:
+ if hasattr(sub, attr):
+ return getattr(sub, attr)
+
+if __name__ == "__main__":
+ db = DatabaseBackend()
+ db.setup()
+
+ class Test():
+ @style.queue
+ def insert(db):
+ c = db.createCursor()
+ for i in range(1000):
+ c.execute("INSERT INTO storage (identifier, key, value) VALUES (?, ?, ?)", ("foo", i, "bar"))
+ @style.async
+ def insert2(db):
+ c = db.createCursor()
+ for i in range(1000*1000):
+ c.execute("INSERT INTO storage (identifier, key, value) VALUES (?, ?, ?)", ("foo", i, "bar"))
+
+ @style.queue
+ def select(db):
+ c = db.createCursor()
+ for i in range(10):
+ res = c.execute("SELECT value FROM storage WHERE identifier=? AND key=?", ("foo", i))
+ print res.fetchone()
+
+ @style.queue
+ def error(db):
+ c = db.createCursor()
+ print "a"
+ c.execute("SELECT myerror FROM storage WHERE identifier=? AND key=?", ("foo", i))
+ print "e"
+
+ db.registerSub(Test)
+ from time import time
+ start = time()
+ for i in range(100):
+ db.insert()
+ end = time()
+ print end-start
+
+ start = time()
+ db.insert2()
+ end = time()
+ print end-start
+
+ db.error()
+