Guys, there's some context to this topic that Sanne has left out.
This discussion origins comes from Scott Marlow who's found a bug in a Hibernate 2LC
test. The test itself can be found in [1].
Basically, the test loads a couple of entities into the 2LC, and then calls evictAll in
the cache that evicts all entities from the 2LC. Then, it expects the size of the cache to
be 0 and entities to be gone from the 2LC.
The 2LC has a peculiar way to deal with evictEntityRegions or evictAll, it doesn't
just call clear() and hope for the best. Instead, it marks the cache as invalid, and next
time someone queries the cache, it clears it in a separate transaction. This is done
cluster wide too by sending messages to other node that the cache region is invalid.
The problem here is that because it's done in a separate transaction, it doesn't
have an impact on the on going transaction, so the assertions after evict fail. IOW, we
implemented evict as a "eventually clear", where eventually all transactions
will stop using the cached data, but any current transactions will still see data. We did
this for performance reasons and to avoids the issues Sanne mentiones below.
The problem is that we didn't envision this evict method to be used in such way. I
always assumed this would be run outside of a transaction. IOW, you'd use this when
you've updated the database separately (i.e. script, PL/SQL) and you want to clear the
2LC. I always thought that'd be something run via JMX or separate from another
transaction.
But, as Scott has found out, the TCK has some particular expectations of what happens
after a evictEntityRegions or evictAll call within a transaction :(
With this in mind, let me comment on the specifics below:
[1]
https://github.com/scottmarlow/wildfly/blob/b61dc1dddb1f70847d1d82206a366...
On Oct 2, 2013, at 1:03 AM, Sanne Grinovero <sanne(a)infinispan.org> wrote:
I'd love to brainstorm about the clear() operation and what it
means
on Infinispan.
I'm not sure to what extent, but it seems that clear() is designed to
work in a TX, or even create an implicit transaction if needed, but
I'm not understanding how that can work.
Obviously a clear() operation isn't listing all keys explicitly. Which
implies that it's undefined on which keys it's going to operate when
it's fired.. that seems like terribly wrong in a distributed key/value
store as we can't possibly freeze the global state and somehow define
a set of keys which are going to be affected, while an explicit
enumeration is needed to acquire the needed locks.
It might give a nice safe feeling that, when invoking a clear()
operation in a transaction, I can still abort the transaction to make
it cancel the operation; that's the only good part I can think of: we
can cancel it.
I don't think it has anything to do with consistency though? To make
sure you're effectively involving all replicas of all entries in a
consistent way, a lock would need to be acquired on each affected key,
which again implies a need to enumerate all keys, including the
unknown keys which might be hiding in a CacheStore: it's not enough to
broadcast the clear() operation to all nodes and have them simply wipe
their local state as that's never going to deal correctly
(consistently) with in-flight transactions working on different nodes
at different times (I guess enabling Total Order could help but you'd
need to make it mandatory).
So let's step back a second and consider what is the use case for
clear() ? I suspect it's primarily a method needed during testing, or
maybe cleanup before a backup is restored (operations), maybe a
manually activated JMX operation to clear the cache in exceptional
cases.
^ Well, that's precisely the problem of second level cache evictEntityRegions or
evictAll. In some scenarios, the clear is expected to affect the ongoing transaction too,
see above use case from the TCK.
I don't think there would ever be a need for a clear() operation
to
interact with other transactions, so I'd rather make it illegal to
invoke a clear() inside a transaction,
-1, unless you have other ideas to deal with evict calls that I mentioned above that
satisfy what the TCK is after.
or simply ignore the
transactional scope and have an immediate and distributed effect.
That'd be more inline with what's needed above.
I'm likely missing something. What terrible consequences would
this have?
p.s. For the 2LC use case, I'm trying to see if the clear() could be done in the same
transaction and see if that helps, but no luck yet as that causes other failures.
Cheers,
Sanne
_______________________________________________
infinispan-dev mailing list
infinispan-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/infinispan-dev
--
Galder Zamarreño
galder(a)redhat.com
twitter.com/galderz
Project Lead, Escalante
http://escalante.io
Engineer, Infinispan
http://infinispan.org