Home | History | Annotate | Download | only in bsddb
      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