an experiment. lets don't use threading locks, hope it helps with performance
This commit is contained in:
parent
2e09b286f4
commit
372936fcad
8 changed files with 88 additions and 77 deletions
|
@ -1,6 +1,5 @@
|
|||
import operator
|
||||
import pickle
|
||||
import threading
|
||||
from collections import deque
|
||||
from itertools import chain
|
||||
|
||||
|
@ -17,6 +16,11 @@ from c3nav.mapdata.utils.cache import AccessRestrictionAffected, MapHistory
|
|||
from c3nav.mapdata.utils.cache.package import CachePackage
|
||||
from c3nav.mapdata.utils.geometry import get_rings, unwrap_geom
|
||||
|
||||
try:
|
||||
from asgiref.local import Local as LocalContext
|
||||
except ImportError:
|
||||
from threading import local as LocalContext
|
||||
|
||||
empty_geometry_collection = GeometryCollection()
|
||||
|
||||
|
||||
|
@ -292,9 +296,7 @@ class LevelRenderData:
|
|||
|
||||
package.save_all()
|
||||
|
||||
cached = {}
|
||||
cache_key = None
|
||||
cache_lock = threading.Lock()
|
||||
cached = LocalContext()
|
||||
|
||||
@staticmethod
|
||||
def _level_filename(pk):
|
||||
|
@ -304,22 +306,21 @@ class LevelRenderData:
|
|||
def get(cls, level):
|
||||
# get the current render data from local variable if no new processed mapupdate exists.
|
||||
# this is much faster than any other possible cache
|
||||
with cls.cache_lock:
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
level_pk = str(level.pk if isinstance(level, Level) else level)
|
||||
if cls.cache_key != cache_key:
|
||||
cls.cache_key = cache_key
|
||||
cls.cached = {}
|
||||
else:
|
||||
result = cls.cached.get(level_pk, None)
|
||||
if result is not None:
|
||||
return result
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
level_pk = str(level.pk if isinstance(level, Level) else level)
|
||||
if getattr(cls.cached, 'cache_key', None) != cache_key:
|
||||
cls.cached.key = cache_key
|
||||
cls.cached.data = {}
|
||||
else:
|
||||
result = cls.cached.data.get(level_pk, None)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
pk = level.pk if isinstance(level, Level) else level
|
||||
result = pickle.load(open(cls._level_filename(pk), 'rb'))
|
||||
pk = level.pk if isinstance(level, Level) else level
|
||||
result = pickle.load(open(cls._level_filename(pk), 'rb'))
|
||||
|
||||
cls.cached[level_pk] = result
|
||||
return result
|
||||
cls.cached.data[level_pk] = result
|
||||
return result
|
||||
|
||||
def save(self, pk):
|
||||
return pickle.dump(self, open(self._level_filename(pk), 'wb'))
|
||||
|
|
35
src/c3nav/mapdata/utils/cache/indexed.py
vendored
35
src/c3nav/mapdata/utils/cache/indexed.py
vendored
|
@ -1,9 +1,13 @@
|
|||
import math
|
||||
import struct
|
||||
import threading
|
||||
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
from asgiref.local import Local as LocalContext
|
||||
except ImportError:
|
||||
from threading import local as LocalContext
|
||||
|
||||
|
||||
class GeometryIndexed:
|
||||
# binary format (everything little-endian):
|
||||
|
@ -207,23 +211,20 @@ class LevelGeometryIndexed(GeometryIndexed):
|
|||
# noinspection PyArgumentList
|
||||
return self.save(self.level_filename(level_id, mode))
|
||||
|
||||
cached = {}
|
||||
cache_key = None
|
||||
cache_lock = threading.Lock()
|
||||
cached = LocalContext()
|
||||
|
||||
@classmethod
|
||||
def open_level_cached(cls, level_id, mode):
|
||||
with cls.cache_lock:
|
||||
from c3nav.mapdata.models import MapUpdate
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
if cls.cache_key != cache_key:
|
||||
cls.cache_key = cache_key
|
||||
cls.cached = {}
|
||||
else:
|
||||
result = cls.cached.get((level_id, mode), None)
|
||||
if result is not None:
|
||||
return result
|
||||
from c3nav.mapdata.models import MapUpdate
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
if getattr(cls.cached, 'cache_key', None) != cache_key:
|
||||
cls.cached.key = cache_key
|
||||
cls.cached.data = {}
|
||||
else:
|
||||
result = cls.cached.data.get((level_id, mode), None)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
result = cls.open_level(level_id, mode)
|
||||
cls.cached[(level_id, mode)] = result
|
||||
return result
|
||||
result = cls.open_level(level_id, mode)
|
||||
cls.cached.data[(level_id, mode)] = result
|
||||
return result
|
||||
|
|
1
src/c3nav/mapdata/utils/cache/local.py
vendored
1
src/c3nav/mapdata/utils/cache/local.py
vendored
|
@ -12,6 +12,7 @@ class NoneFromCache:
|
|||
class LocalCacheProxy:
|
||||
# django cache, buffered using a LRU cache
|
||||
# only usable for stuff that never changes, obviously
|
||||
# todo: ensure thread-safety, compatible with async + daphne etc
|
||||
def __init__(self, maxsize=128):
|
||||
self._maxsize = maxsize
|
||||
self._mapupdate = None
|
||||
|
|
31
src/c3nav/mapdata/utils/cache/package.py
vendored
31
src/c3nav/mapdata/utils/cache/package.py
vendored
|
@ -1,15 +1,19 @@
|
|||
import os
|
||||
import struct
|
||||
import threading
|
||||
from collections import namedtuple
|
||||
from io import BytesIO
|
||||
from tarfile import TarFile, TarInfo
|
||||
from typing import BinaryIO
|
||||
from typing import BinaryIO, Self
|
||||
|
||||
from pyzstd import CParameter, ZstdError, ZstdFile
|
||||
|
||||
from c3nav.mapdata.utils.cache import AccessRestrictionAffected, GeometryIndexed, MapHistory
|
||||
|
||||
try:
|
||||
from asgiref.local import Local as LocalContext
|
||||
except ImportError:
|
||||
from threading import local as LocalContext
|
||||
|
||||
ZSTD_MAGIC_NUMBER = b"\x28\xb5\x2f\xfd"
|
||||
CachePackageLevel = namedtuple('CachePackageLevel', ('history', 'restrictions'))
|
||||
|
||||
|
@ -109,23 +113,20 @@ class CachePackage:
|
|||
package = settings.CACHE_ROOT / 'package.tar'
|
||||
return cls.read(package.open('rb'))
|
||||
|
||||
cached = None
|
||||
cache_key = None
|
||||
cache_lock = threading.Lock()
|
||||
cached = LocalContext()
|
||||
|
||||
@classmethod
|
||||
def open_cached(cls):
|
||||
with cls.cache_lock:
|
||||
from c3nav.mapdata.models import MapUpdate
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
if cls.cache_key != cache_key:
|
||||
cls.cache_key = cache_key
|
||||
cls.cached = None
|
||||
def open_cached(cls) -> Self:
|
||||
from c3nav.mapdata.models import MapUpdate
|
||||
cache_key = MapUpdate.current_processed_cache_key()
|
||||
if getattr(cls.cached, 'cache_key', None) != cache_key:
|
||||
cls.cached.key = cache_key
|
||||
cls.cached.data = None
|
||||
|
||||
if cls.cached is None:
|
||||
cls.cached = cls.open()
|
||||
if cls.cached.data is None:
|
||||
cls.cached.data = cls.open()
|
||||
|
||||
return cls.cached
|
||||
return cls.cached.data
|
||||
|
||||
def bounds_valid(self, minx, miny, maxx, maxy):
|
||||
return (minx <= self.bounds[2] and maxx >= self.bounds[0] and
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue