| RE: [eclipselink-dev] Need help understanding why invalid objectstill returned without refresh when read via UOW |
|
It seems to be a regression; our old unit tests are failing different
ways. We execute a query via UOW. A child of the returned object is returned stale;
we can see that it is stale in the cache by calling API and by debugging the
CacheKey. From the stack you can confirm that the stale child object is retrieved
from the session cache and not the UOW because of this -> getAndCloneCacheKeyFromParent Where in "Traversing a direct relationship" does the refresh
supposed to occur? We rarely use indirection in our application, so this relation was direct
relationship. So far I did notice this strange behavior in the following code: Extract from TopLink source code class UnitOfWorkImpl. In some scenario
collection getNewObjectsCloneToOriginal doesn’t have the object but getNewObjectsOriginalToClone has it! So
the _expression_ [if (original != null)],
which seems an insignificant optimization, is creating an issue when the
assumption that both getNewObjectsCloneToOriginal() and getNewObjectsOriginalToClone()
are always in sync is not true. // Remove
object from the new object
cache
// PERF: Avoid
initialization of new objects if none.
if
(hasNewObjects()) {
Object original = getNewObjectsCloneToOriginal().remove(object);
if (original != null) {
getNewObjectsOriginalToClone().remove(original);
}
} -----Original Message----- Hi Sebastien, What, specifically are you doing when you see this
issue? From the stack trace, I see you are executing some kind of a query. What kind of
query? Is the behavior always the same, or does it depend on whether the object
returned by your query is already registered in the UnitOfWork? In general, the getFromIdentityMap code in UnitOfWork is
designed to always return a value whether or not the object is invalidated in other levels
of caching in order to maintain identity within the transaction the
UnitOfWork represents. In the bug you mention below, we adjusted the behavior of
the UnitOfWork as a whole to deal better with a list of circumstances list in the bug: -- When an object is registered in a UnitOfWork through: a) Direct query execution against the UOW b) Session.read* calls (which execute a query) c) Traversing a direct relationship d) traversing an indirect relationship -- Has this behavior actually changed or have you encountered
a new variant of the use case. (i.e. is it possible to write code that succeeds on
TopLink 10.x and fails on EclipseLink 1.1.1) From your questions: The comment should definitely be
updated and depending on what we determine from our discussion about this issue, it is
possible that we will want to update the code path you are seeing in your stack
trace. The list above from the TopLink bug-fix provides a list of areas where we
would like to be doing the refresh for you. -Tom > The original issue was fixed in TopLink 10.x under bug/patch
6865193 - > INVALID OBJECTS IN CACHE SHOULD BE REFRESHED WHEN REGISTERED IN
UOW. > > > > But now I'm testing my production application using EclipseLink
1.1.1 > RC1 and the bug is back. Simple test case doesn't fail! So besides
> answering questions below, if someone wants to have a live trace session
> on my desktop using my application for test case that's a
possibility. > > > > In the stack below getAndCloneCacheKeyFromParent is called with > shouldReturnInvalidatedObjects == true while the object is
invalid, so > the code in getAndCloneCacheKeyFromParent still return the object > because of this condition: > > if ((cacheKey != null) && (shouldReturnInvalidatedObjects
|| > !descriptor.getCacheInvalidationPolicy().isInvalidated(cacheKey)))
{ > > > > Strangely the caller passing true for
shouldReturnInvalidatedObjects has > this comment: > > //Bug#4613774 In the parent session, only return the object
if it has > not been Invalidated > > return
getAndCloneCacheKeyFromParent(primaryKey, theClass, > shouldReturnInvalidatedObjects, descriptor); > > > > True is hardcoded in the code of line 327: > > *public* Object getFromIdentityMap(Vector primaryKey, Class
theClass, > ClassDescriptor descriptor) { > > *return*
getFromIdentityMap(primaryKey, theClass, *true*, > descriptor); > > } > > > > So the questions are: > > 1- Does the following comment wrong? only return
the object if it has > not been Invalidated > > 2- Should line 327 be modified to pass false? > > 3- Where is the responsibility to refresh the
invalid object? > > > > Daemon Thread [WebContainer : 0] (Suspended) > > >
UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(Vector, > Class, boolean, ClassDescriptor) line: 136 > >
UnitOfWorkIdentityMapAccessor.getFromIdentityMap(Vector, Class, > boolean, ClassDescriptor) line: 110 > > >
UnitOfWorkIdentityMapAccessor(IdentityMapAccessor).getFromIdentityMap(Vector, > Class, ClassDescriptor) line: 327 > > UnitOfWorkImpl.registerExistingObject(Object,
ClassDescriptor) > line: 3781 > >
UnitOfWorkImpl.registerExistingObject(Object) line: 3741 > > >
OneToOneMapping(ObjectReferenceMapping).buildCloneForPartObject(Object, > Object, Object, UnitOfWorkImpl, boolean) line: 68 > >
NoIndirectionPolicy.cloneAttribute(Object, Object, Object, > UnitOfWorkImpl, boolean) line: 72 > >
OneToOneMapping(ForeignReferenceMapping).buildClone(Object, > Object, UnitOfWorkImpl) line: 156 > >
ObjectBuilder.populateAttributesForClone(Object, Object, > UnitOfWorkImpl) line: 2627 > >
UnitOfWorkImpl.populateAndRegisterObject(Object, Object, CacheKey, > CacheKey, ClassDescriptor) line: 3537 > > UnitOfWorkImpl.cloneAndRegisterObject(Object,
CacheKey, CacheKey, > ClassDescriptor) line: 923 > >
UnitOfWorkImpl.cloneAndRegisterObject(Object, CacheKey, > ClassDescriptor) line: 832 > > > UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(Vector,
> Class, boolean, ClassDescriptor) line: 171 > >
UnitOfWorkIdentityMapAccessor.getFromIdentityMap(Vector, Class, > boolean, ClassDescriptor) line: 110 > > >
UnitOfWorkIdentityMapAccessor(IdentityMapAccessor).getFromIdentityMap(Vector, > Class, ClassDescriptor) line: 327 > >
UnitOfWorkImpl.registerExistingObject(Object, ClassDescriptor) > line: 3781 > >
UnitOfWorkImpl.registerExistingObject(Object) line: 3741 > > >
ReadObjectQuery(ObjectBuildingQuery).registerIndividualResult(Object, > UnitOfWorkImpl, JoinedAttributeManager) line: 362 > >
ObjectBuilder.buildWorkingCopyCloneNormally(ObjectBuildingQuery, > AbstractRecord, UnitOfWorkImpl, Vector, ClassDescriptor, > JoinedAttributeManager) line: 584 > >
ObjectBuilder.buildObjectInUnitOfWork(ObjectBuildingQuery, > JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Vector, > ClassDescriptor) line: 544 > >
ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, > JoinedAttributeManager) line: 485 > >
ObjectBuilder.buildObject(ObjectLevelReadQuery, AbstractRecord) > line: 437 > >
ReadObjectQuery(ObjectLevelReadQuery).buildObject(AbstractRecord) > line: 569 > >
ReadObjectQuery.registerResultInUnitOfWork(Object, UnitOfWorkImpl, > AbstractRecord, boolean) line: 712 > >
ReadObjectQuery.executeObjectLevelReadQuery() line: 436 > >
ReadObjectQuery(ObjectLevelReadQuery).executeDatabaseQuery() line: > 928 > >
ReadObjectQuery(DatabaseQuery).execute(AbstractSession, > AbstractRecord) line: 664 > >
ReadObjectQuery(ObjectLevelReadQuery).execute(AbstractSession, > AbstractRecord) line: 889 > >
ReadObjectQuery.execute(AbstractSession, AbstractRecord) line: > 397 > > >
ReadObjectQuery(ObjectLevelReadQuery).executeInUnitOfWork(UnitOfWorkImpl, > AbstractRecord) line: 952 > >
UnitOfWorkImpl.internalExecuteQuery(DatabaseQuery, AbstractRecord) > line: 2755 > >
UnitOfWorkImpl(AbstractSession).executeQuery(DatabaseQuery, > AbstractRecord, int) line: 1181 > > >
------------------------------------------------------------------------ > > _______________________________________________ > eclipselink-dev mailing list > eclipselink-dev@xxxxxxxxxxx > https://dev.eclipse.org/mailman/listinfo/eclipselink-dev _______________________________________________ eclipselink-dev mailing list eclipselink-dev@xxxxxxxxxxx https://dev.eclipse.org/mailman/listinfo/eclipselink-dev |