Merge lp:~openerp-dev/openobject-server/6.0-dbcreatecache into lp:openobject-server/6.0

Proposed by Antony Lesuisse (OpenERP)
Status: Needs review
Proposed branch: lp:~openerp-dev/openobject-server/6.0-dbcreatecache
Merge into: lp:openobject-server/6.0
Diff against target: 303 lines (+126/-75)
2 files modified
bin/service/web_services.py (+113/-67)
bin/tools/misc.py (+13/-8)
To merge this branch: bzr merge lp:~openerp-dev/openobject-server/6.0-dbcreatecache
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+63185@code.launchpad.net

Description of the change

It's freaking fast !!!
Actually, this should be ported into 6.1 and should stay as a patch for the 6.0 serie.

To post a comment you must log in.
3442. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache reload pool for cached db too (thanks dsh)

3443. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache typo

3444. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache remove print

Revision history for this message
Antony Lesuisse (OpenERP) (al-openerp) wrote :

Bug for password

3445. By Antony Lesuisse (OpenERP)

createdbcache change admin password

3446. By Antony Lesuisse (OpenERP)

createdbcache change admin password

3447. By Antony Lesuisse (OpenERP)

createdbcache wait pg_restore

Unmerged revisions

3447. By Antony Lesuisse (OpenERP)

createdbcache wait pg_restore

3446. By Antony Lesuisse (OpenERP)

createdbcache change admin password

3445. By Antony Lesuisse (OpenERP)

createdbcache change admin password

3444. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache remove print

3443. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache typo

3442. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache reload pool for cached db too (thanks dsh)

3441. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache fix databased created using cache

3440. By Antony Lesuisse (OpenERP)

createdbcache DBInitializeCache it's freaking fast...

3439. By Antony Lesuisse (OpenERP)

createdbcache more cleanup DBInitialize, space and folding cleanups

3438. By Antony Lesuisse (OpenERP)

createdbcache cleanup DBInitialize

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/service/web_services.py'
2--- bin/service/web_services.py 2011-01-15 17:04:10 +0000
3+++ bin/service/web_services.py 2011-06-10 15:19:25 +0000
4@@ -37,8 +37,104 @@
5 import tools
6 import locale
7 import logging
8+import traceback
9+import zlib
10 from cStringIO import StringIO
11
12+DBInitializerCache = {}
13+
14+class DBInitializer(object):
15+ def __init__(self, service, action_id, db_name, db_demo, db_lang, db_user_password='admin'):
16+ self.service = service
17+ self.action_id = action_id
18+ self.action = self.service.actions[action_id]
19+ self.db_name = db_name
20+ self.db_lang = db_lang
21+ self.db_demo = db_demo
22+ self.db_user_password = db_user_password
23+ self.registry = None
24+
25+ def __call__(self):
26+ self.run()
27+
28+ def with_cr(self,f):
29+ cr = None
30+ try:
31+ cr = sql_db.db_connect(self.db_name).cursor()
32+ f(cr)
33+ finally:
34+ if cr:
35+ cr.close()
36+
37+ def run(self):
38+ try:
39+ self.action['progress'] = 0
40+ key = (self.db_lang, self.db_demo)
41+ if key not in DBInitializerCache:
42+ self.run_new(key)
43+ else:
44+ self.run_cached(key)
45+ except Exception, e:
46+ e_str = StringIO()
47+ traceback.print_exc(file=e_str)
48+ traceback_str = e_str.getvalue()
49+ e_str.close()
50+ netsvc.Logger().notifyChannel('web-services', netsvc.LOG_ERROR, 'CREATE DATABASE\n%s' % (traceback_str))
51+ self.action['clean'] = False
52+ self.action['exception'] = e
53+ self.action['traceback'] = traceback_str
54+
55+ def run_new(self,key):
56+ self.service._create_empty_database(self.db_name)
57+ self.with_cr(self.init_base)
58+ self.with_cr(self.init_lang)
59+ try:
60+ s = zlib.compress(self.service.exp_dump(self.db_name), 9)
61+ DBInitializerCache[key] = s
62+ netsvc.Logger().notifyChannel('web-services', netsvc.LOG_DEBUG, 'CREATE DATABASE cached %r size %d' % (key, len(s)))
63+ except Exception,e:
64+ pass
65+ self.with_cr(self.init_user)
66+
67+ def run_cached(self,key):
68+ s = DBInitializerCache[key]
69+ self.service.exp_restore(self.db_name, zlib.decompress(s))
70+ self.registry = pooler.restart_pool(self.db_name, self.db_demo, None)[1]
71+ self.with_cr(self.init_user)
72+ self.with_cr(self.init_cached)
73+
74+ def init_base(self,cr):
75+ tools.init_db(cr)
76+ cr.commit()
77+ tools.config['lang'] = self.db_lang
78+ self.registry = pooler.restart_pool(self.db_name, self.db_demo, self.action, update_module=True)[1]
79+
80+ def init_lang(self,cr):
81+ if self.db_lang:
82+ modobj = self.registry.get('ir.module.module')
83+ mids = modobj.search(cr, 1, [('state', '=', 'installed')])
84+ modobj.update_translations(cr, 1, mids, self.db_lang)
85+ cr.commit()
86+
87+ def init_user(self,cr):
88+ cr.execute('UPDATE res_users SET password=%s, context_lang=%s, active=True WHERE login=%s', ( self.db_user_password, self.db_lang, 'admin'))
89+ cr.execute('SELECT login, password, name FROM res_users ORDER BY login')
90+ self.action['users'] = cr.dictfetchall()
91+ self.action['clean'] = True
92+ cr.commit()
93+
94+ def init_cached(self,cr):
95+ cr.execute('DELETE from ir_config_parameter')
96+ self.registry.get('ir.config_parameter').init(cr)
97+ cr.execute('UPDATE res_users SET password=%s WHERE id=1',(self.db_user_password,))
98+ for i in self.registry.obj_list():
99+ table = self.registry.get(i)._table
100+ cr.execute("SELECT c.relname FROM pg_class c, pg_attribute a WHERE c.oid=a.attrelid AND c.relname=%s AND a.attname=%s", (table, 'create_date'))
101+ if len(cr.fetchall()) > 0:
102+ cr.execute('UPDATE %s SET create_date = NOW() WHERE create_date IS NOT NULL'%table)
103+ cr.execute('UPDATE %s SET write_date = NOW() WHERE write_date IS NOT NULL'%table)
104+ cr.commit()
105+
106 class db(netsvc.ExportService):
107 def __init__(self, name="db"):
108 netsvc.ExportService.__init__(self, name)
109@@ -67,6 +163,7 @@
110
111 def new_dispatch(self,method,auth,params):
112 pass
113+
114 def _create_empty_database(self, name):
115 db = sql_db.db_connect('template1')
116 cr = db.cursor()
117@@ -84,55 +181,14 @@
118
119 self.actions[id] = {'clean': False}
120
121- self._create_empty_database(db_name)
122-
123- class DBInitialize(object):
124- def __call__(self, serv, id, db_name, demo, lang, user_password='admin'):
125- cr = None
126- try:
127- serv.actions[id]['progress'] = 0
128- cr = sql_db.db_connect(db_name).cursor()
129- tools.init_db(cr)
130- tools.config['lang'] = lang
131- cr.commit()
132- cr.close()
133- cr = None
134- pool = pooler.restart_pool(db_name, demo, serv.actions[id],
135- update_module=True)[1]
136-
137- cr = sql_db.db_connect(db_name).cursor()
138-
139- if lang:
140- modobj = pool.get('ir.module.module')
141- mids = modobj.search(cr, 1, [('state', '=', 'installed')])
142- modobj.update_translations(cr, 1, mids, lang)
143-
144- cr.execute('UPDATE res_users SET password=%s, context_lang=%s, active=True WHERE login=%s', (
145- user_password, lang, 'admin'))
146- cr.execute('SELECT login, password, name ' \
147- ' FROM res_users ' \
148- ' ORDER BY login')
149- serv.actions[id]['users'] = cr.dictfetchall()
150- serv.actions[id]['clean'] = True
151- cr.commit()
152- cr.close()
153- except Exception, e:
154- serv.actions[id]['clean'] = False
155- serv.actions[id]['exception'] = e
156- import traceback
157- e_str = StringIO()
158- traceback.print_exc(file=e_str)
159- traceback_str = e_str.getvalue()
160- e_str.close()
161- netsvc.Logger().notifyChannel('web-services', netsvc.LOG_ERROR, 'CREATE DATABASE\n%s' % (traceback_str))
162- serv.actions[id]['traceback'] = traceback_str
163- if cr:
164- cr.close()
165+ if self.exp_db_exist(db_name):
166+ logger.notifyChannel("web-services", netsvc.LOG_WARNING, 'CREATE DATABASE: %s already exists' % (db_name,))
167+ raise Exception, "Database already exists"
168+
169 logger = netsvc.Logger()
170 logger.notifyChannel("web-services", netsvc.LOG_INFO, 'CREATE DATABASE: %s' % (db_name.lower()))
171- dbi = DBInitialize()
172- create_thread = threading.Thread(target=dbi,
173- args=(self, id, db_name, demo, lang, user_password))
174+ dbi = DBInitializer(self, id, db_name, demo, lang, user_password)
175+ create_thread = threading.Thread(target=dbi)
176 create_thread.start()
177 self.actions[id]['thread'] = create_thread
178 return id
179@@ -217,8 +273,7 @@
180 self._set_pg_psw_env_var()
181
182 if self.exp_db_exist(db_name):
183- logger.notifyChannel("web-services", netsvc.LOG_WARNING,
184- 'RESTORE DB: %s already exists' % (db_name,))
185+ logger.notifyChannel("web-services", netsvc.LOG_WARNING, 'RESTORE DB: %s already exists' % (db_name,))
186 raise Exception, "Database already exists"
187
188 self._create_empty_database(db_name)
189@@ -240,11 +295,13 @@
190 args2=list(args2)
191 args2.append(' ' + tmpfile)
192 args2=tuple(args2)
193- stdin, stdout = tools.exec_pg_command_pipe(*args2)
194+ p = tools.exec_pg_command_pipe_subprocess(*args2)
195 if not os.name == "nt":
196- stdin.write(base64.decodestring(data))
197- stdin.close()
198- res = stdout.close()
199+ p.stdin.write(base64.decodestring(data))
200+ p.stdin.close()
201+ p.stdout.close()
202+ res = p.wait()
203+ print "WAIT ",res
204 if res:
205 raise Exception, "Couldn't restore database"
206 logger.notifyChannel("web-services", netsvc.LOG_INFO,
207@@ -346,6 +403,7 @@
208 l.notifyChannel('web-services', netsvc.LOG_ERROR, tb_s)
209 raise
210 return True
211+
212 db()
213
214 class _ObjectService(netsvc.ExportService):
215@@ -397,7 +455,6 @@
216 fn = getattr(self, 'exp_'+method)
217 return fn(*params)
218
219-
220 def new_dispatch(self,method,auth,params):
221 pass
222
223@@ -423,16 +480,7 @@
224 @param extended: if True then return version info
225 @return string if extended is False else tuple
226 """
227-
228- info = _('''
229-
230-OpenERP is an ERP+CRM program for small and medium businesses.
231-
232-The whole source code is distributed under the terms of the
233-GNU Public Licence.
234-
235-(c) 2003-TODAY, Fabien Pinckaers - Tiny sprl''')
236-
237+ info = 'OpenERP'
238 if extended:
239 return info, release.version
240 return info
241@@ -452,7 +500,6 @@
242 except tm.RemoteContractException, e:
243 self.abortResponse(1, 'Migration Error', 'warning', str(e))
244
245-
246 def exp_get_migration_scripts(self, contract_id, contract_password):
247 l = netsvc.Logger()
248 import tools.maintenance as tm
249@@ -665,6 +712,7 @@
250 raise Exception, 'AccessDenied'
251 else:
252 raise Exception, 'WizardNotFound'
253+
254 wizard()
255
256 #
257@@ -781,6 +829,4 @@
258
259 report_spool()
260
261-
262 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
263-
264
265=== modified file 'bin/tools/misc.py'
266--- bin/tools/misc.py 2011-01-20 12:40:20 +0000
267+++ bin/tools/misc.py 2011-06-10 15:19:25 +0000
268@@ -158,15 +158,19 @@
269
270 return subprocess.call(args2)
271
272+def exec_pg_command_pipe_subprocess(name, *args):
273+ prog = find_pg_tool(name)
274+ if not prog:
275+ raise Exception('Couldn\'t find %s' % name)
276+ # on win32, passing close_fds=True is not compatible
277+ # with redirecting std[in/err/out]
278+ pop = subprocess.Popen((prog,) + args, bufsize= -1,
279+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
280+ close_fds=(os.name=="posix"))
281+ return pop
282+
283 def exec_pg_command_pipe(name, *args):
284- prog = find_pg_tool(name)
285- if not prog:
286- raise Exception('Couldn\'t find %s' % name)
287- # on win32, passing close_fds=True is not compatible
288- # with redirecting std[in/err/out]
289- pop = subprocess.Popen((prog,) + args, bufsize= -1,
290- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
291- close_fds=(os.name=="posix"))
292+ pop = exec_pg_command_pipe_subprocess(name, *args)
293 return (pop.stdin, pop.stdout)
294
295 def exec_command_pipe(name, *args):
296@@ -799,6 +803,7 @@
297 self.fun_default_values = dict(zip(self.fun_arg_names[-len(argspec[3]):], argspec[3]))
298
299 def cached_result(self2, cr, *args, **kwargs):
300+
301 if time.time()-int(self.timeout) > self.lasttime:
302 self.lasttime = time.time()
303 t = time.time()-int(self.timeout)