mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -04:00
...
This commit is contained in:
parent
9d041c7969
commit
c51a171384
@ -7,9 +7,33 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
from calibre.db.locking import create_locks
|
from calibre.db.locking import create_locks
|
||||||
from calibre.db.fields import create_field
|
from calibre.db.fields import create_field
|
||||||
|
|
||||||
|
def api(f):
|
||||||
|
f.is_cache_api = True
|
||||||
|
return f
|
||||||
|
|
||||||
|
def read_api(f):
|
||||||
|
f = api(f)
|
||||||
|
f.is_read_api = True
|
||||||
|
return f
|
||||||
|
|
||||||
|
def write_api(f):
|
||||||
|
f = api(f)
|
||||||
|
f.is_read_api = False
|
||||||
|
return f
|
||||||
|
|
||||||
|
def wrap_simple(lock, func):
|
||||||
|
@wraps(func)
|
||||||
|
def ans(*args, **kwargs):
|
||||||
|
with lock:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
class Cache(object):
|
class Cache(object):
|
||||||
|
|
||||||
def __init__(self, backend):
|
def __init__(self, backend):
|
||||||
@ -17,14 +41,100 @@ class Cache(object):
|
|||||||
self.fields = {}
|
self.fields = {}
|
||||||
self.read_lock, self.write_lock = create_locks()
|
self.read_lock, self.write_lock = create_locks()
|
||||||
|
|
||||||
|
# Implement locking for all simple read/write API methods
|
||||||
|
# An unlocked version of the method is stored with the name starting
|
||||||
|
# with a leading underscore. Use the unlocked versions when the lock
|
||||||
|
# has already been acquired.
|
||||||
|
for name in dir(self):
|
||||||
|
func = getattr(self, name)
|
||||||
|
ira = getattr(func, 'is_read_api', None)
|
||||||
|
if ira is not None:
|
||||||
|
# Save original function
|
||||||
|
setattr(self, '_'+name, func)
|
||||||
|
# Wrap it in a lock
|
||||||
|
lock = self.read_lock if ira else self.write_lock
|
||||||
|
setattr(self, name, wrap_simple(lock, func))
|
||||||
|
|
||||||
# Cache Layer API {{{
|
# Cache Layer API {{{
|
||||||
|
|
||||||
|
@api
|
||||||
def init(self):
|
def init(self):
|
||||||
|
'''
|
||||||
|
Initialize this cache with data from the backend.
|
||||||
|
'''
|
||||||
with self.write_lock:
|
with self.write_lock:
|
||||||
self.backend.read_tables()
|
self.backend.read_tables()
|
||||||
|
|
||||||
for field, table in self.backend.tables.iteritems():
|
for field, table in self.backend.tables.iteritems():
|
||||||
self.fields[field] = create_field(field, table)
|
self.fields[field] = create_field(field, table)
|
||||||
|
|
||||||
|
@read_api
|
||||||
|
def field_for(self, name, book_id, default_value=None):
|
||||||
|
'''
|
||||||
|
Return the value of the field ``name`` for the book identified by
|
||||||
|
``book_id``. If no such book exists or it has no defined value for the
|
||||||
|
field ``name`` or no such field exists, then ``default_value`` is returned.
|
||||||
|
|
||||||
|
The returned value for is_multiple fields are always tuples.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
return self.fields[name].for_book(book_id, default_value=default_value)
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
return default_value
|
||||||
|
|
||||||
|
@read_api
|
||||||
|
def field_ids_for(self, name, book_id):
|
||||||
|
'''
|
||||||
|
Return the ids (as a tuple) for the values that the field ``name`` has on the book
|
||||||
|
identified by ``book_id``. If there are no values, or no such book, or
|
||||||
|
no such field, an empty tuple is returned.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
return self.fields[name].ids_for_book(book_id)
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
return ()
|
||||||
|
|
||||||
|
@read_api
|
||||||
|
def books_for_field(self, name, item_id):
|
||||||
|
'''
|
||||||
|
Return all the books associated with the item identified by
|
||||||
|
``item_id``, where the item belongs to the field ``name``.
|
||||||
|
|
||||||
|
Returned value is a tuple of book ids, or the empty tuple if the item
|
||||||
|
or the field does not exist.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
return self.fields[name].books_for(item_id)
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
return ()
|
||||||
|
|
||||||
|
@read_api
|
||||||
|
def all_book_ids(self):
|
||||||
|
'''
|
||||||
|
Frozen set of all known book ids.
|
||||||
|
'''
|
||||||
|
return frozenset(self.fields['uuid'].iter_book_ids())
|
||||||
|
|
||||||
|
@read_api
|
||||||
|
def all_field_ids(self, name):
|
||||||
|
'''
|
||||||
|
Frozen set of ids for all values in the field ``name``.
|
||||||
|
'''
|
||||||
|
return frozenset(iter(self.fields[name]))
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
# Testing {{{
|
||||||
|
|
||||||
|
def test(library_path):
|
||||||
|
from calibre.db.backend import DB
|
||||||
|
backend = DB(library_path)
|
||||||
|
cache = Cache(backend)
|
||||||
|
cache.init()
|
||||||
|
print ('All book ids:', cache.all_book_ids())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from calibre.utils.config import prefs
|
||||||
|
test(prefs['library_path'])
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
@ -63,6 +63,9 @@ class OneToOneField(Field):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self.table.book_col_map.iterkeys()
|
return self.table.book_col_map.iterkeys()
|
||||||
|
|
||||||
|
def iter_book_ids(self):
|
||||||
|
return self.table.book_col_map.iterkeys()
|
||||||
|
|
||||||
class ManyToOneField(Field):
|
class ManyToOneField(Field):
|
||||||
|
|
||||||
def for_book(self, book_id, default_value=None):
|
def for_book(self, book_id, default_value=None):
|
||||||
|
@ -110,8 +110,8 @@ class ManyToOneTable(Table):
|
|||||||
self.col_book_map[row[1]].append(row[0])
|
self.col_book_map[row[1]].append(row[0])
|
||||||
self.book_col_map[row[0]] = row[1]
|
self.book_col_map[row[0]] = row[1]
|
||||||
|
|
||||||
for key, val in self.col_book_map:
|
for key in tuple(self.col_book_map.iterkeys()):
|
||||||
self.col_book_map[key] = tuple(val)
|
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||||
|
|
||||||
class ManyToManyTable(ManyToOneTable):
|
class ManyToManyTable(ManyToOneTable):
|
||||||
|
|
||||||
@ -134,20 +134,21 @@ class ManyToManyTable(ManyToOneTable):
|
|||||||
self.book_col_map[row[0]] = []
|
self.book_col_map[row[0]] = []
|
||||||
self.book_col_map[row[0]].append(row[1])
|
self.book_col_map[row[0]].append(row[1])
|
||||||
|
|
||||||
for key, val in self.col_book_map:
|
for key in tuple(self.col_book_map.iterkeys()):
|
||||||
self.col_book_map[key] = tuple(val)
|
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||||
|
|
||||||
for key, val in self.book_col_map:
|
for key in tuple(self.book_col_map.iterkeys()):
|
||||||
self.book_col_map[key] = tuple(val)
|
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||||
|
|
||||||
class AuthorsTable(ManyToManyTable):
|
class AuthorsTable(ManyToManyTable):
|
||||||
|
|
||||||
def read_id_maps(self, db):
|
def read_id_maps(self, db):
|
||||||
self.alink_map = {}
|
self.alink_map = {}
|
||||||
|
self.sort_map = {}
|
||||||
for row in db.conn.execute(
|
for row in db.conn.execute(
|
||||||
'SELECT id, name, sort, link FROM authors'):
|
'SELECT id, name, sort, link FROM authors'):
|
||||||
self.id_map[row[0]] = row[1]
|
self.id_map[row[0]] = row[1]
|
||||||
self.extra_map[row[0]] = (row[2] if row[2] else
|
self.sort_map[row[0]] = (row[2] if row[2] else
|
||||||
author_to_author_sort(row[1]))
|
author_to_author_sort(row[1]))
|
||||||
self.alink_map[row[0]] = row[3]
|
self.alink_map[row[0]] = row[3]
|
||||||
|
|
||||||
@ -166,11 +167,11 @@ class FormatsTable(ManyToManyTable):
|
|||||||
self.book_col_map[row[0]] = []
|
self.book_col_map[row[0]] = []
|
||||||
self.book_col_map[row[0]].append((row[1], row[2]))
|
self.book_col_map[row[0]].append((row[1], row[2]))
|
||||||
|
|
||||||
for key, val in self.col_book_map:
|
for key in tuple(self.col_book_map.iterkeys()):
|
||||||
self.col_book_map[key] = tuple(val)
|
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||||
|
|
||||||
for key, val in self.book_col_map:
|
for key in tuple(self.book_col_map.iterkeys()):
|
||||||
self.book_col_map[key] = tuple(val)
|
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||||
|
|
||||||
class IdentifiersTable(ManyToManyTable):
|
class IdentifiersTable(ManyToManyTable):
|
||||||
|
|
||||||
@ -187,9 +188,9 @@ class IdentifiersTable(ManyToManyTable):
|
|||||||
self.book_col_map[row[0]] = []
|
self.book_col_map[row[0]] = []
|
||||||
self.book_col_map[row[0]].append((row[1], row[2]))
|
self.book_col_map[row[0]].append((row[1], row[2]))
|
||||||
|
|
||||||
for key, val in self.col_book_map:
|
for key in tuple(self.col_book_map.iterkeys()):
|
||||||
self.col_book_map[key] = tuple(val)
|
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||||
|
|
||||||
for key, val in self.book_col_map:
|
for key in tuple(self.book_col_map.iterkeys()):
|
||||||
self.book_col_map[key] = tuple(val)
|
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user