-
Notifications
You must be signed in to change notification settings - Fork 1
352 DB limitation #427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
352 DB limitation #427
Changes from 8 commits
9a5e998
3a58841
927930f
8a20911
8802224
1d4e949
dcdab5b
fdf1bef
489a3fd
f7011df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
| from gridfs import GridFSBucket, NoFile | ||
| from pymodm import connect | ||
| from pymodm.connection import _get_db | ||
| from pymodm.errors import ValidationError | ||
| from pymodm.errors import ValidationError, DoesNotExist | ||
| from pymodm.files import GridFSStorage | ||
| from pymongo import ReturnDocument | ||
| from pymongo.errors import CollectionInvalid | ||
|
|
@@ -23,26 +23,35 @@ | |
| RecognizedAudioToProcess, | ||
| RecognizedPresentationsToProcess, Sessions, | ||
| TaskAttempts, TaskAttemptsToPassBack, Tasks, | ||
| Trainings, TrainingsToProcess) | ||
| Trainings, TrainingsToProcess, StorageMeta) | ||
| from app.status import (AudioStatus, PassBackStatus, PresentationStatus, | ||
| TrainingStatus) | ||
| from app.utils import remove_blank_and_none | ||
|
|
||
| logger = get_root_logger() | ||
|
|
||
|
|
||
| BYTES_PER_MB = 1024*1024 | ||
|
|
||
| class DBManager: | ||
| def __new__(cls): | ||
| def __new__(cls, max_size=20000): # max_size only on first creation, in MB | ||
|
||
| if not hasattr(cls, 'init_done'): | ||
| cls.instance = super(DBManager, cls).__new__(cls) | ||
| connect(Config.c.mongodb.url + Config.c.mongodb.database_name) | ||
| cls.instance.storage = GridFSStorage(GridFSBucket(_get_db())) | ||
| cls.instance.max_size = max_size * BYTES_PER_MB | ||
| cls.init_done = True | ||
| return cls.instance | ||
|
|
||
| def add_file(self, file, filename=uuid.uuid4()): | ||
| return self.storage.save(name=filename, content=file) | ||
| try: | ||
| file.seek(0, os.SEEK_END) | ||
| size = file.tell() | ||
| file.seek(0) | ||
| except: | ||
| size = len(file) | ||
| _id = self.storage.save(name=filename, content=file) | ||
| self.update_storage_size(size) | ||
| return _id | ||
|
|
||
| def read_and_add_file(self, path, filename=None): | ||
| if filename is None: | ||
|
|
@@ -67,6 +76,41 @@ def get_file(self, file_id): | |
| except (NoFile, ValidationError, InvalidId) as e: | ||
| logger.warning('file_id = {}, {}.'.format(file_id, e)) | ||
| return None | ||
|
|
||
| def _get_or_create_storage_meta(self): | ||
| try: | ||
| return StorageMeta.objects.get({}) | ||
| except DoesNotExist: | ||
| meta = StorageMeta(used_size=0).save() | ||
| return meta | ||
|
|
||
| def get_used_storage_size(self): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. добавьте метод для актуализации данных (вдруг где-то логика дала сбой и насчитала нам что-то, или вручную из бд были удалены файлы) - ему нужно будет пройтись по всем документам и посчитать их общий вес
|
||
| return self._get_or_create_storage_meta().used_size | ||
|
|
||
| def set_used_storage_size(self, size): | ||
| meta = self._get_or_create_storage_meta() | ||
| meta.used_size = size | ||
| meta.save() | ||
|
|
||
| def update_storage_size(self, deltasize): | ||
| meta = self._get_or_create_storage_meta() | ||
| meta.used_size += deltasize | ||
| meta.save() | ||
|
|
||
| def get_max_size(self): | ||
| return self.max_size | ||
|
|
||
| # returns Bool variable - True if file can be stored else False | ||
| def check_storage_limit(self, new_file_size): | ||
| current_size = self.get_used_storage_size() | ||
| inf_msg = ( | ||
| f"Check for ability to add file: " | ||
| f"Current: {current_size/BYTES_PER_MB:.2f} MB, " | ||
| f"New file: {new_file_size/BYTES_PER_MB:.2f} MB, " | ||
| f"Storage size: {self.max_size/BYTES_PER_MB} MB" | ||
| ) | ||
| logger.info(inf_msg) | ||
| return False if current_size + new_file_size > self.max_size else True | ||
|
|
||
|
|
||
| class TrainingsDBManager: | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Добавьте ссылку на эту страницу в /admin |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| from flask import Blueprint, render_template | ||
| from app.mongo_odm import DBManager | ||
| from app.root_logger import get_root_logger | ||
| from app.lti_session_passback.auth_checkers import is_admin | ||
|
|
||
| logger = get_root_logger() | ||
|
|
||
| BYTES_PER_MB = 1024*1024 | ||
|
|
||
| routes_capacity = Blueprint( | ||
| 'routes_capacity', __name__, url_prefix='/capacity') | ||
|
|
||
| @routes_capacity.route('/', methods=['GET']) | ||
| def storage_capacity(): | ||
| if not is_admin(): | ||
| return {}, 404 | ||
| current_size = DBManager().get_used_storage_size() | ||
| max_size = DBManager().get_max_size() | ||
| ratio = current_size / max_size | ||
| return render_template( | ||
| 'capacity.html', | ||
| size=round(current_size / BYTES_PER_MB, 2), | ||
| max_size=round(max_size / BYTES_PER_MB, 2), | ||
| ratio=round(ratio * 100, 1) | ||
| ) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| {% extends 'base.html' %} | ||
|
|
||
| {% block content %} | ||
| <div class="container mt-4"> | ||
| <div class="card"> | ||
| <div class="card-body"> | ||
| <h4 class="card-title">Загруженность Базы Данных</h4> | ||
| <p><strong>Использовано:</strong> {{ size }} Мбайт</p> | ||
| <p><strong>Максимум:</strong> {{ max_size }} Мбайт</p> | ||
| <p><strong>Заполнено:</strong> {{ ratio }}%</p> | ||
| <div class="progress"> | ||
| <div class="progress-bar" role="progressbar" style="width: {{ ratio }}%;" aria-valuenow="{{ ratio }}" aria-valuemin="0" aria-valuemax="100"> | ||
| {{ ratio }} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| {% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Измените код на 413 (он тут более логичен - в 146 строчке тоже обновите) и добавьте обработку этой ошибки на клиенте - чтобы пользователь не гадал что и как сломалось (для случая переполнения БД добавьте сообщение, что необходимо обратиться по почте - она есть в конфиге в разделе bugreport)