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

chenglei updated PHOENIX-2613:
------------------------------
    Description: 
In pheonix 4.6,any column of multi-part primary key can be null.If a table has 
one row which has a column of multi-part primary key is null, and the java 
assertion is disable, when we do a query,the Skip Scan may cause RegionServer 
scan indefinite loop,just as the following unit test:

{code:borderStyle=solid}

@Test
public void testNullInfiniteLoop() throws Exception
{
        this.jdbcTemplate.update("drop table if exists NULL_TEST ");
                
        this.jdbcTemplate.update(
          "create table NULL_TEST"+
          "("+
                 "CREATETIME VARCHAR,"+
                 "ACCOUNTID VARCHAR,"+
                 "SERVICENAME VARCHAR,"+
                 "SPAN.APPID VARCHAR,"+
                 "CONSTRAINT pk PRIMARY KEY(CREATETIME,ACCOUNTID,SERVICENAME)"+
          ")");
                
        this.jdbcTemplate.update("upsert into 
NULL_TEST(CREATETIME,SERVICENAME,SPAN.APPID) 
values('20160116141006','servlet','android')");
        this.jdbcTemplate.update("upsert into 
NULL_TEST(CREATETIME,ACCOUNTID,SERVICENAME,SPAN.APPID) 
values('20160116151006','2404787','jdbc','ios')");
        this.jdbcTemplate.queryForList("select * from NULL_TEST where 
CREATETIME>='20160116121006' and  CREATETIME<='20160116181006' and 
ACCOUNTID='2404787'");
                                
}
{code}

As above unit test explained,we create a NULL_TEST table, and insert  a row 
which ACCOUNTID column is null, When we do a query which condition is  
CREATETIME column and ACCOUNTID column, Phoenix will use SkipScanFilter to scan 
the table. Unfortunately,the query will run forever,can not return result.


If we construct  a SkipScanFilter using the above query condition,and we can 
see after the SkipScanFilter's filterKeyValue method is called on the KeyValue 
which rowKey is(the ACCOUNTID column is null) :
{noformat}
20160116141006\\x00\\x00servlet
{noformat}
the SkipScanFilter will return a erroneous NextHintCell value(2404787 is the 
ACCOUNTID): 
{noformat}
20160116141006\\x00\\x002404787
{noformat}
which should be:
{noformat}
 20160116141006\\x002404787
{noformat}

Just as the following unit test on the SkipScanFilter:

{code:borderStyle=solid}

@Test
public void testNextCellHintError() throws Exception
{
        List<List<KeyRange>> keyRanges=Arrays.asList(
                        
Collections.singletonList(KeyRange.getKeyRange(Bytes.toBytes("20160116121006"),true,Bytes.toBytes("20160116181006"),true)),
                        
Collections.singletonList(PChar.INSTANCE.getKeyRange(Bytes.toBytes("2404787"), 
true, Bytes.toBytes("2404787"), true)));
        
        RowKeySchemaBuilder rowKeySchemaBuilder = new RowKeySchemaBuilder(3);
        
        for(int i=1;i<=3;i++)
        {

                rowKeySchemaBuilder.addField(new PDatum() {
                        @Override
                        public boolean isNullable() {
                                return true;
                        }
                        @Override
                        public PDataType getDataType() {
                                return PVarchar.INSTANCE;
                        }
                        @Override
                        public Integer getMaxLength() {
                                return null;
                        }
                        @Override
                        public Integer getScale() {
                                return null;
                        }
                        @Override
                        public SortOrder getSortOrder() {
                                return SortOrder.getDefault();
                        }
                }, true, SortOrder.getDefault());
        }
        
        RowKeySchema rowKeySchema=rowKeySchemaBuilder.build();
        
        byte[] rowKey=Bytes.toBytesBinary("20160116141006\\x00\\x00servlet");
        KeyValue keyValue=new KeyValue(
                        rowKey, 
                        Bytes.toBytes("SPAN"), 
                        Bytes.toBytes("APPID"),
                        1453117575829L, 
                        org.apache.hadoop.hbase.KeyValue.Type.Put);
        SkipScanFilter skipScanFilter=new SkipScanFilter(keyRanges, 
rowKeySchema);
        skipScanFilter.filterKeyValue(keyValue);
        Cell nextCellHint=skipScanFilter.getNextCellHint(keyValue);
        
assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
        //try once again...
        skipScanFilter.filterKeyValue(keyValue);
        nextCellHint=skipScanFilter.getNextCellHint(keyValue);
        
assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
}

{code}

W also notice if we enable the java assertion, the query will not  run 
forever,but get a error reponse,caused by the following code in 
SkipScanFilter's setNextCellHint method:

{code:borderStyle=solid}
        if (!isHintAfterPrevious) {
            String msg = "The next hint must come after previous hint (prev=" + 
previousCellHint + ", next=" + nextCellHint + ", kv=" + kv + ")";
            assert isHintAfterPrevious : msg;
            logger.warn(msg);
        }

{code}
but often java assertion is disable,so it should throw a exception instead of 
assertion.


  was:
In pheonix 4.6,any column of multi-part primary key can be null.If a table has 
one row which has a column of multi-part primary key is null, and the java 
assert is disable, when we do a query,the Skip Scan may cause RegionServer scan 
indefinite loop,just as the following unit test:

{code:borderStyle=solid}

@Test
public void testNullInfiniteLoop() throws Exception
{
        this.jdbcTemplate.update("drop table if exists NULL_TEST ");
                
        this.jdbcTemplate.update(
          "create table NULL_TEST"+
          "("+
                 "CREATETIME VARCHAR,"+
                 "ACCOUNTID VARCHAR,"+
                 "SERVICENAME VARCHAR,"+
                 "SPAN.APPID VARCHAR,"+
                 "CONSTRAINT pk PRIMARY KEY(CREATETIME,ACCOUNTID,SERVICENAME)"+
          ")");
                
        this.jdbcTemplate.update("upsert into 
NULL_TEST(CREATETIME,SERVICENAME,SPAN.APPID) 
values('20160116141006','servlet','android')");
        this.jdbcTemplate.update("upsert into 
NULL_TEST(CREATETIME,ACCOUNTID,SERVICENAME,SPAN.APPID) 
values('20160116151006','2404787','jdbc','ios')");
        this.jdbcTemplate.queryForList("select * from NULL_TEST where 
CREATETIME>='20160116121006' and  CREATETIME<='20160116181006' and 
ACCOUNTID='2404787'");
                                
}
{code}

As above unit test explained,we create a NULL_TEST table, and insert  a row 
which ACCOUNTID column is null, When we do a query which condition is  
CREATETIME column and ACCOUNTID column, Phoenix will use SkipScanFilter to scan 
the table. Unfortunately,the query will run forever,can not return result.


If we construct  a SkipScanFilter using the above query condition,and we can 
see after the SkipScanFilter's filterKeyValue method is called on the KeyValue 
which rowKey is(the ACCOUNTID column is null) :
{noformat}
20160116141006\\x00\\x00servlet
{noformat}
the SkipScanFilter will return a erroneous NextHintCell value(2404787 is the 
ACCOUNTID): 
{noformat}
20160116141006\\x00\\x002404787
{noformat}
which should be:
{noformat}
 20160116141006\\x002404787
{noformat}

Just as the following unit test on the SkipScanFilter:

{code:borderStyle=solid}

@Test
public void testNextCellHintError() throws Exception
{
        List<List<KeyRange>> keyRanges=Arrays.asList(
                        
Collections.singletonList(KeyRange.getKeyRange(Bytes.toBytes("20160116121006"),true,Bytes.toBytes("20160116181006"),true)),
                        
Collections.singletonList(PChar.INSTANCE.getKeyRange(Bytes.toBytes("2404787"), 
true, Bytes.toBytes("2404787"), true)));
        
        RowKeySchemaBuilder rowKeySchemaBuilder = new RowKeySchemaBuilder(3);
        
        for(int i=1;i<=3;i++)
        {

                rowKeySchemaBuilder.addField(new PDatum() {
                        @Override
                        public boolean isNullable() {
                                return true;
                        }
                        @Override
                        public PDataType getDataType() {
                                return PVarchar.INSTANCE;
                        }
                        @Override
                        public Integer getMaxLength() {
                                return null;
                        }
                        @Override
                        public Integer getScale() {
                                return null;
                        }
                        @Override
                        public SortOrder getSortOrder() {
                                return SortOrder.getDefault();
                        }
                }, true, SortOrder.getDefault());
        }
        
        RowKeySchema rowKeySchema=rowKeySchemaBuilder.build();
        
        byte[] rowKey=Bytes.toBytesBinary("20160116141006\\x00\\x00servlet");
        KeyValue keyValue=new KeyValue(
                        rowKey, 
                        Bytes.toBytes("SPAN"), 
                        Bytes.toBytes("APPID"),
                        1453117575829L, 
                        org.apache.hadoop.hbase.KeyValue.Type.Put);
        SkipScanFilter skipScanFilter=new SkipScanFilter(keyRanges, 
rowKeySchema);
        skipScanFilter.filterKeyValue(keyValue);
        Cell nextCellHint=skipScanFilter.getNextCellHint(keyValue);
        
assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
        //try once again...
        skipScanFilter.filterKeyValue(keyValue);
        nextCellHint=skipScanFilter.getNextCellHint(keyValue);
        
assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
}

{code}



> if any column of multi-part primary key is null, the Skip Scan may cause 
> RegionServer scan indefinite loop
> ----------------------------------------------------------------------------------------------------------
>
>                 Key: PHOENIX-2613
>                 URL: https://issues.apache.org/jira/browse/PHOENIX-2613
>             Project: Phoenix
>          Issue Type: Bug
>    Affects Versions: 4.6.0
>         Environment: HBase 0.98.6-cdh5.3.2, Phoenix 4.6.0-HBase-0.98
>            Reporter: chenglei
>
> In pheonix 4.6,any column of multi-part primary key can be null.If a table 
> has one row which has a column of multi-part primary key is null, and the 
> java assertion is disable, when we do a query,the Skip Scan may cause 
> RegionServer scan indefinite loop,just as the following unit test:
> {code:borderStyle=solid}
> @Test
> public void testNullInfiniteLoop() throws Exception
> {
>       this.jdbcTemplate.update("drop table if exists NULL_TEST ");
>               
>       this.jdbcTemplate.update(
>           "create table NULL_TEST"+
>           "("+
>                  "CREATETIME VARCHAR,"+
>                  "ACCOUNTID VARCHAR,"+
>                  "SERVICENAME VARCHAR,"+
>                  "SPAN.APPID VARCHAR,"+
>                  "CONSTRAINT pk PRIMARY 
> KEY(CREATETIME,ACCOUNTID,SERVICENAME)"+
>           ")");
>               
>       this.jdbcTemplate.update("upsert into 
> NULL_TEST(CREATETIME,SERVICENAME,SPAN.APPID) 
> values('20160116141006','servlet','android')");
>       this.jdbcTemplate.update("upsert into 
> NULL_TEST(CREATETIME,ACCOUNTID,SERVICENAME,SPAN.APPID) 
> values('20160116151006','2404787','jdbc','ios')");
>       this.jdbcTemplate.queryForList("select * from NULL_TEST where 
> CREATETIME>='20160116121006' and  CREATETIME<='20160116181006' and 
> ACCOUNTID='2404787'");
>                               
> }
> {code}
> As above unit test explained,we create a NULL_TEST table, and insert  a row 
> which ACCOUNTID column is null, When we do a query which condition is  
> CREATETIME column and ACCOUNTID column, Phoenix will use SkipScanFilter to 
> scan the table. Unfortunately,the query will run forever,can not return 
> result.
> If we construct  a SkipScanFilter using the above query condition,and we can 
> see after the SkipScanFilter's filterKeyValue method is called on the 
> KeyValue which rowKey is(the ACCOUNTID column is null) :
> {noformat}
> 20160116141006\\x00\\x00servlet
> {noformat}
> the SkipScanFilter will return a erroneous NextHintCell value(2404787 is the 
> ACCOUNTID): 
> {noformat}
> 20160116141006\\x00\\x002404787
> {noformat}
> which should be:
> {noformat}
>  20160116141006\\x002404787
> {noformat}
> Just as the following unit test on the SkipScanFilter:
> {code:borderStyle=solid}
> @Test
> public void testNextCellHintError() throws Exception
> {
>       List<List<KeyRange>> keyRanges=Arrays.asList(
>                       
> Collections.singletonList(KeyRange.getKeyRange(Bytes.toBytes("20160116121006"),true,Bytes.toBytes("20160116181006"),true)),
>                       
> Collections.singletonList(PChar.INSTANCE.getKeyRange(Bytes.toBytes("2404787"),
>  true, Bytes.toBytes("2404787"), true)));
>       
>       RowKeySchemaBuilder rowKeySchemaBuilder = new RowKeySchemaBuilder(3);
>       
>       for(int i=1;i<=3;i++)
>       {
>               rowKeySchemaBuilder.addField(new PDatum() {
>                       @Override
>                       public boolean isNullable() {
>                               return true;
>                       }
>                       @Override
>                       public PDataType getDataType() {
>                               return PVarchar.INSTANCE;
>                       }
>                       @Override
>                       public Integer getMaxLength() {
>                               return null;
>                       }
>                       @Override
>                       public Integer getScale() {
>                               return null;
>                       }
>                       @Override
>                       public SortOrder getSortOrder() {
>                               return SortOrder.getDefault();
>                       }
>               }, true, SortOrder.getDefault());
>       }
>       
>       RowKeySchema rowKeySchema=rowKeySchemaBuilder.build();
>       
>       byte[] rowKey=Bytes.toBytesBinary("20160116141006\\x00\\x00servlet");
>       KeyValue keyValue=new KeyValue(
>                       rowKey, 
>                       Bytes.toBytes("SPAN"), 
>                       Bytes.toBytes("APPID"),
>                       1453117575829L, 
>                       org.apache.hadoop.hbase.KeyValue.Type.Put);
>       SkipScanFilter skipScanFilter=new SkipScanFilter(keyRanges, 
> rowKeySchema);
>       skipScanFilter.filterKeyValue(keyValue);
>       Cell nextCellHint=skipScanFilter.getNextCellHint(keyValue);
>       
> assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
>       //try once again...
>       skipScanFilter.filterKeyValue(keyValue);
>       nextCellHint=skipScanFilter.getNextCellHint(keyValue);
>       
> assertTrue(Bytes.toStringBinary(CellUtil.cloneRow(nextCellHint)).equals("20160116141006\\x00\\x002404787"));
> }
> {code}
> W also notice if we enable the java assertion, the query will not  run 
> forever,but get a error reponse,caused by the following code in 
> SkipScanFilter's setNextCellHint method:
> {code:borderStyle=solid}
>         if (!isHintAfterPrevious) {
>             String msg = "The next hint must come after previous hint (prev=" 
> + previousCellHint + ", next=" + nextCellHint + ", kv=" + kv + ")";
>             assert isHintAfterPrevious : msg;
>             logger.warn(msg);
>         }
> {code}
> but often java assertion is disable,so it should throw a exception instead of 
> assertion.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to