View previous topic :: View next topic |
Author |
Message |
OneOfOne Guru
Joined: 28 May 2003 Posts: 368
|
Posted: Thu May 20, 2004 4:08 am Post subject: mysql database module for portage! |
|
|
I know the database feature in portage is rather hidden and only few people know about.
you can specify modules that portage will use to store its internal cache, you can set them in /etc/portage/modules (make it if it doesn't exist).
this is simply a mysql version of it and it works fine 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
Code: |
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;
|
5. create /usr/lib/portage/pym/portage_db_mysql.py and put this in it :
Code: |
# 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)
|
6. Create /etc/portage/modules and add :
Code: | portdbapi.auxdbmodule="portage_db_mysql.database"
eclass_cache.dbmodule="portage_db_mysql.database"
|
7. emerge regen (you dont have to, it'll update the cache when you do emerge -s or something)
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-stuff/portage_db_mysql.py
the sql file : http://oneofone.limitlessfx.com/gentoo-stuff/init-portage-db.sql
edit:
fixed a type and gave direct links.
edit2: fixed a typo
edit: fixed the sql to make it stop corrupting and optimized the code a little.
peace
Last edited by OneOfOne on Tue May 25, 2004 8:20 am; edited 3 times in total |
|
Back to top |
|
|
lolli78 Apprentice
Joined: 14 Jan 2004 Posts: 162 Location: Europe
|
Posted: Thu May 20, 2004 8:51 pm Post subject: Re: mysql database module for portage! |
|
|
hi,
i just found a bug...
OneOfOne wrote: |
Code: | CREATE DATABASE `portage`;
CREATE DATABASE `portage`;
USE mysql;
INSERT INTO user (Host,User,Password) VALUES ('localhost','portage','');
FLUSH PRIVILEGES;
[...]
|
|
remove the first line of the sql-script and it works better.
Code: | CREATE DATABASE `portage`;
USE mysql;
INSERT 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(7) PRIMARY KEY AUTO_INCREMENT,
name char(255) NOT NULL UNIQUE
) TYPE=INNODB;
CREATE TABLE `category_table` (
c_id int(7) PRIMARY KEY AUTO_INCREMENT,
name char(255) NOT NULL UNIQUE
) TYPE=INNODB;
CREATE TABLE `package_name` (
name char(255) NOT NULL,
cat_id int(7) NOT NULL,
path_id int(7) 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)
) TYPE=INNODB;
|
great script, portage is now lightning-fast.
lorenz _________________ frag' doch deinadmin.de |
|
Back to top |
|
|
bicolao n00b
Joined: 05 Jan 2004 Posts: 50
|
Posted: Thu May 20, 2004 9:53 pm Post subject: |
|
|
Well, can i use berkeley db instead of mysql? I don't like to start mysql _________________ Bi Cờ Lao |
|
Back to top |
|
|
provicemo Apprentice
Joined: 12 Dec 2003 Posts: 201 Location: Detroit, MI
|
Posted: Fri May 21, 2004 6:44 pm Post subject: |
|
|
Quote: | emerge mysql and configure it (if you haven't already) |
how much of that is similar to this
...I just want a fast portage.... |
|
Back to top |
|
|
OneOfOne Guru
Joined: 28 May 2003 Posts: 368
|
Posted: Tue May 25, 2004 8:22 am Post subject: |
|
|
bicolao wrote: | Well, can i use berkeley db instead of mysql? I don't like to start mysql |
in theory yes, in reality i have no idea how.
@provicemo : nope, not related at all.
this will store the portage cache in mysql instead of normal files, so it'd be easier to do queries on it.
i just updated the code, basicly if it works fine you don't need the update.
if the table goes corrupt you need to drop the database then recreate it with the new sql file.
peace |
|
Back to top |
|
|
langthang Retired Dev
Joined: 27 Nov 2003 Posts: 620
|
Posted: Tue May 25, 2004 7:14 pm Post subject: |
|
|
`emerge -S something` still slow. Is it portage or it can be improved? BTW, thanks. |
|
Back to top |
|
|
timfreeman Tux's lil' helper
Joined: 19 May 2003 Posts: 142 Location: Chicago
|
Posted: Tue May 25, 2004 10:05 pm Post subject: |
|
|
This is great. I just installed it on two clean installs (vmware nodes), working very well, thankyou!
The -S description are in the database, I just looked. So -S is slow probably because the different fields aren't stored by portage as separate fields, just the one "data" column..
(maybe this should be moved to Documentation Tips forum?) _________________ ||| |
|
Back to top |
|
|
Fitzsimmons Guru
Joined: 01 Jan 2003 Posts: 415 Location: Waterloo, Ontario, Canada
|
Posted: Wed May 26, 2004 1:50 am Post subject: |
|
|
I have also managed to get this to work in a server/client setup. By making some quick changes to the mysql permissions (change which hosts the portage user is allowed to connect from), and a modification of the code:
defaultOptions = {'host':'localhost', 'port': 3306, 'user': 'portage', 'password': "", 'db': 'portage'}
to
defaultOptions = {'host':'[server_address]', 'port': 3306, 'user': 'portage', 'password': "", 'db': 'portage'}
Also note that by default the mysql server only listens on loopback for incoming connections and will drop any attempts at connection from outside sources unless you comment out
Code: |
bind-address = 127.0.0.1
|
from /etc/mysql/my.cnf
Remember to restart your server if you do this.
UPDATE: You also need to have a network mount to /usr/portage. I hadn't thought of adding this important point because I was in fact already distributing the tree this way and as a result the previous method Just Worked(tm). |
|
Back to top |
|
|
langthang Retired Dev
Joined: 27 Nov 2003 Posts: 620
|
Posted: Tue Jun 01, 2004 8:58 pm Post subject: |
|
|
equery (gentoolkit-0.2.0_pre8) does not work. Do we have a patch?
# equery list -i -o -p squirrelmail
Searching for package 'squirrelmail' in all categories among:
* installed packages
* Portage tree (/usr/portage)
* overlay tree (/usr/local/portage)
[-P-] [ ~] mail-client/squirrelmail-1.4.3-r1 (1.4.3-r1)
[-P-] [ ] mail-client/squirrelmail-1.4.3 (1)
[-P-] [ ] mail-client/squirrelmail-1.4.3_rc1 (1)
[-P-] [ ~] mail-client/squirrelmail-1.4.3_rc1-r1 (1.4.3_rc1-r1)
Exception exceptions.AttributeError: "'NoneType' object has no attribute 'close'" in <bound method Cursor.__del__ of <MySQLdb.cursors.Cursor instance at 0x40a94aac>> ignored _________________ Gentoo users' map |
|
Back to top |
|
|
CaribbeanKnight Apprentice
Joined: 27 Apr 2003 Posts: 240 Location: Earth -> Europe -> Belgium -> Diest
|
Posted: Wed Jun 02, 2004 2:52 am Post subject: |
|
|
just tried this setup and everything seems to be working fine
but i have a question: i have a setup of 4 pc's, where 1 pc has the portage db that i keep in sync and the other 3 pc's just mount this portage dir using nfs..
now should i convert the other 3 pc's to mysql portage too or do they automatically use it allready? _________________ ...we ain't shit...
Linux User #353893 |
|
Back to top |
|
|
Fitzsimmons Guru
Joined: 01 Jan 2003 Posts: 415 Location: Waterloo, Ontario, Canada
|
Posted: Wed Jun 02, 2004 3:05 pm Post subject: |
|
|
It requires a small hack in the code. Take a look at my previous post in which I posted directions on how to do this. |
|
Back to top |
|
|
CaribbeanKnight Apprentice
Joined: 27 Apr 2003 Posts: 240 Location: Earth -> Europe -> Belgium -> Diest
|
Posted: Wed Jun 02, 2004 9:01 pm Post subject: |
|
|
hmmm, could you maybe tell me how to give the portage user permission to connect from other hosts, as i don't know any sql...?
thanx in advance! _________________ ...we ain't shit...
Linux User #353893 |
|
Back to top |
|
|
Fitzsimmons Guru
Joined: 01 Jan 2003 Posts: 415 Location: Waterloo, Ontario, Canada
|
Posted: Wed Jun 02, 2004 10:56 pm Post subject: |
|
|
Sure.
Copy the following to a file:
Code: |
USE mysql;
UPDATE `user` SET `Host` = '%' WHERE `Host` = 'localhost' AND `User` = 'portage' LIMIT 1 ;
|
then run
Code: |
$mysql -u root -p < foo.sql
|
Or just run the mysql command without the < foo and copy/type the two lines in.
Please note, this command will allow the portage user to connect from any host without a password (the lack of a password is default of the script, not my code). This shouldn't be a problem on a LAN where you have no malicious users, but if you open your mysql server to the internet or use this in a corporate setting more security would be needed. |
|
Back to top |
|
|
CaribbeanKnight Apprentice
Joined: 27 Apr 2003 Posts: 240 Location: Earth -> Europe -> Belgium -> Diest
|
Posted: Wed Jun 02, 2004 11:16 pm Post subject: |
|
|
hmmm, when i try to run that command on my server, i get this error:
Code: |
mysql> UPDATE 'user' SET 'Host' = '%' WHERE 'Host' = 'localhost' AND 'User' = 'portage' LIMIT 1 ;
ERROR 1064: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near ''user' SET 'Host' = '%' WHERE 'Host' = 'localhost' AND 'User' =
mysql>
|
any ideas..? _________________ ...we ain't shit...
Linux User #353893 |
|
Back to top |
|
|
int2str Guru
Joined: 29 Sep 2003 Posts: 362
|
Posted: Thu Jun 03, 2004 2:03 am Post subject: |
|
|
Caribbean
Check your punctuation. It's ` around fields and ' around values ...
OneOfOne
I can add a "works for me" here, but honestly, it doesn't seem much faster (if any). At least on my machine.
Cheers
André _________________ Adpot an unanswered post today! |
|
Back to top |
|
|
Fitzsimmons Guru
Joined: 01 Jan 2003 Posts: 415 Location: Waterloo, Ontario, Canada
|
Posted: Thu Jun 03, 2004 2:05 am Post subject: |
|
|
Those are backticks (`), not singlequotes ('), around `user` and `Host`. |
|
Back to top |
|
|
CaribbeanKnight Apprentice
Joined: 27 Apr 2003 Posts: 240 Location: Earth -> Europe -> Belgium -> Diest
|
Posted: Thu Jun 03, 2004 2:38 am Post subject: |
|
|
thanks for the help so far, that sql statement worked now, stupid quotes
but it still isn't really right, when i try an emerge on the clients now, i get:
Code: |
StardusT sql # emerge -s parser
Traceback (most recent call last):
File "/usr/bin/emerge", line 14, in ?
import portage
File "/usr/lib/portage/pym/portage.py", line 6143, in ?
portdb=portdbapi(settings["PORTDIR"])
File "/usr/lib/portage/pym/portage.py", line 4426, in __init__
self.eclassdb = eclass_cache(self.mysettings)
File "/usr/lib/portage/pym/portage.py", line 4328, in __init__
self.dbmodule = self.settings.load_best_module("eclass_cache.dbmodule")
File "/usr/lib/portage/pym/portage.py", line 1307, in load_best_module
return load_mod(best_mod)
File "/usr/lib/portage/pym/portage.py", line 34, in load_mod
mod = __import__(modname)
File "/usr/lib/portage/pym/portage_db_mysql.py", line 2, in ?
import MySQLdb,cPickle
ImportError: No module named MySQLdb
StardusT sql #
|
does this mean i need to install mysql on my clients too or am i wrong? _________________ ...we ain't shit...
Linux User #353893 |
|
Back to top |
|
|
int2str Guru
Joined: 29 Sep 2003 Posts: 362
|
Posted: Thu Jun 03, 2004 2:49 am Post subject: |
|
|
Carebean
You forgot step 2:
Quote: | emerge mysql-python |
Rename /etc/portage/modules to something else and do step two. Then move the file back to /etc/portage/modules and voila.
Fitzsimmons
You didn't read my post, did ya?! :p _________________ Adpot an unanswered post today! |
|
Back to top |
|
|
CaribbeanKnight Apprentice
Joined: 27 Apr 2003 Posts: 240 Location: Earth -> Europe -> Belgium -> Diest
|
Posted: Thu Jun 03, 2004 2:52 am Post subject: |
|
|
int2str: yeah, ok, but mysql-python is dependent on mysql, and where is the whole client/server approach when i have to install mysql on every pc?? _________________ ...we ain't shit...
Linux User #353893 |
|
Back to top |
|
|
langthang Retired Dev
Joined: 27 Nov 2003 Posts: 620
|
Posted: Thu Jun 03, 2004 2:59 am Post subject: |
|
|
I wonder if you can `emerge --nodeps mysql-python`? _________________ Gentoo users' map |
|
Back to top |
|
|
arkane l33t
Joined: 30 Apr 2002 Posts: 918 Location: Phoenix, AZ
|
Posted: Thu Jun 03, 2004 2:30 pm Post subject: |
|
|
provicemo wrote: | Quote: | emerge mysql and configure it (if you haven't already) |
how much of that is similar to this
...I just want a fast portage.... |
Well, they both hold the common characteristic of using MySQL, I guess they have that commonality...
Other than that, they are different applications that do different things in different ways...
On a side note, I'm testing this out right now. I'm populating the cache currently. (emerge regen) Can't wait to see just how much quicker it is using a mysql back-end. |
|
Back to top |
|
|
Fitzsimmons Guru
Joined: 01 Jan 2003 Posts: 415 Location: Waterloo, Ontario, Canada
|
Posted: Thu Jun 03, 2004 2:36 pm Post subject: |
|
|
int2str wrote: | Carebean
Fitzsimmons
You didn't read my post, did ya?! :p |
Well, yeah, I did, after I pressed submit on mine. When I had pressed the reply button, it was before 9:03, before you had posted. When I posted my reply it was after 9:03 (at 9:05). |
|
Back to top |
|
|
arkane l33t
Joined: 30 Apr 2002 Posts: 918 Location: Phoenix, AZ
|
Posted: Thu Jun 03, 2004 3:13 pm Post subject: |
|
|
Man, this works nice.
I followed the instructions exactly, and talk about a significant difference. Just doing an "emerge -s perl" takes no time at all
I just did an "emerge -s x" just to be stupid, figuring it'd take forever...
30 seconds... that's for display and everything.
I personally think this should be included in the instructions as a possible alteration to the system on build. Or even an ebuild called "portage-mysql-backend" or something. |
|
Back to top |
|
|
arkane l33t
Joined: 30 Apr 2002 Posts: 918 Location: Phoenix, AZ
|
Posted: Thu Jun 03, 2004 3:14 pm Post subject: |
|
|
OneOfOne wrote: | bicolao wrote: | Well, can i use berkeley db instead of mysql? I don't like to start mysql |
in theory yes, in reality i have no idea how.
@provicemo : nope, not related at all.
this will store the portage cache in mysql instead of normal files, so it'd be easier to do queries on it. |
Doesn't portage use the berkeley db by default?
That's what I've always thought.... |
|
Back to top |
|
|
bicolao n00b
Joined: 05 Jan 2004 Posts: 50
|
Posted: Sat Jun 05, 2004 8:27 am Post subject: |
|
|
arkane wrote: | OneOfOne wrote: | bicolao wrote: | Well, can i use berkeley db instead of mysql? I don't like to start mysql |
in theory yes, in reality i have no idea how.
@provicemo : nope, not related at all.
this will store the portage cache in mysql instead of normal files, so it'd be easier to do queries on it. |
Doesn't portage use the berkeley db by default?
That's what I've always thought.... |
Yes, thanks it works. just replace portage_db_mysql by portage_db_anydbm. Haven't compared the performance between berkdb and mysql yet. But at least you don't need to start mysql _________________ Bi Cờ Lao |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|