This was done by OneofOne.
http://forums.gentoo.org/viewtopic.php? ... sc&start=0
Here's a copy just to make sure it's documented here.
Instructions:
1. emerge mysql and configure it (if you haven't already)
2. emerge mysql-python
3. /etc/init.d/mysql start
4. put this code in a file and do mysql -u root -p < file.sql
Here's the SQL code to use (file.sql):
Code: Select all
CREATE DATABASE `portage`;
USE mysql;
REPLACE INTO user (Host,User,Password) VALUES ('localhost','portage','');
FLUSH PRIVILEGES;
GRANT SELECT,UPDATE,DELETE,INSERT,CREATE,LOCK TABLES ON portage.* TO portage@localhost;
FLUSH PRIVILEGES;
USE portage;
CREATE TABLE `path_table` (
p_id int PRIMARY KEY AUTO_INCREMENT,
name char(255) NOT NULL UNIQUE
);
CREATE TABLE `category_table` (
c_id int(7) PRIMARY KEY AUTO_INCREMENT,
name char(255) NOT NULL UNIQUE
) ;
CREATE TABLE `package_name` (
name char(255) NOT NULL,
cat_id int NOT NULL,
path_id int NOT NULL,
data TEXT,
FOREIGN KEY (cat_id) REFERENCES category_table (c_id) ON DELETE CASCADE,
FOREIGN KEY (path_id) REFERENCES path_table (p_id) ON DELETE CASCADE,
#INDEX p_index (name,cat_id,path_id),
primary key (name, cat_id, path_id)
) MAX_ROWS=99999999;
Code: Select all
# 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)
Code: Select all
portdbapi.auxdbmodule="portage_db_mysql.database"
eclass_cache.dbmodule="portage_db_mysql.database"
8. enjoy!
btw portage won't work if unless mysql is started (of course you can always delete /etc/portage/modules and it'll use the default flat file db system).
This is provided with no warrant, if the computer blows up DON'T BLAME ME!
Credits to everyone on #gentoo-portage (specially carpaski and ferringb) for helping me optimize it and to joecool and redeeman (#love-sources) for testing.
the module : http://oneofone.limitlessfx.com/gentoo- ... b_mysql.py
the sql file : http://oneofone.limitlessfx.com/gentoo- ... age-db.sql





