avalon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Robert Mouat <rob...@mouat.net>
Subject transactions and threadsafety
Date Thu, 13 Jun 2002 17:45:23 GMT
This is a summary of my previous rantings where I try to outline a way
to avoid forcing the client to do [OT (== old terminology)]
ComponentManager->XXXXXManager->Component whenever possible.  (Mainly
because in simple situations (e.g. unit testing) I don't want to have
to create an XXXXXManager if possible).


definition of transaction [second attempt]:

  An interface contract with a well defined begining and ending.

more definitions:

  type 1: the interface has no transaction.

  type 2: the interface has a transaction with begining and ending
  methods. (e.g. begin/end, open/close)

  type 3: the interface has a transaction with no begining and ending
  methods.  In this case the initialize/dispose are used to mark the
  begining and ending of the transaction (where initialize and/or
  dispose can be replaced with recycle() for a pooled component).

contracts:

  An implementation may not hold any resources outside a transaction
  (e.g. filehandles and database connections -- memory and caches
  don't count).

  An implementation of an interface with no transactions (i.e. type 1)
  must be threadsafe.

  An implementation of an interface with transaction (i.e. types 2 and
  3) may not be assumed to be threadsafe.

These contracts seem very reasonable and allow the client to make the
minimal assumptions necessary for its own (small) participation in the
component's management (e.g the client has to indicate to the
component when it may start and stop holding resources, and respect
threadsafety declarations).

I'm going to add one more contract to aid implementation:

  The ComponentManager will never return a type 3 component directly,
  but rather an XXXXXManager which has lookup() and release() methods
  which the client can use to access the component, and which mark the
  begining and end of the transaction.

previously I showed:

  using dynamic proxies and the VM's GC it is possible to detect when
  a client has finished using a component (and so that component can
  be disposed or recycled as necessary).

  for a type 1 and type 2 component, by the time the client has lost
  all references to the component it has freed any resources it may
  have had.

  for a type 3 component, by the time the client has lost all
  references to the XXXXXManager it should have called the release()
  method to end the transaction.

  hence, by the time the client has lost all references to the
  object returned by the ComponentManager any transaction has
  ended and there is no danger of resources still being held.

Finally I want to readdress the issue of looking up a component
outside the compose() method...

with the above contracts I dont think that threadsafety is an issue --
it would only be a problem if a type 1 component tried to look up a
type 2 or 3 component in the compose() method (and keep a reference to
the component), but doing so would violate the contracts above.

If you want to use the compose() method to ensure that the components
you need are available then you can use the CM.exists() method(s).

e.g.

  // type 1 component
  class MyComponent extends AbstractLogEnabled // implements lifecycle methods
  {

    private ComponentManager m_cm;
    private TypeOneInterface m_type1;

    public compose( ComponentManager cm )
    {
      boolean foundAll = true;

      if (! cm.exists( "TypeTwoInterface" ) )
      {
        error( "Couldn't find TypeTwoInterface" );
        foundAll = false;
      }

      if ( cm.exists( "TypeOneInterface" ) )
      {
        m_type1 = cm.lookup( "TypeOneInterface" );
      } else {
        error( "Couldn't find TypeOneInterface" );
        foundAll = false;
      }

      // ...

      if ( !foundAll )
        throw new SomeException(
          "Not all needed components found, see logs for details"
        );

      m_cm = cm;

    }

    public void doStuff()
    {
      // guaranteed to work because of the exists() method called earlier
      TypeTwoInterface type2 =
        (Type2Interface) m_cm.lookup( "TypeTypeInterface" );

      type2.begin();
      type2.foo();
      type2.end();
    }

  }

Finally addressing an earlier email: I don't see any benefit, in the
case of a type 2 component, of the ComponentManager returning a
XXXXXManager, and having the client remembering the XXXXXManager
instead of remembering the ComponentManager.

Robert.


--
To unsubscribe, e-mail:   <mailto:avalon-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:avalon-dev-help@jakarta.apache.org>


Mime
View raw message