1 #------------------------------------------------------------------------ 2 # 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 # 12 # Author: Gregory P. Smith <greg (at] krypto.org> 13 # 14 # Note: I don't know how useful this is in reality since when a 15 # DBLockDeadlockError happens the current transaction is supposed to be 16 # aborted. If it doesn't then when the operation is attempted again 17 # the deadlock is still happening... 18 # --Robin 19 # 20 #------------------------------------------------------------------------ 21 22 23 # 24 # import the time.sleep function in a namespace safe way to allow 25 # "from bsddb.dbutils import *" 26 # 27 from time import sleep as _sleep 28 29 import sys 30 absolute_import = (sys.version_info[0] >= 3) 31 if absolute_import : 32 # Because this syntaxis is not valid before Python 2.5 33 exec("from . import db") 34 else : 35 import db 36 37 # always sleep at least N seconds between retrys 38 _deadlock_MinSleepTime = 1.0/128 39 # never sleep more than N seconds between retrys 40 _deadlock_MaxSleepTime = 3.14159 41 42 # Assign a file object to this for a "sleeping" message to be written to it 43 # each retry 44 _deadlock_VerboseFile = None 45 46 47 def DeadlockWrap(function, *_args, **_kwargs): 48 """DeadlockWrap(function, *_args, **_kwargs) - automatically retries 49 function in case of a database deadlock. 50 51 This is a function intended to be used to wrap database calls such 52 that they perform retrys with exponentially backing off sleeps in 53 between when a DBLockDeadlockError exception is raised. 54 55 A 'max_retries' parameter may optionally be passed to prevent it 56 from retrying forever (in which case the exception will be reraised). 57 58 d = DB(...) 59 d.open(...) 60 DeadlockWrap(d.put, "foo", data="bar") # set key "foo" to "bar" 61 """ 62 sleeptime = _deadlock_MinSleepTime 63 max_retries = _kwargs.get('max_retries', -1) 64 if 'max_retries' in _kwargs: 65 del _kwargs['max_retries'] 66 while True: 67 try: 68 return function(*_args, **_kwargs) 69 except db.DBLockDeadlockError: 70 if _deadlock_VerboseFile: 71 _deadlock_VerboseFile.write( 72 'dbutils.DeadlockWrap: sleeping %1.3f\n' % sleeptime) 73 _sleep(sleeptime) 74 # exponential backoff in the sleep time 75 sleeptime *= 2 76 if sleeptime > _deadlock_MaxSleepTime: 77 sleeptime = _deadlock_MaxSleepTime 78 max_retries -= 1 79 if max_retries == -1: 80 raise 81 82 83 #------------------------------------------------------------------------ 84