【Alluxio】文件系统锁模型之LockPool

2024-05-08 01:12

本文主要是介绍【Alluxio】文件系统锁模型之LockPool,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Alluxio设计LockPool的主要目的是:

作为保存锁的一个资源池、不让任何正在使用的锁entries被evict掉、超过某个配置的高水位时后台线程evict那些没有使用的资源。

这个池子设计的很好,我们从这个LockPool的设计里也可以学习到如何自己设计一个资源池。

关键词:
存储Lock的池子(底层是个Map)、负载因子、evict线程、低水位、高水位。

定义LockPool里存储的实体资源类:Resource。

看到Resource类里有两个关键成员变量:一个是可重入的读写锁、另外一个是原子整数类型的引用次数。
其中读写锁是资源的实体,引用次数代表了当前实体被多少个线程使用。只有引用次数为0时资源才能被清理线程清理掉。

  /*** Resource containing the lock and other information to be stored in the pool.*/private static final class Resource {private final ReentrantReadWriteLock mLock;private volatile boolean mIsAccessed;private AtomicInteger mRefCount;private Resource(ReentrantReadWriteLock lock) {mLock = lock;mIsAccessed = false;mRefCount = new AtomicInteger(1);}}

LockPool存储Resource实体的数据结构定义

public class LockPool<K> implements Closeable {// 存储Resource的Map,根据key获取对应的锁资源,会被初始化成ConcurrentHashMap类型,线程安全private final Map<K, Resource> mPool;// 通过key对应的Resource在mPool里不存在,使用这个mDefaultLoader去生成Resource对象放进mPool映射里.private final Function<? super K, ? extends ReentrantReadWriteLock> mDefaultLoader;// 低水位private final int mLowWatermark;// 高水位private final int mHighWatermark;// 下面的成员变量都跟evictor相关,清理无用Resource	private final Lock mEvictLock = new ReentrantLock();private final Condition mOverHighWatermark = mEvictLock.newCondition();private final ExecutorService mEvictor;private final Future<?> mEvictorTask;
}

上面是成员变量。看下依据key(一般是inode id)获取Resource的源码,见LockPool#getResource方法:

  // 参数是泛型,一般外层传的是Long类型的inode id,可以理解成文件idprivate Resource getResource(K key) {// key不允许为nullPreconditions.checkNotNull(key, "key can not be null");// 使用Map接口的compute方法对(k,v)进行重映射。// 1、如果key存在于mPool中,则置资源对象的mIsAccessed为true,并把mRefCount自增1后返回。// 2、如果mPool中不存在key,则new Resource返回。 关于mDefaultLoader的逻辑我们后面看Resource resource = mPool.compute(key, (k, v) -> {if (v != null && v.mRefCount.incrementAndGet() > 0) {// If the entry is to be removed, ref count will be INT_MIN, so incrementAndGet will < 0.v.mIsAccessed = true;return v;}return new Resource(mDefaultLoader.apply(k));});// 如果当前池子里的资源数超过了高水位if (mPool.size() > mHighWatermark) {if (mEvictLock.tryLock()) {try {// Condition对象发出信号,唤醒await的evictor线程,进行清理工作。mOverHighWatermark.signal();} finally {mEvictLock.unlock();}}}// 返回当前资源。return resource;}

看下mDefaultLoader的逻辑,也就是说怎么把一个(k,v)添加到mPool里的:
mDefaultLoader是个Function, 第一个泛型是输入类型,第二个泛型是期望的输出类型。

private final Function<? super K, ? extends ReentrantReadWriteLock> mDefaultLoader;

在InodeLockManager类里,初始化LockPool时,会传入mDefaultLoader参数。如下所示:

  private final LockPool<Long> mInodeLocks =new LockPool<>((key) -> new ReentrantReadWriteLock(),Configuration.getInt(PropertyKey.MASTER_LOCK_POOL_INITSIZE),Configuration.getInt(PropertyKey.MASTER_LOCK_POOL_LOW_WATERMARK),Configuration.getInt(PropertyKey.MASTER_LOCK_POOL_HIGH_WATERMARK),Configuration.getInt(PropertyKey.MASTER_LOCK_POOL_CONCURRENCY_LEVEL));

因此mDefaultLoader是:

(key) -> new ReentrantReadWriteLock()

结合Map的compute函数,当mPool里不存在key时,就用key初始化一个ReentrantReadWriteLock,然后put(key, new ReentrantReadWriteLock())。

常用方法:
get
tryGet
getRawReadWriteLock

LockPool的使用

MetadataSyncLockManager、InodeLockManager。

这里我们先只关注InodeLockManager。

InodeLockManager主要职责就是负责管理inode locking相关事项。

其内部有两个LockPool,一个是用于inode lock的LockPool<Long> mInodeLocks
另一个是用于edge locks的LockPool<Edge> mEdgeLocks

看下加锁逻辑:InodeLockManager#lockInode。
返回的是个RWLockResource类对象。

  // LockMode有读、写两种模式public RWLockResource lockInode(InodeView inode, LockMode mode, boolean useTryLock) {// 从LockPool里根据inode id去get锁资源。return mInodeLocks.get(inode.getId(), mode, useTryLock);}

这篇关于【Alluxio】文件系统锁模型之LockPool的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968900

相关文章

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Linux中的缓冲区和文件系统详解

《Linux中的缓冲区和文件系统详解》:本文主要介绍Linux中的缓冲区和文件系统方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、FILE结构1、fd2、缓冲区二、文件系统1、固态硬盘2、逻辑地址LBA(一)数据块 Data blocks(二)inode表

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

SpringBoot快速接入OpenAI大模型的方法(JDK8)

《SpringBoot快速接入OpenAI大模型的方法(JDK8)》本文介绍了如何使用AI4J快速接入OpenAI大模型,并展示了如何实现流式与非流式的输出,以及对函数调用的使用,AI4J支持JDK8... 目录使用AI4J快速接入OpenAI大模型介绍AI4J-github快速使用创建SpringBoot

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

Spring AI Alibaba接入大模型时的依赖问题小结

《SpringAIAlibaba接入大模型时的依赖问题小结》文章介绍了如何在pom.xml文件中配置SpringAIAlibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓... 目录(一)pom.XML文件:(二)application.yml配置文件(一)pom.xml文件:首

如何在本地部署 DeepSeek Janus Pro 文生图大模型

《如何在本地部署DeepSeekJanusPro文生图大模型》DeepSeekJanusPro模型在本地成功部署,支持图片理解和文生图功能,通过Gradio界面进行交互,展示了其强大的多模态处... 目录什么是 Janus Pro1. 安装 conda2. 创建 python 虚拟环境3. 克隆 janus

本地私有化部署DeepSeek模型的详细教程

《本地私有化部署DeepSeek模型的详细教程》DeepSeek模型是一种强大的语言模型,本地私有化部署可以让用户在自己的环境中安全、高效地使用该模型,避免数据传输到外部带来的安全风险,同时也能根据自... 目录一、引言二、环境准备(一)硬件要求(二)软件要求(三)创建虚拟环境三、安装依赖库四、获取 Dee