Allan,

Thanks for the bug report, analysis, and contribution. I will incorporate you 
patches as part of HBASE-4116: https://issues.apache.org/jira/browse/HBASE-4116

 
Best regards,


- Andy


Problems worthy of attack prove their worth by hitting back. - Piet Hein (via 
Tom White)


----- Original Message -----
> From: allan yan <hailun...@gmail.com>
> To: user@hbase.apache.org
> Cc: d...@hbase.apache.org
> Sent: Monday, July 18, 2011 2:49 PM
> Subject: HBase rest RowSpec bug on startRow and endRow
> 
> Hi,
> 
> I don't know how to report issue to HBase team. So I just post it here. 
> There might be a bug for REST web service to get rows with given startRow and 
> endRow.
> 
> For example, to get a list of rows with startRow=testrow1, endRow=testrow2, 
> I  
> send GET request: 
> 
> curl http://localhost:8123/TestRowResource/testrow1,testrow2/a:1
> 
> And got StringIndexOutOfBoundsException:
> 
> 2011-07-18 14:25:49,977 ERROR [1378924033@qtp-310826391-0] log.Slf4jLog(87): 
> /TestRowResource/testrow1,testrow2/a:1
> java.lang.IllegalArgumentException: 
> java.lang.StringIndexOutOfBoundsException: 
> String index out of range: -1
>     at org.apache.hadoop.hbase.rest.RowSpec.parseRowKeys(RowSpec.java:84)
>     at org.apache.hadoop.hbase.rest.RowSpec.<init>(RowSpec.java:56)
>     at 
> org.apache.hadoop.hbase.rest.RowResource.<init>(RowResource.java:71)
>     at 
> org.apache.hadoop.hbase.rest.TableResource.getRowResource(TableResource.java:278)
>     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>     at 
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>     at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>     at java.lang.reflect.Method.invoke(Method.java:597)
>     at 
> com.sun.jersey.server.impl.uri.rules.SubLocatorRule.invokeSubLocator(SubLocatorRule.java:165)
>     at 
> com.sun.jersey.server.impl.uri.rules.SubLocatorRule.accept(SubLocatorRule.java:97)
>     at 
> com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:136)
>     at 
> com.sun.jersey.server.impl.uri.rules.SubLocatorRule.accept(SubLocatorRule.java:121)
>     at 
> com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:136)
>     at 
> com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:86)
>     at 
> com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:136)
>     at 
> com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:74)
>     at 
> com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1357)
>     at 
> com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1289)
>     at 
> com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1239)
>     at 
> com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1229)
>     at 
> com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:420)
>     at 
> com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:497)
>     at 
> com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:684)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
>     at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
>     at 
> org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1221)
>     at 
> org.apache.hadoop.hbase.rest.filter.GzipFilter.doFilter(GzipFilter.java:73)
>     at 
> org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
>     at 
> org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399)
>     at 
> org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
>     at 
> org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
>     at 
> org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
>     at org.mortbay.jetty.Server.handle(Server.java:326)
>     at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
>     at 
> org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:928)
>     at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
>     at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
>     at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
>     at 
> org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
>     at 
> org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
> Caused by: java.lang.StringIndexOutOfBoundsException: String index out of 
> range: 
> -1
>     at java.lang.String.substring(String.java:1937)
>     at java.lang.String.substring(String.java:1904)
>     at org.apache.hadoop.hbase.rest.RowSpec.parseRowKeys(RowSpec.java:78)
>     ... 39 more
> 
> This was because in the RowSpec.java, parseRowKeys method, startRow value was 
> changed:
> ---------------------------------------------------------------------------------
>       startRow = sb.toString();
>       int idx = startRow.indexOf(',');
>       if (idx != -1) {
>         startRow = URLDecoder.decode(startRow.substring(0, idx),
>           HConstants.UTF8_ENCODING);
>         endRow = URLDecoder.decode(startRow.substring(idx + 1),
>           HConstants.UTF8_ENCODING);
>       } else {
>         startRow = URLDecoder.decode(startRow, HConstants.UTF8_ENCODING);
>       }
> ---------------------------------------------------------------------------------
> After change to this, it works:
> ---------------------------------------------------------------------------------
>       String row = sb.toString();
>       int idx = row.indexOf(',');
>       if (idx != -1) {
>         startRow = URLDecoder.decode(row.substring(0, idx),
>           HConstants.UTF8_ENCODING);
>         endRow = URLDecoder.decode(row.substring(idx + 1),
>           HConstants.UTF8_ENCODING);
>       } else {
>         startRow = URLDecoder.decode(row, HConstants.UTF8_ENCODING);
>       }
> ---------------------------------------------------------------------------------
> 
> I've also created a unit test method in TestRowResource.java,
> ---------------------------------------------------------------------------------
>   @Test
>   public void testStartEndRowGetPutXML() throws IOException, JAXBException {
>     String[] rows = {ROW_1,ROW_2,ROW_3};
>     String[] values = {VALUE_1,VALUE_2,VALUE_3};  
>     Response response = null;
>     for(int i=0; i<rows.length; i++){
>         response = putValueXML(TABLE, rows[i], COLUMN_1, values[i]);
>         assertEquals(200, response.getCode());
>         checkValueXML(TABLE, rows[i], COLUMN_1, values[i]);
>     }
> 
>     response = getValueXML(TABLE, rows[0], rows[2], COLUMN_1);
>     assertEquals(200, response.getCode());
>     CellSetModel cellSet = (CellSetModel)
>       unmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
>     assertEquals(2, cellSet.getRows().size());
>     for(int i=0; i<cellSet.getRows().size()-1; i++){
>         RowModel rowModel = cellSet.getRows().get(i);
>         for(CellModel cell : rowModel.getCells()){
>             assertEquals(COLUMN_1, Bytes.toString(cell.getColumn()));
>             assertEquals(values[i], Bytes.toString(cell.getValue()));
>         }    
>     }
>     
>     for(String row : rows){
>         response = deleteRow(TABLE, row);
>         assertEquals(200, response.getCode());
>     }
>   }
> 
>   private static Response getValueXML(String table, String startRow, String 
> endRow, String column)
>           throws IOException {
>         StringBuilder path = new StringBuilder();
>         path.append('/');
>         path.append(table);
>         path.append('/');
>         path.append(startRow);
>         path.append(",");
>         path.append(endRow);
>         path.append('/');
>         path.append(column);
>         return getValueXML(path.toString());
>   }
> ---------------------------------------------------------------------------------
> 
> Thanks,
> Allan Yan
>

Reply via email to