[ https://issues.apache.org/jira/browse/PHOENIX-7212?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17817152#comment-17817152 ]
ASF GitHub Bot commented on PHOENIX-7212: ----------------------------------------- tkhurana commented on code in PR #1823: URL: https://github.com/apache/phoenix/pull/1823#discussion_r1488553793 ########## phoenix-core/src/test/java/org/apache/phoenix/cache/ServerMetadataCacheTest.java: ########## @@ -1591,8 +1593,93 @@ public void testAncestorLastDDLMapPopulatedInDifferentClient() throws Exception } } + /** + * Test that tenant connections are able to learn about state change of an inherited index + * on their tenant views with different names. + */ + @Test + public void testInheritedIndexOnTenantViewsDifferentNames() throws Exception { + testInheritedIndexOnTenantViews(false); + } + + /** + * Test that tenant connections are able to learn about state change of an inherited index + * on their tenant views with same names. + */ + @Test + public void testInheritedIndexOnTenantViewsSameNames() throws Exception { + testInheritedIndexOnTenantViews(true); + } + + public void testInheritedIndexOnTenantViews(boolean sameTenantViewNames) throws Exception { + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + String url = QueryUtil.getConnectionUrl(props, config, "client1"); + ConnectionQueryServices cqs = driver.getConnectionQueryServices(url, props); + String baseTableName = generateUniqueName(); + String globalViewName = generateUniqueName(); + String globalViewIndexName = generateUniqueName(); + String tenantViewName1 = generateUniqueName(); + String tenantViewName2 = sameTenantViewNames ? tenantViewName1 : generateUniqueName(); + try (Connection conn = cqs.connect(url, props)) { + // create table, view and view index + conn.createStatement().execute("CREATE TABLE " + baseTableName + + " (TENANT_ID CHAR(9) NOT NULL, KP CHAR(3) NOT NULL, PK CHAR(3) NOT NULL, KV CHAR(2), KV2 CHAR(2) " + + "CONSTRAINT PK PRIMARY KEY(TENANT_ID, KP, PK)) MULTI_TENANT=true,UPDATE_CACHE_FREQUENCY=NEVER"); + conn.createStatement().execute("CREATE VIEW " + globalViewName + + " AS SELECT * FROM " + baseTableName + " WHERE KP = '001'"); + conn.createStatement().execute("CREATE INDEX " + globalViewIndexName + " on " + + globalViewName + " (KV) " + " INCLUDE (KV2) ASYNC"); + String tenantId1 = "tenantId1"; + String tenantId2 = "tenantId2"; + Properties tenantProps1 = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Properties tenantProps2 = PropertiesUtil.deepCopy(TEST_PROPERTIES); + tenantProps1.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId1); + tenantProps2.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId2); + + //create tenant views and upsert one row, this updates all the timestamps in the client's cache + try (Connection tenantConn1 = cqs.connect(url, tenantProps1); + Connection tenantConn2 = cqs.connect(url, tenantProps2)) { + tenantConn1.createStatement().execute("CREATE VIEW " + tenantViewName1 + " AS SELECT * FROM " + globalViewName); + tenantConn1.createStatement().execute("UPSERT INTO " + tenantViewName1 + " (PK, KV, KV2) VALUES " + "('PK1', 'KV', '01')"); + tenantConn1.commit(); + + tenantConn2.createStatement().execute("CREATE VIEW " + tenantViewName2 + " AS SELECT * FROM " + globalViewName); + tenantConn2.createStatement().execute("UPSERT INTO " + tenantViewName2 + " (PK, KV, KV2) VALUES " + "('PK2', 'KV', '02')"); + tenantConn2.commit(); + } + // build global view index + IndexToolIT.runIndexTool(false, "", globalViewName, + globalViewIndexName); + + // query on secondary key should use inherited index for all tenant views. + try (Connection tenantConn1 = cqs.connect(url, tenantProps1); + Connection tenantConn2 = cqs.connect(url, tenantProps2)) { + + String query1 = "SELECT KV2 FROM " + tenantViewName1 + " WHERE KV = 'KV'"; + String query2 = "SELECT KV2 FROM " + tenantViewName2 + " WHERE KV = 'KV'"; + + ResultSet rs = tenantConn1.createStatement().executeQuery(query1); + assertPlan((PhoenixResultSet) rs, "", tenantViewName1 + "#" + globalViewIndexName); Review Comment: Small nit: Instead of using `#` use the constant `CHILD_VIEW_INDEX_NAME_SEPARATOR` in the test code. There are multiple places where `#` is being used. > Handle inherited indexes for tenant views when validating LAST_DDL_TIMESTAMPS > ----------------------------------------------------------------------------- > > Key: PHOENIX-7212 > URL: https://issues.apache.org/jira/browse/PHOENIX-7212 > Project: Phoenix > Issue Type: Sub-task > Reporter: Palash Chauhan > Assignee: Palash Chauhan > Priority: Major > > When a tenant view is resolved and it inherits an index from its parent > view/table, a PTable object for the inherited index is added to the list of > index PTables in the tenant view PTable object. This PTable object has a > modified name of the form `TenantView#Index` and has its tenantId attribute > set to that of the tenant view. > During a query/upsert, along with the table/view, we also add the indexes of > the table/view to the request for validating LAST_DDL_TIMESTAMP. We provide > the key of the PTables i.e. (tenantId, schemaName, tableName) to the server. > Server looks up its cache based on this key to find out the > LAST_DDL_TIMESTAMP and if the key is not present, it fetches the table from > SYSCAT. > Suppose we perform a query on a tenant view which has inherited an index > still in BUILDING state. After the query finishes, server would have cached > (tenantId,schema,table) for the actual global index. The index is then built > and its state changes to ACTIVE. Cache invalidation happens for the key > (null, schema, table). A subsequent query on the tenant view will > successfully validate the inherited index and will not learn about the state > change. -- This message was sent by Atlassian Jira (v8.20.10#820010)