30
30
]
31
31
32
32
33
+ def _monkey_patch_method (cache , name ):
34
+ original_method = getattr (cache , name )
35
+
36
+ @functools .wraps (original_method )
37
+ def wrapper (* args , ** kwargs ):
38
+ panel = cache ._djdt_panel
39
+ if panel is None :
40
+ return original_method (* args , ** kwargs )
41
+ else :
42
+ return panel ._record_call (cache , name , original_method , args , kwargs )
43
+
44
+ setattr (cache , name , wrapper )
45
+
46
+
47
+ def _monkey_patch_cache (cache ):
48
+ if not hasattr (cache , "_djdt_patched" ):
49
+ for name in WRAPPED_CACHE_METHODS :
50
+ _monkey_patch_method (cache , name )
51
+ cache ._djdt_patched = True
52
+
53
+
33
54
class CachePanel (Panel ):
34
55
"""
35
56
Panel that displays the cache statistics.
@@ -72,7 +93,8 @@ def wrapper(self, alias):
72
93
cache = original_method (self , alias )
73
94
panel = cls .current_instance ()
74
95
if panel is not None :
75
- panel ._monkey_patch_cache (cache )
96
+ _monkey_patch_cache (cache )
97
+ cache ._djdt_panel = panel
76
98
return cache
77
99
78
100
CacheHandler .create_connection = wrapper
@@ -120,14 +142,17 @@ def _store_call_info(
120
142
def _record_call (self , cache , name , original_method , args , kwargs ):
121
143
# Some cache backends implement certain cache methods in terms of other cache
122
144
# methods (e.g. get_or_set() in terms of get() and add()). In order to only
123
- # record the calls made directly by the user code, set the _djdt_recording flag
124
- # here to cause the monkey patched cache methods to skip recording additional
125
- # calls made during the course of this call.
126
- cache ._djdt_recording = True
127
- t = time .time ()
128
- value = original_method (* args , ** kwargs )
129
- t = time .time () - t
130
- cache ._djdt_recording = False
145
+ # record the calls made directly by the user code, set the cache's _djdt_panel
146
+ # attribute to None before invoking the original method, which will cause the
147
+ # monkey-patched cache methods to skip recording additional calls made during
148
+ # the course of this call, and then reset it back afterward.
149
+ cache ._djdt_panel = None
150
+ try :
151
+ t = time .time ()
152
+ value = original_method (* args , ** kwargs )
153
+ t = time .time () - t
154
+ finally :
155
+ cache ._djdt_panel = self
131
156
132
157
self ._store_call_info (
133
158
name = name ,
@@ -141,40 +166,6 @@ def _record_call(self, cache, name, original_method, args, kwargs):
141
166
)
142
167
return value
143
168
144
- def _monkey_patch_method (self , cache , name ):
145
- original_method = getattr (cache , name )
146
-
147
- @functools .wraps (original_method )
148
- def wrapper (* args , ** kwargs ):
149
- # If this call is being made as part of the implementation of another cache
150
- # method, don't record it.
151
- if cache ._djdt_recording :
152
- return original_method (* args , ** kwargs )
153
- else :
154
- return self ._record_call (cache , name , original_method , args , kwargs )
155
-
156
- wrapper ._djdt_wrapped = original_method
157
- setattr (cache , name , wrapper )
158
-
159
- def _monkey_patch_cache (self , cache ):
160
- if not hasattr (cache , "_djdt_patched" ):
161
- for name in WRAPPED_CACHE_METHODS :
162
- self ._monkey_patch_method (cache , name )
163
- cache ._djdt_patched = True
164
- cache ._djdt_recording = False
165
-
166
- @staticmethod
167
- def _unmonkey_patch_cache (cache ):
168
- if hasattr (cache , "_djdt_patched" ):
169
- for name in WRAPPED_CACHE_METHODS :
170
- original_method = getattr (cache , name )._djdt_wrapped
171
- if original_method .__func__ == getattr (cache .__class__ , name ):
172
- delattr (cache , name )
173
- else :
174
- setattr (cache , name , original_method )
175
- del cache ._djdt_patched
176
- del cache ._djdt_recording
177
-
178
169
# Implement the Panel API
179
170
180
171
nav_title = _ ("Cache" )
@@ -204,7 +195,8 @@ def enable_instrumentation(self):
204
195
# the .ready() method will ensure that any new cache connections that get opened
205
196
# during this request will also be monkey patched.
206
197
for cache in caches .all (initialized_only = True ):
207
- self ._monkey_patch_cache (cache )
198
+ _monkey_patch_cache (cache )
199
+ cache ._djdt_panel = self
208
200
# Mark this panel instance as the current one for the active thread/async task
209
201
# context. This will be used by the CacheHander.create_connection() monkey
210
202
# patch.
@@ -214,7 +206,7 @@ def disable_instrumentation(self):
214
206
if hasattr (self ._context_locals , "current_instance" ):
215
207
del self ._context_locals .current_instance
216
208
for cache in caches .all (initialized_only = True ):
217
- self . _unmonkey_patch_cache ( cache )
209
+ cache . _djdt_panel = None
218
210
219
211
def generate_stats (self , request , response ):
220
212
self .record_stats (
0 commit comments