这一章讲hbase的缓存机制,这里面涉及的内容也是比较多,呵呵,我理解中的缓存是保存在内存中的特定的便于检索的数据结构就是缓存。
之前在讲put的时候,put是被添加到Store里面,这个Store是个接口,实现是在HStore里面,MemStore其实是它底下的小子。
那它和Region Server、Region是什么关系?
Region Server下面有若干个Region,每个Region下面有若干的列族,每个列族对应着一个HStore。
HStore里面有三个很重要的类,在这章的内容都会提到。
protected final MemStore memstore;
private final CacheConfig cacheConf;
final StoreEngine<?, ?, ?, ?> storeEngine;
MemStore是存储着两个有序的kv集合,kv进来先写到里面,超过阀值之后就会写入硬盘。
CacheConf是针对HFileBlock的缓存,专门用来缓存快,默认是在读的时候缓存块,也可以修改列族的参数,让它在写的时候也缓存,这个在数据模型定义的时候提到过。
StoreEngine是StoreFile的管理器,它管理着这个列族对应的所有StoreFiles。
1. MemStore
memstore比较有意思,我们先看它的add方法,这个是入口。
long add(final KeyValue kv) {
this.lock.readLock().lock();
try {
KeyValue toAdd = maybeCloneWithAllocator(kv);
return internalAdd(toAdd);
} finally {
this.lock.readLock().unlock();
}
}
先把kv放到maybeCloneWithAllocator里面复制出来一个新的kv,然后再走internalAdd的方法,为啥要这么搞呢?
1.1 MemStoreLAB
先看maybeCloneWithAllocator,我们慢慢看,没关系。
private KeyValue maybeCloneWithAllocator(KeyValue kv) {
if (allocator == null) {
return kv;
}
int len = kv.getLength();
//从allocator当中分配出来len长度的非堆空间
Allocation alloc = allocator.allocateBytes(len);
if (alloc == null) {
// 太大了,allocator决定不给它分配return kv;
}
//用allocator生成的空间,new一个kv出来assert alloc != null && alloc.getData() != null;
System.arraycopy(kv.getBuffer(), kv.getOffset(), alloc.getData(), alloc.getOffset(), len);
KeyValue newKv = new KeyValue(alloc.getData(), alloc.getOffset(), len);
newKv.setMvccVersion(kv.getMvccVersion());
return newKv;
}
allocator是何许人也,它是一个MemStoreLAB,它是干啥的呀,这个让人很纠结呀?
public Allocation allocateBytes(int size) {
// 如果申请的size比maxAlloc大,就不分了if (size > maxAlloc) {
return null;
}
while (true) {
Chunk c = getOrMakeChunk();
// 给它分配个位置,返回数组的起始位置int allocOffset = c.alloc(size);
if (allocOffset != -1) {
// 用一个数据结构Allocation来描述这个,它主要包括两个信息,1:数组的引用,2:数据在数组当中的起始位置return new Allocation(c.data, allocOffset);
}
// 空间不足了,释放掉它 tryRetireChunk(c);
}
}
下面看看getOrMakeChunk看看是啥情况,挺疑惑的东西。