Github user ChinmaySKulkarni commented on a diff in the pull request: https://github.com/apache/phoenix/pull/313#discussion_r204968699 --- Diff: phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java --- @@ -1274,28 +1341,145 @@ public void testChildViewCreationFails() throws Exception { PhoenixRuntime.getTableNoCache(conn, fullViewName2); } - private static final String FAILED_VIEWNAME = "FAILED_VIEW"; - private static final byte[] ROWKEY_TO_FAIL_BYTES = SchemaUtil.getTableKey(null, Bytes.toBytes(SCHEMA2), - Bytes.toBytes(FAILED_VIEWNAME)); - - public static class FailingRegionObserver extends SimpleRegionObserver { - @Override - public void preBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c, - MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException { - if (shouldFail(c, miniBatchOp.getOperation(0))) { - // throwing anything other than instances of IOException result - // in this coprocessor being unloaded - // DoNotRetryIOException tells HBase not to retry this mutation - // multiple times - throw new DoNotRetryIOException(); - } - } - - private boolean shouldFail(ObserverContext<RegionCoprocessorEnvironment> c, Mutation m) { - TableName tableName = c.getEnvironment().getRegion().getRegionInfo().getTable(); - return tableName.equals(PhoenixDatabaseMetaData.SYSTEM_CATALOG_HBASE_TABLE_NAME) - && (Bytes.equals(ROWKEY_TO_FAIL_BYTES, m.getRow())); - } - - } + @Test + public void testConcurrentViewCreationAndTableDrop() throws Exception { + try (Connection conn = DriverManager.getConnection(getUrl())) { + String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String fullViewName1 = SchemaUtil.getTableName(SCHEMA2, SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName()); + String fullViewName2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); + latch1 = new CountDownLatch(1); + latch2 = new CountDownLatch(1); + String tableDdl = "CREATE TABLE " + fullTableName + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)" + + tableDDLOptions; + conn.createStatement().execute(tableDdl); + + ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = Executors.defaultThreadFactory().newThread(r); + t.setDaemon(true); + t.setPriority(Thread.MIN_PRIORITY); + return t; + } + }); + + // create the view in a separate thread (which will take some time + // to complete) + Future<Exception> future = executorService.submit(new CreateViewRunnable(fullTableName, fullViewName1)); + // wait till the thread makes the rpc to create the view + latch1.await(); + tableDdl = "DROP TABLE " + fullTableName; + try { + // drop table should fail as we are concurrently adding a view + conn.createStatement().execute(tableDdl); + fail("Creating a view while concurrently dropping the base table should fail"); + } catch (ConcurrentTableMutationException e) { + } + latch2.countDown(); + + Exception e = future.get(); + assertTrue(e == null); + + // create another view to ensure that the cell used to prevent + // concurrent modifications was removed + String ddl = "CREATE VIEW " + fullViewName2 + " (v2 VARCHAR) AS SELECT * FROM " + fullTableName + + " WHERE k = 6"; + conn.createStatement().execute(ddl); + } + } + + @Test + public void testConcurrentAddColumn() throws Exception { + try (Connection conn = DriverManager.getConnection(getUrl())) { + String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String fullViewName = SchemaUtil.getTableName(SCHEMA2, SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName()); + // create base table + String tableDdl = "CREATE TABLE " + fullTableName + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)" + + tableDDLOptions; + conn.createStatement().execute(tableDdl); + // create a view + String ddl = "CREATE VIEW " + fullViewName + " (v2 VARCHAR) AS SELECT * FROM " + fullTableName + + " WHERE k = 6"; + conn.createStatement().execute(ddl); + + latch1 = new CountDownLatch(1); + latch2 = new CountDownLatch(1); + ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = Executors.defaultThreadFactory().newThread(r); + t.setDaemon(true); + t.setPriority(Thread.MIN_PRIORITY); + return t; + } + }); + + // add a column to the view in a separate thread (which will take + // some time to complete) + Future<Exception> future = executorService.submit(new AddColumnRunnable(fullViewName)); + // wait till the thread makes the rpc to create the view + boolean result = latch1.await(2, TimeUnit.MINUTES); + if (!result) { + fail("The create view rpc look too long"); + } + tableDdl = "ALTER TABLE " + fullTableName + " ADD v3 INTEGER"; + try { + // add the same column to the base table with a different type + conn.createStatement().execute(tableDdl); + fail("Creating a view while concurrently dropping the base table should fail"); + } catch (ConcurrentTableMutationException e) { + } + latch2.countDown(); + + Exception e = future.get(); + assertTrue(e == null); --- End diff -- nit: `assertNull`
---