You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hbase.apache.org by "Andrew Purtell (JIRA)" <ji...@apache.org> on 2016/12/13 02:24:58 UTC

[jira] [Commented] (HBASE-17300) Concurrently calling checkAndPut with expected value as null returns true unexpectedly

    [ https://issues.apache.org/jira/browse/HBASE-17300?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15743886#comment-15743886 ] 

Andrew Purtell commented on HBASE-17300:
----------------------------------------

bq. 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. 
You're more likely to get engagement from the HBase community if the repro case just works with the HBase API. FWIW

> 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)