You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hbase.apache.org by "Samarth Jain (JIRA)" <ji...@apache.org> on 2016/12/13 02:11:59 UTC
[jira] [Created] (HBASE-17300) Concurrently calling checkAndPut
with expected value as null returns true unexpectedly
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)