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