// Cache flushing thread. this.cacheFlusher = new MemStoreFlusher(conf, this);
3.HRegion:
private boolean isFlushSize(final long size) { return size > this.memstoreFlushSize; // size为当前region下所有MemStore大小的和。 }
memstoreFlushSize的默认大小是:134217728B=128MB,可以在HTableDescriptor中设置。
if (this.memstoreSize.get() > this.blockingMemStoreSize) { requestFlush(); throw new RegionTooBusyException(); }
blockingMemStoreSize默认大小是: 2 * memstoreFlushSize,系数可以设置。
1 int handlerCount = conf.getInt("hbase.hstore.flusher.count", 2); 2 this.flushHandlers = new FlushHandler[handlerCount];
4.flushHandler调用flushRegion
1 Collection<Store> specificStoresToFlush = forceFlushAllStores ? stores.values() : flushPolicy.selectStoresToFlush(); 2 FlushResult fs = internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker);
5.3.prepare阶段:internalPrepareFlushCache,主要完成memstore建立snapshot,然后将snapshot写到一个临时目录。
1 writeEntry = mvcc.begin(); 2 mvcc.completeAndWait(writeEntry);
5.3.2为region下所有store创建storeFlushContext --> 本质是storeFlusherImpl
1 /** 2 * This is not thread safe. The caller should have a lock on the region or the store. 3 * If necessary, the lock can be added with the patch provided in HBASE-10087 4 */ 5 @Override 6 public void prepare() { 7 this.snapshot = memstore.snapshot(); 8 this.cacheFlushCount = snapshot.getCellsCount(); 9 this.cacheFlushSize = snapshot.getSize(); 10 committedFiles = new ArrayList<Path>(1); 11 }
5.3.4释放region.updatesLock.writeLock --> 占用时间还是很短暂的
for (StoreFlushContext flush : storeFlushCtxs.values()) { flush.flushCache(status); } StoreFlusher flusher = storeEngine.getStoreFlusher(); IOException lastException = null; for (int i = 0; i < flushRetriesNumber; i++) { try { List<Path> pathNames = flusher.flushSnapshot(snapshot, logCacheFlushId, status); Path lastPathName = null; try { for (Path pathName : pathNames) { lastPathName = pathName; validateStoreFile(pathName); } return pathNames; } catch (Exception e) { LOG.warn("Failed validating store file " + lastPathName + ", retrying num=" + i, e); if (e instanceof IOException) { lastException = (IOException) e; } else { lastException = new IOException(e); } } } catch (IOException e) { LOG.warn("Failed flushing store file, retrying num=" + i, e); lastException = e; } .... }
5.4.2.flusher.flushSnapshot --> performFlush
1 boolean hasMore; 2 do { 3 hasMore = scanner.next(kvs, scannerContext); 4 if (!kvs.isEmpty()) { 5 for (Cell c : kvs) { 6 // If we know that this KV is going to be included always, then let us 7 // set its memstoreTS to 0. This will help us save space when writing to 8 // disk. 9 sink.append(c); 10 } 11 kvs.clear(); 12 } 13 } while (hasMore);
5.4.3.执行commit,将临时目录提交到线上目录,并更新内存中的列表。
1 for (StoreFlushContext flush : storeFlushCtxs.values()) { 2 boolean needsCompaction = flush.commit(status); 3 if (needsCompaction) { 4 compactionRequested = true; 5 } 6 byte[] storeName = it.next().getFamily().getName(); 7 List<Path> storeCommittedFiles = flush.getCommittedFiles(); 8 committedFiles.put(storeName, storeCommittedFiles); 9 // Flush committed no files, indicating flush is empty or flush was canceled 10 if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) { 11 totalFlushableSizeOfFlushableStores -= prepareResult.storeFlushableSize.get(storeName); 12 } 13 }
5.4.4.向WAL写入flush完成的标记。
1 if (wal != null) { 2 // write flush marker to WAL. If fail, we should throw DroppedSnapshotException 3 FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH, 4 getRegionInfo(), flushOpSeqId, committedFiles); 5 WALUtil.writeFlushMarker(wal, this.htableDescriptor, getRegionInfo(), 6 desc, true, mvcc); 7 }
5.5.检查是否需要split和compact。