Add function decorator to catch dabatase errors

svn: r13163
This commit is contained in:
Gerald Britton 2009-09-07 16:19:59 +00:00
parent be1aaf9f7b
commit 54d4bf6134

View File

@ -202,6 +202,20 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
self.secondary_connected = False self.secondary_connected = False
self.has_changed = False self.has_changed = False
def catch_db_error(func):
"""
Decorator function for catching database errors. If *func* throws
one of the exceptions in DBERRS, the error is logged and a DbError
exception is raised.
"""
def try_(*args, **kwargs):
try:
return func(*args, **kwargs)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
return try_
def __open_db(self, file_name, table_name, dbtype=db.DB_HASH, flags=0): def __open_db(self, file_name, table_name, dbtype=db.DB_HASH, flags=0):
dbmap = db.DB(self.env) dbmap = db.DB(self.env)
dbmap.set_pagesize(DBPAGE) dbmap.set_pagesize(DBPAGE)
@ -248,48 +262,34 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
# the referenced_handle index: the referenced_handle # the referenced_handle index: the referenced_handle
# the main index is unique, the others allow duplicate entries. # the main index is unique, the others allow duplicate entries.
@catch_db_error
def get_reference_map_cursor(self): def get_reference_map_cursor(self):
""" """
Returns a reference to a cursor over the reference map Returns a reference to a cursor over the reference map
""" """
try: return GrampsDBDirAssocCursor(self.reference_map, self.txn)
return GrampsDBDirAssocCursor(self.reference_map, self.txn)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
@catch_db_error
def get_reference_map_primary_cursor(self): def get_reference_map_primary_cursor(self):
""" """
Returns a reference to a cursor over the reference map primary map Returns a reference to a cursor over the reference map primary map
""" """
try: return GrampsDBDirAssocCursor(self.reference_map_primary_map,
return GrampsDBDirAssocCursor(self.reference_map_primary_map,
self.txn) self.txn)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
@catch_db_error
def get_reference_map_referenced_cursor(self): def get_reference_map_referenced_cursor(self):
""" """
Returns a reference to a cursor over the reference map referenced map Returns a reference to a cursor over the reference map referenced map
""" """
try: return GrampsDBDirAssocCursor(self.reference_map_referenced_map,
return GrampsDBDirAssocCursor(self.reference_map_referenced_map,
self.txn) self.txn)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
# These are overriding the GrampsDbRead's methods of saving metadata # These are overriding the GrampsDbRead's methods of saving metadata
# because we now have txn-capable metadata table # because we now have txn-capable metadata table
def set_default_person_handle(self, handle):
try:
return self.__set_default_person_handle(handle)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __set_default_person_handle(self, handle): @catch_db_error
def set_default_person_handle(self, handle):
"""Set the default Person to the passed instance.""" """Set the default Person to the passed instance."""
if not self.readonly: if not self.readonly:
# Start transaction # Start transaction
@ -297,14 +297,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
txn.put('default', str(handle)) txn.put('default', str(handle))
self.emit('home-person-changed') self.emit('home-person-changed')
@catch_db_error
def get_default_person(self): def get_default_person(self):
try:
return self.__get_default_person()
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __get_default_person(self):
"""Return the default Person of the database.""" """Return the default Person of the database."""
person = self.get_person_from_handle(self.get_default_handle()) person = self.get_person_from_handle(self.get_default_handle())
if person: if person:
@ -328,33 +322,15 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
with BSDDBTxn(self.env, self.metadata) as txn: with BSDDBTxn(self.env, self.metadata) as txn:
txn.put(name, col_list) txn.put(name, col_list)
@catch_db_error
def version_supported(self): def version_supported(self):
try: dbversion = self.metadata.get('version', default=0)
dbversion = self.metadata.get('version', default=0) return ((dbversion <= _DBVERSION) and (dbversion >= _MINVERSION))
return ((dbversion <= _DBVERSION) and (dbversion >= _MINVERSION))
except DBERRS, msg: @catch_db_error
self.__log_error()
raise Errors.DbError(msg)
def need_upgrade(self): def need_upgrade(self):
try: dbversion = self.metadata.get('version', default=0)
dbversion = self.metadata.get('version', default=0) return not self.readonly and dbversion < _DBVERSION
return not self.readonly and dbversion < _DBVERSION
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def load(self, name, callback, mode=DBMODE_W):
try:
if self.__check_readonly(name):
mode = DBMODE_R
else:
write_lock_file(name)
return self.__load(name, callback, mode)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __check_readonly(self, name): def __check_readonly(self, name):
""" """
@ -376,7 +352,13 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
# All tests passed. Inform caller that we are NOT read only # All tests passed. Inform caller that we are NOT read only
return False return False
def __load(self, name, callback, mode=DBMODE_W): @catch_db_error
def load(self, name, callback, mode=DBMODE_W):
if self.__check_readonly(name):
mode = DBMODE_R
else:
write_lock_file(name)
if self.db_is_open: if self.db_is_open:
self.close() self.close()
@ -519,17 +501,17 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
def __close_undodb(self): def __close_undodb(self):
if not self.readonly: if not self.readonly:
self.undodb.close() try:
self.undodb.close()
except db.DBNoSuchFileError:
pass
@catch_db_error
def load_from(self, other_database, filename, callback): def load_from(self, other_database, filename, callback):
try: self.load(filename, callback)
self.load(filename, callback) from gen.utils import db_copy
from gen.utils import db_copy db_copy(other_database, self, callback)
db_copy(other_database, self, callback) return 1
return 1
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __load_metadata(self): def __load_metadata(self):
# name display formats # name display formats
@ -645,14 +627,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
self.rmap_index = len(self.repository_map) self.rmap_index = len(self.repository_map)
self.nmap_index = len(self.note_map) self.nmap_index = len(self.note_map)
@catch_db_error
def rebuild_secondary(self, callback=None): def rebuild_secondary(self, callback=None):
try:
self.__rebuild_secondary(callback)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __rebuild_secondary(self, callback=None):
if self.readonly: if self.readonly:
return return
@ -692,14 +668,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
if callback: if callback:
callback(12) callback(12)
@catch_db_error
def find_backlink_handles(self, handle, include_classes=None): def find_backlink_handles(self, handle, include_classes=None):
try:
return self.__find_backlink_handles(handle, include_classes)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __find_backlink_handles(self, handle, include_classes=None):
""" """
Find all objects that hold a reference to the object handle. Find all objects that hold a reference to the object handle.
@ -896,14 +866,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
transaction.add(REFERENCE_KEY, TXNADD, str(key), None, data) transaction.add(REFERENCE_KEY, TXNADD, str(key), None, data)
#transaction.reference_add.append((str(key), data)) #transaction.reference_add.append((str(key), data))
@catch_db_error
def reindex_reference_map(self, callback): def reindex_reference_map(self, callback):
try:
self.__reindex_reference_map(callback)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __reindex_reference_map(self, callback):
""" """
Reindex all primary records in the database. Reindex all primary records in the database.
@ -1035,18 +999,9 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
"version of GRAMPS.\nPlease upgrade to the " "version of GRAMPS.\nPlease upgrade to the "
"corresponding version or use XML for porting " "corresponding version or use XML for porting "
"data between different database versions.")) "data between different database versions."))
@catch_db_error
def close(self): def close(self):
try:
self.__close()
clear_lock_file(self.get_save_path())
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
except IOError:
pass
def __close(self):
if not self.db_is_open: if not self.db_is_open:
return return
@ -1079,11 +1034,7 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
self.media_map.close() self.media_map.close()
self.event_map.close() self.event_map.close()
self.env.close() self.env.close()
self.__close_undodb()
try:
self.__close_undodb()
except db.DBNoSuchFileError:
pass
self.person_map = None self.person_map = None
self.family_map = None self.family_map = None
@ -1099,6 +1050,11 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
self.metadata = None self.metadata = None
self.db_is_open = False self.db_is_open = False
try:
clear_lock_file(self.get_save_path())
except IOError:
pass
def create_id(self): def create_id(self):
return "%08x%08x" % ( int(time.time()*10000), return "%08x%08x" % ( int(time.time()*10000),
self.rand.randint(0, maxint)) self.rand.randint(0, maxint))
@ -1310,18 +1266,19 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
self.__do_remove(handle, transaction, self.note_map, self.__do_remove(handle, transaction, self.note_map,
NOTE_KEY) NOTE_KEY)
@catch_db_error
def set_name_group_mapping(self, name, group): def set_name_group_mapping(self, name, group):
""" if not self.readonly:
Make name group under the value of group. # Start transaction
with BSDDBTxn(self.env, self.name_group) as txn:
If group =None, the old grouping is deleted. name = str(name)
""" data = txn.get(name)
try: if data is not None:
self.__set_name_group_mapping(name, group) txn.delete(name)
except DBERRS, msg: if group is not None:
self.__log_error() txn.put(name, group)
raise Errors.DbError(msg) self.emit('person-rebuild')
def __set_name_group_mapping(self, name, group): def __set_name_group_mapping(self, name, group):
if not self.readonly: if not self.readonly:
# Start transaction # Start transaction
@ -1337,12 +1294,9 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
def sort_surname_list(self): def sort_surname_list(self):
self.surname_list.sort(key=locale.strxfrm) self.surname_list.sort(key=locale.strxfrm)
@catch_db_error
def build_surname_list(self): def build_surname_list(self):
try: self.surname_list = sorted(map(unicode, set(self.surnames.keys())), key=locale.strxfrm)
self.surname_list = sorted(map(unicode, set(self.surnames.keys())), key=locale.strxfrm)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def add_to_surname_list(self, person, batch_transaction): def add_to_surname_list(self, person, batch_transaction):
if batch_transaction: if batch_transaction:
@ -1355,6 +1309,7 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
else: else:
self.surname_list.insert(i, name) self.surname_list.insert(i, name)
@catch_db_error
def remove_from_surname_list(self, person): def remove_from_surname_list(self, person):
""" """
Check whether there are persons with the same surname left in Check whether there are persons with the same surname left in
@ -1373,9 +1328,6 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
del self.surname_list[i-1] del self.surname_list[i-1]
except ValueError: except ValueError:
pass pass
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
finally: finally:
cursor.close() cursor.close()
@ -1601,14 +1553,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
return newobj return newobj
return None return None
@catch_db_error
def transaction_begin(self, msg="", batch=False, no_magic=False): def transaction_begin(self, msg="", batch=False, no_magic=False):
try:
return self.__transaction_begin(msg, batch, no_magic)
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __transaction_begin(self, msg="", batch=False, no_magic=False):
""" """
Create a new Transaction tied to the current UNDO database. Create a new Transaction tied to the current UNDO database.
@ -1638,7 +1584,8 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
_db = db.DB(self.env) _db = db.DB(self.env)
_db.remove(_mkname(self.full_name, REF_REF), REF_REF) _db.remove(_mkname(self.full_name, REF_REF), REF_REF)
return transaction return transaction
@catch_db_error
def transaction_commit(self, transaction, msg): def transaction_commit(self, transaction, msg):
if self._LOG_ALL: if self._LOG_ALL:
LOG.debug("%s: Transaction commit '%s'\n" LOG.debug("%s: Transaction commit '%s'\n"
@ -1647,14 +1594,10 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
if self.readonly: if self.readonly:
return return
try: transaction.commit(msg)
transaction.commit(msg) self.undodb.commit(transaction, msg)
self.undodb.commit(transaction, msg) self.__after_commit(transaction, msg)
self.__after_commit(transaction, msg) self.has_changed = True
self.has_changed = True
except DBERRS, msg:
self.__log_error()
raise Errors.DbError(msg)
def __after_commit(self, transaction, msg): def __after_commit(self, transaction, msg):
""" """
@ -1832,10 +1775,25 @@ def write_lock_file(name):
if __name__ == "__main__": if __name__ == "__main__":
import sys import os, sys, pdb
d = GrampsDBDir() d = GrampsDBDir()
d.load(sys.argv[1], lambda x: x) if len(sys.argv) > 1:
db_name = sys.argv[1]
else:
db_home = os.path.join(os.environ['HOME'], '.gramps','grampsdb')
for dir in os.listdir(db_home):
db_path = os.path.join(db_home, dir)
db_fn = os.path.join(db_path, 'name.txt')
if os.stat(db_fn):
f = open(db_fn)
db_name = f.read()
if db_name == 'Small Example':
break
print "loading", db_path
d.load(db_path, lambda x: x)
print d.get_default_person()
with d.get_person_cursor() as c: with d.get_person_cursor() as c:
for key, data in c: for key, data in c: