HBASE-27 hregioninfo cell empty in meta table
Summary of changes: HMaster: - When a row has an empty HRegionInfo (info:regioninfo), log it with the row name and and the other keys still in the row. - Log the number of rows with empty HRegionInfo - Delete the rows - Make RowMap inner class static, change methods to have package scope to avoid synthetic accessors. - Provide row name to getHRegionInfo so it can issue better log messages - add method deleteEmptyMetaRows to remove rows with empty HRegionInfo HRegion - change removeRegionFromMETA to use deleteAll rather than using a BatchUpdate containing deletes for each cell. TestEmptyMetaInfo - new test case git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@636589 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6fb7767fc6
commit
9057e559a1
|
@ -37,6 +37,7 @@ Hbase Change Log
|
||||||
HBASE-495 No server address listed in .META.
|
HBASE-495 No server address listed in .META.
|
||||||
HBASE-433 HBASE-251 Region server should delete restore log after successful
|
HBASE-433 HBASE-251 Region server should delete restore log after successful
|
||||||
restore, Stuck replaying the edits of crashed machine.
|
restore, Stuck replaying the edits of crashed machine.
|
||||||
|
HBASE-27 hregioninfo cell empty in meta table
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
HBASE-415 Rewrite leases to use DelayedBlockingQueue instead of polling
|
HBASE-415 Rewrite leases to use DelayedBlockingQueue instead of polling
|
||||||
|
|
|
@ -21,7 +21,8 @@ package org.apache.hadoop.hbase.master;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.SortedMap;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ -36,7 +37,6 @@ import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
import org.apache.hadoop.hbase.HServerInfo;
|
import org.apache.hadoop.hbase.HServerInfo;
|
||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.io.HbaseMapWritable;
|
|
||||||
import org.apache.hadoop.hbase.util.Writables;
|
import org.apache.hadoop.hbase.util.Writables;
|
||||||
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
||||||
import org.apache.hadoop.hbase.UnknownScannerException;
|
import org.apache.hadoop.hbase.UnknownScannerException;
|
||||||
|
@ -124,6 +124,7 @@ abstract class BaseScanner extends Chore implements HConstants {
|
||||||
this.initialScanComplete = false;
|
this.initialScanComplete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return true if initial scan completed successfully */
|
||||||
public boolean isInitialScanComplete() {
|
public boolean isInitialScanComplete() {
|
||||||
return initialScanComplete;
|
return initialScanComplete;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +153,7 @@ abstract class BaseScanner extends Chore implements HConstants {
|
||||||
// scan we go check if parents can be removed.
|
// scan we go check if parents can be removed.
|
||||||
Map<HRegionInfo, RowResult> splitParents =
|
Map<HRegionInfo, RowResult> splitParents =
|
||||||
new HashMap<HRegionInfo, RowResult>();
|
new HashMap<HRegionInfo, RowResult>();
|
||||||
|
List<Text> emptyRows = new ArrayList<Text>();
|
||||||
try {
|
try {
|
||||||
regionServer = master.connection.getHRegionConnection(region.getServer());
|
regionServer = master.connection.getHRegionConnection(region.getServer());
|
||||||
scannerId =
|
scannerId =
|
||||||
|
@ -165,8 +167,9 @@ abstract class BaseScanner extends Chore implements HConstants {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRegionInfo info = master.getHRegionInfo(values);
|
HRegionInfo info = master.getHRegionInfo(values.getRow(), values);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
|
emptyRows.add(values.getRow());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +213,20 @@ abstract class BaseScanner extends Chore implements HConstants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan is finished. Take a look at split parents to see if any we can
|
// Scan is finished.
|
||||||
// clean up.
|
|
||||||
|
// First clean up any meta region rows which had null HRegionInfos
|
||||||
|
|
||||||
|
if (emptyRows.size() > 0) {
|
||||||
|
LOG.warn("Found " + emptyRows.size() +
|
||||||
|
" rows with empty HRegionInfo while scanning meta region " +
|
||||||
|
region.getRegionName());
|
||||||
|
master.deleteEmptyMetaRows(regionServer, region.getRegionName(),
|
||||||
|
emptyRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a look at split parents to see if any we can clean up.
|
||||||
|
|
||||||
if (splitParents.size() > 0) {
|
if (splitParents.size() > 0) {
|
||||||
for (Map.Entry<HRegionInfo, RowResult> e : splitParents.entrySet()) {
|
for (Map.Entry<HRegionInfo, RowResult> e : splitParents.entrySet()) {
|
||||||
HRegionInfo hri = e.getKey();
|
HRegionInfo hri = e.getKey();
|
||||||
|
@ -289,7 +304,7 @@ abstract class BaseScanner extends Chore implements HConstants {
|
||||||
* @return True if still has references to parent.
|
* @return True if still has references to parent.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected boolean hasReferences(final Text metaRegionName,
|
private boolean hasReferences(final Text metaRegionName,
|
||||||
final HRegionInterface srvr, final Text parent,
|
final HRegionInterface srvr, final Text parent,
|
||||||
RowResult rowContent, final Text splitColumn)
|
RowResult rowContent, final Text splitColumn)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -21,49 +21,38 @@ package org.apache.hadoop.hbase.master;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.DelayQueue;
|
import java.util.concurrent.DelayQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
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.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.hbase.io.BatchUpdate;
|
|
||||||
import org.apache.hadoop.hbase.io.Cell;
|
import org.apache.hadoop.hbase.io.Cell;
|
||||||
import org.apache.hadoop.hbase.io.RowResult;
|
import org.apache.hadoop.hbase.io.RowResult;
|
||||||
import org.apache.hadoop.hbase.ipc.HbaseRPC;
|
import org.apache.hadoop.hbase.ipc.HbaseRPC;
|
||||||
import org.apache.hadoop.hbase.util.FSUtils;
|
import org.apache.hadoop.hbase.util.FSUtils;
|
||||||
import org.apache.hadoop.hbase.util.InfoServer;
|
import org.apache.hadoop.hbase.util.InfoServer;
|
||||||
import org.apache.hadoop.hbase.util.Sleeper;
|
import org.apache.hadoop.hbase.util.Sleeper;
|
||||||
import org.apache.hadoop.hbase.util.Threads;
|
|
||||||
import org.apache.hadoop.hbase.util.Writables;
|
import org.apache.hadoop.hbase.util.Writables;
|
||||||
import org.apache.hadoop.hbase.io.HbaseMapWritable;
|
import org.apache.hadoop.hbase.io.HbaseMapWritable;
|
||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
import org.apache.hadoop.io.Writable;
|
|
||||||
import org.apache.hadoop.ipc.RemoteException;
|
import org.apache.hadoop.ipc.RemoteException;
|
||||||
import org.apache.hadoop.ipc.Server;
|
import org.apache.hadoop.ipc.Server;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.HBaseConfiguration;
|
import org.apache.hadoop.hbase.HBaseConfiguration;
|
||||||
import org.apache.hadoop.hbase.HStoreKey;
|
import org.apache.hadoop.hbase.HStoreKey;
|
||||||
import org.apache.hadoop.hbase.Leases;
|
|
||||||
import org.apache.hadoop.hbase.HServerAddress;
|
import org.apache.hadoop.hbase.HServerAddress;
|
||||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||||
|
@ -75,7 +64,6 @@ import org.apache.hadoop.hbase.LocalHBaseCluster;
|
||||||
import org.apache.hadoop.hbase.HServerInfo;
|
import org.apache.hadoop.hbase.HServerInfo;
|
||||||
import org.apache.hadoop.hbase.TableExistsException;
|
import org.apache.hadoop.hbase.TableExistsException;
|
||||||
import org.apache.hadoop.hbase.MasterNotRunningException;
|
import org.apache.hadoop.hbase.MasterNotRunningException;
|
||||||
import org.apache.hadoop.hbase.LeaseListener;
|
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.client.HConnection;
|
import org.apache.hadoop.hbase.client.HConnection;
|
||||||
import org.apache.hadoop.hbase.client.HConnectionManager;
|
import org.apache.hadoop.hbase.client.HConnectionManager;
|
||||||
|
@ -320,6 +308,9 @@ public class HMaster extends Thread implements HConstants, HMasterInterface,
|
||||||
return rootServer;
|
return rootServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until root region is available
|
||||||
|
*/
|
||||||
public void waitForRootRegionLocation() {
|
public void waitForRootRegionLocation() {
|
||||||
regionManager.waitForRootRegionLocation();
|
regionManager.waitForRootRegionLocation();
|
||||||
}
|
}
|
||||||
|
@ -471,7 +462,6 @@ public class HMaster extends Thread implements HConstants, HMasterInterface,
|
||||||
* need to install an unexpected exception handler.
|
* need to install an unexpected exception handler.
|
||||||
*/
|
*/
|
||||||
private void startServiceThreads() {
|
private void startServiceThreads() {
|
||||||
String threadName = Thread.currentThread().getName();
|
|
||||||
try {
|
try {
|
||||||
regionManager.start();
|
regionManager.start();
|
||||||
serverManager.start();
|
serverManager.start();
|
||||||
|
@ -693,21 +683,45 @@ public class HMaster extends Thread implements HConstants, HMasterInterface,
|
||||||
* Get HRegionInfo from passed META map of row values.
|
* Get HRegionInfo from passed META map of row values.
|
||||||
* Returns null if none found (and logs fact that expected COL_REGIONINFO
|
* Returns null if none found (and logs fact that expected COL_REGIONINFO
|
||||||
* was missing). Utility method used by scanners of META tables.
|
* was missing). Utility method used by scanners of META tables.
|
||||||
|
* @param row name of the row
|
||||||
* @param map Map to do lookup in.
|
* @param map Map to do lookup in.
|
||||||
* @return Null or found HRegionInfo.
|
* @return Null or found HRegionInfo.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
HRegionInfo getHRegionInfo(final Map<Text, Cell> map)
|
HRegionInfo getHRegionInfo(final Text row, final Map<Text, Cell> map)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Cell regioninfo = map.get(COL_REGIONINFO);
|
Cell regioninfo = map.get(COL_REGIONINFO);
|
||||||
if (regioninfo == null) {
|
if (regioninfo == null) {
|
||||||
LOG.warn(COL_REGIONINFO.toString() + " is empty; has keys: " +
|
LOG.warn(COL_REGIONINFO.toString() + " is empty for row: " + row +
|
||||||
map.keySet().toString());
|
"; has keys: " + map.keySet().toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (HRegionInfo)Writables.getWritable(regioninfo.getValue(), new HRegionInfo());
|
return (HRegionInfo)Writables.getWritable(regioninfo.getValue(), new HRegionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we find rows in a meta region that has an empty HRegionInfo, we
|
||||||
|
* clean them up here.
|
||||||
|
*
|
||||||
|
* @param server connection to server serving meta region
|
||||||
|
* @param metaRegionName name of the meta region we scanned
|
||||||
|
* @param emptyRows the row keys that had empty HRegionInfos
|
||||||
|
*/
|
||||||
|
protected void deleteEmptyMetaRows(HRegionInterface server,
|
||||||
|
Text metaRegionName,
|
||||||
|
List<Text> emptyRows) {
|
||||||
|
for (Text regionName: emptyRows) {
|
||||||
|
try {
|
||||||
|
HRegion.removeRegionFromMETA(server, metaRegionName, regionName);
|
||||||
|
LOG.warn("Removed region: " + regionName + " from meta region: " +
|
||||||
|
metaRegionName + " because HRegionInfo was empty");
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("deleting region: " + regionName + " from meta region: " +
|
||||||
|
metaRegionName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main program
|
* Main program
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,14 +24,13 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedMap;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.hbase.HRegionInfo;
|
import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
import org.apache.hadoop.hbase.HServerAddress;
|
import org.apache.hadoop.hbase.HServerAddress;
|
||||||
import org.apache.hadoop.hbase.HServerInfo;
|
import org.apache.hadoop.hbase.HServerInfo;
|
||||||
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
||||||
import org.apache.hadoop.hbase.io.HbaseMapWritable;
|
|
||||||
import org.apache.hadoop.hbase.ipc.HRegionInterface;
|
import org.apache.hadoop.hbase.ipc.HRegionInterface;
|
||||||
import org.apache.hadoop.hbase.regionserver.HLog;
|
import org.apache.hadoop.hbase.regionserver.HLog;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
|
@ -66,6 +65,7 @@ class ProcessServerShutdown extends RegionServerOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param master
|
||||||
* @param serverInfo
|
* @param serverInfo
|
||||||
*/
|
*/
|
||||||
public ProcessServerShutdown(HMaster master, HServerInfo serverInfo) {
|
public ProcessServerShutdown(HMaster master, HServerInfo serverInfo) {
|
||||||
|
@ -93,9 +93,9 @@ class ProcessServerShutdown extends RegionServerOperation {
|
||||||
private void scanMetaRegion(HRegionInterface server, long scannerId,
|
private void scanMetaRegion(HRegionInterface server, long scannerId,
|
||||||
Text regionName) throws IOException {
|
Text regionName) throws IOException {
|
||||||
|
|
||||||
ArrayList<ToDoEntry> toDoList = new ArrayList<ToDoEntry>();
|
List<ToDoEntry> toDoList = new ArrayList<ToDoEntry>();
|
||||||
HashSet<HRegionInfo> regions = new HashSet<HRegionInfo>();
|
Set<HRegionInfo> regions = new HashSet<HRegionInfo>();
|
||||||
|
List<Text> emptyRows = new ArrayList<Text>();
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
RowResult values = null;
|
RowResult values = null;
|
||||||
|
@ -133,8 +133,9 @@ class ProcessServerShutdown extends RegionServerOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bingo! Found it.
|
// Bingo! Found it.
|
||||||
HRegionInfo info = master.getHRegionInfo(values);
|
HRegionInfo info = master.getHRegionInfo(row, values);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
|
emptyRows.add(row);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +181,14 @@ class ProcessServerShutdown extends RegionServerOperation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan complete. Remove any rows which had empty HRegionInfos
|
||||||
|
|
||||||
|
if (emptyRows.size() > 0) {
|
||||||
|
LOG.warn("Found " + emptyRows.size() +
|
||||||
|
" rows with empty HRegionInfo while scanning meta region " +
|
||||||
|
regionName);
|
||||||
|
master.deleteEmptyMetaRows(server, regionName, emptyRows);
|
||||||
|
}
|
||||||
// Update server in root/meta entries
|
// Update server in root/meta entries
|
||||||
for (ToDoEntry e: toDoList) {
|
for (ToDoEntry e: toDoList) {
|
||||||
if (e.deleteRegion) {
|
if (e.deleteRegion) {
|
||||||
|
|
|
@ -36,10 +36,10 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
|
||||||
* Data structure used to return results out of the toRowMap method.
|
* Data structure used to return results out of the toRowMap method.
|
||||||
*/
|
*/
|
||||||
class RowMap {
|
class RowMap {
|
||||||
static final Log LOG = LogFactory.getLog(RowMap.class.getName());
|
private static final Log LOG = LogFactory.getLog(RowMap.class.getName());
|
||||||
|
|
||||||
final Text row;
|
private final Text row;
|
||||||
final SortedMap<Text, byte[]> map;
|
private final SortedMap<Text, byte[]> map;
|
||||||
|
|
||||||
RowMap(final Text r, final SortedMap<Text, byte[]> m) {
|
RowMap(final Text r, final SortedMap<Text, byte[]> m) {
|
||||||
this.row = r;
|
this.row = r;
|
||||||
|
@ -61,7 +61,7 @@ class RowMap {
|
||||||
* @return Returns a SortedMap currently. TODO: This looks like it could
|
* @return Returns a SortedMap currently. TODO: This looks like it could
|
||||||
* be a plain Map.
|
* be a plain Map.
|
||||||
*/
|
*/
|
||||||
public static RowMap fromHbaseMapWritable(HbaseMapWritable mw) {
|
static RowMap fromHbaseMapWritable(HbaseMapWritable mw) {
|
||||||
if (mw == null) {
|
if (mw == null) {
|
||||||
throw new IllegalArgumentException("Passed MapWritable cannot be null");
|
throw new IllegalArgumentException("Passed MapWritable cannot be null");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.apache.hadoop.hbase.master;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -51,11 +50,11 @@ class ServerManager implements HConstants {
|
||||||
static final Log LOG = LogFactory.getLog(ServerManager.class.getName());
|
static final Log LOG = LogFactory.getLog(ServerManager.class.getName());
|
||||||
|
|
||||||
/** The map of known server names to server info */
|
/** The map of known server names to server info */
|
||||||
private final Map<String, HServerInfo> serversToServerInfo =
|
final Map<String, HServerInfo> serversToServerInfo =
|
||||||
new ConcurrentHashMap<String, HServerInfo>();
|
new ConcurrentHashMap<String, HServerInfo>();
|
||||||
|
|
||||||
/** Set of known dead servers */
|
/** Set of known dead servers */
|
||||||
private final Set<String> deadServers =
|
final Set<String> deadServers =
|
||||||
Collections.synchronizedSet(new HashSet<String>());
|
Collections.synchronizedSet(new HashSet<String>());
|
||||||
|
|
||||||
/** SortedMap server load -> Set of server names */
|
/** SortedMap server load -> Set of server names */
|
||||||
|
@ -63,20 +62,27 @@ class ServerManager implements HConstants {
|
||||||
Collections.synchronizedSortedMap(new TreeMap<HServerLoad, Set<String>>());
|
Collections.synchronizedSortedMap(new TreeMap<HServerLoad, Set<String>>());
|
||||||
|
|
||||||
/** Map of server names -> server load */
|
/** Map of server names -> server load */
|
||||||
private final Map<String, HServerLoad> serversToLoad =
|
final Map<String, HServerLoad> serversToLoad =
|
||||||
new ConcurrentHashMap<String, HServerLoad>();
|
new ConcurrentHashMap<String, HServerLoad>();
|
||||||
|
|
||||||
private HMaster master;
|
HMaster master;
|
||||||
|
|
||||||
private final Leases serverLeases;
|
private final Leases serverLeases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param master
|
||||||
|
*/
|
||||||
public ServerManager(HMaster master) {
|
public ServerManager(HMaster master) {
|
||||||
this.master = master;
|
this.master = master;
|
||||||
serverLeases = new Leases(master.leaseTimeout,
|
serverLeases = new Leases(master.leaseTimeout,
|
||||||
master.conf.getInt("hbase.master.lease.thread.wakefrequency", 15 * 1000));
|
master.conf.getInt("hbase.master.lease.thread.wakefrequency", 15 * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Let the server manager know a new regionserver has come online */
|
/**
|
||||||
|
* Let the server manager know a new regionserver has come online
|
||||||
|
*
|
||||||
|
* @param serverInfo
|
||||||
|
*/
|
||||||
public void regionServerStartup(HServerInfo serverInfo) {
|
public void regionServerStartup(HServerInfo serverInfo) {
|
||||||
String s = serverInfo.getServerAddress().toString().trim();
|
String s = serverInfo.getServerAddress().toString().trim();
|
||||||
LOG.info("received start message from: " + s);
|
LOG.info("received start message from: " + s);
|
||||||
|
@ -121,7 +127,14 @@ class ServerManager implements HConstants {
|
||||||
loadToServers.put(load, servers);
|
loadToServers.put(load, servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/**
|
||||||
|
* @param serverInfo
|
||||||
|
* @param msgs
|
||||||
|
* @return messages from master to region server indicating what region
|
||||||
|
* server should do.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public HMsg[] regionServerReport(HServerInfo serverInfo, HMsg msgs[])
|
public HMsg[] regionServerReport(HServerInfo serverInfo, HMsg msgs[])
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String serverName = serverInfo.getServerAddress().toString().trim();
|
String serverName = serverInfo.getServerAddress().toString().trim();
|
||||||
|
@ -377,7 +390,16 @@ class ServerManager implements HConstants {
|
||||||
return returnMsgs.toArray(new HMsg[returnMsgs.size()]);
|
return returnMsgs.toArray(new HMsg[returnMsgs.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A region has split. **/
|
/**
|
||||||
|
* A region has split.
|
||||||
|
*
|
||||||
|
* @param serverName
|
||||||
|
* @param serverInfo
|
||||||
|
* @param region
|
||||||
|
* @param splitA
|
||||||
|
* @param splitB
|
||||||
|
* @param returnMsgs
|
||||||
|
*/
|
||||||
private void processSplitRegion(String serverName, HServerInfo serverInfo,
|
private void processSplitRegion(String serverName, HServerInfo serverInfo,
|
||||||
HRegionInfo region, HMsg splitA, HMsg splitB, ArrayList<HMsg> returnMsgs) {
|
HRegionInfo region, HMsg splitA, HMsg splitB, ArrayList<HMsg> returnMsgs) {
|
||||||
|
|
||||||
|
@ -467,54 +489,6 @@ class ServerManager implements HConstants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Region server reporting that it has closed a region */
|
|
||||||
private void processRegionClose(String serverName, HServerInfo info,
|
|
||||||
HRegionInfo region) {
|
|
||||||
LOG.info(info.getServerAddress().toString() + " no longer serving " +
|
|
||||||
region.getRegionName());
|
|
||||||
|
|
||||||
if (region.isRootRegion()) {
|
|
||||||
if (region.isOffline()) {
|
|
||||||
// Can't proceed without root region. Shutdown.
|
|
||||||
LOG.fatal("root region is marked offline");
|
|
||||||
master.shutdown();
|
|
||||||
}
|
|
||||||
master.regionManager.unassignRootRegion();
|
|
||||||
} else {
|
|
||||||
boolean reassignRegion = !region.isOffline();
|
|
||||||
boolean deleteRegion = false;
|
|
||||||
|
|
||||||
if (master.regionManager.isClosing(region.getRegionName())) {
|
|
||||||
master.regionManager.noLongerClosing(region.getRegionName());
|
|
||||||
reassignRegion = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (master.regionManager.isMarkedForDeletion(region.getRegionName())) {
|
|
||||||
master.regionManager.regionDeleted(region.getRegionName());
|
|
||||||
reassignRegion = false;
|
|
||||||
deleteRegion = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (region.isMetaTable()) {
|
|
||||||
// Region is part of the meta table. Remove it from onlineMetaRegions
|
|
||||||
master.regionManager.offlineMetaRegion(region.getStartKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: we cannot put the region into unassignedRegions as that
|
|
||||||
// could create a race with the pending close if it gets
|
|
||||||
// reassigned before the close is processed.
|
|
||||||
master.regionManager.noLongerUnassigned(region);
|
|
||||||
|
|
||||||
try {
|
|
||||||
master.toDoQueue.put(new ProcessRegionClose(master, region, reassignRegion,
|
|
||||||
deleteRegion));
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Putting into toDoQueue was interrupted.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cancel a server's lease and update its load information */
|
/** Cancel a server's lease and update its load information */
|
||||||
private boolean cancelLease(final String serverName) {
|
private boolean cancelLease(final String serverName) {
|
||||||
boolean leaseCancelled = false;
|
boolean leaseCancelled = false;
|
||||||
|
@ -544,16 +518,20 @@ class ServerManager implements HConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** compute the average load across all region servers */
|
/** @return the average load across all region servers */
|
||||||
public int averageLoad() {
|
public int averageLoad() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the number of active servers */
|
||||||
public int numServers() {
|
public int numServers() {
|
||||||
return serversToServerInfo.size();
|
return serversToServerInfo.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get HServerInfo from a server address */
|
/**
|
||||||
|
* @param address server address
|
||||||
|
* @return HServerInfo for the given server address
|
||||||
|
*/
|
||||||
public HServerInfo getServerInfo(String address) {
|
public HServerInfo getServerInfo(String address) {
|
||||||
return serversToServerInfo.get(address);
|
return serversToServerInfo.get(address);
|
||||||
}
|
}
|
||||||
|
@ -579,6 +557,9 @@ class ServerManager implements HConstants {
|
||||||
return Collections.unmodifiableMap(loadToServers);
|
return Collections.unmodifiableMap(loadToServers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wakes up threads waiting on serversToServerInfo
|
||||||
|
*/
|
||||||
public void notifyServers() {
|
public void notifyServers() {
|
||||||
synchronized (serversToServerInfo) {
|
synchronized (serversToServerInfo) {
|
||||||
serversToServerInfo.notifyAll();
|
serversToServerInfo.notifyAll();
|
||||||
|
@ -666,10 +647,17 @@ class ServerManager implements HConstants {
|
||||||
serverLeases.close();
|
serverLeases.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param serverName
|
||||||
|
*/
|
||||||
public void removeDeadServer(String serverName) {
|
public void removeDeadServer(String serverName) {
|
||||||
deadServers.remove(serverName);
|
deadServers.remove(serverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param serverName
|
||||||
|
* @return true if server is dead
|
||||||
|
*/
|
||||||
public boolean isDead(String serverName) {
|
public boolean isDead(String serverName) {
|
||||||
return deadServers.contains(serverName);
|
return deadServers.contains(serverName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
package org.apache.hadoop.hbase.master;
|
package org.apache.hadoop.hbase.master;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -32,10 +33,8 @@ import org.apache.hadoop.hbase.ipc.HRegionInterface;
|
||||||
import org.apache.hadoop.hbase.HServerInfo;
|
import org.apache.hadoop.hbase.HServerInfo;
|
||||||
import org.apache.hadoop.hbase.MasterNotRunningException;
|
import org.apache.hadoop.hbase.MasterNotRunningException;
|
||||||
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
||||||
import org.apache.hadoop.hbase.io.HbaseMapWritable;
|
|
||||||
import org.apache.hadoop.hbase.util.Writables;
|
import org.apache.hadoop.hbase.util.Writables;
|
||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
import org.apache.hadoop.hbase.io.Cell;
|
|
||||||
import org.apache.hadoop.hbase.io.RowResult;
|
import org.apache.hadoop.hbase.io.RowResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,14 +94,17 @@ abstract class TableOperation implements HConstants {
|
||||||
server.openScanner(m.getRegionName(), COLUMN_FAMILY_ARRAY,
|
server.openScanner(m.getRegionName(), COLUMN_FAMILY_ARRAY,
|
||||||
tableName, System.currentTimeMillis(), null);
|
tableName, System.currentTimeMillis(), null);
|
||||||
|
|
||||||
|
List<Text> emptyRows = new ArrayList<Text>();
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
RowResult values = server.next(scannerId);
|
RowResult values = server.next(scannerId);
|
||||||
if(values == null || values.size() == 0) {
|
if(values == null || values.size() == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HRegionInfo info = this.master.getHRegionInfo(values);
|
HRegionInfo info =
|
||||||
|
this.master.getHRegionInfo(values.getRow(), values);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
|
emptyRows.add(values.getRow());
|
||||||
throw new IOException(COL_REGIONINFO + " not found on " +
|
throw new IOException(COL_REGIONINFO + " not found on " +
|
||||||
values.getRow());
|
values.getRow());
|
||||||
}
|
}
|
||||||
|
@ -132,6 +134,15 @@ abstract class TableOperation implements HConstants {
|
||||||
scannerId = -1L;
|
scannerId = -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get rid of any rows that have a null HRegionInfo
|
||||||
|
|
||||||
|
if (emptyRows.size() > 0) {
|
||||||
|
LOG.warn("Found " + emptyRows.size() +
|
||||||
|
" rows with empty HRegionInfo while scanning meta region " +
|
||||||
|
m.getRegionName());
|
||||||
|
master.deleteEmptyMetaRows(server, m.getRegionName(), emptyRows);
|
||||||
|
}
|
||||||
|
|
||||||
if (!tableExists) {
|
if (!tableExists) {
|
||||||
throw new IOException(tableName + " does not exist");
|
throw new IOException(tableName + " does not exist");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import org.apache.hadoop.io.Text;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hbase.client.HTable;
|
||||||
|
import org.apache.hadoop.hbase.io.BatchUpdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests master cleanup of rows in meta table where there is no HRegionInfo
|
||||||
|
*/
|
||||||
|
public class TestEmptyMetaInfo extends HBaseClusterTestCase {
|
||||||
|
/**
|
||||||
|
* Insert some bogus rows in meta. Master should clean them up.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void testEmptyMetaInfo() throws IOException {
|
||||||
|
HTable t = new HTable(conf, HConstants.META_TABLE_NAME);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Text regionName = new Text("tablename," + (i == 0 ? "" : (i +",")) +
|
||||||
|
System.currentTimeMillis());
|
||||||
|
BatchUpdate b = new BatchUpdate(regionName);
|
||||||
|
b.put(HConstants.COL_SERVER,
|
||||||
|
"localhost:1234".getBytes(HConstants.UTF8_ENCODING));
|
||||||
|
t.commit(b);
|
||||||
|
}
|
||||||
|
long sleepTime =
|
||||||
|
conf.getLong("hbase.master.meta.thread.rescanfrequency", 10000);
|
||||||
|
int tries = conf.getInt("hbase.client.retries.number", 5);
|
||||||
|
int count = 0;
|
||||||
|
do {
|
||||||
|
tries -= 1;
|
||||||
|
try {
|
||||||
|
Thread.sleep(sleepTime);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
HScannerInterface scanner =
|
||||||
|
t.obtainScanner(HConstants.ALL_META_COLUMNS, new Text("tablename"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
count = 0;
|
||||||
|
HStoreKey key = new HStoreKey();
|
||||||
|
SortedMap<Text, byte[]> results = new TreeMap<Text, byte[]>();
|
||||||
|
while (scanner.next(key, results)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
} while (count != 0 && tries >= 0);
|
||||||
|
assertTrue(tries >= 0);
|
||||||
|
assertEquals(0, count);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue