Fixed chunk and preview cache usage (#5569)

main
Andrey Zhavoronkov 3 years ago committed by GitHub
parent 11e398d391
commit 6c3e3c98a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Helm: Empty password for Redis (<https://github.com/opencv/cvat/pull/5520>) - Helm: Empty password for Redis (<https://github.com/opencv/cvat/pull/5520>)
- Preview & chunk cache settings are ignored (<https://github.com/opencv/cvat/pull/5569>)
### Security ### Security
- Fixed vulnerability with social authentication (<https://github.com/opencv/cvat/pull/5521>) - Fixed vulnerability with social authentication (<https://github.com/opencv/cvat/pull/5521>)

@ -8,7 +8,7 @@ from datetime import datetime
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import pytz import pytz
from diskcache import Cache from django.core.cache import cache
from django.conf import settings from django.conf import settings
from rest_framework.exceptions import ValidationError, NotFound from rest_framework.exceptions import ValidationError, NotFound
@ -25,42 +25,42 @@ from cvat.apps.engine.mime_types import mimetypes
from utils.dataset_manifest import ImageManifestManager from utils.dataset_manifest import ImageManifestManager
class CacheInteraction: class MediaCache:
def __init__(self, dimension=DimensionType.DIM_2D): def __init__(self, dimension=DimensionType.DIM_2D):
self._cache = Cache(settings.CACHE_ROOT)
self._dimension = dimension self._dimension = dimension
def __del__(self): @staticmethod
self._cache.close() def _get_or_set_cache_item(key, create_function):
item = cache.get(key)
if not item:
item = create_function()
cache.set(key, item)
def get_buf_chunk_with_mime(self, chunk_number, quality, db_data): return item
cache_key = f'{db_data.id}_{chunk_number}_{quality}'
chunk, tag = self._cache.get(cache_key, tag=True)
if not chunk: def get_buf_chunk_with_mime(self, chunk_number, quality, db_data):
chunk, tag = self._prepare_chunk_buff(db_data, quality, chunk_number) item = self._get_or_set_cache_item(
self._cache.set(cache_key, chunk, tag=tag) key=f'{db_data.id}_{chunk_number}_{quality}',
create_function=lambda: self._prepare_chunk_buff(db_data, quality, chunk_number),
)
return chunk, tag return item
def get_local_preview_with_mime(self, frame_number, db_data): def get_local_preview_with_mime(self, frame_number, db_data):
key = f'data_{db_data.id}_{frame_number}_preview' item = self._get_or_set_cache_item(
buf, mime = self._cache.get(key, tag=True) key=f'data_{db_data.id}_{frame_number}_preview',
if not buf: create_function=lambda: self._prepare_local_preview(frame_number, db_data),
buf, mime = self._prepare_local_preview(frame_number, db_data) )
self._cache.set(key, buf, tag=mime)
return buf, mime return item
def get_cloud_preview_with_mime(self, db_storage): def get_cloud_preview_with_mime(self, db_storage):
key = f'cloudstorage_{db_storage.id}_preview' item = self._get_or_set_cache_item(
preview, mime = self._cache.get(key, tag=True) key=f'cloudstorage_{db_storage.id}_preview',
create_function=lambda: self._prepare_cloud_preview(db_storage)
)
if not preview: return item
preview, mime = self._prepare_cloud_preview(db_storage)
self._cache.set(key, preview, tag=mime)
return preview, mime
@staticmethod @staticmethod
def _get_frame_provider(): def _get_frame_provider():
@ -147,9 +147,9 @@ class CacheInteraction:
def _prepare_local_preview(self, frame_number, db_data): def _prepare_local_preview(self, frame_number, db_data):
FrameProvider = self._get_frame_provider() FrameProvider = self._get_frame_provider()
frame_provider = FrameProvider(db_data, self._dimension) frame_provider = FrameProvider(db_data, self._dimension)
buf, mime = frame_provider.get_preview(frame_number) buff, mime_type = frame_provider.get_preview(frame_number)
return buf, mime return buff, mime_type
def _prepare_cloud_preview(self, db_storage): def _prepare_cloud_preview(self, db_storage):
storage = db_storage_to_storage_instance(db_storage) storage = db_storage_to_storage_instance(db_storage)
@ -179,7 +179,7 @@ class CacheInteraction:
slogger.cloud_storage[db_storage.pk].info(msg) slogger.cloud_storage[db_storage.pk].info(msg)
raise NotFound(msg) raise NotFound(msg)
preview = storage.download_fileobj(preview_path) buff = storage.download_fileobj(preview_path)
mime = mimetypes.guess_type(preview_path)[0] mime_type = mimetypes.guess_type(preview_path)[0]
return preview, mime return buff, mime_type

@ -12,7 +12,7 @@ import cv2
import numpy as np import numpy as np
from PIL import Image from PIL import Image
from cvat.apps.engine.cache import CacheInteraction from cvat.apps.engine.cache import MediaCache
from cvat.apps.engine.media_extractors import VideoReader, ZipReader from cvat.apps.engine.media_extractors import VideoReader, ZipReader
from cvat.apps.engine.mime_types import mimetypes from cvat.apps.engine.mime_types import mimetypes
from cvat.apps.engine.models import DataChoice, StorageMethodChoice, DimensionType from cvat.apps.engine.models import DataChoice, StorageMethodChoice, DimensionType
@ -97,7 +97,7 @@ class FrameProvider:
} }
if db_data.storage_method == StorageMethodChoice.CACHE: if db_data.storage_method == StorageMethodChoice.CACHE:
cache = CacheInteraction(dimension=dimension) cache = MediaCache(dimension=dimension)
self._loaders[self.Quality.COMPRESSED] = self.BuffChunkLoader( self._loaders[self.Quality.COMPRESSED] = self.BuffChunkLoader(
reader_class[db_data.compressed_chunk_type], reader_class[db_data.compressed_chunk_type],

@ -75,7 +75,7 @@ from .log import clogger, slogger
from cvat.apps.iam.permissions import (CloudStoragePermission, from cvat.apps.iam.permissions import (CloudStoragePermission,
CommentPermission, IssuePermission, JobPermission, ProjectPermission, CommentPermission, IssuePermission, JobPermission, ProjectPermission,
TaskPermission, UserPermission) TaskPermission, UserPermission)
from cvat.apps.engine.cache import CacheInteraction from cvat.apps.engine.cache import MediaCache
@extend_schema(tags=['server']) @extend_schema(tags=['server'])
@ -721,7 +721,7 @@ class DataChunkGetter:
f'[{start}, {stop}] range') f'[{start}, {stop}] range')
if self.type == 'preview': if self.type == 'preview':
cache = CacheInteraction(self.dimension) cache = MediaCache(self.dimension)
buf, mime = cache.get_local_preview_with_mime(self.number, db_data) buf, mime = cache.get_local_preview_with_mime(self.number, db_data)
else: else:
buf, mime = frame_provider.get_frame(self.number, self.quality) buf, mime = frame_provider.get_frame(self.number, self.quality)
@ -2185,7 +2185,7 @@ class CloudStorageViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
def preview(self, request, pk): def preview(self, request, pk):
try: try:
db_storage = self.get_object() db_storage = self.get_object()
cache = CacheInteraction() cache = MediaCache()
preview, mime = cache.get_cloud_preview_with_mime(db_storage) preview, mime = cache.get_cloud_preview_with_mime(db_storage)
return HttpResponse(preview, mime) return HttpResponse(preview, mime)
except CloudStorageModel.DoesNotExist: except CloudStorageModel.DoesNotExist:

@ -514,6 +514,7 @@ CACHES = {
'BACKEND' : 'diskcache.DjangoCache', 'BACKEND' : 'diskcache.DjangoCache',
'LOCATION' : CACHE_ROOT, 'LOCATION' : CACHE_ROOT,
'TIMEOUT' : None, 'TIMEOUT' : None,
'SHARDS': 32,
'OPTIONS' : { 'OPTIONS' : {
'size_limit' : 2 ** 40, # 1 Tb 'size_limit' : 2 ** 40, # 1 Tb
} }

Loading…
Cancel
Save