1. Put put = new Put(key);首先会构造put对象,以传入的rowkey,如果未传入时间戳,那么就会默认为null,接下来就会判断是否传入的控制hbase事务的rowlock,如果传入的rowlock不为空,那么就拿到lockId,赋值给当前lockid.
调用的代码为
return new KeyValue(this.row, family, qualifier, ts, KeyValue.Type.Put,value);将生产好的keyvalue,加入cf对于的keyvalue list中,然后将信息再全部放入familyMap中。
(3)当put中add完要加入的colmn对应的cf,name,value之后,便调用table.put方法,这里调用的方法是天蓉师姐改过源码之后的putOne方法,原来的put方法会将你放入的put加入一个writeBuffer的arraylist中,然后统计当前currentWriteBufferSize的大小,如果大于了writeBufferSize,并且设置了autoflush,就会调用flushCommits方法,这个方法会将你放入writeBuffer中的所有put对象,在新版本中是采用的调用processBatch方法,processBatch内部有retry机制,如果是retry,就会根据retry次数得到一个pausetime,然后sleep该pausetime。 接下来,会通过tablename,row,是否启用缓存这3个参数,去定位region:
HRegionLocation loc = locateRegion(tableName, row.getRow(), true);
(a) 如果tableName == -ROOT- 就会调用waitRootRegionLocation方法,通过zookeeper得到rootregion的地址。接下来返回一个new HRegionLocation(HRegionInfo.ROOT_REGIONINFO, hsa);
(b) 如果tableName == .META.,就会调用locateRegionInMeta方法,先去从缓存中拿,如果缓存中没有,会组合metakey,然后去获得这个row所在的的region在哪个哪个regionServer上。
(c) 如果不是.META.表也不是-ROOT-表,那么也会调用locateRegionInMeta方法,parentTable传入meta表,依然通过参数形成metakey,
定位到region之后,拿到region对应的serveraddress,然后组装MultiAction,将HserverAddress以及MultiAction放入Map<HServerAddress, MultiAction> actionsByServer中,接下来遍历actionsByServer,建立异步任务,createCallable,然后将异步任务submit给threadpool,call方法会调用public MultiResponse multi(MultiAction multi)方法,为这个multiaction中对应的每个action,即每个活动,判断action类型,delete,get,put,然后针对不同的做不同的处理,这些是多线程的 处理,核心会调用doMiniBatchPut方法,并在写入完之后,清空writeBuffer
doMiniBatchPut方法:
1. 第一步是尽最大可能获得锁,(Try to acquire as many locks as we can),保证我们至少有一个锁,期间会检验checkFamilies,并且如果没有足够的rows,会陷入阻塞,numReadyToWrite这个属性就是判断有多少个rows需要put,知道获得了next one,然后就是获得锁的过程。
2. 第二步,更新时间戳。
3. 第三步,写入WAL日志,WALLog与mysql的binlog类似,作用都是灾难恢复,它记录所有的数据改动。一旦服务器崩溃,通过重放log,我们可以恢复崩溃之前的数据。这也意味如果写入WAL失败,整个操作将认为失败。(红色字体参考的是网上资料)。
4. 第四步,写入memstore中,然后返回OperationStatusCode.SUCCESS。
(4)当doMiniBatchPut调用完成之后,会返回addedSize,此时,将memstoreSize加上addedSize然后判断是否满足条件flush到磁盘,这里的条件是看size > this.memstoreFlushSize;而memstoreFlushSize是由regionInfo.getTableDesc().
getMemStoreFlushSize()获得的。默认大小是long DEFAULT_MEMSTORE_FLUSH_SIZE = 1024*1024*64L;64MB。如果满足了flush条件,就会把writestate.flushRequested标志位设为true,由单独的线程flush到磁盘上,成为一个StoreFile。
但是官方的插入策略第一步是放入本地缓存中,即writeBuffer中,只有满足条件了,才会调用flushCommits方法,也就是说放入本地缓存的时候,并没有计入WAL日志,如果这个时候机器挂了,那么数据就丢失了,无法恢复。
其他实现是:
直接调用HregionServer的put方法,不将put放入writeBuffer中,得到相应的region之后,调用region的put方法,这里的put方法,也是更新时间戳,写入WAL日志,写入memstore中。
(5)Hregion存储了table中某一个region的数据,它存储了每一行的所有columns,一个table由一个或多个Hregions组成,一个Hregion中包含了多个Hstore,Store是包含了部分列的行的集合,同时,他们组成了这些行的所有数据。
一个Hregion是靠表以及key的范围定义的,它至少包含一个store,store的数量是可配置的,以便同时进来的数据能存放在同一个store中,目前,我们近似通过为每个列族创建一个store
HtableDescriptor包含了hregion所在的table的元数据信息,regionname是一个Hregion的唯一标识符,(startKey, endKey]定义了这个Hregion的key区间。