Samarth Jain created HBASE-17300: ------------------------------------ Summary: Concurrently calling checkAndPut with expected value as null returns true unexpectedly Key: HBASE-17300 URL: https://issues.apache.org/jira/browse/HBASE-17300 Project: HBase Issue Type: Bug Reporter: Samarth Jain
Attached is the test case. I have added some comments so hopefully the test makes sense. It actually is causing test failures on the Phoenix branches. PS - I am using a bit of Phoenix API to get hold of HBaseAdmin. But it should be fairly straightforward to adopt it for HBase IT tests. The test fails consistently using HBase-0.98.23. It exhibits flappy behavior with the 1.2 branch (failed twice in 5 tries). {code} @Test public void testNullCheckAndPut() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { try (HBaseAdmin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) { Callable<Boolean> c1 = new CheckAndPutCallable(); Callable<Boolean> c2 = new CheckAndPutCallable(); ExecutorService e = Executors.newFixedThreadPool(5); Future<Boolean> f1 = e.submit(c1); Future<Boolean> f2 = e.submit(c2); assertTrue(f1.get() || f2.get()); assertFalse(f1.get() && f2.get()); } } } private static final class CheckAndPutCallable implements Callable<Boolean> { @Override public Boolean call() throws Exception { byte[] rowToLock = "ROW".getBytes(); byte[] colFamily = "COLUMN_FAMILY".getBytes(); byte[] column = "COLUMN".getBytes(); byte[] newValue = "NEW_VALUE".getBytes(); byte[] oldValue = "OLD_VALUE".getBytes(); byte[] tableName = "table".getBytes(); boolean acquired = false; try (Connection conn = DriverManager.getConnection(getUrl())) { try (HBaseAdmin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) { HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(tableName)); HColumnDescriptor columnDesc = new HColumnDescriptor(colFamily); columnDesc.setTimeToLive(600); tableDesc.addFamily(columnDesc); try { admin.createTable(tableDesc); } catch (TableExistsException e) { // ignore } try (HTableInterface table = admin.getConnection().getTable(tableName)) { Put put = new Put(rowToLock); put.add(colFamily, column, oldValue); // add a row with column set to oldValue table.put(put); put = new Put(rowToLock); put.add(colFamily, column, newValue); // only one of the threads should be able to get return value of true for the expected value of oldValue acquired = table.checkAndPut(rowToLock, colFamily, column, oldValue, put); if (!acquired) { // if a thread didn't get true before, then it shouldn't get true this time either // because the column DOES exist acquired = table.checkAndPut(rowToLock, colFamily, column, null, put); } } } } return acquired; } } {code} cc [~apurtell], [~jamestaylor], [~lhofhansl]. -- This message was sent by Atlassian JIRA (v6.3.4#6332)