[ 
https://issues.apache.org/jira/browse/HBASE-17300?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Samarth Jain updated HBASE-17300:
---------------------------------
    Description: 
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]. 


  was:
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]. 



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