pub fn gc_keys(
&mut self,
keys: Vec<Key>,
safe_point: TimeStamp,
regions_provider: Option<(u64, Arc<dyn RegionInfoProvider>)>, //用来看当前key 是否还在当前 tikv server 上的,有可能 key 所在 region 已经迁移走了
) -> Result<(usize, usize)> {
let count = keys.len();
let range_start_key = keys.first().unwrap().clone().into_encoded();
let range_end_key = {
let mut k = keys
.last()
.unwrap()
.to_raw()
.map_err(|e| EngineError::Codec(e))?;
k.push(0);
Key::from_raw(&k).into_encoded()
};
let snapshot = self
.engine
.snapshot_on_kv_engine(&range_start_key, &range_end_key)?;
let mut keys = get_keys_in_regions(keys, regions_provider)?;
//得到所有 region 还在当前节点的 key
let mut txn = Self::new_txn();
let mut reader = if count <= 1 {
MvccReader::new(snapshot, None, false)
} else {
// keys are closing to each other in one batch of gc keys, so do not use
// prefix seek here to avoid too many seeks
MvccReader::new(snapshot, Some(ScanMode::Forward), false)
};
//handled_keys
//wasted_keys
let (mut handled_keys, mut wasted_keys) = (0, 0);
while {//遍历,需要处理的 key
self.gc_key(safe_point, key, &mut gc_info, &mut txn, &mut reader)
if gc_info.is_completed { // 如果这个 key 的所有版本都扫完了(没有因提前达到扫描 limiter 而提前返回)
if gc_info.found_versions > 0 { //self.reader.seek_write(&self.key, self.cur_ts)?; 扫到数据的话+1
handled_keys += 1;
} else {
wasted_keys += 1;
}
next_gc_key = keys.next();
gc_info = GcInfo::default();
} else {
Self::flush_txn(txn, &self.limiter, &self.engine)?;
let snapshot = self
.engine
.snapshot_on_kv_engine(&range_start_key, &range_end_key)?;
txn = Self::new_txn();
reader = MvccReader::new(snapshot, Some(ScanMode::Forward), false);
}
}
//再刷一下 buffer 的数据
Self::flush_txn(txn, &self.limiter, &self.engine)?;
Ok((handled_keys, wasted_keys))
}
Gc key 流程
gc_keys
=>gc_key
=> gc
=> gc.run
每次处理一条 key
从cur_ts: TimeStamp::max(), 开始扫数据
fn run(mut self, safe_point: TimeStamp) -> MvccResult<GcInfo> {
let mut state = State::Rewind(safe_point);
while next_write { // 扫数据
if txn.write_size buffer大小>= MAX_TXN_WRITE_SIZE{
返回上一层
}
}
while let Some((commit, write)) = self.next_write()? {
if self.txn.write_size >= MAX_TXN_WRITE_SIZE {
return Ok(self.info);
}
state.step(&mut self, write, commit);
}
// 最新 delete 那条数据不能一上来直接删掉,因为被MAX_TXN_WRITE_SIZE分成了多个 batch。直接删最新那条 delete,会读到旧数据
// 如果确定当前 key 的所有历史版本都删光了,就把这条 delete 也删了;否则不能删;
if let State::RemoveAll(Some((commit, write))) = state {
self.delete_write(write, commit);
}
self.info.is_completed = true;
Ok(self.info)
}