Re: Managing EOF caching
Re: Managing EOF caching
- Subject: Re: Managing EOF caching
- From: Michael DeMan <email@hidden>
- Date: Thu, 19 Jan 2006 13:54:31 -0800
Hi,
Sounds like your hardware situation is okay. Doesn't matter what the
specs are, as long as its got plenty of unused memory. You can
always trade RAM for CPU cycles.
You are correct on blowing away your editing contexts impacting
performance heavily. Of course, the other side of the coin is that
if you never do that over time EOF will try to cache the entire
database in RAM...
Here's a couple small things to look at...
#1. Review your EOModel and make sure you are locking only on
columns you need to. On fresh applications I've always put in a
dateLastUpdated column in each object and lock only on that. A super
class called GSGenericRecord implements the following as part of
validateForSave(). There is overhead in EOF with the snapshot code
in locking. I'm not 100% sure, but I think the snapshot only tracks
the columns that you have marked as used for locking in your model.
This will save your memory in your snapshot and and reduce the
overhead in saveChanges() when EOF has to review the current data
against the snapshot.
You can actually add this code to your GenericRecord super class and
add the column to all your tables on the fly, and defaulting the
column to NULL if 3rd party applications are inserting into the
database. If 3rd party apps are updating other columns live, then
you''ll have to keep those as locked columns anyway though.
public void validateForSave() throws
NSValidation.ValidationException ()
if (dateLastUpdated()==null) setDateLastUpdated(new NSTimestamp
());
... do rest of validation...
}
#2. If you have certain objects with many columns and you need to
only work with some of those columns, make a subclass of your main
class in EOModeler. The subclass will include only the columns you
need plus of course the columns you lock on. This way EOF will not
pull in the extra columns of data, reducing SQL overhead and again
RAM utilization. This is only helpful once you've identified which
columns are needed for locking - if you lock on every column, then
your 'mini' class has to include every column otherwise
#3. As you are doing now, review each and every place that you do
invalidateAllObjects() or whatever else that blows away the data.
Comment out everywhere that you think it is not absolutely needed and
perhaps even make a session method wrapper for EZ maintenance for
invalidateAllObjects() that also logs out your application memory
size, number of objects in the editing context (total, changed,
inserted, deleted), etc, so you can review those logs later on to see
exactly how much work is being done with each call. Again, I usually
subclass EOEditingContext for these handy-dandy wrappers and
implement defaultEC() in MySession to return MyEditingContext and ec
() in my GenericRecord to return MyEditingContext() for convenience
methods.
You also have to modify your Session constructor to instantiate
MyEditingContext instead of EOEditingContext when it first gets created.
Subclassing EOEditingContext is extremely useful as you can do a lot
of magic there, and at minimum, have a quick and easy way to override
the standard methods to get some high quality logging information.
I'd be interested in staying in touch on your progress with this as
performance/memory utilization is always tricky business with larger
WO applications and its interesting to see what works in what kinds
of conditions. Another common workaround I've seen is using raw row
fetches on 'search' and 'list' pages to avoid bringing in large
numbers of objects into the editing context. However, since your app
is transactional not a web-application, that probably wouldn't work
here.
- mike
On Jan 19, 2006, at 7:27 AM, Dave Rathnow wrote:
This application runs on a dual processor (2GHz I think) machine
with 4GB of RAM so memory isn't much of an issue. Also, throwing
hardware at this problem hasn't resulted in any great improvements
so we have to start doing opitimization of the code. The good news
is that we are currently using very little for the 4GB so enabling
EOF caching should enable us to get by for the short term.
The app has all the "-X" options to give it lots of memeory but,
because we are waxing the EC, we use very little memory. This, of
course will change. The app also runs on a Windoz box so the
options for tuning are limited.
Thanks,
Dave.
-----Original Message-----
From: Michael DeMan [mailto:email@hidden]
Sent: January 19, 2006 02:36 AM
To: Ken Anderson
Cc: Dave Rathnow; 'email@hidden'
Subject: Re: Managing EOF caching
The cheezy option is always hardware. Quick fix, and usually pretty
cheap. Definitely not elegant.
If this is a production application, I would check swap utilization
on the server, and if its low, and especially if there are some bucks
for a few extra GB of RAM, do as follows:
1. Get the production system working, deferring the elegant work with
a crappy fix. i.e., make sure you have lots of RAM and toss
parameters into your shell or Monitor startups like:
-Xms512m -XX:NewSize=4m -Xms256m
right along with your -DWOAutoOpenInBrowser=false statements, etc.
Your apps will get huge, but keep in mind that on a decent UNIX
system with WebObjects (and nearly any server-side java app) you can
expect a good 100MB+ of RAM to be unused, shared, and swapped out
forever. When you look at RAM utilization, only look at whats
resident.
2. In regards to more elegant solutions, look at some of the fetches
and/or 1:M relationship accesses you do in the application. You can
take some of those subroutines and when they're done, have them
discard only those objects from your primary editing context and
snapshot that they brought in for their local use and that you expect
will not be needed in the near future.
3. Even if they are needed in the near future, have your database do
the work and optimize your fetches to include only the columns of
data you need and where possible use stored procedures. Obviously on
this one 'near future' means minutes not milliseconds.
4. If you need the stuff in RAM, buy more RAM!
5. If you're running multiple instances, implement a global cross-
instance EODatabaseObjectStoreCoordinator (or whatever the class is
called, I forget right now), that will cache all your data in one
spot across all your instances on the same host. You need to do a
little bit of inter-process notification, but its a well understood
methodology and you can find snippets at www.wosource.com.
My 2-cents anyway.
- mike
On Jan 18, 2006, at 10:20 AM, Ken Anderson wrote:
> Dave,
>
> It depends. If it's a to-one relationship, and either:
>
> a) The object is already in your current editing context from your
> fetch, or
> b) The object is in a different editing context, but the database
> snapshot is recent enough for your editing context to accept it
>
> then yes, there will be no database activity. This is because the
> object can be found or created purely based on the global ID, which
> can be constructed because a to-one relationship requires you to
> know the entire primary key.
>
> However, if the snapshot is old, your editing context might refuse
> the snapshot and request a fresh one (it depends on that context's
> timestamp or the default timestamp lag).
>
> Lastly, to-many faults will always require a trip to the database,
> since the set information is not known. You can always improve
> this by setting the to-many relationship to batch fault. Don't
> forget though, if only one instance of a to-many fault exists at a
> particular time in the context, no amount of batch faulting will
> help you. Another way to improve this is to have a method in your
> class that determines the to-many grouping via an in-memory
> qualification (if you already have a group of objects you know are
> the superset). This of course gets dicey, because you're doing
> EOF's job...but some circumstances might warrant it.
>
> To answer your original question, fetches from fetch specs or
> faulting go through the same plumbing.
>
> Ken
>
> On Jan 18, 2006, at 12:56 PM, Dave Rathnow wrote:
>
>> Is there a difference in the way EOF caches an object if it is
>> fetched using an EOFetchSpecification or if it is retrieved by
>> traversing a relationship? If I do a bulk fetch using a fetchSpec
>> and then access these object via a relationship from a related
>> object, will EOF use the cached object or fetch it from the
database?
>>
>> Thanks,
>> Dave.
>> -----Original Message-----
>> From: Ken Anderson [mailto:email@hidden]
>> Sent: January 18, 2006 08:29 AM
>> To: Dave Rathnow
>> Cc: 'email@hidden'
>> Subject: Re: Managing EOF caching
>>
>> Dave,
>>
>> What you're doing is OK, and pretty typical (at least for me). I
>> try to limit the destruction of snapshots to the destruction of an
>> editing context, so I don't have objects lying around that are not
>> garbage collected, but their snapshots have been removed from the
>> database context.
>>
>> In one situation, I would have a singleton manage the 'ref data'
>> context (which stored often used reference data). When a
>> 'transaction' editing context was destroyed, it would invalidated
>> all the EOs in THAT editing context that did not have a companion
>> in the ref editing context (managed by the singleton). In that
>> manner, we would hold on to ref data indefinitely, but only hold
>> on to transactional data for the life of the context.
>>
>> Ken
>>
>> On Jan 17, 2006, at 12:07 PM, Dave Rathnow wrote:
>>
>>>
>>> We have an application that processes well data that is reported
>>> at regular and irregular
>>> reporting periods. The bulk of the data arrives in the morning
>>> within a two hour window. The
>>> application is headless, that is, it has no UI.
>>>
>>> When we first wrote the program we were having problems with
>>> running out of memory and
>>> the simplest solution we found was to periodically dispose of the
>>> editing context and then
>>> nuke all snapshots from the EODatabase object. This solved the
>>> memory problems but of
>>> course we lost the advantage of any EOF caching. Unfortunately,
>>> we are now at a point where
>>> we are falling too far behind during busy periods so we have to
>>> revisit the problem and find
>>> a better solution.
>>>
>>> This application is one part of a bigger system and it's primary
>>> job is to process incoming data
>>> according to a set of business rule. The processing involves
>>> fectching object from the DB and
>>> creating other objects that are then stored in the DB and
>>> consumed by other applications in the
>>> system. Most of the fetched objects should stay in memory since
>>> they will likely be used in the
>>> future to process data from the same location. Other objects
>>> could probably be nuked after a
>>> period of time. The newly created objects are not required and
>>> could be released as soon as they
>>> are saved to the DB.
>>>
>>> I've been playing around with different optimization strategies
>>> including batch fetching but the one
>>> that seems to work the best is to save all inserted objects in my
>>> EC before I call saveChanges and
>>> then nuke the snapshots from the EODatabase after the saveChanges
>>> has finished. My overall memory
>>> requirements have increased but they seem to level out at an
>>> acceptable level.
>>>
>>> So here are my question:
>>>
>>> 1. Does anyone have some ideas how to handle this type of caching
>>> requirements? Is there
>>> another/better approach or different solution?
>>>
>>> 2. Assuming what I'm doing is an acceptable approach, can I
>>> control how long objects are cached
>>> by EOF and what objects are cached?
>>>
>>> 3. Does nuking snapshots in the way I'm doing it have an bad
>>> side effects.
>>>
>>> Thanks,
>>> Dave.
>>>
>>> _______________________________________________
>>> Do not post admin requests to the list. They will be ignored.
>>> Webobjects-dev mailing list (email@hidden)
>>> Help/Unsubscribe/Update your Subscription:
>>> 40anderhome.com
>>>
>>> This email sent to email@hidden
>>
>
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Webobjects-dev mailing list (email@hidden)
> Help/Unsubscribe/Update your Subscription:
> 40geminisolutions.com
>
> This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden