Impala3.4源码阅读笔记(二)data-cache的Lookup实现

news2024/12/22 15:23:19

前言

本文为笔者个人阅读Apache Impala源码时的笔记,仅代表我个人对代码的理解,个人水平有限,文章可能存在理解错误、遗漏或者过时之处。如果有任何错误或者有更好的见解,欢迎指正。

正文

本文介绍Lookup的具体流程和细节,如果对data-cache的工作流程还不了解,建议先阅读完Impala3.4源码阅读笔记(一)data-cache功能后再继续。
Lookup的关键步骤有二,一是根据缓存键去缓存元数据中查找缓存条目,二是根据缓存条目去缓存文件读取数据,还是那张图:
在这里插入图片描述

1. 缓存元数据

我们首先来看第一步查找缓存元数据的实现:

DataCache::Partition::Lookup中可以看到调用缓存元数据的语句如下:

Slice key = cache_key.ToSlice();
Cache::UniqueHandle handle(meta_cache_->Lookup(key, Cache::EXPECT_IN_CACHE));

其中Slice是Kudu提供的一个小工具,此处可以简单地把它理解为一个字节数组。UniqueHandle是一个包装不透明句柄的指针结构,此处可以简单地把它理解为一个handle指针。其中meta_cache_就是缓存元数据,是Partition类的私有成员,其定义为:

std::unique_ptr<Cache> meta_cache_;

Cache类是一个抽象类,定义了缓存的各种接口,我们直接看meta_cache_的具体类型,在Partition的构造函数初始化列表可以看到meta_cache_通过NewCache初始化:

meta_cache_(NewCache<Cache::EvictionPolicy::LRU, Cache::MemoryType::DRAM>(capacity_, path_))

这是一个NewCache的特化模板,从中可以看见meta_cache_实际类型为ShardedCache,其实现了缓存分片的管理功能,其内部包括了一组缓存分片,缓存分片完成缓存的具体功能:

template<>
Cache* NewCache<Cache::EvictionPolicy::LRU, Cache::MemoryType::DRAM>
    (size_t capacity, const std::string& id) {
  return new ShardedCache<Cache::EvictionPolicy::LRU>(capacity, id);
}

继续沿着Lookup的调用路径深入,meta_cache_->Lookup实际调用了ShardedCache::Lookup

UniqueHandle Lookup(const Slice& key, CacheBehavior caching) override {
    const uint32_t hash = HashSlice(key);
    HandleBase* h = shards_[Shard(hash)]->Lookup(key, hash, caching == EXPECT_IN_CACHE);
    return UniqueHandle(reinterpret_cast<Cache::Handle*>(h), Cache::HandleDeleter(this));
}

可以发现其根据Key的哈希值调用了某缓存分片的Lookup,我们继续看缓存分片的定义:

for (int s = 0; s < num_shards; s++) {
	unique_ptr<CacheShard> shard(NewCacheShard<policy>(mem_tracker_.get()));
	shard->SetCapacity(per_shard);
	shards_.push_back(shard.release());
}

其中NewCacheShard函数构造了具体的分片类型为RLCacheShard

template<Cache::EvictionPolicy policy>
CacheShard* NewCacheShard(kudu::MemTracker* mem_tracker) {
  return new RLCacheShard<policy>(mem_tracker);
}

继续沿着Lookup的调用路径深入,ShardedCache::Lookup又调用了RLCacheShard::Lookup,在RLCacheShard::Lookup中我们可以发现又调用了table_.Lookup

e = static_cast<RLHandle*>(table_.Lookup(key, hash));

table_RLCacheShard的私有成员,类型为HandleTable,这是Impala自己实现的轻量级开链哈希表,继续分析其Lookup方法:

HandleBase* Lookup(const Slice& key, uint32_t hash) {
	return *FindPointer(key, hash);
}

FindPointer之后就是开链哈希表的具体实现逻辑了,非本文重点,此处不再展开。接下来我们分析返回值HandleBase*HandleBase可以理解为哈希表的键值对,每个HandleBase以字节数组的形式保存了一对(CacheKey,CacheEntry)HandleBase*RLCacheShard::Lookup中被转换为RLHandle*类型,RLHandleHandleBase的派生类,其额外增加了引用计数和实现双链表的一些成员。获取到RLHandle后,我们返回到最外层的调用处DataCache::Partition::Lookup,根据返回的RLHandle构建CacheEntry

CacheEntry entry(meta_cache_->Value(handle));

其中meta_cache_->Value间接调用了HandleBase::value,其会以Slice的形式返回其保存的键值对的值,然后依据该Slice来构造CacheEntry。至此,我们就根据CacheKey获取到了对应的CacheEntry

2. 缓存文件

紧接上一步获取的CacheEntry,我们继续看第二步缓存文件读取的实现。

CacheEntry包括了缓存数据所在缓存文件CacheFile的指针、缓存数据在文件中的偏移量offset和缓存长度len,然后就可以调用CacheFile::Read方法读取缓存文件中的缓存数据,数据会被读进buffer,一个上层调用者传进来的字节数组地址:

 CacheFile* cache_file = entry.file();
 bytes_to_read = min(entry.len(), bytes_to_read);
 if (UNLIKELY(!cache_file->Read(entry.offset(), buffer, bytes_to_read))) {
     meta_cache_->Erase(key);
     return 0;
 }

如果有读取失败的情况则会通过meta_cache_->Erase(key)删除无效的缓存数据。我们继续看CacheFile::Read的实现,其核心读取部分为:

kudu::Status status = file_->Read(offset, Slice(buffer, bytes_to_read));

file_CacheFile的私有成员,其定义如下:

unique_ptr<RWFile> file_;

其中RWFile是一个抽象类,定义了可读写文件的接口,我们直接看file_的具体类型,CacheFile的构造函数是私有的,只允许通过其静态方法CacheFile::Create来创建CacheFile对象,在其中我们可以看见的file_初始化:

KUDU_RETURN_IF_ERROR(kudu::Env::Default()->NewRWFile(path, &cache_file->file_), "Failed to create cache file");

其调用了Env::NewRWFile来创建文件,Env也是一个抽象类,定义了一些环境接口,Default()返回一个适合当前操作系统的默认环境,实际上是Env的一个派生类PosixEnv

static Env* default_env;
static void InitDefaultEnv() { default_env = new PosixEnv; }
Env* Env::Default() {
    pthread_once(&once, InitDefaultEnv);
    return default_env;
}

继续看PosixEnvNewRWFile方法:

result->reset(new PosixRWFile(fname, fd, opts.sync_on_close));

可以看出file_的实际类型为PosixRWFile,我们继续看其Read方法:

virtual Status Read(uint64_t offset, Slice result) const OVERRIDE {
    return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1));
}

此时最初的buffer已经被包装进了一个Slice对象result,可以看见其调用了DoReadV实现文件读取,这是一个比较复杂的函数,最终调用了系统API的pread函数实现文件读取,此处也不再展开。DoReadV执行完,数据被读入buffer之后Lookup的过程也就结束了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/722125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于matlab使用深度学习进行图像类别分类(附源码)

一、前言 此示例演示如何使用预训练卷积神经网络 &#xff08;CNN&#xff09; 作为特征提取器来训练图像类别分类器。 卷积神经网络 &#xff08;CNN&#xff09; 是深度学习领域的一种强大的机器学习技术。CNN使用大量不同图像进行训练。从这些大型集合中&#xff0c;CNN可…

【软考系统架构师】数据库三大模式:外模式、概念模式和内模式

目录 1 数据库的三种模式 1.1 内模式 1.2 概念模式 1.3 外模式 2 为什么要设置这些模式 2.1 物理层 2.2 概念层 2.3 用户层 1 数据库的三种模式 1.1 内模式 也称存储模式&#xff08;Storage Schema&#xff09;&#xff0c;内模式是整个数据库的最低层表示&#xff…

【macOS 系列】mac设置截屏或其他操作的默认保存位置

1、第一步、在用户/图片文件夹下&#xff0c;新建“截图”文件夹 2、第二步、打开终端&#xff0c;输入defaults write com.apple.screencapture location ~/Pictures/截图/后回车 3、第三步、操作完成后&#xff0c;再次输入killall SystemUIServer后回车 如果你在web前端开发…

对输入图像按比例压缩、居中填充

摘要&#xff1a; 图像在输入神经网络之前&#xff0c;通常需要进行尺寸压缩&#xff0c;如yolov5的输入为640x640&#xff0c;分类网络Resnet-50的输入为224x224。通常地&#xff0c;分类网络直接将输入进行resize处理&#xff0c;而对于目标检测网络&#xff0c;为了防止目标…

js封装公用from表单验证工具验证长度邮件电话身份证非空

效果 function validateRequiredFields(formId) {var form document.getElementById(formId);var elements form.elements;var valid true;for (var i 0; i < elements.length; i) {var element elements[i];if (element.hasAttribute("req")) {var value e…

Linux:YUM仓库服务

Linux的yum仓库有4种 网络yum源 本地yum源 ftpyum源 httpyum源 第一个网络yum源不用做任何设置&#xff0c;官方默认的yum仓库配置就是从公网上下载的 环境&#xff1a; 主centos 192.168.254.11 从centos 192.168.254.10 思路&#xff1a; 我们在一台主服务器上做个本地…

30.RocketMQ之消费者拉取消息源码

highlight: arduino-light 消息拉取概述 消息消费模式有两种模式&#xff1a;广播模式与集群模式。 广播模式比较简单&#xff0c;每一个消费者需要拉取订阅主题下所有队列的消息。本文重点讲解集群模式。 在集群模式下&#xff0c;同一个消费者组内有多个消息消费者&#xff0…

split()分割字符串【JavaScript】

分割字符串 在JavaScript中&#xff0c;我们可以使用split&#xff08; &#xff09;方法把一个字符串分割成一个数组&#xff0c; 这个数组存放的是原来字符串的所有字符片段。 有多少个片段&#xff0c;数组元素个数就是多少。 语法 字符串名.split&#xff08;"分割…

TypeScript——简介、开发环境搭建、基本类型、编译选项、webpack、babel、类、面向对象的特点、接口、泛型

文章目录 第一章 快速入门0、TypeScript简介1、TypeScript 开发环境搭建2、基本类型3、编译选项4、webpack5、Babel 第二章&#xff1a;面向对象1、类&#xff08;class&#xff09;2、面向对象的特点3、接口&#xff08;Interface&#xff09;4、泛型&#xff08;Generic&…

6、架构:组件与物料设计

本章节主要是物料组件的开发设计&#xff0c;之前提到了物料的结构与构成&#xff0c;但是并没有做明确的解释。作为低代码编辑器中核心的模块之一。 物料即承担了一个提供者的角色&#xff0c;通过对编辑器注入物料组件来完成页面的渲染和可视化编辑器的编排&#xff0c;最终…

服务无法注册进Eureka

相同的配置&#xff0c;在demo里能注册&#xff0c;在自己项目的无法注册&#xff0c;眼睛都快盯出老花眼了&#xff0c;还是不行&#xff0c;果然出现的问题只有在发现问题以后才觉得简单&#xff08;虽然确实是小问题&#xff0c;但是排查了一整天&#xff0c;值得记录一下&a…

IntelliJ IDEA 控制台中文乱码和错误: 非法字符: ‘\ufeff‘

一、问题描述&#xff1a; 最近在 Windows 电脑上使用 IntelliJ IDEA 运行 Java 程序时&#xff0c;发现运行报错且控制台显示乱码。如下图1&#xff1a; &#xfffd;&#xfffd;&#xfffd;&#xfffd;: &#xfffd;&#xfffd;&#xfffd;&#xfffd; GBK &#xff…

Xshell7连接Linux服务器的两种方式

文章目录 一、创建会话式连接二、直接在窗口中连接服务器 一、创建会话式连接 打开Xshell7之后&#xff0c;点击左上角的新建。 然后可以看到一下界面 在名称位置填入会话的名称&#xff0c;自己命名的&#xff0c;叫什么都可以。 主机那里需要填写服务器的ip地址&#xff0…

100种思维模型之黄金圈思维模型-90

黄金圈法则由西蒙.斯涅克&#xff08;Simon.sinek&#xff09;在TED演讲而被人所熟知&#xff0c;它是一种更好地思考问题的习惯。 西蒙.斯涅克说&#xff1a;“世界上所有伟大的领袖和组织——无论是苹果公司&#xff0c;马丁路德金&#xff0c;还是莱特兄弟&#xff0c;他们的…

SpringBoot 集成 xxl-job 实现定时任务管理

SpringBoot 集成 xxl-job 实现定时任务管理 摘要XXL-Job 优势集成XXL-Job操作环境运行XXL-Job1. 下载XXL-Job2. 创建数据库并导入数据3. 修改数据库连接配置4. 启动项目 项目集成1. 导入依赖2. 配置 application.yml 信息3. XxlJobConfig 配置类4. 创建 XxlJobTest 任务测试dem…

qt实现日历和天气显示(QCalendarWidget)

完成展示效果&#xff1a; 本项目主要有QCalendarWidget类和获取天气api 一、QCalendarWidget 关键代码&#xff1a; ui->mCalendarWidget->setHorizontalHeaderFormat(QCalendarWidget :: ShortDayNames);//星期一、二ui->mCalendarWidget->setVerticalHeaderFo…

基于Tars高并发IM系统的设计与实现--进阶篇2

基于Tars高并发IM系统的设计与实现–进阶篇2 消息时序 分为时间和序号 时间 分布式系统中&#xff0c;消息的时间一般都取服务端本地时间戳&#xff0c;一般IM系统服务主机不止一台&#xff0c;每台机器上时间可能会有差异&#xff0c;系统处理也会有延时&#xff0c;时间也…

neo4j删除Property Keys值方法

首先&#xff0c;停止neo4j服务 然后删除安装目录下面databases下面所有文件 重新运行neo4j&#xff0c;发现Property Keys值已经完全清干净了

Docker如何安装Nacos

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

邮件收发原理及部署postfix邮件系统

目录 一、邮件收发原理 1、原理图及名词解释 2、MTA功能介绍 3、POP和IMAP获取邮件介绍 二、部署postfix邮件系统 1、环境准备 2、DNS服务器部署 3、部署Postfix 4、部署Dovecot 三、使用Foxmail测试 1、修改DNS服务器 2、Foxmail登录测试账户 3、发送测试邮件 …