You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/04/26 06:36:04 UTC
git commit: PHOENIX-935 create local index table with the same split
keys of user table (Rajeshbabu)
Repository: incubator-phoenix
Updated Branches:
refs/heads/local-index 611045292 -> 492f77522
PHOENIX-935 create local index table with the same split keys of user table (Rajeshbabu)
Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/492f7752
Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/492f7752
Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/492f7752
Branch: refs/heads/local-index
Commit: 492f775227391d87128aa174035d4c3a60b9b42e
Parents: 6110452
Author: James Taylor <ja...@apache.org>
Authored: Fri Apr 25 21:36:03 2014 -0700
Committer: James Taylor <ja...@apache.org>
Committed: Fri Apr 25 21:36:03 2014 -0700
----------------------------------------------------------------------
.../phoenix/end2end/index/LocalIndexIT.java | 62 +++++++++++++++++-
.../index/balancer/TestIndexLoadBalancer.java | 43 +-----------
.../hbase/index/IndexRegionSplitPolicy.java | 32 +++++++++
.../hbase/index/master/IndexMasterObserver.java | 69 ++++++++++++++++++++
.../query/ConnectionQueryServicesImpl.java | 47 ++++++++++++-
.../apache/phoenix/schema/MetaDataClient.java | 35 ++++++++--
.../org/apache/phoenix/util/MetaDataUtil.java | 29 ++++++++
7 files changed, 267 insertions(+), 50 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
index 4589259..4c3e8ab 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java
@@ -19,33 +19,43 @@ package org.apache.phoenix.end2end.index;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.phoenix.hbase.index.IndexRegionSplitPolicy;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTable.IndexType;
import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.TableNotFoundException;
+import org.apache.phoenix.util.MetaDataUtil;
+import org.apache.phoenix.util.TestUtil;
import org.junit.Test;
public class LocalIndexIT extends BaseIndexIT {
- private void createBaseTable(String tableName, Integer saltBuckets) throws SQLException {
+ private void createBaseTable(String tableName, Integer saltBuckets, String splits) throws SQLException {
Connection conn = DriverManager.getConnection(getUrl());
String ddl = "CREATE TABLE " + tableName + " (t_id VARCHAR NOT NULL,\n" +
"k1 INTEGER NOT NULL,\n" +
"k2 INTEGER NOT NULL,\n" +
"v1 VARCHAR,\n" +
"CONSTRAINT pk PRIMARY KEY (t_id, k1, k2))\n"
- + (saltBuckets == null ? "" : (",salt_buckets="+saltBuckets));
+ + (saltBuckets == null || splits != null ? "" : (",salt_buckets=" + saltBuckets)
+ + (saltBuckets != null || splits == null ? "" : ",splits=" + splits));
conn.createStatement().execute(ddl);
conn.close();
}
@Test
public void testLocalIndexRoundTrip() throws Exception {
- createBaseTable(DATA_TABLE_NAME, null);
+ createBaseTable(DATA_TABLE_NAME, null, null);
Connection conn1 = DriverManager.getConnection(getUrl());
Connection conn2 = DriverManager.getConnection(getUrl());
conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + " ON " + DATA_TABLE_NAME + "(v1)");
@@ -54,5 +64,51 @@ public class LocalIndexIT extends BaseIndexIT {
assertEquals(IndexType.LOCAL, localIndex.getIndexType());
assertNotNull(localIndex.getViewIndexId());
}
+
+ @Test
+ public void testLocalIndexCreationWithSplitsShouldFail() throws Exception {
+ createBaseTable(DATA_TABLE_NAME, null, null);
+ Connection conn1 = DriverManager.getConnection(getUrl());
+ Connection conn2 = DriverManager.getConnection(getUrl());
+ try {
+ conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + " ON " + DATA_TABLE_NAME + "(v1)"+" splits={1,2,3}");
+ fail("Local index cannot be pre-split");
+ } catch (SQLException e) { }
+ try {
+ conn2.createStatement().executeQuery("SELECT * FROM " + DATA_TABLE_FULL_NAME).next();
+ conn2.unwrap(PhoenixConnection.class).getMetaDataCache().getTable(new PTableKey(null,INDEX_TABLE_NAME));
+ fail("Local index should be created.");
+ } catch (TableNotFoundException e) { }
+ }
+
+ @Test
+ public void testLocalIndexCreationWithSaltingShouldFail() throws Exception {
+ createBaseTable(DATA_TABLE_NAME, null, null);
+ Connection conn1 = DriverManager.getConnection(getUrl());
+ Connection conn2 = DriverManager.getConnection(getUrl());
+ try {
+ conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + " ON " + DATA_TABLE_NAME + "(v1)"+" salt_buckets=16");
+ fail("Local index cannot be salted.");
+ } catch (SQLException e) { }
+ try {
+ conn2.createStatement().executeQuery("SELECT * FROM " + DATA_TABLE_FULL_NAME).next();
+ conn2.unwrap(PhoenixConnection.class).getMetaDataCache().getTable(new PTableKey(null,INDEX_TABLE_NAME));
+ fail("Local index should not be created.");
+ } catch (TableNotFoundException e) { }
+ }
+ @Test
+ public void testLocalIndexTableRegionSplitPolicyAndSplitKeys() throws Exception {
+ createBaseTable(DATA_TABLE_NAME, null,"{1,2,3}");
+ Connection conn1 = DriverManager.getConnection(getUrl());
+ Connection conn2 = DriverManager.getConnection(getUrl());
+ conn1.createStatement().execute("CREATE LOCAL INDEX " + INDEX_TABLE_NAME + " ON " + DATA_TABLE_NAME + "(v1)");
+ conn2.createStatement().executeQuery("SELECT * FROM " + DATA_TABLE_FULL_NAME).next();
+ HBaseAdmin admin = driver.getConnectionQueryServices(getUrl(), TestUtil.TEST_PROPERTIES).getAdmin();
+ HTableDescriptor htd = admin.getTableDescriptor(TableName.valueOf(MetaDataUtil.getLocalIndexTableName(DATA_TABLE_NAME)));
+ assertEquals(IndexRegionSplitPolicy.class.getName(), htd.getValue(HTableDescriptor.SPLIT_POLICY));
+ HTable userTable = new HTable(admin.getConfiguration(),TableName.valueOf(DATA_TABLE_NAME));
+ HTable indexTable = new HTable(admin.getConfiguration(),TableName.valueOf(MetaDataUtil.getLocalIndexTableName(DATA_TABLE_NAME)));
+ assertEquals("Both user region and index table should have same split keys.", userTable.getStartKeys(), indexTable.getStartKeys());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/balancer/TestIndexLoadBalancer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/balancer/TestIndexLoadBalancer.java b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/balancer/TestIndexLoadBalancer.java
index fb0afa9..7a5d61c 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/balancer/TestIndexLoadBalancer.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/balancer/TestIndexLoadBalancer.java
@@ -39,10 +39,7 @@ import org.apache.hadoop.hbase.catalog.MetaReader;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
-import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
-import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
-import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.master.LoadBalancer;
import org.apache.hadoop.hbase.master.RegionStates;
@@ -55,6 +52,7 @@ import org.apache.hadoop.hbase.zookeeper.ZKAssign;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.phoenix.hbase.index.IndexTestingUtils;
import org.apache.phoenix.hbase.index.Indexer;
+import org.apache.phoenix.hbase.index.master.IndexMasterObserver;
import org.apache.phoenix.util.ConfigUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -75,7 +73,7 @@ public class TestIndexLoadBalancer {
final int NUM_RS = 4;
Configuration conf = UTIL.getConfiguration();
conf.setBoolean(HConstants.REGIONSERVER_INFO_PORT_AUTO, true);
- conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, MockedMasterObserver.class.getName());
+ conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, IndexMasterObserver.class.getName());
conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, IndexLoadBalancer.class,
LoadBalancer.class);
IndexTestingUtils.setupConfig(conf);
@@ -491,41 +489,4 @@ public class TestIndexLoadBalancer {
}
return regionsColocated;
}
-
- public static class MockedMasterObserver extends BaseMasterObserver {
- IndexLoadBalancer balancer = null;
-
- @Override
- public void preMasterInitialization(ObserverContext<MasterCoprocessorEnvironment> ctx)
- throws IOException {
- LoadBalancer loadBalancer =
- ctx.getEnvironment().getMasterServices().getAssignmentManager().getBalancer();
- if (loadBalancer instanceof IndexLoadBalancer) {
- balancer = (IndexLoadBalancer) loadBalancer;
- }
- super.preMasterInitialization(ctx);
- }
-
- @Override
- public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
- HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
- TableName userTableName = null;
- if (balancer != null && desc.getValue(IndexLoadBalancer.PARENT_TABLE_KEY) != null) {
- userTableName =
- TableName.valueOf(desc.getValue(IndexLoadBalancer.PARENT_TABLE_KEY));
- balancer.addTablesToColocate(userTableName, desc.getTableName());
- }
- if (userTableName != null) balancer.populateRegionLocations(userTableName);
- super.preCreateTableHandler(ctx, desc, regions);
- }
-
- @Override
- public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
- TableName tableName) throws IOException {
- if (balancer.isTableColocated(tableName)) {
- balancer.removeTablesFromColocation(tableName);
- }
- }
- }
-
}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/IndexRegionSplitPolicy.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/IndexRegionSplitPolicy.java b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/IndexRegionSplitPolicy.java
new file mode 100644
index 0000000..b754ad9
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/IndexRegionSplitPolicy.java
@@ -0,0 +1,32 @@
+/*
+ * 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.hbase.index;
+
+import org.apache.hadoop.hbase.regionserver.RegionSplitPolicy;
+
+/**
+ * Split policy for index regions to avoid split from external requests.
+ */
+public class IndexRegionSplitPolicy extends RegionSplitPolicy {
+
+ @Override
+ protected boolean shouldSplit() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/master/IndexMasterObserver.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/master/IndexMasterObserver.java b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/master/IndexMasterObserver.java
new file mode 100644
index 0000000..35a0fae
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/master/IndexMasterObserver.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hbase.index.master;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver;
+import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
+import org.apache.hadoop.hbase.coprocessor.ObserverContext;
+import org.apache.hadoop.hbase.master.LoadBalancer;
+import org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer;
+
+/**
+ * Defines of coprocessor hooks(to support secondary indexing) of operations on
+ * {@link org.apache.hadoop.hbase.master.HMaster} process.
+ */
+public class IndexMasterObserver extends BaseMasterObserver {
+ IndexLoadBalancer balancer = null;
+
+ @Override
+ public void preMasterInitialization(ObserverContext<MasterCoprocessorEnvironment> ctx)
+ throws IOException {
+ LoadBalancer loadBalancer =
+ ctx.getEnvironment().getMasterServices().getAssignmentManager().getBalancer();
+ if (loadBalancer instanceof IndexLoadBalancer) {
+ balancer = (IndexLoadBalancer) loadBalancer;
+ }
+ super.preMasterInitialization(ctx);
+ }
+
+ @Override
+ public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
+ HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
+ TableName userTableName = null;
+ if (balancer != null && desc.getValue(IndexLoadBalancer.PARENT_TABLE_KEY) != null) {
+ userTableName =
+ TableName.valueOf(desc.getValue(IndexLoadBalancer.PARENT_TABLE_KEY));
+ balancer.addTablesToColocate(userTableName, desc.getTableName());
+ }
+ if (userTableName != null) balancer.populateRegionLocations(userTableName);
+ super.preCreateTableHandler(ctx, desc, regions);
+ }
+
+ @Override
+ public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
+ TableName tableName) throws IOException {
+ if (balancer != null && balancer.isTableColocated(tableName)) {
+ balancer.removeTablesFromColocation(tableName);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/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 bd7c9d4..6e0a6ca 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
@@ -120,6 +120,7 @@ import org.apache.phoenix.exception.PhoenixIOException;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.execute.MutationState;
+import org.apache.phoenix.hbase.index.IndexRegionSplitPolicy;
import org.apache.phoenix.hbase.index.Indexer;
import org.apache.phoenix.hbase.index.covered.CoveredColumnsIndexBuilder;
import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
@@ -788,6 +789,9 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
if (isMetaTable) {
newDesc.remove(HTableDescriptor.SPLIT_POLICY);
}
+ if (newDesc.getValue(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_BYTES) != null && Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(newDesc.getValue(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_BYTES)))) {
+ newDesc.setValue(HTableDescriptor.SPLIT_POLICY, IndexRegionSplitPolicy.class.getName());
+ }
try {
if (splits == null) {
admin.createTable(newDesc);
@@ -1004,6 +1008,40 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
}
}
+ private void ensureLocalIndexTableCreated(byte[] physicalTableName, Map<String,Object> tableProps, List<Pair<byte[],Map<String,Object>>> families, byte[][] splits, long timestamp) throws SQLException {
+ PTable table;
+ String parentTableName = Bytes.toString(physicalTableName, MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX_BYTES.length,
+ physicalTableName.length - MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX_BYTES.length);
+ try {
+ table = latestMetaData.getTable(new PTableKey(PName.EMPTY_NAME, parentTableName));
+ if (table.getTimeStamp() >= timestamp) { // Table in cache is newer than client timestamp which shouldn't be the case
+ throw new TableNotFoundException(table.getSchemaName().getString(), table.getTableName().getString());
+ }
+ } catch (TableNotFoundException e) {
+ byte[] schemaName = Bytes.toBytes(SchemaUtil.getSchemaNameFromFullName(parentTableName));
+ byte[] tableName = Bytes.toBytes(SchemaUtil.getTableNameFromFullName(parentTableName));
+ MetaDataMutationResult result = this.getTable(null, schemaName, tableName, HConstants.LATEST_TIMESTAMP, timestamp);
+ table = result.getTable();
+ if (table == null) {
+ throw e;
+ }
+ }
+ ensureLocalIndexTableCreated(physicalTableName, tableProps, families, splits);
+ }
+
+ private void ensureLocalIndexTableCreated(byte[] physicalTableName, Map<String, Object> tableProps, List<Pair<byte[], Map<String, Object>>> families, byte[][] splits) throws SQLException, TableAlreadyExistsException {
+ tableProps.put(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_NAME, TRUE_BYTES_AS_STRING);
+ HTableDescriptor desc = ensureTableCreated(physicalTableName, PTableType.TABLE, tableProps, families, splits, false);
+ if (desc != null) {
+ if (!Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(desc.getValue(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_BYTES)))) {
+ String fullTableName = Bytes.toString(physicalTableName);
+ throw new TableAlreadyExistsException(
+ "Unable to create shared physical table for local indexes.",
+ SchemaUtil.getSchemaNameFromFullName(fullTableName),
+ SchemaUtil.getTableNameFromFullName(fullTableName));
+ }
+ }
+ }
private boolean ensureViewIndexTableDropped(byte[] physicalTableName, long timestamp) throws SQLException {
byte[] physicalIndexName = MetaDataUtil.getViewIndexPhysicalName(physicalTableName);
@@ -1049,6 +1087,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
byte[] schemaBytes = rowKeyMetadata[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX];
byte[] tableBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TABLE_NAME_INDEX];
byte[] tableName = physicalTableName != null ? physicalTableName : SchemaUtil.getTableNameAsBytes(schemaBytes, tableBytes);
+ boolean localIndexTable = Boolean.TRUE.equals(tableProps.remove(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_NAME));
+
if ((tableType == PTableType.VIEW && physicalTableName != null) || (tableType != PTableType.VIEW && physicalTableName == null)) {
// For views this will ensure that metadata already exists
// For tables and indexes, this will create the metadata if it doesn't already exist
@@ -1059,7 +1099,11 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
// Physical index table created up front for multi tenant
// TODO: if viewIndexId is Short.MIN_VALUE, then we don't need to attempt to create it
if (physicalTableName != null && !MetaDataUtil.isMultiTenant(m, kvBuilder, ptr)) {
- ensureViewIndexTableCreated(tenantIdBytes.length == 0 ? null : PNameFactory.newName(tenantIdBytes), physicalTableName, MetaDataUtil.getClientTimeStamp(m));
+ if (localIndexTable) {
+ ensureLocalIndexTableCreated(tableName, tableProps, families, splits, MetaDataUtil.getClientTimeStamp(m));
+ } else {
+ ensureViewIndexTableCreated(tenantIdBytes.length == 0 ? null : PNameFactory.newName(tenantIdBytes), physicalTableName, MetaDataUtil.getClientTimeStamp(m));
+ }
}
} else if (tableType == PTableType.TABLE && MetaDataUtil.isMultiTenant(m, kvBuilder, ptr)) { // Create view index table up front for multi tenant tables
ptr.set(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES);
@@ -1081,6 +1125,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
familiesPlusDefault.add(new Pair<byte[],Map<String,Object>>(defaultCF,Collections.<String,Object>emptyMap()));
}
ensureViewIndexTableCreated(tableName, tableProps, familiesPlusDefault, MetaDataUtil.isSalted(m, kvBuilder, ptr) ? splits : null, MetaDataUtil.getClientTimeStamp(m));
+ ensureLocalIndexTableCreated(MetaDataUtil.getLocalIndexPhysicalName(tableName), tableProps, families, splits);
}
byte[] tableKey = SchemaUtil.getTableKey(tenantIdBytes, schemaBytes, tableBytes);
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/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 6d02bad..557e79f 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
@@ -77,6 +77,7 @@ import java.util.Set;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Mutation;
@@ -764,8 +765,13 @@ public class MetaDataClient {
saltBucketNum = parent.getBucketNum();
addSaltColumn = (saltBucketNum != null && indexType != IndexType.LOCAL);
defaultFamilyName = parent.getDefaultFamilyName() == null ? null : parent.getDefaultFamilyName().getString();
- // Set physical name of view index table
- physicalNames = Collections.singletonList(PNameFactory.newName(MetaDataUtil.getViewIndexPhysicalName(physicalName.getBytes())));
+ if (indexType == IndexType.LOCAL) {
+ // Set physical name of local index table
+ physicalNames = Collections.singletonList(PNameFactory.newName(MetaDataUtil.getLocalIndexPhysicalName(physicalName.getBytes())));
+ } else {
+ // Set physical name of view index table
+ physicalNames = Collections.singletonList(PNameFactory.newName(MetaDataUtil.getViewIndexPhysicalName(physicalName.getBytes())));
+ }
}
multiTenant = parent.isMultiTenant();
@@ -1170,8 +1176,14 @@ public class MetaDataClient {
*/
Collections.reverse(tableMetaData);
- splits = SchemaUtil.processSplits(splits, pkColumns, saltBucketNum, connection.getQueryServices().getProps().getBoolean(
+ if (parent != null && tableType == PTableType.INDEX && indexType == IndexType.LOCAL) {
+ tableProps.put(MetaDataUtil.PARENT_TABLE_KEY, parent.getPhysicalName().getString());
+ tableProps.put(MetaDataUtil.IS_LOCAL_INDEX_TABLE_PROP_NAME, Boolean.TRUE);
+ splits = getSplitKeys(connection.getQueryServices().getAllTableRegions(parent.getPhysicalName().getBytes()));
+ } else {
+ splits = SchemaUtil.processSplits(splits, pkColumns, saltBucketNum, connection.getQueryServices().getProps().getBoolean(
QueryServices.ROW_KEY_ORDER_SALTED_TABLE_ATTRIB, QueryServicesOptions.DEFAULT_ROW_KEY_ORDER_SALTED_TABLE));
+ }
MetaDataMutationResult result = connection.getQueryServices().createTable(
tableMetaData,
viewType == ViewType.MAPPED || indexId != null ? physicalNames.get(0).getBytes() : null,
@@ -1207,7 +1219,20 @@ public class MetaDataClient {
connection.setAutoCommit(wasAutoCommit);
}
}
-
+
+ private byte[][] getSplitKeys(List<HRegionLocation> allTableRegions) {
+ if(allTableRegions.size() == 1) return null;
+ byte[][] splitKeys = new byte[allTableRegions.size()-1][];
+ int i = 0;
+ for (HRegionLocation region : allTableRegions) {
+ if (region.getRegionInfo().getStartKey().length != 0) {
+ splitKeys[i] = region.getRegionInfo().getStartKey();
+ i++;
+ }
+ }
+ return splitKeys;
+ }
+
private static boolean hasColumnWithSameNameAndFamily(Collection<PColumn> columns, PColumn column) {
for (PColumn currColumn : columns) {
if (Objects.equal(currColumn.getFamilyName(), column.getFamilyName()) &&
@@ -1317,7 +1342,7 @@ public class MetaDataClient {
// PName name, PTableType type, long timeStamp, long sequenceNumber, List<PColumn> columns
List<TableRef> tableRefs = Lists.newArrayListWithExpectedSize(2 + table.getIndexes().size());
// All multi-tenant tables have a view index table, so no need to check in that case
- if (tableType == PTableType.TABLE && (table.isMultiTenant() || MetaDataUtil.hasViewIndexTable(connection, table.getPhysicalName()))) {
+ if (tableType == PTableType.TABLE && (table.isMultiTenant() || MetaDataUtil.hasViewIndexTable(connection, table.getPhysicalName()) || MetaDataUtil.hasLocalIndexTable(connection, table.getPhysicalName()))) {
MetaDataUtil.deleteViewIndexSequences(connection, table.getPhysicalName());
// TODO: consider removing this, as the DROP INDEX done for each DROP VIEW command
// would have deleted all the rows already
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/492f7752/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
index 1af644f..8a3a190 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
@@ -48,9 +48,13 @@ import org.apache.phoenix.schema.TableNotFoundException;
public class MetaDataUtil {
public static final String VIEW_INDEX_TABLE_PREFIX = "_IDX_";
public static final byte[] VIEW_INDEX_TABLE_PREFIX_BYTES = Bytes.toBytes(VIEW_INDEX_TABLE_PREFIX);
+ public static final String LOCAL_INDEX_TABLE_PREFIX = "_LOCAL_IDX_";
+ public static final byte[] LOCAL_INDEX_TABLE_PREFIX_BYTES = Bytes.toBytes(LOCAL_INDEX_TABLE_PREFIX);
public static final String VIEW_INDEX_SEQUENCE_PREFIX = "_SEQ_";
public static final byte[] VIEW_INDEX_SEQUENCE_PREFIX_BYTES = Bytes.toBytes(VIEW_INDEX_SEQUENCE_PREFIX);
public static final String VIEW_INDEX_ID_COLUMN_NAME = "_INDEX_ID";
+ public static final String PARENT_TABLE_KEY = "PARENT_TABLE";
+ public static final byte[] PARENT_TABLE_KEY_BYTES = Bytes.toBytes("PARENT_TABLE");
public static boolean areClientAndServerCompatible(long version) {
// As of 3.0, we allow a client and server to differ for the minor version.
@@ -246,6 +250,18 @@ public class MetaDataUtil {
return schemaName;
}
+ public static byte[] getLocalIndexPhysicalName(byte[] physicalTableName) {
+ return ByteUtil.concat(LOCAL_INDEX_TABLE_PREFIX_BYTES, physicalTableName);
+ }
+
+ public static String getLocalIndexTableName(String tableName) {
+ return LOCAL_INDEX_TABLE_PREFIX + tableName;
+ }
+
+ public static String getLocalIndexSchemaName(String schemaName) {
+ return schemaName;
+ }
+
public static SequenceKey getViewIndexSequenceKey(String tenantId, PName physicalName) {
// Create global sequence of the form: <prefixed base table name><tenant id>
// rather than tenant-specific sequence, as it makes it much easier
@@ -274,6 +290,16 @@ public class MetaDataUtil {
}
}
+ public static boolean hasLocalIndexTable(PhoenixConnection connection, PName name) throws SQLException {
+ byte[] physicalIndexName = MetaDataUtil.getLocalIndexPhysicalName(name.getBytes());
+ try {
+ HTableDescriptor desc = connection.getQueryServices().getTableDescriptor(physicalIndexName);
+ return desc != null && Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(desc.getValue(IS_LOCAL_INDEX_TABLE_PROP_BYTES)));
+ } catch (TableNotFoundException e) {
+ return false;
+ }
+ }
+
public static void deleteViewIndexSequences(PhoenixConnection connection, PName name) throws SQLException {
SequenceKey key = getViewIndexSequenceKey(null, name);
connection.createStatement().executeUpdate("DELETE FROM " + PhoenixDatabaseMetaData.SEQUENCE_TABLE_NAME +
@@ -284,4 +310,7 @@ public class MetaDataUtil {
public static final String IS_VIEW_INDEX_TABLE_PROP_NAME = "IS_VIEW_INDEX_TABLE";
public static final byte[] IS_VIEW_INDEX_TABLE_PROP_BYTES = Bytes.toBytes(IS_VIEW_INDEX_TABLE_PROP_NAME);
+
+ public static final String IS_LOCAL_INDEX_TABLE_PROP_NAME = "IS_LOCAL_INDEX_TABLE";
+ public static final byte[] IS_LOCAL_INDEX_TABLE_PROP_BYTES = Bytes.toBytes(IS_LOCAL_INDEX_TABLE_PROP_NAME);
}