HBASE-1671 HBASE-1609 broke scanners riding across splits

git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@798679 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2009-07-28 19:41:54 +00:00
parent 3086b191dd
commit a68b5ee409
13 changed files with 198 additions and 90 deletions

View File

@ -295,6 +295,7 @@ Release 0.20.0 - Unreleased
(Tim Sell and Ryan Rawson via Stack) (Tim Sell and Ryan Rawson via Stack)
HBASE-1703 ICVs across /during a flush can cause multiple keys with the HBASE-1703 ICVs across /during a flush can cause multiple keys with the
same TS (bad) same TS (bad)
HBASE-1671 HBASE-1609 broke scanners riding across splits
IMPROVEMENTS IMPROVEMENTS
HBASE-1089 Add count of regions on filesystem to master UI; add percentage HBASE-1089 Add count of regions on filesystem to master UI; add percentage

View File

@ -31,9 +31,8 @@ class TransactionScannerCallable extends ScannerCallable {
private TransactionState transactionState; private TransactionState transactionState;
TransactionScannerCallable(final TransactionState transactionState, TransactionScannerCallable(final TransactionState transactionState,
final HConnection connection, final byte[] tableName, final HConnection connection, final byte[] tableName, Scan scan) {
final byte[] startRow, Scan scan) { super(connection, tableName, scan);
super(connection, tableName, startRow, scan);
this.transactionState = transactionState; this.transactionState = transactionState;
} }

View File

@ -186,7 +186,7 @@ public class TransactionalTable extends HTable {
final byte[] localStartKey, int caching) { final byte[] localStartKey, int caching) {
TransactionScannerCallable t = TransactionScannerCallable t =
new TransactionScannerCallable(transactionState, getConnection(), new TransactionScannerCallable(transactionState, getConnection(),
getTableName(), getScan().getStartRow(), getScan()); getTableName(), getScan());
t.setCaching(caching); t.setCaching(caching);
return t; return t;
} }

View File

@ -42,4 +42,12 @@ public class DoNotRetryIOException extends IOException {
public DoNotRetryIOException(String message) { public DoNotRetryIOException(String message) {
super(message); super(message);
} }
/**
* @param message
* @param cause
*/
public DoNotRetryIOException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -65,8 +65,6 @@ import org.apache.zookeeper.Watcher.Event.KeeperState;
* Used by {@link HTable} and {@link HBaseAdmin} * Used by {@link HTable} and {@link HBaseAdmin}
*/ */
public class HConnectionManager implements HConstants { public class HConnectionManager implements HConstants {
private static final Log LOG = LogFactory.getLog(HConnectionManager.class);
/* /*
* Not instantiable. * Not instantiable.
*/ */
@ -94,7 +92,6 @@ public class HConnectionManager implements HConstants {
if (connection == null) { if (connection == null) {
connection = new TableServers(conf); connection = new TableServers(conf);
HBASE_INSTANCES.put(conf, connection); HBASE_INSTANCES.put(conf, connection);
LOG.debug("Created new HBASE_INSTANCES");
} }
} }
return connection; return connection;
@ -131,7 +128,7 @@ public class HConnectionManager implements HConstants {
/* Encapsulates finding the servers for an HBase instance */ /* Encapsulates finding the servers for an HBase instance */
private static class TableServers implements ServerConnection, HConstants, Watcher { private static class TableServers implements ServerConnection, HConstants, Watcher {
private static final Log LOG = LogFactory.getLog(TableServers.class); static final Log LOG = LogFactory.getLog(TableServers.class);
private final Class<? extends HRegionInterface> serverInterfaceClass; private final Class<? extends HRegionInterface> serverInterfaceClass;
private final long pause; private final long pause;
private final int numRetries; private final int numRetries;
@ -353,8 +350,7 @@ public class HConnectionManager implements HConstants {
MetaScannerVisitor visitor = new MetaScannerVisitor() { MetaScannerVisitor visitor = new MetaScannerVisitor() {
public boolean processRow(Result result) throws IOException { public boolean processRow(Result result) throws IOException {
try { try {
byte[] value = byte[] value = result.getValue(CATALOG_FAMILY, REGIONINFO_QUALIFIER);
result.getValue(CATALOG_FAMILY, REGIONINFO_QUALIFIER);
HRegionInfo info = null; HRegionInfo info = null;
if (value != null) { if (value != null) {
info = Writables.getHRegionInfo(value); info = Writables.getHRegionInfo(value);
@ -411,9 +407,7 @@ public class HConnectionManager implements HConstants {
scan.addColumn(CATALOG_FAMILY, REGIONINFO_QUALIFIER); scan.addColumn(CATALOG_FAMILY, REGIONINFO_QUALIFIER);
ScannerCallable s = new ScannerCallable(this, ScannerCallable s = new ScannerCallable(this,
(Bytes.equals(tableName, HConstants.META_TABLE_NAME) ? (Bytes.equals(tableName, HConstants.META_TABLE_NAME) ?
HConstants.ROOT_TABLE_NAME : HConstants.META_TABLE_NAME), HConstants.ROOT_TABLE_NAME : HConstants.META_TABLE_NAME), scan);
scan.getStartRow(),
scan);
try { try {
// Open scanner // Open scanner
getRegionServerWithRetries(s); getRegionServerWithRetries(s);
@ -542,7 +536,7 @@ public class HConnectionManager implements HConstants {
*/ */
private HRegionLocation locateRegionInMeta(final byte [] parentTable, private HRegionLocation locateRegionInMeta(final byte [] parentTable,
final byte [] tableName, final byte [] row, boolean useCache) final byte [] tableName, final byte [] row, boolean useCache)
throws IOException{ throws IOException {
HRegionLocation location = null; HRegionLocation location = null;
// If supposed to be using the cache, then check it for a possible hit. // If supposed to be using the cache, then check it for a possible hit.
// Otherwise, delete any existing cached location so it won't interfere. // Otherwise, delete any existing cached location so it won't interfere.
@ -969,7 +963,7 @@ public class HConnectionManager implements HConstants {
throw (DoNotRetryIOException) t; throw (DoNotRetryIOException) t;
} }
} }
return null; return null;
} }
private HRegionLocation private HRegionLocation

View File

@ -29,6 +29,7 @@ import java.util.TreeMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
@ -36,6 +37,7 @@ import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HServerAddress; import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.NotServingRegionException;
import org.apache.hadoop.hbase.UnknownScannerException; import org.apache.hadoop.hbase.UnknownScannerException;
import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
import org.apache.hadoop.hbase.filter.RowFilterInterface; import org.apache.hadoop.hbase.filter.RowFilterInterface;
@ -54,7 +56,6 @@ import org.apache.hadoop.hbase.util.Writables;
/** /**
* Used to communicate with a single HBase table * Used to communicate with a single HBase table
* TODO: checkAndSave in oldAPI * TODO: checkAndSave in oldAPI
* TODO: Converting filters
* TODO: Regex deletes. * TODO: Regex deletes.
*/ */
public class HTable { public class HTable {
@ -1778,13 +1779,18 @@ public class HTable {
*/ */
protected class ClientScanner implements ResultScanner { protected class ClientScanner implements ResultScanner {
private final Log CLIENT_LOG = LogFactory.getLog(this.getClass()); private final Log CLIENT_LOG = LogFactory.getLog(this.getClass());
// HEADSUP: The scan internal start row can change as we move through table.
private Scan scan; private Scan scan;
private boolean closed = false; private boolean closed = false;
// Current region scanner is against. Gets cleared if current region goes
// wonky: e.g. if it splits on us.
private HRegionInfo currentRegion = null; private HRegionInfo currentRegion = null;
private ScannerCallable callable = null; private ScannerCallable callable = null;
private final LinkedList<Result> cache = new LinkedList<Result>(); private final LinkedList<Result> cache = new LinkedList<Result>();
private final int scannerCaching = HTable.this.scannerCaching; private final int caching = HTable.this.scannerCaching;
private long lastNext; private long lastNext;
// Keep lastResult returned successfully in case we have to reset scanner.
private Result lastResult = null;
protected ClientScanner(final Scan scan) { protected ClientScanner(final Scan scan) {
if (CLIENT_LOG.isDebugEnabled()) { if (CLIENT_LOG.isDebugEnabled()) {
@ -1804,7 +1810,7 @@ public class HTable {
} }
public void initialize() throws IOException { public void initialize() throws IOException {
nextScanner(this.scannerCaching); nextScanner(this.caching);
} }
protected Scan getScan() { protected Scan getScan() {
@ -1814,10 +1820,12 @@ public class HTable {
protected long getTimestamp() { protected long getTimestamp() {
return lastNext; return lastNext;
} }
/* /*
* Gets a scanner for the next region. * Gets a scanner for the next region. If this.currentRegion != null, then
* Returns false if there are no more scanners. * we will move to the endrow of this.currentRegion. Else we will get
* scanner at the scan.getStartRow().
* @param nbRows
*/ */
private boolean nextScanner(int nbRows) throws IOException { private boolean nextScanner(int nbRows) throws IOException {
// Close the previous scanner if it's open // Close the previous scanner if it's open
@ -1826,38 +1834,38 @@ public class HTable {
getConnection().getRegionServerWithRetries(callable); getConnection().getRegionServerWithRetries(callable);
this.callable = null; this.callable = null;
} }
// Where to start the next scanner
byte [] localStartKey = null;
// if we're at the end of the table, then close and return false // if we're at the end of the table, then close and return false
// to stop iterating // to stop iterating
if (currentRegion != null) { if (this.currentRegion != null) {
if (CLIENT_LOG.isDebugEnabled()) { if (CLIENT_LOG.isDebugEnabled()) {
CLIENT_LOG.debug("Advancing forward from region " + currentRegion); CLIENT_LOG.debug("Finished with region " + this.currentRegion);
} }
byte [] endKey = this.currentRegion.getEndKey();
byte [] endKey = currentRegion.getEndKey();
if (endKey == null || if (endKey == null ||
Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) || Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) ||
filterSaysStop(endKey)) { filterSaysStop(endKey)) {
close(); close();
return false; return false;
} }
} localStartKey = endKey;
} else {
HRegionInfo oldRegion = this.currentRegion; localStartKey = this.scan.getStartRow();
byte [] localStartKey = }
oldRegion == null ? scan.getStartRow() : oldRegion.getEndKey();
if (CLIENT_LOG.isDebugEnabled()) { if (CLIENT_LOG.isDebugEnabled()) {
CLIENT_LOG.debug("Advancing internal scanner to startKey at '" + CLIENT_LOG.debug("Advancing internal scanner to startKey at '" +
Bytes.toStringBinary(localStartKey) + "'"); Bytes.toStringBinary(localStartKey) + "'");
} }
try { try {
callable = getScannerCallable(localStartKey, nbRows); callable = getScannerCallable(localStartKey, nbRows);
// open a scanner on the region server starting at the // Open a scanner on the region server starting at the
// beginning of the region // beginning of the region
getConnection().getRegionServerWithRetries(callable); getConnection().getRegionServerWithRetries(callable);
currentRegion = callable.getHRegionInfo(); this.currentRegion = callable.getHRegionInfo();
} catch (IOException e) { } catch (IOException e) {
close(); close();
throw e; throw e;
@ -1867,8 +1875,9 @@ public class HTable {
protected ScannerCallable getScannerCallable(byte [] localStartKey, protected ScannerCallable getScannerCallable(byte [] localStartKey,
int nbRows) { int nbRows) {
scan.setStartRow(localStartKey);
ScannerCallable s = new ScannerCallable(getConnection(), ScannerCallable s = new ScannerCallable(getConnection(),
getTableName(), localStartKey, scan); getTableName(), scan);
s.setCaching(nbRows); s.setCaching(nbRows);
return s; return s;
} }
@ -1915,13 +1924,35 @@ public class HTable {
} }
if (cache.size() == 0) { if (cache.size() == 0) {
Result [] values = null; Result [] values = null;
int countdown = this.scannerCaching; int countdown = this.caching;
// We need to reset it if it's a new callable that was created // We need to reset it if it's a new callable that was created
// with a countdown in nextScanner // with a countdown in nextScanner
callable.setCaching(this.scannerCaching); callable.setCaching(this.caching);
// This flag is set when we want to skip the result returned. We do
// this when we reset scanner because it split under us.
boolean skipFirst = false;
do { do {
try { try {
values = getConnection().getRegionServerWithRetries(callable); values = getConnection().getRegionServerWithRetries(callable);
if (skipFirst) {
skipFirst = false;
// Reget.
values = getConnection().getRegionServerWithRetries(callable);
}
} catch (DoNotRetryIOException e) {
Throwable cause = e.getCause();
if (cause == null || !(cause instanceof NotServingRegionException)) {
throw e;
}
// Else, its signal from depths of ScannerCallable that we got an
// NSRE on a next and that we need to reset the scanner.
this.scan.setStartRow(this.lastResult.getRow());
// Clear region as flag to nextScanner to use this.scan.startRow.
this.currentRegion = null;
// Skip first row returned. We already let it out on previous
// invocation.
skipFirst = true;
continue;
} catch (IOException e) { } catch (IOException e) {
if (e instanceof UnknownScannerException && if (e instanceof UnknownScannerException &&
lastNext + scannerTimeout < System.currentTimeMillis()) { lastNext + scannerTimeout < System.currentTimeMillis()) {
@ -1936,6 +1967,7 @@ public class HTable {
for (Result rs : values) { for (Result rs : values) {
cache.add(rs); cache.add(rs);
countdown--; countdown--;
this.lastResult = rs;
} }
} }
} while (countdown > 0 && nextScanner(countdown)); } while (countdown > 0 && nextScanner(countdown));
@ -1965,7 +1997,7 @@ public class HTable {
} }
return resultSets.toArray(new Result[resultSets.size()]); return resultSets.toArray(new Result[resultSets.size()]);
} }
public void close() { public void close() {
if (callable != null) { if (callable != null) {
callable.setClose(); callable.setClose();
@ -1998,7 +2030,7 @@ public class HTable {
return next != null; return next != null;
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
return true; return true;
} }

View File

@ -49,7 +49,7 @@ class MetaScanner implements HConstants {
ScannerCallable callable = null; ScannerCallable callable = null;
do { do {
Scan scan = new Scan(startRow).addFamily(CATALOG_FAMILY); Scan scan = new Scan(startRow).addFamily(CATALOG_FAMILY);
callable = new ScannerCallable(connection, META_TABLE_NAME, scan.getStartRow(), scan); callable = new ScannerCallable(connection, META_TABLE_NAME, scan);
// Open scanner // Open scanner
connection.getRegionServerWithRetries(callable); connection.getRegionServerWithRetries(callable);
try { try {

View File

@ -1,3 +1,4 @@
/** /**
* Copyright 2008 The Apache Software Foundation * Copyright 2008 The Apache Software Foundation
* *
@ -22,7 +23,12 @@ package org.apache.hadoop.hbase.client;
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.NotServingRegionException;
import org.apache.hadoop.hbase.RemoteExceptionHandler;
import org.apache.hadoop.ipc.RemoteException;
import org.mortbay.log.Log;
/** /**
@ -34,20 +40,16 @@ public class ScannerCallable extends ServerCallable<Result[]> {
private boolean instantiated = false; private boolean instantiated = false;
private boolean closed = false; private boolean closed = false;
private Scan scan; private Scan scan;
private byte [] startRow;
private int caching = 1; private int caching = 1;
/** /**
* @param connection * @param connection
* @param tableName * @param tableName
* @param startRow
* @param scan * @param scan
*/ */
public ScannerCallable (HConnection connection, byte [] tableName, public ScannerCallable (HConnection connection, byte [] tableName, Scan scan) {
byte [] startRow, Scan scan) { super(connection, tableName, scan.getStartRow());
super(connection, tableName, startRow);
this.scan = scan; this.scan = scan;
this.startRow = startRow;
} }
/** /**
@ -67,18 +69,42 @@ public class ScannerCallable extends ServerCallable<Result[]> {
*/ */
public Result [] call() throws IOException { public Result [] call() throws IOException {
if (scannerId != -1L && closed) { if (scannerId != -1L && closed) {
server.close(scannerId); close();
scannerId = -1L;
} else if (scannerId == -1L && !closed) { } else if (scannerId == -1L && !closed) {
// open the scanner this.scannerId = openScanner();
scannerId = openScanner();
} else { } else {
Result [] rrs = server.next(scannerId, caching); Result [] rrs = null;
try {
rrs = server.next(scannerId, caching);
} catch (IOException e) {
IOException ioe = null;
if (e instanceof RemoteException) {
ioe = RemoteExceptionHandler.decodeRemoteException((RemoteException)e);
}
if (ioe != null && ioe instanceof NotServingRegionException) {
// Throw a DNRE so that we break out of cycle of calling NSRE
// when what we need is to open scanner against new location.
// Attach NSRE to signal client that it needs to resetup scanner.
throw new DoNotRetryIOException("Reset scanner", ioe);
}
}
return rrs == null || rrs.length == 0? null: rrs; return rrs == null || rrs.length == 0? null: rrs;
} }
return null; return null;
} }
private void close() {
if (this.scannerId == -1L) {
return;
}
try {
this.server.close(this.scannerId);
} catch (IOException e) {
Log.warn("Ignore, probably already closed", e);
}
this.scannerId = -1L;
}
protected long openScanner() throws IOException { protected long openScanner() throws IOException {
return server.openScanner( return server.openScanner(
this.location.getRegionInfo().getRegionName(), scan); this.location.getRegionInfo().getRegionName(), scan);

View File

@ -729,7 +729,7 @@ public class HFile {
} }
protected String toStringLastKey() { protected String toStringLastKey() {
return KeyValue.keyToString(getFirstKey()); return KeyValue.keyToString(getLastKey());
} }
public long length() { public long length() {

View File

@ -188,7 +188,7 @@ public class HLog implements HConstants, Syncable {
* @param listener * @param listener
* @throws IOException * @throws IOException
*/ */
public HLog(final FileSystem fs, final Path dir, final Configuration conf, public HLog(final FileSystem fs, final Path dir, final HBaseConfiguration conf,
final LogRollListener listener) final LogRollListener listener)
throws IOException { throws IOException {
super(); super();
@ -219,7 +219,7 @@ public class HLog implements HConstants, Syncable {
", optionallogflushinternal=" + this.optionalFlushInterval + "ms"); ", optionallogflushinternal=" + this.optionalFlushInterval + "ms");
rollWriter(); rollWriter();
// Test if syncfs is available. // Test if syncfs is available.
this.append = conf.getBoolean("dfs.support.append", false); this.append = isAppend(conf);
Method m = null; Method m = null;
if (this.append) { if (this.append) {
try { try {
@ -784,7 +784,7 @@ public class HLog implements HConstants, Syncable {
* @throws IOException * @throws IOException
*/ */
public static List<Path> splitLog(final Path rootDir, final Path srcDir, public static List<Path> splitLog(final Path rootDir, final Path srcDir,
final FileSystem fs, final Configuration conf) final FileSystem fs, final HBaseConfiguration conf)
throws IOException { throws IOException {
long millis = System.currentTimeMillis(); long millis = System.currentTimeMillis();
List<Path> splits = null; List<Path> splits = null;
@ -833,7 +833,8 @@ public class HLog implements HConstants, Syncable {
* @return List of splits made. * @return List of splits made.
*/ */
private static List<Path> splitLog(final Path rootDir, private static List<Path> splitLog(final Path rootDir,
final FileStatus [] logfiles, final FileSystem fs, final Configuration conf) final FileStatus [] logfiles, final FileSystem fs,
final HBaseConfiguration conf)
throws IOException { throws IOException {
final Map<byte [], WriterAndPath> logWriters = final Map<byte [], WriterAndPath> logWriters =
new TreeMap<byte [], WriterAndPath>(Bytes.BYTES_COMPARATOR); new TreeMap<byte [], WriterAndPath>(Bytes.BYTES_COMPARATOR);
@ -848,11 +849,12 @@ public class HLog implements HConstants, Syncable {
// More means faster but bigger mem consumption */ // More means faster but bigger mem consumption */
int concurrentLogReads = int concurrentLogReads =
conf.getInt("hbase.regionserver.hlog.splitlog.reader.threads", 3); conf.getInt("hbase.regionserver.hlog.splitlog.reader.threads", 3);
// Is append supported?
boolean append = isAppend(conf);
try { try {
int maxSteps = Double.valueOf(Math.ceil((logfiles.length * 1.0) / int maxSteps = Double.valueOf(Math.ceil((logfiles.length * 1.0) /
concurrentLogReads)).intValue(); concurrentLogReads)).intValue();
for(int step = 0; step < maxSteps; step++) { for (int step = 0; step < maxSteps; step++) {
final Map<byte[], LinkedList<HLogEntry>> logEntries = final Map<byte[], LinkedList<HLogEntry>> logEntries =
new TreeMap<byte[], LinkedList<HLogEntry>>(Bytes.BYTES_COMPARATOR); new TreeMap<byte[], LinkedList<HLogEntry>>(Bytes.BYTES_COMPARATOR);
// Stop at logfiles.length when it's the last step // Stop at logfiles.length when it's the last step
@ -867,7 +869,6 @@ public class HLog implements HConstants, Syncable {
LOG.debug("Splitting hlog " + (i + 1) + " of " + logfiles.length + LOG.debug("Splitting hlog " + (i + 1) + " of " + logfiles.length +
": " + logfiles[i].getPath() + ", length=" + logfiles[i].getLen()); ": " + logfiles[i].getPath() + ", length=" + logfiles[i].getLen());
} }
boolean append = conf.getBoolean("dfs.support.append", false);
recoverLog(fs, logfiles[i].getPath(), append); recoverLog(fs, logfiles[i].getPath(), append);
SequenceFile.Reader in = null; SequenceFile.Reader in = null;
int count = 0; int count = 0;
@ -1021,6 +1022,24 @@ public class HLog implements HConstants, Syncable {
return splits; return splits;
} }
/**
* @param conf
* @return True if append enabled and we have the syncFs in our path.
*/
private static boolean isAppend(final HBaseConfiguration conf) {
boolean append = conf.getBoolean("dfs.support.append", false);
if (append) {
try {
SequenceFile.Writer.class.getMethod("syncFs", new Class<?> []{});
append = true;
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
append = false;
}
}
return append;
}
/** /**
* Utility class that lets us keep track of the edit with it's key * Utility class that lets us keep track of the edit with it's key
* Only used when splitting logs * Only used when splitting logs
@ -1158,10 +1177,9 @@ public class HLog implements HConstants, Syncable {
System.exit(-1); System.exit(-1);
} }
} }
Configuration conf = new HBaseConfiguration(); HBaseConfiguration conf = new HBaseConfiguration();
FileSystem fs = FileSystem.get(conf); FileSystem fs = FileSystem.get(conf);
Path baseDir = new Path(conf.get(HBASE_DIR)); Path baseDir = new Path(conf.get(HBASE_DIR));
for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
Path logPath = new Path(args[i]); Path logPath = new Path(args[i]);
if (!fs.exists(logPath)) { if (!fs.exists(logPath)) {

View File

@ -110,7 +110,7 @@ public class HRegion implements HConstants, HeapSize { // , Writable{
* master as a region to close if the carrying regionserver is overloaded. * master as a region to close if the carrying regionserver is overloaded.
* Once set, it is never cleared. * Once set, it is never cleared.
*/ */
private final AtomicBoolean closing = new AtomicBoolean(false); final AtomicBoolean closing = new AtomicBoolean(false);
private final RegionHistorian historian; private final RegionHistorian historian;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -1671,8 +1671,6 @@ public class HRegion implements HConstants, HeapSize { // , Writable{
return this.basedir; return this.basedir;
} }
//TODO
/** /**
* RegionScanner is an iterator through a bunch of rows in an HRegion. * RegionScanner is an iterator through a bunch of rows in an HRegion.
* <p> * <p>
@ -1710,9 +1708,15 @@ public class HRegion implements HConstants, HeapSize { // , Writable{
* Get the next row of results from this region. * Get the next row of results from this region.
* @param results list to append results to * @param results list to append results to
* @return true if there are more rows, false if scanner is done * @return true if there are more rows, false if scanner is done
* @throws NotServerRegionException If this region is closing or closed
*/ */
public boolean next(List<KeyValue> results) public boolean next(List<KeyValue> results)
throws IOException { throws IOException {
if (closing.get() || closed.get()) {
close();
throw new NotServingRegionException(regionInfo.getRegionNameAsString() +
" is closing=" + closing.get() + " or closed=" + closed.get());
}
// This method should probably be reorganized a bit... has gotten messy // This method should probably be reorganized a bit... has gotten messy
KeyValue kv = this.storeHeap.peek(); KeyValue kv = this.storeHeap.peek();
if (kv == null) { if (kv == null) {

View File

@ -803,7 +803,7 @@ public class HRegionServer implements HConstants, HRegionInterface,
*/ */
private Throwable cleanup(final Throwable t, final String msg) { private Throwable cleanup(final Throwable t, final String msg) {
if (msg == null) { if (msg == null) {
LOG.error(RemoteExceptionHandler.checkThrowable(t)); LOG.error("", RemoteExceptionHandler.checkThrowable(t));
} else { } else {
LOG.error(msg, RemoteExceptionHandler.checkThrowable(t)); LOG.error(msg, RemoteExceptionHandler.checkThrowable(t));
} }
@ -1890,7 +1890,7 @@ public class HRegionServer implements HConstants, HRegionInterface,
public Result [] next(final long scannerId, int nbRows) throws IOException { public Result [] next(final long scannerId, int nbRows) throws IOException {
try { try {
String scannerName = String.valueOf(scannerId); String scannerName = String.valueOf(scannerId);
InternalScanner s = scanners.get(scannerName); InternalScanner s = this.scanners.get(scannerName);
if (s == null) { if (s == null) {
throw new UnknownScannerException("Name: " + scannerName); throw new UnknownScannerException("Name: " + scannerName);
} }
@ -1918,6 +1918,9 @@ public class HRegionServer implements HConstants, HRegionInterface,
} }
return results.toArray(new Result[0]); return results.toArray(new Result[0]);
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof NotServingRegionException) {
this.scanners.remove(scannerId);
}
throw convertThrowableToIOE(cleanup(t)); throw convertThrowableToIOE(cleanup(t));
} }
} }
@ -1978,9 +1981,9 @@ public class HRegionServer implements HConstants, HRegionInterface,
boolean writeToWAL = true; boolean writeToWAL = true;
this.cacheFlusher.reclaimMemStoreMemory(); this.cacheFlusher.reclaimMemStoreMemory();
this.requestCount.incrementAndGet(); this.requestCount.incrementAndGet();
Integer lock = getLockFromId(delete.getLockId()); Integer lid = getLockFromId(delete.getLockId());
HRegion region = getRegion(regionName); HRegion region = getRegion(regionName);
region.delete(delete, lock, writeToWAL); region.delete(delete, lid, writeToWAL);
} catch(WrongRegionException ex) { } catch(WrongRegionException ex) {
} catch (NotServingRegionException ex) { } catch (NotServingRegionException ex) {
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -21,7 +21,10 @@ package org.apache.hadoop.hbase.client;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.HBaseClusterTestCase; import org.apache.hadoop.hbase.HBaseClusterTestCase;
import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
@ -34,6 +37,7 @@ import org.apache.hadoop.hbase.util.Bytes;
* Tests forced splitting of HTable * Tests forced splitting of HTable
*/ */
public class TestForceSplit extends HBaseClusterTestCase { public class TestForceSplit extends HBaseClusterTestCase {
static final Log LOG = LogFactory.getLog(TestForceSplit.class);
private static final byte[] tableName = Bytes.toBytes("test"); private static final byte[] tableName = Bytes.toBytes("test");
private static final byte[] columnName = Bytes.toBytes("a:"); private static final byte[] columnName = Bytes.toBytes("a:");
@ -44,7 +48,7 @@ public class TestForceSplit extends HBaseClusterTestCase {
} }
/** /**
* the test * Tests forcing split from client and having scanners successfully ride over split.
* @throws Exception * @throws Exception
* @throws IOException * @throws IOException
*/ */
@ -55,7 +59,7 @@ public class TestForceSplit extends HBaseClusterTestCase {
htd.addFamily(new HColumnDescriptor(columnName)); htd.addFamily(new HColumnDescriptor(columnName));
HBaseAdmin admin = new HBaseAdmin(conf); HBaseAdmin admin = new HBaseAdmin(conf);
admin.createTable(htd); admin.createTable(htd);
HTable table = new HTable(conf, tableName); final HTable table = new HTable(conf, tableName);
byte[] k = new byte[3]; byte[] k = new byte[3];
int rowCount = 0; int rowCount = 0;
for (byte b1 = 'a'; b1 < 'z'; b1++) { for (byte b1 = 'a'; b1 < 'z'; b1++) {
@ -88,31 +92,50 @@ public class TestForceSplit extends HBaseClusterTestCase {
scanner.close(); scanner.close();
assertEquals(rowCount, rows); assertEquals(rowCount, rows);
// tell the master to split the table // Have an outstanding scan going on to make sure we can scan over splits.
admin.split(Bytes.toString(tableName));
// give some time for the split to happen
Thread.sleep(15 * 1000);
// check again table = new HTable(conf, tableName);
m = table.getRegionsInfo();
System.out.println("Regions after split (" + m.size() + "): " + m);
// should have two regions now
assertTrue(m.size() == 2);
// Verify row count
scan = new Scan(); scan = new Scan();
scanner = table.getScanner(scan); scanner = table.getScanner(scan);
rows = 0; // Scan first row so we are into first region before split happens.
for(Result result : scanner) { scanner.next();
final AtomicInteger count = new AtomicInteger(0);
Thread t = new Thread("CheckForSplit") {
public void run() {
for (int i = 0; i < 20; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
continue;
}
// check again table = new HTable(conf, tableName);
Map<HRegionInfo, HServerAddress> regions = null;
try {
regions = table.getRegionsInfo();
} catch (IOException e) {
e.printStackTrace();
}
if (regions == null) continue;
count.set(regions.size());
if (count.get() >= 2) break;
LOG.debug("Cycle waiting on split");
}
}
};
t.start();
// tell the master to split the table
admin.split(Bytes.toString(tableName));
t.join();
// Verify row count
rows = 1; // We counted one row above.
for (Result result : scanner) {
rows++; rows++;
if(rows > rowCount) { if (rows > rowCount) {
scanner.close(); scanner.close();
assertTrue("Have already scanned more rows than expected (" + assertTrue("Scanned more than expected (" + rowCount + ")", false);
rowCount + ")", false);
} }
} }
scanner.close(); scanner.close();
assertEquals(rowCount, rows); assertEquals(rowCount, rows);
} }
} }