Package org.apache.hadoop.hbase.client

Source Code of org.apache.hadoop.hbase.client.HTable

/**
* Copyright 2008 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
import org.apache.hadoop.hbase.filter.RowFilterInterface;
import org.apache.hadoop.hbase.filter.StopRowFilter;
import org.apache.hadoop.hbase.filter.WhileMatchRowFilter;
import org.apache.hadoop.hbase.io.BatchUpdate;
import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Writables;
import org.apache.hadoop.io.Text;

/**
* Used to communicate with a single HBase table
*/
public class HTable {
  private final HConnection connection;
  private final byte [] tableName;
  private HBaseConfiguration configuration;

  /**
   * Creates an object to access a HBase table
   *
   * @param tableName name of the table
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public HTable(final Text tableName)
  throws IOException {
    this(new HBaseConfiguration(), tableName.getBytes());
  }

  /**
   * Creates an object to access a HBase table
   *
   * @param tableName name of the table
   * @throws IOException
   */
  public HTable(final String tableName)
  throws IOException {
    this(new HBaseConfiguration(), Bytes.toBytes(tableName));
  }

  /**
   * Creates an object to access a HBase table
   *
   * @param tableName name of the table
   * @throws IOException
   */
  public HTable(final byte [] tableName)
  throws IOException {
    this(new HBaseConfiguration(), tableName);
  }

  /**
   * Creates an object to access a HBase table
   *
   * @param conf configuration object
   * @param tableName name of the table
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public HTable(HBaseConfiguration conf, final Text tableName)
  throws IOException {
    this(conf, tableName.getBytes());
  }

  /**
   * Creates an object to access a HBase table
   *
   * @param conf configuration object
   * @param tableName name of the table
   * @throws IOException
   */
  public HTable(HBaseConfiguration conf, final String tableName)
  throws IOException {
    this(conf, Bytes.toBytes(tableName));
  }

  /**
   * Creates an object to access a HBase table
   *
   * @param conf configuration object
   * @param tableName name of the table
   * @throws IOException
   */
  public HTable(HBaseConfiguration conf, final byte [] tableName)
  throws IOException {
    this.connection = HConnectionManager.getConnection(conf);
    this.configuration = conf;
    this.tableName = tableName;
    this.connection.locateRegion(tableName, HConstants.EMPTY_START_ROW);
  }

  /**
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public static boolean isTableEnabled(Text tableName) throws IOException {
    return isTableEnabled(tableName.getBytes());
  }
  /**
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   */
  public static boolean isTableEnabled(String tableName) throws IOException {
    return isTableEnabled(Bytes.toBytes(tableName));
  }
  /**
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   */
  public static boolean isTableEnabled(byte[] tableName) throws IOException {
    return isTableEnabled(new HBaseConfiguration(), tableName);
  }
 
  /**
   * @param conf HBaseConfiguration object
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public static boolean isTableEnabled(HBaseConfiguration conf, Text tableName)
  throws IOException {
    return isTableEnabled(conf, tableName.getBytes());
  }
 
  /**
   * @param conf HBaseConfiguration object
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   */
  public static boolean isTableEnabled(HBaseConfiguration conf, String tableName)
  throws IOException {
    return isTableEnabled(conf, Bytes.toBytes(tableName));
  }

  /**
   * @param conf HBaseConfiguration object
   * @param tableName name of table to check
   * @return true if table is on-line
   * @throws IOException
   */
  public static boolean isTableEnabled(HBaseConfiguration conf, byte[] tableName)
  throws IOException {
    return HConnectionManager.getConnection(conf).isTableEnabled(tableName);
  }
 
  /**
   * Find region location hosting passed row using cached info
   * @param row Row to find.
   * @return Location of row.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public HRegionLocation getRegionLocation(final Text row)
  throws IOException {
    return connection.getRegionLocation(tableName, row.getBytes(), false);
  }

  /**
   * Find region location hosting passed row using cached info
   * @param row Row to find.
   * @return Location of row.
   * @throws IOException
   */
  public HRegionLocation getRegionLocation(final String row)
  throws IOException {
    return connection.getRegionLocation(tableName, Bytes.toBytes(row), false);
  }

  /**
   * Find region location hosting passed row using cached info
   * @param row Row to find.
   * @return Location of row.
   * @throws IOException
   */
  public HRegionLocation getRegionLocation(final byte [] row)
  throws IOException {
    return connection.getRegionLocation(tableName, row, false);
  }

  /** @return the table name */
  public byte [] getTableName() {
    return this.tableName;
  }

  /**
   * Used by unit tests and tools to do low-level manipulations.  Not for
   * general use.
   * @return An HConnection instance.
   */
  public HConnection getConnection() {
    return this.connection;
  }

  /**
   * @return table metadata
   * @throws IOException
   */
  @Deprecated
  public HTableDescriptor getMetadata() throws IOException {
    return getTableDescriptor();
  }

  /**
   * @return table metadata
   * @throws IOException
   */
  public HTableDescriptor getTableDescriptor() throws IOException {
    return new UnmodifyableHTableDescriptor(
      this.connection.getHTableDescriptor(this.tableName));
  }

  /**
   * Gets the starting row key for every region in the currently open table
   *
   * @return Array of region starting row keys
   * @throws IOException
   */
  @SuppressWarnings("null")
  public byte[][] getStartKeys() throws IOException {
    final List<byte[]> keyList = new ArrayList<byte[]>();

    MetaScannerVisitor visitor = new MetaScannerVisitor() {
      public boolean processRow(RowResult rowResult) throws IOException {
        HRegionInfo info = Writables.getHRegionInfo(
            rowResult.get(HConstants.COL_REGIONINFO));
        if (Bytes.equals(info.getTableDesc().getName(), getTableName())) {
          if (!(info.isOffline() || info.isSplit())) {
            keyList.add(info.getStartKey());
          }
        }
        return true;
      }

    };
    MetaScanner.metaScan(configuration, visitor, this.tableName);
    return keyList.toArray(new byte[keyList.size()][]);
  }

  /**
   * Get all the regions and their address for this table
   *
   * @return A map of HRegionInfo with it's server address
   * @throws IOException
   */
  public Map<HRegionInfo, HServerAddress> getRegionsInfo() throws IOException {
    final Map<HRegionInfo, HServerAddress> regionMap =
      new TreeMap<HRegionInfo, HServerAddress>();

    MetaScannerVisitor visitor = new MetaScannerVisitor() {
      public boolean processRow(RowResult rowResult) throws IOException {
        HRegionInfo info = Writables.getHRegionInfo(
            rowResult.get(HConstants.COL_REGIONINFO));
       
        if (!(Bytes.equals(info.getTableDesc().getName(), getTableName()))) {
          return false;
        }

        HServerAddress server = new HServerAddress();
        Cell c = rowResult.get(HConstants.COL_SERVER);
        if (c != null && c.getValue() != null && c.getValue().length > 0) {
          String address = Bytes.toString(c.getValue());
          server = new HServerAddress(address);
        }
       
        if (!(info.isOffline() || info.isSplit())) {
          regionMap.put(new UnmodifyableHRegionInfo(info), server);
        }
        return true;
      }

    };
    MetaScanner.metaScan(configuration, visitor, tableName);
    return regionMap;
  }
 
  /**
   * Get a single value for the specified row and column
   *
   * @param row row key
   * @param column column name
   * @return value for specified row/column
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Cell get(final Text row, final Text column)
  throws IOException {
    return get(row.getBytes(), column.getBytes());
  }

  /**
   * Get a single value for the specified row and column
   *
   * @param row row key
   * @param column column name
   * @param numVersions - number of versions to retrieve
   * @return value for specified row/column
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Cell[] get(final Text row, final Text column, int numVersions)
  throws IOException {
    return get(row.getBytes(), column.getBytes(), numVersions);
  }

  /**
   * Get a single value for the specified row and column
   *
   * @param row row key
   * @param column column name
   * @return value for specified row/column
   * @throws IOException
   */
  public Cell get(final String row, final String column)
  throws IOException {
    return get(Bytes.toBytes(row), Bytes.toBytes(column));
  }

  /**
   * Get a single value for the specified row and column
   *
   * @param row row key
   * @param column column name
   * @param numVersions - number of versions to retrieve
   * @return value for specified row/column
   * @throws IOException
   */
  public Cell[] get(final String row, final String column, int numVersions)
  throws IOException {
    return get(Bytes.toBytes(row), Bytes.toBytes(column), numVersions);
  }

  /**
   * Get a single value for the specified row and column
   *
   * @param row row key
   * @param column column name
   * @return value for specified row/column
   * @throws IOException
   */
  public Cell get(final byte [] row, final byte [] column)
  throws IOException {
    return connection.getRegionServerWithRetries(
        new ServerCallable<Cell>(connection, tableName, row) {
          public Cell call() throws IOException {
            return server.get(location.getRegionInfo().getRegionName(), row,
                column);
          }
        }
    );
  }

  /**
   * Get the specified number of versions of the specified row and column
   * @param row row key
   * @param column column name
   * @param numVersions number of versions to retrieve
   * @return Array of Cells.
   * @throws IOException
   */
  public Cell[] get(final byte [] row, final byte [] column,
    final int numVersions)
  throws IOException {
    return connection.getRegionServerWithRetries(
        new ServerCallable<Cell[]>(connection, tableName, row) {
          public Cell[] call() throws IOException {
            return server.get(location.getRegionInfo().getRegionName(), row,
                column, numVersions);
          }
        }
    );
  }

  /**
   * Get the specified number of versions of the specified row and column with
   * the specified timestamp.
   *
   * @param row         - row key
   * @param column      - column name
   * @param timestamp   - timestamp
   * @param numVersions - number of versions to retrieve
   * @return            - array of values that match the above criteria
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Cell[] get(final Text row, final Text column,
    final long timestamp, final int numVersions)
  throws IOException {
    return get(row.getBytes(), column.getBytes(), timestamp, numVersions);
  }

  /**
   * Get the specified number of versions of the specified row and column with
   * the specified timestamp.
   *
   * @param row         - row key
   * @param column      - column name
   * @param timestamp   - timestamp
   * @param numVersions - number of versions to retrieve
   * @return            - array of values that match the above criteria
   * @throws IOException
   */
  public Cell[] get(final String row, final String column,
    final long timestamp, final int numVersions)
  throws IOException {
    return get(Bytes.toBytes(row), Bytes.toBytes(column), timestamp, numVersions);
  }

  /**
   * Get the specified number of versions of the specified row and column with
   * the specified timestamp.
   *
   * @param row         - row key
   * @param column      - column name
   * @param timestamp   - timestamp
   * @param numVersions - number of versions to retrieve
   * @return            - array of values that match the above criteria
   * @throws IOException
   */
  public Cell[] get(final byte [] row, final byte [] column,
    final long timestamp, final int numVersions)
  throws IOException {
    Cell[] values = null;
    values = connection.getRegionServerWithRetries(
        new ServerCallable<Cell[]>(connection, tableName, row) {
          public Cell[] call() throws IOException {
            return server.get(location.getRegionInfo().getRegionName(), row,
                column, timestamp, numVersions);
          }
        }
    );

    if (values != null) {
      ArrayList<Cell> cellValues = new ArrayList<Cell>();
      for (int i = 0 ; i < values.length; i++) {
        cellValues.add(values[i]);
      }
      return cellValues.toArray(new Cell[values.length]);
    }
    return null;
  }

  /**
   * Get all the data for the specified row at the latest timestamp
   *
   * @param row row key
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public RowResult getRow(final Text row) throws IOException {
    return getRow(row.getBytes());
  }

  /**
   * Get all the data for the specified row at the latest timestamp
   *
   * @param row row key
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final String row) throws IOException {
    return getRow(Bytes.toBytes(row));
  }

  /**
   * Get all the data for the specified row at the latest timestamp
   *
   * @param row row key
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final byte [] row) throws IOException {
    return getRow(row, HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Get all the data for the specified row at a specified timestamp
   *
   * @param row row key
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public RowResult getRow(final Text row, final long ts)
  throws IOException {
    return getRow(row.getBytes(), ts);
  }

  /**
   * Get all the data for the specified row at a specified timestamp
   *
   * @param row row key
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final String row, final long ts)
  throws IOException {
    return getRow(Bytes.toBytes(row), ts);
  }

  /**
   * Get all the data for the specified row at a specified timestamp
   *
   * @param row row key
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final byte [] row, final long ts)
  throws IOException {
    return connection.getRegionServerWithRetries(
        new ServerCallable<RowResult>(connection, tableName, row) {
          public RowResult call() throws IOException {
            return server.getRow(location.getRegionInfo().getRegionName(), row,
                ts);
          }
        }
    );
  }

  /**
   * Get selected columns for the specified row at the latest timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public RowResult getRow(final Text row, final Text[] columns)
  throws IOException {
    return getRow(row.getBytes(), Bytes.toByteArrays(columns));
  }

  /**
   * Get selected columns for the specified row at the latest timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final String row, final String [] columns)
  throws IOException {
    return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns));
  }

  /**
   * Get selected columns for the specified row at the latest timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final byte [] row, final byte [][] columns)
  throws IOException {
    return getRow(row, columns, HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Get selected columns for the specified row at a specified timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public RowResult getRow(final Text row, final Text [] columns,
    final long ts)
  throws IOException
    return getRow(row.getBytes(), Bytes.toByteArrays(columns), ts);
  }

  /**
   * Get selected columns for the specified row at a specified timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final String row, final String [] columns,
    final long ts)
  throws IOException
    return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns), ts);
  }

  /**
   * Get selected columns for the specified row at a specified timestamp
   *
   * @param row row key
   * @param columns Array of column names and families you want to retrieve.
   * @param ts timestamp
   * @return RowResult is empty if row does not exist.
   * @throws IOException
   */
  public RowResult getRow(final byte [] row, final byte [][] columns,
    final long ts)
  throws IOException {      
    return connection.getRegionServerWithRetries(
        new ServerCallable<RowResult>(connection, tableName, row) {
          public RowResult call() throws IOException {
            return server.getRow(location.getRegionInfo().getRegionName(), row,
                columns, ts);
          }
        }
    );
  }

  /**
   * Get a scanner on the current table starting at first row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @return scanner
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Scanner getScanner(final Text [] columns)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW);
  }

  /**
   * Get a scanner on the current table starting at first row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final String [] columns)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW);
  }

  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @return scanner
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Scanner getScanner(final Text [] columns, final Text startRow)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), startRow.getBytes());
  }

  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final String [] columns, final String startRow)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow));
  }

  /**
   * Get a scanner on the current table starting at first row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte[][] columns)
  throws IOException {
    return getScanner(columns, HConstants.EMPTY_START_ROW,
      HConstants.LATEST_TIMESTAMP, null);
  }

  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte[][] columns, final byte [] startRow)
  throws IOException {
    return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, null);
  }
 
  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param timestamp only return results whose timestamp <= this value
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte[][] columns, final byte [] startRow,
    long timestamp)
  throws IOException {
    return getScanner(columns, startRow, timestamp, null);
  }
 
  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param filter a row filter using row-key regexp and/or column data filter.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte[][] columns, final byte [] startRow,
    RowFilterInterface filter)
  throws IOException {
    return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, filter);
  }
 
  /**
   * Get a scanner on the current table starting at the specified row and
   * ending just before <code>stopRow<code>.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param stopRow Row to stop scanning on. Once we hit this row we stop
   * returning values; i.e. we return the row before this one but not the
   * <code>stopRow</code> itself.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte [][] columns,
    final byte [] startRow, final byte [] stopRow)
  throws IOException {
    return getScanner(columns, startRow, stopRow,
      HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Get a scanner on the current table starting at the specified row and
   * ending just before <code>stopRow<code>.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param stopRow Row to stop scanning on. Once we hit this row we stop
   * returning values; i.e. we return the row before this one but not the
   * <code>stopRow</code> itself.
   * @param timestamp only return results whose timestamp <= this value
   * @return scanner
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Scanner getScanner(final Text[] columns,
    final Text startRow, final Text stopRow, final long timestamp)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(),
      stopRow.getBytes(), timestamp);
  }

  /**
   * Get a scanner on the current table starting at the specified row and
   * ending just before <code>stopRow<code>.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param stopRow Row to stop scanning on. Once we hit this row we stop
   * returning values; i.e. we return the row before this one but not the
   * <code>stopRow</code> itself.
   * @param timestamp only return results whose timestamp <= this value
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final String [] columns,
    final String startRow, final String stopRow, final long timestamp)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow),
      Bytes.toBytes(stopRow), timestamp);
  }

  /**
   * Get a scanner on the current table starting at the specified row and
   * ending just before <code>stopRow<code>.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param stopRow Row to stop scanning on. Once we hit this row we stop
   * returning values; i.e. we return the row before this one but not the
   * <code>stopRow</code> itself.
   * @param timestamp only return results whose timestamp <= this value
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte [][] columns,
    final byte [] startRow, final byte [] stopRow, final long timestamp)
  throws IOException {
    return getScanner(columns, startRow, timestamp,
      new WhileMatchRowFilter(new StopRowFilter(stopRow)));
 
 
  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param timestamp only return results whose timestamp <= this value
   * @param filter a row filter using row-key regexp and/or column data filter.
   * @return scanner
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public Scanner getScanner(Text[] columns,
    Text startRow, long timestamp, RowFilterInterface filter)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(),
      timestamp, filter);
  }

  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param timestamp only return results whose timestamp <= this value
   * @param filter a row filter using row-key regexp and/or column data filter.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(String[] columns,
    String startRow, long timestamp, RowFilterInterface filter)
  throws IOException {
    return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow),
      timestamp, filter);
  }

  /**
   * Get a scanner on the current table starting at the specified row.
   * Return the specified columns.
   *
   * @param columns columns to scan. If column name is a column family, all
   * columns of the specified column family are returned.  Its also possible
   * to pass a regex in the column qualifier. A column qualifier is judged to
   * be a regex if it contains at least one of the following characters:
   * <code>\+|^&*$[]]}{)(</code>.
   * @param startRow starting row in table to scan
   * @param timestamp only return results whose timestamp <= this value
   * @param filter a row filter using row-key regexp and/or column data filter.
   * @return scanner
   * @throws IOException
   */
  public Scanner getScanner(final byte [][] columns,
    final byte [] startRow, long timestamp, RowFilterInterface filter)
  throws IOException {
    return new ClientScanner(columns, startRow, timestamp, filter);
  }
 
  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @throws IOException
   */
  public void deleteAll(final byte [] row) throws IOException {
    deleteAll(row, null);
  }
 
  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public void deleteAll(final Text row) throws IOException {
    deleteAll(row, null);
  }
 
  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @throws IOException
   */
  public void deleteAll(final String row) throws IOException {
    deleteAll(row, null);
  }
 
  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @param column column to be deleted
   * @throws IOException
   */
  public void deleteAll(final byte [] row, final byte [] column)
  throws IOException {
    deleteAll(row, column, HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   */
  public void deleteAll(final byte [] row, final long ts)
  throws IOException {
    deleteAll(row, null, ts);
  }

  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   */
  public void deleteAll(final String row, final long ts)
  throws IOException {
    deleteAll(row, null, ts);
  }

  /**
   * Completely delete the row's cells.
   *
   * @param row Key of the row you want to completely delete.
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public void deleteAll(final Text row, final long ts)
  throws IOException {
    deleteAll(row, null, ts);
  }

  /**
   * Delete all cells that match the passed row and column.
   * @param row Row to update
   * @param column name of column whose value is to be deleted
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public void deleteAll(final Text row, final Text column) throws IOException {
    deleteAll(row, column, HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Delete all cells that match the passed row and column.
   * @param row Row to update
   * @param column name of column whose value is to be deleted
   * @throws IOException
   */
  public void deleteAll(final String row, final String column)
  throws IOException {
    deleteAll(row, column, HConstants.LATEST_TIMESTAMP);
  }

  /**
   * Delete all cells that match the passed row and column and whose
   * timestamp is equal-to or older than the passed timestamp.
   * @param row Row to update
   * @param column name of column whose value is to be deleted
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */
  public void deleteAll(final Text row, final Text column, final long ts)
  throws IOException {
    deleteAll(row.getBytes(), column.getBytes(), ts);
  }
 
  /**
   * Delete all cells that match the passed row and column and whose
   * timestamp is equal-to or older than the passed timestamp.
   * @param row Row to update
   * @param column name of column whose value is to be deleted
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   */
  public void deleteAll(final String row, final String column, final long ts)
  throws IOException {
    deleteAll(Bytes.toBytes(row),
      column != null? Bytes.toBytes(column): null, ts);
  }

  /**
   * Delete all cells that match the passed row and column and whose
   * timestamp is equal-to or older than the passed timestamp.
   * @param row Row to update
   * @param column name of column whose value is to be deleted
   * @param ts Delete all cells of the same timestamp or older.
   * @throws IOException
   */
  public void deleteAll(final byte [] row, final byte [] column, final long ts)
  throws IOException {
    connection.getRegionServerWithRetries(
        new ServerCallable<Boolean>(connection, tableName, row) {
          public Boolean call() throws IOException {
            if (column != null) {
              this.server.deleteAll(location.getRegionInfo().getRegionName(),
                row, column, ts);
            } else {
              this.server.deleteAll(location.getRegionInfo().getRegionName(),
                  row, ts);
            }
            return null;
          }
        }
    );
  }

  /**
   * Delete all cells for a row with matching column family at all timestamps.
   *
   * @param row The row to operate on
   * @param family The column family to match
   * @param timestamp Timestamp to match
   * @throws IOException
   * @deprecated Use String or byte [] overload instead
   */ 
  public void deleteFamily(final Text row, final Text family,
      final long timestamp)
  throws IOException{
    deleteFamily(row.getBytes(), family.getBytes(), timestamp);
  }

  /**
   * Delete all cells for a row with matching column family at all timestamps.
   *
   * @param row The row to operate on
   * @param family The column family to match
   * @param timestamp Timestamp to match
   * @throws IOException
   */ 
  public void deleteFamily(final String row, final String family,
      final long timestamp)
  throws IOException{
    deleteFamily(Bytes.toBytes(row), Bytes.toBytes(family), timestamp);
  }

  /**
   * Delete all cells for a row with matching column family with timestamps
   * less than or equal to <i>timestamp</i>.
   *
   * @param row The row to operate on
   * @param family The column family to match
   * @param timestamp Timestamp to match
   * @throws IOException
   */
  public void deleteFamily(final byte [] row, final byte [] family,
    final long timestamp)
  throws IOException {
    connection.getRegionServerWithRetries(
        new ServerCallable<Boolean>(connection, tableName, row) {
          public Boolean call() throws IOException {
            server.deleteFamily(location.getRegionInfo().getRegionName(), row,
                family, timestamp);
            return null;
          }
        }
    );
  }

  /**
   * Commit a BatchUpdate to the table.
   * @param batchUpdate
   * @throws IOException
   */
  public synchronized void commit(final BatchUpdate batchUpdate)
  throws IOException {
    connection.getRegionServerWithRetries(
      new ServerCallable<Boolean>(connection, tableName, batchUpdate.getRow()) {
        public Boolean call() throws IOException {
          server.batchUpdate(location.getRegionInfo().getRegionName(),
            batchUpdate);
          return null;
        }
      }
    )
  }
 
  /**
   * Commit a RowsBatchUpdate to the table.
   * @param batchUpdates
   * @throws IOException
   */
  public synchronized void commit(final List<BatchUpdate> batchUpdates)
  throws IOException {
    for (BatchUpdate batchUpdate : batchUpdates)
      commit(batchUpdate);
  }

  /**
   * Implements the scanner interface for the HBase client.
   * If there are multiple regions in a table, this scanner will iterate
   * through them all.
   */
  protected class ClientScanner implements Scanner {
    private final Log CLIENT_LOG = LogFactory.getLog(this.getClass());
    private byte[][] columns;
    private byte [] startRow;
    protected long scanTime;
    @SuppressWarnings("hiding")
    private boolean closed = false;
    private HRegionInfo currentRegion = null;
    private ScannerCallable callable = null;
    protected RowFilterInterface filter;
   
    protected ClientScanner(final Text [] columns, final Text startRow,
        long timestamp, RowFilterInterface filter)
    throws IOException {
      this(Bytes.toByteArrays(columns), startRow.getBytes(), timestamp,
        filter);
    }

    protected ClientScanner(final byte[][] columns, final byte [] startRow,
        final long timestamp, final RowFilterInterface filter)
    throws IOException {
      if (CLIENT_LOG.isDebugEnabled()) {
        CLIENT_LOG.debug("Creating scanner over " + Bytes.toString(getTableName()) +
          " starting at key '" + Bytes.toString(startRow) + "'");
      }
      // save off the simple parameters
      this.columns = columns;
      this.startRow = startRow;
      this.scanTime = timestamp;
     
      // save the filter, and make sure that the filter applies to the data
      // we're expecting to pull back
      this.filter = filter;
      if (filter != null) {
        filter.validate(columns);
      }
      nextScanner();
    }
   
    protected byte[][] getColumns() {
      return columns;
    }
   
    protected long getTimestamp() {
      return scanTime;
    }
   
    protected RowFilterInterface getFilter() {
      return filter;
    }
       
    /*
     * Gets a scanner for the next region.
     * Returns false if there are no more scanners.
     */
    private boolean nextScanner() throws IOException {
      // Close the previous scanner if it's open
      if (this.callable != null) {
        this.callable.setClose();
        getConnection().getRegionServerWithRetries(callable);
        this.callable = null;
      }

      // if we're at the end of the table, then close and return false
      // to stop iterating
      if (currentRegion != null) {
        if (CLIENT_LOG.isDebugEnabled()) {
          CLIENT_LOG.debug("Advancing forward from region " + currentRegion);
        }

        byte [] endKey = currentRegion.getEndKey();
        if (endKey == null ||
            Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) ||
            filterSaysStop(endKey)) {
          close();
          return false;
        }
      }
     
      HRegionInfo oldRegion = this.currentRegion;
      byte [] localStartKey = oldRegion == null? startRow: oldRegion.getEndKey();

      if (CLIENT_LOG.isDebugEnabled()) {
        CLIENT_LOG.debug("Advancing internal scanner to startKey at '" +
          Bytes.toString(localStartKey) + "'");
      }
           
      try {
        callable = getScannerCallable(localStartKey);
        // open a scanner on the region server starting at the
        // beginning of the region
        getConnection().getRegionServerWithRetries(callable);
        currentRegion = callable.getHRegionInfo();
      } catch (IOException e) {
        close();
        throw e;
      }
      return true;
    }
   
    protected ScannerCallable getScannerCallable(byte [] localStartKey) {
      return new ScannerCallable(getConnection(), getTableName(), columns,
          localStartKey, scanTime, filter);
    }

    /**
     * @param endKey
     * @return Returns true if the passed region endkey is judged beyond
     * filter.
     */
    private boolean filterSaysStop(final byte [] endKey) {
      if (this.filter == null) {
        return false;
      }
      // Let the filter see current row.
      this.filter.filterRowKey(endKey);
      return this.filter.filterAllRemaining();
    }

    /** {@inheritDoc} */
    public RowResult next() throws IOException {
      if (this.closed) {
        return null;
      }
      RowResult values = null;
      do {
        values = getConnection().getRegionServerWithRetries(callable);
      } while ((values == null || values.size() == 0) && nextScanner());

      if (values != null && values.size() != 0) {
        return values;
      }
      return null;
    }

    /**
     * {@inheritDoc}
     */
    public void close() {
      if (callable != null) {
        callable.setClose();
        try {
          getConnection().getRegionServerWithRetries(callable);
        } catch (IOException e) {
          // We used to catch this error, interpret, and rethrow. However, we
          // have since decided that it's not nice for a scanner's close to
          // throw exceptions. Chances are it was just an UnknownScanner
          // exception due to lease time out.
        }
        callable = null;
      }
      closed = true;
    }

    /** {@inheritDoc} */
    public Iterator<RowResult> iterator() {
      return new Iterator<RowResult>() {
        // The next RowResult, possibly pre-read
        RowResult next = null;
       
        // return true if there is another item pending, false if there isn't.
        // this method is where the actual advancing takes place, but you need
        // to call next() to consume it. hasNext() will only advance if there
        // isn't a pending next().
        public boolean hasNext() {
          if (next == null) {
            try {
              next = ClientScanner.this.next();
              return next != null;
            } catch (IOException e) {
              throw new RuntimeException(e);
            }           
          }
          return true;
        }

        // get the pending next item and advance the iterator. returns null if
        // there is no next item.
        public RowResult next() {
          // since hasNext() does the real advancing, we call this to determine
          // if there is a next before proceeding.
          if (!hasNext()) {
            return null;
          }
         
          // if we get to here, then hasNext() has given us an item to return.
          // we want to return the item and then null out the next pointer, so
          // we use a temporary variable.
          RowResult temp = next;
          next = null;
          return temp;
        }

        public void remove() {
          throw new UnsupportedOperationException();
        }
      };
    }
  }
}
TOP

Related Classes of org.apache.hadoop.hbase.client.HTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.