Skip to content

Commit

Permalink
Cache url_for calls with lru_cache
Browse files Browse the repository at this point in the history
This commit adds a caching_url_for using functools.lru_cache (currently
with maxsize at 4096 entries) and replaces flask.url_for with it, as
there is no harm in doing so.

This greatly improves template generation speed, from ~115ms to ~75ms on
the front page (using the simple benchmark introduced in the previous
commit).
  • Loading branch information
TheAMM authored and CounterPillow committed Apr 8, 2019
1 parent a755882 commit 885cccc
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
10 changes: 10 additions & 0 deletions nyaa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@
from nyaa.api_handler import api_blueprint
from nyaa.extensions import assets, cache, db, fix_paginate, toolbar
from nyaa.template_utils import bp as template_utils_bp
from nyaa.template_utils import caching_url_for
from nyaa.utils import random_string
from nyaa.views import register_views

# Replace the Flask url_for with our cached version, since there's no real harm in doing so
# (caching_url_for has stored a reference to the OG url_for, so we won't recurse)
# Touching globals like this is a bit dirty, but nicer than replacing every url_for usage
flask.url_for = caching_url_for


def create_app(config):
""" Nyaa app factory """
Expand Down Expand Up @@ -86,6 +92,10 @@ def internal_error(exception):
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True

# The default jinja_env has the OG Flask url_for (from before we replaced it),
# so update the globals with our version
app.jinja_env.globals['url_for'] = flask.url_for

# Database
fix_paginate() # This has to be before the database is initialized
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
Expand Down
23 changes: 23 additions & 0 deletions nyaa/template_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functools
import os.path
import re
from datetime import datetime
Expand Down Expand Up @@ -25,6 +26,28 @@ def create_magnet_from_es_torrent():

# ######################### TEMPLATE GLOBALS #########################

flask_url_for = flask.url_for


@functools.lru_cache(maxsize=1024*4)
def _caching_url_for(endpoint, **values):
return flask_url_for(endpoint, **values)


@bp.app_template_global()
def caching_url_for(*args, **kwargs):
try:
# lru_cache requires the arguments to be hashable.
# Majority of the time, they are! But there are some small edge-cases,
# like our copypasted pagination, parameters can be lists.
# Attempt caching first:
return _caching_url_for(*args, **kwargs)
except TypeError:
# Then fall back to the original url_for.
# We could convert the lists to tuples, but the savings are marginal.
return flask_url_for(*args, **kwargs)


@bp.app_template_global()
def static_cachebuster(filename):
""" Adds a ?t=<mtime> cachebuster to the given path, if the file exists.
Expand Down

0 comments on commit 885cccc

Please sign in to comment.