From a510c7b55c99b88d6d28be4d4537b8e61c69280c Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Sun, 12 Nov 2017 15:21:53 -0800 Subject: [PATCH] Improve Album bytes caching, start caching photo count. More careful uncaching of the summed bytes, to minimize recalculation. Fewer cases where the album itself is removed from the photodb's getter cache. This also helps the download link on album pages disappear if the child albums don't actually have any photos. --- etiquette/objects.py | 66 +++++++++++++------ etiquette/photodb.py | 7 +- .../etiquette_flask/templates/album.html | 11 ++-- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/etiquette/objects.py b/etiquette/objects.py index ff8e927..d658224 100644 --- a/etiquette/objects.py +++ b/etiquette/objects.py @@ -85,7 +85,6 @@ class GroupableMixin: 'INSERT INTO %s VALUES(?, ?)' % self.group_table, [self.id, member.id] ) - self._uncache() if commit: self.photodb.log.debug('Committing - add to group') self.photodb.commit() @@ -197,7 +196,6 @@ class GroupableMixin: 'DELETE FROM %s WHERE memberid == ?' % self.group_table, [self.id] ) - self._uncache() if commit: self.photodb.log.debug('Committing - leave group') self.photodb.commit() @@ -228,8 +226,10 @@ class Album(ObjectBase, GroupableMixin): self.description = db_row['description'] or '' self.name = 'Album %s' % self.id self.group_getter = self.photodb.get_album - self._sum_bytes_photos = None - self._sum_bytes_albums = None + + self._sum_bytes_local = None + self._sum_bytes_recursive = None + self._sum_photos_recursive = None def __hash__(self): return hash(self.id) @@ -238,13 +238,24 @@ class Album(ObjectBase, GroupableMixin): return 'Album:{id}'.format(id=self.id) def _uncache(self): + self._uncache_sums() self.photodb.caches['album'].remove(self.id) - self._sum_bytes_photos = None - self._sum_bytes_albums = None + + def _uncache_sums(self): + self._sum_photos_recursive = None + self._sum_bytes_local = None + self._sum_bytes_recursive = None + parent = self.parent() + if parent is not None: + parent._sum_photos_recursive = None + parent._sum_bytes_recursive = None + @decorators.required_feature('album.edit') def add_child(self, *args, **kwargs): - return super().add_child(*args, **kwargs) + result = super().add_child(*args, **kwargs) + self._uncache_sums() + return result @decorators.required_feature('album.edit') @decorators.transaction @@ -293,7 +304,7 @@ class Album(ObjectBase, GroupableMixin): self.photodb.log.debug('Adding photo %s to %s' % (photo, self)) cur = self.photodb.sql.cursor() cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id]) - self._uncache() + self._uncache_sums() if commit: self.photodb.log.debug('Committing - add photo to album') self.photodb.commit() @@ -369,7 +380,7 @@ class Album(ObjectBase, GroupableMixin): ) self.title = title self.description = description - self._uncache() + if commit: self.photodb.log.debug('Committing - edit album') self.photodb.commit() @@ -386,11 +397,15 @@ class Album(ObjectBase, GroupableMixin): @decorators.required_feature('album.edit') def join_group(self, *args, **kwargs): - return super().join_group(*args, **kwargs) + result = super().join_group(*args, **kwargs) + return result @decorators.required_feature('album.edit') def leave_group(self, *args, **kwargs): - return super().leave_group(*args, **kwargs) + parent = self.parent() + if parent is not None: + parent._uncache_sums() + result = super().leave_group(*args, **kwargs) def photos(self): photos = [] @@ -416,27 +431,40 @@ class Album(ObjectBase, GroupableMixin): 'DELETE FROM album_photo_rel WHERE albumid == ? AND photoid == ?', [self.id, photo.id] ) - self._uncache() + self._uncache_sums() if commit: self.photodb.log.debug('Committing - remove photo from album') self.photodb.commit() def sum_bytes(self, recurse=True, string=False): - if self._sum_bytes_photos is None: - photos = (photo.bytes for photo in self.photos() if photo.bytes is not None) - self._sum_bytes_photos = sum(photos) - total = self._sum_bytes_photos + if self._sum_bytes_local is None: + #print(self, 'sumbytes cache miss local') + photos = (photo for photo in self.photos() if photo.bytes is not None) + self._sum_bytes_local = sum(photo.bytes for photo in photos) + total = self._sum_bytes_local if recurse: - if self._sum_bytes_albums is None: - self._sum_bytes_albums = sum(a.sum_bytes(recurse=True) for a in self.children()) - total += self._sum_bytes_albums + if self._sum_bytes_recursive is None: + #print(self, 'sumbytes cache miss recursive') + child_bytes = sum(child.sum_bytes(recurse=True) for child in self.children()) + self._sum_bytes_recursive = self._sum_bytes_local + child_bytes + total = self._sum_bytes_recursive if string: return bytestring.bytestring(total) else: return total + def sum_photos(self): + if self._sum_photos_recursive is None: + #print(self, 'sumphotos cache miss') + total = 0 + total += sum(1 for x in self.photos()) + total += sum(child.sum_photos() for child in self.children()) + self._sum_photos_recursive = total + + return self._sum_photos_recursive + def walk_photos(self): yield from self.photos() children = self.walk_children() diff --git a/etiquette/photodb.py b/etiquette/photodb.py index 9dbd0cc..b19318f 100644 --- a/etiquette/photodb.py +++ b/etiquette/photodb.py @@ -1387,12 +1387,9 @@ class PhotoDB(PDBAlbumMixin, PDBBookmarkMixin, PDBPhotoMixin, PDBTagMixin, PDBUs if isinstance(thing_id, thing_map['class']): thing_id = thing_id.id - cache = { - 'album': self._album_cache, - 'photo': self._photo_cache, - 'tag': self._tag_cache, - }[thing_type] + cache = self.caches[thing_type] try: + #self.log.debug('Cache hit for %s %s', thing_type, thing_id) val = cache[thing_id] return val except KeyError: diff --git a/frontends/etiquette_flask/templates/album.html b/frontends/etiquette_flask/templates/album.html index e7e2751..abf4cd3 100644 --- a/frontends/etiquette_flask/templates/album.html +++ b/frontends/etiquette_flask/templates/album.html @@ -91,16 +91,19 @@ p {% endfor %} {% endif %} +

- {% if photos or sub_albums %} + {% set has_local_photos = photos|length > 0 %} + {% set has_child_photos = album.sum_photos() > photos|length %} + {% if has_local_photos or has_child_photos %} Download: - {% if photos %} + {% if has_local_photos %} These files ({{album.sum_bytes(recurse=False, string=True)}}) {% endif %} - {% if photos and sub_albums %}—{% endif %} - {% if sub_albums %} + {% if has_local_photos and has_child_photos %}—{% endif %} + {% if has_child_photos %} Include children ({{album.sum_bytes(recurse=True, string=True)}})