在前面的文章里粗略地分析了hbase的put的源码,但是对提交那块分析的不够深入.........现在把提交那块拿出来再分析一下。
书接上文,前面说了在HconnectionManager 其中有一步是提交请求,调用了如下代码
private <R> Callable<MultiResponse> createCallable(final HRegionLocation loc,
final MultiAction<R> multi, final byte [] tableName) {
final HConnection connection = this;
return new Callable<MultiResponse>() {
public MultiResponse call() throws IOException {
return getRegionServerWithoutRetries(
new ServerCallable<MultiResponse>(connection, tableName, null) {
public MultiResponse call() throws IOException {
return server.multi(multi);
}
@Override
public void connect(boolean reload) throws IOException {
server =
connection.getHRegionConnection(loc.getHostname(), loc.getPort());
}
}
);
}
};
}
跟进这个server.multi(multi); 方法,来到HRegionServer的multi这个方法
public <R> MultiResponse multi(MultiAction<R> multi) throws IOException {
checkOpen();
MultiResponse response = new MultiResponse();
for (Map.Entry<byte[], List<Action<R>>> e : multi.actions.entrySet()) {
byte[] regionName = e.getKey();
List<Action<R>> actionsForRegion = e.getValue();
// sort based on the row id - this helps in the case where we reach the
// end of a region, so that we don't have to try the rest of the
// actions in the list.
Collections.sort(actionsForRegion);
Row action;
List<Action<R>> puts = new ArrayList<Action<R>>();
for (Action<R> a : actionsForRegion) {
action = a.getAction();
int originalIndex = a.getOriginalIndex();
try {
if (action instanceof Delete) {
delete(regionName, (Delete) action);
response.add(regionName, originalIndex, new Result());
} else if (action instanceof Get) {
response.add(regionName, originalIndex, get(regionName, (Get) action));
} else if (action instanceof Put) {
puts.add(a); // wont throw.
} else if (action instanceof Exec) {
ExecResult result = execCoprocessor(regionName, (Exec)action);
response.add(regionName, new Pair<Integer, Object>(
a.getOriginalIndex(), result.getValue()
));
} else {
LOG.debug("Error: invalid Action, row must be a Get, Delete, " +
"Put or Exec.");
throw new DoNotRetryIOException("Invalid Action, row must be a " +
"Get, Delete or Put.");
}
} catch (IOException ex) {
response.add(regionName, originalIndex, ex);
}
}
// We do the puts with result.put so we can get the batching efficiency
// we so need. All this data munging doesn't seem great, but at least
// we arent copying bytes or anything.
if (!puts.isEmpty()) {
try {
HRegion region = getRegion(regionName);
if (!region.getRegionInfo().isMetaTable()) {
this.cacheFlusher.reclaimMemStoreMemory();
}
List<Pair<Put,Integer>> putsWithLocks =
Lists.newArrayListWithCapacity(puts.size());
for (Action<R> a : puts) {
Put p = (Put) a.getAction();
Integer lock;
try {
lock = getLockFromId(p.getLockId());
} catch (UnknownRowLockException ex) {
response.add(regionName, a.getOriginalIndex(), ex);
continue;
}
putsWithLocks.add(new Pair<Put, Integer>(p, lock));
}
this.requestCount.addAndGet(puts.size());
OperationStatus[] codes =
region.put(putsWithLocks.toArray(new Pair[]{}));
for( int i = 0 ; i < codes.length ; i++) {
OperationStatus code = codes[i];
Action<R> theAction = puts.get(i);
Object result = null;
if (code.getOperationStatusCode() == OperationStatusCode.SUCCESS) {
result = new Result();
} else if (code.getOperationStatusCode()
== OperationStatusCode.BAD_FAMILY) {
result = new NoSuchColumnFamilyException(code.getExceptionMsg());
}
// FAILURE && NOT_RUN becomes null, aka: need to run again.
response.add(regionName, theAction.getOriginalIndex(), result);
}
} catch (IOException ioe) {
// fail all the puts with the ioe in question.
for (Action<R> a: puts) {
response.add(regionName, a.getOriginalIndex(), ioe);
}
}
}
}
return response;
}
又是一个冗长的方法(囧......)
首先处理action 还是按region来处理的(一个region 一个 region顺序来处理的)。
在一个region范围内,首先把所有action 按照row-id 排序,并排除掉不属于该region的action。
接下来判断 action 的类型 , 如果是put类型的话 就放到新new的一个数组里。
程序再往后,对装有put的list做处理。
首先
List<Pair<Put,Integer>> putsWithLocks = Lists.newArrayListWithCapacity(puts.size());
先new 了一个存有put和锁的数组,针对于每一个put都去调用 getLockFromId 这个方法,获得锁(Integer类型),放入list中。
然后在requestcout里计数
this.requestCount.addAndGet(puts.size());
再往后就看到了提交层.......
OperationStatus[] codes =
region.put(putsWithLocks.toArray(new Pair[]{}));
接下来的工作就简单了,针对返回的codes 逐一进行遍历,
if (code.getOperationStatusCode() == OperationStatusCode.SUCCESS) {
result = new Result();
} else if (code.getOperationStatusCode()
== OperationStatusCode.BAD_FAMILY) {
result = new NoSuchColumnFamilyException(code.getExceptionMsg());
}
// FAILURE && NOT_RUN becomes null, aka: need to run again.
response.add(regionName, theAction.getOriginalIndex(), result);
如果成功了就new一个新的result放进去,如果是BAD_FAMILY这个错,就new一个Exception ,否则的话就是null。 这样上面这层就能按照返回类型进行重试判断了。
最核心的提交层又没分析........等下次吧!