HBASE-26688 Threads shared EMPTY_RESULT may lead to unexpected client job down. ...
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / client / Get.java
blob0f04407ac3e3bfba17f5b77558724e0874a30e34
1 /**
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org.apache.hadoop.hbase.client;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NavigableSet;
29 import java.util.Set;
30 import java.util.TreeMap;
31 import java.util.TreeSet;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.yetus.audience.InterfaceAudience;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.apache.hadoop.hbase.filter.Filter;
38 import org.apache.hadoop.hbase.io.TimeRange;
39 import org.apache.hadoop.hbase.security.access.Permission;
40 import org.apache.hadoop.hbase.security.visibility.Authorizations;
41 import org.apache.hadoop.hbase.util.Bytes;
43 /**
44 * Used to perform Get operations on a single row.
45 * <p>
46 * To get everything for a row, instantiate a Get object with the row to get.
47 * To further narrow the scope of what to Get, use the methods below.
48 * <p>
49 * To get all columns from specific families, execute {@link #addFamily(byte[]) addFamily}
50 * for each family to retrieve.
51 * <p>
52 * To get specific columns, execute {@link #addColumn(byte[], byte[]) addColumn}
53 * for each column to retrieve.
54 * <p>
55 * To only retrieve columns within a specific range of version timestamps,
56 * execute {@link #setTimeRange(long, long) setTimeRange}.
57 * <p>
58 * To only retrieve columns with a specific timestamp, execute
59 * {@link #setTimestamp(long) setTimestamp}.
60 * <p>
61 * To limit the number of versions of each column to be returned, execute
62 * {@link #readVersions(int) readVersions}.
63 * <p>
64 * To add a filter, call {@link #setFilter(Filter) setFilter}.
66 @InterfaceAudience.Public
67 public class Get extends Query implements Row {
68 private static final Logger LOG = LoggerFactory.getLogger(Get.class);
70 private byte [] row = null;
71 private int maxVersions = 1;
72 private boolean cacheBlocks = true;
73 private int storeLimit = -1;
74 private int storeOffset = 0;
75 private TimeRange tr = TimeRange.allTime();
76 private boolean checkExistenceOnly = false;
77 private Map<byte [], NavigableSet<byte []>> familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
79 /**
80 * Create a Get operation for the specified row.
81 * <p>
82 * If no further operations are done, this will get the latest version of
83 * all columns in all families of the specified row.
84 * @param row row key
86 public Get(byte [] row) {
87 Mutation.checkRow(row);
88 this.row = row;
91 /**
92 * Copy-constructor
94 * @param get
96 public Get(Get get) {
97 this(get.getRow());
98 // from Query
99 this.setFilter(get.getFilter());
100 this.setReplicaId(get.getReplicaId());
101 this.setConsistency(get.getConsistency());
102 // from Get
103 this.cacheBlocks = get.getCacheBlocks();
104 this.maxVersions = get.getMaxVersions();
105 this.storeLimit = get.getMaxResultsPerColumnFamily();
106 this.storeOffset = get.getRowOffsetPerColumnFamily();
107 this.tr = get.getTimeRange();
108 this.checkExistenceOnly = get.isCheckExistenceOnly();
109 this.loadColumnFamiliesOnDemand = get.getLoadColumnFamiliesOnDemandValue();
110 Map<byte[], NavigableSet<byte[]>> fams = get.getFamilyMap();
111 for (Map.Entry<byte[],NavigableSet<byte[]>> entry : fams.entrySet()) {
112 byte [] fam = entry.getKey();
113 NavigableSet<byte[]> cols = entry.getValue();
114 if (cols != null && cols.size() > 0) {
115 for (byte[] col : cols) {
116 addColumn(fam, col);
118 } else {
119 addFamily(fam);
122 for (Map.Entry<String, byte[]> attr : get.getAttributesMap().entrySet()) {
123 setAttribute(attr.getKey(), attr.getValue());
125 for (Map.Entry<byte[], TimeRange> entry : get.getColumnFamilyTimeRange().entrySet()) {
126 TimeRange tr = entry.getValue();
127 setColumnFamilyTimeRange(entry.getKey(), tr.getMin(), tr.getMax());
129 super.setPriority(get.getPriority());
133 * Create a Get operation for the specified row.
134 * @param row
135 * @param rowOffset
136 * @param rowLength
138 public Get(byte[] row, int rowOffset, int rowLength) {
139 Mutation.checkRow(row, rowOffset, rowLength);
140 this.row = Bytes.copy(row, rowOffset, rowLength);
144 * Create a Get operation for the specified row.
145 * @param row
147 public Get(ByteBuffer row) {
148 Mutation.checkRow(row);
149 this.row = new byte[row.remaining()];
150 row.get(this.row);
153 public boolean isCheckExistenceOnly() {
154 return checkExistenceOnly;
157 public Get setCheckExistenceOnly(boolean checkExistenceOnly) {
158 this.checkExistenceOnly = checkExistenceOnly;
159 return this;
163 * Get all columns from the specified family.
164 * <p>
165 * Overrides previous calls to addColumn for this family.
166 * @param family family name
167 * @return the Get object
169 public Get addFamily(byte [] family) {
170 familyMap.remove(family);
171 familyMap.put(family, null);
172 return this;
176 * Get the column from the specific family with the specified qualifier.
177 * <p>
178 * Overrides previous calls to addFamily for this family.
179 * @param family family name
180 * @param qualifier column qualifier
181 * @return the Get objec
183 public Get addColumn(byte [] family, byte [] qualifier) {
184 NavigableSet<byte []> set = familyMap.get(family);
185 if(set == null) {
186 set = new TreeSet<>(Bytes.BYTES_COMPARATOR);
187 familyMap.put(family, set);
189 if (qualifier == null) {
190 qualifier = HConstants.EMPTY_BYTE_ARRAY;
192 set.add(qualifier);
193 return this;
197 * Get versions of columns only within the specified timestamp range,
198 * [minStamp, maxStamp).
199 * @param minStamp minimum timestamp value, inclusive
200 * @param maxStamp maximum timestamp value, exclusive
201 * @return this for invocation chaining
203 public Get setTimeRange(long minStamp, long maxStamp) throws IOException {
204 tr = TimeRange.between(minStamp, maxStamp);
205 return this;
209 * Get versions of columns with the specified timestamp.
210 * @param timestamp version timestamp
211 * @return this for invocation chaining
213 public Get setTimestamp(long timestamp) {
214 try {
215 tr = TimeRange.at(timestamp);
216 } catch(Exception e) {
217 // This should never happen, unless integer overflow or something extremely wrong...
218 LOG.error("TimeRange failed, likely caused by integer overflow. ", e);
219 throw e;
221 return this;
224 @Override
225 public Get setColumnFamilyTimeRange(byte[] cf, long minStamp, long maxStamp) {
226 return (Get) super.setColumnFamilyTimeRange(cf, minStamp, maxStamp);
230 * Get all available versions.
231 * @return this for invocation chaining
233 public Get readAllVersions() {
234 this.maxVersions = Integer.MAX_VALUE;
235 return this;
239 * Get up to the specified number of versions of each column.
240 * @param versions specified number of versions for each column
241 * @throws IOException if invalid number of versions
242 * @return this for invocation chaining
244 public Get readVersions(int versions) throws IOException {
245 if (versions <= 0) {
246 throw new IOException("versions must be positive");
248 this.maxVersions = versions;
249 return this;
252 @Override
253 public Get setLoadColumnFamiliesOnDemand(boolean value) {
254 return (Get) super.setLoadColumnFamiliesOnDemand(value);
258 * Set the maximum number of values to return per row per Column Family
259 * @param limit the maximum number of values returned / row / CF
260 * @return this for invocation chaining
262 public Get setMaxResultsPerColumnFamily(int limit) {
263 this.storeLimit = limit;
264 return this;
268 * Set offset for the row per Column Family. This offset is only within a particular row/CF
269 * combination. It gets reset back to zero when we move to the next row or CF.
270 * @param offset is the number of kvs that will be skipped.
271 * @return this for invocation chaining
273 public Get setRowOffsetPerColumnFamily(int offset) {
274 this.storeOffset = offset;
275 return this;
278 @Override
279 public Get setFilter(Filter filter) {
280 super.setFilter(filter);
281 return this;
284 /* Accessors */
287 * Set whether blocks should be cached for this Get.
288 * <p>
289 * This is true by default. When true, default settings of the table and
290 * family are used (this will never override caching blocks if the block
291 * cache is disabled for that family or entirely).
293 * @param cacheBlocks if false, default settings are overridden and blocks
294 * will not be cached
296 public Get setCacheBlocks(boolean cacheBlocks) {
297 this.cacheBlocks = cacheBlocks;
298 return this;
302 * Get whether blocks should be cached for this Get.
303 * @return true if default caching should be used, false if blocks should not
304 * be cached
306 public boolean getCacheBlocks() {
307 return cacheBlocks;
311 * Method for retrieving the get's row
312 * @return row
314 @Override
315 public byte [] getRow() {
316 return this.row;
320 * Method for retrieving the get's maximum number of version
321 * @return the maximum number of version to fetch for this get
323 public int getMaxVersions() {
324 return this.maxVersions;
328 * Method for retrieving the get's maximum number of values
329 * to return per Column Family
330 * @return the maximum number of values to fetch per CF
332 public int getMaxResultsPerColumnFamily() {
333 return this.storeLimit;
337 * Method for retrieving the get's offset per row per column
338 * family (#kvs to be skipped)
339 * @return the row offset
341 public int getRowOffsetPerColumnFamily() {
342 return this.storeOffset;
346 * Method for retrieving the get's TimeRange
347 * @return timeRange
349 public TimeRange getTimeRange() {
350 return this.tr;
354 * Method for retrieving the keys in the familyMap
355 * @return keys in the current familyMap
357 public Set<byte[]> familySet() {
358 return this.familyMap.keySet();
362 * Method for retrieving the number of families to get from
363 * @return number of families
365 public int numFamilies() {
366 return this.familyMap.size();
370 * Method for checking if any families have been inserted into this Get
371 * @return true if familyMap is non empty false otherwise
373 public boolean hasFamilies() {
374 return !this.familyMap.isEmpty();
378 * Method for retrieving the get's familyMap
379 * @return familyMap
381 public Map<byte[],NavigableSet<byte[]>> getFamilyMap() {
382 return this.familyMap;
386 * Compile the table and column family (i.e. schema) information
387 * into a String. Useful for parsing and aggregation by debugging,
388 * logging, and administration tools.
389 * @return Map
391 @Override
392 public Map<String, Object> getFingerprint() {
393 Map<String, Object> map = new HashMap<>();
394 List<String> families = new ArrayList<>(this.familyMap.entrySet().size());
395 map.put("families", families);
396 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
397 this.familyMap.entrySet()) {
398 families.add(Bytes.toStringBinary(entry.getKey()));
400 return map;
404 * Compile the details beyond the scope of getFingerprint (row, columns,
405 * timestamps, etc.) into a Map along with the fingerprinted information.
406 * Useful for debugging, logging, and administration tools.
407 * @param maxCols a limit on the number of columns output prior to truncation
408 * @return Map
410 @Override
411 public Map<String, Object> toMap(int maxCols) {
412 // we start with the fingerprint map and build on top of it.
413 Map<String, Object> map = getFingerprint();
414 // replace the fingerprint's simple list of families with a
415 // map from column families to lists of qualifiers and kv details
416 Map<String, List<String>> columns = new HashMap<>();
417 map.put("families", columns);
418 // add scalar information first
419 map.put("row", Bytes.toStringBinary(this.row));
420 map.put("maxVersions", this.maxVersions);
421 map.put("cacheBlocks", this.cacheBlocks);
422 List<Long> timeRange = new ArrayList<>(2);
423 timeRange.add(this.tr.getMin());
424 timeRange.add(this.tr.getMax());
425 map.put("timeRange", timeRange);
426 int colCount = 0;
427 // iterate through affected families and add details
428 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
429 this.familyMap.entrySet()) {
430 List<String> familyList = new ArrayList<>();
431 columns.put(Bytes.toStringBinary(entry.getKey()), familyList);
432 if(entry.getValue() == null) {
433 colCount++;
434 --maxCols;
435 familyList.add("ALL");
436 } else {
437 colCount += entry.getValue().size();
438 if (maxCols <= 0) {
439 continue;
441 for (byte [] column : entry.getValue()) {
442 if (--maxCols <= 0) {
443 continue;
445 familyList.add(Bytes.toStringBinary(column));
449 map.put("totalColumns", colCount);
450 if (this.filter != null) {
451 map.put("filter", this.filter.toString());
453 // add the id if set
454 if (getId() != null) {
455 map.put("id", getId());
457 return map;
460 @Override
461 public int hashCode() {
462 // TODO: This is wrong. Can't have two gets the same just because on same row. But it
463 // matches how equals works currently and gets rid of the findbugs warning.
464 return Bytes.hashCode(this.getRow());
467 @Override
468 public boolean equals(Object obj) {
469 if (this == obj) {
470 return true;
472 if (obj == null || getClass() != obj.getClass()) {
473 return false;
475 Row other = (Row) obj;
476 // TODO: This is wrong. Can't have two gets the same just because on same row.
477 return Row.COMPARATOR.compare(this, other) == 0;
480 @Override
481 public Get setAttribute(String name, byte[] value) {
482 return (Get) super.setAttribute(name, value);
485 @Override
486 public Get setId(String id) {
487 return (Get) super.setId(id);
490 @Override
491 public Get setAuthorizations(Authorizations authorizations) {
492 return (Get) super.setAuthorizations(authorizations);
495 @Override
496 public Get setACL(Map<String, Permission> perms) {
497 return (Get) super.setACL(perms);
500 @Override
501 public Get setACL(String user, Permission perms) {
502 return (Get) super.setACL(user, perms);
505 @Override
506 public Get setConsistency(Consistency consistency) {
507 return (Get) super.setConsistency(consistency);
510 @Override
511 public Get setReplicaId(int Id) {
512 return (Get) super.setReplicaId(Id);
515 @Override
516 public Get setIsolationLevel(IsolationLevel level) {
517 return (Get) super.setIsolationLevel(level);
520 @Override
521 public Get setPriority(int priority) {
522 return (Get) super.setPriority(priority);