fix: disk loader not fiiling all requested cached data from the disk

This commit is contained in:
Vinicius Moreira
2019-09-17 13:11:22 -03:00
parent bfd947043c
commit 16e55c9613
7 changed files with 56 additions and 33 deletions

View File

@@ -15,11 +15,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- "Application settings" button located in right lower corner
- Package "Name" filter field (above the packages table)
- Showing the number of packages being shown by the total found
- "Show" button for large fields of the "Info" window
### Improvements:
- Reading installed Snaps now takes around 95% less time
- Reading installed Flatpaks now takes around 45% less time
- Refreshing only the associated package type after a successful operation (install, uninstall, downgrade, ...)
- When a package is installed, it will be the first element of the table after refreshing
- Progress bar status can now be controlled by the software manager while an operation is being executed
- Flatpak: showing runtime branches as versions when they are not available
@@ -32,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixes:
- cached Flatpak app current version
- disk loader not filling all requested cached data from the disk
### Code
- Code was internally modularized as: "api" (conceptual classes used to create custom software managers), "gems" (software managers), "commons" (common classes shared between the UI and "gems")

View File

@@ -30,7 +30,7 @@ context = ApplicationContext(i18n=i18n,
download_icons=args.download_icons,
app_root_dir=ROOT_DIR,
cache_factory=cache_factory,
disk_loader_factory=DefaultDiskCacheLoaderFactory(disk_cache_enabled=args.disk_cache),
disk_loader_factory=DefaultDiskCacheLoaderFactory(disk_cache_enabled=args.disk_cache, logger=logger),
logger=logger)
user_config = config.read()

View File

@@ -1,3 +1,4 @@
import time
from argparse import Namespace
from threading import Thread
from typing import List, Set, Type
@@ -20,6 +21,8 @@ class GenericSoftwareManager(SoftwareManager):
self.thread_prepare = None
self.i18n = context.i18n
self.disk_loader_factory = context.disk_loader_factory
self.logger = context.logger
self._already_prepared = []
def reset_cache(self):
if self._available_map is not None:
@@ -66,6 +69,7 @@ class GenericSoftwareManager(SoftwareManager):
res.new.extend(apps_found.new)
def search(self, word: str, disk_loader: DiskCacheLoader = None, limit: int = -1) -> SearchResult:
ti = time.time()
self._wait_to_be_ready()
res = SearchResult([], [], 0)
@@ -85,13 +89,15 @@ class GenericSoftwareManager(SoftwareManager):
t.join()
if disk_loader:
disk_loader.stop = True
disk_loader.stop_working()
disk_loader.join()
res.installed = self._sort(res.installed, norm_word)
res.new = self._sort(res.new, norm_word)
res.total = len(res.installed) + len(res.new)
tf = time.time()
self.logger.info('Took {0:.2f} seconds'.format(tf - ti))
return res
def _wait_to_be_ready(self):
@@ -106,6 +112,7 @@ class GenericSoftwareManager(SoftwareManager):
return True
def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
ti = time.time()
self._wait_to_be_ready()
res = SearchResult([], None, 0)
@@ -138,9 +145,11 @@ class GenericSoftwareManager(SoftwareManager):
res.total += man_res.total
if disk_loader:
disk_loader.stop = True
disk_loader.stop_working()
disk_loader.join()
tf = time.time()
self.logger.info('Took {0:.2f} seconds'.format(tf - ti))
return res
def downgrade(self, app: SoftwarePackage, root_password: str, handler: ProcessWatcher) -> bool:
@@ -221,8 +230,9 @@ class GenericSoftwareManager(SoftwareManager):
def _prepare(self):
if self.managers:
for man in self.managers:
if self._can_work(man):
if man not in self._already_prepared and self._can_work(man):
man.prepare()
self._already_prepared.append(man)
def prepare(self):
self.thread_prepare = Thread(target=self._prepare)

View File

@@ -100,13 +100,13 @@ class ArchManager(SoftwareManager):
if pkgsinfo:
for pkgdata in pkgsinfo:
app = self.mapper.map_api_data(pkgdata, not_signed)
app.downgrade_enabled = downgrade_enabled
pkg = self.mapper.map_api_data(pkgdata, not_signed)
pkg.downgrade_enabled = downgrade_enabled
if disk_loader:
disk_loader.fill(app)
app.status = PackageStatus.READY
disk_loader.fill(pkg)
pkg.status = PackageStatus.READY
apps.append(app)
apps.append(pkg)
def _fill_mirror_pkgs(self, mirrors: dict, apps: list):
# TODO
@@ -203,8 +203,8 @@ class ArchManager(SoftwareManager):
watcher.change_progress(50)
if info.get('required by'):
pkname = '"{}"'.format(pkg.name)
msg = '{}:\n\n{}\n\n{}'.format(self.i18n['arch.uninstall.required_by'].format(pkname), info['required by'], self.i18n['arch.uninstall.required_by.advice'].format(pkname))
pkname = bold(pkg.name)
msg = '{}:<br/><br/>{}<br/><br/>{}'.format(self.i18n['arch.uninstall.required_by'].format(pkname), bold(info['required by']), self.i18n['arch.uninstall.required_by.advice'].format(pkname))
watcher.show_message(title=self.i18n['error'], body=msg, type_=MessageType.WARNING)
return False
@@ -537,7 +537,6 @@ class ArchManager(SoftwareManager):
def prepare(self):
self.dcache_updater.start()
self.aur_index_updater.start()
def list_updates(self) -> List[PackageUpdate]:

View File

@@ -22,7 +22,6 @@ class AURIndexUpdater(Thread):
self.man = man
def run(self):
while True:
self.logger.info('Pre-indexing AUR packages in memory')
res = self.http_client.get(URL_INDEX)

View File

@@ -1,5 +1,7 @@
import json
import logging
import os
import time
from threading import Thread, Lock
from typing import Type, Dict
@@ -10,13 +12,15 @@ from bauh.api.abstract.model import SoftwarePackage
class AsyncDiskCacheLoader(Thread, DiskCacheLoader):
def __init__(self, enabled: bool, cache_map: Dict[Type[SoftwarePackage], MemoryCache]):
def __init__(self, enabled: bool, cache_map: Dict[Type[SoftwarePackage], MemoryCache], logger: logging.Logger):
super(AsyncDiskCacheLoader, self).__init__(daemon=True)
self.apps = []
self.stop = False
self.pkgs = []
self._work = True
self.lock = Lock()
self.cache_map = cache_map
self.enabled = enabled
self.logger = logger
self.processed = 0
def fill(self, pkg: SoftwarePackage):
"""
@@ -24,25 +28,28 @@ class AsyncDiskCacheLoader(Thread, DiskCacheLoader):
:param pkg:
:return:
"""
if self.enabled:
if pkg and pkg.supports_disk_cache():
self.lock.acquire()
self.apps.append(pkg)
self.lock.release()
if self.enabled and pkg and pkg.supports_disk_cache():
self.pkgs.append(pkg)
def stop_working(self):
self._work = False
def run(self):
if self.enabled:
last = 0
while True:
if self.apps:
self.lock.acquire()
app = self.apps[0]
del self.apps[0]
self.lock.release()
self._fill_cached_data(app)
elif self.stop:
time.sleep(0.00001)
if len(self.pkgs) > self.processed:
pkg = self.pkgs[last]
self._fill_cached_data(pkg)
self.processed += 1
last += 1
elif not self._work:
break
def _fill_cached_data(self, pkg: SoftwarePackage):
def _fill_cached_data(self, pkg: SoftwarePackage) -> bool:
if self.enabled:
if os.path.exists(pkg.get_disk_data_path()):
with open(pkg.get_disk_data_path()) as f:
@@ -54,12 +61,16 @@ class AsyncDiskCacheLoader(Thread, DiskCacheLoader):
if cache:
cache.add_non_existing(pkg.id, cached_data)
return True
return False
class DefaultDiskCacheLoaderFactory(DiskCacheLoaderFactory):
def __init__(self, disk_cache_enabled: bool):
def __init__(self, disk_cache_enabled: bool, logger: logging.Logger):
super(DefaultDiskCacheLoaderFactory, self).__init__()
self.disk_cache_enabled = disk_cache_enabled
self.logger = logger
self.cache_map = {}
def map(self, pkg_type: Type[SoftwarePackage], cache: MemoryCache):
@@ -68,4 +79,4 @@ class DefaultDiskCacheLoaderFactory(DiskCacheLoaderFactory):
self.cache_map[pkg_type] = cache
def new(self) -> AsyncDiskCacheLoader:
return AsyncDiskCacheLoader(enabled=self.disk_cache_enabled, cache_map=self.cache_map)
return AsyncDiskCacheLoader(enabled=self.disk_cache_enabled, cache_map=self.cache_map, logger=self.logger)

View File

@@ -5,7 +5,7 @@ from typing import List, Type, Set
from PyQt5.QtCore import QEvent, Qt, QSize, pyqtSignal
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap, QCursor
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QCheckBox, QHeaderView, QToolBar, \
QLabel, QPlainTextEdit, QLineEdit, QProgressBar, QPushButton, QComboBox, QMenu, QAction
QLabel, QPlainTextEdit, QLineEdit, QProgressBar, QPushButton, QComboBox, QMenu, QAction, QApplication
from bauh.api.abstract.cache import MemoryCache
from bauh.api.abstract.context import ApplicationContext
@@ -231,7 +231,8 @@ class ManageWindow(QWidget):
self.toolbar_bottom.addWidget(new_spacer())
self.progress_bar = QProgressBar()
self.progress_bar.setMaximumHeight(7)
self.progress_bar.setMaximumHeight(10 if QApplication.instance().style().objectName().lower() == 'windows' else 4)
self.progress_bar.setTextVisible(False)
self.ref_progress_bar = self.toolbar_bottom.addWidget(self.progress_bar)