KYLIN-2583 introduce DBCP as DataSource with cache logic

Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/5e6ed11e
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/5e6ed11e
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/5e6ed11e

Branch: refs/heads/master
Commit: 5e6ed11efd9a6a607fd1c8abf01f2c0d829c5e62
Parents: ca106b8
Author: Yifan Zhang <event.dim...@gmail.com>
Authored: Fri May 5 09:46:28 2017 +0800
Committer: hongbin ma <m...@kyligence.io>
Committed: Fri May 5 10:31:54 2017 +0800

----------------------------------------------------------------------
 .../org/apache/kylin/query/KylinTestBase.java   |   4 +-
 .../java/org/apache/kylin/query/QueryCli.java   |   9 +-
 .../org/apache/kylin/query/QueryDataSource.java | 162 +++++++++++++++++++
 .../apache/kylin/query/QueryDataSourceTest.java |  86 ++++++++++
 .../apache/kylin/rest/service/CacheService.java |  39 +----
 5 files changed, 256 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/5e6ed11e/kylin-it/src/test/java/org/apache/kylin/query/KylinTestBase.java
----------------------------------------------------------------------
diff --git a/kylin-it/src/test/java/org/apache/kylin/query/KylinTestBase.java 
b/kylin-it/src/test/java/org/apache/kylin/query/KylinTestBase.java
index 2174094..fad7a94 100644
--- a/kylin-it/src/test/java/org/apache/kylin/query/KylinTestBase.java
+++ b/kylin-it/src/test/java/org/apache/kylin/query/KylinTestBase.java
@@ -49,7 +49,6 @@ import org.apache.kylin.common.util.Pair;
 import org.apache.kylin.metadata.project.ProjectInstance;
 import org.apache.kylin.query.relnode.OLAPContext;
 import org.apache.kylin.query.routing.rules.RemoveBlackoutRealizationsRule;
-import org.apache.kylin.query.schema.OLAPSchemaFactory;
 import org.dbunit.DatabaseUnitException;
 import org.dbunit.database.DatabaseConfig;
 import org.dbunit.database.DatabaseConnection;
@@ -659,8 +658,7 @@ public class KylinTestBase {
         config = KylinConfig.getInstanceFromEnv();
 
         //setup cube conn
-        File olapTmp = 
OLAPSchemaFactory.createTempOLAPJson(ProjectInstance.DEFAULT_PROJECT_NAME, 
config);
-        cubeConnection = DriverManager.getConnection("jdbc:calcite:model=" + 
olapTmp.getAbsolutePath());
+        cubeConnection = 
QueryDataSource.create(ProjectInstance.DEFAULT_PROJECT_NAME, 
config).getConnection();
 
         //setup h2
         h2Connection = DriverManager.getConnection("jdbc:h2:mem:db" + 
(h2InstanceCount++) + ";CACHE_SIZE=32072", "sa", "");

http://git-wip-us.apache.org/repos/asf/kylin/blob/5e6ed11e/query/src/main/java/org/apache/kylin/query/QueryCli.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/QueryCli.java 
b/query/src/main/java/org/apache/kylin/query/QueryCli.java
index d3f1521..5ced8e3 100644
--- a/query/src/main/java/org/apache/kylin/query/QueryCli.java
+++ b/query/src/main/java/org/apache/kylin/query/QueryCli.java
@@ -18,14 +18,11 @@
 
 package org.apache.kylin.query;
 
-import java.io.File;
 import java.sql.Connection;
-import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.Statement;
 
-import org.apache.calcite.jdbc.Driver;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.GnuParser;
@@ -34,7 +31,6 @@ import org.apache.commons.cli.OptionBuilder;
 import org.apache.commons.cli.Options;
 import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.util.DBUtils;
-import org.apache.kylin.query.schema.OLAPSchemaFactory;
 
 public class QueryCli {
 
@@ -55,14 +51,11 @@ public class QueryCli {
         KylinConfig config = 
KylinConfig.createInstanceFromUri(commandLine.getOptionValue(OPTION_METADATA.getOpt()));
         String sql = commandLine.getOptionValue(OPTION_SQL.getOpt());
 
-        Class.forName(Driver.class.getName());
-        File olapTmp = OLAPSchemaFactory.createTempOLAPJson(null, config);
-
         Connection conn = null;
         Statement stmt = null;
         ResultSet rs = null;
         try {
-            conn = DriverManager.getConnection("jdbc:calcite:model=" + 
olapTmp.getAbsolutePath());
+            conn = QueryDataSource.create(null, config).getConnection();
 
             stmt = conn.createStatement();
             rs = stmt.executeQuery(sql);

http://git-wip-us.apache.org/repos/asf/kylin/blob/5e6ed11e/query/src/main/java/org/apache/kylin/query/QueryDataSource.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/QueryDataSource.java 
b/query/src/main/java/org/apache/kylin/query/QueryDataSource.java
new file mode 100644
index 0000000..32feea6
--- /dev/null
+++ b/query/src/main/java/org/apache/kylin/query/QueryDataSource.java
@@ -0,0 +1,162 @@
+/*
+ * 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.kylin.query;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.sql.DataSource;
+
+import org.apache.calcite.jdbc.Driver;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.dbcp.BasicDataSourceFactory;
+import org.apache.commons.io.FileUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.query.schema.OLAPSchemaFactory;
+import org.apache.log4j.Logger;
+
+import com.google.common.collect.Lists;
+
+public class QueryDataSource {
+
+    private static final Logger logger = 
Logger.getLogger(QueryDataSource.class);
+
+    private ConcurrentMap<String, DataSource> olapDataSources = new 
ConcurrentHashMap<String, DataSource>();
+    private List<File> usedFiles = Lists.newLinkedList();
+
+    /**
+     * Get available data source
+     * 
+     * @param project
+     * @param config
+     * @return
+     * @throws Exception
+     */
+    public DataSource get(String project, KylinConfig config) {
+        return get(project, config, new Properties());
+    }
+
+    /**
+     * Get available data source with advanced DBCP configuration
+     * 
+     * @see http://commons.apache.org/proper/commons-dbcp/configuration.html
+     * 
+     * @param project
+     * @param config
+     * @return
+     */
+    public DataSource get(String project, KylinConfig config, Properties 
props) {
+        if (project == null) {
+            throw new IllegalArgumentException("project should not be null");
+        }
+        
+        DataSource ds = olapDataSources.get(project);
+        if (ds != null) {
+            return ds;
+        }
+        
+        WrappedDataSource wrappedDS = getWrapped(project, config, props);
+        ds = wrappedDS.getDataSource();
+        olapDataSources.putIfAbsent(project, ds);
+        usedFiles.add(wrappedDS.getOlapFile());
+        return ds;
+    }
+
+    public DataSource removeCache(String project) {
+        return olapDataSources.remove(project);
+    }
+
+    public void clearCache() {
+        olapDataSources.clear();
+        for (File usedFile : usedFiles) {
+            FileUtils.deleteQuietly(usedFile);
+        }
+    }
+
+    /**
+     * Get data source without cache
+     * 
+     * @param project
+     * @param config
+     * @return
+     */
+    public static DataSource create(String project, KylinConfig config) {
+        return create(project, config, new Properties());
+    }
+
+    /**
+     * Get data source without cache, advanced configuration
+     * 
+     * @param project
+     * @param config
+     * @param props
+     * @return
+     */
+    public static DataSource create(String project, KylinConfig config, 
Properties props) {
+        return getWrapped(project, config, props).getDataSource();
+    }
+
+    private static WrappedDataSource getWrapped(String project, KylinConfig 
config, Properties props) {
+        File olapTmp = OLAPSchemaFactory.createTempOLAPJson(project, config);
+        if (logger.isDebugEnabled()) {
+            try {
+                String text = FileUtils.readFileToString(olapTmp, 
Charset.defaultCharset());
+                logger.debug("The new temp olap json is :" + text);
+            } catch (IOException e) {
+                // logging failure is not critical
+            }
+        }
+
+        BasicDataSource ds = null;
+        try {
+            ds = (BasicDataSource) 
BasicDataSourceFactory.createDataSource(props);
+        } catch (Exception e) {
+            // Basic mode
+            ds = new BasicDataSource();
+        }
+        ds.setUrl("jdbc:calcite:model=" + olapTmp.getAbsolutePath());
+        ds.setDriverClassName(Driver.class.getName());
+
+        WrappedDataSource wrappedDS = new WrappedDataSource(ds, olapTmp);
+        return wrappedDS;
+    }
+
+    private static class WrappedDataSource {
+        private DataSource ds;
+        private File tempOlap;
+
+        private WrappedDataSource(DataSource dataSource, File olapModel) {
+            this.ds = dataSource;
+            this.tempOlap = olapModel;
+        }
+
+        public DataSource getDataSource() {
+            return ds;
+        }
+
+        public File getOlapFile() {
+            return tempOlap;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/5e6ed11e/query/src/test/java/org/apache/kylin/query/QueryDataSourceTest.java
----------------------------------------------------------------------
diff --git 
a/query/src/test/java/org/apache/kylin/query/QueryDataSourceTest.java 
b/query/src/test/java/org/apache/kylin/query/QueryDataSourceTest.java
new file mode 100644
index 0000000..90d3518
--- /dev/null
+++ b/query/src/test/java/org/apache/kylin/query/QueryDataSourceTest.java
@@ -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.kylin.query;
+
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.apache.calcite.jdbc.Driver;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.LocalFileMetadataTestCase;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class QueryDataSourceTest extends LocalFileMetadataTestCase {
+
+    @Before
+    public void setUp() throws Exception {
+        this.createTestMetadata();
+    }
+
+    @After
+    public void after() throws Exception {
+        this.cleanupTestMetadata();
+    }
+
+    @Test
+    public void testCreateDataSource() {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        DataSource ds = QueryDataSource.create("default", config);
+        Assert.assertNotNull(ds);
+    }
+
+    @Test
+    public void testCreateDataSourceWithProps() {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        Properties props = new Properties();
+        props.setProperty("username", "ADMIN");
+        props.setProperty("password", "KYLIN");
+        BasicDataSource ds = (BasicDataSource) 
QueryDataSource.create("default", config, props);
+
+        Assert.assertNotNull(ds);
+        Assert.assertTrue(ds instanceof BasicDataSource);
+        Assert.assertTrue(ds.getUrl().startsWith("jdbc:calcite:model="));
+        Assert.assertEquals(ds.getDriverClassName(), Driver.class.getName());
+        Assert.assertEquals(ds.getUsername(), "ADMIN");
+        Assert.assertEquals(ds.getPassword(), "KYLIN");
+    }
+
+    @Test
+    public void testGetCachedDataSource() {
+        QueryDataSource dsCache = new QueryDataSource();
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        DataSource ds1 = dsCache.get("default", config);
+        DataSource ds2 = dsCache.get("default", config);
+        dsCache.removeCache("default");
+        DataSource ds3 = dsCache.get("default", config);
+
+        Assert.assertNotNull(ds1);
+        Assert.assertNotNull(ds2);
+        Assert.assertNotNull(ds3);
+        Assert.assertEquals(ds1, ds2);
+        Assert.assertNotEquals(ds1, ds3);
+        
+        dsCache.clearCache();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/5e6ed11e/server-base/src/main/java/org/apache/kylin/rest/service/CacheService.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/service/CacheService.java 
b/server-base/src/main/java/org/apache/kylin/rest/service/CacheService.java
index d3d6237..fc82bfe 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/service/CacheService.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/CacheService.java
@@ -18,25 +18,18 @@
 
 package org.apache.kylin.rest.service;
 
-import java.io.File;
 import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
 import javax.sql.DataSource;
 
-import org.apache.calcite.jdbc.Driver;
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.kylin.metadata.cachesync.Broadcaster;
 import org.apache.kylin.metadata.cachesync.Broadcaster.Event;
 import org.apache.kylin.metadata.project.ProjectInstance;
-import org.apache.kylin.query.schema.OLAPSchemaFactory;
+import org.apache.kylin.query.QueryDataSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import org.springframework.stereotype.Component;
 
 import net.sf.ehcache.CacheManager;
@@ -47,8 +40,8 @@ import net.sf.ehcache.CacheManager;
 public class CacheService extends BasicService {
 
     private static final Logger logger = 
LoggerFactory.getLogger(CacheService.class);
-
-    private ConcurrentMap<String, DataSource> olapDataSources = new 
ConcurrentHashMap<String, DataSource>();
+    
+    private static QueryDataSource queryDataSource = new QueryDataSource();
 
     @Autowired
     private CubeService cubeService;
@@ -137,40 +130,20 @@ public class CacheService extends BasicService {
             throw new IllegalArgumentException("removeOLAPDataSource: project 
name not given");
 
         project = ProjectInstance.getNormalizedProjectName(project);
-        olapDataSources.remove(project);
+        queryDataSource.removeCache(project);
     }
 
     public void removeAllOLAPDataSources() {
         // brutal, yet simplest way
         logger.info("removeAllOLAPDataSources is called.");
-        olapDataSources.clear();
+        queryDataSource.clearCache();
     }
 
     public DataSource getOLAPDataSource(String project) {
 
         project = ProjectInstance.getNormalizedProjectName(project);
 
-        DataSource ret = olapDataSources.get(project);
-        if (ret == null) {
-            logger.debug("Creating a new data source, OLAP data source 
pointing to " + getConfig());
-            File modelJson = OLAPSchemaFactory.createTempOLAPJson(project, 
getConfig());
-
-            try {
-                String text = FileUtils.readFileToString(modelJson, 
Charset.defaultCharset());
-                logger.debug("The new temp olap json is :" + text);
-            } catch (IOException e) {
-                e.printStackTrace(); // logging failure is not critical
-            }
-
-            DriverManagerDataSource ds = new DriverManagerDataSource();
-            ds.setDriverClassName(Driver.class.getName());
-            ds.setUrl("jdbc:calcite:model=" + modelJson.getAbsolutePath());
-
-            ret = olapDataSources.putIfAbsent(project, ds);
-            if (ret == null) {
-                ret = ds;
-            }
-        }
+        DataSource ret = queryDataSource.get(project, getConfig());
         return ret;
     }
 

Reply via email to