diff --git a/ChangeLog b/ChangeLog index a43057bc4..b1d0220c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-06-12 Don Allingham + * src/ViewManager.py: detection and recovery from db errors + * src/GrampsDb/_GrampsDBDir.py: detection and recovery from db errors + * src/GrampsDb/_GrampsBSDDB.py: detection and recovery from db errors + * src/DbManager.py: detection and recovery from db errors + * src/DbState.py: detection and recovery from db errors + * src/ArgHandler.py: detection and recovery from db errors + 2007-06-11 Don Allingham * src/ViewManager.py: Improve backup strategy * src/GrampsDb/_GrampsDBDir.py: Improve backup strategy diff --git a/src/ArgHandler.py b/src/ArgHandler.py index d5483984f..d2aced753 100644 --- a/src/ArgHandler.py +++ b/src/ArgHandler.py @@ -449,7 +449,8 @@ class ArgHandler: filetype = Mime.get_type(rf) self.vm.read_recent_file(rf, filetype) elif os.path.isdir(rf): - if os.path.isfile(os.path.join(rf, "name.txt")): + if os.path.isfile(os.path.join(rf, "name.txt")) and \ + not os.path.isfile(os.path.join(rf,"need_recover"): self.vm.read_recent_file(rf, 'x-directory/normal') #------------------------------------------------------------------------- diff --git a/src/DbManager.py b/src/DbManager.py index a88c6438c..578c32fc3 100644 --- a/src/DbManager.py +++ b/src/DbManager.py @@ -160,7 +160,7 @@ class DbManager: if not node: self.connect.set_sensitive(False) self.rename.set_sensitive(False) - self.repair.set_sensitive(False) + self.repair.hide() self.remove.set_sensitive(False) else: if store.get_value(node, OPEN_COL): @@ -168,7 +168,15 @@ class DbManager: else: self.connect.set_sensitive(True) self.rename.set_sensitive(True) - self.repair.set_sensitive(True) + if store.get_value(node, STOCK_COL) == gtk.STOCK_DIALOG_ERROR: + path = store.get_value(node, PATH_COL) + if os.path.isfile(os.path.join(path,"person.gbkp")): + self.repair.show() + else: + self.repair.hide() + else: + self.repair.hide() + self.remove.set_sensitive(True) def build_interface(self): @@ -349,6 +357,8 @@ class DbManager: db.load(dirname, None) GrampsDbUtils.Backup.restore(db) db.close() + self.dbstate.no_database() + self.populate() def new_db(self, obj): """ @@ -436,6 +446,8 @@ def icon_values(dirpath, active): """ if dirpath == active: return (True, gtk.STOCK_OPEN) + if os.path.isfile(os.path.join(dirpath,"need_recover")): + return (True, gtk.STOCK_DIALOG_ERROR) else: return (False, "") diff --git a/src/DbState.py b/src/DbState.py index 39064e8a5..213f3fdf3 100644 --- a/src/DbState.py +++ b/src/DbState.py @@ -45,9 +45,10 @@ class DbState(GrampsDBCallback): just a place holder until a real DB is assigned. """ GrampsDBCallback.__init__(self) - self.db = GrampsDbBase() - self.open = False - self.active = None + self.db = GrampsDbBase() + self.open = False + self.active = None + self.sighndl = None def change_active_person(self, person): """ diff --git a/src/GrampsDb/_GrampsBSDDB.py b/src/GrampsDb/_GrampsBSDDB.py index 046320a6a..e69f0ab16 100644 --- a/src/GrampsDb/_GrampsBSDDB.py +++ b/src/GrampsDb/_GrampsBSDDB.py @@ -760,10 +760,11 @@ class GrampsBSDDB(GrampsDbBase, UpdateCallback): > result_list = [i for i in find_backlink_handles(handle)] """ - # Use the secondary index to locate all the reference_map entries # that include a reference to the object we are looking for. + print "FIND BACKLINK" referenced_cur = self.get_reference_map_referenced_cursor() + print "refcur", referenced_cur try: ret = referenced_cur.set(handle) @@ -772,6 +773,7 @@ class GrampsBSDDB(GrampsDbBase, UpdateCallback): while (ret is not None): (key, data) = ret + print key, data # data values are of the form: # ((primary_object_class_name, primary_object_handle), @@ -794,8 +796,6 @@ class GrampsBSDDB(GrampsDbBase, UpdateCallback): referenced_cur.close() - return - def __delete_primary_from_reference_map(self, hndl, transaction, txn=None): """ Remove all references to the primary object from the reference_map. diff --git a/src/GrampsDb/_GrampsDBDir.py b/src/GrampsDb/_GrampsDBDir.py index c3d11f5f8..eaed85e75 100644 --- a/src/GrampsDb/_GrampsDBDir.py +++ b/src/GrampsDb/_GrampsDBDir.py @@ -53,6 +53,7 @@ import _GrampsDbConst as const from _GrampsDbExceptions import FileVersionError from BasicUtils import UpdateCallback from _GrampsCursor import GrampsCursor +import Errors _MINVERSION = 9 _DBVERSION = 13 @@ -82,6 +83,9 @@ REF_MAP = "reference_map" REF_PRI = "primary_map" REF_REF = "referenced_map" +DBERRS = (db.DBRunRecoveryError, db.DBAccessError, db.DBPageNotFoundError, db.DBInvalidArgError) + + def find_surname(key,data): return str(data[3][5]) @@ -197,104 +201,130 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): dbmap.open(fname, table_name, dbtype, self.__open_flags(), 0666) return dbmap - def _all_handles(self,table): + def __all_handles(self,table): return table.keys(self.txn) + def __log_error(self): + mypath = os.path.join(self.get_save_path(),"need_recover") + ofile = open(mypath, "w") + ofile.close() + + def __get_cursor(self, table): + try: + return GrampsDBDirCursor(table, self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + def get_person_cursor(self): - return GrampsDBDirCursor(self.person_map, self.txn) + return self.__get_cursor(self.person_map) def get_family_cursor(self): - return GrampsDBDirCursor(self.family_map, self.txn) + return self.__get_cursor(self.family_map) def get_event_cursor(self): - return GrampsDBDirCursor(self.event_map, self.txn) + return self.__get_cursor(self.event_map) def get_place_cursor(self): - return GrampsDBDirCursor(self.place_map, self.txn) + return self.__get_cursor(self.place_map) def get_source_cursor(self): - return GrampsDBDirCursor(self.source_map, self.txn) + return self.__get_cursor(self.source_map) def get_media_cursor(self): - return GrampsDBDirCursor(self.media_map, self.txn) + return self.__get_cursor(self.media_map) def get_repository_cursor(self): - return GrampsDBDirCursor(self.repository_map, self.txn) + return self.__get_cursor(self.repository_map) def get_note_cursor(self): - return GrampsDBDirCursor(self.note_map, self.txn) + return self.__get_cursor(self.note_map) - def has_person_handle(self,handle): + def __has_handle(self, table, handle): + try: + return table.get(str(handle), txn=self.txn) != None + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def has_person_handle(self, handle): """ returns True if the handle exists in the current Person database. """ - return self.person_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.person_map, handle) def has_family_handle(self,handle): """ returns True if the handle exists in the current Family database. """ - return self.family_map.get(str(handle),txn=self.txn) != None + return self.__has_handle(self.family_map, handle) def has_object_handle(self,handle): """ returns True if the handle exists in the current MediaObjectdatabase. """ - return self.media_map.get(str(handle),txn=self.txn) != None + return self.__has_handle(self.media_map, handle) def has_repository_handle(self,handle): """ returns True if the handle exists in the current Repository database. """ - return self.repository_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.repository_map, handle) def has_note_handle(self,handle): """ returns True if the handle exists in the current Note database. """ - return self.note_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.note_map, handle) def has_event_handle(self,handle): """ returns True if the handle exists in the current Repository database. """ - return self.event_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.event_map, handle) def has_place_handle(self,handle): """ returns True if the handle exists in the current Repository database. """ - return self.place_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.place_map, handle) - def has_source_handle(self,handle): + def has_source_handle(self, handle): """ returns True if the handle exists in the current Repository database. """ - return self.source_map.get(str(handle), txn=self.txn) != None + return self.__has_handle(self.source_map, handle) - def get_raw_person_data(self,handle): - return self.person_map.get(str(handle), txn=self.txn) + def __get_raw_data(self, table, handle): + try: + return table.get(str(handle), txn=self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def get_raw_person_data(self, handle): + return self.__get_raw_data(self.person_map, handle) def get_raw_family_data(self,handle): - return self.family_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.family_map, handle) def get_raw_object_data(self,handle): - return self.media_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.media_map, handle) def get_raw_place_data(self,handle): - return self.place_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.place_map, handle) def get_raw_event_data(self,handle): - return self.event_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.event_map, handle) def get_raw_source_data(self,handle): - return self.source_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.source_map, handle) def get_raw_repository_data(self,handle): - return self.repository_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.repository_map, handle) def get_raw_note_data(self,handle): - return self.note_map.get(str(handle), txn=self.txn) + return self.__get_raw_data(self.note_map, handle) # cursors for lookups in the reference_map for back reference # lookups. The reference_map has three indexes: @@ -304,17 +334,36 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): # the main index is unique, the others allow duplicate entries. def get_reference_map_cursor(self): - return GrampsDBDirAssocCursor(self.reference_map, self.txn) + try: + return GrampsDBDirAssocCursor(self.reference_map, self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def get_reference_map_primary_cursor(self): - return GrampsDBDirDupCursor(self.reference_map_primary_map, self.txn) + try: + return GrampsDBDirDupCursor(self.reference_map_primary_map, self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def get_reference_map_referenced_cursor(self): - return GrampsDBDirDupCursor(self.reference_map_referenced_map, self.txn) + try: + return GrampsDBDirDupCursor(self.reference_map_referenced_map, self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) # These are overriding the GrampsDbBase's methods of saving metadata # 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): """sets the default Person to the passed instance""" if not self.readonly: if self.UseTXN: @@ -329,6 +378,13 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.metadata.sync() 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): """returns the default Person of the database""" person = self.get_person_from_handle(self.get_default_handle()) if person: @@ -346,7 +402,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.metadata.sync() return None - def _set_column_order(self, col_list, name): + def __set_column_order(self, col_list, name): if self.metadata and not self.readonly: if self.UseTXN: # Start transaction if needed @@ -360,14 +416,29 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.metadata.sync() def version_supported(self): - dbversion = self.metadata.get('version',default=0) - return ((dbversion <= _DBVERSION) and (dbversion >= _MINVERSION)) + try: + dbversion = self.metadata.get('version',default=0) + return ((dbversion <= _DBVERSION) and (dbversion >= _MINVERSION)) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def need_upgrade(self): - dbversion = self.metadata.get('version',default=0) - return not self.readonly and dbversion < _DBVERSION + try: + dbversion = self.metadata.get('version',default=0) + return not self.readonly and dbversion < _DBVERSION + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def load(self, name, callback, mode="w"): + try: + return self.__load(name, callback, mode) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def __load(self, name, callback, mode="w"): if self.db_is_open: self.close() @@ -380,6 +451,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): callback(12) self.full_name = os.path.abspath(name) + self.path = self.full_name self.brief_name = os.path.basename(name) self.env = db.DBEnv() @@ -417,7 +489,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): # If we cannot work with this DB version, # it makes no sense to go further if not self.version_supported: - self._close_early() + self.__close_early() self.family_map = self.__open_table(self.full_name, FAMILY_TBL) self.place_map = self.__open_table(self.full_name, PLACES_TBL) @@ -490,9 +562,13 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): return 1 def load_from(self, other_database, filename, callback): - self.load(filename,callback) - db_copy(other_database,self,callback) - return 1 + try: + self.load(filename,callback) + db_copy(other_database,self,callback) + return 1 + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def __load_metadata(self): # name display formats @@ -660,7 +736,14 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.rmap_index = len(self.repository_map) self.nmap_index = len(self.note_map) - 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: return @@ -683,8 +766,8 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): ( self.reference_map_referenced_map, REF_REF), ] - for (db, name) in items: - db.close() + for (database, name) in items: + database.close() env = db.DB(self.env) env.remove(_mkname(self.full_name, name), name) if callback: @@ -702,6 +785,13 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): callback(12) 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. Returns an interator over a list of (class_name,handle) tuples. @@ -752,8 +842,6 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): referenced_cur.close() - return - def __delete_primary_from_reference_map(self,handle,transaction,txn=None): """ Remove all references to the primary object from the reference_map. @@ -789,9 +877,9 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): # Now that the cursor is closed, we can remove things for main_key in remove_list: - self._remove_reference(main_key,transaction,txn) + self.__remove_reference(main_key,transaction,txn) - def _update_reference_map(self, obj, transaction, txn=None): + def __update_reference_map(self, obj, transaction, txn=None): """ If txn is given, then changes are written right away using txn. """ @@ -859,17 +947,17 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): for (ref_class_name,ref_handle) in new_references: data = ((CLASS_TO_KEY_MAP[obj.__class__.__name__],handle), (CLASS_TO_KEY_MAP[ref_class_name],ref_handle),) - self._add_reference((handle,ref_handle),data,transaction,txn) + self.__add_reference((handle,ref_handle),data,transaction,txn) # handle deletion of old references for (ref_class_name,ref_handle) in no_longer_required_references: try: - self._remove_reference((handle,ref_handle),transaction,txn) + self.__remove_reference((handle,ref_handle),transaction,txn) except: # ignore missing old reference pass - def _remove_reference(self,key,transaction,txn=None): + def __remove_reference(self,key,transaction,txn=None): """ Removes the reference specified by the key, preserving the change in the passed transaction. @@ -884,7 +972,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): transaction.add(REFERENCE_KEY,str(key),old_data,None) transaction.reference_del.append(str(key)) - def _add_reference(self,key,data,transaction,txn=None): + def __add_reference(self,key,data,transaction,txn=None): """ Adds the reference specified by the key and the data, preserving the change in the passed transaction. @@ -902,6 +990,13 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): transaction.reference_add.append((str(key),data)) 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. This will be a slow process for large databases. @@ -981,7 +1076,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): the_txn = self.env.txn_begin() else: the_txn = None - self._update_reference_map(obj,transaction,the_txn) + self.__update_reference_map(obj,transaction,the_txn) if not self.UseTXN: self.reference_map.sync() if the_txn: @@ -1002,9 +1097,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): find_referenced_handle,open_flags) callback(6) - return - - def _close_metadata(self): + def __close_metadata(self): if not self.readonly: if self.UseTXN: # Start transaction if needed @@ -1077,7 +1170,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.metadata.close() - def _close_early(self): + def __close_early(self): """ Bail out if the incompatible version is discovered: * close cleanly to not damage data/env @@ -1095,13 +1188,20 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): "data between different database versions.") def close(self): + try: + self.__close() + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def __close(self): if not self.db_is_open: return if self.UseTXN: self.env.txn_checkpoint() - self._close_metadata() + self.__close_metadata() self.name_group.close() self.surnames.close() self.id_trans.close() @@ -1126,16 +1226,6 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.source_map.close() self.media_map.close() self.event_map.close() - - # Attempt to clear log sequence numbers, to make database portable - # This will only work for python2.5 and higher -# Comment this our because it causes crashes. -# To reproduce the crash, create a new DB, import example.gramps, open and close the db a few times. -# try: -# self.env.lsn_reset(self.full_name) -# except AttributeError: -# pass - self.env.close() try: @@ -1219,7 +1309,14 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): if not self.UseTXN: self.event_map.sync() - def set_name_group_mapping(self,name,group): + def set_name_group_mapping(self, name, group): + try: + self.__set_name_group_mapping(name, group) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def __set_name_group_mapping(self, name, group): if not self.readonly: if self.UseTXN: # Start transaction if needed @@ -1239,8 +1336,12 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.emit('person-rebuild') def build_surname_list(self): - self.surname_list = list(set(self.surnames.keys())) - self.sort_surname_list() + try: + self.surname_list = list(set(self.surnames.keys())) + self.sort_surname_list() + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def remove_from_surname_list(self,person): """ @@ -1254,90 +1355,97 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.surname_list.remove(unicode(name)) except ValueError: pass + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) - def _get_obj_from_gramps_id(self,val,tbl,class_init,prim_tbl): - if tbl.has_key(str(val)): - data = tbl.get(str(val),txn=self.txn) - obj = class_init() - ### FIXME: this is a dirty hack that works without no - ### sensible explanation. For some reason, for a readonly - ### database, secondary index returns a primary table key - ### corresponding to the data, not the data. - if self.readonly: - tuple_data = prim_tbl.get(data,txn=self.txn) + def __get_obj_from_gramps_id(self,val,tbl,class_init,prim_tbl): + try: + if tbl.has_key(str(val)): + data = tbl.get(str(val),txn=self.txn) + obj = class_init() + ### FIXME: this is a dirty hack that works without no + ### sensible explanation. For some reason, for a readonly + ### database, secondary index returns a primary table key + ### corresponding to the data, not the data. + if self.readonly: + tuple_data = prim_tbl.get(data,txn=self.txn) + else: + tuple_data = pickle.loads(data) + obj.unserialize(tuple_data) + return obj else: - tuple_data = pickle.loads(data) - obj.unserialize(tuple_data) - return obj - else: - return None + return None + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def get_person_from_gramps_id(self,val): """ Finds a Person in the database from the passed gramps' ID. If no such Person exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.id_trans,Person, - self.person_map) + return self.__get_obj_from_gramps_id(val, self.id_trans, Person, + self.person_map) def get_family_from_gramps_id(self,val): """ Finds a Family in the database from the passed gramps' ID. If no such Family exists, None is return. """ - return self._get_obj_from_gramps_id(val,self.fid_trans,Family, - self.family_map) - + return self.__get_obj_from_gramps_id(val, self.fid_trans, Family, + self.family_map) + def get_event_from_gramps_id(self,val): """ Finds an Event in the database from the passed gramps' ID. If no such Family exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.eid_trans,Event, - self.event_map) + return self.__get_obj_from_gramps_id(val, self.eid_trans,Event, + self.event_map) def get_place_from_gramps_id(self,val): """ Finds a Place in the database from the passed gramps' ID. If no such Place exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.pid_trans,Place, - self.place_map) + return self.__get_obj_from_gramps_id(val, self.pid_trans, Place, + self.place_map) def get_source_from_gramps_id(self,val): """ Finds a Source in the database from the passed gramps' ID. If no such Source exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.sid_trans,Source, - self.source_map) + return self.__get_obj_from_gramps_id(val,self.sid_trans,Source, + self.source_map) def get_object_from_gramps_id(self,val): """ Finds a MediaObject in the database from the passed gramps' ID. If no such MediaObject exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.oid_trans,MediaObject, - self.media_map) + return self.__get_obj_from_gramps_id(val,self.oid_trans,MediaObject, + self.media_map) def get_repository_from_gramps_id(self,val): """ Finds a Repository in the database from the passed gramps' ID. If no such Repository exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.rid_trans,Repository, - self.repository_map) + return self.__get_obj_from_gramps_id(val,self.rid_trans,Repository, + self.repository_map) def get_note_from_gramps_id(self,val): """ Finds a Note in the database from the passed gramps' ID. If no such Note exists, None is returned. """ - return self._get_obj_from_gramps_id(val,self.nid_trans,Note, - self.note_map) + return self.__get_obj_from_gramps_id(val,self.nid_trans,Note, + self.note_map) def __commit_base(self, obj, data_map, key, update_list, add_list, - transaction, change_time): + transaction, change_time): """ Commits the specified object to the database, storing the changes as part of the transaction. @@ -1356,7 +1464,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): the_txn = self.env.txn_begin() else: the_txn = None - self._update_reference_map(obj,transaction,txn=the_txn) + self.__update_reference_map(obj,transaction,txn=the_txn) data_map.put(handle,obj.serialize(),txn=the_txn) if not self.UseTXN: data_map.sync() @@ -1364,7 +1472,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): the_txn.commit() old_data = None else: - self._update_reference_map(obj,transaction) + self.__update_reference_map(obj,transaction) old_data = data_map.get(handle,txn=self.txn) new_data = obj.serialize() transaction.add(key,handle,old_data,new_data) @@ -1383,7 +1491,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): retlist.append(str(handle)) return retlist - def _get_from_handle(self, handle, class_type, data_map): + def __get_from_handle(self, handle, class_type, data_map): try: data = data_map.get(str(handle),txn=self.txn) except: @@ -1398,7 +1506,7 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): return newobj return None - def _find_from_handle(self,handle,transaction,class_type,dmap,add_func): + def __find_from_handle(self, handle, transaction, class_type, dmap, add_func): obj = class_type() handle = str(handle) if dmap.has_key(handle): @@ -1409,7 +1517,14 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): add_func(obj,transaction) return obj - 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): """ Creates a new Transaction tied to the current UNDO database. The transaction has no effect until it is committed using the @@ -1441,7 +1556,14 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): return transaction - def transaction_commit(self,transaction,msg): + def transaction_commit(self, transaction, msg): + try: + self.__transaction_commit(transaction, msg) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) + + def __transaction_commit(self, transaction, msg): # Start BSD DB transaction -- DBTxn if self.UseTXN: @@ -1496,49 +1618,63 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): self.txn = None def undo(self,update_history=True): - print "Undoing it" - if self.UseTXN: - self.txn = self.env.txn_begin() - status = GrampsDbBase.undo(self,update_history) - if self.UseTXN: - if status: - self.txn.commit() - else: - self.txn.abort() - self.txn = None - return status + try: + if self.UseTXN: + self.txn = self.env.txn_begin() + status = GrampsDbBase.undo(self,update_history) + if self.UseTXN: + if status: + self.txn.commit() + else: + self.txn.abort() + self.txn = None + return status + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def redo(self,update_history=True): - print "Redoing it" - if self.UseTXN: - self.txn = self.env.txn_begin() - status = GrampsDbBase.redo(self,update_history) - if self.UseTXN: - if status: - self.txn.commit() - else: - self.txn.abort() - self.txn = None - return status + try: + if self.UseTXN: + self.txn = self.env.txn_begin() + status = GrampsDbBase.redo(self,update_history) + if self.UseTXN: + if status: + self.txn.commit() + else: + self.txn.abort() + self.txn = None + return status + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def undo_reference(self,data,handle): - if data == None: - self.reference_map.delete(handle,txn=self.txn) - else: - self.reference_map.put(handle,data,txn=self.txn) + try: + if data == None: + self.reference_map.delete(handle,txn=self.txn) + else: + self.reference_map.put(handle,data,txn=self.txn) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def undo_data(self,data,handle,db_map,signal_root): - if data == None: - self.emit(signal_root + '-delete',([handle],)) - db_map.delete(handle,txn=self.txn) - else: - ex_data = db_map.get(handle,txn=self.txn) - if ex_data: - signal = signal_root + '-update' + try: + if data == None: + self.emit(signal_root + '-delete',([handle],)) + db_map.delete(handle,txn=self.txn) else: - signal = signal_root + '-add' - db_map.put(handle,data,txn=self.txn) - self.emit(signal,([handle],)) + ex_data = db_map.get(handle,txn=self.txn) + if ex_data: + signal = signal_root + '-update' + else: + signal = signal_root + '-add' + db_map.put(handle,data,txn=self.txn) + self.emit(signal,([handle],)) + except DBERRS, msg: + self.__log_error() + raise Errors.DbError(msg) def gramps_upgrade(self,callback=None): UpdateCallback.__init__(self,callback) @@ -1556,8 +1692,8 @@ class GrampsDBDir(GrampsDbBase,UpdateCallback): class BdbTransaction(Transaction): - def __init__(self,msg,db,batch=False,no_magic=False): - Transaction.__init__(self,msg,db,batch,no_magic) + def __init__(self, msg, db, batch=False, no_magic=False): + Transaction.__init__(self, msg, db, batch, no_magic) self.reference_del = [] self.reference_add = [] diff --git a/src/ViewManager.py b/src/ViewManager.py index 7b06bdca0..64a80033a 100644 --- a/src/ViewManager.py +++ b/src/ViewManager.py @@ -81,9 +81,6 @@ import GrampsDisplay from GrampsDb import ProgressMonitor import ProgressDialog -from bsddb.db import DBRunRecoveryError, DBAccessError, \ - DBPageNotFoundError, DBInvalidArgError - def show_url(dialog, link, user_data): """ Sets the about dialog callback for showing the URL. Call the GrampsDisplay @@ -900,7 +897,7 @@ class ViewManager: self.post_load() def import_data(self, obj): - if self.state.db.db_is_open: + if self.state.db.is_open(): self.db_loader.import_file() self.post_load() @@ -972,7 +969,7 @@ class ViewManager: os.chdir(os.path.dirname(filename)) except: print "could not change directory" - except DBRunRecoveryError, msg: + except Errors.DbError, msg: QuestionDialog.ErrorDialog( _("Low level database corruption detected"), _("GRAMPS has detected a problem in the underlying " @@ -981,18 +978,15 @@ class ViewManager: "the next time you open this database. If this " "problem persists, create a new database, import " "from a backup database, and report the problem to " - "gramps-bugs@lists.sourceforge.net.")) - except (DBAccessError, DBPageNotFoundError, DBInvalidArgError), msg: - QuestionDialog.ErrorDialog( - _("Could not open file: %s") % filename, - str(msg[1])) + "gramps-bugs@lists.sourceforge.net.") + "\n\n" + str(msg.value)) + self.state.no_database() except Exception: LOG.error("Failed to open database.", exc_info=True) return True def save_as_activate(self, obj): - if self.state.db.db_is_open: + if self.state.db.is_open(): (filename, filetype) = self.db_loader.save_as() self.post_load_newdb(filename, filetype)