Skip to content

Commit

Permalink
Merge pull request #1131 from girder/fix-cache-styling-reference
Browse files Browse the repository at this point in the history
Fix a bug with caching tiles and styling.
  • Loading branch information
manthey authored Apr 24, 2023
2 parents b66c5f4 + 7e8ce56 commit b1ab7a8
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Bug Fixes
- Allow clearing the min/max fields of the frame selector ([#1030](../../pull/1030))
- Fix a bug with caching tiles and styling ([#1031](../../pull/1031))

## 1.20.5

Expand Down
4 changes: 3 additions & 1 deletion girder/girder_large_image/models/image_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,12 @@ def _tileFromHash(cls, item, x, y, z, mayRedirect=False, **kwargs):
sourceClass = girder_tilesource.AvailableGirderTileSources[sourceName]
except TileSourceError:
return None
if '_' in kwargs:
if '_' in kwargs or 'style' in kwargs:
kwargs = kwargs.copy()
kwargs.pop('_', None)
classHash = sourceClass.getLRUHash(item, **kwargs)
# style isn't part of the tile hash strhash parameters
kwargs.pop('style', None)
tileHash = sourceClass.__name__ + ' ' + classHash + ' ' + strhash(
sourceClass.__name__ + ' ' + classHash) + strhash(
*(x, y, z), mayRedirect=mayRedirect, **kwargs)
Expand Down
14 changes: 11 additions & 3 deletions large_image/cache_util/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def strhash(*args, **kwargs):
return '%r' % (args, )


def methodcache(key=None):
def methodcache(key=None): # noqa
"""
Decorator to wrap a function with a memoizing callable that saves results
in self.cache. This is largely taken from cachetools, but uses a cache
Expand All @@ -72,9 +72,17 @@ def decorator(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
k = key(*args, **kwargs) if key else self.wrapKey(*args, **kwargs)
if hasattr(self, '_classkey'):
k = self._classkey + ' ' + k
lock = getattr(self, 'cache_lock', None)
ck = getattr(self, '_classkey', None)
if lock:
with self.cache_lock:
if hasattr(self, '_classkeyLock'):
if self._classkeyLock.acquire(blocking=False):
self._classkeyLock.release()
else:
ck = getattr(self, '_unlocked_classkey', ck)
if ck:
k = ck + ' ' + k
try:
if lock:
with self.cache_lock:
Expand Down
34 changes: 22 additions & 12 deletions large_image/tilesource/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ def _setStyle(self, style):
:param style: The new style.
"""
for key in {'_unlocked_classkey', '_classkeyLock'}:
try:
delattr(self, key)
except Exception:
pass
self._bandRanges = {}
self._jsonstyle = style
if style:
Expand Down Expand Up @@ -1042,10 +1047,7 @@ def _scanForMinMax(self, dtype, frame=None, analysisSize=1024, onlyMinMax=True,
:param onlyMinMax: if True, only find the min and max. If False, get
the entire histogram.
"""
self._skipStyle = True
# Divert the tile cache while querying unstyled tiles
classkey = self._classkey
self._classkey = self._unstyledClassKey()
self._setSkipStyle(True)
try:
self._bandRanges[frame] = self.histogram(
dtype=dtype,
Expand All @@ -1059,8 +1061,7 @@ def _scanForMinMax(self, dtype, frame=None, analysisSize=1024, onlyMinMax=True,
k: v for k, v in self._bandRanges[frame].items() if k in {
'min', 'max', 'mean', 'stdev'}})
finally:
del self._skipStyle
self._classkey = classkey
self._setSkipStyle(False)

def _validateMinMaxValue(self, value, frame, dtype):
"""
Expand Down Expand Up @@ -1306,6 +1307,19 @@ def _applyICCProfile(self, sc, frame):
self.logger.exception('Failed to apply ICC profile')
return sc.iccimage

def _setSkipStyle(self, setSkip=False):
if setSkip:
self._unlocked_classkey = self._classkey
if hasattr(self, 'cache_lock'):
with self.cache_lock:
self._classkeyLock = self._styleLock
self._skipStyle = True
# Divert the tile cache while querying unstyled tiles
self._classkey = self._unstyledClassKey()
else:
del self._skipStyle
self._classkey = self._unlocked_classkey

def _applyStyle(self, image, style, x, y, z, frame=None): # noqa
"""
Apply a style to a numpy image.
Expand Down Expand Up @@ -1349,18 +1363,14 @@ def _applyStyle(self, image, style, x, y, z, frame=None): # noqa
else:
frame = entry['frame'] if entry.get('frame') is not None else (
sc.mainFrame + entry['framedelta'])
self._skipStyle = True
# Divert the tile cache while querying unstyled tiles
classkey = self._classkey
self._classkey = self._unstyledClassKey()
self._setSkipStyle(True)
try:
image = self.getTile(x, y, z, frame=frame, numpyAllowed=True)
image = image[:sc.mainImage.shape[0],
:sc.mainImage.shape[1],
:sc.mainImage.shape[2]]
finally:
del self._skipStyle
self._classkey = classkey
self._setSkipStyle(False)
if (isinstance(entry.get('band'), int) and
entry['band'] >= 1 and entry['band'] <= image.shape[2]):
sc.bandidx = entry['band'] - 1
Expand Down

0 comments on commit b1ab7a8

Please sign in to comment.