【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

相关文章

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

SpringBoot整合Sa-Token实现RBAC权限模型的过程解析

《SpringBoot整合Sa-Token实现RBAC权限模型的过程解析》:本文主要介绍SpringBoot整合Sa-Token实现RBAC权限模型的过程解析,本文给大家介绍的非常详细,对大家的学... 目录前言一、基础概念1.1 RBAC模型核心概念1.2 Sa-Token核心功能1.3 环境准备二、表结

什么是ReFS 文件系统? ntfs和refs的优缺点区别介绍

《什么是ReFS文件系统?ntfs和refs的优缺点区别介绍》最近有用户在Win11Insider的安装界面中发现,可以使用ReFS来格式化硬盘,这是不是意味着,ReFS有望在未来成为W... 数十年以来,Windows 系统一直将 NTFS 作为「内置硬盘」的默认文件系统。不过近些年来,微软还在研发一款名

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

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步搞定一个应