Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 1 | #------------------------------------------------------------------------ |
| 2 | # |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 3 | # Copyright (C) 2000 Autonomous Zone Industries |
| 4 | # |
| 5 | # License: This is free software. You may use this software for any |
| 6 | # purpose including modification/redistribution, so long as |
| 7 | # this header remains intact and that you do not claim any |
| 8 | # rights of ownership or authorship of this software. This |
| 9 | # software has been tested, but no warranty is expressed or |
| 10 | # implied. |
| 11 | # |
Gregory P. Smith | 3fd22da | 2007-08-28 08:05:56 +0000 | [diff] [blame] | 12 | # Author: Gregory P. Smith <greg@krypto.org> |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 13 | # |
| 14 | # Note: I don't know how useful this is in reality since when a |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 15 | # DBLockDeadlockError happens the current transaction is supposed to be |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 16 | # aborted. If it doesn't then when the operation is attempted again |
| 17 | # the deadlock is still happening... |
| 18 | # --Robin |
| 19 | # |
| 20 | #------------------------------------------------------------------------ |
| 21 | |
Gregory P. Smith | 3fd22da | 2007-08-28 08:05:56 +0000 | [diff] [blame] | 22 | import time |
Guido van Rossum | cde2ead | 2006-08-17 23:29:08 +0000 | [diff] [blame] | 23 | from . import db |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 24 | |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 25 | # always sleep at least N seconds between retrys |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 26 | _deadlock_MinSleepTime = 1.0/128 |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 27 | # never sleep more than N seconds between retrys |
| 28 | _deadlock_MaxSleepTime = 3.14159 |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 29 | |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 30 | # Assign a file object to this for a "sleeping" message to be written to it |
| 31 | # each retry |
| 32 | _deadlock_VerboseFile = None |
| 33 | |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 34 | |
| 35 | def DeadlockWrap(function, *_args, **_kwargs): |
| 36 | """DeadlockWrap(function, *_args, **_kwargs) - automatically retries |
| 37 | function in case of a database deadlock. |
| 38 | |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 39 | This is a function intended to be used to wrap database calls such |
| 40 | that they perform retrys with exponentially backing off sleeps in |
| 41 | between when a DBLockDeadlockError exception is raised. |
| 42 | |
| 43 | A 'max_retries' parameter may optionally be passed to prevent it |
| 44 | from retrying forever (in which case the exception will be reraised). |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 45 | |
| 46 | d = DB(...) |
| 47 | d.open(...) |
| 48 | DeadlockWrap(d.put, "foo", data="bar") # set key "foo" to "bar" |
| 49 | """ |
| 50 | sleeptime = _deadlock_MinSleepTime |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 51 | max_retries = _kwargs.get('max_retries', -1) |
Guido van Rossum | 2043513 | 2006-08-21 00:21:47 +0000 | [diff] [blame] | 52 | if 'max_retries' in _kwargs: |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 53 | del _kwargs['max_retries'] |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 54 | while True: |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 55 | try: |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 56 | return function(*_args, **_kwargs) |
Gregory P. Smith | 3fd22da | 2007-08-28 08:05:56 +0000 | [diff] [blame] | 57 | except db.DBLockDeadlockError as e: |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 58 | if _deadlock_VerboseFile: |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 59 | _deadlock_VerboseFile.write( |
Gregory P. Smith | 3fd22da | 2007-08-28 08:05:56 +0000 | [diff] [blame] | 60 | 'bsddb.dbutils.DeadlockWrap: ' + |
| 61 | 'sleeping %1.3f\n' % sleeptime) |
| 62 | time.sleep(sleeptime) |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 63 | # exponential backoff in the sleep time |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 64 | sleeptime *= 2 |
| 65 | if sleeptime > _deadlock_MaxSleepTime: |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 66 | sleeptime = _deadlock_MaxSleepTime |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 67 | max_retries -= 1 |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 68 | if max_retries == -1: |
Gregory P. Smith | 3fd22da | 2007-08-28 08:05:56 +0000 | [diff] [blame] | 69 | if _deadlock_VerboseFile: |
| 70 | _deadlock_VerboseFile.write( |
| 71 | 'bsddb.dbutils.DeadlockWrap: ' + |
| 72 | 'max_retries reached, reraising %s\n' % e) |
Martin v. Löwis | b2c7aff | 2002-11-23 11:26:07 +0000 | [diff] [blame] | 73 | raise |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 74 | |
| 75 | |
| 76 | #------------------------------------------------------------------------ |