HRegion.doMiniBatchUpdate方法解析

 

-- doMiniBatchPut(BatchOperationInProgress)

 

实例化一个WALEdit

 

 

如果CoprocessorHost不为空,对每一个Put操作调用CoprocessorHost的prePut方法,如果该方法返回true,设置这次Put操作的返回状态为

 

SUCCESS。(为什么要这样做?CoprocessorHost是干什么用的?调用prePut又是为何,源代码中说是为了防止死锁,为何这样做就能防止死锁?如果不这样做就会有死锁发生?)

 

 

一开始设置变量firstIndex和lastIndexExclusive,二者都为此次batchOperation的nextIndexToProcess。

 

 

只要lastIndexExclusive小于此次批次操作的总数量,做下面的循环,该循环的主要功能是尽可能多地得到操作某一行的行锁。

++++++++++++++++++++++++++++++++++++++++++++++++++++

 

得到下次要做处理的Put(通过batchOp.operations[lastIndexExclusive]得到),同时提取该Put的familyMap信息。

 

如果该次Put操作的状态已经执行过了(不一定是已经执行过,只要该次操作的结果code不等于OperationStatusCode.NOT_RUN),

 

lastIndexExclusive递增,退出该次操作,处理下一个Put操作。

 

检查familyMap是否合法,如果不合法,将该次Put操作的结果code设置为OperationStatusCode.BAD_FAMILY,同时递增lastIndexExclusive,退

 

出该次操作,处理下一个操作。

 

下面做该步骤的主要任务:得到该行的锁。

要获得锁需要判断客户端是否提供了lockId:

====================================================

a) 如果客户端提供了lockId,但是该行并没有被锁住,说明客户端提供了一个非法的锁,抛出一个IOException。

 

b) 如果客户端没有提供lockId,尝试调用internalObtainRowLock获得该行的锁,该方法保证一个row只能有一个锁存在。HRegion在关于行锁方

 

面有三个数据结构,分别是lockedRows,该变量是一个ConcurrentHashMap<HashedBytes, CountDownLatch>,以HashedBytes为key,该key即是

 

row,value为CountDownLatch;另外一个变量是lockIds,该变量也是一个ConcurrentHashMap<Integer, HashedBytes>,该变量的key为Integer

 

,即一把锁id,value为该锁对应的row;第三个变量是AtomicInteger类型的lockIdGenerator,当生成新的lockId时,循环incrementAndGet方

 

法直到得到一个没有被使用的锁id。使用ConcurrentHashMap.putIfAbsent方法保证了map操作的原子性。

====================================================

 

++++++++++++++++++++++++++++++++++++++++++++++++++++

 

 

此刻,我们尽可能地将游标(lastIndexExclusive)移到了该批次的尾端,firstIndex到lastIndexExclusive之间的Put操作是我们下面要做的

 

操作。下面记这些Put操作为集合PS。

 

 

对集合PS中的每一个put操作,调用updateKVTimestamps更新family的timestamp。

 

 

尝试获得updatesLock的读锁。

 

 

对集合PS中的每一个put操作,调用addFamilyMapToWALEdit,将该put的familyMap信息保存到WALEdit。

 

 

调用HLog的append方法,将WALEdit保存,这一步即是写入操作日志。

 

 

对集合PS中的每一个put操作,调用applyFamilyMapToMemstore,将该put的familyMap信息保存的memstore。此时,数据在内存中就做了添加或

 

更新。如果该

 

 

如果coprocessorHost不为空,对集合PS中的每一个put操作,调用coprocessorHost的postPut做善后处理。

 

 

设置标识变量success为true,该变量代表本批次操作是否完全成功(当然,并不是每一个put操作都成功,如果某个put的familyMap不合法,该

 

put的操作结果code为BAD_FAMILY)。

 

 

finally的善后工作

++++++++++++++++++++++++++++++++++++++++++++++++++++

 

如果获得了读锁,就解锁。

 

 

集合PS中的每一个put操作的行锁(这些行锁在最开始的循环中得到,并放入了List<Integer>类型的acquiredLocks变量中)。

 

 

如果success为false,即在处理某一个put时出错抛出了异常,需要对PS集合中操作结果是NOT_RUN的操作做处理,将这些操作结果code设置为

 

FAILURE。

 

++++++++++++++++++++++++++++++++++++++++++++++++++++

 

 

-- 能学到什么?

 

1) 合理使用ConcurrentHashMap.putIfAbsent,在不使用synchronized的情况下保证操作的原子性,提高性能。

 

2) 对大块的逻辑操作,一定要使用finally做最终的善后处理,处理诸如解锁,移除一些变量,将某些错误的操作记录下来。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值