MTP: only populate driveinfo during the fetching of the book lists so that the get_device_information() job is not slow

This commit is contained in:
Kovid Goyal 2012-09-12 15:26:08 +05:30
parent c0aee6772d
commit 5008cc5d92
6 changed files with 45 additions and 7 deletions

View File

@ -95,6 +95,10 @@ class DevicePlugin(Plugin):
#: call post_yank_cleanup(). #: call post_yank_cleanup().
MANAGES_DEVICE_PRESENCE = False MANAGES_DEVICE_PRESENCE = False
#: If set the True, calibre will call the :method:`get_driveinfo()` method
#: after the books lists have been loaded to get the driveinfo.
SLOW_DRIVEINFO = False
@classmethod @classmethod
def get_gui_name(cls): def get_gui_name(cls):
if hasattr(cls, 'gui_name'): if hasattr(cls, 'gui_name'):
@ -352,6 +356,18 @@ class DevicePlugin(Plugin):
""" """
raise NotImplementedError() raise NotImplementedError()
def get_driveinfo(self):
'''
Return the driveinfo dictionary. Usually called from
get_device_information(), but if loading the driveinfo is slow for this
driver, then it should set SLOW_DRIVEINFO. In this case, this method
will be called by calibre after the book lists have been loaded. Note
that it is not called on the device thread, so the driver should cache
the drive info in the books() method and this function should return
the cached data.
'''
return {}
def card_prefix(self, end_session=True): def card_prefix(self, end_session=True):
''' '''
Return a 2 element list of the prefix to paths on the cards. Return a 2 element list of the prefix to paths on the cards.

View File

@ -35,6 +35,7 @@ class MTP_DEVICE(BASE):
MANAGES_DEVICE_PRESENCE = True MANAGES_DEVICE_PRESENCE = True
FORMATS = ['epub', 'azw3', 'mobi', 'pdf'] FORMATS = ['epub', 'azw3', 'mobi', 'pdf']
DEVICE_PLUGBOARD_NAME = 'MTP_DEVICE' DEVICE_PLUGBOARD_NAME = 'MTP_DEVICE'
SLOW_DRIVEINFO = True
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
BASE.__init__(self, *args, **kwargs) BASE.__init__(self, *args, **kwargs)
@ -76,6 +77,7 @@ class MTP_DEVICE(BASE):
def open(self, devices, library_uuid): def open(self, devices, library_uuid):
self.current_library_uuid = library_uuid self.current_library_uuid = library_uuid
self.location_paths = None self.location_paths = None
self.driveinfo = {}
BASE.open(self, devices, library_uuid) BASE.open(self, devices, library_uuid)
h = self.prefs['history'] h = self.prefs['history']
if self.current_serial_num: if self.current_serial_num:
@ -109,13 +111,17 @@ class MTP_DEVICE(BASE):
self.put_file(storage, self.DRIVEINFO, BytesIO(raw), len(raw)) self.put_file(storage, self.DRIVEINFO, BytesIO(raw), len(raw))
self.driveinfo[location_code] = dinfo self.driveinfo[location_code] = dinfo
def get_device_information(self, end_session=True): def get_driveinfo(self):
self.report_progress(1.0, _('Get device information...')) if not self.driveinfo:
self.driveinfo = {} self.driveinfo = {}
for sid, location_code in ( (self._main_id, 'main'), (self._carda_id, for sid, location_code in ( (self._main_id, 'main'), (self._carda_id,
'A'), (self._cardb_id, 'B')): 'A'), (self._cardb_id, 'B')):
if sid is None: continue if sid is None: continue
self._update_drive_info(self.filesystem_cache.storage(sid), location_code) self._update_drive_info(self.filesystem_cache.storage(sid), location_code)
return self.driveinfo
def get_device_information(self, end_session=True):
self.report_progress(1.0, _('Get device information...'))
dinfo = self.get_basic_device_information() dinfo = self.get_basic_device_information()
return tuple( list(dinfo) + [self.driveinfo] ) return tuple( list(dinfo) + [self.driveinfo] )
@ -135,6 +141,7 @@ class MTP_DEVICE(BASE):
def books(self, oncard=None, end_session=True): def books(self, oncard=None, end_session=True):
from calibre.devices.mtp.books import JSONCodec from calibre.devices.mtp.books import JSONCodec
from calibre.devices.mtp.books import BookList, Book from calibre.devices.mtp.books import BookList, Book
self.get_driveinfo() # Ensure driveinfo is loaded
sid = {'carda':self._carda_id, 'cardb':self._cardb_id}.get(oncard, sid = {'carda':self._carda_id, 'cardb':self._cardb_id}.get(oncard,
self._main_id) self._main_id)
if sid is None: if sid is None:

View File

@ -230,6 +230,9 @@ class FilesystemCache(object):
continue # Ignore .txt files in the root continue # Ignore .txt files in the root
yield x yield x
def __len__(self):
return len(self.id_map)
def resolve_mtp_id_path(self, path): def resolve_mtp_id_path(self, path):
if not path.startswith('mtp:::'): if not path.startswith('mtp:::'):
raise ValueError('%s is not a valid MTP path'%path) raise ValueError('%s is not a valid MTP path'%path)

View File

@ -222,7 +222,8 @@ class MTP_DEVICE(MTPDeviceBase):
self.current_friendly_name, self.current_friendly_name,
self.format_errorstack(all_errs))) self.format_errorstack(all_errs)))
self._filesystem_cache = FilesystemCache(storage, all_items) self._filesystem_cache = FilesystemCache(storage, all_items)
debug('Filesystem metadata loaded in %g seconds'%(time.time()-st)) debug('Filesystem metadata loaded in %g seconds (%d objects)'%(
time.time()-st, len(self._filesystem_cache)))
return self._filesystem_cache return self._filesystem_cache
@synchronous @synchronous

View File

@ -220,7 +220,8 @@ class MTP_DEVICE(MTPDeviceBase):
all_storage.append(storage) all_storage.append(storage)
items.append(id_map.itervalues()) items.append(id_map.itervalues())
self._filesystem_cache = FilesystemCache(all_storage, chain(*items)) self._filesystem_cache = FilesystemCache(all_storage, chain(*items))
debug('Filesystem metadata loaded in %g seconds'%(time.time()-st)) debug('Filesystem metadata loaded in %g seconds (%d objects)'%(
time.time()-st, len(self._filesystem_cache)))
return self._filesystem_cache return self._filesystem_cache
@same_thread @same_thread

View File

@ -433,6 +433,15 @@ class DeviceManager(Thread): # {{{
return self.create_job_step(self._get_device_information, done, return self.create_job_step(self._get_device_information, done,
description=_('Get device information'), to_job=add_as_step_to_job) description=_('Get device information'), to_job=add_as_step_to_job)
def slow_driveinfo(self):
''' Update the stored device information with the driveinfo if the
device indicates that getting driveinfo is slow '''
info = self._device_information['info']
if (not info[4] and self.device.SLOW_DRIVEINFO):
info = list(info)
info[4] = self.device.get_driveinfo()
self._device_information['info'] = tuple(info)
def get_current_device_information(self): def get_current_device_information(self):
return self._device_information return self._device_information
@ -1023,6 +1032,7 @@ class DeviceMixin(object): # {{{
if job.failed: if job.failed:
self.device_job_exception(job) self.device_job_exception(job)
return return
self.device_manager.slow_driveinfo()
# set_books_in_library might schedule a sync_booklists job # set_books_in_library might schedule a sync_booklists job
self.set_books_in_library(job.result, reset=True, add_as_step_to_job=job) self.set_books_in_library(job.result, reset=True, add_as_step_to_job=job)
mainlist, cardalist, cardblist = job.result mainlist, cardalist, cardblist = job.result