Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: third_party/google-endpoints/dogpile/lock.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 import time
2 import logging
3
4 log = logging.getLogger(__name__)
5
6
7 class NeedRegenerationException(Exception):
8 """An exception that when raised in the 'with' block,
9 forces the 'has_value' flag to False and incurs a
10 regeneration of the value.
11
12 """
13
14 NOT_REGENERATED = object()
15
16
17 class Lock(object):
18 """Dogpile lock class.
19
20 Provides an interface around an arbitrary mutex
21 that allows one thread/process to be elected as
22 the creator of a new value, while other threads/processes
23 continue to return the previous version
24 of that value.
25
26 :param mutex: A mutex object that provides ``acquire()``
27 and ``release()`` methods.
28 :param creator: Callable which returns a tuple of the form
29 (new_value, creation_time). "new_value" should be a newly
30 generated value representing completed state. "creation_time"
31 should be a floating point time value which is relative
32 to Python's ``time.time()`` call, representing the time
33 at which the value was created. This time value should
34 be associated with the created value.
35 :param value_and_created_fn: Callable which returns
36 a tuple of the form (existing_value, creation_time). This
37 basically should return what the last local call to the ``creator()``
38 callable has returned, i.e. the value and the creation time,
39 which would be assumed here to be from a cache. If the
40 value is not available, the :class:`.NeedRegenerationException`
41 exception should be thrown.
42 :param expiretime: Expiration time in seconds. Set to
43 ``None`` for never expires. This timestamp is compared
44 to the creation_time result and ``time.time()`` to determine if
45 the value returned by value_and_created_fn is "expired".
46 :param async_creator: A callable. If specified, this callable will be
47 passed the mutex as an argument and is responsible for releasing the mutex
48 after it finishes some asynchronous value creation. The intent is for
49 this to be used to defer invocation of the creator callable until some
50 later time.
51
52 """
53
54 def __init__(
55 self,
56 mutex,
57 creator,
58 value_and_created_fn,
59 expiretime,
60 async_creator=None,
61 ):
62 self.mutex = mutex
63 self.creator = creator
64 self.value_and_created_fn = value_and_created_fn
65 self.expiretime = expiretime
66 self.async_creator = async_creator
67
68 def _is_expired(self, createdtime):
69 """Return true if the expiration time is reached, or no
70 value is available."""
71
72 return not self._has_value(createdtime) or \
73 (
74 self.expiretime is not None and
75 time.time() - createdtime > self.expiretime
76 )
77
78 def _has_value(self, createdtime):
79 """Return true if the creation function has proceeded
80 at least once."""
81 return createdtime > 0
82
83 def _enter(self):
84 value_fn = self.value_and_created_fn
85
86 try:
87 value = value_fn()
88 value, createdtime = value
89 except NeedRegenerationException:
90 log.debug("NeedRegenerationException")
91 value = NOT_REGENERATED
92 createdtime = -1
93
94 generated = self._enter_create(createdtime)
95
96 if generated is not NOT_REGENERATED:
97 generated, createdtime = generated
98 return generated
99 elif value is NOT_REGENERATED:
100 try:
101 value, createdtime = value_fn()
102 return value
103 except NeedRegenerationException:
104 raise Exception("Generation function should "
105 "have just been called by a concurrent "
106 "thread.")
107 else:
108 return value
109
110 def _enter_create(self, createdtime):
111
112 if not self._is_expired(createdtime):
113 return NOT_REGENERATED
114
115 async = False
116
117 if self._has_value(createdtime):
118 if not self.mutex.acquire(False):
119 log.debug("creation function in progress "
120 "elsewhere, returning")
121 return NOT_REGENERATED
122 else:
123 log.debug("no value, waiting for create lock")
124 self.mutex.acquire()
125
126 try:
127 log.debug("value creation lock %r acquired" % self.mutex)
128
129 # see if someone created the value already
130 try:
131 value, createdtime = self.value_and_created_fn()
132 except NeedRegenerationException:
133 pass
134 else:
135 if not self._is_expired(createdtime):
136 log.debug("value already present")
137 return value, createdtime
138 elif self.async_creator:
139 log.debug("Passing creation lock to async runner")
140 self.async_creator(self.mutex)
141 async = True
142 return value, createdtime
143
144 log.debug("Calling creation function")
145 created = self.creator()
146 return created
147 finally:
148 if not async:
149 self.mutex.release()
150 log.debug("Released creation lock")
151
152
153 def __enter__(self):
154 return self._enter()
155
156 def __exit__(self, type, value, traceback):
157 pass
158
OLDNEW
« no previous file with comments | « third_party/google-endpoints/dogpile/core.py ('k') | third_party/google-endpoints/dogpile/util/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698