Return-Path: Delivered-To: apmail-hadoop-hbase-commits-archive@locus.apache.org Received: (qmail 63960 invoked from network); 22 May 2008 20:49:57 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 22 May 2008 20:49:57 -0000 Received: (qmail 35811 invoked by uid 500); 22 May 2008 20:49:58 -0000 Delivered-To: apmail-hadoop-hbase-commits-archive@hadoop.apache.org Received: (qmail 35791 invoked by uid 500); 22 May 2008 20:49:58 -0000 Mailing-List: contact hbase-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: hbase-dev@hadoop.apache.org Delivered-To: mailing list hbase-commits@hadoop.apache.org Received: (qmail 35782 invoked by uid 99); 22 May 2008 20:49:58 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 22 May 2008 13:49:58 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 22 May 2008 20:49:08 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id A3D382388A0B; Thu, 22 May 2008 13:49:29 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r659249 [1/3] - in /hadoop/hbase/trunk: ./ src/java/org/apache/hadoop/hbase/client/ src/java/org/apache/hadoop/hbase/filter/ src/java/org/apache/hadoop/hbase/mapred/ src/java/org/apache/hadoop/hbase/regionserver/ src/test/org/apache/hadoop/... Date: Thu, 22 May 2008 20:49:27 -0000 To: hbase-commits@hadoop.apache.org From: stack@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080522204929.A3D382388A0B@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: stack Date: Thu May 22 13:49:25 2008 New Revision: 659249 URL: http://svn.apache.org/viewvc?rev=659249&view=rev Log: HBASE-638 Purge \r from src Modified: hadoop/hbase/trunk/CHANGES.txt hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/HTable.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/InclusiveStopRowFilter.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/PageRowFilter.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/RegExpRowFilter.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/RowFilterInterface.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/RowFilterSet.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/StopRowFilter.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/WhileMatchRowFilter.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HStoreScanner.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestInclusiveStopRowFilter.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestPageRowFilter.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestRegExpRowFilter.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestRowFilterSet.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestStopRowFilter.java hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/filter/TestWhileMatchRowFilter.java Modified: hadoop/hbase/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/CHANGES.txt?rev=659249&r1=659248&r2=659249&view=diff ============================================================================== --- hadoop/hbase/trunk/CHANGES.txt (original) +++ hadoop/hbase/trunk/CHANGES.txt Thu May 22 13:49:25 2008 @@ -19,6 +19,7 @@ HBASE-630 Default hbase.rootdir is garbage HBASE-589 Remove references to deprecated methods in Hadoop once hadoop-0.17.0 is released + HBASE-638 Purge \r from src IMPROVEMENTS HBASE-559 MR example job to count table rows Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/HTable.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/HTable.java?rev=659249&r1=659248&r2=659249&view=diff ============================================================================== --- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/HTable.java (original) +++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/HTable.java Thu May 22 13:49:25 2008 @@ -1,979 +1,979 @@ -/** - * 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.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; - -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.io.Text; - -/** - * Used to communicate with a single HBase table - */ -public class HTable implements HConstants { - protected final Log LOG = LogFactory.getLog(this.getClass()); - - protected final HConnection connection; - protected final byte [] tableName; - protected final long pause; - protected final int numRetries; - protected Random rand; - protected HBaseConfiguration configuration; - - protected volatile boolean tableDoesNotExist; - - // For row mutation operations - - /** - * 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 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.pause = conf.getLong("hbase.client.pause", 10 * 1000); - this.numRetries = conf.getInt("hbase.client.retries.number", 5); - this.rand = new Random(); - this.connection.locateRegion(tableName, EMPTY_START_ROW); - } - - /** - * 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 connection */ - public HConnection getConnection() { - return connection; - } - - /** @return the table name */ - public byte [] getTableName() { - return this.tableName; - } - - /** - * @return table metadata - * @throws IOException - */ - public HTableDescriptor getMetadata() throws IOException { - HTableDescriptor [] metas = this.connection.listTables(); - HTableDescriptor result = null; - for (int i = 0; i < metas.length; i++) { - if (Bytes.equals(metas[i].getName(), this.tableName)) { - result = metas[i]; - break; - } - } - return result; - } - - /** - * 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 keyList = new ArrayList(); - - MetaScannerVisitor visitor = new MetaScannerVisitor() { - public boolean processRow(RowResult rowResult, - HRegionLocation metaLocation, HRegionInfo info) - throws IOException { - if (!(Bytes.equals(info.getTableDesc().getName(), tableName))) { - return false; - } - 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 - */ - @SuppressWarnings("null") - public Map getRegionsInfo() throws IOException { - final HashMap regionMap = - new HashMap(); - - MetaScannerVisitor visitor = new MetaScannerVisitor() { - public boolean processRow(RowResult rowResult, - HRegionLocation metaLocation, HRegionInfo info) - throws IOException { - if (!(Bytes.equals(info.getTableDesc().getName(), tableName))) { - return false; - } - if (!(info.isOffline() || info.isSplit())) { - regionMap.put(info, metaLocation.getServerAddress()); - } - 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 - */ - 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 - */ - 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 byte [] row, final byte [] column) - throws IOException { - return connection.getRegionServerWithRetries( - new ServerCallable(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 byte values - * @throws IOException - */ - public Cell[] get(final byte [] row, final byte [] column, - final int numVersions) - throws IOException { - Cell[] values = null; - values = connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Cell[] call() throws IOException { - return server.get(location.getRegionInfo().getRegionName(), row, - column, numVersions); - } - } - ); - - if (values != null) { - ArrayList cellValues = new ArrayList(); - for (int i = 0 ; i < values.length; i++) { - cellValues.add(values[i]); - } - return cellValues.toArray(new Cell[values.length]); - } - return null; - } - - /** - * 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 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 byte [] row, final byte [] column, - final long timestamp, final int numVersions) - throws IOException { - Cell[] values = null; - values = connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Cell[] call() throws IOException { - return server.get(location.getRegionInfo().getRegionName(), row, - column, timestamp, numVersions); - } - } - ); - - if (values != null) { - ArrayList cellValues = new ArrayList(); - 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 - */ - 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 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 - */ - 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 byte [] row, final long ts) - throws IOException { - return connection.getRegionServerWithRetries( - new ServerCallable(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 you want to retrieve. - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - 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 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 you want to retrieve. - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - 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 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(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: - * \+|^&*$[]]}{)(. - * @return scanner - * @throws IOException - */ - 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 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: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @return scanner - * @throws IOException - */ - 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 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: - * \+|^&*$[]]}{)(. - * @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: - * \+|^&*$[]]}{)(. - * @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: - * \+|^&*$[]]}{)(. - * @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: - * \+|^&*$[]]}{)(. - * @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 stopRow. - * 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: - * \+|^&*$[]]}{)(. - * @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 - * stopRow 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 stopRow. - * 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: - * \+|^&*$[]]}{)(. - * @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 - * stopRow itself. - * @param timestamp only return results whose timestamp <= this value - * @return scanner - * @throws IOException - */ - 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 stopRow. - * 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: - * \+|^&*$[]]}{)(. - * @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 - * stopRow 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: - * \+|^&*$[]]}{)(. - * @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(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: - * \+|^&*$[]]}{)(. - * @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 - */ - 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); - } - - /** - * 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 Text row, final Text column) throws IOException { - deleteAll(row, column, 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 - */ - 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 byte [] row, final byte [] column, final long ts) - throws IOException { - connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Boolean call() throws IOException { - server.deleteAll(location.getRegionInfo().getRegionName(), row, - column, 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 - * @throws IOException - */ - public void deleteFamily(final Text row, final Text family) throws IOException{ - deleteFamily(row.getBytes(), family.getBytes(), - HConstants.LATEST_TIMESTAMP); - } - - /** - * Delete all cells for a row with matching column family with timestamps - * less than or equal to timestamp. - * - * @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(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(connection, tableName, batchUpdate.getRow()) { - public Boolean call() throws IOException { - server.batchUpdate(location.getRegionInfo().getRegionName(), - batchUpdate); - return null; - } - } - ); - } - - /** - * Implements the scanner interface for the HBase client. - * If there are multiple regions in a table, this scanner will iterate - * through them all. - */ - private class ClientScanner implements Scanner { - 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 (LOG.isDebugEnabled()) { - LOG.debug("Creating scanner over " + Bytes.toString(tableName) + - " 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(); - } - - /* - * 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(); - connection.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 (LOG.isDebugEnabled()) { - LOG.debug("Advancing forward from region " + currentRegion); - } - - byte [] endKey = currentRegion.getEndKey(); - if (endKey == null || Bytes.equals(endKey, EMPTY_BYTE_ARRAY)) { - close(); - return false; - } - } - - HRegionInfo oldRegion = this.currentRegion; - byte [] localStartKey = oldRegion == null? startRow: oldRegion.getEndKey(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Advancing internal scanner to startKey at " + - Bytes.toString(localStartKey)); - } - - try { - callable = new ScannerCallable(connection, tableName, columns, - localStartKey, scanTime, filter); - // open a scanner on the region server starting at the - // beginning of the region - connection.getRegionServerWithRetries(callable); - currentRegion = callable.getHRegionInfo(); - } catch (IOException e) { - close(); - throw e; - } - return true; - } - - /** {@inheritDoc} */ - public RowResult next() throws IOException { - if (this.closed) { - return null; - } - - RowResult values = null; - do { - values = connection.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 { - connection.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 iterator() { - return new Iterator() { - // 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(); - } - }; - } - } -} +/** + * 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.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; + +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.io.Text; + +/** + * Used to communicate with a single HBase table + */ +public class HTable implements HConstants { + protected final Log LOG = LogFactory.getLog(this.getClass()); + + protected final HConnection connection; + protected final byte [] tableName; + protected final long pause; + protected final int numRetries; + protected Random rand; + protected HBaseConfiguration configuration; + + protected volatile boolean tableDoesNotExist; + + // For row mutation operations + + /** + * 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 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.pause = conf.getLong("hbase.client.pause", 10 * 1000); + this.numRetries = conf.getInt("hbase.client.retries.number", 5); + this.rand = new Random(); + this.connection.locateRegion(tableName, EMPTY_START_ROW); + } + + /** + * 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 connection */ + public HConnection getConnection() { + return connection; + } + + /** @return the table name */ + public byte [] getTableName() { + return this.tableName; + } + + /** + * @return table metadata + * @throws IOException + */ + public HTableDescriptor getMetadata() throws IOException { + HTableDescriptor [] metas = this.connection.listTables(); + HTableDescriptor result = null; + for (int i = 0; i < metas.length; i++) { + if (Bytes.equals(metas[i].getName(), this.tableName)) { + result = metas[i]; + break; + } + } + return result; + } + + /** + * 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 keyList = new ArrayList(); + + MetaScannerVisitor visitor = new MetaScannerVisitor() { + public boolean processRow(RowResult rowResult, + HRegionLocation metaLocation, HRegionInfo info) + throws IOException { + if (!(Bytes.equals(info.getTableDesc().getName(), tableName))) { + return false; + } + 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 + */ + @SuppressWarnings("null") + public Map getRegionsInfo() throws IOException { + final HashMap regionMap = + new HashMap(); + + MetaScannerVisitor visitor = new MetaScannerVisitor() { + public boolean processRow(RowResult rowResult, + HRegionLocation metaLocation, HRegionInfo info) + throws IOException { + if (!(Bytes.equals(info.getTableDesc().getName(), tableName))) { + return false; + } + if (!(info.isOffline() || info.isSplit())) { + regionMap.put(info, metaLocation.getServerAddress()); + } + 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 + */ + 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 + */ + 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 byte [] row, final byte [] column) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(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 byte values + * @throws IOException + */ + public Cell[] get(final byte [] row, final byte [] column, + final int numVersions) + throws IOException { + Cell[] values = null; + values = connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Cell[] call() throws IOException { + return server.get(location.getRegionInfo().getRegionName(), row, + column, numVersions); + } + } + ); + + if (values != null) { + ArrayList cellValues = new ArrayList(); + for (int i = 0 ; i < values.length; i++) { + cellValues.add(values[i]); + } + return cellValues.toArray(new Cell[values.length]); + } + return null; + } + + /** + * 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 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 byte [] row, final byte [] column, + final long timestamp, final int numVersions) + throws IOException { + Cell[] values = null; + values = connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Cell[] call() throws IOException { + return server.get(location.getRegionInfo().getRegionName(), row, + column, timestamp, numVersions); + } + } + ); + + if (values != null) { + ArrayList cellValues = new ArrayList(); + 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 + */ + 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 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 + */ + 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 byte [] row, final long ts) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(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 you want to retrieve. + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + 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 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 you want to retrieve. + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + 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 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(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: + * \+|^&*$[]]}{)(. + * @return scanner + * @throws IOException + */ + 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 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: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @return scanner + * @throws IOException + */ + 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 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: + * \+|^&*$[]]}{)(. + * @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: + * \+|^&*$[]]}{)(. + * @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: + * \+|^&*$[]]}{)(. + * @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: + * \+|^&*$[]]}{)(. + * @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 stopRow. + * 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: + * \+|^&*$[]]}{)(. + * @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 + * stopRow 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 stopRow. + * 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: + * \+|^&*$[]]}{)(. + * @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 + * stopRow itself. + * @param timestamp only return results whose timestamp <= this value + * @return scanner + * @throws IOException + */ + 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 stopRow. + * 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: + * \+|^&*$[]]}{)(. + * @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 + * stopRow 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: + * \+|^&*$[]]}{)(. + * @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(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: + * \+|^&*$[]]}{)(. + * @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 + */ + 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); + } + + /** + * 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 Text row, final Text column) throws IOException { + deleteAll(row, column, 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 + */ + 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 byte [] row, final byte [] column, final long ts) + throws IOException { + connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Boolean call() throws IOException { + server.deleteAll(location.getRegionInfo().getRegionName(), row, + column, 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 + * @throws IOException + */ + public void deleteFamily(final Text row, final Text family) throws IOException{ + deleteFamily(row.getBytes(), family.getBytes(), + HConstants.LATEST_TIMESTAMP); + } + + /** + * Delete all cells for a row with matching column family with timestamps + * less than or equal to timestamp. + * + * @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(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(connection, tableName, batchUpdate.getRow()) { + public Boolean call() throws IOException { + server.batchUpdate(location.getRegionInfo().getRegionName(), + batchUpdate); + return null; + } + } + ); + } + + /** + * Implements the scanner interface for the HBase client. + * If there are multiple regions in a table, this scanner will iterate + * through them all. + */ + private class ClientScanner implements Scanner { + 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 (LOG.isDebugEnabled()) { + LOG.debug("Creating scanner over " + Bytes.toString(tableName) + + " 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(); + } + + /* + * 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(); + connection.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 (LOG.isDebugEnabled()) { + LOG.debug("Advancing forward from region " + currentRegion); + } + + byte [] endKey = currentRegion.getEndKey(); + if (endKey == null || Bytes.equals(endKey, EMPTY_BYTE_ARRAY)) { + close(); + return false; + } + } + + HRegionInfo oldRegion = this.currentRegion; + byte [] localStartKey = oldRegion == null? startRow: oldRegion.getEndKey(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Advancing internal scanner to startKey at " + + Bytes.toString(localStartKey)); + } + + try { + callable = new ScannerCallable(connection, tableName, columns, + localStartKey, scanTime, filter); + // open a scanner on the region server starting at the + // beginning of the region + connection.getRegionServerWithRetries(callable); + currentRegion = callable.getHRegionInfo(); + } catch (IOException e) { + close(); + throw e; + } + return true; + } + + /** {@inheritDoc} */ + public RowResult next() throws IOException { + if (this.closed) { + return null; + } + + RowResult values = null; + do { + values = connection.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 { + connection.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 iterator() { + return new Iterator() { + // 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(); + } + }; + } + } +} Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/InclusiveStopRowFilter.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/InclusiveStopRowFilter.java?rev=659249&r1=659248&r2=659249&view=diff ============================================================================== --- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/InclusiveStopRowFilter.java (original) +++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/InclusiveStopRowFilter.java Thu May 22 13:49:25 2008 @@ -1,55 +1,55 @@ -/** - * Copyright 2007 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.filter; - -import org.apache.hadoop.hbase.util.Bytes; - -/** - * Subclass of StopRowFilter that filters rows > the stop row, - * making it include up to the last row but no further. - */ -public class InclusiveStopRowFilter extends StopRowFilter{ - /** - * Default constructor, filters nothing. Required though for RPC - * deserialization. - */ - public InclusiveStopRowFilter() {super();} - - /** - * Constructor that takes a stopRowKey on which to filter - * - * @param stopRowKey rowKey to filter on. - */ - public InclusiveStopRowFilter(final byte [] stopRowKey) { - super(stopRowKey); - } - - /** {@inheritDoc} */ - @Override - public boolean filterRowKey(final byte [] rowKey) { - if (rowKey == null) { - if (getStopRowKey() == null) { - return true; - } - return false; - } - return Bytes.compareTo(getStopRowKey(), rowKey) < 0; - } -} +/** + * Copyright 2007 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.filter; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * Subclass of StopRowFilter that filters rows > the stop row, + * making it include up to the last row but no further. + */ +public class InclusiveStopRowFilter extends StopRowFilter{ + /** + * Default constructor, filters nothing. Required though for RPC + * deserialization. + */ + public InclusiveStopRowFilter() {super();} + + /** + * Constructor that takes a stopRowKey on which to filter + * + * @param stopRowKey rowKey to filter on. + */ + public InclusiveStopRowFilter(final byte [] stopRowKey) { + super(stopRowKey); + } + + /** {@inheritDoc} */ + @Override + public boolean filterRowKey(final byte [] rowKey) { + if (rowKey == null) { + if (getStopRowKey() == null) { + return true; + } + return false; + } + return Bytes.compareTo(getStopRowKey(), rowKey) < 0; + } +} Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/PageRowFilter.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/PageRowFilter.java?rev=659249&r1=659248&r2=659249&view=diff ============================================================================== --- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/PageRowFilter.java (original) +++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/filter/PageRowFilter.java Thu May 22 13:49:25 2008 @@ -1,145 +1,145 @@ -/** - * Copyright 2007 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.filter; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.SortedMap; - - -/** - * Implementation of RowFilterInterface that limits results to a specific page - * size. It terminates scanning once the number of filter-passed results is >= - * the given page size. - * - *

- * Note that this filter cannot guarantee that the number of results returned - * to a client are <= page size. This is because the filter is applied - * separately on different region servers. It does however optimize the scan of - * individual HRegions by making sure that the page size is never exceeded - * locally. - *

- */ -public class PageRowFilter implements RowFilterInterface { - - private long pageSize = Long.MAX_VALUE; - private int rowsAccepted = 0; - - /** - * Default constructor, filters nothing. Required though for RPC - * deserialization. - */ - public PageRowFilter() { - super(); - } - - /** - * Constructor that takes a maximum page size. - * - * @param pageSize Maximum result size. - */ - public PageRowFilter(final long pageSize) { - this.pageSize = pageSize; - } - - /** - * - * {@inheritDoc} - */ - public void validate(@SuppressWarnings("unused") final byte [][] columns) { - // Doesn't filter columns - } - - /** - * - * {@inheritDoc} - */ - public void reset() { - rowsAccepted = 0; - } - - /** {@inheritDoc} */ - public void rowProcessed(boolean filtered, - @SuppressWarnings("unused") byte [] rowKey) { - if (!filtered) { - this.rowsAccepted++; - } - } - - /** - * - * {@inheritDoc} - */ - public boolean processAlways() { - return false; - } - - /** - * - * {@inheritDoc} - */ - public boolean filterAllRemaining() { - return this.rowsAccepted > this.pageSize; - } - - /** - * - * {@inheritDoc} - */ - public boolean filterRowKey(@SuppressWarnings("unused") final byte [] r) { - return filterAllRemaining(); - } - - /** - * - * {@inheritDoc} - */ - public boolean filterColumn(@SuppressWarnings("unused") final byte [] rowKey, - @SuppressWarnings("unused") final byte [] colKey, - @SuppressWarnings("unused") final byte[] data) { - return filterAllRemaining(); - } - - /** - * - * {@inheritDoc} - */ - public boolean filterRow(@SuppressWarnings("unused") - final SortedMap columns) { - return filterAllRemaining(); - } - - /** - * - * {@inheritDoc} - */ - public void readFields(final DataInput in) throws IOException { - this.pageSize = in.readLong(); - } - - /** - * - * {@inheritDoc} - */ - public void write(final DataOutput out) throws IOException { - out.writeLong(pageSize); - } +/** + * Copyright 2007 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.filter; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.SortedMap; + + +/** + * Implementation of RowFilterInterface that limits results to a specific page + * size. It terminates scanning once the number of filter-passed results is >= + * the given page size. + * + *

+ * Note that this filter cannot guarantee that the number of results returned + * to a client are <= page size. This is because the filter is applied + * separately on different region servers. It does however optimize the scan of + * individual HRegions by making sure that the page size is never exceeded + * locally. + *

+ */ +public class PageRowFilter implements RowFilterInterface { + + private long pageSize = Long.MAX_VALUE; + private int rowsAccepted = 0; + + /** + * Default constructor, filters nothing. Required though for RPC + * deserialization. + */ + public PageRowFilter() { + super(); + } + + /** + * Constructor that takes a maximum page size. + * + * @param pageSize Maximum result size. + */ + public PageRowFilter(final long pageSize) { + this.pageSize = pageSize; + } + + /** + * + * {@inheritDoc} + */ + public void validate(@SuppressWarnings("unused") final byte [][] columns) { + // Doesn't filter columns + } + + /** + * + * {@inheritDoc} + */ + public void reset() { + rowsAccepted = 0; + } + + /** {@inheritDoc} */ + public void rowProcessed(boolean filtered, + @SuppressWarnings("unused") byte [] rowKey) { + if (!filtered) { + this.rowsAccepted++; + } + } + + /** + * + * {@inheritDoc} + */ + public boolean processAlways() { + return false; + } + + /** + * + * {@inheritDoc} + */ + public boolean filterAllRemaining() { + return this.rowsAccepted > this.pageSize; + } + + /** + * + * {@inheritDoc} + */ + public boolean filterRowKey(@SuppressWarnings("unused") final byte [] r) { + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public boolean filterColumn(@SuppressWarnings("unused") final byte [] rowKey, + @SuppressWarnings("unused") final byte [] colKey, + @SuppressWarnings("unused") final byte[] data) { + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public boolean filterRow(@SuppressWarnings("unused") + final SortedMap columns) { + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public void readFields(final DataInput in) throws IOException { + this.pageSize = in.readLong(); + } + + /** + * + * {@inheritDoc} + */ + public void write(final DataOutput out) throws IOException { + out.writeLong(pageSize); + } } \ No newline at end of file