前面看过了客户端入口HTable中Put、Delete的操作,然后向服务端发送rpc请求,服务端就开始干活了。
还记得Put操作在服务端的入口吗?
Put
再看下服务端RSRpcServices的put入口:
public MultiResponse multi(final RpcController rpcc, final MultiRequest request) throws ServiceException {
for (RegionAction regionAction : request.getRegionActionList()) {
this.requestCount.add(regionAction.getActionCount());
...
if (request.hasCondition()) {
...
} else {
// Mutate a list of rows atomically.
ClientProtos.RegionLoadStats stats = mutateRows(region, regionAction.getActionList(),cellScanner);
// add the stats to the request
if (stats != null) {
responseBuilder.addRegionActionResult(RegionActionResult.newBuilder()
.addResultOrException(ResultOrException.newBuilder().setLoadStats(stats)));
}
processed = Boolean.TRUE;
}
}
...
}
构造RowMutations,带着看下RowMutations是怎么设计的:
public class RowMutations implements Row {
private final List<Mutation> mutations = new ArrayList<Mutation>();
private byte [] row;
}
public interface Row extends Comparable<Row> {
/**
* @return The row.
*/
byte [] getRow();
}
继续,Put和Delete操作都会走这里!
RowMutations rm = null;
for (ClientProtos.Action action : actions) {
if (action.hasGet()) {
throw new DoNotRetryIOException("Atomic put and/or delete only, not a Get=" + action.getGet());
}
MutationType type = action.getMutation().getMutateType();
if (rm == null) {
rm = new RowMutations(action.getMutation().getRow().toByteArray());
}
// Put和Delete操作都会走这里
switch (type) {
case PUT:
rm.add(ProtobufUtil.toPut(action.getMutation(), cellScanner));
break;
case DELETE:
rm.add(ProtobufUtil.toDelete(action.getMutation(), cellScanner));
break;
default:
throw new DoNotRetryIOException("Atomic put and/or delete only, not " + type.name());
}
}
region.mutateRow(rm);
终于进入的重要的processRowsWithLocks()方法,先进行各种检查:
// 先检查每条数据是否在region的rowkey范围内
for (byte[] row : processor.getRowsToLock()) {
checkRow(row, "processRowsWithLocks");
}
// 检查region的memstoreSize是否大于blockingMemStoreSize
checkResources();
如果MemStore的堆内存超过了阻塞队列的MemStore大小,则抛RegionTooBusyException异常:
if (this.memstoreSize.get() > this.blockingMemStoreSize) {
blockedRequestsCount.increment();
requestFlush();
throw new RegionTooBusyException("Above memstore limit, " + "regionName=" + (this.getRegionInfo() == null ?
"unknown" :
this.getRegionInfo().getRegionNameAsString()) + ", server=" + (
this.getRegionServerServices() == null ? "unknown" : this.getRegionServerServices().getServerName())
+ ", memstoreSize=" + memstoreSize.get() + ", blockingMemStoreSize=" + blockingMemStoreSize);
}
// Coprocessor
startRegionOperation();
// 实例化WAL日志
WALEdit walEdit = new WALEdit();
...
后面才是重头戏,列出重要步骤:
1、运行pre-process hook
2、获得行锁
3、给region加锁
4、processor扫描行,产生mutations和waledits
5、为这次添加进MemStore的数据添加一个批次号
6、调用preBatchMutate hook
7、Apply to memstore
8、Append no sync
9、Release region lock
10、Release row lock(s)
11、Sync edit log
12、call postBatchMutate hook
13、Roll mvcc forward
14、Run post-process hook
Delete
服务端入口
public MutateResponse mutate(final RpcController rpcc, final MutateRequest request) throws ServiceException {
case DELETE:
Delete delete = ProtobufUtil.toDelete(mutation, cellScanner);
quota.addMutation(delete);
//
if (request.hasCondition()) {
Condition condition = request.getCondition();
byte[] row = condition.getRow().toByteArray();
byte[] family = condition.getFamily().toByteArray();
byte[] qualifier = condition.getQualifier().toByteArray();
CompareOp compareOp = CompareOp.valueOf(condition.getCompareType().name());
ByteArrayComparable comparator = ProtobufUtil.toComparator(condition.getComparator());
if (region.getCoprocessorHost() != null) {
processed = region.getCoprocessorHost()
.preCheckAndDelete(row, family, qualifier, compareOp, comparator, delete);
}
if (processed == null) {
boolean result = region
.checkAndMutate(row, family, qualifier, compareOp, comparator, delete, true);
if (region.getCoprocessorHost() != null) {
result = region.getCoprocessorHost()
.postCheckAndDelete(row, family, qualifier, compareOp, comparator, delete, result);
}
processed = result;
}
} else {
// 调用HRegion的delete方法
region.delete(delete);
processed = Boolean.TRUE;
}
break;
}
HRegion的delete操作,比Put操作简化了很多:
public void delete(Delete delete) throws IOException {
checkReadOnly();
checkResources();
startRegionOperation(Operation.DELETE);
try {
delete.getRow();
// All edits for the given row (across all column families) must happen atomically.
doBatchMutate(delete);
} finally {
closeRegionOperation(Operation.DELETE);
}
}
服务端在put和delete的时候,RegionCoprocessorHost做了许多工作,后面在深挖以下。