# portage_db_mysql.db by oneofone{-a-t-}limitlessfx.com import MySQLdb,cPickle import portage_db_template ex = MySQLdb.escape_string class database(portage_db_template.database): #ought to do ref counting on the number of open connections. course that's worthless till portage calls database.close(). connections = {} cursor = None path_map = {} categories = {} defaultOptions = {'host':'localhost', 'port': 3306, 'user': 'portage', 'password': "", 'db': 'portage'} lastkey = lastval = None # internal caching to make get_values() work a little fast. global ex def __init__(self,path,category,dbkeys,uid,gid,config_path='/etc/portage/module_configs/'): try: portage_db_template.database.__init__(self, path,category,dbkeys,uid,gid,config_path) except: self.path = path self.category = category self.dbkeys = dbkeys self.uid = uid self.gid = gid self.config = {} self.module_init() def __del__(self): try: self.close() except: pass def module_init(self): options = database.defaultOptions.copy() if self.config: for x in self.config.keys(): options[x] = self.config[x] self.config = options; del options from re import sub path = sub('/{2,}', '/', self.path) self.constr = self.config['host'] + ':' + str(self.config['port']) + '/' + self.config['db'] if not database.connections.has_key(self.constr): try: con = [0, MySQLdb.connect(host=self.config['host'], port=self.config['port'], user=self.config['user'], passwd=self.config['password'], db=self.config['db']) ] database.connections.setdefault(self.constr, con) except Exception, e: raise Exception, "Error connecting to Database using self.config=(%s): exception=(%s)" % (str(self.config), str(e)) self.con = database.connections[self.constr][1] self.db = database.connections[self.constr][1].cursor() database.connections[self.constr][0] += 1 try: self.db.execute('set AUTOCOMMIT=1') if len(database.categories.keys()) == 0: self.db.execute('select name,c_id from `category_table`') for y, x in self.db.fetchall(): database.categories[y] = x except Exception, e: self.check_exception(e) raise Exception, "Database Error: failed pulling tables using self.config=(%s), exception=(%s)" % (str(self.config), str(e)) if not database.categories.has_key(self.category) : #create the category table try: self.db.execute('INSERT INTO `category_table` (`name`) VALUES("%s")' % ex(self.category)) database.categories.clear() self.db.execute('select name, c_id from `category_table`') for y, x in self.db.fetchall(): database.categories[y] = x except Exception, e: self.check_exception(e) raise Exception, "Database error: failed creation table for path('%s'), category('%s'), exception=(%s)" % (self.path, self.category, str(e)) self.cat_id = database.categories[self.category] if not database.path_map.has_key(self.path): try: if len( database.path_map.keys()) == 0: if self.db.execute('SELECT name, p_id FROM `path_table` ') > 0: for x,y in self.db.fetchall(): database.path_map[x] = y except Exception, e: self.check_exception(e) raise Exception, "database error: %s" % str(e) if not database.path_map.has_key(path): try: self.db.execute('INSERT INTO `path_table`(`name`) VALUES("%s")' % ex(path)) #flush the table, and load it anew database.path_map.clear() self.db.execute('SELECT name, p_id FROM `path_table`') for path,id in self.db.fetchall(): database.path_map[path] = id except Exception, e: self.check_exception(e) raise Exception, "Database error, failed loading path map: exception=%s" % str(e) self.p_id = database.path_map[path] def check_exception(self, e): if "Got error 127 from table handler" in str(e): if self.db.execute('check table `package_name`') > 1: print '`package_name` got corrupted some how, trying to fix' self.db.execute('repair table `package_name`') check = self.db.execute('check table `package_name`') status = self.db.fetchall() if ( check == 1 and status[0][3] == "OK"): raise Exception, "Database was corrupt be we were able to repair it, please rerun the emerge command" else: raise Exception, "Database is corrupt, exception=(%s)" % str(e) def has_key(self,key): self.check_key(key) try : #self.db.execute('REPAIR TABLE `package_name`') return self.db.execute("SELECT data FROM `package_name` WHERE `name` = '%s' AND `cat_id` = '%d' AND `path_id` = '%d'" % (ex(key), self.cat_id, self.p_id )) > 0 except Exception, e: self.check_exception(e) print "exception in has_key for Key (%s), Error (%s) " % (key, str(e)) return False def keys(self): ks = {} try: self.db.execute("SELECT name, data from `package_name` WHERE `cat_id` ='%d' AND `path_id` = '%d'" % (self.cat_id, self.p_id )) for x,y in self.db.fetchall(): ks[x] = cPickle.loads(y) return ks except Exception, e: self.check_exception(e) raise KeyError, "Keys are dead :( (%s)" % str(e) def get_values(self,key): self.check_key(key) if self.lastkey == key: return self.lastval try: if self.db.execute("SELECT data FROM `package_name` WHERE `name` = '%s' AND `cat_id` = '%d' AND `path_id` = '%d'" % (key, self.cat_id, self.p_id )) > 0: one = self.db.fetchone() if len(one) > 0 and one[0] != None: self.lastkey = key; self.lastval = cPickle.loads(one[0]) return self.lastval return None except Exception, e: self.check_exception(e) raise ValueError, "Value error (%s)" % str(e) return None def set_values(self,key,val): self.check_key(key) try: if self.lastkey == key: self.lastkey = self.lastval = None self.db.execute("""REPLACE INTO `package_name` (`name`,`cat_id`, `data`, `path_id`) VALUES ('%s','%d', '%s','%d') """ % (ex(key), self.cat_id, ex(cPickle.dumps(val)),self.p_id ) ) except Exception, e: self.check_exception(e) raise Exception, "Error inserting/updating the database (%s)." % str(e) def del_key(self,key): try: if self.lastkey == key: self.lastkey = self.lastval = None return (self.db.execute('DELETE FROM `package_name` WHERE `cat_id` = "%d" AND `name`= "%s" AND `path_id` = "%d"' % (self.cat_id, key, self.p_id)) > 0) except Exception, e: self.check_exception(e) print "Error deleting key=(%s), exception= (%s)" % (key,str(e)) return False def sync(self): pass def close(self): if database.connections.get(self.constr, [0])[0] == 0: return 0 # make sure that .close() doesn't get called twice try: #print 'in self.db.close(), instcount=%d' % database.connections[self.constr][0] database.connections[self.constr][0] -= 1 self.db.close() if database.connections[self.constr][0] == 0: #self.db.execute("analyze TABLE `category_table` , `package_name` , `path_table`") # optimize the db on close database.connections[self.constr][1].close() del database.connections[self.constr] return 1 except Exception, e: self.check_exception(e) print "Exception in self.db.close() == (%s), ignored." % str(e)