Index: src/main/java/org/apache/hadoop/hbase/client/coprocessor/AggregationClient.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/client/coprocessor/AggregationClient.java (revision 0)
+++ src/main/java/org/apache/hadoop/hbase/client/coprocessor/AggregationClient.java (revision 0)
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2010 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.coprocessor;
+
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.coprocessor.AggregateCpProtocol;
+import org.apache.hadoop.hbase.coprocessor.AggregateProtocolImpl;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.LongWritable;
+
+/**
+ *
+ * This client class is for invoking the agg functions deployed on the RS side
+ * via the cp impls. This class will implement the supporting functionality for
+ * summing/processing the individual results obtained from the cp impl for each
+ * region server.
+ *
+ * This will serve as the client side handle for invoking the agg funcitons,
+ * like AggrationClient#sum(table, start, end, colFamily, colQualifier);
+ *
+ *
+ * For all aggregate functions,
+ * - start row < end row is an essential condition (if they are not
+ * {@link HConstants#EMPTY_BYTE_ARRAY})
+ *
- Column family can't be null.
+ *
- For all mathematical computations like avg, std etc, a long cell value (8
+ * bytes) is assumed; otherwise that value is skipped.
+ *
+ */
+public class AggregationClient {
+
+ private static final Log log = LogFactory.getLog(AggregationClient.class);
+
+ /**
+ * It gives the maximum value of a column for a given column family for the
+ * given range. In case qualifier is null, a max of all values for the given
+ * family is returned.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @return the maximum value as a long.
+ * @throws Throwable
+ * The caller is supposed to handle the exception as they are thrown
+ * & propagated to it.
+ */
+ public long getMaximum(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ HTable table = new HTable(tableName);
+ class MaxCallBack implements Batch.Callback {
+ long maximum = Long.MIN_VALUE;
+
+ @Override
+ public void update(byte[] region, byte[] row, Long result) {
+ if (maximum < result)
+ maximum = result;
+ }
+
+ long getMax() {
+ return maximum;
+ }
+ }
+
+ MaxCallBack aMaxCallBack = new MaxCallBack();
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call() {
+ @Override
+ public Long call(AggregateCpProtocol instance) throws IOException {
+ return instance.getMax(colFamily, colQualifier, startKey, endKey);
+ }
+ }, aMaxCallBack);
+ return aMaxCallBack.getMax();
+ }
+
+ private void validateStartEndRows(final byte[] startKey, final byte[] endKey)
+ throws IOException {
+ if ((Bytes.equals(startKey, endKey) && (!Bytes.equals(startKey,
+ HConstants.EMPTY_START_ROW)))
+ || Bytes.compareTo(startKey, endKey) > 0) {
+ throw new IOException(
+ "Agg client Exception: Startrow can't be equal or greater than Stoprow");
+ }
+ }
+
+ /**
+ * It gives the minimum value of a column for a given column family for the
+ * given range. In case qualifier is null, a min of all values for the given
+ * family is returned.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @return
+ * @throws Throwable
+ */
+ public Long getMinimum(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ class MinCallBack implements Batch.Callback {
+
+ private Long minimum = Long.MAX_VALUE;
+
+ @Override
+ public void update(byte[] region, byte[] row, Long result) {
+ if (minimum > result)
+ minimum = result;
+ }
+
+ public Long getMinimum() {
+ return minimum;
+ }
+ }
+ HTable table = new HTable(tableName);
+ MinCallBack minCallBack = new MinCallBack();
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call() {
+
+ @Override
+ public Long call(AggregateCpProtocol instance) throws IOException {
+ return instance.getMin(colFamily, colQualifier, startKey, endKey);
+ }
+ }, minCallBack);
+ log.debug("Min fom all regions is: " + minCallBack.getMinimum());
+ return minCallBack.getMinimum();
+ }
+
+ /**
+ * It gives the row num, by summing up the individual results obtained from
+ * regions. In case the qualifier is null, FirstKEyValueFilter is used to
+ * optimised the operation. In case qualifier is provided, I can't use the
+ * filter as it may set the flag to skip to next row, but the value read is
+ * not of the given filter: in this case, this particular row will not be
+ * counted ==> an error.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @return
+ * @throws Throwable
+ */
+ public long getRowNum(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ class RowNumCallback implements Batch.Callback {
+ private Long rowNumCount = 0l;
+
+ @Override
+ public void update(byte[] region, byte[] row, Long result) {
+ rowNumCount += result;
+ }
+
+ public Long getRowNumCount() {
+ return rowNumCount;
+ }
+ }
+ RowNumCallback rowNum = new RowNumCallback();
+ HTable table = new HTable(tableName);
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call() {
+ @Override
+ public Long call(AggregateCpProtocol instance) throws IOException {
+ return instance
+ .getRowNum(colFamily, colQualifier, startKey, endKey);
+ }
+ }, rowNum);
+
+ return rowNum.getRowNumCount();
+ }
+
+ /**
+ * It sums up the value returned from various regions. In case qualifier is
+ * null, summation of all the column qualifiers in the given family is done.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @return
+ * @throws Throwable
+ */
+ public long getSum(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ class SumCallBack implements Batch.Callback {
+ Long sumResult = 0l;
+
+ @Override
+ public void update(byte[] region, byte[] row, Long result) {
+ sumResult += result;
+ }
+
+ public Long getSumResult() {
+ return sumResult;
+ }
+ }
+ SumCallBack sumCallBack = new SumCallBack();
+ HTable table = new HTable(tableName);
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call() {
+ @Override
+ public Long call(AggregateCpProtocol instance) throws IOException {
+ return instance.getSum(colFamily, colQualifier, startKey, endKey);
+ }
+ }, sumCallBack);
+ return sumCallBack.getSumResult();
+ }
+
+ /**
+ * It computes average while fetching sum and row count from all the
+ * corresponding regions. Approach is to compute a global sum of region level
+ * sum and rowcount and then compute the average.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @throws Throwable
+ */
+ public double getAvg(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ class AvgCallBack implements Batch.Callback
> {
+ long sum = 0l;
+ long rsCount = 0;
+
+ @Override
+ public void update(byte[] region, byte[] row, List result) {
+ sum += result.get(0);
+ rsCount += result.get(1);
+ }
+
+ public double getAvg() {
+ double avg = (rsCount != 0) ? (double) sum / rsCount : 0;
+ return avg;
+ }
+ }
+ AvgCallBack avgCallBack = new AvgCallBack();
+ HTable table = new HTable(tableName);
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call>() {
+ @Override
+ public List call(AggregateCpProtocol instance)
+ throws IOException {
+ return instance.getAvg(colFamily, colQualifier, startKey, endKey);
+ }
+ }, avgCallBack);
+ log.debug("Avg of all the region values is: " + avgCallBack.getAvg());
+ return avgCallBack.getAvg();
+ }
+
+ /**
+ * It computes a global standard deviation for a given column and its value.
+ * Standard deviation is square root of (average of squares -
+ * average*average). From individual regions, it obtains sum, square sum and
+ * number of rows. With these, the above values are computed to get the global
+ * std.
+ *
+ * @param tableName
+ * @param startKey
+ * @param endKey
+ * @param colFamily
+ * @param colQualifier
+ * @return TODO: number formatting
+ * @throws Throwable
+ */
+ public double getStd(final byte[] tableName, final byte[] startKey,
+ final byte[] endKey, final byte[] colFamily, final byte[] colQualifier)
+ throws Throwable {
+ validateStartEndRows(startKey, endKey);
+ class StdCallback implements Batch.Callback> {
+ long rowNum = 0l, sum = 0l, sumSq = 0l;
+
+ @Override
+ public void update(byte[] region, byte[] row, List result) {
+ // log.debug("values are: "+result);
+ sum += result.get(0);
+ sumSq += result.get(1);
+ rowNum += result.get(2);
+ }
+
+ public double getStd() {
+ double res = 0d;
+ double avg = (rowNum != 0) ? (double) sum / rowNum : 0;
+ double avgOfSumSq = (rowNum != 0) ? (double) sumSq / rowNum : 0;
+ res = avgOfSumSq - (avg) * (avg); // variance
+ res = Math.pow(res, 0.5);
+ return res;
+ }
+ }
+ StdCallback stdCallback = new StdCallback();
+ HTable table = new HTable(tableName);
+ table.coprocessorExec(AggregateCpProtocol.class, startKey, endKey,
+ new Batch.Call>() {
+ @Override
+ public List call(AggregateCpProtocol instance)
+ throws IOException {
+ return instance.getStd(colFamily, colQualifier, startKey, endKey);
+ }
+
+ }, stdCallback);
+ return stdCallback.getStd();
+ }
+}
Index: src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateCpProtocol.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateCpProtocol.java (revision 0)
+++ src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateCpProtocol.java (revision 0)
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2010 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.coprocessor;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.client.coprocessor.AggregationClient;
+import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;
+
+/**
+ * It defines the aggregation functions that are to be supported in this
+ * Coprocessor. For each method, it take column family, column qualifier, start
+ * row and an end row [startRow, endRow) Refer to {@link AggregationClient} for
+ * some general conditions on input parameters
+ */
+public interface AggregateCpProtocol extends CoprocessorProtocol {
+
+ /**
+ * It gives the maximum for a given combination of column qualifier and column
+ * family, in the given row range. In case of null column qualifier, maximum
+ * value for the entire column family will be returned.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return max value as mentioned above
+ * @throws IOException
+ *
+ */
+ long getMax(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+ /**
+ *
+ * For a given column family and column Qualifier for a table, it gives the
+ * minimum at the region level.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return
+ * @throws IOException
+ */
+ long getMin(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+ /**
+ * For a given column family and column Qualifier for a table, it gives its
+ * sum of all its values at the region level.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return
+ * @throws IOException
+ */
+
+ long getSum(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+ /**
+ * It gives the row count for the given column family and column qualifier. In
+ * case of null qualifier, FirstKeyOnlyFilter is used for optimization.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return
+ * @throws IOException
+ */
+ long getRowNum(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+ /**
+ * It returns sum and number of elements of a given qualifier and family. This
+ * is returned as a list of LongWritables containing sum and total count. The
+ * idea is at the client side, we will just do a grand sum of both these and
+ * get the overall average.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return
+ * @throws IOException
+ */
+ List getAvg(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+ /**
+ * This returns three values in order to be able to calculate a global
+ * standard deviation value. It returns sum, sum of square, and row num for a
+ * given column qualifier and family. The idea is get the value of variance
+ * first: the average of the squares less the square of the average a standard
+ * deviation is square root of variance.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param startRow
+ * @param endRow
+ * @return
+ * @throws IOException
+ */
+ List getStd(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException;
+
+}
\ No newline at end of file
Index: src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateProtocolImpl.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateProtocolImpl.java (revision 0)
+++ src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateProtocolImpl.java (revision 0)
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2010 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.coprocessor;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.filter.Filter;
+import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.regionserver.InternalScanner;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.LongWritable;
+
+public class AggregateProtocolImpl extends BaseEndpointCoprocessor implements
+ AggregateCpProtocol {
+ protected static Log log = LogFactory.getLog(AggregateProtocolImpl.class);
+
+ @Override
+ public long getMax(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException {
+ long maximum = Long.MIN_VALUE;
+ long temp = 0l;
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, null);
+ List results = new ArrayList();
+ try {
+ boolean done = false;
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (done
+ && Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ // temp = Bytes.toLong(results.get(0).getValue());
+ for (KeyValue kv : results) {
+ if (kv == null || kv.getValue().length != 8) {
+ log.warn("Value is not a long, skipping it ");
+ continue;
+ }
+ temp = Bytes.toLong(kv.getValue());
+
+ if (temp > maximum) {
+ maximum = temp;
+ }
+ }
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ log.info("Maximum from this region is "
+ + ((RegionCoprocessorEnvironment) getEnvironment()).getRegion()
+ .hashCode() + ": " + maximum);
+ return maximum;
+ }
+
+ @Override
+ public long getMin(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException {
+ long min = Long.MAX_VALUE;
+ long temp = 0l;
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, null);
+ List results = new ArrayList();
+ try {
+ boolean done = false;
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0 && done) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ for (KeyValue kv : results) {
+ if (kv == null || kv.getValue().length != 8) {
+ log.warn("Value is not a long, skipping it ");
+ continue;
+ }
+ temp = Bytes.toLong(kv.getValue());
+ if (temp < min) {
+ min = temp;
+ }
+ }
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ log.info("Minimum from this region is "
+ + ((RegionCoprocessorEnvironment) getEnvironment()).getRegion()
+ .hashCode() + ": " + min);
+ return min;
+ }
+
+ @Override
+ public long getSum(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException {
+ long sum = 0l;
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, null);
+ List results = new ArrayList();
+ try {
+ boolean done = false;
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0 && done) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ for (KeyValue kv : results) {
+ if (kv == null || kv.getValue().length != 8) {
+ log.warn("Value is not a long, skipping it ");
+ continue;
+ }
+ sum += Bytes.toLong(kv.getValue());
+ }
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ log.debug("Sum from this region is "
+ + ((RegionCoprocessorEnvironment) getEnvironment()).getRegion()
+ .hashCode() + ": " + sum);
+ return sum;
+ }
+
+ @Override
+ public long getRowNum(byte[] colFamily, byte[] colQualifier, byte[] startRow,
+ byte[] endRow) throws IOException {
+ long counter = 0l;
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, (colQualifier != null) ? null
+ : new FirstKeyOnlyFilter());
+ List results = new ArrayList();
+ try {
+ boolean done = false;
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0 && done) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ if (results.size() > 0) {
+ counter++;
+ }
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ log.debug("Row counter from this region is "
+ + ((RegionCoprocessorEnvironment) getEnvironment()).getRegion()
+ .hashCode() + ": " + counter);
+ return counter;
+ }
+
+ /**
+ * Returns a scanner for a given column qualifier and family. Throws an ioe in
+ * case both of them are null.
+ *
+ * @param colFamily
+ * @param colQualifier
+ * @param stopRow
+ * @param filter
+ * @return
+ * @throws IOException
+ */
+
+ private InternalScanner getScanWithColAndQualifier(byte[] colFamily,
+ byte[] colQualifier, byte[] stopRow, Filter filter) throws IOException {
+ if (colFamily == null && colQualifier == null) { // abort the process
+ throw new IOException("Family can't be null");
+ }
+ try {
+ Scan scan = new Scan();
+ scan.setStopRow(stopRow);
+ scan.setFilter(filter);
+ if (colQualifier == null)
+ scan.addFamily(colFamily);
+ else {
+ scan.addColumn(colFamily, colQualifier);
+ }
+ HRegion region = ((RegionCoprocessorEnvironment) getEnvironment())
+ .getRegion();
+ return region.getScanner(scan);
+ } catch (Exception e) {
+ log.error("Exception occurred while creating the scanner!");
+ throw new IOException("Exception occurred while creating the scanner");
+ }
+ }
+
+ @Override
+ public List getAvg(byte[] colFamily, byte[] colQualifier,
+ byte[] startRow, byte[] endRow) throws IOException {
+ long sum = 0l, rowNum = 0l;
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, null);
+ boolean done = false;
+ List results = new ArrayList();
+ try {
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0 && done) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ for (KeyValue kv : results) {
+ if (kv == null || kv.getValue().length != 8) {
+ log.warn("Value is not a long, skipping it ");
+ continue;
+ }
+ sum += Bytes.toLong(kv.getValue());
+ }
+ rowNum++;
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ List sumAndRowcount = new ArrayList();
+ sumAndRowcount.add(sum);
+ sumAndRowcount.add(rowNum);
+ return sumAndRowcount;
+ }
+
+ @Override
+ public List getStd(byte[] colFamily, byte[] colQualifier,
+ byte[] startRow, byte[] endRow) throws IOException {
+ long sum = 0l, rowNum = 0l, sumSq = 0l, temp = 0l;
+ System.out.println("colqul" + Bytes.toString(colQualifier));
+ InternalScanner scanner = getScanWithColAndQualifier(colFamily,
+ colQualifier, endRow, null);
+ boolean done = false;
+ List results = new ArrayList();
+ try {
+ do {
+ results.clear();
+ done = scanner.next(results);
+ while (Bytes.compareTo(startRow, HConstants.EMPTY_START_ROW) != 0
+ && Bytes.compareTo(results.get(0).getRow(), startRow) < 0 && done) {
+ results.clear();
+ done = scanner.next(results);
+ }
+ temp = 0;
+ for (KeyValue kv : results) {
+ if (kv == null || kv.getValue().length != 8) {
+ log.warn("Value is not a long, skipping it ");
+ continue;
+ }
+ temp += Bytes.toLong(kv.getValue());
+ }
+ sum += temp;
+ sumSq += (temp) * temp;
+ rowNum++;
+ } while (done);
+ } finally {
+ scanner.close();
+ }
+ List result = new ArrayList();
+ result.add(sum);
+ result.add(sumSq);
+ result.add(rowNum);
+ log.info("STD results are: " + result);
+ return result;
+ }
+
+}
Index: src/test/java/org/apache/hadoop/hbase/coprocessor/TestAggFunctions.java
===================================================================
--- src/test/java/org/apache/hadoop/hbase/coprocessor/TestAggFunctions.java (revision 0)
+++ src/test/java/org/apache/hadoop/hbase/coprocessor/TestAggFunctions.java (revision 0)
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2010 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.coprocessor;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Assert;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.MiniHBaseCluster;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.coprocessor.AggregationClient;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.JVMClusterUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * A test class to cover agg functions, that can be implemented using
+ * Coprocessors.
+ */
+public class TestAggFunctions {
+ protected static Log myLog = LogFactory.getLog(TestAggFunctions.class);
+
+ /**
+ * Creating the test infrastructure.
+ */
+ private static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
+ private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
+ private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
+ private static final byte[] TEST_MULTI_CQ = Bytes.toBytes("TestMultiCQ");
+
+ private static byte[] ROW = Bytes.toBytes("testRow");
+ private static final int ROWSIZE = 20;
+ private static final int rowSeperator1 = 5;
+ private static final int rowSeperator2 = 12;
+ private static byte[][] ROWS = makeN(ROW, ROWSIZE);
+
+ private static HBaseTestingUtility util = new HBaseTestingUtility();
+ private static MiniHBaseCluster cluster = null;
+
+ /**
+ * A set up method to start the test cluster. AggregateProtocolImpl is
+ * registered and will be loaded during region startup.
+ *
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void setupBeforeClass() throws Exception {
+ Configuration conf = util.getConfiguration();
+ conf.set("hbase.coprocessor.default.classes",
+ "org.apache.hadoop.hbase.coprocessor.AggregateProtocolImpl");
+
+ util.startMiniCluster(2);
+ cluster = util.getMiniHBaseCluster();
+ HTable table = util.createTable(TEST_TABLE, TEST_FAMILY);
+ util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY,
+ new byte[][] { HConstants.EMPTY_BYTE_ARRAY, ROWS[rowSeperator1],
+ ROWS[rowSeperator2] });
+ /**
+ * The testtable has one CQ which is always populated and one variable CQ
+ * for each row rowkey1: CF:CQ CF:CQ1 rowKey2: CF:CQ CF:CQ2
+ */
+ for (int i = 0; i < ROWSIZE; i++) {
+ Put put = new Put(ROWS[i]);
+ Long l = new Long(i);
+ put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(l));
+ table.put(put);
+ Put p2 = new Put(ROWS[i]);
+ p2.add(TEST_FAMILY, Bytes.add(TEST_MULTI_CQ, Bytes.toBytes(l)), Bytes
+ .toBytes(l * 10));
+ table.put(p2);
+ }
+
+ // sleep here is an ugly hack to allow region transitions to finish
+ Thread.sleep(5000); // TODO: Is this sleep really necessary to do...
+ for (JVMClusterUtil.RegionServerThread t : cluster.getRegionServerThreads()) {
+ for (HRegionInfo r : t.getRegionServer().getOnlineRegions()) {
+ t.getRegionServer().getOnlineRegion(r.getRegionName())
+ .getCoprocessorHost().load(AggregateProtocolImpl.class,
+ Coprocessor.Priority.USER);
+
+ }
+ }
+ }
+
+ /**
+ * Shutting down the cluster
+ *
+ * @throws Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ util.shutdownMiniCluster();
+ }
+
+ /**
+ * an infrastructure method to prepare rows for the testtable.
+ *
+ * @param base
+ * @param n
+ * @return
+ */
+ private static byte[][] makeN(byte[] base, int n) {
+ byte[][] ret = new byte[n][];
+ for (int i = 0; i < n; i++) {
+ ret[i] = Bytes.add(base, Bytes.toBytes(i));
+ }
+ return ret;
+ }
+
+ /**
+ * **************************** ROW COUNT Test cases *******************
+ */
+
+ /**
+ *
+ * This will test rowcount with a valid range, i.e., a subset of rows. It will
+ * be the most common use case.
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testRowCountWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = aClient.getRowNum(TEST_TABLE, ROWS[2], ROWS[14],
+ TEST_FAMILY, TEST_QUALIFIER);
+ System.out.printf("Vsl for row num with valid range is: %d", rowCount);
+ assertEquals(12, rowCount);
+
+ }
+
+ /**
+ * This will test the row count on the entire table. Startrow and endrow will
+ * be null.
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testRowCountAllTable() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = aClient.getRowNum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ System.out.printf("Val for rowNum should be %d", rowCount);
+ assertEquals(ROWSIZE, rowCount);
+ }
+
+ /**
+ * This will test the row count with startrow > endrow. The result should be
+ * -1.
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testRowCountWithInvalidRange1() {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = -1;
+ try {
+ rowCount = aClient.getRowNum(TEST_TABLE, ROWS[5], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ myLog.error("Exception thrown in the invalidRange method"
+ + e.getStackTrace());
+ }
+ assertEquals(-1, rowCount);
+ }
+
+ /**
+ * This will test the row count with startrow = endrow and they will be
+ * non-null. The result should be 0, as it assumes a non-get query.
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testRowCountWithInvalidRange2() {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = -1;
+ try {
+ rowCount = aClient.getRowNum(TEST_TABLE, ROWS[5], ROWS[5], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ rowCount = 0;
+ }
+ assertEquals(0, rowCount);
+ }
+
+ /**
+ * This should return a 0
+ */
+ @Test
+ public void testRowCountWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = -1;
+ try {
+ rowCount = aClient.getRowNum(TEST_TABLE, ROWS[5], ROWS[5], null, null);
+ } catch (Throwable e) {
+ rowCount = 0;
+ }
+ assertEquals(0, rowCount);
+ }
+
+ @Test
+ public void testRowCountWithNullCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long rowCount = aClient.getRowNum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(20, rowCount);
+ }
+
+ /**
+ * ***************Test cases for Maximum *******************
+ */
+
+ /**
+ * give max for the entire table.
+ *
+ * @throws Throwable
+ *
+ */
+ @Test
+ public void testMaxWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long maximum = aClient.getMaximum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ assertEquals(19, maximum);
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testMaxWithValidRange2() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long max = aClient.getMaximum(TEST_TABLE, ROWS[5], ROWS[15], TEST_FAMILY,
+ TEST_QUALIFIER);
+ assertEquals(14, max);
+ }
+
+ @Test
+ public void testMaxWithValidRangeWithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long maximum = aClient.getMaximum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(190, maximum);
+ }
+
+ @Test
+ public void testMaxWithValidRange2WithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long max = aClient.getMaximum(TEST_TABLE, ROWS[6], ROWS[7], TEST_FAMILY,
+ null);
+ assertEquals(60, max);
+ }
+
+ @Test
+ public void testMaxWithValidRangeWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ long max = Long.MIN_VALUE;
+ try {
+ max = aClient.getMaximum(TEST_TABLE, ROWS[2], ROWS[5], null, null);
+ } catch (Throwable e) {
+ max = 0;
+ }
+ assertEquals(0, max);// CP will throw an IOException about the
+ // null column family, and max will be set to 0
+ }
+
+ @Test
+ public void testMaxWithInvalidRange() {
+ AggregationClient aClient = new AggregationClient();
+ long max = Long.MIN_VALUE;
+ try {
+ max = aClient.getMaximum(TEST_TABLE, ROWS[4], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ max = 0;
+ }
+ assertEquals(0, max);// control should go to the catch block
+ }
+
+ @Test
+ public void testMaxWithInvalidRange2() throws Throwable {
+ long max = Long.MIN_VALUE;
+ try {
+ AggregationClient aClient = new AggregationClient();
+ max = aClient.getMaximum(TEST_TABLE, ROWS[6], ROWS[6], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Exception e) {
+ max = 0;
+ }
+ assertEquals(0, max);// control should go to the catch block
+ }
+
+ /**
+ * **************************Test cases for Minimum ***********************
+ */
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testMinWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long min = aClient.getMinimum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ assertEquals(0, min);
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testMinWithValidRange2() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long min = aClient.getMinimum(TEST_TABLE, ROWS[5], ROWS[15], TEST_FAMILY,
+ TEST_QUALIFIER);
+ assertEquals(5, min);
+ }
+
+ @Test
+ public void testMinWithValidRangeWithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long min = aClient.getMinimum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(0, min);
+ }
+
+ @Test
+ public void testMinWithValidRange2WithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long min = aClient.getMinimum(TEST_TABLE, ROWS[6], ROWS[7], TEST_FAMILY,
+ null);
+ assertEquals(6, min);
+ }
+
+ @Test
+ public void testMinWithValidRangeWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ long min = Long.MAX_VALUE;
+ try {
+ min = aClient.getMinimum(TEST_TABLE, ROWS[4], ROWS[8], null, null);
+ } catch (Throwable e) {
+ min = 0;
+ }
+ assertEquals(0, min);// CP will throw an IOException about the
+ // null column family, and max will be set to 0
+ }
+
+ @Test
+ public void testMinWithInvalidRange() {
+ AggregationClient aClient = new AggregationClient();
+ long min = Long.MAX_VALUE;
+ try {
+ min = aClient.getMinimum(TEST_TABLE, ROWS[4], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ min = 0;
+ }
+ assertEquals(0, min);// control should go to the catch block
+ }
+
+ @Test
+ public void testMinWithInvalidRange2() {
+ AggregationClient aClient = new AggregationClient();
+ long min = Long.MAX_VALUE;
+ try {
+ min = aClient.getMinimum(TEST_TABLE, ROWS[4], ROWS[4], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ min = 0;
+ }
+ assertEquals(0, min);// control should go to the catch block
+ }
+
+ /**
+ * *************** Test cases for Sum *********************
+ */
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testSumWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long sum = aClient.getSum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ assertEquals(190, sum);
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testSumWithValidRange2() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long sum = aClient.getSum(TEST_TABLE, ROWS[5], ROWS[15], TEST_FAMILY,
+ TEST_QUALIFIER);
+ assertEquals(95, sum);
+ }
+
+ @Test
+ public void testSumWithValidRangeWithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long sum = aClient.getSum(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(190 + 1900, sum);
+ }
+
+ @Test
+ public void testSumWithValidRange2WithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ long sum = aClient.getSum(TEST_TABLE, ROWS[6], ROWS[7], TEST_FAMILY, null);
+ assertEquals(6 + 60, sum);
+ }
+
+ @Test
+ public void testSumWithValidRangeWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ long sum = Long.MAX_VALUE;
+ try {
+ sum = aClient.getSum(TEST_TABLE, ROWS[4], ROWS[4], null, null);
+ } catch (Throwable e) {
+ sum = 0;
+ }
+ assertEquals(0, sum);// CP will throw an IOException about the
+ // null column family, and max will be set to 0
+ }
+
+ @Test
+ public void testSumWithInvalidRange() {
+ AggregationClient aClient = new AggregationClient();
+ long sum = Long.MAX_VALUE;
+ try {
+ sum = aClient.getSum(TEST_TABLE, ROWS[4], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ sum = 0;
+ }
+ assertEquals(0, sum);// control should go to the catch block
+ }
+
+ /**
+ * ****************************** Test Cases for Avg **************
+ */
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testAvgWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double avg = aClient.getAvg(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ assertEquals(9.5, avg, 0);
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testAvgWithValidRange2() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double avg = aClient.getAvg(TEST_TABLE, ROWS[5], ROWS[15], TEST_FAMILY,
+ TEST_QUALIFIER);
+ assertEquals(9.5, avg, 0);
+ }
+
+ @Test
+ public void testAvgWithValidRangeWithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double avg = aClient.getAvg(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(104.5, avg, 0);
+ }
+
+ @Test
+ public void testAvgWithValidRange2WithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double avg = aClient
+ .getAvg(TEST_TABLE, ROWS[6], ROWS[7], TEST_FAMILY, null);
+ assertEquals(6 + 60, avg, 0);
+ }
+
+ @Test
+ public void testAvgWithValidRangeWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ double avg = Double.MAX_VALUE;
+ try {
+ avg = aClient.getAvg(TEST_TABLE, ROWS[4], ROWS[4], null, null);
+ } catch (Throwable e) {
+ avg = 0;
+ }
+ assertEquals(0, avg, 0);// CP will throw an IOException about the
+ // null column family, and max will be set to 0
+ }
+
+ @Test
+ public void testAvgWithInvalidRange() {
+ AggregationClient aClient = new AggregationClient();
+ double avg = Double.MAX_VALUE;
+ try {
+ avg = aClient.getAvg(TEST_TABLE, ROWS[4], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ avg = 0;
+ }
+ assertEquals(0, avg, 0);// control should go to the catch block
+ }
+
+ /**
+ * ****************** Test cases for STD **********************
+ */
+/**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testStdWithValidRange() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double std = aClient.getStd(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, TEST_QUALIFIER);
+ assertEquals(5.766, std, 0.05d);
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testStdWithValidRange2() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double std = aClient.getStd(TEST_TABLE, ROWS[5], ROWS[15], TEST_FAMILY,
+ TEST_QUALIFIER);
+ assertEquals(2.87, std, 0.05d);
+ }
+
+ @Test
+ public void testStdWithValidRangeWithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double std = aClient.getStd(TEST_TABLE, HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW, TEST_FAMILY, null);
+ assertEquals(63.42, std, 0.05d);
+ }
+
+ @Test
+ public void testStdWithValidRange2WithNoCQ() throws Throwable {
+ AggregationClient aClient = new AggregationClient();
+ double std = aClient
+ .getStd(TEST_TABLE, ROWS[6], ROWS[7], TEST_FAMILY, null);
+ assertEquals(0, std, 0);
+ }
+
+ @Test
+ public void testStdWithValidRangeWithNullCF() {
+ AggregationClient aClient = new AggregationClient();
+ double std = Double.MAX_VALUE;
+ try {
+ std = aClient.getStd(TEST_TABLE, ROWS[4], ROWS[4], null, null);
+ } catch (Throwable e) {
+ std = 0;
+ }
+ assertEquals(0, std, 0);// CP will throw an IOException about the
+ // null column family, and max will be set to 0
+ }
+
+ @Test
+ public void testStdWithInvalidRange() {
+ AggregationClient aClient = new AggregationClient();
+ double std = Double.MAX_VALUE;
+ try {
+ std = aClient.getAvg(TEST_TABLE, ROWS[4], ROWS[2], TEST_FAMILY,
+ TEST_QUALIFIER);
+ } catch (Throwable e) {
+ std = 0;
+ }
+ assertEquals(0, std, 0);// control should go to the catch block
+ }
+
+}