From 5e6aa6855043567738048906ef8cea920068922d Mon Sep 17 00:00:00 2001 From: Luc Boudreau Date: Mon, 5 Mar 2012 16:15:31 +0000 Subject: [PATCH] Fixes the trivial call on connect by populating lazily the list of database properties, only when it is needed. Fixes a concurrency issue in the XmlaOlap4jStatement where canceling before the request started would skip the cancellation. Fixes an issue with the XMLA connection test where background statements were not cleaned after a cleanup. git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@519 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- .../driver/xmla/XmlaOlap4jConnection.java | 55 ++++++++++++------- .../driver/xmla/XmlaOlap4jStatement.java | 18 ++++-- testsrc/org/olap4j/ConnectionTest.java | 13 +++++ 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index a099898..646acfd 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -40,6 +40,7 @@ import java.sql.*; import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; @@ -138,7 +139,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection { private final URL serverUrlObject; - private HashSet olap4jDatabaseProperties; + private HashSet olap4jDatabaseProperties = null; /** * This is a private property used for development only. @@ -257,22 +258,6 @@ public void setSessionId(String sessionId) { null, null, null, null, null, null), new XmlaOlap4jConnection.DatabaseHandler(), null); - - this.olap4jDatabaseProperties = new HashSet(); - final ResultSet rs = - this.olap4jDatabaseMetaData.getDatabaseProperties(null, null); - try { - while (rs.next()) { - String property = - rs.getString(XmlaConstants.Literal.PROPERTY_NAME.name()); - if (property != null) { - property = property.toUpperCase(); - olap4jDatabaseProperties.add(property); - } - } - } finally { - rs.close(); - } } /** @@ -331,7 +316,37 @@ static boolean acceptsURL(String url) { return url.startsWith(CONNECT_STRING_PREFIX); } - String makeConnectionPropertyList() { + String makeConnectionPropertyList() throws OlapException { + synchronized (propPopulation) { + if (propPopulation.get()) { + return ""; + } + if (this.olap4jDatabaseProperties == null) { + propPopulation.set(true); + this.olap4jDatabaseProperties = new HashSet(); + final ResultSet rs = + this.olap4jDatabaseMetaData.getDatabaseProperties(null, null); + try { + while (rs.next()) { + String property = + rs.getString(XmlaConstants.Literal.PROPERTY_NAME.name()); + if (property != null) { + property = property.toUpperCase(); + olap4jDatabaseProperties.add(property); + } + } + } catch (SQLException e) { + throw new OlapException(e); + } finally { + propPopulation.set(false); + try { + rs.close(); + } catch (SQLException e) { + throw new OlapException(); + } + } + } + } StringBuilder buf = new StringBuilder(); for (String prop : databaseProperties.keySet()) { if (prop.startsWith( @@ -908,6 +923,8 @@ Element executeMetadataRequest(String request) throws OlapException { return findChild(returnElement, ROWSET_NS, "root"); } + final AtomicBoolean propPopulation = new AtomicBoolean(false); + /** * Generates a metadata request. * @@ -2358,7 +2375,7 @@ enum MetadataRequest { * @return whether this request requires a DatasourceName element */ public boolean requiresDatasourceName() { - return this != DISCOVER_DATASOURCES; + return this != DISCOVER_DATASOURCES && this != DISCOVER_PROPERTIES; } /** diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java b/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java index b7b4b5e..79e06fa 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java @@ -48,6 +48,9 @@ abstract class XmlaOlap4jStatement implements OlapStatement { int timeoutSeconds; Future future; + // Tells this statement to cancel as soon as it starts. + private boolean cancelEarly = false; + /** * Creates an XmlaOlap4jStatement. * @@ -130,10 +133,14 @@ public void setQueryTimeout(int seconds) throws SQLException { } public synchronized void cancel() { - if (!canceled) { - canceled = true; - if (future != null) { - future.cancel(true); + synchronized (this) { + if (!canceled) { + if (future != null) { + canceled = true; + future.cancel(true); + } else { + this.cancelEarly = true; + } } } } @@ -348,6 +355,9 @@ public CellSet executeOlapQuery(String mdx) throws OlapException { olap4jConnection.serverInfos, request); openCellSet = olap4jConnection.factory.newCellSet(this); } + if (cancelEarly) { + cancel(); + } // Release the monitor before calling populate, so that cancel can // grab the monitor if it needs to. openCellSet.populate(); diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index efffbef..8b2ac82 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -2576,6 +2576,13 @@ public void run() { } ).start(); try { + // Because XMLA doesn't pass cancel statements, + // we set a query timeout to cleanup in the background + if (tester.getFlavor().equals(Flavor.XMLA) + || tester.getFlavor().equals(Flavor.REMOTE_XMLA)) + { + MondrianProperties.instance().QueryTimeout.set(5); + } final CellSet cellSet = olapStatement.executeOlapQuery( "SELECT Filter(\n" + " [Product].Members *\n" @@ -2590,6 +2597,12 @@ public void run() { assertTrue( e.getMessage(), e.getMessage().indexOf("Query canceled") >= 0); + } finally { + if (tester.getFlavor().equals(Flavor.XMLA) + || tester.getFlavor().equals(Flavor.REMOTE_XMLA)) + { + MondrianProperties.instance().QueryTimeout.set(0); + } } if (exceptions[0] != null) { throw exceptions[0];