PHOENIX-4891: An index should inherit UPDATE_CACHE_FREQUENCY setting rom parent 
table


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

Branch: refs/heads/omid2
Commit: 647887947f631d624d6897d729bce3acb07a94bf
Parents: fe466eb
Author: Chinmay Kulkarni <chinmayskulka...@gmail.com>
Authored: Tue Oct 30 14:52:26 2018 -0700
Committer: Thomas D'Silva <tdsi...@apache.org>
Committed: Tue Oct 30 16:23:42 2018 -0700

----------------------------------------------------------------------
 .../phoenix/end2end/PropertiesInSyncIT.java     | 172 ++++++++++++++-----
 .../phoenix/end2end/index/IndexMetadataIT.java  | 145 +++++++++++++++-
 .../org/apache/phoenix/rpc/UpdateCacheIT.java   | 134 ++++++++++-----
 .../phoenix/exception/SQLExceptionCode.java     |   7 +-
 .../query/ConnectionQueryServicesImpl.java      |   6 +-
 .../apache/phoenix/schema/MetaDataClient.java   |  33 +++-
 .../org/apache/phoenix/util/MetaDataUtil.java   |   6 +-
 .../org/apache/phoenix/util/UpgradeUtil.java    |  79 ++++++++-
 8 files changed, 476 insertions(+), 106 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/phoenix-core/src/it/java/org/apache/phoenix/end2end/PropertiesInSyncIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PropertiesInSyncIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PropertiesInSyncIT.java
index db44735..348b195 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PropertiesInSyncIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PropertiesInSyncIT.java
@@ -23,9 +23,12 @@ import org.apache.hadoop.hbase.KeepDeletedCells;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Pair;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.schema.PName;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.util.MetaDataUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.SchemaUtil;
@@ -33,17 +36,23 @@ import org.junit.Test;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static 
org.apache.phoenix.query.QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES;
-import static 
org.apache.phoenix.util.MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES;
+import static 
org.apache.phoenix.util.MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES;
 import static org.apache.phoenix.util.MetaDataUtil.VIEW_INDEX_TABLE_PREFIX;
+import static 
org.apache.phoenix.util.UpgradeUtil.UPSERT_UPDATE_CACHE_FREQUENCY;
 import static org.apache.phoenix.util.UpgradeUtil.syncTableAndIndexProperties;
+import static 
org.apache.phoenix.util.UpgradeUtil.syncUpdateCacheFreqAllIndexes;
+import static 
org.apache.phoenix.end2end.index.IndexMetadataIT.assertUpdateCacheFreq;
 
 /**
  * Test properties that need to be kept in sync amongst all column families 
and indexes of a table
@@ -56,12 +65,16 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
     private static final int INITIAL_TTL_VALUE = 700;
     private static final KeepDeletedCells INITIAL_KEEP_DELETED_CELLS_VALUE = 
KeepDeletedCells.TRUE;
     private static final int INITIAL_REPLICATION_SCOPE_VALUE = 1;
+    private static final int INITIAL_UPDATE_CACHE_FREQUENCY = 100;
+    private static final int INITIAL_UPDATE_CACHE_FREQUENCY_VIEWS = 900;
     private static final int MODIFIED_TTL_VALUE = INITIAL_TTL_VALUE + 300;
     private static final KeepDeletedCells MODIFIED_KEEP_DELETED_CELLS_VALUE =
-            (INITIAL_KEEP_DELETED_CELLS_VALUE == KeepDeletedCells.TRUE)
-                    ? KeepDeletedCells.FALSE: KeepDeletedCells.TRUE;
+            (INITIAL_KEEP_DELETED_CELLS_VALUE == KeepDeletedCells.TRUE) ?
+                    KeepDeletedCells.FALSE: KeepDeletedCells.TRUE;
     private static final int MODIFIED_REPLICATION_SCOPE_VALUE =
             (INITIAL_REPLICATION_SCOPE_VALUE == 1) ? 0 : 1;
+    private static final int MODIFIED_UPDATE_CACHE_FREQUENCY = 
INITIAL_UPDATE_CACHE_FREQUENCY + 300;
+    private static final int MODIFIED_UPDATE_CACHE_FREQUENCY_VIEWS = 
INITIAL_UPDATE_CACHE_FREQUENCY_VIEWS + 300;
 
 
     // Test that we disallow specifying synced properties to be set per column 
family
@@ -70,7 +83,7 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
     public void testDisallowSyncedPropsToBeSetColFamSpecificCreateTable() 
throws Exception {
         Connection conn = DriverManager.getConnection(getUrl(), new 
Properties());
         String tableName = generateUniqueName();
-        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
             try {
                 conn.createStatement().execute("create table " + tableName
                         + " (id INTEGER not null primary key, "
@@ -107,7 +120,7 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         String viewName = "VIEW_" + tableName;
         conn.createStatement().execute("create view " + viewName
                 + " (new_col SMALLINT) as select * from " + tableName + " 
where id > 1");
-        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
             try {
                 conn.createStatement().execute("create local index " + 
localIndexName
                         + " on " + tableName + "(name) "
@@ -148,8 +161,8 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
     public void testSyncedPropsBaseTableCreateIndex() throws Exception {
         Connection conn = DriverManager.getConnection(getUrl(), new 
Properties());
         String tableName = createBaseTableWithProps(conn);
-        createIndexTable(conn, tableName, PTable.IndexType.LOCAL);
-        String globalIndexName = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL);
+        createIndexTable(conn, tableName, PTable.IndexType.LOCAL).getSecond();
+        String globalIndexName = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL).getSecond();
 
         // We pass the base table as the physical HBase table since our check 
includes checking
         // the local index column family too
@@ -164,7 +177,7 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
     public void testSyncedPropsBaseTableCreateViewIndex() throws Exception {
         Connection conn = DriverManager.getConnection(getUrl(), new 
Properties());
         String tableName = createBaseTableWithProps(conn);
-        String viewIndexName = createIndexTable(conn, tableName, null);
+        String viewIndexName = createIndexTable(conn, tableName, 
null).getSecond();
 
         verifyHBaseColumnFamilyProperties(tableName, conn, false, false);
         verifyHBaseColumnFamilyProperties(viewIndexName, conn, false, false);
@@ -179,7 +192,7 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         String tableName = createBaseTableWithProps(conn);
         StringBuilder alterAllSyncedPropsString = new StringBuilder();
         String modPropString = COL_FAM1 + ".%s=" + DUMMY_PROP_VALUE + ",";
-        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
             try {
                 conn.createStatement().execute("alter table " + tableName
                         + " set " + COL_FAM1 + "." + propName + "=" + 
DUMMY_PROP_VALUE);
@@ -216,11 +229,11 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         Set<String> tablesToCheck = new HashSet<>();
         tablesToCheck.add(tableName);
         for (int i=0; i<2; i++) {
-            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.LOCAL));
-            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL));
+            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.LOCAL).getSecond());
+            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL).getSecond());
         }
         // Create a view and view index
-        tablesToCheck.add(createIndexTable(conn, tableName, null));
+        tablesToCheck.add(createIndexTable(conn, tableName, null).getSecond());
 
         // Now alter the base table's properties. This should get propagated 
to all index tables
         conn.createStatement().execute("alter table " + tableName + " set 
TTL=" + MODIFIED_TTL_VALUE
@@ -232,8 +245,8 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         }
 
         // Any indexes created henceforth should have the modified properties
-        String newGlobalIndex = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL);
-        String newViewIndex = createIndexTable(conn, tableName, null);
+        String newGlobalIndex = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL).getSecond();
+        String newViewIndex = createIndexTable(conn, tableName, 
null).getSecond();
         verifyHBaseColumnFamilyProperties(newGlobalIndex, conn, true, false);
         verifyHBaseColumnFamilyProperties(newViewIndex, conn, true, false);
         conn.close();
@@ -245,9 +258,8 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         Connection conn = DriverManager.getConnection(getUrl(), new 
Properties());
         String tableName = createBaseTableWithProps(conn);
 
-        // Test that we are not allowed to set any property to be kept in 
sync, specific
-        // to the new column family to be added
-        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+        // Test that we are not allowed to set any property to be kept in 
sync, specific to the new column family to be added
+        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
             try {
                 conn.createStatement().execute(
                         "alter table " + tableName + " add " + NEW_CF + 
".new_column varchar(2) "
@@ -268,11 +280,11 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         Set<String> tablesToCheck = new HashSet<>();
         tablesToCheck.add(tableName);
         for (int i=0; i<2; i++) {
-            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.LOCAL));
-            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL));
+            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.LOCAL).getSecond());
+            tablesToCheck.add(createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL).getSecond());
         }
         // Create a view and view index
-        tablesToCheck.add(createIndexTable(conn, tableName, null));
+        tablesToCheck.add(createIndexTable(conn, tableName, null).getSecond());
 
         // Now add a new column family while simultaneously modifying 
properties to be kept in sync,
         // as well as a property which does not need to be kept in sync. 
Properties to be kept
@@ -307,8 +319,8 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
     public void testDisallowAlterGlobalIndexTable() throws Exception {
         Connection conn = DriverManager.getConnection(getUrl(), new 
Properties());
         String tableName = createBaseTableWithProps(conn);
-        String globalIndexName = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL);
-        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+        String globalIndexName = createIndexTable(conn, tableName, 
PTable.IndexType.GLOBAL).getSecond();
+        for (String propName: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
             try {
                 conn.createStatement().execute("alter table " + 
globalIndexName + " set "
                 + propName + "=" + DUMMY_PROP_VALUE);
@@ -336,12 +348,12 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         createdTables.add(baseTableName1);
         // Create different indexes on the base table
         for (int i=0; i<2; i++) {
-            createdTables.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.GLOBAL));
-            createdTables.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.LOCAL));
-            createdTables.add(createIndexTable(conn, baseTableName, null));
-            createdTables.add(createIndexTable(conn, baseTableName1, 
PTable.IndexType.GLOBAL));
-            createdTables.add(createIndexTable(conn, baseTableName1, 
PTable.IndexType.LOCAL));
-            createdTables.add(createIndexTable(conn, baseTableName1, null));
+            createdTables.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.GLOBAL).getSecond());
+            createdTables.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.LOCAL).getSecond());
+            createdTables.add(createIndexTable(conn, baseTableName, 
null).getSecond());
+            createdTables.add(createIndexTable(conn, baseTableName1, 
PTable.IndexType.GLOBAL).getSecond());
+            createdTables.add(createIndexTable(conn, baseTableName1, 
PTable.IndexType.LOCAL).getSecond());
+            createdTables.add(createIndexTable(conn, baseTableName1, 
null).getSecond());
         }
         for (String t: createdTables) {
             verifyHBaseColumnFamilyProperties(t, conn, false, false);
@@ -394,6 +406,77 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         conn.close();
     }
 
+    @Test
+    public void testOldClientSyncUpdateCacheFreqUpgradePath() throws Exception 
{
+        PTable base, index;
+        String baseTableName, viewName, viewName2;
+        Map<String, Set<String>> createdTablesAndViews = new HashMap<>();
+
+        try (Connection conn = DriverManager.getConnection(getUrl(), new 
Properties())) {
+            baseTableName = createBaseTableWithProps(conn);
+            createdTablesAndViews.put(baseTableName, new HashSet<String>());
+            Set<String> indexes = createdTablesAndViews.get(baseTableName);
+            indexes.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.GLOBAL).getSecond());
+            indexes.add(createIndexTable(conn, baseTableName, 
PTable.IndexType.LOCAL).getFirst());
+
+            viewName = createViewOnBaseTableOrView(conn, baseTableName);
+            createdTablesAndViews.put(viewName, new HashSet<String>());
+            indexes = createdTablesAndViews.get(viewName);
+            indexes.add(createIndexTable(conn, viewName, 
PTable.IndexType.GLOBAL).getSecond());
+
+            viewName2 = createViewOnBaseTableOrView(conn, viewName);
+            createdTablesAndViews.put(viewName2, new HashSet<String>());
+            indexes = createdTablesAndViews.get(viewName2);
+            indexes.add(createIndexTable(conn, viewName2, 
PTable.IndexType.LOCAL).getFirst());
+
+            // Intentionally make UPDATE_CACHE_FREQUENCY out of sync for 
indexes
+            PreparedStatement stmt = 
conn.prepareStatement(UPSERT_UPDATE_CACHE_FREQUENCY);
+            for (String tableOrViewName : createdTablesAndViews.keySet()) {
+                base = PhoenixRuntime.getTable(conn, tableOrViewName);
+                for (String indexTableName : 
createdTablesAndViews.get(tableOrViewName)) {
+                    index = PhoenixRuntime.getTable(conn, indexTableName);
+                    PName tenantId = index.getTenantId();
+                    stmt.setString(1, tenantId == null ? null : 
tenantId.getString());
+                    stmt.setString(2, index.getSchemaName().getString());
+                    stmt.setString(3, index.getTableName().getString());
+                    stmt.setLong(4, base.getType() == PTableType.TABLE ?
+                            MODIFIED_UPDATE_CACHE_FREQUENCY : 
MODIFIED_UPDATE_CACHE_FREQUENCY_VIEWS);
+                    stmt.addBatch();
+                }
+            }
+            stmt.executeBatch();
+            conn.commit();
+
+            // Clear the server-side cache so that we get the latest built 
PTables
+            
conn.unwrap(PhoenixConnection.class).getQueryServices().clearCache();
+            // Verify that the modified values are reflected
+            for (String tableOrViewName : createdTablesAndViews.keySet()) {
+                assertUpdateCacheFreq(conn, tableOrViewName, 
baseTableName.equals(tableOrViewName) ?
+                        INITIAL_UPDATE_CACHE_FREQUENCY : 
INITIAL_UPDATE_CACHE_FREQUENCY_VIEWS);
+                for (String indexName : 
createdTablesAndViews.get(tableOrViewName)) {
+                    assertUpdateCacheFreq(conn, indexName, 
baseTableName.equals(tableOrViewName) ?
+                            MODIFIED_UPDATE_CACHE_FREQUENCY : 
MODIFIED_UPDATE_CACHE_FREQUENCY_VIEWS);
+                }
+            }
+
+            PhoenixConnection upgradeConn = 
conn.unwrap(PhoenixConnection.class);
+            upgradeConn.setRunningUpgrade(true);
+            syncUpdateCacheFreqAllIndexes(upgradeConn,
+                    PhoenixRuntime.getTableNoCache(conn, baseTableName));
+
+            
conn.unwrap(PhoenixConnection.class).getQueryServices().clearCache();
+            // Verify that indexes have the synced values for 
UPDATE_CACHE_FREQUENCY
+            for (String tableOrViewName : createdTablesAndViews.keySet()) {
+                long expectedVal = baseTableName.equals(tableOrViewName) ?
+                        INITIAL_UPDATE_CACHE_FREQUENCY : 
INITIAL_UPDATE_CACHE_FREQUENCY_VIEWS;
+                assertUpdateCacheFreq(conn, tableOrViewName, expectedVal);
+                for (String indexOnTableOrView : 
createdTablesAndViews.get(tableOrViewName)) {
+                    assertUpdateCacheFreq(conn, indexOnTableOrView, 
expectedVal);
+                }
+            }
+        }
+    }
+
     /**
      * Helper method to modify the synced properties for a column family 
descriptor
      * @param cfd The column family descriptor object
@@ -417,9 +500,9 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
         conn.createStatement().execute("create table " + tableName
                 + " (id INTEGER not null primary key, type varchar(5), "
                 + COL_FAM1 + ".name varchar(10), " + COL_FAM2 + ".flag 
boolean) "
-                + "TTL=" + INITIAL_TTL_VALUE + ",KEEP_DELETED_CELLS="
-                + INITIAL_KEEP_DELETED_CELLS_VALUE
-                + ",REPLICATION_SCOPE=" + INITIAL_REPLICATION_SCOPE_VALUE);
+                + "TTL=" + INITIAL_TTL_VALUE + ",KEEP_DELETED_CELLS=" + 
INITIAL_KEEP_DELETED_CELLS_VALUE
+                + ",REPLICATION_SCOPE=" + INITIAL_REPLICATION_SCOPE_VALUE
+                + ",UPDATE_CACHE_FREQUENCY=" + INITIAL_UPDATE_CACHE_FREQUENCY);
         return tableName;
     }
 
@@ -429,34 +512,43 @@ public class PropertiesInSyncIT extends 
ParallelStatsDisabledIT {
      * @param baseTableName Name of the HBase base table on which to create an 
index
      * @param indexType LOCAL, GLOBAL or if we pass in null as the indexType,
      *                 we create a view and an index on that view for the 
given base table
-     * @return The physical HBase table corresponding to the index created
+     * @return A pair consisting of the index name and the name of the 
physical HBase table
+     * corresponding to the index created
      * @throws SQLException
      */
-    private String createIndexTable(Connection conn, String baseTableName,
+    private Pair<String,String> createIndexTable(Connection conn, String 
baseTableName,
             PTable.IndexType indexType) throws SQLException {
         // Create a view on top of the base table and then an index on that 
view
         if (indexType == null) {
-            String viewName = "VIEW_" + baseTableName + "_" + 
generateUniqueName();
+            String viewName = createViewOnBaseTableOrView(conn, baseTableName);
             String viewIndexName = VIEW_INDEX_TABLE_PREFIX + baseTableName;
-            conn.createStatement().execute("create view " + viewName
-                    + " (new_col SMALLINT) as select * from " + baseTableName 
+ " where id > 1");
             conn.createStatement().execute("create index view_index_" + 
generateUniqueName()
                     + " on " + viewName + " (flag)");
-            return viewIndexName;
+            return new Pair<>(viewIndexName, viewIndexName);
         }
         switch(indexType) {
         case LOCAL:
             String localIndexName = baseTableName + "_LOCAL_" + 
generateUniqueName();
             conn.createStatement().execute(
                     "create local index " + localIndexName + " on " + 
baseTableName + "(flag)");
-            return baseTableName;
+            return new Pair<>(localIndexName, baseTableName);
         case GLOBAL:
             String globalIndexName = baseTableName + "_GLOBAL_" + 
generateUniqueName();
             conn.createStatement()
                     .execute("create index " + globalIndexName + " on " + 
baseTableName + "(name)");
-            return globalIndexName;
+            return new Pair<>(globalIndexName, globalIndexName);
+        default:
+            return new Pair<>(baseTableName, baseTableName);
         }
-        return baseTableName;
+    }
+
+    private String createViewOnBaseTableOrView(Connection conn, String 
baseTableOrView) throws SQLException {
+        String viewName = "VIEW_" + baseTableOrView + "_" + 
generateUniqueName();
+        conn.createStatement().execute("create view " + viewName
+                + " (" + generateUniqueName() + " SMALLINT) as select * from "
+                + baseTableOrView + " where id > 1 UPDATE_CACHE_FREQUENCY="
+                + INITIAL_UPDATE_CACHE_FREQUENCY_VIEWS);
+        return viewName;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
index 21fa312..f797b70 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
@@ -19,6 +19,8 @@ package org.apache.phoenix.end2end.index;
 
 import static org.apache.phoenix.util.TestUtil.INDEX_DATA_SCHEMA;
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static 
org.apache.phoenix.exception.SQLExceptionCode.CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX;
+import static 
org.apache.phoenix.query.QueryServicesOptions.DEFAULT_UPDATE_CACHE_FREQUENCY;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -675,15 +677,12 @@ public class IndexMetadataIT extends 
ParallelStatsDisabledIT {
         }
     }
 
-
-
     @Test
     public void testIndexAlterPhoenixProperty() throws Exception {
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
         Connection conn = DriverManager.getConnection(getUrl(), props);
         String testTable = generateUniqueName();
 
-
         String ddl = "create table " + testTable  + " (k varchar primary key, 
v1 varchar)";
         Statement stmt = conn.createStatement();
         stmt.execute(ddl);
@@ -703,6 +702,123 @@ public class IndexMetadataIT extends 
ParallelStatsDisabledIT {
         assertEquals(20,rs.getInt(1));
     }
 
+    @Test
+    public void testCreateIndexSetUpdateCacheFreqFails() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String testTable = generateUniqueName();
+
+        String ddl = "CREATE TABLE " + testTable  + " (k varchar primary key, 
v1 varchar)";
+        Statement stmt = conn.createStatement();
+        stmt.execute(ddl);
+        String indexName = "IDX_" + generateUniqueName();
+
+        ddl = "CREATE INDEX " + indexName + " ON " + testTable  + " (v1) " +
+                "UPDATE_CACHE_FREQUENCY=10000";
+        try {
+            stmt.execute(ddl);
+            fail("Should fail trying to set UPDATE_CACHE_FREQUENCY when 
creating an index");
+        } catch (SQLException sqlE) {
+            assertEquals("Unexpected error occurred",
+                    
CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX.getErrorCode(), 
sqlE.getErrorCode());
+        }
+    }
+
+    @Test
+    public void testIndexGetsUpdateCacheFreqFromBaseTable() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String testTable = generateUniqueName();
+
+        long updateCacheFreq = 10000;
+        String ddl = "CREATE TABLE " + testTable  + " (k varchar primary key, 
v1 varchar) " +
+                "UPDATE_CACHE_FREQUENCY=" + updateCacheFreq;
+        Statement stmt = conn.createStatement();
+        stmt.execute(ddl);
+
+        String localIndex = "LOCAL_" + generateUniqueName();
+        String globalIndex = "GLOBAL_" + generateUniqueName();
+
+        ddl = "CREATE LOCAL INDEX " + localIndex + " ON " + testTable  + " 
(v1) ";
+        stmt.execute(ddl);
+        ddl = "CREATE INDEX " + globalIndex + " ON " + testTable  + " (v1) ";
+        stmt.execute(ddl);
+
+        // Check that local and global index both have the propagated 
UPDATE_CACHE_FREQUENCY value
+        assertUpdateCacheFreq(conn, testTable, updateCacheFreq);
+        assertUpdateCacheFreq(conn, localIndex, updateCacheFreq);
+        assertUpdateCacheFreq(conn, globalIndex, updateCacheFreq);
+    }
+
+    @Test
+    public void testAlterTablePropagatesUpdateCacheFreqToIndexes() throws 
Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String testTable = generateUniqueName();
+
+        String ddl = "CREATE TABLE " + testTable  + " (k varchar primary key, 
v1 varchar) ";
+        Statement stmt = conn.createStatement();
+        stmt.execute(ddl);
+
+        String localIndex = "LOCAL_" + generateUniqueName();
+        String globalIndex = "GLOBAL_" + generateUniqueName();
+
+        ddl = "CREATE LOCAL INDEX " + localIndex + " ON " + testTable  + " 
(v1) ";
+        stmt.execute(ddl);
+        ddl = "CREATE INDEX " + globalIndex + " ON " + testTable  + " (v1) ";
+        stmt.execute(ddl);
+
+        assertUpdateCacheFreq(conn, testTable, DEFAULT_UPDATE_CACHE_FREQUENCY);
+        assertUpdateCacheFreq(conn, localIndex, 
DEFAULT_UPDATE_CACHE_FREQUENCY);
+        assertUpdateCacheFreq(conn, globalIndex, 
DEFAULT_UPDATE_CACHE_FREQUENCY);
+
+        // Alter UPDATE_CACHE_FREQUENCY on the base table
+        long updateCacheFreq = 10000;
+        ddl = "ALTER TABLE " + testTable + " SET UPDATE_CACHE_FREQUENCY=" + 
updateCacheFreq;
+        stmt.execute(ddl);
+
+        // Check that local and global index both have the propagated 
UPDATE_CACHE_FREQUENCY value
+        assertUpdateCacheFreq(conn, testTable, updateCacheFreq);
+        assertUpdateCacheFreq(conn, localIndex, updateCacheFreq);
+        assertUpdateCacheFreq(conn, globalIndex, updateCacheFreq);
+    }
+
+    @Test
+    public void testIndexAlterUpdateCacheFreqFails() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String testTable = generateUniqueName();
+
+        String ddl = "CREATE TABLE " + testTable  + " (k varchar primary key, 
v1 varchar)";
+        Statement stmt = conn.createStatement();
+        stmt.execute(ddl);
+
+        String localIndex = "LOCAL_" + generateUniqueName();
+        String globalIndex = "GLOBAL_" + generateUniqueName();
+
+        ddl = "CREATE LOCAL INDEX " + localIndex + " ON " + testTable  + " 
(v1) ";
+        stmt.execute(ddl);
+        ddl = "CREATE INDEX " + globalIndex + " ON " + testTable  + " (v1) ";
+        stmt.execute(ddl);
+
+        try {
+            stmt.execute("ALTER INDEX " + localIndex + " ON " + testTable +
+                    " ACTIVE SET UPDATE_CACHE_FREQUENCY=NEVER");
+            fail("Should fail trying to alter UPDATE_CACHE_FREQUENCY on 
index");
+        } catch (SQLException sqlE) {
+            assertEquals("Unexpected error occurred",
+                    
CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX.getErrorCode(), 
sqlE.getErrorCode());
+        }
+
+        try {
+            stmt.execute("ALTER INDEX " + globalIndex + " ON " + testTable +
+                    " ACTIVE SET UPDATE_CACHE_FREQUENCY=NEVER");
+            fail("Should fail trying to alter UPDATE_CACHE_FREQUENCY on 
index");
+        } catch (SQLException sqlE) {
+            assertEquals("Unexpected error occurred",
+                    
CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX.getErrorCode(), 
sqlE.getErrorCode());
+        }
+    }
 
     @Test
     public void testIndexAlterHBaseProperty() throws Exception {
@@ -718,10 +834,10 @@ public class IndexMetadataIT extends 
ParallelStatsDisabledIT {
         ddl = "CREATE INDEX " + indexName + " ON " + testTable  + " (v1) ";
         stmt.execute(ddl);
 
-        conn.createStatement().execute("ALTER INDEX "+indexName+" ON " + 
testTable +" ACTIVE SET DISABLE_WAL=false");
-        asssertIsWALDisabled(conn,indexName,false);
         conn.createStatement().execute("ALTER INDEX "+indexName+" ON " + 
testTable +" ACTIVE SET DISABLE_WAL=true");
         asssertIsWALDisabled(conn,indexName,true);
+        conn.createStatement().execute("ALTER INDEX "+indexName+" ON " + 
testTable +" ACTIVE SET DISABLE_WAL=false");
+        asssertIsWALDisabled(conn,indexName,false);
     }
 
     private static void asssertIsWALDisabled(Connection conn, String 
fullTableName, boolean expectedValue) throws SQLException {
@@ -729,4 +845,23 @@ public class IndexMetadataIT extends 
ParallelStatsDisabledIT {
         assertEquals(expectedValue, pconn.getTable(new 
PTableKey(pconn.getTenantId(), fullTableName)).isWALDisabled());
     }
 
+    /**
+     * Helper method to assert the value of UPDATE_CACHE_FREQUENCY for a 
table/index/view
+     * @param conn Phoenix connection
+     * @param name table/view/index name
+     * @param expectedUpdateCacheFreq expected value of UPDATE_CACHE_FREQUENCY
+     * @throws SQLException
+     */
+    public static void assertUpdateCacheFreq(Connection conn, String name,
+            long expectedUpdateCacheFreq) throws SQLException {
+        ResultSet rs = conn.createStatement().executeQuery(
+                "select UPDATE_CACHE_FREQUENCY from SYSTEM.\"CATALOG\" where 
TABLE_NAME='" +
+                        name + "'");
+        assertTrue(rs.next());
+        assertEquals("Mismatch found for " + name, expectedUpdateCacheFreq, 
rs.getLong(1));
+        assertEquals("Mismatch in UPDATE_CACHE_FREQUENCY for PTable of " + 
name,
+                expectedUpdateCacheFreq, PhoenixRuntime.getTableNoCache(conn, 
name)
+                        .getUpdateCacheFrequency());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/phoenix-core/src/it/java/org/apache/phoenix/rpc/UpdateCacheIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/rpc/UpdateCacheIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/rpc/UpdateCacheIT.java
index 0ddbed3..2959b99 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/rpc/UpdateCacheIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/rpc/UpdateCacheIT.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.rpc;
 
 import static org.apache.phoenix.util.TestUtil.INDEX_DATA_SCHEMA;
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
@@ -73,7 +74,7 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT {
                 String fullTableName = INDEX_DATA_SCHEMA + 
QueryConstants.NAME_SEPARATOR + tableName;
                 Connection conn = DriverManager.getConnection(getUrl(), 
PropertiesUtil.deepCopy(TEST_PROPERTIES));
                 conn.createStatement().execute("create table " + fullTableName 
+ TestUtil.TEST_TABLE_SCHEMA + "TRANSACTIONAL=true,TRANSACTION_PROVIDER='" + 
provider + "'");
-                helpTestUpdateCache(fullTableName, new int[] {1, 1});
+                helpTestUpdateCache(fullTableName, new int[] {1, 1}, false);
             }
         }
     }
@@ -84,14 +85,14 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT {
         String fullTableName = INDEX_DATA_SCHEMA + 
QueryConstants.NAME_SEPARATOR + tableName;
         Connection conn = DriverManager.getConnection(getUrl(), 
PropertiesUtil.deepCopy(TEST_PROPERTIES));
         conn.createStatement().execute("create table " + fullTableName + 
TestUtil.TEST_TABLE_SCHEMA);
-        helpTestUpdateCache(fullTableName, new int[] {1, 3});
+        helpTestUpdateCache(fullTableName, new int[] {1, 3}, false);
     }
        
     @Test
     public void testUpdateCacheForNonTxnSystemTable() throws Exception {
         String fullTableName = "\""+ QueryConstants.SYSTEM_SCHEMA_NAME + "\""+ 
QueryConstants.NAME_SEPARATOR + generateUniqueName();
         setupSystemTable(fullTableName);
-        helpTestUpdateCache(fullTableName, new int[] {0, 0});
+        helpTestUpdateCache(fullTableName, new int[] {0, 0}, false);
     }
     
     @Test
@@ -104,7 +105,7 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT {
             conn.createStatement().execute(
             "alter table " + fullTableName + " SET 
UPDATE_CACHE_FREQUENCY=NEVER");
         }
-        helpTestUpdateCache(fullTableName, new int[] {0, 0});
+        helpTestUpdateCache(fullTableName, new int[] {0, 0}, false);
     }
     
     @Test
@@ -114,7 +115,7 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT {
         try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
             conn.createStatement().execute("CREATE TABLE " + fullTableName + 
TestUtil.TEST_TABLE_SCHEMA + " UPDATE_CACHE_FREQUENCY=always");
         }
-        helpTestUpdateCache(fullTableName, new int[] {1, 3});
+        helpTestUpdateCache(fullTableName, new int[] {1, 3}, false);
     }
     
     @Test
@@ -124,9 +125,9 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT {
         try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
             conn.createStatement().execute("CREATE TABLE " + fullTableName + 
TestUtil.TEST_TABLE_SCHEMA + " UPDATE_CACHE_FREQUENCY=" + 10000);
         }
-        helpTestUpdateCache(fullTableName, new int[] {0, 0});
+        helpTestUpdateCache(fullTableName, new int[] {0, 0}, false);
         Thread.sleep(10000);
-        helpTestUpdateCache(fullTableName, new int[] {1, 0});
+        helpTestUpdateCache(fullTableName, new int[] {1, 0}, false);
     }
     
     @Test
@@ -136,14 +137,55 @@ public class UpdateCacheIT extends 
ParallelStatsDisabledIT {
         try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
             conn.createStatement().execute("CREATE TABLE " + fullTableName + 
TestUtil.TEST_TABLE_SCHEMA + " UPDATE_CACHE_FREQUENCY=never");
         }
-        helpTestUpdateCache(fullTableName, new int[] {0, 0});
+        helpTestUpdateCache(fullTableName, new int[] {0, 0}, false);
         try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
             conn.createStatement().execute("ALTER TABLE " + fullTableName + " 
SET UPDATE_CACHE_FREQUENCY=ALWAYS");
         }
-        helpTestUpdateCache(fullTableName, new int[] {1, 3});
+        helpTestUpdateCache(fullTableName, new int[] {1, 3}, false);
+    }
+
+    @Test
+    public void testUpdateCacheFreqPropagatedToIndexes() throws Exception {
+        String baseTableName = generateUniqueName();
+        String fullTableName = INDEX_DATA_SCHEMA + 
QueryConstants.NAME_SEPARATOR + baseTableName;
+        String localIndex = "LOCAL_" + baseTableName;
+        String globalIndex = "GLOBAL_" + baseTableName;
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+            conn.createStatement().execute("CREATE TABLE " + fullTableName +
+                    TestUtil.TEST_TABLE_SCHEMA + " 
UPDATE_CACHE_FREQUENCY=never");
+
+            // Create local and global indexes on the base table
+            conn.createStatement().execute("CREATE LOCAL INDEX " + localIndex
+                    + " on " + fullTableName + " (a.date1, b.varchar_col2)");
+            conn.createStatement().execute("CREATE INDEX " + globalIndex + " 
on "
+                    + fullTableName + " (a.int_col1, a.long_col1)");
+        }
+
+        // The indexes should have got the UPDATE_CACHE_FREQUENCY value of 
their base table
+        helpTestUpdateCache(fullTableName, new int[] {0, 0}, false);
+        helpTestUpdateCache(INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR 
+ localIndex,
+                new int[] {0}, true);
+        helpTestUpdateCache(INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR 
+ globalIndex,
+                new int[] {0}, true);
+
+        // Now alter the UPDATE_CACHE_FREQUENCY value of the base table
+        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+            conn.createStatement()
+                    .execute("ALTER TABLE " + fullTableName + " SET 
UPDATE_CACHE_FREQUENCY=ALWAYS");
+        }
+        // Even the indexes should now have the modified value of 
UPDATE_CACHE_FREQUENCY
+        // Note that when we query the base table, during query plan 
generation, we make 2 getTable
+        // requests (to retrieve the base table) for each index of the base 
table
+        helpTestUpdateCache(fullTableName, new int[] {1, 15}, false);
+        helpTestUpdateCache(INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR 
+ localIndex,
+                new int[] {3}, true);
+        helpTestUpdateCache(INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR 
+ globalIndex,
+                new int[] {3}, true);
     }
     
-       private static void helpTestUpdateCache(String fullTableName, int[] 
expectedRPCs) throws Exception {
+       private static void helpTestUpdateCache(String fullTableName, int[] 
expectedRPCs,
+            boolean skipUpsertForIndexes) throws Exception {
            String tableName = 
SchemaUtil.getTableNameFromFullName(fullTableName);
            String schemaName = 
SchemaUtil.getSchemaNameFromFullName(fullTableName);
                String selectSql = "SELECT * FROM "+fullTableName;
@@ -154,46 +196,31 @@ public class UpdateCacheIT extends 
ParallelStatsDisabledIT {
                Connection conn = connectionQueryServices.connect(getUrl(), 
props);
                try {
                        conn.setAutoCommit(false);
-               String upsert = "UPSERT INTO " + fullTableName + "(varchar_pk, 
char_pk, int_pk, long_pk, decimal_pk, date_pk) VALUES(?, ?, ?, ?, ?, ?)";
-               PreparedStatement stmt = conn.prepareStatement(upsert);
-                       // upsert three rows
-               TestUtil.setRowKeyColumns(stmt, 1);
-                       stmt.execute();
-                       TestUtil.setRowKeyColumns(stmt, 2);
-                       stmt.execute();
-                       TestUtil.setRowKeyColumns(stmt, 3);
-                       stmt.execute();
-                       conn.commit();
-            int numUpsertRpcs = expectedRPCs[0];
-                       // verify only 0 or 1 rpc to fetch table metadata, 
-            verify(connectionQueryServices, 
times(numUpsertRpcs)).getTable((PName) isNull(),
-                eq(PVarchar.INSTANCE.toBytes(schemaName)), 
eq(PVarchar.INSTANCE.toBytes(tableName)),
-                anyLong(), anyLong(), eq(false), eq(false), (PTable)isNull());
-            reset(connectionQueryServices);
-            
-            ResultSet rs = conn.createStatement().executeQuery(selectSql);
-                       TestUtil.validateRowKeyColumns(rs, 1);
-                       TestUtil.validateRowKeyColumns(rs, 2);
-                       TestUtil.validateRowKeyColumns(rs, 3);
-               assertFalse(rs.next());
-               
-               rs = conn.createStatement().executeQuery(selectSql);
-               TestUtil.validateRowKeyColumns(rs, 1);
-               TestUtil.validateRowKeyColumns(rs, 2);
-               TestUtil.validateRowKeyColumns(rs, 3);
-               assertFalse(rs.next());
-               
-               rs = conn.createStatement().executeQuery(selectSql);
-               TestUtil.validateRowKeyColumns(rs, 1);
-               TestUtil.validateRowKeyColumns(rs, 2);
-               TestUtil.validateRowKeyColumns(rs, 3);
-               assertFalse(rs.next());
-               
+            if (!skipUpsertForIndexes) {
+                String upsert = "UPSERT INTO " + fullTableName + "(varchar_pk, 
char_pk, int_pk, long_pk, decimal_pk, date_pk) VALUES(?, ?, ?, ?, ?, ?)";
+                PreparedStatement stmt = conn.prepareStatement(upsert);
+                // upsert three rows
+                for (int i=0; i<3; i++) {
+                    TestUtil.setRowKeyColumns(stmt, i);
+                    stmt.execute();
+                }
+                conn.commit();
+                int numUpsertRpcs = expectedRPCs[0];
+                // verify only 0 or 1 rpc to fetch table metadata,
+                verify(connectionQueryServices, 
times(numUpsertRpcs)).getTable((PName) isNull(),
+                        eq(PVarchar.INSTANCE.toBytes(schemaName)), 
eq(PVarchar.INSTANCE.toBytes(tableName)),
+                        anyLong(), anyLong(), eq(false), eq(false), 
(PTable)isNull());
+                reset(connectionQueryServices);
+            }
+            validateSelectRowKeyCols(conn, selectSql, skipUpsertForIndexes);
+            validateSelectRowKeyCols(conn, selectSql, skipUpsertForIndexes);
+            validateSelectRowKeyCols(conn, selectSql, skipUpsertForIndexes);
+
                // for non-transactional tables without a scn : verify one rpc 
to getTable occurs *per* query
             // for non-transactional tables with a scn : verify *only* one rpc 
occurs
             // for transactional tables : verify *only* one rpc occurs
                // for non-transactional, system tables : verify no rpc occurs
-            int numRpcs = expectedRPCs[1]; 
+            int numRpcs = skipUpsertForIndexes ? expectedRPCs[0] : 
expectedRPCs[1];
             verify(connectionQueryServices, times(numRpcs)).getTable((PName) 
isNull(),
                 eq(PVarchar.INSTANCE.toBytes(schemaName)), 
eq(PVarchar.INSTANCE.toBytes(tableName)),
                 anyLong(), anyLong(), eq(false), eq(false), (PTable)isNull());
@@ -202,4 +229,19 @@ public class UpdateCacheIT extends ParallelStatsDisabledIT 
{
                conn.close();
         }
        }
+
+       private static void validateSelectRowKeyCols(Connection conn, String 
selectSql,
+            boolean skipUpsertForIndexes) throws SQLException {
+        ResultSet rs = conn.createStatement().executeQuery(selectSql);
+        if (skipUpsertForIndexes) {
+            for (int i=0; i<3; i++) {
+                assertTrue(rs.next());
+            }
+        } else {
+            for (int i=0; i<3; i++) {
+                TestUtil.validateRowKeyColumns(rs, i);
+            }
+        }
+        assertFalse(rs.next());
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/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 6696521..5bffed5 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
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.phoenix.coprocessor.MetaDataProtocol;
 import org.apache.phoenix.hbase.index.util.IndexManagementUtil;
+import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
 import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.schema.AmbiguousColumnException;
@@ -263,7 +264,7 @@ public enum SQLExceptionCode {
     NO_LOCAL_INDEX_ON_TABLE_WITH_IMMUTABLE_ROWS(1048,"43A05","Local indexes 
aren't allowed on tables with immutable rows."),
     COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY(1049, "43A06", "Column family not 
allowed for table properties."),
     COLUMN_FAMILY_NOT_ALLOWED_FOR_PROPERTY(1050, "43A07", "Setting  or 
altering any of the following properties: "
-            + MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES.toString()
+            + 
MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES.toString()
             + " for a column family is not supported since they must be kept 
in sync. You can only set these properties for the entire table."),
     CANNOT_ALTER_PROPERTY(1051, "43A08", "Property can be specified or changed 
only when creating a table."),
     CANNOT_SET_PROPERTY_FOR_COLUMN_NOT_ADDED(1052, "43A09", "Property cannot 
be specified for a column family that is not being added or modified."),
@@ -308,7 +309,9 @@ public enum SQLExceptionCode {
     TTL_UNSUPPORTED_FOR_TXN_TABLE(10947, "44A28", "TTL is not supported for"),
     CANNOT_CREATE_LOCAL_INDEX_FOR_TXN_TABLE(10948, "44A29", "Local indexes 
cannot be created for"),
     CANNOT_SET_OR_ALTER_PROPERTY_FOR_INDEX(10949, "44A30", "Cannot set or 
alter the following properties on an index: "
-            + MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES.toString()),
+            + 
MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES.toString()),
+    CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX(10950, "44A31", "Cannot 
set or alter "
+            + PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY + " on an index"),
 
     /** Sequence related */
     SEQUENCE_ALREADY_EXIST(1200, "42Z00", "Sequence already exists.", new 
Factory() {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/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 ebcb7b9..1381247 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
@@ -2519,7 +2519,7 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
      * Keep the TTL, KEEP_DELETED_CELLS and REPLICATION_SCOPE properties of 
new column families
      * in sync with the existing column families. Note that we use the new 
values for these properties in case they
      * are passed from our alter table command, if not, we use the default 
column family's value for each property
-     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES}
+     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES}
      * @param allFamiliesProps Map of all column family properties
      * @param table original table
      * @param tableDesc new table descriptor
@@ -2565,7 +2565,7 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
     /**
      * Set the new values for properties that are to be kept in sync amongst 
those column families of the table which are
      * not referenced in the context of our alter table command, including the 
local index column family if it exists
-     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES}
+     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES}
      * @param tableDesc original table descriptor
      * @param allFamiliesProps Map of all column family properties
      * @param newTTL new value of TTL
@@ -2587,7 +2587,7 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
     /**
      * Set properties to be kept in sync for global indexes of a table, as 
well as
      * the physical table corresponding to indexes created on views of a table
-     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES} and
+     * See {@link MetaDataUtil#SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES} 
and
      * @param table base table
      * @param tableAndIndexDescriptorMappings old to new table descriptor 
mappings
      * @param applyPropsToAllIndexesDefaultCF new properties to apply to all 
index column families

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/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 6563c40..df0e5d4 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
@@ -272,6 +272,7 @@ public class MetaDataClient {
                     TABLE_NAME + "," +
                     SYNC_INDEX_CREATED_DATE + " " + 
PDate.INSTANCE.getSqlTypeName() +
                     ") VALUES (?, ?, ?, ?)";
+
     private static final String CREATE_TABLE =
             "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + 
SYSTEM_CATALOG_TABLE + "\"( " +
                     TENANT_ID + "," +
@@ -1147,7 +1148,7 @@ public class MetaDataClient {
     /**
      * Populate properties for the table and common properties for all column 
families of the table
      * @param statementProps Properties specified in SQL statement
-     * @param tableProps Properties for an HTableDescriptor
+     * @param tableProps Properties for an HTableDescriptor and Phoenix Table 
Properties
      * @param commonFamilyProps Properties common to all column families
      * @param tableType Used to distinguish between index creation vs. base 
table creation paths
      * @throws SQLException
@@ -1164,9 +1165,17 @@ public class MetaDataClient {
                             .setMessage("Property: " + prop.getFirst()).build()
                             .buildException();
                 }
+                // HTableDescriptor property or Phoenix Table Property
                 if (defaultDescriptor.getValue(Bytes.toBytes(prop.getFirst())) 
== null) {
+                    // See PHOENIX-4891
+                    if (tableType == PTableType.INDEX && 
UPDATE_CACHE_FREQUENCY.equals(prop.getFirst())) {
+                        throw new SQLExceptionInfo.Builder(
+                                
SQLExceptionCode.CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX)
+                                .build()
+                                .buildException();
+                    }
                     tableProps.put(prop.getFirst(), prop.getSecond());
-                } else {
+                } else { // HColumnDescriptor property
                     commonFamilyProps.put(prop.getFirst(), prop.getSecond());
                 }
             }
@@ -2127,8 +2136,11 @@ public class MetaDataClient {
             }
             long updateCacheFrequency = 
connection.getQueryServices().getProps().getLong(
                 QueryServices.DEFAULT_UPDATE_CACHE_FREQUENCY_ATRRIB, 
QueryServicesOptions.DEFAULT_UPDATE_CACHE_FREQUENCY);
+            if (tableType == PTableType.INDEX && parent != null) {
+                updateCacheFrequency = parent.getUpdateCacheFrequency();
+            }
             Long updateCacheFrequencyProp = (Long) 
TableProperty.UPDATE_CACHE_FREQUENCY.getValue(tableProps);
-            if (updateCacheFrequencyProp != null) {
+            if (tableType != PTableType.INDEX && updateCacheFrequencyProp != 
null) {
                 updateCacheFrequency = updateCacheFrequencyProp;
             }
             String autoPartitionSeq = (String) 
TableProperty.AUTO_PARTITION_SEQ.getValue(tableProps);
@@ -3613,9 +3625,13 @@ public class MetaDataClient {
                     }
                 }
 
-                if (!table.getIndexes().isEmpty() && (numPkColumnsAdded>0 || 
metaProperties.getNonTxToTx())) {
+                if (!table.getIndexes().isEmpty() &&
+                        (numPkColumnsAdded>0 || metaProperties.getNonTxToTx() 
||
+                                
metaPropertiesEvaluated.getUpdateCacheFrequency() != null)) {
                     for (PTable index : table.getIndexes()) {
-                        incrementTableSeqNum(index, index.getType(), 
numPkColumnsAdded, metaProperties.getNonTxToTx() ? Boolean.TRUE : null, 
metaPropertiesEvaluated.getUpdateCacheFrequency());
+                        incrementTableSeqNum(index, index.getType(), 
numPkColumnsAdded,
+                                metaProperties.getNonTxToTx() ? Boolean.TRUE : 
null,
+                                
metaPropertiesEvaluated.getUpdateCacheFrequency());
                     }
                     
tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                     connection.rollback();
@@ -4573,6 +4589,13 @@ public class MetaDataClient {
         }
 
         if (metaProperties.getUpdateCacheFrequencyProp() != null) {
+            // See PHOENIX-4891
+            if (table.getType() == PTableType.INDEX) {
+                throw new SQLExceptionInfo.Builder(
+                        
SQLExceptionCode.CANNOT_SET_OR_ALTER_UPDATE_CACHE_FREQ_FOR_INDEX)
+                        .build()
+                        .buildException();
+            }
             if (metaProperties.getUpdateCacheFrequencyProp().longValue() != 
table.getUpdateCacheFrequency()) {
                 
metaPropertiesEvaluated.setUpdateCacheFrequency(metaProperties.getUpdateCacheFrequencyProp());
                 changingPhoenixTableProperty = true;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/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 df7530c..8cf514f 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
@@ -109,7 +109,7 @@ public class MetaDataUtil {
     public static final byte[] DATA_TABLE_NAME_PROP_BYTES = 
Bytes.toBytes(DATA_TABLE_NAME_PROP_NAME);
 
     // See PHOENIX-3955
-    public static final List<String> SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES = 
ImmutableList.of(
+    public static final List<String> 
SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES = ImmutableList.of(
             HColumnDescriptor.TTL,
             HColumnDescriptor.KEEP_DELETED_CELLS,
             HColumnDescriptor.REPLICATION_SCOPE);
@@ -725,13 +725,13 @@ public class MetaDataUtil {
     }
 
     public static boolean propertyNotAllowedToBeOutOfSync(String colFamProp) {
-        return SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES.contains(colFamProp);
+        return 
SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES.contains(colFamProp);
     }
 
     public static Map<String, Object> getSyncedProps(HColumnDescriptor 
defaultCFDesc) {
         Map<String, Object> syncedProps = new HashMap<>();
         if (defaultCFDesc != null) {
-            for (String propToKeepInSync: 
SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+            for (String propToKeepInSync: 
SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
                 syncedProps.put(propToKeepInSync, Bytes.toString(
                         
defaultCFDesc.getValue(Bytes.toBytes(propToKeepInSync))));
             }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/64788794/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java 
b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
index ede14b8..8d0aca1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
@@ -46,6 +46,7 @@ import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SEQ_NUM;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_TYPE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TENANT_ID;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID;
 import static 
org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT;
 import static 
org.apache.phoenix.query.QueryConstants.DIVERGED_VIEW_BASE_COLUMN_COUNT;
@@ -140,6 +141,14 @@ public class UpgradeUtil {
             + "(TENANT_ID, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, 
COLUMN_FAMILY, BASE_COLUMN_COUNT) "
             + "VALUES (?, ?, ?, ?, ?, ?) ";
 
+    public static final String UPSERT_UPDATE_CACHE_FREQUENCY =
+            "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + 
SYSTEM_CATALOG_TABLE + "\"( " +
+            TENANT_ID + "," +
+            TABLE_SCHEM + "," +
+            TABLE_NAME + "," +
+            UPDATE_CACHE_FREQUENCY +
+            ") VALUES (?, ?, ?, ?)";
+
     public static String SELECT_BASE_COLUMN_COUNT_FROM_HEADER_ROW = "SELECT "
             + "BASE_COLUMN_COUNT "
             + "FROM \"SYSTEM\".CATALOG "
@@ -1227,7 +1236,7 @@ public class UpgradeUtil {
         for (HColumnDescriptor currentColFam: tableDesc.getColumnFamilies()) {
             if (!currentColFam.equals(defaultColFam)) {
                 HColumnDescriptor newColFamDesc = new 
HColumnDescriptor(currentColFam);
-                for (String prop: 
MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_PROPERTIES) {
+                for (String prop: 
MetaDataUtil.SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
                     String existingPropVal = 
Bytes.toString(currentColFam.getValue(Bytes.toBytes(prop)));
                     String expectedPropVal = syncedProps.get(prop).toString();
                     if (existingPropVal == null || 
!existingPropVal.toLowerCase().equals(expectedPropVal.toLowerCase())) {
@@ -1299,6 +1308,71 @@ public class UpgradeUtil {
         }
     }
 
+    private static void syncUpdateCacheFreqForIndexesOfTable(PTable baseTable,
+            PreparedStatement stmt) throws SQLException {
+        for (PTable index : baseTable.getIndexes()) {
+            if (index.getUpdateCacheFrequency() == 
baseTable.getUpdateCacheFrequency()) {
+                continue;
+            }
+            stmt.setString(2, index.getSchemaName().getString());
+            stmt.setString(3, index.getTableName().getString());
+            stmt.setLong(4, baseTable.getUpdateCacheFrequency());
+            stmt.addBatch();
+        }
+    }
+
+    /**
+     * See PHOENIX-4891. We set the UPDATE_CACHE_FREQUENCY of indexes to be 
same as their parent.
+     * We do this for both physical base tables as well as views
+     * @param conn Phoenix Connection object
+     * @param table PTable corresponding to a physical base table
+     * @throws SQLException
+     * @throws IOException
+     */
+    public static void syncUpdateCacheFreqAllIndexes(PhoenixConnection conn, 
PTable table)
+    throws SQLException, IOException {
+        // Use own connection with max time stamp to be able to read all data 
from SYSTEM.CATALOG
+        try(PhoenixConnection newConn = new PhoenixConnection(conn, 
HConstants.LATEST_TIMESTAMP)) {
+            // Clear the server-side cache so that we get the latest built 
PTables
+            
newConn.unwrap(PhoenixConnection.class).getQueryServices().clearCache();
+            byte[] tenantId = newConn.getTenantId() != null ?
+                    newConn.getTenantId().getBytes() : null;
+
+            PreparedStatement stmt =
+                    newConn.prepareStatement(UPSERT_UPDATE_CACHE_FREQUENCY);
+            stmt.setString(1, Bytes.toString(tenantId));
+            syncUpdateCacheFreqForIndexesOfTable(table, stmt);
+
+            TableViewFinderResult childViewsResult = new 
TableViewFinderResult();
+            try (Table childLinkTable = newConn.getQueryServices()
+                    .getTable(SchemaUtil.getPhysicalName(
+                            
PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES,
+                            newConn.getQueryServices().getProps())
+                            .getName())) {
+                ViewFinder.findAllRelatives(childLinkTable, tenantId,
+                        table.getSchemaName().getBytes(), 
table.getTableName().getBytes(),
+                        LinkType.CHILD_TABLE, childViewsResult);
+
+                // Iterate over the chain of child views
+                for (TableInfo tableInfo: childViewsResult.getLinks()) {
+                    PTable view;
+                    String viewName = 
SchemaUtil.getTableName(tableInfo.getSchemaName(),
+                            tableInfo.getTableName());
+                    try {
+                        view = PhoenixRuntime.getTable(newConn, viewName);
+                    } catch (TableNotFoundException e) {
+                        // Ignore
+                        logger.warn("Error getting PTable for view: " + 
viewName);
+                        continue;
+                    }
+                    syncUpdateCacheFreqForIndexesOfTable(view, stmt);
+                }
+            }
+            stmt.executeBatch();
+            newConn.commit();
+        }
+    }
+
     /**
      * Make sure that all tables have necessary column family properties in 
sync
      * with each other and also in sync with all the table's indexes
@@ -1316,7 +1390,7 @@ public class UpgradeUtil {
                 // Ignore physical view index tables since we handle them for 
each base table already
                 continue;
             }
-            PTable table = null;
+            PTable table;
             String tableName = origTableDesc.getTableName().getNameAsString();
             try {
                 table = PhoenixRuntime.getTable(conn, tableName);
@@ -1329,6 +1403,7 @@ public class UpgradeUtil {
                 // Ignore global index tables since we handle them for each 
base table already
                 continue;
             }
+            syncUpdateCacheFreqAllIndexes(conn, table);
             HColumnDescriptor defaultColFam = 
origTableDesc.getFamily(SchemaUtil.getEmptyColumnFamily(table));
             Map<String, Object> syncedProps = 
MetaDataUtil.getSyncedProps(defaultColFam);
 

Reply via email to