Only wait for preemptive cache if it's enabled for path & view

This commit is contained in:
Gina Häußge 2016-08-18 13:56:46 +02:00
parent 599098a589
commit 6499bd160f
3 changed files with 93 additions and 25 deletions

View file

@ -371,7 +371,9 @@ def cached(timeout=5 * 60, key=lambda: "view:%s" % flask.request.path, unless=No
return decorator
def is_in_cache(key=lambda: "view:%s" % flask.request.path):
return key() in _cache
if callable(key):
key = key()
return key in _cache
def cache_check_headers():
return "no-cache" in flask.request.cache_control or "no-cache" in flask.request.pragma
@ -400,10 +402,11 @@ class PreemptiveCache(object):
self.cachefile = cachefile
self._lock = threading.RLock()
self._log_lock = threading.RLock()
self._logger = logging.getLogger(__name__ + "." + self.__class__.__name__)
self._log_access = True
def record(self, data, unless=None):
def record(self, data, unless=None, root=None):
if callable(unless) and unless():
return
@ -412,12 +415,32 @@ class PreemptiveCache(object):
entry_data = entry_data()
if entry_data is not None:
if root is None:
from flask import request
root = request.path
self.add_data(root, entry_data)
def has_record(self, data, root=None):
if callable(data):
data = data()
if data is None:
return False
if root is None:
from flask import request
self.add_data(request.path, entry_data)
root = request.path
all_data = self.get_data(root)
for existing in all_data:
if self._compare_data(data, existing):
return True
return False
@contextlib.contextmanager
def disable_access_logging(self):
with self._lock:
with self._log_lock:
self._log_access = False
yield
self._log_access = True
@ -482,20 +505,19 @@ class PreemptiveCache(object):
self.set_all_data(all_data)
def add_data(self, root, data):
from octoprint.util import dict_filter
def strip_ignored(d):
return dict_filter(d, lambda k, v: not k.startswith("_"))
def compare(a, b):
return set(strip_ignored(a).items()) == set(strip_ignored(b).items())
with self._log_lock:
if not self._log_access:
self._logger.debug(
"Not updating timestamp and counter for {} and {!r}, currently flagged as disabled".format(root,
data))
return
def split_matched_and_unmatched(entry, entries):
matched = []
unmatched = []
for e in entries:
if compare(e, entry):
if self._compare_data(e, entry):
matched.append(e)
else:
unmatched.append(e)
@ -503,12 +525,6 @@ class PreemptiveCache(object):
return matched, unmatched
with self._lock:
if not self._log_access:
self._logger.debug(
"Not updating timestamp and counter for {} and {!r}, currently flagged as disabled".format(root,
data))
return
cache_data = self.get_all_data()
if not root in cache_data:
@ -537,6 +553,14 @@ class PreemptiveCache(object):
self.set_data(root, [to_persist] + other)
def _compare_data(self, a, b):
from octoprint.util import dict_filter
def strip_ignored(d):
return dict_filter(d, lambda k, v: not k.startswith("_"))
return set(strip_ignored(a).items()) == set(strip_ignored(b).items())
def preemptively_cached(cache, data, unless=None):
def decorator(f):

View file

@ -30,25 +30,63 @@ _logger = logging.getLogger(__name__)
_valid_id_re = re.compile("[a-z_]+")
_valid_div_re = re.compile("[a-zA-Z_-]+")
def _preemptive_unless(root=None, path=None):
if root is None:
root = request.url_root
if path is None:
path = request.path
return not settings().getBoolean(["devel", "cache", "preemptive"]) \
or path in settings().get(["server", "preemptiveCache", "exceptions"]) \
or not (root.startswith("http://") or root.startswith("https://"))
def _preemptive_data(path=None, base_url=None):
if path is None:
path = request.path
if base_url is None:
base_url = request.url_root
return dict(path=path,
base_url=base_url,
query_string="l10n={}".format(g.locale.language) if g.locale else "en")
def _cache_key(url=None, locale=None):
if url is None:
url = request.base_url
if locale is None:
locale = g.locale.language if g.locale else "en"
return "view:{}:{}".format(url, locale)
@app.route("/cached.gif")
def in_cache():
url = request.base_url.replace("/cached.gif", "/")
key = lambda: "view:{}:{}".format(url, g.locale.language if g.locale else "en")
if not util.flask.is_in_cache(key):
return abort(404)
path = request.path.replace("/cached.gif", "/")
key = _cache_key(url)
data = _preemptive_data(path=path)
response = make_response(bytes(base64.b64decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")))
response.headers["Content-Type"] = "image/gif"
return response
if _preemptive_unless(root=url, path=path) or not preemptiveCache.has_record(data, root=path):
_logger.info("Preemptive cache not active for path {} and data {!r}, signaling as cached".format(path, data))
return response
elif util.flask.is_in_cache(key):
_logger.info("Found path {} in cache (key: {}), signaling as cached".format(path, key))
return response
else:
_logger.info("Path {} not yet cached (key: {}), signaling as missing".format(path, key))
return abort(404)
@app.route("/")
@util.flask.preemptively_cached(cache=preemptiveCache,
data=lambda: dict(path=request.path, base_url=request.url_root, query_string="l10n={}".format(g.locale.language) if g.locale else "en"),
unless=lambda: request.url_root in settings().get(["server", "preemptiveCache", "exceptions"]) or not (request.url_root.startswith("http://") or request.url_root.startswith("https://")))
data=_preemptive_data,
unless=_preemptive_unless)
@util.flask.conditional(lambda: _check_etag_and_lastmodified_for_index(), NOT_MODIFIED)
@util.flask.cached(timeout=-1,
refreshif=lambda cached: _validate_cache_for_index(cached),
key=lambda: "view:{}:{}".format(request.base_url, g.locale.language if g.locale else "en"),
key=_cache_key,
unless_response=lambda response: util.flask.cache_check_response_headers(response))
@util.flask.etagged(lambda _: _compute_etag_for_index())
@util.flask.lastmodified(lambda _: _compute_date_for_index())

View file

@ -162,9 +162,15 @@
var message = window.document.getElementById("message");
var indexCached = false;
var indexCachedCallback = function(result) {
if (result == "load") {
if (indexCached) {
return;
}
// our cached.gif loaded, so the index is cached now, let's reload
indexCached = true;
message.className = "pulsate1 green";
message.innerText = "OctoPrint server ready, reloading page...";