文章目录
读一条value可真费劲
总体代码
@Override
public byte[] get(byte[] key, ReadOptions options)
throws DBException
{
checkBackgroundException();
LookupKey lookupKey;
mutex.lock();
try {
SnapshotImpl snapshot = getSnapshot(options);
lookupKey = new LookupKey(Slices.wrappedBuffer(key), snapshot.getLastSequence());
LookupResult lookupResult = memTable.get(lookupKey);
if (lookupResult != null) {
Slice value = lookupResult.getValue();
if (value == null) {
return null;
}
return value.getBytes();
}
if (immutableMemTable != null) {
lookupResult = immutableMemTable.get(lookupKey);
if (lookupResult != null) {
Slice value = lookupResult.getValue();
if (value == null) {
return null;
}
return value.getBytes();
}
}
}
finally {
mutex.unlock();
}
LookupResult lookupResult = versions.get(lookupKey);
mutex.lock();
try {
if (versions.needsCompaction()) {
maybeScheduleCompaction();
}
}
finally {
mutex.unlock();
}
if (lookupResult != null) {
Slice value = lookupResult.getValue();
if (value != null) {
return value.getBytes();
}
}
return null;
}
步骤
step0. 加互斥锁,ReentrantLock
step1. 根据option决定是否生成快照
step2. 根据编码规则生成LookupKey
LookupKey的类型是InternalKey(User key+sequence number+value type)
step3. 从memtable中找value,找不到执行下一步
step4. 从immutableMemTable中找,找不到执行下一步
step5. 从当前version的sst文件中找
在versionSet中的当前版本找
public LookupResult get(LookupKey key)
{
return current.get(key);
}
在当前版本中一层一层往下找
public LookupResult get(LookupKey key)
{
// 首先从level 0 找,找不到的话,一层一层往下找
ReadStats readStats = new ReadStats();
LookupResult lookupResult = level0.get(key, readStats);
if (lookupResult == null) {
for (Level level : levels) {
lookupResult = level.get(key, readStats);
if (lookupResult != null) {
break;
}
}
}
updateStats(readStats.getSeekFileLevel(), readStats.getSeekFile());
return lookupResult;
}
ReadStats记录了level信息,需要在每次查找中携带
public class ReadStats
{
private int seekFileLevel = -1;
private FileMetaData seekFile;
}
level 0的查找源码如下:
public LookupResult get(LookupKey key, ReadStats readStats)
{
if (files.isEmpty()) {
return null;
}
List<FileMetaData> fileMetaDataList = new ArrayList<>(files.size());
// level0 内的.sst文件,两个文件可能存在key重叠,所以需要遍历level0内的sst,找到要查找的key在sst内的所有sst
// 如果不是level0 内的.sst文件,key不存在重叠
for (FileMetaData fileMetaData : files) {
if (internalKeyComparator.getUserComparator().compare(key.getUserKey(), fileMetaData.getSmallest().getUserKey()) >= 0 &&
internalKeyComparator.getUserComparator().compare(key.getUserKey(), fileMetaData.getLargest().getUserKey()) <= 0) {
fileMetaDataList.add(fileMetaData);
}
}
// 根据file number,将新的fileMetaData排在前面
Collections.sort(fileMetaDataList, NEWEST_FIRST);
readStats.clear();
for (FileMetaData fileMetaData : fileMetaDataList) {
// 根据fileMetaData中的file number,从tableCache中获得对应的table的iterator
InternalTableIterator iterator = tableCache.newIterator(fileMetaData);
// 在table中指向 >= lookup key的第一个key
iterator.seek(key.getInternalKey());
if (iterator.hasNext()) {
// 解析出block中的key
Map.Entry<InternalKey, Slice> entry = iterator.next();
InternalKey internalKey = entry.getKey();
checkState(internalKey != null, "Corrupt key for %s", key.getUserKey().toString(UTF_8));
// 如果找到了key
// 1. valuetype是value,那么返回LookupResult
// 1. valuetype是delete,那么返回LookupResult
if (key.getUserKey().equals(internalKey.getUserKey())) {
if (internalKey.getValueType() == ValueType.DELETION) {
return LookupResult.deleted(key);
}
else if (internalKey.getValueType() == VALUE) {
return LookupResult.ok(key, entry.getValue());
}
}
}
// 如果readStats中没有File信息,设置当前最新的sst文件为level0
if (readStats.getSeekFile() == null) {
readStats.setSeekFile(fileMetaData);
readStats.setSeekFileLevel(0);
}
}
return null;
}
其他level的查找如下:
public LookupResult get(LookupKey key, ReadStats readStats)
{
if (files.isEmpty()) {
return null;
}
List<FileMetaData> fileMetaDataList = new ArrayList<>(files.size());
// level0 内的.sst文件,两个文件可能存在key重叠,所以需要遍历level0内的sst,找到要查找的key在sst内的所有sst
// 如果不是level0 内的.sst文件,key不存在重叠,就可以直接二分
if (levelNumber == 0) {
for (FileMetaData fileMetaData : files) {
if (internalKeyComparator.getUserComparator().compare(key.getUserKey(), fileMetaData.getSmallest().getUserKey()) >= 0 &&
internalKeyComparator.getUserComparator().compare(key.getUserKey(), fileMetaData.getLargest().getUserKey()) <= 0) {
fileMetaDataList.add(fileMetaData);
}
}
}
else {
// 二分查找最小的 key >= ikey的文件
int index = ceilingEntryIndex(Lists.transform(files, FileMetaData::getLargest), key.getInternalKey(), internalKeyComparator);
// 如果已经找到了文件最后,都没找到,说明sstable中不包含key
if (index >= files.size()) {
return null;
}
// 验证文件的最小key是不是大于key
FileMetaData fileMetaData = files.get(index);
if (internalKeyComparator.getUserComparator().compare(key.getUserKey(), fileMetaData.getSmallest().getUserKey()) < 0) {
return null;
}
// 将该文件添加到带查找列表
fileMetaDataList.add(fileMetaData);
}
FileMetaData lastFileRead = null;
int lastFileReadLevel = -1;
readStats.clear();
for (FileMetaData fileMetaData : fileMetaDataList) {
if (lastFileRead != null && readStats.getSeekFile() == null) {
// 记录第一个文件的信息
readStats.setSeekFile(lastFileRead);
readStats.setSeekFileLevel(lastFileReadLevel);
}
lastFileRead = fileMetaData;
lastFileReadLevel = levelNumber;
// 根据fileMetaData中的file number,从tableCache中获得对应的table的iterator
InternalTableIterator iterator = tableCache.newIterator(fileMetaData);
// 在table中指向 >= lookup key的第一个key
iterator.seek(key.getInternalKey());
if (iterator.hasNext()) {
// 解析出block中的key
Map.Entry<InternalKey, Slice> entry = iterator.next();
InternalKey internalKey = entry.getKey();
checkState(internalKey != null, "Corrupt key for %s", key.getUserKey().toString(UTF_8));
// 如果找到了key
// 1. valuetype是value,那么返回LookupResult
// 1. valuetype是delete,那么返回LookupResult
if (key.getUserKey().equals(internalKey.getUserKey())) {
if (internalKey.getValueType() == ValueType.DELETION) {
return LookupResult.deleted(key);
}
else if (internalKey.getValueType() == VALUE) {
return LookupResult.ok(key, entry.getValue());
}
}
}
}
return null;
}
step6. 加互斥锁
step7. 判断是否需要compact,需要就compact
压缩条件如下:
public boolean needsCompaction()
{
return current.getCompactionScore() >= 1 || current.getFileToCompact() != null;
}
// todo:压缩过程待另写一篇博客