Return-Path: Delivered-To: apmail-openjpa-dev-archive@www.apache.org Received: (qmail 59896 invoked from network); 3 May 2008 03:17:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 3 May 2008 03:17:28 -0000 Received: (qmail 8092 invoked by uid 500); 3 May 2008 03:17:30 -0000 Delivered-To: apmail-openjpa-dev-archive@openjpa.apache.org Received: (qmail 8066 invoked by uid 500); 3 May 2008 03:17:30 -0000 Mailing-List: contact dev-help@openjpa.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@openjpa.apache.org Delivered-To: mailing list dev@openjpa.apache.org Received: (qmail 8052 invoked by uid 99); 3 May 2008 03:17:29 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 02 May 2008 20:17:29 -0700 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of plinskey@gmail.com designates 66.249.82.236 as permitted sender) Received: from [66.249.82.236] (HELO wx-out-0506.google.com) (66.249.82.236) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 03 May 2008 03:16:45 +0000 Received: by wx-out-0506.google.com with SMTP id s7so44256wxc.24 for ; Fri, 02 May 2008 20:16:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:from:to:in-reply-to:content-type:content-transfer-encoding:mime-version:subject:date:references:x-mailer; bh=YuM14AxfEhMRC3RYzWD0w0OrPTp3B2yR8v9fzEwBsuw=; b=PjQgL/D6I6Q4s+Vbsv2TwaFsIOPPSw3irltytZg7K2Zwk2E/I6Mi9E/LCZpORmkbuZ3EZ5Nlyoqb6UJxjVRATEiStQ8tsBdrl9Sa3UYYjl96N5HFg1AT8x2VRNVQsqKE1Q3iYBJTwhNjxmn0AahtaSRuWZSuCbJjojW9MrMmIQU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:from:to:in-reply-to:content-type:content-transfer-encoding:mime-version:subject:date:references:x-mailer; b=QMS9O7gUJigu/xLJC5JPkk2j7GiQ06/2wtD1CygjoPMiWfmY+13XY1dDHYZ3NjNIq9YoXrxTgjuG40UQLuscFMm1zW6ksD89+WNfvjPuv0vHJLpS0OyKde512yTMNXo8vzENGqF+fEUx61QgFGhVaiidTEmyMl5GY3QvvIFzu/g= Received: by 10.70.72.11 with SMTP id u11mr3139907wxa.39.1209784617765; Fri, 02 May 2008 20:16:57 -0700 (PDT) Received: from executor.bea.com ( [66.248.222.34]) by mx.google.com with ESMTPS id c44sm5385561hsc.8.2008.05.02.20.16.55 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 02 May 2008 20:16:57 -0700 (PDT) Message-Id: <47F72C8E-75B8-432B-AA6C-B055529F82DD@gmail.com> From: Patrick Linskey To: dev@openjpa.apache.org In-Reply-To: <20080502210916.578BE2388999@eris.apache.org> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v919.2) Subject: Re: svn commit: r652913 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ openjpa-jdbc/src/main/java/org/... Date: Fri, 2 May 2008 20:16:03 -0700 References: <20080502210916.578BE2388999@eris.apache.org> X-Mailer: Apple Mail (2.919.2) X-Virus-Checked: Checked by ClamAV on apache.org Hi, This is failing the license header check test in the snapshot build. -Patrick On May 2, 2008, at 2:09 PM, mikedd@apache.org wrote: > Author: mikedd > Date: Fri May 2 14:09:14 2008 > New Revision: 652913 > > URL: http://svn.apache.org/viewvc?rev=652913&view=rev > Log: > OPENJPA-407 committing patch provided by Fay Wang and Jeremy Bauer > > Added: > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/QuerySQLCacheValue.java (with props) > openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ > openjpa/kernel/TestQuerySQLCache.java (with props) > Modified: > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfiguration.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfigurationImpl.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > kernel/JDBCStoreManager.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/RelationFieldStrategy.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/StoreCollectionFieldStrategy.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/LogicalUnion.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SQLBuffer.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/Select.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectExecutor.java > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectImpl.java > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/kernel/localizer.properties > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/meta/strats/localizer.properties > openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ > kernel/FetchConfigurationImpl.java > openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml > openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/conf/JDBCConfiguration.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfiguration.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfiguration.java Fri May 2 14:09:14 2008 > @@ -18,6 +18,8 @@ > */ > package org.apache.openjpa.jdbc.conf; > > +import java.util.Map; > + > import javax.sql.DataSource; > > import org.apache.openjpa.conf.OpenJPAConfiguration; > @@ -602,4 +604,23 @@ > * @see #getDataSource > */ > public DataSource getDataSource2(StoreContext ctx); > + > + /** > + * Return QuerySQLCacheValue. > + * @since 1.2.0 > + */ > + public QuerySQLCacheValue getQuerySQLCache(); > + > + /** > + * Whether querySQLCache is enabled or not. > + * @since 1.2.0 > + */ > + public boolean isQuerySQLCacheOn(); > + > + /** > + * Return QuerySQLCacheInstance. > + * @since 1.2.0 > + */ > + public Map getQuerySQLCacheInstance(); > + > } > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/conf/JDBCConfigurationImpl.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfigurationImpl.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/JDBCConfigurationImpl.java Fri May 2 14:09:14 2008 > @@ -20,6 +20,9 @@ > > import java.sql.Connection; > import java.sql.ResultSet; > +import java.util.HashMap; > +import java.util.Map; > + > import javax.sql.DataSource; > > import org.apache.commons.lang.StringUtils; > @@ -82,6 +85,8 @@ > public ObjectValue mappingDefaultsPlugin; > public PluginValue driverDataSourcePlugin; > public MappingFactoryValue mappingFactoryPlugin; > + public QuerySQLCacheValue querySQLCache; > + private Map querySQLCacheInstance = new HashMap(); > > // used internally > private String firstUser = null; > @@ -302,6 +307,9 @@ > seqPlugin.setDefault(JDBCSeqValue.ALIASES[0]); > seqPlugin.setString(JDBCSeqValue.ALIASES[0]); > > + querySQLCache = new QuerySQLCacheValue("jdbc.QuerySQLCache"); > + addValue(querySQLCache); > + > // this static initializer is to get past a weird > // ClassCircularityError that happens only under IBM's > // JDK 1.3.1 on Linux from within the JRun ClassLoader; > @@ -856,4 +864,21 @@ > return true; > return false; > } > + > + public void setQuerySQLCache(String querySQLCache) { > + this.querySQLCache.setString(querySQLCache); > + } > + > + public QuerySQLCacheValue getQuerySQLCache() { > + return querySQLCache; > + } > + > + public boolean isQuerySQLCacheOn() { > + return querySQLCache.isSQLCacheOn(); > + } > + > + public Map getQuerySQLCacheInstance() { > + return querySQLCacheInstance; > + } > + > } > > Added: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/ > jdbc/conf/QuerySQLCacheValue.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/QuerySQLCacheValue.java?rev=652913&view=auto > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/QuerySQLCacheValue.java (added) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > conf/QuerySQLCacheValue.java Fri May 2 14:09:14 2008 > @@ -0,0 +1,86 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > +package org.apache.openjpa.jdbc.conf; > + > +import java.util.Collections; > +import java.util.Hashtable; > +import java.util.Map; > +import java.util.concurrent.ConcurrentHashMap; > + > +import org.apache.openjpa.lib.conf.Configurations; > +import org.apache.openjpa.lib.conf.PluginValue; > +import org.apache.openjpa.util.CacheMap; > + > + > +/** > + * A cache of sql queries. > + * > + * @since 1.2 > + * @nojavadoc > + */ > +public class QuerySQLCacheValue > + extends PluginValue { > + > + public static final String[] ALIASES = { > + "true", CacheMap.class.getName(), > + "all", ConcurrentHashMap.class.getName(), > + "false", null, > + }; > + > + public QuerySQLCacheValue(String prop) { > + super(prop, true); > + setAliases(ALIASES); > + setDefault(ALIASES[0]); > + setClassName(ALIASES[1]); > + } > + > + public boolean isSQLCacheOn() { > + if (getClassName() == null) > + return false; > + return true; > + } > + > + public Object newInstance() { > + // make sure map handles concurrency > + String clsName = getClassName(); > + if (clsName == null) > + return null; > + Map map = null; > + > + try { > + // Use the "OpenJPA" classloader first... > + map = (Map) Configurations.newInstance(clsName, > this.getClass() > + .getClassLoader()); > + } catch (Exception e) { > + // If the "OpenJPA" classloader fails, then try the > classloader > + // that was used to load java.util.Map... > + map = (Map) Configurations.newInstance(clsName, > + Map.class.getClassLoader()); > + } > + if (map != null > + && !(map instanceof Hashtable) > + && !(map instanceof CacheMap) > + && !(map instanceof > + > org.apache.openjpa.lib.util.concurrent.ConcurrentMap) > + && !(map instanceof > java.util.concurrent.ConcurrentMap)) > + map = Collections.synchronizedMap(map); > + return map; > + } > + > +} > > Propchange: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/conf/QuerySQLCacheValue.java > ------------------------------------------------------------------------------ > svn:eol-style = native > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/kernel/JDBCStoreManager.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > kernel/JDBCStoreManager.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > kernel/JDBCStoreManager.java Fri May 2 14:09:14 2008 > @@ -29,15 +29,20 @@ > import java.util.Collections; > import java.util.HashSet; > import java.util.Iterator; > +import java.util.List; > +import java.util.Map; > import java.util.Set; > + > import javax.sql.DataSource; > > import org.apache.openjpa.event.OrphanedKeyAction; > import org.apache.openjpa.jdbc.conf.JDBCConfiguration; > +import org.apache.openjpa.jdbc.conf.QuerySQLCacheValue; > import org.apache.openjpa.jdbc.meta.ClassMapping; > import org.apache.openjpa.jdbc.meta.Discriminator; > import org.apache.openjpa.jdbc.meta.FieldMapping; > import org.apache.openjpa.jdbc.meta.ValueMapping; > +import org.apache.openjpa.jdbc.schema.Column; > import org.apache.openjpa.jdbc.sql.DBDictionary; > import org.apache.openjpa.jdbc.sql.JoinSyntaxes; > import org.apache.openjpa.jdbc.sql.Joins; > @@ -60,10 +65,12 @@ > import org.apache.openjpa.lib.jdbc.DelegatingConnection; > import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement; > import org.apache.openjpa.lib.jdbc.DelegatingStatement; > +import org.apache.openjpa.lib.log.Log; > import org.apache.openjpa.lib.rop.MergedResultObjectProvider; > import org.apache.openjpa.lib.rop.ResultObjectProvider; > import org.apache.openjpa.lib.util.Localizer; > import org.apache.openjpa.meta.ClassMetaData; > +import org.apache.openjpa.meta.FetchGroup; > import org.apache.openjpa.meta.FieldMetaData; > import org.apache.openjpa.meta.JavaTypes; > import org.apache.openjpa.meta.ValueStrategies; > @@ -99,7 +106,11 @@ > > // track the pending statements so we can cancel them > private Set _stmnts = Collections.synchronizedSet(new HashSet()); > - > + > + private Map _sqlCache = null; > + private boolean _isQuerySQLCache = true; > + private static final Object _nullCacheValue = new Object(); > + > public StoreContext getContext() { > return _ctx; > } > @@ -125,6 +136,9 @@ > > if (_conf.getUpdateManagerInstance().orderDirty()) > ctx.setOrderDirtyObjects(true); > + > + _sqlCache = _conf.getQuerySQLCacheInstance(); > + _isQuerySQLCache = _conf.isQuerySQLCacheOn(); > } > > public JDBCConfiguration getConfiguration() { > @@ -402,13 +416,86 @@ > private Result getInitializeStateResult(OpenJPAStateManager sm, > ClassMapping mapping, JDBCFetchConfiguration fetch, int subs) > throws SQLException { > + List params = new ArrayList(); > + Select sel = newSelect(sm, mapping, fetch, subs, params); > + if (sel == null) return null; > + return sel.execute(this, fetch, params); > + } > + > + private Select newSelect(OpenJPAStateManager sm, > + ClassMapping mapping, JDBCFetchConfiguration fetch, int subs, > + List params) { > + if (!_isQuerySQLCache) > + return newSelect(sm, mapping, fetch, subs); > + > + Map selectImplCacheMap = > + getCacheMapFromQuerySQLCache(JDBCStoreManager.class); > + JDBCFetchConfiguration fetchClone = new > JDBCFetchConfigurationImpl(); > + fetchClone.copy(fetch); > + SelectKey selKey = new SelectKey(mapping, null, fetchClone); > + Select sel = null; > + boolean found = true; > + Object obj = selectImplCacheMap.get(selKey); > + if (obj == null) { > + synchronized (selectImplCacheMap) { > + obj = selectImplCacheMap.get(selKey); > + if (obj == null) { > + // Not found in cache, create a new select > + obj = newSelect(sm, mapping, fetch, subs); > + found = false; > + } > + > + if (obj == null) { > + // If the generated SelectImpl is null, store a > generic > + // known object in the cache as a placeholder. > Some map > + // implementations do not allow null values. > + obj = _nullCacheValue; > + found = false; > + } > + else if (obj != _nullCacheValue) > + { > + sel = (Select)obj; > + if (sel.getSQL() == null) { > + sel.setSQL(this, fetch); > + found = false; > + } > + } > + if (!found) { > + addToSqlCache(selectImplCacheMap, selKey, obj); > + } > + } > + } > + > + if (obj != null && obj != _nullCacheValue) > + sel = (Select) obj; > + > + Log log = _conf.getLog(JDBCConfiguration.LOG_JDBC); > + if (log.isTraceEnabled()) { > + if (!found) > + log.trace(_loc.get("cache-missed", mapping, > this.getClass())); > + else > + log.trace(_loc.get("cache-hit", mapping, > this.getClass())); > + } > + > + if (sel == null) > + return null; > + > + Object oid = sm.getObjectId(); > + Column[] cols = mapping.getPrimaryKeyColumns(); > + sel.wherePrimaryKey(mapping, cols, cols, oid, this, > + null, null, params); > + return sel; > + } > + > + protected Select newSelect(OpenJPAStateManager sm, > + ClassMapping mapping, JDBCFetchConfiguration fetch, int > subs) { > Select sel = _sql.newSelect(); > if (!select(sel, mapping, subs, sm, null, fetch, > JDBCFetchConfiguration.EAGER_JOIN, true, false)) > return null; > sel.wherePrimaryKey(sm.getObjectId(), mapping, this); > sel.setExpectedResultCount(1, false); > - return sel.execute(this, fetch); > + return sel; > } > > /** > @@ -1419,4 +1506,163 @@ > } > } > } > + > + public Map getCacheMapFromQuerySQLCache(Object key) { > + synchronized(_sqlCache) { > + //sqlCache is a map of map > + Map cacheMap = (Map)_sqlCache.get(key); > + if (cacheMap == null) { > + cacheMap = createSQLCache(); > + _sqlCache.put(key, cacheMap); > + } > + return cacheMap; > + } > + } > + > + public void addToSqlCache(Map cacheMap, Object key, Object > value) { > + cacheMap.put(key, value); > + } > + > + public Map createSQLCache() { > + QuerySQLCacheValue querySQLCache = _conf.getQuerySQLCache(); > + return (Map)querySQLCache.newInstance(); > + } > + > + public boolean isQuerySQLCacheOn() { > + return _isQuerySQLCache; > + } > + > + public Map getQuerySQLCache() { > + return _sqlCache; > + } > + > + public static class SelectKey { > + public ClassMapping mapping; > + public FieldMapping fm; > + public JDBCFetchConfiguration fetch; > + > + public SelectKey (ClassMapping mapping, FieldMapping fm, > + JDBCFetchConfiguration fetch) { > + this.mapping = mapping; > + this.fm = fm; > + this.fetch = fetch; > + } > + > + public boolean equals(Object o) { > + if (this == o) return true; > + if (o == null || getClass() != o.getClass()) return > false; > + > + SelectKey selectKey = (SelectKey) o; > + if (fetch != null ? !equals(fetch, selectKey.fetch) : > + selectKey.fetch != null) return false; > + if (mapping != null ? ! > mapping.equals(selectKey.mapping) : > + selectKey.mapping != null) return false; > + if (fm != null ? !fm.equals(selectKey.fm) : > + selectKey.fm != null) return false; > + return true; > + } > + > + public boolean equals(JDBCFetchConfiguration fetch1, > + JDBCFetchConfiguration fetch2) { > + if (fetch1 == fetch2) > + return true; > + > + if (fetch1.getIsolation() != fetch2.getIsolation()) > + return false; > + if (fetch1.getFetchDirection() != > fetch2.getFetchDirection()) > + return false; > + if (fetch1.getEagerFetchMode() != > fetch2.getEagerFetchMode()) > + return false; > + if (fetch1.getSubclassFetchMode() != > fetch2.getSubclassFetchMode()) > + return false; > + if (fetch1.getJoinSyntax() != fetch2.getJoinSyntax()) > + return false; > + Set joins1 = fetch1.getJoins(); > + Set joins2 = fetch2.getJoins(); > + if (joins1 != null ? !joins1.equals(joins2) : joins2 != > null) > + return false; > + > + if (fetch1.getMaxFetchDepth() != > fetch2.getMaxFetchDepth()) > + return false; > + if (fetch1.getReadLockLevel() != > fetch2.getReadLockLevel()) > + return false; > + if (fetch1.getWriteLockLevel() != > fetch2.getWriteLockLevel()) > + return false; > + > + boolean sameFetchGroup = false; > + boolean hasFetchGroupAll = > ((JDBCFetchConfigurationImpl)fetch1). > + hasFetchGroupAll(); > + boolean hasFetchGroupAll1 = > ((JDBCFetchConfigurationImpl)fetch2). > + hasFetchGroupAll(); > + if (hasFetchGroupAll && hasFetchGroupAll1) > + sameFetchGroup = true; > + else if (!hasFetchGroupAll && !hasFetchGroupAll1){ > + boolean hasFetchGroupDefault = > + > ((JDBCFetchConfigurationImpl)fetch1).hasFetchGroupDefault(); > + boolean hasFetchGroupDefault1 = > + > ((JDBCFetchConfigurationImpl)fetch2).hasFetchGroupDefault(); > + if (hasFetchGroupDefault && hasFetchGroupDefault1) > + sameFetchGroup = true; > + } > + > + if (!sameFetchGroup) { > + Set fetchGroups = fetch1.getFetchGroups(); > + Set fetchGroups1 = fetch2.getFetchGroups(); > + if (fetchGroups != null ? ! > fetchGroups.equals(fetchGroups1) : > + fetchGroups1 != null) > + return false; > + } > + > + Set fields = fetch1.getFields(); > + Set fields1 = fetch2.getFields(); > + int size = fields.size(); > + int size1 = fields1.size(); > + if (size == 0 && size1 == 0) > + return true; > + else if (size != size1) > + return false; > + > + if (fields != null ? !fields.equals(fields1) : fields1 ! > = null) > + return false; > + > + return true; > + } > + > + > + public int hashCode() { > + int result = 0; > + result = 31 * result + (mapping != null ? > mapping.hashCode() : 0); > + result = 31 * result + (fm != null ? fm.hashCode() : 0); > + result = 31 * result + fetch.getIsolation(); > + result = 31 * result + fetch.getFetchDirection(); > + result = 31 * result + fetch.getEagerFetchMode(); > + result = 31 * result + fetch.getSubclassFetchMode(); > + result = 31 * result + fetch.getJoinSyntax(); > + Set joins = fetch.getJoins(); > + result = 31 * result + (joins != null ? > joins.hashCode() : 0); > + > + result = 31 * result + fetch.getMaxFetchDepth(); > + result = 31 * result + fetch.getReadLockLevel(); > + result = 31 * result + fetch.getWriteLockLevel(); > + > + if > (((JDBCFetchConfigurationImpl)fetch).hasFetchGroupAll()) > + result = 31 * result + FetchGroup.NAME_ALL.hashCode(); > + else { > + Set fetchGroups = fetch.getFetchGroups(); > + if > (((JDBCFetchConfigurationImpl)fetch).hasFetchGroupDefault() > + && fetchGroups != null && fetchGroups.size() == 1) > + result = 31 * result + > FetchGroup.NAME_DEFAULT.hashCode(); > + else { > + result = 31 * result + (fetchGroups != null && > + fetchGroups.size() > 0 ? > + fetchGroups.hashCode() : 0); > + } > + } > + Set fields = fetch.getFields(); > + result = 31 * result + (fields != null && fields.size() > > 0 ? > + fields.hashCode() : 0); > + > + return result; > + } > + } > } > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/meta/strats/RelationFieldStrategy.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/RelationFieldStrategy.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/RelationFieldStrategy.java Fri May 2 14:09:14 2008 > @@ -19,11 +19,16 @@ > package org.apache.openjpa.jdbc.meta.strats; > > import java.sql.SQLException; > +import java.util.ArrayList; > import java.util.HashMap; > +import java.util.List; > import java.util.Map; > > +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; > import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; > +import org.apache.openjpa.jdbc.kernel.JDBCFetchConfigurationImpl; > import org.apache.openjpa.jdbc.kernel.JDBCStore; > +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager; > import org.apache.openjpa.jdbc.meta.ClassMapping; > import org.apache.openjpa.jdbc.meta.Embeddable; > import org.apache.openjpa.jdbc.meta.FieldMapping; > @@ -38,12 +43,14 @@ > import org.apache.openjpa.jdbc.schema.Table; > import org.apache.openjpa.jdbc.sql.DBDictionary; > import org.apache.openjpa.jdbc.sql.Joins; > +import org.apache.openjpa.jdbc.sql.LogicalUnion; > import org.apache.openjpa.jdbc.sql.Result; > import org.apache.openjpa.jdbc.sql.Row; > import org.apache.openjpa.jdbc.sql.RowManager; > import org.apache.openjpa.jdbc.sql.SQLBuffer; > import org.apache.openjpa.jdbc.sql.Select; > import org.apache.openjpa.jdbc.sql.SelectExecutor; > +import org.apache.openjpa.jdbc.sql.SelectImpl; > import org.apache.openjpa.jdbc.sql.Union; > import org.apache.openjpa.kernel.OpenJPAStateManager; > import org.apache.openjpa.lib.log.Log; > @@ -55,6 +62,7 @@ > import org.apache.openjpa.util.MetaDataException; > import org.apache.openjpa.util.OpenJPAId; > import org.apache.openjpa.util.UnsupportedException; > + > import serp.util.Numbers; > > /** > @@ -579,9 +587,97 @@ > final int subs = field.getSelectSubclasses(); > final Joins[] resJoins = new Joins[rels.length]; > > - // select related mapping columns; joining from the related > type > - // back to our fk table if not an inverse mapping (in which > case we > - // can just make sure the inverse cols == our pk values) > + //cache union for field here > + //select data for this sm > + Union union = null; > + SelectImpl sel = null; > + List parmList = null; > + > + if (!((JDBCStoreManager)store).isQuerySQLCacheOn()) > + union = newUnion(sm, store, fetch, rels, subs, resJoins); > + else { > + Map > relationFieldUnionCache = > + > ((JDBCStoreManager)store).getCacheMapFromQuerySQLCache( > + RelationFieldStrategy.class); > + boolean found = true; > + JDBCFetchConfiguration fetchClone = new > JDBCFetchConfigurationImpl(); > + fetchClone.copy(fetch); > + JDBCStoreManager.SelectKey selKey = > + new JDBCStoreManager.SelectKey(null, field, fetch); > + Object[] obj = relationFieldUnionCache.get(selKey); > + if (obj != null) { > + union = (Union) obj[0]; > + resJoins[0] = (Joins)obj[1]; > + } else { > + synchronized(relationFieldUnionCache) { > + obj = relationFieldUnionCache.get(selKey); > + if (obj != null) { > + union = (Union) obj[0]; > + resJoins[0] = (Joins) obj[1]; > + } else { > + // select related mapping columns; joining > from the > + // related type back to our fk table if not > an inverse > + // mapping (in which case we can just make > sure the > + // inverse cols == our pk values) > + union = newUnion(sm, store, fetch, rels, > subs, > + resJoins); > + found = false; > + } > + sel = > ((LogicalUnion.UnionSelect)union.getSelects()[0]). > + getDelegate(); > + SQLBuffer buf = sel.getSQL(); > + if (buf == null) { > + ((SelectImpl)sel).setSQL(store, fetch); > + found = false; > + } > + > + // only cache the union when elems length is 1 > for now > + if (!found && rels.length == 1) { > + Object[] obj1 = new Object[2]; > + obj1[0] = union; > + obj1[1] = resJoins[0]; > + ((JDBCStoreManager)store).addToSqlCache( > + relationFieldUnionCache, selKey, obj1); > + } > + } > + } > + Log log = store.getConfiguration(). > + getLog(JDBCConfiguration.LOG_JDBC); > + if (log.isTraceEnabled()){ > + if (found) > + log.trace(_loc.get("cache-hit", field, > this.getClass())); > + else > + log.trace(_loc.get("cache-missed", field, > this.getClass())); > + } > + > + parmList = new ArrayList(); > + ClassMapping mapping = field.getDefiningMapping(); > + Object oid = sm.getObjectId(); > + Column[] cols = mapping.getPrimaryKeyColumns(); > + if (sel == null) > + sel = ((LogicalUnion.UnionSelect)union.getSelects() > [0]). > + getDelegate(); > + > + sel.wherePrimaryKey(mapping, cols, cols, oid, store, > + null, null, parmList); > + } > + > + Result res = union.execute(store, fetch, parmList); > + try { > + Object val = null; > + if (res.next()) > + val = res.load(rels[res.indexOf()], store, fetch, > + resJoins[res.indexOf()]); > + sm.storeObject(field.getIndex(), val); > + } finally { > + res.close(); > + } > + } > + > + protected Union newUnion(final OpenJPAStateManager sm, > + final JDBCStore store, final JDBCFetchConfiguration fetch, > + final ClassMapping[] rels, final int subs, > + final Joins[] resJoins) { > Union union = store.getSQLFactory().newUnion(rels.length); > union.setExpectedResultCount(1, false); > if (fetch.getSubclassFetchMode(field.getTypeMapping()) > @@ -602,17 +698,7 @@ > resJoins[idx]); > } > }); > - > - Result res = union.execute(store, fetch); > - try { > - Object val = null; > - if (res.next()) > - val = res.load(rels[res.indexOf()], store, fetch, > - resJoins[res.indexOf()]); > - sm.storeObject(field.getIndex(), val); > - } finally { > - res.close(); > - } > + return union; > } > > public Object toDataStoreValue(Object val, JDBCStore store) { > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/StoreCollectionFieldStrategy.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > meta/strats/StoreCollectionFieldStrategy.java Fri May 2 14:09:14 2008 > @@ -22,21 +22,29 @@ > import java.util.ArrayList; > import java.util.Collection; > import java.util.HashMap; > +import java.util.List; > import java.util.Map; > > +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; > import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; > +import org.apache.openjpa.jdbc.kernel.JDBCFetchConfigurationImpl; > import org.apache.openjpa.jdbc.kernel.JDBCStore; > +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager; > import org.apache.openjpa.jdbc.meta.ClassMapping; > import org.apache.openjpa.jdbc.meta.FieldMapping; > import org.apache.openjpa.jdbc.meta.FieldStrategy; > import org.apache.openjpa.jdbc.schema.Column; > import org.apache.openjpa.jdbc.schema.ForeignKey; > import org.apache.openjpa.jdbc.sql.Joins; > +import org.apache.openjpa.jdbc.sql.LogicalUnion; > import org.apache.openjpa.jdbc.sql.Result; > import org.apache.openjpa.jdbc.sql.Select; > import org.apache.openjpa.jdbc.sql.SelectExecutor; > +import org.apache.openjpa.jdbc.sql.SelectImpl; > import org.apache.openjpa.jdbc.sql.Union; > import org.apache.openjpa.kernel.OpenJPAStateManager; > +import org.apache.openjpa.lib.log.Log; > +import org.apache.openjpa.lib.util.Localizer; > import org.apache.openjpa.meta.JavaTypes; > import org.apache.openjpa.util.ChangeTracker; > import org.apache.openjpa.util.Id; > @@ -55,6 +63,9 @@ > public abstract class StoreCollectionFieldStrategy > extends ContainerFieldStrategy { > > + private static final Localizer _loc = Localizer.forPackage > + (StoreCollectionFieldStrategy.class); > + > /** > * Return the foreign key used to join to the owning field for > the given > * element mapping from {@link #getIndependentElementMappings} > (or null). > @@ -445,19 +456,83 @@ > return; > } > > + //cache union for field here > // select data for this sm > + boolean found = true; > final ClassMapping[] elems = > getIndependentElementMappings(true); > final Joins[] resJoins = new Joins[Math.max(1, elems.length)]; > - Union union = store.getSQLFactory().newUnion > - (Math.max(1, elems.length)); > - union.select(new Union.Selector() { > - public void select(Select sel, int idx) { > - ClassMapping elem = (elems.length == 0) ? null : > elems[idx]; > - resJoins[idx] = selectAll(sel, elem, sm, store, > fetch, > - JDBCFetchConfiguration.EAGER_PARALLEL); > + List parmList = null; > + Union union = null; > + SelectImpl sel = null; > + Map > storeCollectionUnionCache = null; > + JDBCStoreManager.SelectKey selKey = null; > + if (!((JDBCStoreManager)store).isQuerySQLCacheOn()) > + union = newUnion(sm, store, fetch, elems, resJoins); > + else { > + parmList = new ArrayList(); > + JDBCFetchConfiguration fetchClone = new > JDBCFetchConfigurationImpl(); > + fetchClone.copy(fetch); > + > + // to specify the type so that no cast is needed > + storeCollectionUnionCache = ((JDBCStoreManager)store). > + > getCacheMapFromQuerySQLCache(StoreCollectionFieldStrategy.class); > + selKey = > + new JDBCStoreManager.SelectKey(null, field, > fetchClone); > + Object[] objs = storeCollectionUnionCache.get(selKey); > + if (objs != null) { > + union = (Union) objs[0]; > + resJoins[0] = (Joins) objs[1]; > } > - }); > + else { > + synchronized(storeCollectionUnionCache) { > + objs = storeCollectionUnionCache.get(selKey); > + if (objs == null) { > + // select data for this sm > + union = newUnion(sm, store, fetch, elems, > resJoins); > + found = false; > + } else { > + union = (Union) objs[0]; > + resJoins[0] = (Joins) objs[1]; > + } > + > + sel = > ((LogicalUnion.UnionSelect)union.getSelects()[0]). > + getDelegate(); > + if (sel.getSQL() == null) { > + ((SelectImpl)sel).setSQL(store, fetch); > + found = false; > + } > + > + // only cache the union when elems length is 1 > for now > + if (!found && elems.length == 1) { > + Object[] objs1 = new Object[2]; > + objs1[0] = union; > + objs1[1] = resJoins[0]; > + ((JDBCStoreManager)store).addToSqlCache( > + storeCollectionUnionCache, selKey, > objs1); > + } > + } > + } > + > + Log log = store.getConfiguration(). > + getLog(JDBCConfiguration.LOG_JDBC); > + if (log.isTraceEnabled()) { > + if (found) > + log.trace(_loc.get("cache-hit", field, > this.getClass())); > + else > + log.trace(_loc.get("cache-missed", field, > this.getClass())); > + } > + > + ClassMapping mapping = field.getDefiningMapping(); > + Object oid = sm.getObjectId(); > + Column[] cols = mapping.getPrimaryKeyColumns(); > + if (sel == null) > + sel = ((LogicalUnion.UnionSelect)union.getSelects() > [0]). > + getDelegate(); > > + sel.wherePrimaryKey(mapping, cols, cols, oid, store, > + null, null, parmList); > + } > + > // create proxy > Object coll; > ChangeTracker ct = null; > @@ -470,14 +545,14 @@ > } > > // load values > - Result res = union.execute(store, fetch); > + Result res = union.execute(store, fetch, parmList); > try { > int seq = -1; > while (res.next()) { > if (ct != null && field.getOrderColumn() != null) > seq = res.getInt(field.getOrderColumn()); > - add(store, coll, loadElement(sm, store, fetch, res, > - resJoins[res.indexOf()])); > + add(store, coll, loadElement(sm, store, fetch, res, > + resJoins[res.indexOf()])); > } > if (ct != null && field.getOrderColumn() != null) > ct.setNextSequence(seq + 1); > @@ -493,6 +568,21 @@ > sm.storeObject(field.getIndex(), coll); > } > > + protected Union newUnion(final OpenJPAStateManager sm, final > JDBCStore store, > + final JDBCFetchConfiguration fetch, final ClassMapping[] > elems, > + final Joins[] resJoins) { > + Union union = store.getSQLFactory().newUnion > + (Math.max(1, elems.length)); > + union.select(new Union.Selector() { > + public void select(Select sel, int idx) { > + ClassMapping elem = (elems.length == 0) ? null : > elems[idx]; > + resJoins[idx] = selectAll(sel, elem, sm, store, > fetch, > + JDBCFetchConfiguration.EAGER_PARALLEL); > + } > + }); > + return union; > + } > + > /** > * Select data for loading, starting in field table. > */ > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/sql/LogicalUnion.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/LogicalUnion.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/LogicalUnion.java Fri May 2 14:09:14 2008 > @@ -202,20 +202,32 @@ > } > > public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch) > + throws SQLException { > + return execute(store, fetch, null); > + } > + > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + int lockLevel) > + throws SQLException { > + return execute(store, fetch, lockLevel, null); > + } > + > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + List params) > throws SQLException { > if (fetch == null) > fetch = store.getFetchConfiguration(); > - return execute(store, fetch, fetch.getReadLockLevel()); > + return execute(store, fetch, fetch.getReadLockLevel(), > params); > } > > public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > - int lockLevel) > + int lockLevel, List params) > throws SQLException { > if (fetch == null) > fetch = store.getFetchConfiguration(); > > if (sels.length == 1) { > - Result res = sels[0].execute(store, fetch, lockLevel); > + Result res = sels[0].execute(store, fetch, lockLevel, > params); > ((AbstractResult) res).setBaseMapping(mappings[0]); > return res; > } > @@ -224,7 +236,7 @@ > AbstractResult res; > for (int i = 0; i < sels.length; i++) { > res = (AbstractResult) sels[i].execute(store, fetch, > - lockLevel); > + lockLevel, params); > res.setBaseMapping(mappings[i]); > res.setIndexOf(i); > > @@ -256,7 +268,7 @@ > List l; > for (int i = 0; i < res.length; i++) { > res[i] = (AbstractResult) sels[i].execute(store, > fetch, > - lockLevel); > + lockLevel, params); > res[i].setBaseMapping(mappings[i]); > res[i].setIndexOf(i); > > @@ -303,7 +315,7 @@ > /** > * A select that is part of a logical union. > */ > - protected class UnionSelect > + public class UnionSelect > implements Select { > > protected final SelectImpl sel; > @@ -396,6 +408,18 @@ > return sel.getCount(store); > } > > + public Result execute(JDBCStore store, > JDBCFetchConfiguration fetch, > + List params) > + throws SQLException { > + return sel.execute(store, fetch, params); > + } > + > + public Result execute(JDBCStore store, > JDBCFetchConfiguration fetch, > + int lockLevel, List params) > + throws SQLException { > + return sel.execute(store, fetch, lockLevel, params); > + } > + > public Result execute(JDBCStore store, > JDBCFetchConfiguration fetch) > throws SQLException { > return sel.execute(store, fetch); > @@ -406,7 +430,7 @@ > throws SQLException { > return sel.execute(store, fetch, lockLevel); > } > - > + > public List getSubselects() { > return Collections.EMPTY_LIST; > } > @@ -475,6 +499,14 @@ > return sel.getHaving(); > } > > + public SQLBuffer getSQL() { > + return sel.getSQL(); > + } > + > + public void setSQL(JDBCStore store, JDBCFetchConfiguration > fetch) { > + sel.setSQL(store, fetch); > + } > + > public void addJoinClassConditions() { > sel.addJoinClassConditions(); > } > @@ -717,6 +749,15 @@ > JDBCStore store) { > sel.wherePrimaryKey(oid, mapping, store); > } > + > + public int wherePrimaryKey(ClassMapping mapping, Column[] > toCols, > + Column[] fromCols, Object oid, JDBCStore store, > PathJoins pj, > + SQLBuffer buf, List parmList) { > + return sel.wherePrimaryKey(mapping, toCols, fromCols, > oid, store, pj, > + buf, parmList); > + } > + > + > > public void whereForeignKey(ForeignKey fk, Object oid, > ClassMapping mapping, JDBCStore store) { > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/sql/SQLBuffer.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SQLBuffer.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SQLBuffer.java Fri May 2 14:09:14 2008 > @@ -450,9 +450,19 @@ > * the SQL in this buffer. > */ > public PreparedStatement prepareStatement(Connection conn, int > rsType, > + int rsConcur, List parms) > + throws SQLException { > + return prepareStatement(conn, null, rsType, rsConcur, parms); > + } > + > + /** > + * Create and populate the parameters of a prepared statement > using > + * the SQL in this buffer. > + */ > + public PreparedStatement prepareStatement(Connection conn, int > rsType, > int rsConcur) > throws SQLException { > - return prepareStatement(conn, null, rsType, rsConcur); > + return prepareStatement(conn, rsType, rsConcur, null); > } > > /** > @@ -462,6 +472,16 @@ > public PreparedStatement prepareStatement(Connection conn, > JDBCFetchConfiguration fetch, int rsType, int rsConcur) > throws SQLException { > + return prepareStatement(conn, fetch, rsType, rsConcur, null); > + } > + > + /** > + * Create and populate the parameters of a prepred statement > using the > + * SQL in this buffer and the given fetch configuration. > + */ > + public PreparedStatement prepareStatement(Connection conn, > + JDBCFetchConfiguration fetch, int rsType, int rsConcur, > List parms) > + throws SQLException { > if (rsType == -1 && fetch == null) > rsType = ResultSet.TYPE_FORWARD_ONLY; > else if (rsType == -1) > @@ -476,7 +496,7 @@ > else > stmnt = conn.prepareStatement(getSQL(), rsType, rsConcur); > try { > - setParameters(stmnt); > + setParameters(stmnt, parms); > if (fetch != null) { > if (fetch.getFetchBatchSize() > 0) > stmnt.setFetchSize(fetch.getFetchBatchSize()); > @@ -559,13 +579,25 @@ > */ > public void setParameters(PreparedStatement ps) > throws SQLException { > - if (_params == null) > + setParameters(ps, null); > + } > + > + /** > + * Populate the parameters of an existing PreparedStatement > + * with values from this buffer. > + */ > + public void setParameters(PreparedStatement ps, List cacheParams) > + throws SQLException { > + List params = ((cacheParams != null && cacheParams.size() > > 0) ? > + cacheParams : _params); > + > + if (params == null) > return; > > Column col; > - for (int i = 0; i < _params.size(); i++) { > + for (int i = 0; i < params.size(); i++) { > col = (_cols == null) ? null : (Column) _cols.get(i); > - _dict.setUnknown(ps, i + 1, _params.get(i), col); > + _dict.setUnknown(ps, i + 1, params.get(i), col); > } > } > > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/sql/Select.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/Select.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/Select.java Fri May 2 14:09:14 2008 > @@ -193,6 +193,19 @@ > public SQLBuffer getHaving(); > > /** > + * Return the SQL for this select. This buffer contains > + * the final SQL to be executed/cached. > + */ > + public SQLBuffer getSQL(); > + > + /** > + * Create and set the SQLBuffer object to this select. This > buffer contains > + * the final SQL to be executed/cached. > + */ > + public void setSQL(JDBCStore store, JDBCFetchConfiguration > fetch); > + > + > + /** > * Apply class conditions from relation joins. This may affect > the return > * values of {@link #getJoins}, {@link #getJoinIterator}, and > * {@link #getWhere}. > @@ -515,6 +528,19 @@ > */ > public void wherePrimaryKey(Object oid, ClassMapping mapping, > JDBCStore store); > + > + > + /** > + * Add where conditions setting the mapping's primary key to > the given > + * oid values. If the parmList is not null, the value of the > primary > + * key will be collected and saved into the parmList. If the > parmList is > + * null, this method will build the where clause with the value > + * incorporated in the where clause. > + */ > + public int wherePrimaryKey(ClassMapping mapping, Column[] toCols, > + Column[] fromCols, Object oid, JDBCStore store, > PathJoins pj, > + SQLBuffer buf, List parmList); > + > > /** > * Add where conditions setting the given foreign key to the given > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/sql/SelectExecutor.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectExecutor.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectExecutor.java Fri May 2 14:09:14 2008 > @@ -19,6 +19,7 @@ > package org.apache.openjpa.jdbc.sql; > > import java.sql.SQLException; > +import java.util.List; > > import org.apache.openjpa.jdbc.conf.JDBCConfiguration; > import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; > @@ -133,6 +134,20 @@ > * Execute this select in the context of the given store manager. > */ > public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + List params) > + throws SQLException; > + > + /** > + * Execute this select in the context of the given store manager. > + */ > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + int lockLevel, List params) > + throws SQLException; > + > + /** > + * Execute this select in the context of the given store manager. > + */ > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > int lockLevel) > throws SQLException; > } > > Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ > openjpa/jdbc/sql/SelectImpl.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectImpl.java (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ > sql/SelectImpl.java Fri May 2 14:09:14 2008 > @@ -118,6 +118,9 @@ > // 'parent.address.street' for the purposes of comparisons > private Map _aliases = null; > > + // to cache table alias using Table as the key > + private Map _tableAliases = null; > + > // map of indexes to table aliases like 'TABLENAME t0' > private SortedMap _tables = null; > > @@ -167,7 +170,10 @@ > // if the bit is set, the corresponding alias has been removed > from parent > // and recorded under subselect. > private BitSet _removedAliasFromParent = new BitSet(16); > - > + > + //contains final sql statement to be executed/cached > + private SQLBuffer _sql = null; > + > /** > * Helper method to return the proper table alias for the given > alias index. > */ > @@ -300,7 +306,7 @@ > stmnt = prepareStatement(conn, sql, null, > ResultSet.TYPE_FORWARD_ONLY, > ResultSet.CONCUR_READ_ONLY, false); > - rs = executeQuery(conn, stmnt, sql, false, store); > + rs = executeQuery(conn, stmnt, sql, false, store, null); > return getCount(rs); > } finally { > if (rs != null) > @@ -312,20 +318,31 @@ > } > } > > - public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch) > - throws SQLException { > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + List parms) throws SQLException { > if (fetch == null) > fetch = store.getFetchConfiguration(); > return execute(store.getContext(), store, fetch, > - fetch.getReadLockLevel()); > + fetch.getReadLockLevel(), parms); > + } > + > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch) > + throws SQLException { > + return execute(store, fetch, null); > + } > + > + public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > + int lockLevel, List parms) > + throws SQLException { > + if (fetch == null) > + fetch = store.getFetchConfiguration(); > + return execute(store.getContext(), store, fetch, > lockLevel, parms); > } > > public Result execute(JDBCStore store, JDBCFetchConfiguration > fetch, > int lockLevel) > throws SQLException { > - if (fetch == null) > - fetch = store.getFetchConfiguration(); > - return execute(store.getContext(), store, fetch, lockLevel); > + return execute(store, fetch, lockLevel, null); > } > > /** > @@ -333,16 +350,21 @@ > * context is passed in separately for profiling purposes. > */ > protected Result execute(StoreContext ctx, JDBCStore store, > - JDBCFetchConfiguration fetch, int lockLevel) > + JDBCFetchConfiguration fetch, int lockLevel, List params) > throws SQLException { > - boolean forUpdate = false; > - if (!isAggregate() && _grouping == null) { > - JDBCLockManager lm = store.getLockManager(); > - if (lm != null) > - forUpdate = lm.selectForUpdate(this, lockLevel); > - } > - > - SQLBuffer sql = toSelect(forUpdate, fetch); > + boolean forUpdate = isForUpdate(store, lockLevel); > + > + // A non-null _sql indicates that this SelectImpl object > + // is obtained from cache. The _sql is constructed > + // under the assumption that isAggregate() is false > + // and _grouping is null. If neither of these holds, > + // we need to re-construct the _sql > + if (_sql != null && (isAggregate() || _grouping != null)) > + _sql = null; > + > + if (_sql == null) > + _sql = toSelect(forUpdate, fetch); > + > boolean isLRS = isLRS(); > int rsType = (isLRS && supportsRandomAccess(forUpdate)) > ? -1 : ResultSet.TYPE_FORWARD_ONLY; > @@ -351,13 +373,15 @@ > ResultSet rs = null; > try { > if (isLRS) > - stmnt = prepareStatement(conn, sql, fetch, rsType, > -1, true); > + stmnt = prepareStatement(conn, _sql, fetch, rsType, > -1, true, > + params); > else > - stmnt = prepareStatement(conn, sql, null, rsType, > -1, false); > + stmnt = prepareStatement(conn, _sql, null, rsType, > -1, false, > + params); > > setTimeout(stmnt, forUpdate, fetch); > > - rs = executeQuery(conn, stmnt, sql, isLRS, store); > + rs = executeQuery(conn, stmnt, _sql, isLRS, store, > params); > } catch (SQLException se) { > // clean up statement > if (stmnt != null) > @@ -367,7 +391,17 @@ > } > > return getEagerResult(conn, stmnt, rs, store, fetch, > forUpdate, > - sql.getSQL()); > + _sql.getSQL()); > + } > + > + private boolean isForUpdate(JDBCStore store, int lockLevel) { > + boolean forUpdate = false; > + if (!isAggregate() && _grouping == null) { > + JDBCLockManager lm = store.getLockManager(); > + if (lm != null) > + forUpdate = lm.selectForUpdate(this, lockLevel); > + } > + return forUpdate; > } > > /** > @@ -413,10 +447,22 @@ > protected PreparedStatement prepareStatement(Connection conn, > SQLBuffer sql, JDBCFetchConfiguration fetch, int rsType, > int rsConcur, boolean isLRS) throws SQLException { > + // add comments why we pass in null as the last parameter > + return prepareStatement(conn, sql, fetch, rsType, rsConcur, > isLRS, > + null); > + } > + > + /** > + * This method is to provide override for non-JDBC or JDBC-like > + * implementation of preparing statement. > + */ > + protected PreparedStatement prepareStatement(Connection conn, > + SQLBuffer sql, JDBCFetchConfiguration fetch, int rsType, > + int rsConcur, boolean isLRS, List params) throws > SQLException { > if (fetch == null) > - return sql.prepareStatement(conn, rsType, rsConcur); > + return sql.prepareStatement(conn, rsType, rsConcur, > params); > else > - return sql.prepareStatement(conn, fetch, rsType, -1); > + return sql.prepareStatement(conn, fetch, rsType, -1, > params); > } > > /** > @@ -445,7 +491,8 @@ > * implementation of executing query. > */ > protected ResultSet executeQuery(Connection conn, > PreparedStatement stmnt, > - SQLBuffer sql, boolean isLRS, JDBCStore store) throws > SQLException { > + SQLBuffer sql, boolean isLRS, JDBCStore store, List params) > + throws SQLException { > return stmnt.executeQuery(); > } > > @@ -589,6 +636,19 @@ > return _having; > } > > + public SQLBuffer getSQL() { > + return _sql; > + } > + > + public void setSQL(SQLBuffer sql) { > + _sql = sql; > + } > + > + public void setSQL(JDBCStore store, JDBCFetchConfiguration > fetch) { > + boolean forUpdate = isForUpdate(store, > fetch.getReadLockLevel()); > + _sql = toSelect(forUpdate, fetch); > + } > + > public void addJoinClassConditions() { > if (_joins == null || _joins.joins() == null) > return; > @@ -656,13 +716,30 @@ > * Return the alias for the given column. > */ > private String getColumnAlias(String col, Table table, PathJoins > pj) { > + String tableAlias = null; > + if (pj == null || pj.path() == null) { > + if (_tableAliases == null) > + _tableAliases = new HashMap(); > + tableAlias = (String) _tableAliases.get(table); > + if (tableAlias == null) { > + tableAlias = getTableAlias(table, pj).toString(); > + _tableAliases.put(table, tableAlias); > + } > + return new > StringBuilder(tableAlias).append(col).toString(); > + } > + return getTableAlias(table, pj).append(col).toString(); > + } > + > + private StringBuilder getTableAlias(Table table, PathJoins pj) { > + StringBuilder buf = new StringBuilder(); > if (_from != null) { > String alias = toAlias(_from.getTableIndex(table, pj, > true)); > if (_dict.requiresAliasForSubselect) > - return FROM_SELECT_ALIAS + "." + alias + "_" + col; > - return alias + "_" + col; > + return > buf.append(FROM_SELECT_ALIAS).append(".").append(alias). > + append("_"); > + return buf.append(alias).append("_"); > } > - return toAlias(getTableIndex(table, pj, true)) + "." + col; > + return buf.append(toAlias(getTableIndex(table, pj, > true))).append("."); > } > > public boolean isAggregate() { > @@ -1263,12 +1340,38 @@ > return; > } > > + SQLBuffer buf = new SQLBuffer(_dict); > + > + // only bother to pack pk values into array if app id > + int count = wherePrimaryKey(mapping, toCols, fromCols, oid, > store, pj, > + buf, null); > + > + if (constCols != null && constCols.length > 0) { > + for (int i = 0; i < constCols.length; i++, count++) { > + if (count > 0) > + buf.append(" AND "); > + buf.append(getColumnAlias(constCols[i], pj)); > + > + if (vals[i] == null) > + buf.append(" IS "); > + else > + buf.append(" = "); > + buf.appendValue(vals[i], constCols[i]); > + } > + } > + > + where(buf, pj); > + } > + > + public int wherePrimaryKey(ClassMapping mapping, Column[] toCols, > + Column[] fromCols, Object oid, JDBCStore store, PathJoins pj, > + SQLBuffer buf, List parmList) { > // only bother to pack pk values into array if app id > + boolean collectParmValueOnly = (parmList != null ? true : > false); > Object[] pks = null; > if (mapping.getIdentityType() == ClassMapping.ID_APPLICATION) > pks = ApplicationIds.toPKValues(oid, mapping); > > - SQLBuffer buf = new SQLBuffer(_dict); > Joinable join; > Object val; > int count = 0; > @@ -1281,8 +1384,13 @@ > val = pks[mapping.getField(join.getFieldIndex()). > getPrimaryKeyIndex()]; > val = join.getJoinValue(val, toCols[i], store); > + if (parmList != null) > + parmList.add(val); > } > - > + > + if (collectParmValueOnly) > + continue; > + > if (count > 0) > buf.append(" AND "); > buf.append(getColumnAlias(fromCols[i], pj)); > @@ -1292,24 +1400,9 @@ > buf.append(" = "); > buf.appendValue(val, fromCols[i]); > } > - > - if (constCols != null && constCols.length > 0) { > - for (int i = 0; i < constCols.length; i++, count++) { > - if (count > 0) > - buf.append(" AND "); > - buf.append(getColumnAlias(constCols[i], pj)); > - > - if (vals[i] == null) > - buf.append(" IS "); > - else > - buf.append(" = "); > - buf.appendValue(vals[i], constCols[i]); > - } > - } > - > - where(buf, pj); > + return count; > } > - > + > /** > * Test to see if the given set of columns contains all the > * columns in the given potential subset. > > Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/ > openjpa/jdbc/kernel/localizer.properties > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/kernel/localizer.properties (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/kernel/localizer.properties Fri May 2 14:09:14 2008 > @@ -113,4 +113,5 @@ > batch_limit: The batch limit is set to {0}. > batch_update_info: ExecuteBatch command returns update count {0} for \ > statement {1}. > - > +cache-hit: SQL Cache hit with key: {0} in {1} > +cache-missed: SQL Cache missed with key: {0} in {1} > > Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/ > openjpa/jdbc/meta/strats/localizer.properties > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/strats/localizer.properties?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/meta/strats/localizer.properties (original) > +++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ > jdbc/meta/strats/localizer.properties Fri May 2 14:09:14 2008 > @@ -134,3 +134,5 @@ > its "{1}" primary key field does not use a simple mapping. > unmapped-datastore-value: Instances of type "{0}" are not valid > query \ > parameters because the type is not mapped. > +cache-hit: SQL Cache hit with key: {0} in {1} > +cache-missed: SQL Cache missed with key: {0} in {1} > > Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/ > openjpa/kernel/FetchConfigurationImpl.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ > kernel/FetchConfigurationImpl.java (original) > +++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ > kernel/FetchConfigurationImpl.java Fri May 2 14:09:14 2008 > @@ -82,6 +82,9 @@ > public Set rootClasses; > public Set rootInstances; > public Map hints = null; > + > + public boolean fetchGroupContainsDefault = false; > + public boolean fetchGroupContainsAll = false; > } > > private final ConfigurationState _state; > @@ -92,7 +95,7 @@ > private boolean _load = true; > private int _availableRecursion; > private int _availableDepth; > - > + > public FetchConfigurationImpl() { > this(null); > } > @@ -221,10 +224,22 @@ > > public boolean hasFetchGroup(String group) { > return _state.fetchGroups != null > - && (_state.fetchGroups.contains(group) > - || _state.fetchGroups.contains(FetchGroup.NAME_ALL)); > + && (hasFetchGroupAll() > + || _state.fetchGroups.contains(group)); > } > > + public boolean hasFetchGroupDefault() > + { > + // Fetch group All includes fetch group Default by definition > + return _state.fetchGroupContainsDefault || > + _state.fetchGroupContainsAll; > + } > + > + public boolean hasFetchGroupAll() > + { > + return _state.fetchGroupContainsAll; > + } > + > public FetchConfiguration addFetchGroup(String name) { > if (StringUtils.isEmpty(name)) > throw new UserException(_loc.get("null-fg")); > @@ -234,6 +249,10 @@ > if (_state.fetchGroups == null) > _state.fetchGroups = new HashSet(); > _state.fetchGroups.add(name); > + if (FetchGroup.NAME_ALL.equals(name)) > + _state.fetchGroupContainsAll = true; > + else if (FetchGroup.NAME_DEFAULT.equals(name)) > + _state.fetchGroupContainsDefault = true; > } finally { > unlock(); > } > @@ -251,8 +270,13 @@ > public FetchConfiguration removeFetchGroup(String group) { > lock(); > try { > - if (_state.fetchGroups != null) > + if (_state.fetchGroups != null) { > _state.fetchGroups.remove(group); > + if (FetchGroup.NAME_ALL.equals(group)) > + _state.fetchGroupContainsAll = false; > + else if (FetchGroup.NAME_DEFAULT.equals(group)) > + _state.fetchGroupContainsDefault = false; > + } > } finally { > unlock(); > } > @@ -262,8 +286,9 @@ > public FetchConfiguration removeFetchGroups(Collection groups) { > lock(); > try { > - if (_state.fetchGroups != null) > - _state.fetchGroups.removeAll(groups); > + if (_state.fetchGroups != null && groups != null) > + for (Object group : groups) > + removeFetchGroup(group.toString()); > } finally { > unlock(); > } > @@ -273,8 +298,11 @@ > public FetchConfiguration clearFetchGroups() { > lock(); > try { > - if (_state.fetchGroups != null) > + if (_state.fetchGroups != null) { > _state.fetchGroups.clear(); > + _state.fetchGroupContainsAll = false; > + _state.fetchGroupContainsDefault = true; > + } > } finally { > unlock(); > } > @@ -562,9 +590,9 @@ > * Whether our configuration state includes the given field. > */ > private boolean includes(FieldMetaData fmd) { > - if ((fmd.isInDefaultFetchGroup() > - && hasFetchGroup(FetchGroup.NAME_DEFAULT)) > - || hasFetchGroup(FetchGroup.NAME_ALL) > + if (hasFetchGroupAll() > + || (fmd.isInDefaultFetchGroup() > + && hasFetchGroupDefault()) > || hasField(fmd.getFullName(false))) > return true; > String[] fgs = fmd.getCustomFetchGroups(); > > Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/ > apache/openjpa/kernel/TestQuerySQLCache.java > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestQuerySQLCache.java?rev=652913&view=auto > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ > openjpa/kernel/TestQuerySQLCache.java (added) > +++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ > openjpa/kernel/TestQuerySQLCache.java Fri May 2 14:09:14 2008 > @@ -0,0 +1,391 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > +package org.apache.openjpa.kernel; > + > +import java.util.HashMap; > +import java.util.Iterator; > +import java.util.Map; > +import java.util.Set; > +import java.util.concurrent.ConcurrentHashMap; > + > +import javax.persistence.EntityManager; > +import javax.persistence.EntityManagerFactory; > +import javax.persistence.Persistence; > + > +import junit.framework.TestCase; > + > +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager; > +import org.apache.openjpa.persistence.EntityManagerImpl; > +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; > +import org.apache.openjpa.persistence.OpenJPAPersistence; > +import org.apache.openjpa.persistence.simple.Person; > + > +/* > + * Verify multiple permutations of openjpa.jdbc.QuerySQLCache > settings. > + */ > +public class TestQuerySQLCache > + extends TestCase { > + > + final int nThreads = 5; > + final int nPeople = 100; > + final int nIterations = 10; > + > + /* > + * Verify QuerySQLCacheValue setting "all" is caching queries. > + */ > + public void testAllCacheSetting() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", "all"); > + OpenJPAEntityManagerFactorySPI emf = > (OpenJPAEntityManagerFactorySPI) > + OpenJPAPersistence.cast( > + Persistence.createEntityManagerFactory("test", > props)); > + > + EntityManagerImpl em = > (EntityManagerImpl)emf.createEntityManager(); > + BrokerImpl broker = (BrokerImpl) em.getBroker(); > + DelegatingStoreManager dstore = broker.getStoreManager(); > + JDBCStoreManager jstore = > + (JDBCStoreManager)dstore.getInnermostDelegate(); > + > + em.getTransaction().begin(); > + Person p = new Person(); > + p.setId(1); > + em.persist(p); > + em.flush(); > + em.getTransaction().commit(); > + > + Person p1 = em.find(Person.class, 1); > + Map sqlCache = jstore.getQuerySQLCache(); > + Set keys = sqlCache.keySet(); > + for (Iterator iter = keys.iterator(); iter.hasNext();) { > + Map cacheMap = (Map) iter.next(); > + //make sure there is an entry in the cache > + assertEquals(1, cacheMap.size()); > + } > + > + em.getTransaction().begin(); > + em.remove(p); > + em.flush(); > + em.getTransaction().commit(); > + > + em.close(); > + emf.close(); > + } > + > + /* > + * Verify QuerySQLCacheValue setting "true" uses the expected > cache > + * implementation and is caching. > + */ > + public void testTrueCacheSetting() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", "true"); > + OpenJPAEntityManagerFactorySPI emf = > (OpenJPAEntityManagerFactorySPI) > + OpenJPAPersistence.cast( > + Persistence.createEntityManagerFactory("test", > props)); > + > + EntityManagerImpl em = > (EntityManagerImpl)emf.createEntityManager(); > + BrokerImpl broker = (BrokerImpl) em.getBroker(); > + DelegatingStoreManager dstore = broker.getStoreManager(); > + JDBCStoreManager jstore = > + (JDBCStoreManager)dstore.getInnermostDelegate(); > + > + em.getTransaction().begin(); > + Person p = new Person(); > + p.setId(1); > + em.persist(p); > + em.flush(); > + em.getTransaction().commit(); > + > + Person p1 = em.find(Person.class, 1); > + Map sqlCache = jstore.getQuerySQLCache(); > + Set keys = sqlCache.keySet(); > + for (Iterator iter = keys.iterator(); iter.hasNext();) { > + Map cacheMap = (Map) iter.next(); > + //make sure there is an entry in the cache > + assertEquals(1, cacheMap.size()); > + } > + > + em.getTransaction().begin(); > + em.remove(p); > + em.flush(); > + em.getTransaction().commit(); > + > + em.close(); > + emf.close(); > + } > + > + /* > + * Verify caching is disabled when the QuerySQLCacheValue > setting is > + * "false". > + */ > + public void testFalseCacheSetting() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", "false"); > + OpenJPAEntityManagerFactorySPI emf = > (OpenJPAEntityManagerFactorySPI) > + OpenJPAPersistence.cast( > + Persistence.createEntityManagerFactory("test", > props)); > + > + EntityManagerImpl em = > (EntityManagerImpl)emf.createEntityManager(); > + BrokerImpl broker = (BrokerImpl) em.getBroker(); > + DelegatingStoreManager dstore = broker.getStoreManager(); > + JDBCStoreManager jstore = > + (JDBCStoreManager)dstore.getInnermostDelegate(); > + > + em.getTransaction().begin(); > + Person p = new Person(); > + p.setId(1); > + em.persist(p); > + em.flush(); > + em.getTransaction().commit(); > + > + Person p1 = em.find(Person.class, 1); > + > + assertFalse(jstore.isQuerySQLCacheOn()); > + > + em.getTransaction().begin(); > + em.remove(p); > + em.flush(); > + em.getTransaction().commit(); > + > + em.close(); > + emf.close(); > + } > + > + /* > + * Verify QuerySQLCacheValue setting with a custom cache > backend uses > + * the expected cache implementation and is caching. > + */ > + public void testCustomCacheSetting() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", > + > "org.apache.openjpa.kernel.TestQuerySQLCache.CustomCacheMap"); > + OpenJPAEntityManagerFactorySPI emf = > (OpenJPAEntityManagerFactorySPI) > + OpenJPAPersistence.cast( > + Persistence.createEntityManagerFactory("test", > props)); > + > + EntityManagerImpl em = > (EntityManagerImpl)emf.createEntityManager(); > + BrokerImpl broker = (BrokerImpl) em.getBroker(); > + DelegatingStoreManager dstore = broker.getStoreManager(); > + JDBCStoreManager jstore = > + (JDBCStoreManager)dstore.getInnermostDelegate(); > + > + em.getTransaction().begin(); > + Person p = new Person(); > + p.setId(1); > + em.persist(p); > + em.flush(); > + em.getTransaction().commit(); > + > + Person p1 = em.find(Person.class, 1); > + > + assertTrue(jstore.isQuerySQLCacheOn()); > + > + Map sqlCache = jstore.getQuerySQLCache(); > + Set keys = sqlCache.keySet(); > + for (Iterator iter = keys.iterator(); iter.hasNext();) { > + Map cacheMap = (Map) iter.next(); > + assertTrue((cacheMap instanceof > + > org.apache.openjpa.kernel.TestQuerySQLCache.CustomCacheMap)); > + //make sure there is an entry in the cache > + assertEquals(1, cacheMap.size()); > + } > + > + em.getTransaction().begin(); > + em.remove(p); > + em.flush(); > + em.getTransaction().commit(); > + > + em.close(); > + emf.close(); > + } > + > + /* > + * Verify an exception is thrown if a bad cache implementation > class > + * is specified. > + */ > + public void testBadCustomCacheSetting() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", > + > "org.apache.openjpa.kernel.TestQuerySQLCache.BadCacheMap"); > + > + try { > + OpenJPAEntityManagerFactorySPI emf = > + > (OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.cast( > + > Persistence.createEntityManagerFactory("test", props)); > + // EMF creation should throw an exception because the > cache > + // implementation class will not be found. > + assertFalse(false); > + } catch (Exception e) { > + assertTrue(true); > + } > + } > + > + /* > + * Verify multi-threaded multi-entity manager finder works with > the > + * QuerySQLCache set to "all". > + */ > + public void testMultiEMCachingAll() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", > + "all"); > + runMultiEMCaching(props); > + } > + > + /* > + * Verify multi-threaded multi-entity manager finder works with > the > + * QuerySQLCache set to "true". > + */ > + public void testMultiEMCachingTrue() { > + Map props = new HashMap(System.getProperties()); > + props.put("openjpa.MetaDataFactory", "jpa(Types=" > + + Person.class.getName() + ")"); > + props.put("openjpa.jdbc.QuerySQLCache", > + "true"); > + runMultiEMCaching(props); > + } > + > + private void runMultiEMCaching(Map props) { > + > + EntityManagerFactory emfac = > + Persistence.createEntityManagerFactory("test", > props); > + > + EntityManager em = emfac.createEntityManager(); > + > + // Create some entities > + em.getTransaction().begin(); > + for (int i = 0; i < nPeople; i++) > + { > + Person p = new Person(); > + p.setId(i); > + em.persist(p); > + } > + em.flush(); > + em.getTransaction().commit(); > + em.close(); > + > + Thread[] newThreads = new Thread[nThreads]; > + FindPeople[] customer = new FindPeople[nThreads]; > + > + for (int i=0; i < nThreads; i++) { > + customer[i] = new FindPeople(emfac, 0, nPeople, > + nIterations, i); > + newThreads[i] = new Thread(customer[i]); > + newThreads[i].start(); > + } > + > + // Wait for the worker threads to complete > + for (int i = 0; i < nThreads; i++) { > + try { > + newThreads[i].join(); > + } catch (InterruptedException e) { > + this.fail("Caught Interrupted Exception: " + e); > + } > + } > + > + // Run through the state of all runnables to assert if any > of them > + // failed. > + for (int i = 0; i < nThreads; i++) { > + assertFalse(customer[i].hadFailures()); > + } > + > + // Clean up the entities used in this test > + em = emfac.createEntityManager(); > + em.getTransaction().begin(); > + > + for (int i = 0; i < nPeople; i++) { > + Person p = em.find(Person.class, i); > + em.remove(p); > + } > + em.flush(); > + em.getTransaction().commit(); > + em.close(); > + } > + > + /* > + * Empty ConcurrentHashMap subclass. Useful for testing custom > cache > + * storage implementations. > + */ > + public class CustomCacheMap extends ConcurrentHashMap { > + > + } > + > + /* > + * Simple runnable to test finder in a tight loop. Multiple > instances > + * of this runnable will run simultaneously. > + */ > + private class FindPeople implements Runnable { > + > + private int startId; > + private int endId; > + private int thread; > + private int iterations; > + private EntityManagerFactory emf; > + private boolean failures = false; > + > + public FindPeople(EntityManagerFactory emf, > + int startId, int endId, int iterations, int thread) { > + super(); > + this.startId = startId; > + this.endId = endId; > + this.thread = thread; > + this.iterations = iterations; > + this.emf = emf; > + } > + > + public boolean hadFailures() > + { > + return failures; > + } > + > + public void run() { > + try { > + EntityManager em = emf.createEntityManager(); > + for (int j = 0; j < iterations; j++) { > + > + for (int i = startId; i < endId; i++) { > + Person p1 = em.find(Person.class, i); > + if (p1.getId() != i) { > + System.out.println("Finder failed: " + > i); > + failures = true; > + break; > + } > + } > + em.clear(); > + } > + em.close(); > + } > + catch (Exception e) { > + failures = true; > + System.out.println("Thread " + thread + " > exception :" + > + e ); > + } > + } > + } > +} > > Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/ > apache/openjpa/kernel/TestQuerySQLCache.java > ------------------------------------------------------------------------------ > svn:eol-style = native > > Modified: openjpa/trunk/openjpa-project/src/doc/manual/ > ref_guide_caching.xml > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-project/src/doc/manual/ > ref_guide_caching.xml (original) > +++ openjpa/trunk/openjpa-project/src/doc/manual/ > ref_guide_caching.xml Fri May 2 14:09:14 2008 > @@ -885,4 +885,85 @@ > > > > +
> + > + Query SQL Cache > + > + > + > + caching > + > + > + query sql cache > + > + > + > +The query SQL cache is a Map used to cache > +pushed-down SQL query strings for the find operation. As a result, > +the SQL queries are only generated once in OpenJPA, and cached > thereafter. > +This query SQL cache is shared across entity managers and the fetch > plan > +is part of the cache key. You can control the SQL cache through > +the > +openjpa.jdbc.QuerySQLCache configuration > property. This > +property accepts a plugin string (see linkend="ref_guide_conf_plugins"/>) > +describing the Map used to associate query > strings and > +their parsed form. This property accepts the following aliases: > + > + > + > + Pre-defined aliases > + > + > + > + > + > + > + > + Alias > + Value > + Notes > + > + > + > + > + > +true > + > + > +org.apache.openjpa.util.CacheMap > + > + > +The default option. Uses a > + > +CacheMap to store sql string. > +CacheMap maintains a fixed number of cache > entries, and an > +optional soft reference map for entries that are moved out of the > LRU space. > +So, for applications that have a monotonically increasing number of > distinct > +queries, this option can be used to ensure that a fixed amount of > memory is > +used by the cache. > + > + > + > + all literal> > + > +org.apache.openjpa.lib.util.ConcurrentHashMap > + > + > +This is the fastest option, but sql string is never dropped from the > +cache, so if you use a large number of dynamic queries, this option > may result > +in ever-increasing memory usage. Note that if your queries only > differ in the > +values of the parameters, this should not be an issue. > + > + > + > + false literal> > + none emphasis> > + > +Disables the sql cache. > + > + > + > + > +
> +
> > > Modified: openjpa/trunk/openjpa-project/src/doc/manual/ > ref_guide_conf.xml > URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml?rev=652913&r1=652912&r2=652913&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml > (original) > +++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml > Fri May 2 14:09:14 2008 > @@ -3328,6 +3328,42 @@ > classes. See for details. > > > +
> + > + openjpa.jdbc.QuerySQLCache > + > + > + > + QuerySQLCache > + > + > + > + > + caching > + > + > + QuerySQLCache > + > + > + > +Property name: > +openjpa.jdbc.QuerySQLCache > + > + > +Resource adaptor config-property: > +QuerySQLCache > + > + > +Default: true. > + > + > +Description: A plugin string (see > +) describing the > +java.util.Map to use for caching of the SQL > string > +used by the find operation. See linkend="ref_guide_cache_querysql"/> for > +details. > + > +
>
> > openjpa.jdbc.ResultSetType > > -- Patrick Linskey 202 669 5907