Hello Craig,

seem comments inline below....

Monday, October 28, 2002, 12:14:05 PM, you wrote:
CRM> On Mon, 28 Oct 2002, Jacob Kjome wrote:

>> Date: Mon, 28 Oct 2002 08:08:09 -0600
>> From: Jacob Kjome <[EMAIL PROTECTED]>
>> Reply-To: Tomcat Users List <[EMAIL PROTECTED]>
>> To: Tomcat Users List <[EMAIL PROTECTED]>
>> Subject: DBCP speed of lookup -vs- stored reference to Datasource?
>>
>>
>> I'm wondering what kind of performance penalty there is, if any, when doing
>> a full lookup of the Datasource object each and every time through JNDI
>> calls?  Basically, does it make sense to do one lookup and store a local
>> copy for future use?  The one problem I see with doing that is that if one
>> ever wants to use the Tomcat Manager app to modify configuration on the
>> fly, using the local copy of the Datasource would make it so you never
>> really realize that a change to configuration has been made.  Am I simply
>> losing flexibility without gaining any performance?

CRM> The JNDI lookup, after some manipulations of the name, turns into a
CRM> HashMap lookup inside the server.  It's not particularly expensive -- and
CRM> isn't even worth looking at (from a performance perspective) unless you've
CRM> already tuned all your database queries for maximum performance.  That's
CRM> where the vast majority of problems occur.

CRM> Performance aside, there are two functionality reasons to do the lookup
CRM> every time:

CRM> * Keeping a reference to the data source yourself means that
CRM>   you need to either pass it on to every method, or make it
CRM>   available some other way.  The lookup code requires zero references
CRM>   to things like the ServletContext or any static variables.

In my setup, I have data object and a single manager class for each
data object where the queries are actually done.  Each manager class
extends Manager which, itself, extends ConnectionManager which
contains the getConnection() and returnConnection(Connection) methods
so holding a static variable in the ConnectionManager isn't all that
big of a deal.  I don't have to pass the DataSource around at all.  I
just ask for a connection and the stored DataSource returns an
available connection object.

CRM> * In a high-available application server environment (i.e. Tomcat
CRM>   by itself doesn't support this), doing the lookup every time gives
CRM>   the server an opportunity to gracefully deal with things like
CRM>   switching to a backup database, or dynamically reconfiguring the
CRM>   connection pool by giving you a new instance from now on.

Doesn't the Tomcat Admin app support managing DBCP DataSource
configuration?  I think I can switch the connection string an other
variables on the fly there.  This is the primary reason that I am
interested in whether doing the lookup incurs a performance penalty or
not.  Sounds like there isn't really a performance penalty so if Tomcat
could switch the DataSource at runtime, then I'd
continue keeping a local static copy of the DataSource.  So, can the
Admin app do this for me or not?

>>
>> The way I have the lookup performed is the following.  Please let me know
>> if this is totally unnecessary....
>>
>> final class MyDataSourceClass {
>>
>>      private static DataSource ds = null;
>>      public static Boolean DS_INITIALIZED = Boolean.FALSE;
>>
>>      public static Connection getConnection() throws SQLException {
>>          if (DS_INITIALIZED.equals(Boolean.FALSE) || ds == null) {
>>              synchronized (DS_INITIALIZED) {
>>                  if (DS_INITIALIZED.equals(Boolean.FALSE) || ds == null) {
>>                      try {
>>                          Context ctx = new InitialContext();
>>                          ds =
>> (DataSource)ctx.lookup("java:comp/env/jdbc/myDB");
>>                          if (ds == null) throw new SQLException("No
>> DataSource available for Connection");
>>                          DS_INITIALIZED = Boolean.TRUE;
>>                      }
>>                      catch (NamingException ne) {
>>                          throw new SQLException("JNDI Lookup Failed: " +
>> ne.getMessage());
>>                      }
>>                  }
>>              }
>>          }
>>          return ds.getConnection();
>>      }
>>
>>      public static void returnConnection(Connection conn) throws SQLException {
>>          conn.close();
>>      }
>>
>> }
>>
>> So, basically I want to know if the lookup isn't expensive enough to bother
>> with storing the DataSource locally.
>>

CRM> As others will undoubtedly point out, the "Double-Checked Locking"
CRM> algorithm you use above is not guaranteed to work.  There was a JavaWorld
CRM> article on this topic last year.

Yep, this was brought to my attention in a previous post.  I have
modified the Double-checking Locking scheme to something that
supposedly works and is safe.

See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html under the 
heading
"Fixing Double-Checked Locking using Thread Local Storage"

In my case, it is slightly modified since I am using static variables
and a static method:


final class ConnectionManager {

    /** 
     * If perThreadInstance.get() returns a non-null value, this thread
     * has done synchronization needed to see initialization
     * of helper:
     * http://www.javaworld.com/javaworld/javaqa/2002-04/01-qa-0412-doublelock.html
     * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
     */
    private final static ThreadLocal perThreadInstance = new ThreadLocal();
    private static DataSource ds = null;

    /**
    * Used by servlets and JSPs to get a connection from the pool.  
    */
    public static Connection getConnection() throws SQLException {
        if (perThreadInstance.get() == null) createDataSource();
        return ds.getConnection();
    }

    private final static void createDataSource() throws SQLException {
        synchronized(ConnectionManager.class) {
            if (ds == null) {
                try {
                    Context ctx = new InitialContext();
                    ds = (DataSource)ctx.lookup("java:comp/env/jdbc/MyDB");
                    if (ds == null) throw new SQLException("No DataSource available 
for Connection");
                    if (logger.isDebugEnabled()) logger.debug("The Datasource is: " + 
ds);
                } 
                catch (NamingException ne) {
                    throw new SQLException("JNDI Lookup Failed: " + ne.getMessage());
                }
            }
        }
            // Any non-null value would do as the argument here
        perThreadInstance.set(perThreadInstance);
    }

    /**
    * Returns the connection back to the pool.
    */
    public static void returnConnection(Connection conn) throws SQLException {
        conn.close();
    }  

}

>> thanks,
>>
>> Jake

CRM> Craig

Jake


--
To unsubscribe, e-mail:   <mailto:tomcat-user-unsubscribe@;jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-user-help@;jakarta.apache.org>

Reply via email to