HBASE-8205. HBCK support for table locks
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1467497 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1c81734163
commit
af834c404f
|
@ -4925,6 +4925,10 @@ public final class ZooKeeperProtos {
|
||||||
// optional string purpose = 5;
|
// optional string purpose = 5;
|
||||||
boolean hasPurpose();
|
boolean hasPurpose();
|
||||||
String getPurpose();
|
String getPurpose();
|
||||||
|
|
||||||
|
// optional int64 createTime = 6;
|
||||||
|
boolean hasCreateTime();
|
||||||
|
long getCreateTime();
|
||||||
}
|
}
|
||||||
public static final class TableLock extends
|
public static final class TableLock extends
|
||||||
com.google.protobuf.GeneratedMessage
|
com.google.protobuf.GeneratedMessage
|
||||||
|
@ -5030,12 +5034,23 @@ public final class ZooKeeperProtos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional int64 createTime = 6;
|
||||||
|
public static final int CREATETIME_FIELD_NUMBER = 6;
|
||||||
|
private long createTime_;
|
||||||
|
public boolean hasCreateTime() {
|
||||||
|
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||||
|
}
|
||||||
|
public long getCreateTime() {
|
||||||
|
return createTime_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
tableName_ = com.google.protobuf.ByteString.EMPTY;
|
tableName_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
lockOwner_ = org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ServerName.getDefaultInstance();
|
lockOwner_ = org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ServerName.getDefaultInstance();
|
||||||
threadId_ = 0L;
|
threadId_ = 0L;
|
||||||
isShared_ = false;
|
isShared_ = false;
|
||||||
purpose_ = "";
|
purpose_ = "";
|
||||||
|
createTime_ = 0L;
|
||||||
}
|
}
|
||||||
private byte memoizedIsInitialized = -1;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
|
@ -5070,6 +5085,9 @@ public final class ZooKeeperProtos {
|
||||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||||
output.writeBytes(5, getPurposeBytes());
|
output.writeBytes(5, getPurposeBytes());
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
output.writeInt64(6, createTime_);
|
||||||
|
}
|
||||||
getUnknownFields().writeTo(output);
|
getUnknownFields().writeTo(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5099,6 +5117,10 @@ public final class ZooKeeperProtos {
|
||||||
size += com.google.protobuf.CodedOutputStream
|
size += com.google.protobuf.CodedOutputStream
|
||||||
.computeBytesSize(5, getPurposeBytes());
|
.computeBytesSize(5, getPurposeBytes());
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
size += com.google.protobuf.CodedOutputStream
|
||||||
|
.computeInt64Size(6, createTime_);
|
||||||
|
}
|
||||||
size += getUnknownFields().getSerializedSize();
|
size += getUnknownFields().getSerializedSize();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
|
@ -5147,6 +5169,11 @@ public final class ZooKeeperProtos {
|
||||||
result = result && getPurpose()
|
result = result && getPurpose()
|
||||||
.equals(other.getPurpose());
|
.equals(other.getPurpose());
|
||||||
}
|
}
|
||||||
|
result = result && (hasCreateTime() == other.hasCreateTime());
|
||||||
|
if (hasCreateTime()) {
|
||||||
|
result = result && (getCreateTime()
|
||||||
|
== other.getCreateTime());
|
||||||
|
}
|
||||||
result = result &&
|
result = result &&
|
||||||
getUnknownFields().equals(other.getUnknownFields());
|
getUnknownFields().equals(other.getUnknownFields());
|
||||||
return result;
|
return result;
|
||||||
|
@ -5176,6 +5203,10 @@ public final class ZooKeeperProtos {
|
||||||
hash = (37 * hash) + PURPOSE_FIELD_NUMBER;
|
hash = (37 * hash) + PURPOSE_FIELD_NUMBER;
|
||||||
hash = (53 * hash) + getPurpose().hashCode();
|
hash = (53 * hash) + getPurpose().hashCode();
|
||||||
}
|
}
|
||||||
|
if (hasCreateTime()) {
|
||||||
|
hash = (37 * hash) + CREATETIME_FIELD_NUMBER;
|
||||||
|
hash = (53 * hash) + hashLong(getCreateTime());
|
||||||
|
}
|
||||||
hash = (29 * hash) + getUnknownFields().hashCode();
|
hash = (29 * hash) + getUnknownFields().hashCode();
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
@ -5307,6 +5338,8 @@ public final class ZooKeeperProtos {
|
||||||
bitField0_ = (bitField0_ & ~0x00000008);
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
purpose_ = "";
|
purpose_ = "";
|
||||||
bitField0_ = (bitField0_ & ~0x00000010);
|
bitField0_ = (bitField0_ & ~0x00000010);
|
||||||
|
createTime_ = 0L;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000020);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5369,6 +5402,10 @@ public final class ZooKeeperProtos {
|
||||||
to_bitField0_ |= 0x00000010;
|
to_bitField0_ |= 0x00000010;
|
||||||
}
|
}
|
||||||
result.purpose_ = purpose_;
|
result.purpose_ = purpose_;
|
||||||
|
if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
to_bitField0_ |= 0x00000020;
|
||||||
|
}
|
||||||
|
result.createTime_ = createTime_;
|
||||||
result.bitField0_ = to_bitField0_;
|
result.bitField0_ = to_bitField0_;
|
||||||
onBuilt();
|
onBuilt();
|
||||||
return result;
|
return result;
|
||||||
|
@ -5400,6 +5437,9 @@ public final class ZooKeeperProtos {
|
||||||
if (other.hasPurpose()) {
|
if (other.hasPurpose()) {
|
||||||
setPurpose(other.getPurpose());
|
setPurpose(other.getPurpose());
|
||||||
}
|
}
|
||||||
|
if (other.hasCreateTime()) {
|
||||||
|
setCreateTime(other.getCreateTime());
|
||||||
|
}
|
||||||
this.mergeUnknownFields(other.getUnknownFields());
|
this.mergeUnknownFields(other.getUnknownFields());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -5466,6 +5506,11 @@ public final class ZooKeeperProtos {
|
||||||
purpose_ = input.readBytes();
|
purpose_ = input.readBytes();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 48: {
|
||||||
|
bitField0_ |= 0x00000020;
|
||||||
|
createTime_ = input.readInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5664,6 +5709,27 @@ public final class ZooKeeperProtos {
|
||||||
onChanged();
|
onChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional int64 createTime = 6;
|
||||||
|
private long createTime_ ;
|
||||||
|
public boolean hasCreateTime() {
|
||||||
|
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||||
|
}
|
||||||
|
public long getCreateTime() {
|
||||||
|
return createTime_;
|
||||||
|
}
|
||||||
|
public Builder setCreateTime(long value) {
|
||||||
|
bitField0_ |= 0x00000020;
|
||||||
|
createTime_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Builder clearCreateTime() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000020);
|
||||||
|
createTime_ = 0L;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:TableLock)
|
// @@protoc_insertion_point(builder_scope:TableLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5758,11 +5824,12 @@ public final class ZooKeeperProtos {
|
||||||
"tate.State\"\"\n\005State\022\013\n\007ENABLED\020\000\022\014\n\010DISA" +
|
"tate.State\"\"\n\005State\022\013\n\007ENABLED\020\000\022\014\n\010DISA" +
|
||||||
"BLED\020\001\"+\n\027ReplicationHLogPosition\022\020\n\010pos" +
|
"BLED\020\001\"+\n\027ReplicationHLogPosition\022\020\n\010pos" +
|
||||||
"ition\030\001 \002(\003\"$\n\017ReplicationLock\022\021\n\tlockOw" +
|
"ition\030\001 \002(\003\"$\n\017ReplicationLock\022\021\n\tlockOw" +
|
||||||
"ner\030\001 \002(\t\"s\n\tTableLock\022\021\n\ttableName\030\001 \001(",
|
"ner\030\001 \002(\t\"\207\001\n\tTableLock\022\021\n\ttableName\030\001 \001",
|
||||||
"\014\022\036\n\tlockOwner\030\002 \001(\0132\013.ServerName\022\020\n\010thr" +
|
"(\014\022\036\n\tlockOwner\030\002 \001(\0132\013.ServerName\022\020\n\010th" +
|
||||||
"eadId\030\003 \001(\003\022\020\n\010isShared\030\004 \001(\010\022\017\n\007purpose" +
|
"readId\030\003 \001(\003\022\020\n\010isShared\030\004 \001(\010\022\017\n\007purpos" +
|
||||||
"\030\005 \001(\tBE\n*org.apache.hadoop.hbase.protob" +
|
"e\030\005 \001(\t\022\022\n\ncreateTime\030\006 \001(\003BE\n*org.apach" +
|
||||||
"uf.generatedB\017ZooKeeperProtosH\001\210\001\001\240\001\001"
|
"e.hadoop.hbase.protobuf.generatedB\017ZooKe" +
|
||||||
|
"eperProtosH\001\210\001\001\240\001\001"
|
||||||
};
|
};
|
||||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||||
|
@ -5854,7 +5921,7 @@ public final class ZooKeeperProtos {
|
||||||
internal_static_TableLock_fieldAccessorTable = new
|
internal_static_TableLock_fieldAccessorTable = new
|
||||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||||
internal_static_TableLock_descriptor,
|
internal_static_TableLock_descriptor,
|
||||||
new java.lang.String[] { "TableName", "LockOwner", "ThreadId", "IsShared", "Purpose", },
|
new java.lang.String[] { "TableName", "LockOwner", "ThreadId", "IsShared", "Purpose", "CreateTime", },
|
||||||
org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.TableLock.class,
|
org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.TableLock.class,
|
||||||
org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.TableLock.Builder.class);
|
org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.TableLock.Builder.class);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -143,4 +143,5 @@ message TableLock {
|
||||||
optional int64 threadId = 3;
|
optional int64 threadId = 3;
|
||||||
optional bool isShared = 4;
|
optional bool isShared = 4;
|
||||||
optional string purpose = 5;
|
optional string purpose = 5;
|
||||||
|
optional int64 createTime = 6;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,11 +63,23 @@ public interface InterProcessLock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If supported, attempts to reap all the locks of this type by forcefully
|
* If supported, attempts to reap all the locks of this type by forcefully
|
||||||
* deleting the locks. Lock reaping is different than coordinated lock revocation
|
* deleting the locks (both held and attempted) that have expired according
|
||||||
|
* to the given timeout. Lock reaping is different than coordinated lock revocation
|
||||||
* in that, there is no coordination, and the behavior is undefined if the
|
* in that, there is no coordination, and the behavior is undefined if the
|
||||||
* lock holder is still alive.
|
* lock holder is still alive.
|
||||||
* @throws IOException If there is an unrecoverable error reaping the locks
|
* @throws IOException If there is an unrecoverable error reaping the locks
|
||||||
*/
|
*/
|
||||||
|
public void reapExpiredLocks(long expireTimeoutMs) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If supported, attempts to reap all the locks of this type by forcefully
|
||||||
|
* deleting the locks (both held and attempted). Lock reaping is different
|
||||||
|
* than coordinated lock revocation in that, there is no coordination, and
|
||||||
|
* the behavior is undefined if the lock holder is still alive.
|
||||||
|
* Calling this should have the same affect as calling {@link #reapExpiredLocks(long)}
|
||||||
|
* with timeout=0.
|
||||||
|
* @throws IOException If there is an unrecoverable error reaping the locks
|
||||||
|
*/
|
||||||
public void reapAllLocks() throws IOException;
|
public void reapAllLocks() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,4 +95,11 @@ public interface InterProcessLock {
|
||||||
*/
|
*/
|
||||||
public void handleMetadata(byte[] metadata);
|
public void handleMetadata(byte[] metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the locks (both held and attempted) of this type with the given
|
||||||
|
* {@link MetadataHandler}.
|
||||||
|
* @throws InterruptedException If there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
public void visitLocks(MetadataHandler handler) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,20 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
public interface InterProcessReadWriteLock {
|
public interface InterProcessReadWriteLock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a reader lock containing given metadata.
|
* Obtain a read lock containing given metadata.
|
||||||
* @param metadata Serialized lock metadata (this may contain information
|
* @param metadata Serialized lock metadata (this may contain information
|
||||||
* such as the process owning the lock or the purpose for
|
* such as the process owning the lock or the purpose for
|
||||||
* which the lock was acquired). Must not be null.
|
* which the lock was acquired).
|
||||||
* @return An instantiated InterProcessReadWriteLock instance
|
* @return An instantiated InterProcessLock instance
|
||||||
*/
|
*/
|
||||||
public InterProcessLock readLock(byte[] metadata);
|
public InterProcessLock readLock(byte[] metadata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a writer lock containing given metadata.
|
* Obtain a write lock containing given metadata.
|
||||||
* @param metadata See documentation of metadata parameter in readLock()
|
* @param metadata Serialized lock metadata (this may contain information
|
||||||
* @return An instantiated InterProcessReadWriteLock instance
|
* such as the process owning the lock or the purpose for
|
||||||
|
* which the lock was acquired).
|
||||||
|
* @return An instantiated InterProcessLock instance
|
||||||
*/
|
*/
|
||||||
public InterProcessLock writeLock(byte[] metadata);
|
public InterProcessLock writeLock(byte[] metadata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -721,7 +721,7 @@ Server {
|
||||||
//are invalidated
|
//are invalidated
|
||||||
this.tableLockManager = TableLockManager.createTableLockManager(conf, zooKeeper, serverName);
|
this.tableLockManager = TableLockManager.createTableLockManager(conf, zooKeeper, serverName);
|
||||||
if (!masterRecovery) {
|
if (!masterRecovery) {
|
||||||
this.tableLockManager.reapAllTableWriteLocks();
|
this.tableLockManager.reapWriteLocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
status.setStatus("Initializing ZK system trackers");
|
status.setStatus("Initializing ZK system trackers");
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.hadoop.hbase.exceptions.LockTimeoutException;
|
||||||
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
|
import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
|
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
||||||
import org.apache.hadoop.hbase.zookeeper.lock.ZKInterProcessReadWriteLock;
|
import org.apache.hadoop.hbase.zookeeper.lock.ZKInterProcessReadWriteLock;
|
||||||
|
@ -66,12 +67,17 @@ public abstract class TableLockManager {
|
||||||
protected static final String TABLE_READ_LOCK_TIMEOUT_MS =
|
protected static final String TABLE_READ_LOCK_TIMEOUT_MS =
|
||||||
"hbase.table.read.lock.timeout.ms";
|
"hbase.table.read.lock.timeout.ms";
|
||||||
|
|
||||||
protected static final int DEFAULT_TABLE_WRITE_LOCK_TIMEOUT_MS =
|
protected static final long DEFAULT_TABLE_WRITE_LOCK_TIMEOUT_MS =
|
||||||
600 * 1000; //10 min default
|
600 * 1000; //10 min default
|
||||||
|
|
||||||
protected static final int DEFAULT_TABLE_READ_LOCK_TIMEOUT_MS =
|
protected static final long DEFAULT_TABLE_READ_LOCK_TIMEOUT_MS =
|
||||||
600 * 1000; //10 min default
|
600 * 1000; //10 min default
|
||||||
|
|
||||||
|
public static final String TABLE_LOCK_EXPIRE_TIMEOUT = "hbase.table.lock.expire.ms";
|
||||||
|
|
||||||
|
public static final long DEFAULT_TABLE_LOCK_EXPIRE_TIMEOUT_MS =
|
||||||
|
600 * 1000; //10 min default
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A distributed lock for a table.
|
* A distributed lock for a table.
|
||||||
*/
|
*/
|
||||||
|
@ -109,14 +115,32 @@ public abstract class TableLockManager {
|
||||||
public abstract TableLock readLock(byte[] tableName, String purpose);
|
public abstract TableLock readLock(byte[] tableName, String purpose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force releases all table write locks and lock attempts even if this thread does
|
* Visits all table locks(read and write), and lock attempts with the given callback
|
||||||
|
* MetadataHandler.
|
||||||
|
* @param handler the metadata handler to call
|
||||||
|
* @throws IOException If there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
public abstract void visitAllLocks(MetadataHandler handler) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force releases all table locks(read and write) that have been held longer than
|
||||||
|
* "hbase.table.lock.expire.ms". Assumption is that the clock skew between zookeeper
|
||||||
|
* and this servers is negligible.
|
||||||
|
* The behavior of the lock holders still thinking that they have the lock is undefined.
|
||||||
|
* @throws IOException If there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
public abstract void reapAllExpiredLocks() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force releases table write locks and lock attempts even if this thread does
|
||||||
* not own the lock. The behavior of the lock holders still thinking that they
|
* not own the lock. The behavior of the lock holders still thinking that they
|
||||||
* have the lock is undefined. This should be used carefully and only when
|
* have the lock is undefined. This should be used carefully and only when
|
||||||
* we can ensure that all write-lock holders have died. For example if only
|
* we can ensure that all write-lock holders have died. For example if only
|
||||||
* the master can hold write locks, then we can reap it's locks when the backup
|
* the master can hold write locks, then we can reap it's locks when the backup
|
||||||
* master starts.
|
* master starts.
|
||||||
|
* @throws IOException If there is an unrecoverable error
|
||||||
*/
|
*/
|
||||||
public abstract void reapAllTableWriteLocks() throws IOException;
|
public abstract void reapWriteLocks() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a table has been deleted, and after the table lock is released.
|
* Called after a table has been deleted, and after the table lock is released.
|
||||||
|
@ -135,11 +159,14 @@ public abstract class TableLockManager {
|
||||||
// Initialize table level lock manager for schema changes, if enabled.
|
// Initialize table level lock manager for schema changes, if enabled.
|
||||||
if (conf.getBoolean(TABLE_LOCK_ENABLE,
|
if (conf.getBoolean(TABLE_LOCK_ENABLE,
|
||||||
DEFAULT_TABLE_LOCK_ENABLE)) {
|
DEFAULT_TABLE_LOCK_ENABLE)) {
|
||||||
int writeLockTimeoutMs = conf.getInt(TABLE_WRITE_LOCK_TIMEOUT_MS,
|
long writeLockTimeoutMs = conf.getLong(TABLE_WRITE_LOCK_TIMEOUT_MS,
|
||||||
DEFAULT_TABLE_WRITE_LOCK_TIMEOUT_MS);
|
DEFAULT_TABLE_WRITE_LOCK_TIMEOUT_MS);
|
||||||
int readLockTimeoutMs = conf.getInt(TABLE_READ_LOCK_TIMEOUT_MS,
|
long readLockTimeoutMs = conf.getLong(TABLE_READ_LOCK_TIMEOUT_MS,
|
||||||
DEFAULT_TABLE_READ_LOCK_TIMEOUT_MS);
|
DEFAULT_TABLE_READ_LOCK_TIMEOUT_MS);
|
||||||
return new ZKTableLockManager(zkWatcher, serverName, writeLockTimeoutMs, readLockTimeoutMs);
|
long lockExpireTimeoutMs = conf.getLong(TABLE_LOCK_EXPIRE_TIMEOUT,
|
||||||
|
DEFAULT_TABLE_LOCK_EXPIRE_TIMEOUT_MS);
|
||||||
|
|
||||||
|
return new ZKTableLockManager(zkWatcher, serverName, writeLockTimeoutMs, readLockTimeoutMs, lockExpireTimeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NullTableLockManager();
|
return new NullTableLockManager();
|
||||||
|
@ -167,11 +194,33 @@ public abstract class TableLockManager {
|
||||||
return new NullTableLock();
|
return new NullTableLock();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void reapAllTableWriteLocks() throws IOException {
|
public void reapAllExpiredLocks() throws IOException {
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void reapWriteLocks() throws IOException {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void tableDeleted(byte[] tableName) throws IOException {
|
public void tableDeleted(byte[] tableName) throws IOException {
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void visitAllLocks(MetadataHandler handler) throws IOException {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Public for hbck */
|
||||||
|
public static ZooKeeperProtos.TableLock fromBytes(byte[] bytes) {
|
||||||
|
int pblen = ProtobufUtil.lengthOfPBMagic();
|
||||||
|
if (bytes == null || bytes.length < pblen) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ZooKeeperProtos.TableLock data = ZooKeeperProtos.TableLock.newBuilder().mergeFrom(
|
||||||
|
bytes, pblen, bytes.length - pblen).build();
|
||||||
|
return data;
|
||||||
|
} catch (InvalidProtocolBufferException ex) {
|
||||||
|
LOG.warn("Exception in deserialization", ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,9 +241,9 @@ public abstract class TableLockManager {
|
||||||
}
|
}
|
||||||
LOG.debug("Table is locked by: " +
|
LOG.debug("Table is locked by: " +
|
||||||
String.format("[tableName=%s, lockOwner=%s, threadId=%s, " +
|
String.format("[tableName=%s, lockOwner=%s, threadId=%s, " +
|
||||||
"purpose=%s, isShared=%s]", Bytes.toString(data.getTableName().toByteArray()),
|
"purpose=%s, isShared=%s, createTime=%s]", Bytes.toString(data.getTableName().toByteArray()),
|
||||||
ProtobufUtil.toServerName(data.getLockOwner()), data.getThreadId(),
|
ProtobufUtil.toServerName(data.getLockOwner()), data.getThreadId(),
|
||||||
data.getPurpose(), data.getIsShared()));
|
data.getPurpose(), data.getIsShared(), data.getCreateTime()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -278,7 +327,8 @@ public abstract class TableLockManager {
|
||||||
.setLockOwner(ProtobufUtil.toServerName(serverName))
|
.setLockOwner(ProtobufUtil.toServerName(serverName))
|
||||||
.setThreadId(Thread.currentThread().getId())
|
.setThreadId(Thread.currentThread().getId())
|
||||||
.setPurpose(purpose)
|
.setPurpose(purpose)
|
||||||
.setIsShared(isShared).build();
|
.setIsShared(isShared)
|
||||||
|
.setCreateTime(EnvironmentEdgeManager.currentTimeMillis()).build();
|
||||||
byte[] lockMetadata = toBytes(data);
|
byte[] lockMetadata = toBytes(data);
|
||||||
|
|
||||||
InterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(zkWatcher, tableLockZNode,
|
InterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(zkWatcher, tableLockZNode,
|
||||||
|
@ -291,25 +341,11 @@ public abstract class TableLockManager {
|
||||||
return ProtobufUtil.prependPBMagic(data.toByteArray());
|
return ProtobufUtil.prependPBMagic(data.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ZooKeeperProtos.TableLock fromBytes(byte[] bytes) {
|
|
||||||
int pblen = ProtobufUtil.lengthOfPBMagic();
|
|
||||||
if (bytes == null || bytes.length < pblen) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ZooKeeperProtos.TableLock data = ZooKeeperProtos.TableLock.newBuilder().mergeFrom(
|
|
||||||
bytes, pblen, bytes.length - pblen).build();
|
|
||||||
return data;
|
|
||||||
} catch (InvalidProtocolBufferException ex) {
|
|
||||||
LOG.warn("Exception in deserialization", ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ServerName serverName;
|
private final ServerName serverName;
|
||||||
private final ZooKeeperWatcher zkWatcher;
|
private final ZooKeeperWatcher zkWatcher;
|
||||||
private final long writeLockTimeoutMs;
|
private final long writeLockTimeoutMs;
|
||||||
private final long readLockTimeoutMs;
|
private final long readLockTimeoutMs;
|
||||||
|
private final long lockExpireTimeoutMs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a new manager for table-level locks.
|
* Initialize a new manager for table-level locks.
|
||||||
|
@ -322,11 +358,12 @@ public abstract class TableLockManager {
|
||||||
* given table, or -1 for no timeout
|
* given table, or -1 for no timeout
|
||||||
*/
|
*/
|
||||||
public ZKTableLockManager(ZooKeeperWatcher zkWatcher,
|
public ZKTableLockManager(ZooKeeperWatcher zkWatcher,
|
||||||
ServerName serverName, long writeLockTimeoutMs, long readLockTimeoutMs) {
|
ServerName serverName, long writeLockTimeoutMs, long readLockTimeoutMs, long lockExpireTimeoutMs) {
|
||||||
this.zkWatcher = zkWatcher;
|
this.zkWatcher = zkWatcher;
|
||||||
this.serverName = serverName;
|
this.serverName = serverName;
|
||||||
this.writeLockTimeoutMs = writeLockTimeoutMs;
|
this.writeLockTimeoutMs = writeLockTimeoutMs;
|
||||||
this.readLockTimeoutMs = readLockTimeoutMs;
|
this.readLockTimeoutMs = readLockTimeoutMs;
|
||||||
|
this.lockExpireTimeoutMs = lockExpireTimeoutMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -340,19 +377,33 @@ public abstract class TableLockManager {
|
||||||
serverName, readLockTimeoutMs, true, purpose);
|
serverName, readLockTimeoutMs, true, purpose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitAllLocks(MetadataHandler handler) throws IOException {
|
||||||
|
for (String tableName : getTableNames()) {
|
||||||
|
String tableLockZNode = ZKUtil.joinZNode(zkWatcher.tableLockZNode, tableName);
|
||||||
|
ZKInterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(
|
||||||
|
zkWatcher, tableLockZNode, null);
|
||||||
|
lock.readLock(null).visitLocks(handler);
|
||||||
|
lock.writeLock(null).visitLocks(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getTableNames() throws IOException {
|
||||||
|
|
||||||
|
List<String> tableNames;
|
||||||
|
try {
|
||||||
|
tableNames = ZKUtil.listChildrenNoWatch(zkWatcher, zkWatcher.tableLockZNode);
|
||||||
|
} catch (KeeperException e) {
|
||||||
|
LOG.error("Unexpected ZooKeeper error when listing children", e);
|
||||||
|
throw new IOException("Unexpected ZooKeeper exception", e);
|
||||||
|
}
|
||||||
|
return tableNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reapAllTableWriteLocks() throws IOException {
|
public void reapWriteLocks() throws IOException {
|
||||||
//get the table names
|
//get the table names
|
||||||
try {
|
try {
|
||||||
List<String> tableNames;
|
for (String tableName : getTableNames()) {
|
||||||
try {
|
|
||||||
tableNames = ZKUtil.listChildrenNoWatch(zkWatcher, zkWatcher.tableLockZNode);
|
|
||||||
} catch (KeeperException e) {
|
|
||||||
LOG.error("Unexpected ZooKeeper error when listing children", e);
|
|
||||||
throw new IOException("Unexpected ZooKeeper exception", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String tableName : tableNames) {
|
|
||||||
String tableLockZNode = ZKUtil.joinZNode(zkWatcher.tableLockZNode, tableName);
|
String tableLockZNode = ZKUtil.joinZNode(zkWatcher.tableLockZNode, tableName);
|
||||||
ZKInterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(
|
ZKInterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(
|
||||||
zkWatcher, tableLockZNode, null);
|
zkWatcher, tableLockZNode, null);
|
||||||
|
@ -365,6 +416,24 @@ public abstract class TableLockManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapAllExpiredLocks() throws IOException {
|
||||||
|
//get the table names
|
||||||
|
try {
|
||||||
|
for (String tableName : getTableNames()) {
|
||||||
|
String tableLockZNode = ZKUtil.joinZNode(zkWatcher.tableLockZNode, tableName);
|
||||||
|
ZKInterProcessReadWriteLock lock = new ZKInterProcessReadWriteLock(
|
||||||
|
zkWatcher, tableLockZNode, null);
|
||||||
|
lock.readLock(null).reapExpiredLocks(lockExpireTimeoutMs);
|
||||||
|
lock.writeLock(null).reapExpiredLocks(lockExpireTimeoutMs);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw ex;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IOException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tableDeleted(byte[] tableName) throws IOException {
|
public void tableDeleted(byte[] tableName) throws IOException {
|
||||||
//table write lock from DeleteHandler is already released, just delete the parent znode
|
//table write lock from DeleteHandler is already released, just delete the parent znode
|
||||||
|
|
|
@ -64,9 +64,7 @@ import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
import org.apache.hadoop.hbase.HRegionLocation;
|
import org.apache.hadoop.hbase.HRegionLocation;
|
||||||
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.exceptions.MasterNotRunningException;
|
|
||||||
import org.apache.hadoop.hbase.ServerName;
|
import org.apache.hadoop.hbase.ServerName;
|
||||||
import org.apache.hadoop.hbase.exceptions.ZooKeeperConnectionException;
|
|
||||||
import org.apache.hadoop.hbase.catalog.MetaEditor;
|
import org.apache.hadoop.hbase.catalog.MetaEditor;
|
||||||
import org.apache.hadoop.hbase.client.AdminProtocol;
|
import org.apache.hadoop.hbase.client.AdminProtocol;
|
||||||
import org.apache.hadoop.hbase.client.Delete;
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
|
@ -82,6 +80,8 @@ import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitorBase;
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
import org.apache.hadoop.hbase.client.RowMutations;
|
import org.apache.hadoop.hbase.client.RowMutations;
|
||||||
|
import org.apache.hadoop.hbase.exceptions.MasterNotRunningException;
|
||||||
|
import org.apache.hadoop.hbase.exceptions.ZooKeeperConnectionException;
|
||||||
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
|
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
|
||||||
import org.apache.hadoop.hbase.io.hfile.HFile;
|
import org.apache.hadoop.hbase.io.hfile.HFile;
|
||||||
import org.apache.hadoop.hbase.master.MasterFileSystem;
|
import org.apache.hadoop.hbase.master.MasterFileSystem;
|
||||||
|
@ -95,6 +95,7 @@ import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
|
||||||
import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
|
import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
|
||||||
import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandler;
|
import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandler;
|
||||||
import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandlerImpl;
|
import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandlerImpl;
|
||||||
|
import org.apache.hadoop.hbase.util.hbck.TableLockChecker;
|
||||||
import org.apache.hadoop.hbase.zookeeper.MetaRegionTracker;
|
import org.apache.hadoop.hbase.zookeeper.MetaRegionTracker;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
|
import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
||||||
|
@ -197,6 +198,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
private boolean fixSplitParents = false; // fix lingering split parents
|
private boolean fixSplitParents = false; // fix lingering split parents
|
||||||
private boolean fixReferenceFiles = false; // fix lingering reference store file
|
private boolean fixReferenceFiles = false; // fix lingering reference store file
|
||||||
private boolean fixEmptyMetaCells = false; // fix (remove) empty REGIONINFO_QUALIFIER rows
|
private boolean fixEmptyMetaCells = false; // fix (remove) empty REGIONINFO_QUALIFIER rows
|
||||||
|
private boolean fixTableLocks = false; // fix table locks which are expired
|
||||||
|
|
||||||
// limit checking/fixes to listed tables, if empty attempt to check/fix all
|
// limit checking/fixes to listed tables, if empty attempt to check/fix all
|
||||||
// .META. are always checked
|
// .META. are always checked
|
||||||
|
@ -455,6 +457,8 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
|
|
||||||
offlineReferenceFileRepair();
|
offlineReferenceFileRepair();
|
||||||
|
|
||||||
|
checkAndFixTableLocks();
|
||||||
|
|
||||||
// Print table summary
|
// Print table summary
|
||||||
printTableSummary(tablesInfo);
|
printTableSummary(tablesInfo);
|
||||||
return errors.summarize();
|
return errors.summarize();
|
||||||
|
@ -2471,6 +2475,15 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
return hbi;
|
return hbi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkAndFixTableLocks() throws IOException {
|
||||||
|
TableLockChecker checker = new TableLockChecker(createZooKeeperWatcher(), errors);
|
||||||
|
checker.checkTableLocks();
|
||||||
|
|
||||||
|
if (this.fixTableLocks) {
|
||||||
|
checker.fixExpiredTableLocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check values in regionInfo for .META.
|
* Check values in regionInfo for .META.
|
||||||
* Check if zero or more than one regions with META are found.
|
* Check if zero or more than one regions with META are found.
|
||||||
|
@ -2560,7 +2573,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
Pair<HRegionInfo, ServerName> pair = HRegionInfo.getHRegionInfoAndServerName(result);
|
Pair<HRegionInfo, ServerName> pair = HRegionInfo.getHRegionInfoAndServerName(result);
|
||||||
if (pair == null || pair.getFirst() == null) {
|
if (pair == null || pair.getFirst() == null) {
|
||||||
emptyRegionInfoQualifiers.add(result);
|
emptyRegionInfoQualifiers.add(result);
|
||||||
errors.reportError(ERROR_CODE.EMPTY_META_CELL,
|
errors.reportError(ERROR_CODE.EMPTY_META_CELL,
|
||||||
"Empty REGIONINFO_QUALIFIER found in .META.");
|
"Empty REGIONINFO_QUALIFIER found in .META.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2897,7 +2910,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
FIRST_REGION_STARTKEY_NOT_EMPTY, LAST_REGION_ENDKEY_NOT_EMPTY, DUPE_STARTKEYS,
|
FIRST_REGION_STARTKEY_NOT_EMPTY, LAST_REGION_ENDKEY_NOT_EMPTY, DUPE_STARTKEYS,
|
||||||
HOLE_IN_REGION_CHAIN, OVERLAP_IN_REGION_CHAIN, REGION_CYCLE, DEGENERATE_REGION,
|
HOLE_IN_REGION_CHAIN, OVERLAP_IN_REGION_CHAIN, REGION_CYCLE, DEGENERATE_REGION,
|
||||||
ORPHAN_HDFS_REGION, LINGERING_SPLIT_PARENT, NO_TABLEINFO_FILE, LINGERING_REFERENCE_HFILE,
|
ORPHAN_HDFS_REGION, LINGERING_SPLIT_PARENT, NO_TABLEINFO_FILE, LINGERING_REFERENCE_HFILE,
|
||||||
WRONG_USAGE, EMPTY_META_CELL
|
WRONG_USAGE, EMPTY_META_CELL, EXPIRED_TABLE_LOCK
|
||||||
}
|
}
|
||||||
public void clear();
|
public void clear();
|
||||||
public void report(String message);
|
public void report(String message);
|
||||||
|
@ -3237,6 +3250,14 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
checkMetaOnly = true;
|
checkMetaOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set table locks fix mode.
|
||||||
|
* Delete table locks held for a long time
|
||||||
|
*/
|
||||||
|
public void setFixTableLocks(boolean shouldFix) {
|
||||||
|
fixTableLocks = shouldFix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we should rerun fsck again. This checks if we've tried to
|
* Check if we should rerun fsck again. This checks if we've tried to
|
||||||
* fix something and we should rerun fsck tool again.
|
* fix something and we should rerun fsck tool again.
|
||||||
|
@ -3476,9 +3497,13 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
out.println("");
|
out.println("");
|
||||||
out.println(" Metadata Repair shortcuts");
|
out.println(" Metadata Repair shortcuts");
|
||||||
out.println(" -repair Shortcut for -fixAssignments -fixMeta -fixHdfsHoles " +
|
out.println(" -repair Shortcut for -fixAssignments -fixMeta -fixHdfsHoles " +
|
||||||
"-fixHdfsOrphans -fixHdfsOverlaps -fixVersionFile -sidelineBigOverlaps -fixReferenceFiles");
|
"-fixHdfsOrphans -fixHdfsOverlaps -fixVersionFile -sidelineBigOverlaps -fixReferenceFiles -fixTableLocks");
|
||||||
out.println(" -repairHoles Shortcut for -fixAssignments -fixMeta -fixHdfsHoles");
|
out.println(" -repairHoles Shortcut for -fixAssignments -fixMeta -fixHdfsHoles");
|
||||||
|
|
||||||
|
out.println("");
|
||||||
|
out.println(" Table lock options");
|
||||||
|
out.println(" -fixTableLocks Deletes table locks held for a long time (hbase.table.lock.expire.ms, 10min by default)");
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
errors.reportError(ERROR_CODE.WRONG_USAGE, sw.toString());
|
errors.reportError(ERROR_CODE.WRONG_USAGE, sw.toString());
|
||||||
|
|
||||||
|
@ -3603,6 +3628,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
setFixSplitParents(false);
|
setFixSplitParents(false);
|
||||||
setCheckHdfs(true);
|
setCheckHdfs(true);
|
||||||
setFixReferenceFiles(true);
|
setFixReferenceFiles(true);
|
||||||
|
setFixTableLocks(true);
|
||||||
} else if (cmd.equals("-repairHoles")) {
|
} else if (cmd.equals("-repairHoles")) {
|
||||||
// this will make all missing hdfs regions available but may lose data
|
// this will make all missing hdfs regions available but may lose data
|
||||||
setFixHdfsHoles(true);
|
setFixHdfsHoles(true);
|
||||||
|
@ -3647,6 +3673,8 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
setSummary();
|
setSummary();
|
||||||
} else if (cmd.equals("-metaonly")) {
|
} else if (cmd.equals("-metaonly")) {
|
||||||
setCheckMetaOnly();
|
setCheckMetaOnly();
|
||||||
|
} else if (cmd.equals("-fixTableLocks")) {
|
||||||
|
setFixTableLocks(true);
|
||||||
} else if (cmd.startsWith("-")) {
|
} else if (cmd.startsWith("-")) {
|
||||||
errors.reportError(ERROR_CODE.WRONG_USAGE, "Unrecognized option:" + cmd);
|
errors.reportError(ERROR_CODE.WRONG_USAGE, "Unrecognized option:" + cmd);
|
||||||
return printUsageAndExit();
|
return printUsageAndExit();
|
||||||
|
|
|
@ -62,6 +62,7 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
protected final ZooKeeperWatcher zkWatcher;
|
protected final ZooKeeperWatcher zkWatcher;
|
||||||
protected final String parentLockNode;
|
protected final String parentLockNode;
|
||||||
protected final String fullyQualifiedZNode;
|
protected final String fullyQualifiedZNode;
|
||||||
|
protected final String childZNode;
|
||||||
protected final byte[] metadata;
|
protected final byte[] metadata;
|
||||||
protected final MetadataHandler handler;
|
protected final MetadataHandler handler;
|
||||||
|
|
||||||
|
@ -113,18 +114,22 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
/** Parses sequenceId from the znode name. Zookeeper documentation
|
/** Parses sequenceId from the znode name. Zookeeper documentation
|
||||||
* states: The sequence number is always fixed length of 10 digits, 0 padded
|
* states: The sequence number is always fixed length of 10 digits, 0 padded
|
||||||
*/
|
*/
|
||||||
public static int getChildSequenceId(String childZNode) {
|
public static long getChildSequenceId(String childZNode) {
|
||||||
Preconditions.checkNotNull(childZNode);
|
Preconditions.checkNotNull(childZNode);
|
||||||
assert childZNode.length() >= 10;
|
assert childZNode.length() >= 10;
|
||||||
String sequenceIdStr = childZNode.substring(childZNode.length() - 10);
|
String sequenceIdStr = childZNode.substring(childZNode.length() - 10);
|
||||||
return Integer.parseInt(sequenceIdStr);
|
return Long.parseLong(sequenceIdStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(String zNode1, String zNode2) {
|
public int compare(String zNode1, String zNode2) {
|
||||||
int seq1 = getChildSequenceId(zNode1);
|
long seq1 = getChildSequenceId(zNode1);
|
||||||
int seq2 = getChildSequenceId(zNode2);
|
long seq2 = getChildSequenceId(zNode2);
|
||||||
return seq1 - seq2;
|
if (seq1 == seq2) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return seq1 < seq2 ? -1 : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +148,7 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
this.fullyQualifiedZNode = ZKUtil.joinZNode(parentLockNode, childNode);
|
this.fullyQualifiedZNode = ZKUtil.joinZNode(parentLockNode, childNode);
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
this.childZNode = childNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,6 +238,17 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a child znode represents a read lock.
|
||||||
|
* @param child The child znode we want to check.
|
||||||
|
* @return whether the child znode represents a read lock
|
||||||
|
*/
|
||||||
|
protected static boolean isChildReadLock(String child) {
|
||||||
|
int idx = child.lastIndexOf(ZKUtil.ZNODE_PATH_SEPARATOR);
|
||||||
|
String suffix = child.substring(idx + 1);
|
||||||
|
return suffix.startsWith(WRITE_LOCK_CHILD_NODE_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a child znode represents a write lock.
|
* Check if a child znode represents a write lock.
|
||||||
* @param child The child znode we want to check.
|
* @param child The child znode we want to check.
|
||||||
|
@ -243,6 +260,17 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
return suffix.startsWith(WRITE_LOCK_CHILD_NODE_PREFIX);
|
return suffix.startsWith(WRITE_LOCK_CHILD_NODE_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a child znode represents the same type(read or write) of lock
|
||||||
|
* @param child The child znode we want to check.
|
||||||
|
* @return whether the child znode represents the same type(read or write) of lock
|
||||||
|
*/
|
||||||
|
protected boolean isChildOfSameType(String child) {
|
||||||
|
int idx = child.lastIndexOf(ZKUtil.ZNODE_PATH_SEPARATOR);
|
||||||
|
String suffix = child.substring(idx + 1);
|
||||||
|
return suffix.startsWith(this.childZNode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state as to indicate that a lock is held
|
* Update state as to indicate that a lock is held
|
||||||
* @param createdZNode The lock znode
|
* @param createdZNode The lock znode
|
||||||
|
@ -303,32 +331,108 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process metadata stored in a ZNode using a callback
|
||||||
|
* <p>
|
||||||
|
* @param lockZNode The node holding the metadata
|
||||||
|
* @return True if metadata was ready and processed, false otherwise.
|
||||||
|
*/
|
||||||
|
protected boolean handleLockMetadata(String lockZNode) {
|
||||||
|
return handleLockMetadata(lockZNode, handler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process metadata stored in a ZNode using a callback object passed to
|
* Process metadata stored in a ZNode using a callback object passed to
|
||||||
* this instance.
|
* this instance.
|
||||||
* <p>
|
* <p>
|
||||||
* @param lockZNode The node holding the metadata
|
* @param lockZNode The node holding the metadata
|
||||||
* @return True if metadata was ready and processed
|
* @param handler the metadata handler
|
||||||
* @throws IOException If an unexpected ZooKeeper error occurs
|
* @return True if metadata was ready and processed, false on exception.
|
||||||
* @throws InterruptedException If interrupted when reading the metadata
|
|
||||||
*/
|
*/
|
||||||
protected boolean handleLockMetadata(String lockZNode)
|
protected boolean handleLockMetadata(String lockZNode, MetadataHandler handler) {
|
||||||
throws IOException, InterruptedException {
|
if (handler == null) {
|
||||||
byte[] metadata = null;
|
|
||||||
try {
|
|
||||||
metadata = ZKUtil.getData(zkWatcher, lockZNode);
|
|
||||||
} catch (KeeperException ex) {
|
|
||||||
LOG.warn("Cannot getData for znode:" + lockZNode, ex);
|
|
||||||
}
|
|
||||||
if (metadata == null) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (handler != null) {
|
try {
|
||||||
|
byte[] metadata = ZKUtil.getData(zkWatcher, lockZNode);
|
||||||
handler.handleMetadata(metadata);
|
handler.handleMetadata(metadata);
|
||||||
|
} catch (KeeperException ex) {
|
||||||
|
LOG.warn("Error processing lock metadata in " + lockZNode);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapAllLocks() throws IOException {
|
||||||
|
reapExpiredLocks(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will delete all lock znodes of this type (either read or write) which are "expired"
|
||||||
|
* according to timeout. Assumption is that the clock skew between zookeeper and this servers
|
||||||
|
* is negligible.
|
||||||
|
* Referred in zk recipe as "Revocable Shared Locks with Freaking Laser Beams".
|
||||||
|
* (http://zookeeper.apache.org/doc/trunk/recipes.html).
|
||||||
|
*/
|
||||||
|
public void reapExpiredLocks(long timeout) throws IOException {
|
||||||
|
List<String> children;
|
||||||
|
try {
|
||||||
|
children = ZKUtil.listChildrenNoWatch(zkWatcher, parentLockNode);
|
||||||
|
} catch (KeeperException e) {
|
||||||
|
LOG.error("Unexpected ZooKeeper error when listing children", e);
|
||||||
|
throw new IOException("Unexpected ZooKeeper exception", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeeperException deferred = null;
|
||||||
|
Stat stat = new Stat();
|
||||||
|
long expireDate = System.currentTimeMillis() - timeout; //we are using cTime in zookeeper
|
||||||
|
for (String child : children) {
|
||||||
|
if (isChildOfSameType(child)) {
|
||||||
|
String znode = ZKUtil.joinZNode(parentLockNode, child);
|
||||||
|
try {
|
||||||
|
ZKUtil.getDataNoWatch(zkWatcher, znode, stat);
|
||||||
|
if (stat.getCtime() < expireDate) {
|
||||||
|
LOG.info("Reaping lock for znode:" + znode);
|
||||||
|
ZKUtil.deleteNodeFailSilent(zkWatcher, znode);
|
||||||
|
}
|
||||||
|
} catch (KeeperException ex) {
|
||||||
|
LOG.warn("Error reaping the znode for write lock :" + znode);
|
||||||
|
deferred = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deferred != null) {
|
||||||
|
throw new IOException("ZK exception while reaping locks:", deferred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the locks (both held and attempted) with the given MetadataHandler.
|
||||||
|
* @throws InterruptedException If there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
public void visitLocks(MetadataHandler handler) throws IOException {
|
||||||
|
List<String> children;
|
||||||
|
try {
|
||||||
|
children = ZKUtil.listChildrenNoWatch(zkWatcher, parentLockNode);
|
||||||
|
} catch (KeeperException e) {
|
||||||
|
LOG.error("Unexpected ZooKeeper error when listing children", e);
|
||||||
|
throw new IOException("Unexpected ZooKeeper exception", e);
|
||||||
|
}
|
||||||
|
if (children.size() > 0) {
|
||||||
|
for (String child : children) {
|
||||||
|
if (isChildOfSameType(child)) {
|
||||||
|
String znode = ZKUtil.joinZNode(parentLockNode, child);
|
||||||
|
String childWatchesZNode = getLockPath(child, children);
|
||||||
|
if (childWatchesZNode == null) {
|
||||||
|
LOG.info("Lock is held by: " + child);
|
||||||
|
}
|
||||||
|
handleLockMetadata(znode, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine based on a list of children under a ZNode, whether or not a
|
* Determine based on a list of children under a ZNode, whether or not a
|
||||||
* process which created a specified ZNode has obtained a lock. If a lock is
|
* process which created a specified ZNode has obtained a lock. If a lock is
|
||||||
|
@ -343,5 +447,5 @@ public abstract class ZKInterProcessLockBase implements InterProcessLock {
|
||||||
* acquired lock.
|
* acquired lock.
|
||||||
*/
|
*/
|
||||||
protected abstract String getLockPath(String myZNode, List<String> children)
|
protected abstract String getLockPath(String myZNode, List<String> children)
|
||||||
throws IOException, InterruptedException;
|
throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,7 @@ public class ZKInterProcessReadLock extends ZKInterProcessLockBase {
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String getLockPath(String createdZNode, List<String> children)
|
protected String getLockPath(String createdZNode, List<String> children) throws IOException {
|
||||||
throws IOException, InterruptedException {
|
|
||||||
TreeSet<String> writeChildren =
|
TreeSet<String> writeChildren =
|
||||||
new TreeSet<String>(ZNodeComparator.COMPARATOR);
|
new TreeSet<String>(ZNodeComparator.COMPARATOR);
|
||||||
for (String child : children) {
|
for (String child : children) {
|
||||||
|
@ -67,17 +66,8 @@ public class ZKInterProcessReadLock extends ZKInterProcessLockBase {
|
||||||
String pathToWatch = lowerChildren.last();
|
String pathToWatch = lowerChildren.last();
|
||||||
String nodeHoldingLock = lowerChildren.first();
|
String nodeHoldingLock = lowerChildren.first();
|
||||||
String znode = ZKUtil.joinZNode(parentLockNode, nodeHoldingLock);
|
String znode = ZKUtil.joinZNode(parentLockNode, nodeHoldingLock);
|
||||||
try {
|
handleLockMetadata(znode);
|
||||||
handleLockMetadata(znode);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warn("Error processing lock metadata in " + nodeHoldingLock, e);
|
|
||||||
}
|
|
||||||
return pathToWatch;
|
return pathToWatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reapAllLocks() throws IOException {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"Lock reaping is not supported for ZK based read locks");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
|
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
||||||
import org.apache.zookeeper.KeeperException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZooKeeper based write lock:
|
* ZooKeeper based write lock:
|
||||||
|
@ -47,8 +46,7 @@ public class ZKInterProcessWriteLock extends ZKInterProcessLockBase {
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String getLockPath(String createdZNode, List<String> children)
|
protected String getLockPath(String createdZNode, List<String> children) throws IOException {
|
||||||
throws IOException, InterruptedException {
|
|
||||||
TreeSet<String> sortedChildren =
|
TreeSet<String> sortedChildren =
|
||||||
new TreeSet<String>(ZNodeComparator.COMPARATOR);
|
new TreeSet<String>(ZNodeComparator.COMPARATOR);
|
||||||
sortedChildren.addAll(children);
|
sortedChildren.addAll(children);
|
||||||
|
@ -56,43 +54,8 @@ public class ZKInterProcessWriteLock extends ZKInterProcessLockBase {
|
||||||
if (pathToWatch != null) {
|
if (pathToWatch != null) {
|
||||||
String nodeHoldingLock = sortedChildren.first();
|
String nodeHoldingLock = sortedChildren.first();
|
||||||
String znode = ZKUtil.joinZNode(parentLockNode, nodeHoldingLock);
|
String znode = ZKUtil.joinZNode(parentLockNode, nodeHoldingLock);
|
||||||
try {
|
handleLockMetadata(znode);
|
||||||
handleLockMetadata(znode);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warn("Error processing lock metadata in " + nodeHoldingLock, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pathToWatch;
|
return pathToWatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Referred in zk recipe as "Revocable Shared Locks with Freaking Laser Beams"
|
|
||||||
* (http://zookeeper.apache.org/doc/trunk/recipes.html).
|
|
||||||
*/
|
|
||||||
public void reapAllLocks() throws IOException {
|
|
||||||
List<String> children;
|
|
||||||
try {
|
|
||||||
children = ZKUtil.listChildrenNoWatch(zkWatcher, parentLockNode);
|
|
||||||
} catch (KeeperException e) {
|
|
||||||
LOG.error("Unexpected ZooKeeper error when listing children", e);
|
|
||||||
throw new IOException("Unexpected ZooKeeper exception", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeeperException deferred = null;
|
|
||||||
for (String child : children) {
|
|
||||||
if (isChildWriteLock(child)) {
|
|
||||||
String znode = ZKUtil.joinZNode(parentLockNode, child);
|
|
||||||
LOG.info("Reaping write lock for znode:" + znode);
|
|
||||||
try {
|
|
||||||
ZKUtil.deleteNodeFailSilent(zkWatcher, znode);
|
|
||||||
} catch (KeeperException ex) {
|
|
||||||
LOG.warn("Error reaping the znode for write lock :" + znode);
|
|
||||||
deferred = ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (deferred != null) {
|
|
||||||
throw new IOException("ZK exception while reaping locks:", deferred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ public class TestTableLockManager {
|
||||||
writeLocksAttempted.await();
|
writeLocksAttempted.await();
|
||||||
|
|
||||||
//now reap all table locks
|
//now reap all table locks
|
||||||
lockManager.reapAllTableWriteLocks();
|
lockManager.reapWriteLocks();
|
||||||
|
|
||||||
TEST_UTIL.getConfiguration().setInt(TableLockManager.TABLE_WRITE_LOCK_TIMEOUT_MS, 0);
|
TEST_UTIL.getConfiguration().setInt(TableLockManager.TABLE_WRITE_LOCK_TIMEOUT_MS, 0);
|
||||||
TableLockManager zeroTimeoutLockManager = TableLockManager.createTableLockManager(
|
TableLockManager zeroTimeoutLockManager = TableLockManager.createTableLockManager(
|
||||||
|
|
|
@ -34,6 +34,7 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
|
@ -73,6 +74,8 @@ import org.apache.hadoop.hbase.io.hfile.TestHFile;
|
||||||
import org.apache.hadoop.hbase.master.AssignmentManager;
|
import org.apache.hadoop.hbase.master.AssignmentManager;
|
||||||
import org.apache.hadoop.hbase.master.HMaster;
|
import org.apache.hadoop.hbase.master.HMaster;
|
||||||
import org.apache.hadoop.hbase.master.RegionStates;
|
import org.apache.hadoop.hbase.master.RegionStates;
|
||||||
|
import org.apache.hadoop.hbase.master.TableLockManager;
|
||||||
|
import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
|
||||||
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
|
import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
|
||||||
|
@ -1299,7 +1302,7 @@ public class TestHBaseFsck {
|
||||||
// TODO: fixHdfsHoles does not work against splits, since the parent dir lingers on
|
// TODO: fixHdfsHoles does not work against splits, since the parent dir lingers on
|
||||||
// for some time until children references are deleted. HBCK erroneously sees this as
|
// for some time until children references are deleted. HBCK erroneously sees this as
|
||||||
// overlapping regions
|
// overlapping regions
|
||||||
HBaseFsck hbck = doFsck(conf, true, true, false, false, false, true, true, true, false, null);
|
HBaseFsck hbck = doFsck(conf, true, true, false, false, false, true, true, true, false, false, null);
|
||||||
assertErrors(hbck, new ERROR_CODE[] {}); //no LINGERING_SPLIT_PARENT reported
|
assertErrors(hbck, new ERROR_CODE[] {}); //no LINGERING_SPLIT_PARENT reported
|
||||||
|
|
||||||
// assert that the split META entry is still there.
|
// assert that the split META entry is still there.
|
||||||
|
@ -1361,7 +1364,7 @@ public class TestHBaseFsck {
|
||||||
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN}); //no LINGERING_SPLIT_PARENT
|
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN}); //no LINGERING_SPLIT_PARENT
|
||||||
|
|
||||||
// now fix it. The fix should not revert the region split, but add daughters to META
|
// now fix it. The fix should not revert the region split, but add daughters to META
|
||||||
hbck = doFsck(conf, true, true, false, false, false, false, false, false, false, null);
|
hbck = doFsck(conf, true, true, false, false, false, false, false, false, false, false, null);
|
||||||
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED,
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED,
|
||||||
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN});
|
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN});
|
||||||
|
|
||||||
|
@ -1936,6 +1939,71 @@ public class TestHBaseFsck {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout=30000)
|
||||||
|
public void testCheckTableLocks() throws Exception {
|
||||||
|
IncrementingEnvironmentEdge edge = new IncrementingEnvironmentEdge(0);
|
||||||
|
EnvironmentEdgeManager.injectEdge(edge);
|
||||||
|
// check no errors
|
||||||
|
HBaseFsck hbck = doFsck(conf, false);
|
||||||
|
assertNoErrors(hbck);
|
||||||
|
|
||||||
|
ServerName mockName = new ServerName("localhost", 60000, 1);
|
||||||
|
|
||||||
|
// obtain one lock
|
||||||
|
final TableLockManager tableLockManager = TableLockManager.createTableLockManager(conf, TEST_UTIL.getZooKeeperWatcher(), mockName);
|
||||||
|
TableLock writeLock = tableLockManager.writeLock(Bytes.toBytes("foo"), "testCheckTableLocks");
|
||||||
|
writeLock.acquire();
|
||||||
|
hbck = doFsck(conf, false);
|
||||||
|
assertNoErrors(hbck); // should not have expired, no problems
|
||||||
|
|
||||||
|
edge.incrementTime(conf.getLong(TableLockManager.TABLE_LOCK_EXPIRE_TIMEOUT,
|
||||||
|
TableLockManager.DEFAULT_TABLE_LOCK_EXPIRE_TIMEOUT_MS)); // let table lock expire
|
||||||
|
|
||||||
|
hbck = doFsck(conf, false);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.EXPIRED_TABLE_LOCK});
|
||||||
|
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
TableLock readLock = tableLockManager.writeLock(Bytes.toBytes("foo"), "testCheckTableLocks");
|
||||||
|
try {
|
||||||
|
latch.countDown();
|
||||||
|
readLock.acquire();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
return; // expected, since this will be reaped under us.
|
||||||
|
}
|
||||||
|
fail("should not have come here");
|
||||||
|
};
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
latch.await(); // wait until thread starts
|
||||||
|
Threads.sleep(300); // wait some more to ensure writeLock.acquire() is called
|
||||||
|
|
||||||
|
hbck = doFsck(conf, false);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.EXPIRED_TABLE_LOCK}); // still one expired, one not-expired
|
||||||
|
|
||||||
|
edge.incrementTime(conf.getLong(TableLockManager.TABLE_LOCK_EXPIRE_TIMEOUT,
|
||||||
|
TableLockManager.DEFAULT_TABLE_LOCK_EXPIRE_TIMEOUT_MS)); // let table lock expire
|
||||||
|
|
||||||
|
hbck = doFsck(conf, false);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.EXPIRED_TABLE_LOCK, ERROR_CODE.EXPIRED_TABLE_LOCK}); // both are expired
|
||||||
|
|
||||||
|
conf.setLong(TableLockManager.TABLE_LOCK_EXPIRE_TIMEOUT, 1); // reaping from ZKInterProcessWriteLock uses znode cTime,
|
||||||
|
// which is not injectable through EnvironmentEdge
|
||||||
|
Threads.sleep(10);
|
||||||
|
hbck = doFsck(conf, true); // now fix both cases
|
||||||
|
|
||||||
|
hbck = doFsck(conf, false);
|
||||||
|
assertNoErrors(hbck);
|
||||||
|
|
||||||
|
// ensure that locks are deleted
|
||||||
|
writeLock = tableLockManager.writeLock(Bytes.toBytes("foo"), "should acquire without blocking");
|
||||||
|
writeLock.acquire(); // this should not block.
|
||||||
|
writeLock.release(); // release for clean state
|
||||||
|
}
|
||||||
|
|
||||||
@org.junit.Rule
|
@org.junit.Rule
|
||||||
public TestName name = new TestName();
|
public TestName name = new TestName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ public class HbckTestingUtil {
|
||||||
|
|
||||||
public static HBaseFsck doFsck(
|
public static HBaseFsck doFsck(
|
||||||
Configuration conf, boolean fix, String table) throws Exception {
|
Configuration conf, boolean fix, String table) throws Exception {
|
||||||
return doFsck(conf, fix, fix, fix, fix,fix, fix, fix, fix, fix, table);
|
return doFsck(conf, fix, fix, fix, fix,fix, fix, fix, fix, fix, fix, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HBaseFsck doFsck(Configuration conf, boolean fixAssignments,
|
public static HBaseFsck doFsck(Configuration conf, boolean fixAssignments,
|
||||||
boolean fixMeta, boolean fixHdfsHoles, boolean fixHdfsOverlaps,
|
boolean fixMeta, boolean fixHdfsHoles, boolean fixHdfsOverlaps,
|
||||||
boolean fixHdfsOrphans, boolean fixTableOrphans, boolean fixVersionFile,
|
boolean fixHdfsOrphans, boolean fixTableOrphans, boolean fixVersionFile,
|
||||||
boolean fixReferenceFiles, boolean fixEmptyMetaRegionInfo, String table) throws Exception {
|
boolean fixReferenceFiles, boolean fixEmptyMetaRegionInfo, boolean fixTableLocks, String table) throws Exception {
|
||||||
HBaseFsck fsck = new HBaseFsck(conf, exec);
|
HBaseFsck fsck = new HBaseFsck(conf, exec);
|
||||||
fsck.connect();
|
fsck.connect();
|
||||||
fsck.setDisplayFullReport(); // i.e. -details
|
fsck.setDisplayFullReport(); // i.e. -details
|
||||||
|
@ -58,6 +58,7 @@ public class HbckTestingUtil {
|
||||||
fsck.setFixVersionFile(fixVersionFile);
|
fsck.setFixVersionFile(fixVersionFile);
|
||||||
fsck.setFixReferenceFiles(fixReferenceFiles);
|
fsck.setFixReferenceFiles(fixReferenceFiles);
|
||||||
fsck.setFixEmptyMetaCells(fixEmptyMetaRegionInfo);
|
fsck.setFixEmptyMetaCells(fixEmptyMetaRegionInfo);
|
||||||
|
fsck.setFixTableLocks(fixTableLocks);
|
||||||
if (table != null) {
|
if (table != null) {
|
||||||
fsck.includeTable(table);
|
fsck.includeTable(table);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue