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

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

Table creation is not a synchronous operation. The client submits the admin 
action. The master asynchronously executes it. The client will check status via 
the meta table and spin and return when it sees that the table exists. When you 
have two threads concurrently submitting create requests, ignoring 
TableExistsException, and then issuing an op, this is fraught for races. I'd 
change the code to lift the admin action out. I'm going to resolve this issue 
as cannot reproduce. If you continue to have trouble with racy behavior with 
respect to table creation we can follow up on another issue targeted to that. 

> 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
>    Affects Versions: 0.98.23, 1.2.4
>            Reporter: Samarth Jain
>         Attachments: HBASE-17300.patch
>
>
> 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.
> 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 (HBaseAdmin admin = TEST_UTIL.getHBaseAdmin()) {
>                 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 (HBaseAdmin admin = TEST_UTIL.getHBaseAdmin()) {
>                     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)

Reply via email to