|
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@electricrain.com> |
|
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 db |
|
30 |
|
31 # always sleep at least N seconds between retrys |
|
32 _deadlock_MinSleepTime = 1.0/128 |
|
33 # never sleep more than N seconds between retrys |
|
34 _deadlock_MaxSleepTime = 3.14159 |
|
35 |
|
36 # Assign a file object to this for a "sleeping" message to be written to it |
|
37 # each retry |
|
38 _deadlock_VerboseFile = None |
|
39 |
|
40 |
|
41 def DeadlockWrap(function, *_args, **_kwargs): |
|
42 """DeadlockWrap(function, *_args, **_kwargs) - automatically retries |
|
43 function in case of a database deadlock. |
|
44 |
|
45 This is a function intended to be used to wrap database calls such |
|
46 that they perform retrys with exponentially backing off sleeps in |
|
47 between when a DBLockDeadlockError exception is raised. |
|
48 |
|
49 A 'max_retries' parameter may optionally be passed to prevent it |
|
50 from retrying forever (in which case the exception will be reraised). |
|
51 |
|
52 d = DB(...) |
|
53 d.open(...) |
|
54 DeadlockWrap(d.put, "foo", data="bar") # set key "foo" to "bar" |
|
55 """ |
|
56 sleeptime = _deadlock_MinSleepTime |
|
57 max_retries = _kwargs.get('max_retries', -1) |
|
58 if _kwargs.has_key('max_retries'): |
|
59 del _kwargs['max_retries'] |
|
60 while True: |
|
61 try: |
|
62 return function(*_args, **_kwargs) |
|
63 except db.DBLockDeadlockError: |
|
64 if _deadlock_VerboseFile: |
|
65 _deadlock_VerboseFile.write( |
|
66 'dbutils.DeadlockWrap: sleeping %1.3f\n' % sleeptime) |
|
67 _sleep(sleeptime) |
|
68 # exponential backoff in the sleep time |
|
69 sleeptime *= 2 |
|
70 if sleeptime > _deadlock_MaxSleepTime: |
|
71 sleeptime = _deadlock_MaxSleepTime |
|
72 max_retries -= 1 |
|
73 if max_retries == -1: |
|
74 raise |
|
75 |
|
76 |
|
77 #------------------------------------------------------------------------ |