[FIX] res.users: don't delay login() if user row is currently locked
Any running transaction that has created or altered a record that contains a FK to the user is automatically holding an SharedRowLock that prevents login() from updating the last login date. As we cannot delay the login() until all such transactions are finished, it's simpler to try to get the lock and if that fails, we skip the login date update for once, no big deal. A typical candidate for this situation is the Admin user, locked out by long running cron jobs that touch rows as Admin, hence holding a ShareRowLock to res.users ID 1 because of the many create_uid/write_uid foreign keys. lp bug: https://launchpad.net/bugs/713216 fixed bzr revid: odo@openerp.com-20120213183207-45ptopqm0szritgx
This commit is contained in:
parent
e7ca80cdeb
commit
f87324e93e
|
@ -474,23 +474,40 @@ class users(osv.osv):
|
|||
return False
|
||||
cr = pooler.get_db(db).cursor()
|
||||
try:
|
||||
# We autocommit: our single request will be performed atomically.
|
||||
# autocommit: our single request will be performed atomically.
|
||||
# (In this way, there is no opportunity to have two transactions
|
||||
# interleaving ther cr.execute()..cr.commit() calls and have one
|
||||
# of them rollbacked due to a concurrent access.)
|
||||
# interleaving their cr.execute()..cr.commit() calls and have one
|
||||
# of them rolled back due to a concurrent access.)
|
||||
# We effectively unconditionally write the res_users line.
|
||||
cr.autocommit(True)
|
||||
# Even w/ autocommit there's a chance the user row will be locked,
|
||||
# in which case we can't delay the login just for the purpose of
|
||||
# update the last login date - hence we use FOR UPDATE NOWAIT to
|
||||
# try to get the lock - fail-fast
|
||||
cr.execute("""SELECT id from res_users
|
||||
WHERE login=%s AND password=%s
|
||||
AND active FOR UPDATE NOWAIT""",
|
||||
(tools.ustr(login), tools.ustr(password)))
|
||||
cr.execute("""UPDATE res_users
|
||||
SET date = now() AT TIME ZONE 'UTC'
|
||||
WHERE login=%s AND password=%s AND active RETURNING id""",
|
||||
WHERE login=%s AND password=%s AND active
|
||||
RETURNING id""",
|
||||
(tools.ustr(login), tools.ustr(password)))
|
||||
except Exception:
|
||||
# Failing to acquire the lock on the res_users row probably means
|
||||
# another request is holding it. No big deal, we don't want to
|
||||
# prevent/delay login in that case. It will also have been logged
|
||||
# as a SQL error, if anyone cares.
|
||||
cr.execute("""SELECT id from res_users
|
||||
WHERE login=%s AND password=%s
|
||||
AND active""",
|
||||
(tools.ustr(login), tools.ustr(password)))
|
||||
finally:
|
||||
res = cr.fetchone()
|
||||
cr.close()
|
||||
if res:
|
||||
return res[0]
|
||||
else:
|
||||
return False
|
||||
finally:
|
||||
cr.close()
|
||||
return False
|
||||
|
||||
def check_super(self, passwd):
|
||||
if passwd == tools.config['admin_passwd']:
|
||||
|
|
Loading…
Reference in New Issue