hbase-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Andrew Purtell (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (HBASE-17300) Concurrently calling checkAndPut with expected value as null returns true unexpectedly
Date Tue, 13 Dec 2016 21:11:58 GMT

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

Mime
View raw message