From what I see the problem is that RefreshQuery is not propagated to
remote clients. LOCAL_CACHE is local the tier where the query
originated. With some fixes in M4, this statement is true for both
nested contexts and ROP... Since by default there are no events pushed
from the server to the client and no peer-to-peer client
communication, client 1 uses its local cache and knows nothing about
the RefreshQuery executed by client 2.
There are a few solutions to that:
(1) set timemout on the query cache by using something like an OSCache
cache provider. This will give you a delayed refresh. This may or may
not work for your app, but this can be used with the current Cayenne.
For many apps that would be a reasonable compromise, with cache
ensuring that queries don't happen too often..
(2) Setup server-to-client event push. I did that in the past with a
always-on XMPP connection in parallel with the main HTTPS data channel
(I know it worked for object updates... it needs to be extended to
cache groups invalidation). For a long time I wanted to investigate
Jetty Continuations (and more generally, queuing events on the server
for each live client, and letting client frequently poll for events).
This would allow to reuse the main ROP connection, but this needs to
be developed yet.
Andrus
On May 7, 2008, at 7:25 PM, Marcin Skladaniec wrote:
Hi
In our application we are using LOCAL_CACHE and cache keys to
refresh it, but only for a special context called 'shared' . We have
overridden the CayenneContext commitChanges with following to ensure
cache invalidation on every commit :
if (!isSharedContext()) {
try {
List<Class> commitedClasses = new
Vector<Class>();
for (Object o : uncommittedObjects())
if (!commitedClasses.contains(o.getClass()) && o instanceof
PersistentObject)
commitedClasses.add(o.getClass());
super.commitChanges();
for (Class<? extends PersistentObject> c :
commitedClasses) {
performGenericQuery(new RefreshQuery(new String[]
{ PersistentObject.defaultCacheKeyForEntity(c) }));
}
} catch (CayenneRuntimeException e) {
runtimeExceptionThrown(e, false);
}
} else {
logger.error("Attempt to save shared context", new
IllegalStateException("Shared context is read-only"));
}
whenever a select query is executed we are setting the cache policy
and keys
if (query instanceof SelectQuery) {
SelectQuery sq = ((SelectQuery) query);
if (isSharedContext) {
// if the query is on the shared
context then use cache
//
sq.setCachePolicy(QueryMetadata.LOCAL_CACHE);
// if the root class of the query is kind of PersistentObject
then use the cache keys
if (sq.getRoot() instanceof Class &&
PersistentObject.class.isAssignableFrom((Class<? extends
PersistentObject>) (sq.getRoot()))) {
Class<? extends PersistentObject> c = (Class<? extends
PersistentObject>) sq.getRoot();
List<String> currentCacheGroups = new
Vector<String>();
if (sq.getCacheGroups() != null)
currentCacheGroups =
Arrays.asList(sq.getCacheGroups());
String key =
PersistentObject.defaultCacheKeyForEntity(c);
if
(!currentCacheGroups.contains(key)) {
currentCacheGroups.add(key);
sq.setCacheGroups(currentCacheGroups.toArray(new String[] {}));
}
}
}
}
This works nicely, but there is one problem: the relationship query
does not return refreshed values.
An example. there are two views: One is a list of artists with
painting counts, the counts are calculated using relationship
(anArtist.getPaintings().size()). The second is a simple list of
paintings.
1) client app 1: artists list shows:
Monet - 5
Malevich - 4
vanGogh - 3
painting list contains 12 lines
client app 2 adds a new painting for vanGogh, it lists now
Monet - 5
Malevich - 4
vanGogh - 4
painting list contains 13 lines
client app 1 lists the artists again:
Monet - 5
Malevich - 4
vanGogh - 3 <- incorrect
painting list contains 13 records, which is correct
The odd thing is also that for a given client application both lists
(artist and painting) are using the same context, so if the record
is there, why it does not show up when accessed via relationship ?
Is there something I'm doing wrong ? Is there a way to force the
RelationshipQuery to refresh ?
We are using Cayenne build from sources about a month ago (svn
642725).
Marcin