001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import java.io.IOException;
021import java.nio.ByteBuffer;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.NavigableSet;
027import java.util.Set;
028import java.util.TreeMap;
029import java.util.TreeSet;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.filter.Filter;
032import org.apache.hadoop.hbase.io.TimeRange;
033import org.apache.hadoop.hbase.security.access.Permission;
034import org.apache.hadoop.hbase.security.visibility.Authorizations;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.apache.yetus.audience.InterfaceAudience;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040/**
041 * Used to perform Get operations on a single row.
042 * <p>
043 * To get everything for a row, instantiate a Get object with the row to get. To further narrow the
044 * scope of what to Get, use the methods below.
045 * <p>
046 * To get all columns from specific families, execute {@link #addFamily(byte[]) addFamily} for each
047 * family to retrieve.
048 * <p>
049 * To get specific columns, execute {@link #addColumn(byte[], byte[]) addColumn} for each column to
050 * retrieve.
051 * <p>
052 * To only retrieve columns within a specific range of version timestamps, execute
053 * {@link #setTimeRange(long, long) setTimeRange}.
054 * <p>
055 * To only retrieve columns with a specific timestamp, execute {@link #setTimestamp(long)
056 * setTimestamp}.
057 * <p>
058 * To limit the number of versions of each column to be returned, execute
059 * {@link #setMaxVersions(int) setMaxVersions}.
060 * <p>
061 * To add a filter, call {@link #setFilter(Filter) setFilter}.
062 */
063@InterfaceAudience.Public
064public class Get extends Query implements Row {
065  private static final Logger LOG = LoggerFactory.getLogger(Get.class);
066
067  private byte[] row = null;
068  private int maxVersions = 1;
069  private boolean cacheBlocks = true;
070  private int storeLimit = -1;
071  private int storeOffset = 0;
072  private TimeRange tr = TimeRange.allTime();
073  private boolean checkExistenceOnly = false;
074  private boolean closestRowBefore = false;
075  private Map<byte[], NavigableSet<byte[]>> familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
076
077  /**
078   * Create a Get operation for the specified row.
079   * <p>
080   * If no further operations are done, this will get the latest version of all columns in all
081   * families of the specified row.
082   * @param row row key
083   */
084  public Get(byte[] row) {
085    Mutation.checkRow(row);
086    this.row = row;
087  }
088
089  /**
090   * Copy-constructor
091   */
092  public Get(Get get) {
093    this(get.getRow());
094    // from Query
095    this.setFilter(get.getFilter());
096    this.setReplicaId(get.getReplicaId());
097    this.setConsistency(get.getConsistency());
098    // from Get
099    this.cacheBlocks = get.getCacheBlocks();
100    this.maxVersions = get.getMaxVersions();
101    this.storeLimit = get.getMaxResultsPerColumnFamily();
102    this.storeOffset = get.getRowOffsetPerColumnFamily();
103    this.tr = get.getTimeRange();
104    this.checkExistenceOnly = get.isCheckExistenceOnly();
105    this.loadColumnFamiliesOnDemand = get.getLoadColumnFamiliesOnDemandValue();
106    Map<byte[], NavigableSet<byte[]>> fams = get.getFamilyMap();
107    for (Map.Entry<byte[], NavigableSet<byte[]>> entry : fams.entrySet()) {
108      byte[] fam = entry.getKey();
109      NavigableSet<byte[]> cols = entry.getValue();
110      if (cols != null && cols.size() > 0) {
111        for (byte[] col : cols) {
112          addColumn(fam, col);
113        }
114      } else {
115        addFamily(fam);
116      }
117    }
118    for (Map.Entry<String, byte[]> attr : get.getAttributesMap().entrySet()) {
119      setAttribute(attr.getKey(), attr.getValue());
120    }
121    for (Map.Entry<byte[], TimeRange> entry : get.getColumnFamilyTimeRange().entrySet()) {
122      TimeRange tr = entry.getValue();
123      setColumnFamilyTimeRange(entry.getKey(), tr.getMin(), tr.getMax());
124    }
125    super.setPriority(get.getPriority());
126  }
127
128  /**
129   * Create a Get operation for the specified row.
130   */
131  public Get(byte[] row, int rowOffset, int rowLength) {
132    Mutation.checkRow(row, rowOffset, rowLength);
133    this.row = Bytes.copy(row, rowOffset, rowLength);
134  }
135
136  /**
137   * Create a Get operation for the specified row.
138   */
139  public Get(ByteBuffer row) {
140    Mutation.checkRow(row);
141    this.row = new byte[row.remaining()];
142    row.get(this.row);
143  }
144
145  public boolean isCheckExistenceOnly() {
146    return checkExistenceOnly;
147  }
148
149  public Get setCheckExistenceOnly(boolean checkExistenceOnly) {
150    this.checkExistenceOnly = checkExistenceOnly;
151    return this;
152  }
153
154  /**
155   * This will always return the default value which is false as client cannot set the value to this
156   * property any more.
157   * @deprecated since 2.0.0 and will be removed in 3.0.0
158   */
159  @Deprecated
160  public boolean isClosestRowBefore() {
161    return closestRowBefore;
162  }
163
164  /**
165   * This is not used any more and does nothing. Use reverse scan instead.
166   * @deprecated since 2.0.0 and will be removed in 3.0.0
167   */
168  @Deprecated
169  public Get setClosestRowBefore(boolean closestRowBefore) {
170    // do Nothing
171    return this;
172  }
173
174  /**
175   * Get all columns from the specified family.
176   * <p>
177   * Overrides previous calls to addColumn for this family.
178   * @param family family name
179   * @return the Get object
180   */
181  public Get addFamily(byte[] family) {
182    familyMap.remove(family);
183    familyMap.put(family, null);
184    return this;
185  }
186
187  /**
188   * Get the column from the specific family with the specified qualifier.
189   * <p>
190   * Overrides previous calls to addFamily for this family.
191   * @param family    family name
192   * @param qualifier column qualifier
193   * @return the Get objec
194   */
195  public Get addColumn(byte[] family, byte[] qualifier) {
196    NavigableSet<byte[]> set = familyMap.get(family);
197    if (set == null) {
198      set = new TreeSet<>(Bytes.BYTES_COMPARATOR);
199      familyMap.put(family, set);
200    }
201    if (qualifier == null) {
202      qualifier = HConstants.EMPTY_BYTE_ARRAY;
203    }
204    set.add(qualifier);
205    return this;
206  }
207
208  /**
209   * Get versions of columns only within the specified timestamp range, [minStamp, maxStamp).
210   * @param minStamp minimum timestamp value, inclusive
211   * @param maxStamp maximum timestamp value, exclusive
212   * @return this for invocation chaining
213   */
214  public Get setTimeRange(long minStamp, long maxStamp) throws IOException {
215    tr = new TimeRange(minStamp, maxStamp);
216    return this;
217  }
218
219  /**
220   * Get versions of columns with the specified timestamp.
221   * @param timestamp version timestamp
222   * @return this for invocation chaining
223   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use
224   *             {@link #setTimestamp(long)} instead
225   */
226  @Deprecated
227  public Get setTimeStamp(long timestamp) throws IOException {
228    return this.setTimestamp(timestamp);
229  }
230
231  /**
232   * Get versions of columns with the specified timestamp.
233   * @param timestamp version timestamp
234   * @return this for invocation chaining
235   */
236  public Get setTimestamp(long timestamp) {
237    try {
238      tr = new TimeRange(timestamp, timestamp + 1);
239    } catch (Exception e) {
240      // This should never happen, unless integer overflow or something extremely wrong...
241      LOG.error("TimeRange failed, likely caused by integer overflow. ", e);
242      throw e;
243    }
244
245    return this;
246  }
247
248  @Override
249  public Get setColumnFamilyTimeRange(byte[] cf, long minStamp, long maxStamp) {
250    return (Get) super.setColumnFamilyTimeRange(cf, minStamp, maxStamp);
251  }
252
253  /**
254   * Get all available versions.
255   * @return this for invocation chaining
256   * @deprecated It is easy to misunderstand with column family's max versions, so use
257   *             {@link #readAllVersions()} instead.
258   */
259  @Deprecated
260  public Get setMaxVersions() {
261    return readAllVersions();
262  }
263
264  /**
265   * Get up to the specified number of versions of each column.
266   * @param maxVersions maximum versions for each column
267   * @throws IOException if invalid number of versions
268   * @return this for invocation chaining
269   * @deprecated It is easy to misunderstand with column family's max versions, so use
270   *             {@link #readVersions(int)} instead.
271   */
272  @Deprecated
273  public Get setMaxVersions(int maxVersions) throws IOException {
274    return readVersions(maxVersions);
275  }
276
277  /**
278   * Get all available versions.
279   * @return this for invocation chaining
280   */
281  public Get readAllVersions() {
282    this.maxVersions = Integer.MAX_VALUE;
283    return this;
284  }
285
286  /**
287   * Get up to the specified number of versions of each column.
288   * @param versions specified number of versions for each column
289   * @throws IOException if invalid number of versions
290   * @return this for invocation chaining
291   */
292  public Get readVersions(int versions) throws IOException {
293    if (versions <= 0) {
294      throw new IOException("versions must be positive");
295    }
296    this.maxVersions = versions;
297    return this;
298  }
299
300  @Override
301  public Get setLoadColumnFamiliesOnDemand(boolean value) {
302    return (Get) super.setLoadColumnFamiliesOnDemand(value);
303  }
304
305  /**
306   * Set the maximum number of values to return per row per Column Family
307   * @param limit the maximum number of values returned / row / CF
308   * @return this for invocation chaining
309   */
310  public Get setMaxResultsPerColumnFamily(int limit) {
311    this.storeLimit = limit;
312    return this;
313  }
314
315  /**
316   * Set offset for the row per Column Family. This offset is only within a particular row/CF
317   * combination. It gets reset back to zero when we move to the next row or CF.
318   * @param offset is the number of kvs that will be skipped.
319   * @return this for invocation chaining
320   */
321  public Get setRowOffsetPerColumnFamily(int offset) {
322    this.storeOffset = offset;
323    return this;
324  }
325
326  @Override
327  public Get setFilter(Filter filter) {
328    super.setFilter(filter);
329    return this;
330  }
331
332  /* Accessors */
333
334  /**
335   * Set whether blocks should be cached for this Get.
336   * <p>
337   * This is true by default. When true, default settings of the table and family are used (this
338   * will never override caching blocks if the block cache is disabled for that family or entirely).
339   * @param cacheBlocks if false, default settings are overridden and blocks will not be cached
340   */
341  public Get setCacheBlocks(boolean cacheBlocks) {
342    this.cacheBlocks = cacheBlocks;
343    return this;
344  }
345
346  /**
347   * Get whether blocks should be cached for this Get.
348   * @return true if default caching should be used, false if blocks should not be cached
349   */
350  public boolean getCacheBlocks() {
351    return cacheBlocks;
352  }
353
354  /**
355   * Method for retrieving the get's row
356   */
357  @Override
358  public byte[] getRow() {
359    return this.row;
360  }
361
362  /**
363   * Method for retrieving the get's maximum number of version
364   * @return the maximum number of version to fetch for this get
365   */
366  public int getMaxVersions() {
367    return this.maxVersions;
368  }
369
370  /**
371   * Method for retrieving the get's maximum number of values to return per Column Family
372   * @return the maximum number of values to fetch per CF
373   */
374  public int getMaxResultsPerColumnFamily() {
375    return this.storeLimit;
376  }
377
378  /**
379   * Method for retrieving the get's offset per row per column family (#kvs to be skipped)
380   * @return the row offset
381   */
382  public int getRowOffsetPerColumnFamily() {
383    return this.storeOffset;
384  }
385
386  /**
387   * Method for retrieving the get's TimeRange
388   */
389  public TimeRange getTimeRange() {
390    return this.tr;
391  }
392
393  /**
394   * Method for retrieving the keys in the familyMap
395   * @return keys in the current familyMap
396   */
397  public Set<byte[]> familySet() {
398    return this.familyMap.keySet();
399  }
400
401  /**
402   * Method for retrieving the number of families to get from
403   * @return number of families
404   */
405  public int numFamilies() {
406    return this.familyMap.size();
407  }
408
409  /**
410   * Method for checking if any families have been inserted into this Get
411   * @return true if familyMap is non empty false otherwise
412   */
413  public boolean hasFamilies() {
414    return !this.familyMap.isEmpty();
415  }
416
417  /**
418   * Method for retrieving the get's familyMap
419   */
420  public Map<byte[], NavigableSet<byte[]>> getFamilyMap() {
421    return this.familyMap;
422  }
423
424  /**
425   * Compile the table and column family (i.e. schema) information into a String. Useful for parsing
426   * and aggregation by debugging, logging, and administration tools.
427   */
428  @Override
429  public Map<String, Object> getFingerprint() {
430    Map<String, Object> map = new HashMap<>();
431    List<String> families = new ArrayList<>(this.familyMap.entrySet().size());
432    map.put("families", families);
433    for (Map.Entry<byte[], NavigableSet<byte[]>> entry : this.familyMap.entrySet()) {
434      families.add(Bytes.toStringBinary(entry.getKey()));
435    }
436    return map;
437  }
438
439  /**
440   * Compile the details beyond the scope of getFingerprint (row, columns, timestamps, etc.) into a
441   * Map along with the fingerprinted information. Useful for debugging, logging, and administration
442   * tools.
443   * @param maxCols a limit on the number of columns output prior to truncation
444   */
445  @Override
446  public Map<String, Object> toMap(int maxCols) {
447    // we start with the fingerprint map and build on top of it.
448    Map<String, Object> map = getFingerprint();
449    // replace the fingerprint's simple list of families with a
450    // map from column families to lists of qualifiers and kv details
451    Map<String, List<String>> columns = new HashMap<>();
452    map.put("families", columns);
453    // add scalar information first
454    map.put("row", Bytes.toStringBinary(this.row));
455    map.put("maxVersions", this.maxVersions);
456    map.put("cacheBlocks", this.cacheBlocks);
457    List<Long> timeRange = new ArrayList<>(2);
458    timeRange.add(this.tr.getMin());
459    timeRange.add(this.tr.getMax());
460    map.put("timeRange", timeRange);
461    int colCount = 0;
462    // iterate through affected families and add details
463    for (Map.Entry<byte[], NavigableSet<byte[]>> entry : this.familyMap.entrySet()) {
464      List<String> familyList = new ArrayList<>();
465      columns.put(Bytes.toStringBinary(entry.getKey()), familyList);
466      if (entry.getValue() == null) {
467        colCount++;
468        --maxCols;
469        familyList.add("ALL");
470      } else {
471        colCount += entry.getValue().size();
472        if (maxCols <= 0) {
473          continue;
474        }
475        for (byte[] column : entry.getValue()) {
476          if (--maxCols <= 0) {
477            continue;
478          }
479          familyList.add(Bytes.toStringBinary(column));
480        }
481      }
482    }
483    map.put("totalColumns", colCount);
484    if (this.filter != null) {
485      map.put("filter", this.filter.toString());
486    }
487    // add the id if set
488    if (getId() != null) {
489      map.put("id", getId());
490    }
491    return map;
492  }
493
494  // Row
495  @Override
496  public int compareTo(Row other) {
497    // TODO: This is wrong. Can't have two gets the same just because on same row.
498    return Bytes.compareTo(this.getRow(), other.getRow());
499  }
500
501  @Override
502  public int hashCode() {
503    // TODO: This is wrong. Can't have two gets the same just because on same row. But it
504    // matches how equals works currently and gets rid of the findbugs warning.
505    return Bytes.hashCode(this.getRow());
506  }
507
508  @Override
509  public boolean equals(Object obj) {
510    if (this == obj) {
511      return true;
512    }
513    if (obj == null || getClass() != obj.getClass()) {
514      return false;
515    }
516    Row other = (Row) obj;
517    // TODO: This is wrong. Can't have two gets the same just because on same row.
518    return compareTo(other) == 0;
519  }
520
521  @Override
522  public Get setAttribute(String name, byte[] value) {
523    return (Get) super.setAttribute(name, value);
524  }
525
526  @Override
527  public Get setId(String id) {
528    return (Get) super.setId(id);
529  }
530
531  @Override
532  public Get setAuthorizations(Authorizations authorizations) {
533    return (Get) super.setAuthorizations(authorizations);
534  }
535
536  @Override
537  public Get setACL(Map<String, Permission> perms) {
538    return (Get) super.setACL(perms);
539  }
540
541  @Override
542  public Get setACL(String user, Permission perms) {
543    return (Get) super.setACL(user, perms);
544  }
545
546  @Override
547  public Get setConsistency(Consistency consistency) {
548    return (Get) super.setConsistency(consistency);
549  }
550
551  @Override
552  public Get setReplicaId(int Id) {
553    return (Get) super.setReplicaId(Id);
554  }
555
556  @Override
557  public Get setIsolationLevel(IsolationLevel level) {
558    return (Get) super.setIsolationLevel(level);
559  }
560
561  @Override
562  public Get setPriority(int priority) {
563    return (Get) super.setPriority(priority);
564  }
565}