/*
* Copyright (C) 2010-2012 The Async HBase Authors. All rights reserved.
* This file is part of Async HBase.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the StumbleUpon nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.hbase.async.test;
import java.util.ArrayList;
import java.util.HashMap;
import org.hbase.async.AtomicIncrementRequest;
import org.hbase.async.DeleteRequest;
import org.hbase.async.GetRequest;
import org.hbase.async.HBaseClient;
import org.hbase.async.KeyValue;
import org.hbase.async.PutRequest;
import org.hbase.async.RowLock;
import org.hbase.async.RowLockRequest;
import org.hbase.async.Scanner;
import org.slf4j.Logger;
import org.hbase.async.test.Common;
/**
* Simple command-line interface to quickly test async HBase.
*/
final class Test {
private static final Logger LOG = Common.logger(Test.class);
private static final HashMap<String, Cmd> commands;
static {
commands = new HashMap<String, Cmd>();
commands.put("icv", new icv());
commands.put("scan", new scan());
commands.put("mscan", new mscan());
final get get = new get(); // get get get!!
commands.put("get", get);
commands.put("lget", get);
final put put = new put(); // put put put!!
commands.put("put", put);
commands.put("lput", put);
final delete delete = new delete(); // delete delete delete!!
commands.put("delete", delete);
commands.put("ldelete", delete);
final cas cas = new cas(); // cas cas cas!!
commands.put("cas", cas);
commands.put("lcas", cas);
}
private static void printUsage() {
System.err.println("Usage: " + Test.class.getSimpleName()
+ " <zk quorum> <cmd> <table> [args]\n"
+ "Available commands:\n"
+ " get <table> <key> [family] [qualifiers ...]\n"
+ " icv <table> <key> <family> <qualifier> [amount]\n"
+ " put <table> <key> <family> <qualifier> <value>\n"
+ " delete <table> <key> [<family> [<qualifier>]]\n"
+ " scan <table> [start] [family] [qualifier] [stop] [regexp]\n"
+ " mscan <table> [start] [family[:qualifier[,qualifier]]/[family...]] [stop] [regexp]\n"
+ " cas <table> <key> <family> <qualifier> <expected> <value>\n"
+ "Variants that acquire an explicit row-lock:\n"
+ " lget <table> <key> [family] [qualifiers ...]\n"
+ " lput <table> <key> <family> <qualifier> <value>\n"
+ " ldelete <table> <key> <family> <qualifier>\n"
+ " lcas <table> <key> <family> <qualifier> <expected> <value>\n"
);
}
private static void fatalUsage(final String msg, final int rv) {
System.err.println(msg);
printUsage();
System.exit(rv);
}
private static void ensureArguments(final String[] args,
final int min,
final int max) {
if (args.length < min) {
fatalUsage("Not enough arguments, need at least " + min, 1);
} else if (args.length > max && max > min) {
fatalUsage("Too many arguments, need at most " + max, 1);
}
}
public static void main(final String[] args) throws Exception {
ensureArguments(args, 3, -1);
final Cmd cmd = commands.get(args[1]);
if (cmd == null) {
fatalUsage("Unknown command: " + args[1], 2);
}
final HBaseClient client = new HBaseClient(args[0]);
try {
cmd.execute(client, args);
} catch (Exception e) {
LOG.error("Unexpected exception caught in main", e);
}
System.out.println("Starting shutdown...");
LOG.debug("Shutdown returned " + client.shutdown().joinUninterruptibly());
System.out.println("Exiting...");
}
private static interface Cmd {
void execute(HBaseClient client, String[] args) throws Exception;
}
private static final class get implements Cmd {
public void execute(final HBaseClient client, String[] args) throws Exception {
ensureArguments(args, 4, 64);
final GetRequest get = new GetRequest(args[2], args[3]);
if (args.length > 4) {
get.family(args[4]);
}
if (args.length > 5) {
if (args.length == 6) {
get.qualifier(args[5]);
} else {
final byte[][] qualifiers = new byte[args.length - 5][];
for (int i = 5; i < args.length; i++) {
qualifiers[i - 5] = args[i].getBytes();
}
get.qualifiers(qualifiers);
}
}
RowLock lock = null;
if (args[1].charAt(0) == 'l') { // locked version of the command
final RowLockRequest rlr = new RowLockRequest(args[2], args[3]);
lock = client.lockRow(rlr).joinUninterruptibly();
LOG.info("Acquired explicit row lock: " + lock);
}
args = null;
try {
final ArrayList<KeyValue> result = client.get(get).joinUninterruptibly();
LOG.info("Get result=" + result);
} catch (Exception e) {
LOG.error("Get failed", e);
} finally {
if (lock != null) {
client.unlockRow(lock).joinUninterruptibly();
LOG.info("Released explicit row lock: " + lock);
}
}
}
}
private static final class icv implements Cmd {
public void execute(final HBaseClient client, String[] args) {
ensureArguments(args, 6, 7);
final AtomicIncrementRequest icv =
new AtomicIncrementRequest(args[2], args[3], args[4], args[5]);
if (args.length > 6) {
icv.setAmount(Long.parseLong(args[6]));
}
args = null;
try {
final long result = client.atomicIncrement(icv).joinUninterruptibly();
LOG.info("ICV result=" + result);
} catch (Exception e) {
LOG.error("ICV failed", e);
}
}
}
private static final class put implements Cmd {
public void execute(final HBaseClient client, String[] args) throws Exception {
ensureArguments(args, 7, 7);
RowLock lock = null;
if (args[1].charAt(0) == 'l') { // locked version of the command
final RowLockRequest rlr = new RowLockRequest(args[2], args[3]);
lock = client.lockRow(rlr).joinUninterruptibly();
LOG.info("Acquired explicit row lock: " + lock);
}
final PutRequest put = lock == null
? new PutRequest(args[2], args[3], args[4], args[5], args[6])
: new PutRequest(args[2], args[3], args[4], args[5], args[6], lock);
args = null;
try {
final Object result = client.put(put).joinUninterruptibly();
LOG.info("Put result=" + result);
} catch (Exception e) {
LOG.error("Put failed", e);
} finally {
if (lock != null) {
client.unlockRow(lock).joinUninterruptibly();
LOG.info("Released explicit row lock: " + lock);
}
}
}
}
private static final class delete implements Cmd {
public void execute(final HBaseClient client, String[] args) throws Exception {
ensureArguments(args, 4, 6);
RowLock lock = null;
if (args[1].charAt(0) == 'l') { // locked version of the command
ensureArguments(args, 6, 6);
final RowLockRequest rlr = new RowLockRequest(args[2], args[3]);
lock = client.lockRow(rlr).joinUninterruptibly();
LOG.info("Acquired explicit row lock: " + lock);
}
final DeleteRequest delete;
if (lock == null) {
switch (args.length) {
case 4: delete = new DeleteRequest(args[2], args[3]); break;
case 5: delete = new DeleteRequest(args[2], args[3], args[4]); break;
case 6: delete = new DeleteRequest(args[2], args[3], args[4], args[5]); break;
default: throw new AssertionError("Should never be here");
}
} else {
delete = new DeleteRequest(args[2], args[3], args[4], args[5], lock);
}
args = null;
try {
final Object result = client.delete(delete).joinUninterruptibly();
LOG.info("Delete result=" + result);
} catch (Exception e) {
LOG.error("Delete failed", e);
} finally {
if (lock != null) {
client.unlockRow(lock).joinUninterruptibly();
LOG.info("Released explicit row lock: " + lock);
}
}
}
}
private static final class scan implements Cmd {
@SuppressWarnings("fallthrough")
public void execute(final HBaseClient client, String[] args) {
ensureArguments(args, 3, 8);
final Scanner scanner = client.newScanner(args[2]);
switch (args.length) {
case 8: scanner.setKeyRegexp(args[7]);
case 7: scanner.setStopKey(args[6]);
case 6: scanner.setQualifier(args[5]);
case 5: scanner.setFamily(args[4]);
case 4: scanner.setStartKey(args[3]);
}
args = null;
LOG.info("Start scanner=" + scanner);
try {
ArrayList<ArrayList<KeyValue>> rows;
while ((rows = scanner.nextRows().joinUninterruptibly()) != null) {
LOG.info("scanned results=" + rows + " from " + scanner);
}
} catch (Exception e) {
LOG.error("Scan failed", e);
}
}
}
private static final class mscan implements Cmd {
@SuppressWarnings("fallthrough")
public void execute(final HBaseClient client, String[] args) {
ensureArguments(args, 3, 7);
final Scanner scanner = client.newScanner(args[2]);
switch (args.length) {
case 7: scanner.setKeyRegexp(args[6]);
case 6: scanner.setStopKey(args[5]);
case 5:
final String columns = args[4];
final ArrayList<byte[]> families = new ArrayList<byte[]>();
final ArrayList<byte[][]> qualifiers = new ArrayList<byte[][]>();
for (String spec : columns.split("/")) {
final String[] family = spec.split(":");
families.add(family[0].getBytes());
if (family.length == 1) {
qualifiers.add(null);
} else {
final String[] quals = family[1].split(",");
final byte[][] qb = new byte[quals.length][];
for (int i = 0; i < qb.length; i++) {
qb[i] = quals[i].getBytes();
}
qualifiers.add(qb);
}
}
scanner.setFamilies(families.toArray(new byte[families.size()][]),
qualifiers.toArray(new byte[qualifiers.size()][][]));
case 4: scanner.setStartKey(args[3]);
}
LOG.info("Start scanner=" + scanner);
try {
ArrayList<ArrayList<KeyValue>> rows;
while ((rows = scanner.nextRows().joinUninterruptibly()) != null) {
LOG.info("scanned results=" + rows + " from " + scanner);
}
} catch (Exception e) {
LOG.error("Scan failed", e);
}
}
}
private static final class cas implements Cmd {
public void execute(final HBaseClient client, String[] args) throws Exception {
ensureArguments(args, 8, 8);
RowLock lock = null;
if (args[1].charAt(0) == 'l') { // locked version of the command
final RowLockRequest rlr = new RowLockRequest(args[2], args[3]);
lock = client.lockRow(rlr).joinUninterruptibly();
LOG.info("Acquired explicit row lock: " + lock);
}
final PutRequest put = lock == null
? new PutRequest(args[2], args[3], args[4], args[5], args[7])
: new PutRequest(args[2], args[3], args[4], args[5], args[7], lock);
final String expected = args[6];
args = null;
try {
final boolean ok = client.compareAndSet(put, expected).joinUninterruptibly();
LOG.info("CAS "
+ (ok ? "succeeded" : "failed: value wasn't " + expected));
} catch (Exception e) {
LOG.error("CAS failed", e);
} finally {
if (lock != null) {
client.unlockRow(lock).joinUninterruptibly();
LOG.info("Released explicit row lock: " + lock);
}
}
}
}
}