The query refreshes the root entity, but not the relationships. So
MisysDict will be refreshed, while related Xrefs will not. To ensure a
refresh of specific relationships, you can use prefetching:
http://cayenne.apache.org/doc/prefetching.html
In the documentation it is presented as a performance optimization
technique, but it is also happens to be an object graph cache control
technique.
Andrus
On Apr 12, 2009, at 10:17 AM, Lawrence Gerstley wrote:
I'm feeling thick, but I'm really stuck with what is becoming an
increasingly simple attempt to convince myself that I can get the
simplest
of caching examples working.
My attempt now is to get two machines on two separate JVMs to have a
force-reload. To do this, I'm re-running the query that populates on
Content
Provider. The Cayenne Controller has these settings:
/******************************************/
DataSource dataSource = new
PoolManager("com.mysql.jdbc.Driver", server, 1, 5, userId, password);
Configuration config = Configuration.getSharedConfiguration();
DataDomain domain = config.getDomain();
domain.setSharedCacheEnabled(false);
DataNode node = domain.getNode("AmerigoDomainNode");
node.setDataSource(dataSource);
DataMap dataMap = domain.getMap("AmerigoDomainMap");
/******************************************/
All queries follow this pattern, roughly:
/******************************************/
Expression express =
ExpressionFactory.likeIgnoreCaseExp( MisysDict.TEST_NAME_PROPERTY,
nameMatch);
SelectQuery sq = new SelectQuery(MisysDict.class, express);
sq.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE_REFRESH);
sq.setCacheGroups("grp1", "grp2", "grp3");
this.clearMisysDictEntries();
misysDictEntries.addAll(dContext.performQuery(sq));
/******************************************/
Now, I can update a row from either application, and see the change
commit
in the data store. However, when I rerun the query above, the objects
attached to the returned objects remain in their old state. For
example, the
entity MisysDict can return a list of Xrefs
(MisysDict.getMisysRecToXREF():
<List>XREF). When I examine one of these XREFs, I cannot see any
change made
to it from the other application. However, I *can* see changes made
to the
MisysDict record itself.
I know I'm going to feel foolish for asking, but can you tell me
what simple
thing(s) I'm off on here?
Thanks, as always,
Lawrence
On Sat, Apr 11, 2009 at 2:16 AM, Andrus Adamchik <[email protected]
>wrote:
The caching docs are embarrassingly out of date. It's been
requested a
number of times to fix them. Maybe finally I'll do it...
As for the cache strategy, you'd usually pick one of LOCAL_CACHE or
SHARED_CACHE (or NO_CACHE for no caching, but that's the default
already).
Javadocs for QueryCacheStrategy explain each one of the strategies.
Let me
point to the differences between "LOCAL" and "SHARED" here. "Local"
means
attached to your ObjectContext, "Shared" - shared by all
ObjectContext
produced by a given Cayenne stack (usually this means shared by all
contexts
in a given JVM). Accessing shared cache is somewhat slower than
local, so if
you have a singleton DataContext (so DataContext is already shared by
itself), select local cache.
Andrus
On Apr 11, 2009, at 3:31 AM, Joe Baldwin wrote:
Lawrence,
I am still struggling to understand Andrus' setCacheStrategy()
approach in
his previous email (he claims it is simple and I am all for
that :) ). I am
attempting some black box testing to figure out exactly where my
data object
is getting cached (and not updated properly). In my case I am
initializing
a class variable with DB data via Cayenne into a singleton when
the class is
initially loaded. I am not sure whether it is my design or
execution of my
design that is at fault.
strategies, but a simple Refresh All would get me across the line
for the
moment. Is there any info on this?
WRT your issue, I found this class in the 3.0 API:
http://cayenne.apache.org/doc/api/org/apache/cayenne/query/RefreshQuery.html
The docs assert:
"A query that allows to explicitly clear both object and list
caches either via refetch (eager refresh) or invalidate (lazy
refresh)."
This may be the ticket for you.
Unfortunately, my singleton appears to be attached to the Tomcat
app and
not the session so I can't find an elegant way for it to refresh.
Please let me know if you get this working.
Joe
On Apr 10, 2009, at 5:28 PM, Lawrence Gerstley wrote:
So, in my knowledge-gaining journey with this topic, I ran across
this
page: http://cayenne.apache.org/doc/refreshquery.html, which
looks like
a list of items yet to be done or at least yet to be documented
(and boy,
when I have things really understood, I want to volunteer some
documentation
time to the project). There is a topic headline of "Refresh All",
and an
indication in the links posted as to the "RefreshQuery", but the
pertinent
part of the links are broken, and I can't track down the
resolution of the
items. However, this is exactly what I need to do for a first
step. My
application's environment will be (mandated by the customer), a
thick client
running on a Citrix instance, and some of the challenges posed by
JGroups
will take me awhile to understand. In the meantime, I want to
provide a
simple "Refresh All" button that will provide for a dumb refresh
without
leaving the application. I'm struggling with different caching
strategies,
but a simple Refresh All would get me across the line for the
moment. Is
there any info on this?
Cheers,
Lawrence
On Apr 10, 2009, at 6:09 AM, Andrus Adamchik wrote:
As mentioned in the quoted docs, there are ways to receive
immediate
notifications on the individual objects updates (if they are
updated via
Cayenne). This approach, while the most powerful on the surface,
is least
practical, especially across the VM. It suffers from a number of
shortcomings (as also have been mentioned here):
* It has a potential to generate too much network traffic
* As all update events are broadcast, it has a potential to DDOS
the
apps who may not care about 90% of the updates (as all incoming
events incur
processing overhead), so some manual event channel filtering may
be needed.
* It does not correctly refresh cached query lists. E.g. if you
have a
cached fetch for "documents that are in draft mode", and then
received an
event saying that one of the drafts has changed to "not a
draft", the object
will be refreshed, the list will become stale, as its
composition no longer
matches the search criteria.
* Finally, the data can change in DB by non Cayenne clients...
So I am very much in favor of the Query Cache approach that is not
documented that well, but is really simple to use:
query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE); // or
SHARED_CACHE...
query.setCacheGroups("g1", "g2", ...);
Once you start doing that for your queries, you can perform
further
cache configuration in a semi-declarative manner. E.g. I am
successfully
using OSQueryCacheFactory:
dataDomain.setQueryCacheFactory(new OSQueryCacheFactory());
This ties Cayenne query cache to OSCache which allows time based
expiration of entries, cron like expressions, and forced
invalidation,
including remote invalidation via JGroups. All of that incurs
nearly zero
overhead, as the entries are not actively purged from cache, but
rather
marked as invalid by "group" (see 'setCacheGroups' above). Cross-
VM events
are also sent as the names of the groups to invalidate, not full
object
snapshots. This is very powerful and easy to use stuff.
Andrus
On Apr 10, 2009, at 10:17 AM, Andrey Razumovsky wrote:
The proposed way is to use JGroups or JMS for synchronization:
http://cayenne.apache.org/doc/configuring-caching-behavior.html
2009/4/10 Lawrence Gerstley <[email protected]>
So, I have the same question here--multiple thick clients
(desktop RCP
applications), each with a DataContext tied to the same
backend, and
potential database access (direct or otherwise) from other
toolsets
out of
my control. Is there a recommended strategy for refreshing each
applications
singleton DataContext to stay in synch, or manually a supplying
refresh
command to the DataContext to periodically update (and, if so,
with
what/how)?
Kind regards,
Lawrence
===================================
Lawrence Gerstley, Ph.D.
PSMI Consulting
[email protected]
Cel: (415) 694-0844
On Apr 8, 2009, at 4:22 PM, Malcolm Edgar wrote:
Hi Joe,
Your singleton cache is going to need to be update
periodically if
there are changes to the under lying database from other
sources.
regards Malcolm Edgar
On Thu, Apr 9, 2009 at 7:45 AM, Joe Baldwin <[email protected]
wrote:
I *think* this is a life-cycle question, but there may be
more to
it.
Proposed Design:
1. Standard Web page JSP using Tomcat server.
2. One of the JSP's accesses a singleton.
3. The singleton accesses and stores a database field via
Cayenne
(presumably when the class is initially loaded) and should
never
need to
access the field again.
4. I would prefer it if the database field change would be
propagated to
the
singleton upon the next new client-Session.
Problem
1. Here is the odd bit: the database field can be modified via
direct
access
to the database (SQL, etc).
2. Cayenne appears not to see this change even when a new
client-Session
is
initialized.
3. I can *force* the singleton to recognize the change by
restarting
Tomcat
(but that is totally lame :) )
4. Unless I have made a mistake (which is possible), the
singleton
should
be
only associated with JSP session scope. But if I am wrong,
this
could be
the problem.
Obviously, I have a misunderstanding about either Cayenne or
Tomcat
caching
or perhaps its a combo of the two. It appears from my tests
that
the
singleton class may be constructed the first time after
Tomcat is
restarted
and then remains persistent even across different sessions.
Are there any suggestions as to a simple design in which my
singleton
forces
re-initialized (i.e. refresh the Cayenne object from the
DBMS data)
upon
each new session?
Thanks,
Joe
--
============================
Lawrence Gerstley, Ph.D.
PSMI Consulting
Cel: 415.694-0844