PHOENIX-1644 Check for min HBase version before creating local index and 
provide means of disabling usage


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/54c4ed80
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/54c4ed80
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/54c4ed80

Branch: refs/heads/calcite
Commit: 54c4ed80869f6ac0011a65d1247285cfae0a6759
Parents: f3c675b
Author: James Taylor <jtay...@salesforce.com>
Authored: Fri Feb 6 14:43:04 2015 -0800
Committer: James Taylor <jtay...@salesforce.com>
Committed: Fri Feb 6 14:59:01 2015 -0800

----------------------------------------------------------------------
 .../phoenix/end2end/DisableLocalIndexIT.java    | 99 ++++++++++++++++++++
 .../phoenix/exception/SQLExceptionCode.java     |  3 +
 .../phoenix/jdbc/PhoenixDatabaseMetaData.java   |  5 +-
 .../query/ConnectionQueryServicesImpl.java      |  8 ++
 .../org/apache/phoenix/query/HTableFactory.java |  3 +-
 .../org/apache/phoenix/query/QueryServices.java |  1 +
 .../phoenix/query/QueryServicesOptions.java     |  1 +
 .../apache/phoenix/schema/MetaDataClient.java   | 13 ++-
 8 files changed, 127 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/it/java/org/apache/phoenix/end2end/DisableLocalIndexIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DisableLocalIndexIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DisableLocalIndexIT.java
new file mode 100644
index 0000000..5f18a1c
--- /dev/null
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DisableLocalIndexIT.java
@@ -0,0 +1,99 @@
+/*
+ * 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.phoenix.end2end;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.util.MetaDataUtil;
+import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.PropertiesUtil;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.TestUtil;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Maps;
+
+public class DisableLocalIndexIT extends BaseHBaseManagedTimeIT {
+    @BeforeClass
+    @Shadower(classBeingShadowed = BaseHBaseManagedTimeIT.class)
+    public static void doSetup() throws Exception {
+        Map<String,String> props = Maps.newHashMapWithExpectedSize(1);
+        // Must update config before starting server
+        props.put(QueryServices.ALLOW_LOCAL_INDEX_ATTRIB, 
Boolean.FALSE.toString());
+        setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator()));
+    }
+
+    @Test
+    public void testDisabledLocalIndexes() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.setAutoCommit(true);
+        String tableName = "DISABLE_LOCAL_INDEX_TEST";
+        conn.createStatement().execute("CREATE TABLE " + tableName + " (k1 
VARCHAR NOT NULL, k2 VARCHAR, CONSTRAINT PK PRIMARY KEY(K1,K2)) 
MULTI_TENANT=true");
+        conn.createStatement().execute("UPSERT INTO " + tableName + " 
VALUES('t1','x')");
+        conn.createStatement().execute("UPSERT INTO " + tableName + " 
VALUES('t2','y')");
+        HBaseAdmin admin = 
conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin();
+        
assertFalse(admin.tableExists(Bytes.toBytes(MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX
 + tableName)));
+        admin.close();
+        try {
+            HTableInterface t = 
conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX
 + tableName));
+            t.getTableDescriptor(); // Exception no longer thrown by getTable, 
but instead need to force an RPC
+            fail("Local index table should not have been created");
+        } catch (org.apache.hadoop.hbase.TableNotFoundException e) {
+            //expected
+        } finally {
+            admin.close();
+        }
+        
+        Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, "t1");
+        Connection tsconn = DriverManager.getConnection(getUrl(), props);
+        
+        tsconn.createStatement().execute("CREATE VIEW A.BAR(V1 VARCHAR) AS 
SELECT * FROM " + tableName);
+        tsconn.createStatement().execute("CREATE INDEX I1 ON A.BAR(V1)");
+        
tsconn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(MetaDataUtil.VIEW_INDEX_TABLE_PREFIX
 + tableName));
+
+        try {
+            conn.createStatement().execute("CREATE LOCAL INDEX I2 ON " + 
tableName + "(k2)");
+            fail("Should not allow creation of local index");
+        } catch (SQLException e) {
+            
assertEquals(SQLExceptionCode.UNALLOWED_LOCAL_INDEXES.getErrorCode(), 
e.getErrorCode());
+        }
+        try {
+            tsconn.createStatement().execute("CREATE LOCAL INDEX I2 ON 
A.BAR(k2, v1)");
+            fail("Should not allow creation of local index");
+        } catch (SQLException e) {
+            
assertEquals(SQLExceptionCode.UNALLOWED_LOCAL_INDEXES.getErrorCode(), 
e.getErrorCode());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java 
b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 8a6b8d0..19e7cdf 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -236,6 +236,9 @@ public enum SQLExceptionCode {
     CANNOT_SET_PROPERTY_FOR_COLUMN_NOT_ADDED(1052, "43A09", "Property cannot 
be specified for a column family that is not being added or modified"),
     CANNOT_SET_TABLE_PROPERTY_ADD_COLUMN(1053, "43A10", "Table level property 
cannot be set when adding a column"),
     
+    NO_LOCAL_INDEXES(1054, "43A11", "Local secondary indexes are only 
supported for HBase version " + 
MetaDataUtil.decodeHBaseVersionAsString(PhoenixDatabaseMetaData.LOCAL_SI_VERSION_THRESHOLD)
 + " and above."),
+    UNALLOWED_LOCAL_INDEXES(1055, "43A12", "Local secondary indexes are 
configured to not be allowed."),
+
     /** Sequence related */
     SEQUENCE_ALREADY_EXIST(1200, "42Z00", "Sequence already exists.", new 
Factory() {
         @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
index b26f408..7ac2bb6 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
@@ -52,17 +52,17 @@ import org.apache.phoenix.iterate.DelegateResultIterator;
 import org.apache.phoenix.iterate.MaterializedResultIterator;
 import org.apache.phoenix.iterate.ResultIterator;
 import org.apache.phoenix.query.QueryConstants;
-import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PName;
 import org.apache.phoenix.schema.PTable.LinkType;
 import org.apache.phoenix.schema.PTableType;
-import org.apache.phoenix.schema.types.PVarchar;
 import org.apache.phoenix.schema.RowKeyValueAccessor;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.tuple.ResultTuple;
 import org.apache.phoenix.schema.tuple.SingleKeyValueTuple;
 import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
 import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.KeyValueUtil;
 import org.apache.phoenix.util.SchemaUtil;
@@ -274,6 +274,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     public static final int ESSENTIAL_FAMILY_VERSION_THRESHOLD = 
VersionUtil.encodeVersion("0", "94", "7");
     // Version below which we should disallow usage of mutable secondary 
indexing.
     public static final int MUTABLE_SI_VERSION_THRESHOLD = 
VersionUtil.encodeVersion("0", "94", "10");
+    public static final int LOCAL_SI_VERSION_THRESHOLD = 
VersionUtil.encodeVersion("0", "98", "9");
     /** Version below which we fall back on the generic KeyValueBuilder */
     public static final int CLIENT_KEY_VALUE_BUILDER_THRESHOLD = 
VersionUtil.encodeVersion("0", "94", "14");
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 97efc43..6d58f57 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -1069,6 +1069,14 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
     }
 
     private void ensureLocalIndexTableCreated(byte[] physicalTableName, 
Map<String, Object> tableProps, List<Pair<byte[], Map<String, Object>>> 
families, byte[][] splits) throws SQLException, TableAlreadyExistsException {
+        
+        // If we're not allowing local indexes or the hbase version is too low,
+        // don't create the local index table
+        if (   
!this.getProps().getBoolean(QueryServices.ALLOW_LOCAL_INDEX_ATTRIB, 
QueryServicesOptions.DEFAULT_ALLOW_LOCAL_INDEX) 
+            || getLowestClusterHBaseVersion() < 
PhoenixDatabaseMetaData.LOCAL_SI_VERSION_THRESHOLD) {
+                    return;
+        }
+        
         tableProps.put(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_NAME, 
TRUE_BYTES_AS_STRING);
         HTableDescriptor desc = ensureTableCreated(physicalTableName, 
PTableType.TABLE, tableProps, families, splits, true);
         if (desc != null) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/query/HTableFactory.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/query/HTableFactory.java 
b/phoenix-core/src/main/java/org/apache/phoenix/query/HTableFactory.java
index 447267c..7a10683 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/HTableFactory.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/HTableFactory.java
@@ -21,7 +21,6 @@ import java.io.IOException;
 import java.util.concurrent.ExecutorService;
 
 import org.apache.hadoop.hbase.client.HConnection;
-import org.apache.hadoop.hbase.client.HTable;
 import org.apache.hadoop.hbase.client.HTableInterface;
 
 /**
@@ -48,7 +47,7 @@ public interface HTableFactory {
     static class HTableFactoryImpl implements HTableFactory {
         @Override
         public HTableInterface getTable(byte[] tableName, HConnection 
connection, ExecutorService pool) throws IOException {
-            return new HTable(tableName, connection, pool);
+            return connection.getTable(tableName, pool);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java 
b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index ce9016d..d21695d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -123,6 +123,7 @@ public interface QueryServices extends SQLCloseable {
     public static final String MIN_INDEX_PRIOIRTY_ATTRIB = 
"phoenix.regionserver.index.priority.min";
     public static final String MAX_INDEX_PRIOIRTY_ATTRIB = 
"phoenix.regionserver.index.priority.max";
     public static final String INDEX_HANDLER_COUNT_ATTRIB = 
"phoenix.regionserver.index.handler.count";
+    public static final String ALLOW_LOCAL_INDEX_ATTRIB = 
"phoenix.index.allowLocalIndex";
 
     // Config parameters for for configuring tracing
     public static final String TRACING_FREQ_ATTRIB = "phoenix.trace.frequency";

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java 
b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
index 5913796..0f9139f 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
@@ -144,6 +144,7 @@ public class QueryServicesOptions {
      */
     public static final int DEFAULT_INDEX_MIN_PRIORITY = 1000;
     public static final int DEFAULT_INDEX_HANDLER_COUNT = 30;
+    public static final boolean DEFAULT_ALLOW_LOCAL_INDEX = true;
 
     public static final int DEFAULT_TRACING_PAGE_SIZE = 100;
     /**

http://git-wip-us.apache.org/repos/asf/phoenix/blob/54c4ed80/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java 
b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
index 09d2f66..effdb54 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
@@ -909,6 +909,16 @@ public class MetaDataClient {
         boolean retry = true;
         Short indexId = null;
         boolean allocateIndexId = false;
+        boolean isLocalIndex = statement.getIndexType() == IndexType.LOCAL;
+        int hbaseVersion = 
connection.getQueryServices().getLowestClusterHBaseVersion();
+        if (isLocalIndex) {
+            if 
(!connection.getQueryServices().getProps().getBoolean(QueryServices.ALLOW_LOCAL_INDEX_ATTRIB,
 QueryServicesOptions.DEFAULT_ALLOW_LOCAL_INDEX)) {
+                throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.UNALLOWED_LOCAL_INDEXES).setTableName(indexTableName.getTableName()).build().buildException();
+            }
+            if (hbaseVersion < 
PhoenixDatabaseMetaData.LOCAL_SI_VERSION_THRESHOLD) {
+                throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.NO_LOCAL_INDEXES).setTableName(indexTableName.getTableName()).build().buildException();
+            }
+        }
         while (true) {
             try {
                 ColumnResolver resolver = FromCompiler.getResolver(statement, 
connection);
@@ -920,7 +930,6 @@ public class MetaDataClient {
                         throw new SQLFeatureNotSupportedException("An index 
may only be created for a VIEW through a tenant-specific connection");
                     }
                 }
-                int hbaseVersion = 
connection.getQueryServices().getLowestClusterHBaseVersion();
                 if (!dataTable.isImmutableRows()) {
                     if (hbaseVersion < 
PhoenixDatabaseMetaData.MUTABLE_SI_VERSION_THRESHOLD) {
                         throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.NO_MUTABLE_INDEXES).setTableName(indexTableName.getTableName()).build().buildException();
@@ -960,7 +969,7 @@ public class MetaDataClient {
                  * 1) for a local index, as all local indexes will reside in 
the same HBase table
                  * 2) for a view on an index.
                  */
-                if (statement.getIndexType() == IndexType.LOCAL || 
(dataTable.getType() == PTableType.VIEW && dataTable.getViewType() != 
ViewType.MAPPED)) {
+                if (isLocalIndex || (dataTable.getType() == PTableType.VIEW && 
dataTable.getViewType() != ViewType.MAPPED)) {
                     allocateIndexId = true;
                     // Next add index ID column
                     PDataType dataType = MetaDataUtil.getViewIndexIdDataType();

Reply via email to