Skip to content

Commit 344cc0d

Browse files
committed
HBASE-28523 Use a single get call in REST multiget endpoint (#5862)
Signed-off-by: Ankit Singhal <[email protected]>
1 parent ab45e78 commit 344cc0d

File tree

2 files changed

+104
-17
lines changed

2 files changed

+104
-17
lines changed

hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/MultiRowResource.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
package org.apache.hadoop.hbase.rest;
1919

2020
import java.io.IOException;
21+
import java.util.ArrayList;
2122
import java.util.Base64;
2223
import java.util.Base64.Decoder;
24+
import java.util.List;
2325
import org.apache.hadoop.hbase.Cell;
2426
import org.apache.hadoop.hbase.CellUtil;
27+
import org.apache.hadoop.hbase.client.Result;
2528
import org.apache.hadoop.hbase.filter.Filter;
2629
import org.apache.hadoop.hbase.filter.ParseFilter;
2730
import org.apache.hadoop.hbase.rest.model.CellModel;
@@ -98,8 +101,7 @@ public Response get(final @Context UriInfo uriInfo,
98101
ParseFilter pf = new ParseFilter();
99102
parsedParamFilter = pf.parseFilterString(filterBytes);
100103
}
101-
CellSetModel model = new CellSetModel();
102-
// TODO map this to a Table.get(List<Get> gets) call instead of multiple get calls
104+
List<RowSpec> rowSpecs = new ArrayList<>();
103105
for (String rk : params.get(ROW_KEYS_PARAM_NAME)) {
104106
RowSpec rowSpec = new RowSpec(rk, keyEncoding);
105107

@@ -112,24 +114,24 @@ public Response get(final @Context UriInfo uriInfo,
112114
rowSpec.addColumn(Bytes.toBytes(this.columns[i]));
113115
}
114116
}
117+
rowSpecs.add(rowSpec);
118+
}
115119

116-
ResultGenerator generator = ResultGenerator.fromRowSpec(this.tableResource.getName(),
117-
rowSpec, parsedParamFilter, !params.containsKey(NOCACHE_PARAM_NAME));
118-
Cell value = null;
119-
RowModel rowModel = new RowModel(rowSpec.getRow());
120-
if (generator.hasNext()) {
121-
while ((value = generator.next()) != null) {
122-
rowModel.addCell(new CellModel(CellUtil.cloneFamily(value),
123-
CellUtil.cloneQualifier(value), value.getTimestamp(), CellUtil.cloneValue(value)));
124-
}
125-
model.addRow(rowModel);
126-
} else {
127-
if (LOG.isTraceEnabled()) {
128-
LOG.trace("The row : " + rk + " not found in the table.");
129-
}
120+
MultiRowResultReader reader = new MultiRowResultReader(this.tableResource.getName(), rowSpecs,
121+
parsedParamFilter, !params.containsKey(NOCACHE_PARAM_NAME));
122+
123+
CellSetModel model = new CellSetModel();
124+
for (Result r : reader.getResults()) {
125+
if (r.isEmpty()) {
126+
continue;
130127
}
128+
RowModel rowModel = new RowModel(r.getRow());
129+
for (Cell c : r.listCells()) {
130+
rowModel.addCell(new CellModel(CellUtil.cloneFamily(c), CellUtil.cloneQualifier(c),
131+
c.getTimestamp(), CellUtil.cloneValue(c)));
132+
}
133+
model.addRow(rowModel);
131134
}
132-
133135
if (model.getRows().isEmpty()) {
134136
// If no rows found.
135137
servlet.getMetrics().incrementFailedGetRequests(1);
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.rest;
19+
20+
import java.io.IOException;
21+
import java.util.ArrayList;
22+
import java.util.Collection;
23+
import java.util.List;
24+
import org.apache.hadoop.hbase.CellUtil;
25+
import org.apache.hadoop.hbase.DoNotRetryIOException;
26+
import org.apache.hadoop.hbase.client.Get;
27+
import org.apache.hadoop.hbase.client.Result;
28+
import org.apache.hadoop.hbase.client.Table;
29+
import org.apache.hadoop.hbase.filter.Filter;
30+
import org.apache.hadoop.hbase.security.AccessDeniedException;
31+
import org.apache.hadoop.util.StringUtils;
32+
import org.apache.yetus.audience.InterfaceAudience;
33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
35+
36+
@InterfaceAudience.Private
37+
public class MultiRowResultReader {
38+
39+
private static final Logger LOG = LoggerFactory.getLogger(MultiRowResultReader.class);
40+
41+
private Result[] results;
42+
43+
public MultiRowResultReader(final String tableName, final Collection<RowSpec> rowspecs,
44+
final Filter filter, final boolean cacheBlocks) throws IOException {
45+
try (Table table = RESTServlet.getInstance().getTable(tableName)) {
46+
List<Get> gets = new ArrayList<>(rowspecs.size());
47+
for (RowSpec rowspec : rowspecs) {
48+
Get get = new Get(rowspec.getRow());
49+
if (rowspec.hasColumns()) {
50+
for (byte[] col : rowspec.getColumns()) {
51+
byte[][] split = CellUtil.parseColumn(col);
52+
if (split.length == 1) {
53+
get.addFamily(split[0]);
54+
} else if (split.length == 2) {
55+
get.addColumn(split[0], split[1]);
56+
} else {
57+
throw new IllegalArgumentException("Invalid column specifier.");
58+
}
59+
}
60+
}
61+
get.setTimeRange(rowspec.getStartTime(), rowspec.getEndTime());
62+
get.readVersions(rowspec.getMaxVersions());
63+
if (filter != null) {
64+
get.setFilter(filter);
65+
}
66+
get.setCacheBlocks(cacheBlocks);
67+
gets.add(get);
68+
}
69+
results = table.get(gets);
70+
} catch (DoNotRetryIOException e) {
71+
// TODO this is copied from RowResultGenerator, but we probably shouldn't swallow
72+
// every type of exception but AccessDeniedException
73+
LOG.warn(StringUtils.stringifyException(e));
74+
// Lets get the exception rethrown to get a more meaningful error message than 404
75+
if (e instanceof AccessDeniedException) {
76+
throw e;
77+
}
78+
}
79+
}
80+
81+
public Result[] getResults() {
82+
return results;
83+
}
84+
85+
}

0 commit comments

Comments
 (0)