On Sun, 19 Dec 2004 09:53:55 -0500, Frank W. Zammetti
<[EMAIL PROTECTED]> wrote:
> While I agree completely with your point about maintainability and
> testability (I can't think of a single situation where I would ever
> consider dynamic configuration modification), I'm interested in how this
> might be allowed anyway...
> 
> Wouldn't it be possible to create a thread-safe modification method that
> locks the underlying structures during modification?  I don't think you
> need to ensure thread safety on the read operation, just the
> modification operation...

This is *exactly* where the problem lies.  If one looks inside the
implementation of HashMap, one sees that there are times when the
internal data structures are being modified, and are in a potentially
inconsistent state that would corrupt a read operation happening on a
simultaneously executing thread.  If you are accessing a HashMap with
read and write operations on multiple threads, the only safe thing to
do is lock all the reads, as well as all the writes.

There was actually an attempt at dealing with this issue -- the
FastHashMap class that was originally in Struts 1.0, and ended up in
Commons Collections.  The basic idea was that this map operated in one
of two modes:

* "Fast" mode lets you do reads without locks, while simultaneous
  writes make a copy of the entire Map, perform the update, and then
  replace the ponter to the internal data structure with a (hopefully)
  atomic operation.

* "Slow" mode locks all accesses for you.

However, enough people raised thread safety concerns about this class
that we chose not to use it in Struts 1.1.

A second approach you might look at is the "double checked locking"
idiom, where your read method would try to detect (via a flag or
something) that a write operation is in progress, and only lock if
that's the case.  However, nobody has been able to come up with a
reliable mechanism to enforce this, due to some of the intricate
details about how threading is done in a JVM (especially on
multiprocessor machines where the threads really *are* running
simultaneously) -- basically, it just doesn't work.  Google for
"Double Checked Locking is Broken" for more info on this.

> 
> You yourself said no locks are needed during read time when you know the
> configuration won't change, and I assume that's the mechanism by which
> you assure the performance aspects, by simply not synchronizing during
> read... If that's the case, I would think simply synchronizing in the
> modification method would allow you to still have the performance while
> introducing the ability to safely modify the configuration.

The "freeze" operation that is performed after the configuration data
is read prohibits any future operations that might change the
underlying maps -- that's what guarantees that we can safely read from
the maps without locking anything.

> 
> Granted, that introduces a bottleneck because every request would have
> to wait until any modification is complete, but I would consider it the
> pervue of the app developer to decide if that's a problem or not (and
> make sure it isn't through reasonable usage of the ability and proper
> app architecture around it).

Per above, locking only the writes is not good enough.

> 
> I guess the question I should ask is when you say the configuration "is
> frozen", is anything really done to make it read-only?  Or is it simply
> the case that one COULD right now modify the configuration if they are
> willing to forgo thread safety?

Take a look at org.apache.struts.config.FormBeanConfig for an example
of how the protection guarantee is implemented (the other cases are
done in a similar way):

* The "formProperties" HashMap (containing the definitions
  of your properties for a DynaActionForm) is a protected variable,
  with no public way to access it.

* The only mutation mechanisms for this map are other methods
  in this class (addFormPropertyConfig() and removeFormPropertyConfig())
  that both check for the frozen state before allowing the modification,
  and throw an exception if it is frozen.

Thus, there is no mechanism in the standard implementation to bypass
the protection, as long as freeze() is called after all the
configuration has been done and requests haven't started yet.  Because
the configuration is done during the init() method of ActionServlet --
which the container guarantees to run to completion before any
requests are accepted -- that guarantee is completed as well.

Your only escape hatch is that you can subclass FormBeanConfig and use
your own copy instead -- but at that point you are on your own. 
Struts makes zero guarantees about thread safe access to the maps at
that point.

And if you do that to allow dynamic modifications, but don't lock on
the reads as well, I think you're walking across a very thin
tightrope, high above the floor, with no net.

Craig

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to