Hello Wes,
thanks for that analysis, I must admit I haven't really thought of what
this means with optimistic txs!
While it is good that a stale read under optimistic transactions won't
lead to wrong persistent data under any circumstances (your #2), I'd
rather like to avoid optimistic verification exceptions where possible,
though.
Concerning #1: the point with reading from P-NT instances outside
transactions for me is that read-requests can be satisfied from cache
without round-tripping to the DB. For a typical web-application that you
can browse, and where most requests are read-requests, I find this the
most effective. Now if my P-NT instances are never invalidated/hollowed
out, e.g. because they never take part in a datastore transaction, I
might be showing wrong information to the user, which, depending on the
application, can be highly undesired.
The next thing I'd consequently ask for is that P-NT instances are in
fact made transactionally consistent, in that they should also be
hollowed out automatically if they have siblings by id that went from
P-dirty to P-clean in some transaction. That's what I currently must
imitate in a clumsy way after each transaction
This all would make P-NT much more safe to use, and more useful in
consequence, IMHO...
Regards,
Jörg
Wes Biggs schrieb:
> I agree that it would be nice to change the method signatures to
> "evictById" for those that take OIDs in order to avoid confusion.
>
> To clarify what I mean about persistent nontransactional objects, see
> section 5.6.1 of the spec:
> "A persistent-nontransactional instance transitions to
> persistent-clean if any managed field
> is accessed when a datastore transaction is in progress. The state of
> the instance in memory
> is discarded and the state is loaded from the datastore."
>
> If you are running with an optimistic transaction instead, you'll get
> an optimistic verification exception at commit time. So I guess it is
> possible to read stale data from the instance in the PM cache under a
> couple of scenarios:
>
> 1. Reading previously loaded fields of a P-NT instance outside of a
> transaction.
> 2. Reading previously loaded fields of a P-NT instance inside an
> optimistic transaction.
>
> In these cases, I think you're right that it would be necessary to
> hollow the instances in order to be absolutely sure that no stale data
> is read after a L2 cache evict().
>
> On the other hand, if you're in an optimistic transaction, don't you
> want to retain the previously read values (they represent the ACID
> guarantee from the optimistic transaction)? So the only case where it
> might make sense to me is #1 above, and that seems debatable to me.
> Do most people using P-NT objects expect them to be consistent with
> the L2 cache at all times? Or are they expected to act like a limited
> form of an optimistic transaction?
>
> I don't have a strong opinion about this, I'm just trying to fully
> articulate the question.
>
> Wes
>
> Joerg von Frantzius wrote:
>
>> Hi Wes,
>>
>> thanks for your answer, please see my comments below.
>>
>> Wesley Biggs schrieb:
>>
>>> Joerg von Frantzius wrote:
>>>
>>>> The problem here is that either evict() accepts only PC objects,
>>>> not object ids, so we have to call PM.getObjectById() beforehand.
>>>> If no object for that id was present, we're instantiating a hollow
>>>> object here only to discard it afterwards, that's not very effective.
>>>
>>> I'm not quite parsing your "either" here, sorry. But
>>> DataStoreCache.evict() accepts object IDs. I'm not sure I see the
>>> necessity of calling PM.evict() as well, unless you have some
>>> particularly long-lived transactions.
>>
>> We're doing nontransactional reads on long-living objects, so I
>> guessed we needed to call PM.evict() to avoid accessing stale field
>> data.
>>
>> You're of course right about DatastoreCache.evict() accepting IDs,
>> thanks for pointing that out. I had just seen the same method
>> signature, and so I assumed the parameter semantics also being the same.
>>
>> Calling it evictById() probably would be less misleading, even more
>> so as a mistake here won't show up immediately. Also, if you only
>> have a jar without sourcecode, the signatures are absolutely
>> indistinguishable (Which of course is not an excuse for not having
>> read the spec thoroughly enough ;)
>>
>>>> As we really want cache invalidation here, not eviction, this is
>>>> even worse. For this purpose, it would be far more convenient to
>>>> have some method like invalidateCachesFor(Object id) on
>>>> PersistenceManagerFactory.
>>>
>>> That's the intention of DataStoreCache.evict(). The semantics are
>>> different than PM.evict().
>>
>> Only now I start understanding that I was misled by the word evict()
>> for the L2-cache: as the user never gets hold of an L2 cache object
>> anyway (a L1-cache object will be created for that), he shouldn't
>> need to care whether the L2 cache internally needs to throw away
>> (evict) some object in order to invalidate cached state. Spec says
>> "/The evict methods are hints to the implementation that the
>> instances referred to by the object ids are stale and should be
>> evicted from the cache./" It might be nit-picking, but I think it
>> would be clearer if the method was called invalidateByÍd(), which
>> would be natural for some cache interface, and if the explanation
>> said "/that the object state referred to by the object ids should be
>> discarded/"
>>
>> Also, the spec doesn't say anything about DatastoreCache.evict()
>> having any impact on P-nontrans instances. So I still need to go to
>> every PM and evict there as well, which is very inconvenient.
>>
>> Or does the "evict" row in table 2 for P-nontrans really apply to
>> /both /evict() methods, not only PM.evict()!? The RI JPOX isn't doing
>> anything like that, by the way.
>>
>>>> To make our wish complete ;) this method would transition all
>>>> non-transactional instances to hollow for that id, for all the PMs
>>>> the PMF has given out. All transactional objects with that id
>>>> should be transitioned to hollow after their transaction has
>>>> completed (either with commit or rollback).
>>>
>>> Persistent nontransactional instances will have to be revalidated
>>> against the datastore (or cache thereof) before being re-enlisted in
>>> a transaction anyway. The behavior you mention is a good way to
>>> implement that, but it doesn't need to be mandated (hollow is not a
>>> user-visible state).
>>
>> I'm not sure what you mean by mandating here? I'd just like to make
>> sure that invalidated non-transactional instances will reload state
>> upon next read access, without having to iterate all PMs. Also, I'd
>> rather not like a call to PM.getObjectById() afterwards returning a
>> new Java object for the same id, which I guess is the case after
>> calling PM.evict(PM.getObjectById(id)).
>>
>> If a method invalidateById() existed, I'd see the sense of evict() in
>> releasing the associated memory. evict() currently does two things at
>> same time: evicting and transitioning to hollow. For (distributed)
>> cache invalidation, I find it sensible to desire only the latter.
>>
>> Regards,
>> Jörg
>
>
>
>
|