phoenix-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] [phoenix] kadirozde commented on a change in pull request #469: PHOENIX-5156 Consistent Global Indexes for Non-Transactional Tables
Date Fri, 03 May 2019 00:25:27 GMT
kadirozde commented on a change in pull request #469: PHOENIX-5156 Consistent Global Indexes
for Non-Transactional Tables
URL: https://github.com/apache/phoenix/pull/469#discussion_r280639210
 
 

 ##########
 File path: phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java
 ##########
 @@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.end2end.index;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.phoenix.end2end.BaseUniqueNamesOwnClusterIT;
+import org.apache.phoenix.end2end.IndexToolIT;
+import org.apache.phoenix.hbase.index.Indexer;
+import org.apache.phoenix.util.QueryUtil;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import com.google.common.collect.Lists;
+
+@RunWith(Parameterized.class)
+public class GlobalIndexCheckerIT extends BaseUniqueNamesOwnClusterIT {
+    private final boolean async;
+    private final String tableDDLOptions;
+
+    public GlobalIndexCheckerIT(boolean async, boolean encoded) {
+        this.async = async;
+        StringBuilder optionBuilder = new StringBuilder();
+        if (!encoded) {
+            optionBuilder.append(" COLUMN_ENCODED_BYTES=0 ");
+        }
+        this.tableDDLOptions = optionBuilder.toString();
+    }
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        IndexToolIT.setup();
+    }
+
+    @Parameters(
+            name = "async={0},encoded={1}")
+    public static Collection<Object[]> data() {
+        List<Object[]> list = Lists.newArrayListWithExpectedSize(4);
+        boolean[] Booleans = new boolean[]{true, false};
+            for (boolean async : Booleans) {
+                for (boolean encoded : Booleans) {
+                    list.add(new Object[]{async, encoded});
+                }
+            }
+        return list;
+    }
+
+    public static void assertExplainPlan(Connection conn, String selectSql,
+                                         String dataTableFullName, String indexTableFullName)
throws SQLException {
+        ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql);
+        String actualExplainPlan = QueryUtil.getExplainPlan(rs);
+        IndexToolIT.assertExplainPlan(false, actualExplainPlan, dataTableFullName, indexTableFullName);
+    }
+
+    private void populateTable(String tableName) throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("create table " + tableName +
+                " (id varchar(10) not null primary key, val1 varchar(10), val2 varchar(10),
val3 varchar(10))" + tableDDLOptions);
+        conn.createStatement().execute("upsert into " + tableName + " values ('a', 'ab',
'abc', 'abcd')");
+        conn.commit();
+        conn.createStatement().execute("upsert into " + tableName + " values ('b', 'bc',
'bcd', 'bcde')");
+        conn.commit();
+        conn.close();
+    }
+
+    @Test
+    public void skipPostIndexDeleteUpdate() throws Exception {
+        String dataTableName = generateUniqueName();
+        populateTable(dataTableName);
+        Connection conn = DriverManager.getConnection(getUrl());
+        String indexName = generateUniqueName();
+        conn.createStatement().execute("CREATE INDEX " + indexName + " on " +
+                dataTableName + " (val1) include (val2, val3)" + (async ? "ASYNC" : ""));
+        if (async) {
+            // run the index MR job.
+            IndexToolIT.runIndexTool(true, false, null, dataTableName, indexName);
+        }
+        String selectSql =  "SELECT id from " + dataTableName + " WHERE val1  = 'ab'";
+        ResultSet rs = conn.createStatement().executeQuery(selectSql);
+        assertTrue(rs.next());
+        assertEquals("a", rs.getString(1));
+        assertFalse(rs.next());
+
+        // Configure Indexer to skip the last write phase (i.e., the post index update phase)
where the verify flag is set
+        // to true and/or index rows are deleted and check that this does not impact the
correctness
+        Indexer.setSkipPostIndexUpdatesForTesting(true);
+        String dml = "DELETE from " + dataTableName + " WHERE id  = 'a'";
+        assertEquals(1, conn.createStatement().executeUpdate(dml));
+        conn.commit();
+
+        // The index rows are actually not deleted yet because Indexer skipped delete operation.
However, they are
+        // made unverified in the pre index update phase (i.e., the first write phase)
+        dml = "DELETE from " + dataTableName + " WHERE val1  = 'ab'";
 
 Review comment:
   Both delete operations are on the data table. A delete row operation on the data table
should also result in deletion of the corresponding index table row. In the new design, in
order to delete an index table row, the row is first marked unverified in the first write
phase (i.e., before deleting the data table row) and then actually deleted in the third write
phase. Now skipping post index updates means here is skipping the third write phase.  The
first delete DML "DELETE from " + dataTableName + " WHERE id  = 'a'" does not need to scan
index in order to efficiently locate the row to be deleted since id is the primary index of
the data table row. During the execution of this DML, the index row will not be deleted but
left unverified because the last write phase is skipped. The second DML , "DELETE from " +
dataTableName + " WHERE id  = 'a'" needs to use the index table to locate the row (i.e., to
get the primary key for the corresponding row in the data table). Now, the row where id =
'a' does not exist in the data table but exists in the index row. However, the index row is
unverified. This will trigger deletion of index row during read-repair and the scan on the
index table will return no rows thus there will be no rows to delete. To make this clear even
more, I will add a SQL query to count the number of index rows at the end to  make sure there
is only one row left in the index table. The whole point of this test is that failing to complete
the last write phase does not impact correctness.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message