[Modeling-cvs] ProjectModeling/Modeling DatabaseContext.py,1.22,1.23 ChangeLog,1.8,1.9
Status: Abandoned
Brought to you by:
sbigaret
From: Sebastien B. <sbi...@us...> - 2006-02-25 13:26:20
|
Update of /cvsroot/modeling/ProjectModeling/Modeling In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18800/Modeling Modified Files: DatabaseContext.py ChangeLog Log Message: * Fixed a serious problem occuring in multi-threaded environment: unexpected failures happened when an EC was fetching objects while another had a faulted object which was concurrently fetching its own values. Index: DatabaseContext.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/DatabaseContext.py,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -d -r1.22 -r1.23 *** DatabaseContext.py 20 Jul 2004 06:21:36 -0000 1.22 --- DatabaseContext.py 25 Feb 2006 13:26:05 -0000 1.23 *************** *** 234,238 **** # the userInfo dictionary for this notification is assumed to hold only # one row ! entity_name=aNotification.userInfo().values()[0].entityName() from ModelSet import defaultModelSet model=defaultModelSet().modelForEntityNamed(entity_name) --- 234,240 ---- # the userInfo dictionary for this notification is assumed to hold only # one row ! entity_name=aNotification.userInfo().get('entityName') \ ! or aNotification.userInfo().values()[0].entityName() ! # TBD: fix docstring and doc. itself from ModelSet import defaultModelSet model=defaultModelSet().modelForEntityNamed(entity_name) *************** *** 321,335 **** DatabaseChannel.isFetchInProgress() """ ! for channel in self._channels: ! if not channel.isFetchInProgress(): ! return channel ! NC.postNotification(DatabaseChannelNeededNotification, self) ! for channel in self._channels: ! if not channel.isFetchInProgress(): ! return channel ! # None registered, let's create one ! channel=DatabaseChannel(self) ! self.registerChannel(channel) ! return channel def batchFetchRelationship(self, aRelationship, objects, anEditingContext): --- 323,341 ---- DatabaseChannel.isFetchInProgress() """ ! self.lock() ! try: ! for channel in self._channels: ! if not channel.isFetchInProgress(): ! return channel ! NC.postNotification(DatabaseChannelNeededNotification, self) ! for channel in self._channels: ! if not channel.isFetchInProgress(): ! return channel ! # None registered, let's create one ! channel=DatabaseChannel(self) ! self.registerChannel(channel) ! return channel ! finally: ! self.unlock() def batchFetchRelationship(self, aRelationship, objects, anEditingContext): *************** *** 477,485 **** See also: DatabaseChannel.isFetchInProgress() """ ! for channel in self._channels: ! if channel.isFetchInProgress(): ! return 1 ! return 0 ! def localSnapshotForGlobalID(self, aGlobalID): """ --- 483,495 ---- See also: DatabaseChannel.isFetchInProgress() """ ! self.lock() ! try: ! for channel in self._channels: ! if channel.isFetchInProgress(): ! return 1 ! return 0 ! finally: ! self.unlock() ! def localSnapshotForGlobalID(self, aGlobalID): """ *************** *** 859,862 **** --- 869,886 ---- return 0 + def ownsEntityName(self, entityName): + """ + Tells whether the DatabaseContext is responsible for the objects of the + supplied entity. Namely: if the entity is registered in the entities set + managed by the dbContext.database() + """ + try: + # will fail if aGlobalID has no method entityName (TemporaryGlobalID) + if self._database.entityNamed(entityName): + return 1 + except: + pass + return 0 + def ownsGlobalID(self, aGlobalID): """ *************** *** 907,948 **** raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes" ! self.__channel=self.availableChannel().adaptorChannel() ! if self.__channel is None: ! raise RuntimeError, 'Unable to find an available AdaptorChannel' ! self.__channel.adaptorContext().beginTransaction() ! ! _adaptorOperations=[] ! trace('performChanges: dbOps: %s'%self._dbOperations) ! #import pprint ! #pprint.pprint(self._dbOperations) ! ! for dbOp in self._dbOperations: ! # Simple: No locking, just operations ! _adOps = self.__databaseOperationToAdaptorOperations(dbOp) ! if not _adOps: ! pass ! # Note: the following statement was initially coded: ! #self.forgetSnapshotForGlobalID(dbOp.globalID()) ! # meaning: if the object was marked as updated but, in fact, no changes ! # needs to be forwarded to the database, then we simply discard the ! # update and forget the snapshots. Seems Ok... ! # BUT: this leads to a buggy behaviour when an object has been marked ! # as updated because at least one of its toMany-relationships-related ! # objects as been removed (and possibly deleted): sure, since the ! # information about that dropped relationship is stored in the ! # destination object (in the FK), there is no changes to forward to ! # the database as far as the source object (=self) is concerned. ! # However, if we forget the snapshots about that object, the ! # Database's snapshotForSourceGlobalID() will not be updated and will ! # be out of sync. ! # cf. test_EditingContext_Global.test_16_toManySnapshotsUpdated() ! else: ! _adaptorOperations += _adOps ! # order dbOperations NB: __TBD delegate ! _adaptorOperations.sort() ! trace("adaptorOperations: %s"%str(_adaptorOperations)) ! #import pdb ; pdb.set_trace() ! self.__channel.performAdaptorOperations(_adaptorOperations) ! def __databaseOperationToAdaptorOperations(self, databaseOperation): """ --- 931,976 ---- raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes" ! self.lock() ! try: ! self.__channel=self.availableChannel().adaptorChannel() ! if self.__channel is None: ! raise RuntimeError, 'Unable to find an available AdaptorChannel' ! self.__channel.adaptorContext().beginTransaction() ! ! _adaptorOperations=[] ! trace('performChanges: dbOps: %s'%self._dbOperations) ! #import pprint ! #pprint.pprint(self._dbOperations) ! ! for dbOp in self._dbOperations: ! # Simple: No locking, just operations ! _adOps = self.__databaseOperationToAdaptorOperations(dbOp) ! if not _adOps: ! pass ! # Note: the following statement was initially coded: ! #self.forgetSnapshotForGlobalID(dbOp.globalID()) ! # meaning: if the object was marked as updated but, in fact, no changes ! # needs to be forwarded to the database, then we simply discard the ! # update and forget the snapshots. Seems Ok... ! # BUT: this leads to a buggy behaviour when an object has been marked ! # as updated because at least one of its toMany-relationships-related ! # objects as been removed (and possibly deleted): sure, since the ! # information about that dropped relationship is stored in the ! # destination object (in the FK), there is no changes to forward to ! # the database as far as the source object (=self) is concerned. ! # However, if we forget the snapshots about that object, the ! # Database's snapshotForSourceGlobalID() will not be updated and will ! # be out of sync. ! # cf. test_EditingContext_Global.test_16_toManySnapshotsUpdated() ! else: ! _adaptorOperations += _adOps ! # order dbOperations NB: __TBD delegate ! _adaptorOperations.sort() ! trace("adaptorOperations: %s"%str(_adaptorOperations)) ! #import pdb ; pdb.set_trace() ! self.__channel.performAdaptorOperations(_adaptorOperations) ! finally: ! self.unlock() ! def __databaseOperationToAdaptorOperations(self, databaseOperation): """ *************** *** 1041,1053 **** # this could be made more efficient if PKs were asked within a single # round-trip to the DB ! channel=self.availableChannel().adaptorChannel() ! for gID in self._inserted_gIDs: ! entity=ec.objectForGlobalID(gID).classDescription().entity() ! pk=channel.primaryKeysForNewRowsWithEntity(1, entity) ! self._pks_for_inserted_gIDs[gID]=pk[0] ! ! newGid=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[gID]) ! self.__temporaryGID_to_KeyGlobalID[gID]=newGid ! def _recordChangesInEditingContext(self, gID, obj, dbOperator): """ --- 1069,1085 ---- # this could be made more efficient if PKs were asked within a single # round-trip to the DB ! self.lock() ! try: ! channel=self.availableChannel().adaptorChannel() ! for gID in self._inserted_gIDs: ! entity=ec.objectForGlobalID(gID).classDescription().entity() ! pk=channel.primaryKeysForNewRowsWithEntity(1, entity) ! self._pks_for_inserted_gIDs[gID]=pk[0] ! ! newGid=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[gID]) ! self.__temporaryGID_to_KeyGlobalID[gID]=newGid ! finally: ! self.unlock() ! def _recordChangesInEditingContext(self, gID, obj, dbOperator): """ *************** *** 1741,1745 **** See also: DatabaseChannel.selectCountObjectsWithFetchSpecification() """ - channel=self.availableChannel() entitiesNames=[aFetchSpec.entityName()] if aFetchSpec.isDeep(): --- 1773,1776 ---- *************** *** 1750,1760 **** objects=[] ! count=0 for entityName in entitiesNames: aFetchSpec.setEntityName(entityName) - c=channel.selectCountObjectsWithFetchSpecification(aFetchSpec, - anEditingContext) - count+=int(c) # SQLite return count --- 1781,1797 ---- objects=[] ! count=c=0 for entityName in entitiesNames: aFetchSpec.setEntityName(entityName) + self.lock() + try: + channel=self.availableChannel() + c=channel.selectCountObjectsWithFetchSpecification(aFetchSpec, + anEditingContext) + finally: + self.unlock() + count+=int(c) # SQLite + return count *************** *** 1789,1793 **** """ - channel=self.availableChannel() entitiesNames=[aFetchSpec.entityName()] if aFetchSpec.isDeep(): --- 1826,1829 ---- *************** *** 1802,1807 **** for entityName in entitiesNames: aFetchSpec.setEntityName(entityName) ! channel.selectObjectsWithFetchSpecification(aFetchSpec, ! anEditingContext) object=channel.fetchObject() while object: --- 1838,1850 ---- for entityName in entitiesNames: aFetchSpec.setEntityName(entityName) ! ! self.lock() ! try: ! channel=self.availableChannel() ! channel.selectObjectsWithFetchSpecification(aFetchSpec, ! anEditingContext) ! finally: ! self.unlock() ! object=channel.fetchObject() while object: *************** *** 1812,1816 **** aFetchSpec.setEntityName(original_entity_name) return objects ! def refaultObject(self, aDatabaseObject, aGlobalID, anEditingContext): """ --- 1855,1859 ---- aFetchSpec.setEntityName(original_entity_name) return objects ! def refaultObject(self, aDatabaseObject, aGlobalID, anEditingContext): """ Index: ChangeLog =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/ChangeLog,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** ChangeLog 25 Feb 2006 13:08:08 -0000 1.8 --- ChangeLog 25 Feb 2006 13:26:05 -0000 1.9 *************** *** 1,4 **** --- 1,12 ---- 2006-02-25 Sebastien Bigaret <Seb...@en...> + * DatabaseContext (DatabaseContext methods: availableChannel, + hasBusyChannels, performChanges, prepareForSaveWithCoordinator, + objectsCountWithFetchSpecification, + objectsWithFetchSpecification): + modified to fix "random" failures when EC.fetch() and clearing + fault were concurrently fetching values (MT environment only) + + * DatabaseContext.py (DatabaseContext.ownsEntityName): added * ObjectStoreCoordinator.py (ObjectStoreCoordinator.objectStoreForEntityName): added |