Lustre文件系统fid介绍

fid介绍

fid是lustre文件系统中文件的唯一标识,总共128位,fid序列、fid序列内编号、fid版本号(目前未使用默认为0)

/*** File IDentifier.** FID is a cluster-wide unique identifier of a file or an object (stripe).* FIDs are never reused.**/
struct lu_fid {/*** FID sequence. Sequence is a unit of migration: all files (objects)* with FIDs from a given sequence are stored on the same server.* Lustre should support 2^64 objects, so even if each sequence* has only a single object we can still enumerate 2^64 objects.**/__u64 f_seq;/* FID number within sequence. */__u32 f_oid;/*** FID version, used to distinguish different versions (in the sense* of snapshots, etc.) of the same file system object. Not currently* used.**/__u32 f_ver;
};

fid获取流程

fld:fid location database
sequence controller: 运行在MDT0上,拥有全量的fld信息
sequence server:运行在MDT(非MDT0)和OST上,互相不会有重叠,是MDT0上fld的子集
sequence client:每个客户端在挂载文件系统时会提前申请一部分sequence,每个客户端拿到的sequence不会有重叠
管理fid范围的结构体:

/*** Describes a range of sequence, lsr_start is included but lsr_end is* not in the range.* Same structure is used in fld module where lsr_index field holds mdt id* of the home mdt.*/
struct lu_seq_range {__u64 lsr_start; //序列号起始__u64 lsr_end;  //序列号结束__u32 lsr_index;__u32 lsr_flags;
};

在同一个MDT上创建的文件,如果序列号未使用完,则这些文件的序列号相同,fid序列内编号依次递增。

如果序列号使用完,则客户端会向服务端申请下一批序列号
例:假设同一客户端依次在MDT0上创建test1和test2,那么test1的fid为[0x20001:0x1:0x0],那么test2的fid为[0x20001:0x2:0x0]
在这里插入图片描述

fid申请流程

服务端初始化阶段

mdt:

//运行于mdt上的sequnce服务
static int mdt_seq_init(const struct lu_env *env, struct mdt_device *mdt)
{struct seq_server_site    *ss;int			rc;ENTRY;ss = mdt_seq_site(mdt);/* init sequence controller server(MDT0) */if (ss->ss_node_id == 0) {OBD_ALLOC_PTR(ss->ss_control_seq);if (ss->ss_control_seq == NULL)RETURN(-ENOMEM);//在mdt0上运行sequnce controller,分配seq范围给sequence serverrc = seq_server_init(env, ss->ss_control_seq, mdt->mdt_bottom,mdt_obd_name(mdt), LUSTRE_SEQ_CONTROLLER,ss);if (rc)GOTO(out_seq_fini, rc);}/* Init normal sequence server */OBD_ALLOC_PTR(ss->ss_server_seq);if (ss->ss_server_seq == NULL)GOTO(out_seq_fini, rc = -ENOMEM);//其他的mdt会执行下面的代码,运行sequence server,给sequence server分配seq来构建fidrc = seq_server_init(env, ss->ss_server_seq, mdt->mdt_bottom,mdt_obd_name(mdt), LUSTRE_SEQ_SERVER, ss);if (rc)GOTO(out_seq_fini, rc);/* init seq client for seq server to talk to seq controller(MDT0) */rc = mdt_seq_init_cli(env, mdt);if (rc != 0)GOTO(out_seq_fini, rc);if (ss->ss_node_id != 0)/* register controller export through lwp */rc = mdt_register_seq_exp(mdt);EXIT;
out_seq_fini:if (rc)mdt_seq_fini(env, mdt);return rc;
}

ost:

//运行于ost上的sequnce服务
int ofd_fid_init(const struct lu_env *env, struct ofd_device *ofd)
{struct seq_server_site *ss = &ofd->ofd_seq_site;struct lu_device *lu = &ofd->ofd_dt_dev.dd_lu_dev;char *obd_name = ofd_name(ofd);char *name = NULL;int len = strlen(obd_name) + 7;int rc = 0;ss = &ofd->ofd_seq_site;lu->ld_site->ld_seq_site = ss;ss->ss_lu = lu->ld_site;ss->ss_node_id = ofd->ofd_lut.lut_lsd.lsd_osd_index;OBD_ALLOC(name, len);if (name == NULL)return -ENOMEM;OBD_ALLOC_PTR(ss->ss_server_seq);if (ss->ss_server_seq == NULL)GOTO(out_name, rc = -ENOMEM);//在ost上运行sequence serverrc = seq_server_init(env, ss->ss_server_seq, ofd->ofd_osd, obd_name,LUSTRE_SEQ_SERVER, ss);if (rc) {CERROR("%s: seq server init error: rc = %d\n", obd_name, rc);GOTO(out_server, rc);}ss->ss_server_seq->lss_space.lsr_index = ss->ss_node_id;OBD_ALLOC_PTR(ss->ss_client_seq);if (ss->ss_client_seq == NULL)GOTO(out_server, rc = -ENOMEM);snprintf(name, len, "%s-super", obd_name);//初始化ost上的seq clientrc = seq_client_init(ss->ss_client_seq, NULL, LUSTRE_SEQ_DATA,name, NULL);if (rc) {CERROR("%s: seq client init error: rc = %d\n", obd_name, rc);GOTO(out_client, rc);}rc = seq_server_set_cli(env, ss->ss_server_seq, ss->ss_client_seq);if (rc) {
out_client:seq_client_fini(ss->ss_client_seq);OBD_FREE_PTR(ss->ss_client_seq);ss->ss_client_seq = NULL;
out_server:seq_server_fini(ss->ss_server_seq, env);OBD_FREE_PTR(ss->ss_server_seq);ss->ss_server_seq = NULL;}
out_name:OBD_FREE(name, len);return rc;
}

当客户端创建新文件时,会检查申请到的sequence是否够用,够用的话直接走本地分配fid,然后在向MDT发送创建请求时会将新分配的fid反馈给MDT,由MDT进行处理

当客户端本地的sequence不够用时,会向sequence server申请新的sequence,如果sequence server上的sequence也不够用了,那么sequence server会向sequence controller申请新的sequence,最终返回新的sequence给客户端。
在这里插入图片描述

seq cli <–> seq svr

当client中申请的seq使用完之后会向server申请新的seq

static int seq_client_alloc_seq(const struct lu_env *env,struct lu_client_seq *seq, u64 *seqnr)
{......// eq耗尽的话调用seq_client_alloc_meta()获取新的seqif (lu_seq_range_is_exhausted(&seq->lcs_space)) {rc = seq_client_alloc_meta(env, seq);if (rc) {if (rc != -EINPROGRESS)CERROR("%s: Can't allocate new meta-sequence,""rc = %d\n", seq->lcs_name, rc);RETURN(rc);} else {CDEBUG(D_INFO, "%s: New range - "DRANGE"\n",seq->lcs_name, PRANGE(&seq->lcs_space));}} else {rc = 0;}......RETURN(rc);
}static int seq_client_rpc(struct lu_client_seq *seq,struct lu_seq_range *output, __u32 opc,const char *opcname)
{......if (seq->lcs_type == LUSTRE_SEQ_METADATA) {req->rq_reply_portal = MDC_REPLY_PORTAL;req->rq_request_portal = SEQ_METADATA_PORTAL;} else {req->rq_reply_portal = OSC_REPLY_PORTAL;req->rq_request_portal = SEQ_DATA_PORTAL;}......rc = ptlrpc_queue_wait(req);if (rc)GOTO(out_req, rc);//获取到新申请的seqout = req_capsule_server_get(&req->rq_pill, &RMF_SEQ_RANGE);*output = *out;......
}

seq server对应处理函数:

static int seq_handler(struct tgt_session_info *tsi)
{struct lu_seq_range	*out, *tmp;struct lu_site		*site;int			 rc;__u32			*opc;ENTRY;LASSERT(!(lustre_msg_get_flags(tgt_ses_req(tsi)->rq_reqmsg) & MSG_REPLAY));site = tsi->tsi_exp->exp_obd->obd_lu_dev->ld_site;LASSERT(site != NULL);opc = req_capsule_client_get(tsi->tsi_pill, &RMF_SEQ_OPC);if (opc != NULL) {out = req_capsule_server_get(tsi->tsi_pill, &RMF_SEQ_RANGE);if (out == NULL)RETURN(err_serious(-EPROTO));tmp = req_capsule_client_get(tsi->tsi_pill, &RMF_SEQ_RANGE);/* seq client passed mdt id, we need to pass that using out* range parameter */out->lsr_index = tmp->lsr_index;out->lsr_flags = tmp->lsr_flags;//走这个函数申请新seqrc = seq_server_handle(site, tsi->tsi_env, *opc, out);} else {rc = err_serious(-EPROTO);}RETURN(rc);
}static int seq_server_handle(struct lu_site *site,const struct lu_env *env,__u32 opc, struct lu_seq_range *out)
{switch (opc) {case SEQ_ALLOC_META:if (!ss_site->ss_server_seq) {CERROR("Sequence server is not ""initialized\n");RETURN(-EINVAL);}dev = lu2dt_dev(ss_site->ss_server_seq->lss_obj->do_lu.lo_dev);if (dev->dd_rdonly)RETURN(-EROFS);rc = seq_server_alloc_meta(ss_site->ss_server_seq, out, env);break;......
}int seq_server_alloc_meta(struct lu_server_seq *seq,struct lu_seq_range *out,const struct lu_env *env)
{......mutex_lock(&seq->lss_mutex);rc = __seq_server_alloc_meta(seq, out, env);mutex_unlock(&seq->lss_mutex);RETURN(rc);
}static int __seq_server_alloc_meta(struct lu_server_seq *seq,struct lu_seq_range *out,const struct lu_env *env)
{struct lu_seq_range *space = &seq->lss_space;int rc = 0;......// 检查server中seq是否够用,不够用会向controller新申请rc = seq_server_check_and_alloc_super(env, seq){if 耗尽{// 向mdt0申请新的可用的sequence rangerc = seq_client_alloc_super(seq->lss_cli, env);// 插入到本地的sequence server的fldrc = fld_insert_entry(env, fld, space);}}......// 更新server中的seq、将seq server持久化到ldiskfs、赋值给outrc = range_alloc_set(env, out, seq);......
}

seq svr <–> seq controller

当seq server中seq不足时,会向seq controller申请新的seq
seq server :

int seq_server_check_and_alloc_super(const struct lu_env *env,struct lu_server_seq *seq)
{struct lu_seq_range *space = &seq->lss_space;int rc = 0;ENTRY;/* Check if available space ends and allocate new super seq */if (lu_seq_range_is_exhausted(space)) {// 向mdt0申请seqrc = seq_client_alloc_super(seq->lss_cli, env);if (rc) {CDEBUG(D_HA, "%s: Can't allocate super-sequence:"" rc %d\n", seq->lss_name, rc);RETURN(rc);}/* Saving new range to allocation space. */*space = seq->lss_cli->lcs_space;LASSERT(lu_seq_range_is_sane(space));if (seq->lss_cli->lcs_srv == NULL) {struct lu_server_fld *fld;/* Insert it to the local FLDB */fld = seq->lss_site->ss_server_fld;mutex_lock(&fld->lsf_lock);// 将申请好的seq插入到本地的sequence server的fldrc = fld_insert_entry(env, fld, space);mutex_unlock(&fld->lsf_lock);}}if (lu_seq_range_is_zero(&seq->lss_lowater_set))__seq_set_init(env, seq);RETURN(rc);
}

controller:

static int seq_server_handle(struct lu_site *site,const struct lu_env *env,__u32 opc, struct lu_seq_range *out)
{int rc;struct seq_server_site *ss_site;struct dt_device *dev;ENTRY;ss_site = lu_site2seq(site);switch (opc) {case SEQ_ALLOC_META:......break;case SEQ_ALLOC_SUPER:if (!ss_site->ss_control_seq) {CERROR("Sequence controller is not ""initialized\n");RETURN(-EINVAL);}dev = lu2dt_dev(ss_site->ss_control_seq->lss_obj->do_lu.lo_dev);if (dev->dd_rdonly)RETURN(-EROFS);rc = seq_server_alloc_super(ss_site->ss_control_seq, out, env);break;default:rc = -EINVAL;break;}RETURN(rc);
}int seq_server_alloc_super(struct lu_server_seq *seq,struct lu_seq_range *out,const struct lu_env *env)
{int rc;ENTRY;mutex_lock(&seq->lss_mutex);rc = __seq_server_alloc_super(seq, out, env);mutex_unlock(&seq->lss_mutex);RETURN(rc);
}static int __seq_server_alloc_super(struct lu_server_seq *seq,struct lu_seq_range *out,const struct lu_env *env)
{struct lu_seq_range *space = &seq->lss_space;int rc;ENTRY;LASSERT(lu_seq_range_is_sane(space));if (lu_seq_range_is_exhausted(space)) {CERROR("%s: Sequences space is exhausted\n",seq->lss_name);RETURN(-ENOSPC);} else {//在mdt0内分配seqrange_alloc(out, space, seq->lss_width);}//将新申请的seq更新到fldrc = seq_store_update(env, seq, out, 1 /* sync */);LCONSOLE_INFO("%s: super-sequence allocation rc = %d " DRANGE"\n",seq->lss_name, rc, PRANGE(out));RETURN(rc);
}

上述理解如果有理解不正确的地方,欢迎各位大佬指正[手动抱拳]

参考了一位大佬的文章,链接如下:https://cloud.tencent.com/developer/article/2074601

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

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

相关文章

HarmonyOS SDK 助力新浪新闻打造精致易用的新闻应用

原生智能是HarmonyOS NEXT的核心亮点之一&#xff0c;依托HarmonyOS SDK丰富全面的开放能力&#xff0c;开发者只需通过几行代码&#xff0c;即可快速实现AI功能。新浪新闻作为鸿蒙原生应用开发的先行者之一&#xff0c;从有声资讯入手&#xff0c;基于Speech Kit朗读控件上线听…

【C#】.net core 6.0 设置根目录下某个文件夹可访问,访问创建的图片等资源

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

记录 | python list extend()

extend() 函数用于在列表末尾一次性追加另一个序列中的多个值&#xff08;用新列表扩展原来的列表&#xff09;。 以下实例展示了 extend()函数的使用方法&#xff1a; #!/usr/bin/pythonaList [123, xyz, zara, abc, 123]; bList [2009, manni]; aList.extend(bList)print …

应用层DoS

应用层&#xff08;application layer&#xff09;是七层OSI模型的第七层。应用层直接和应用程序 对接并提供常见的网络应用服务&#xff0c;能够在实现多个系统应用进程相互通信的同 时&#xff0c;完成一系列业务处理所需的服务。位于应用层的协议有很多&#xff0c;常见的包…

SpringBoot实现统一异常处理

文章目录 前言实现步骤定义统一响应对象类定义业务异常枚举接口和实现定义业务异常基类定义全局异常处理切面测试和验证 总结 前言 近日心血来潮想做一个开源项目&#xff0c;目标是做一款可以适配多端、功能完备的模板工程&#xff0c;包含后台管理系统和前台系统&#xff0c…

Android CMakeLists.txt语法详解

一.CMake简介 你或许听过好几种 Make 工具&#xff0c;例如 GNU Make &#xff0c;QT 的 qmake &#xff0c;微软的 MSnmake&#xff0c;BSD Make&#xff08;pmake&#xff09;&#xff0c;Makepp&#xff0c;等等。这些 Make 工具遵循着不同的规范和标准&#xff0c;所执行的…

设计模式2-对象池模式

对象池模式&#xff0c;Object Pool Pattern&#xff0c;当你的应用程序需要频繁创建和销毁某种资源&#xff08;比如数据库连接、线程、socket连接等&#xff09;时&#xff0c;Object Pool 设计模式就变得很有用。它通过预先创建一组对象并将它们保存在池中&#xff0c;以便在…

Python datetime 模块的高级应用

Python datetime 模块的高级应用 介绍方法时区处理日期格式化日期计算常见问题及解决方案代码日历应用时间序列分析 介绍 datetime 模块是 Python 中用于处理日期和时间的标准库模块。它提供了日期和时间类型&#xff08;date、time、datetime&#xff09;以及与日期和时间相关…

机器人运动学林沛群——变换矩阵

对于仅有移动&#xff0c;由上图可知&#xff1a; A P B P A P B o r g ^AP^BP^AP_{B org} APBPAPBorg​ 对于仅有转动&#xff0c;可得&#xff1a; A P B A R B P ^AP^A_BR^BP APBA​RBP 将转动与移动混合后&#xff0c;可得&#xff1a; 一个例子 在向量中&#xff…

「递归算法」:二叉树剪枝

一、题目 给你二叉树的根结点 root &#xff0c;此外树的每个结点的值要么是 0 &#xff0c;要么是 1 。 返回移除了所有不包含 1 的子树的原二叉树。 节点 node 的子树为 node 本身加上所有 node 的后代。 示例 1&#xff1a; 输入&#xff1a;root [1,null,0,0,1] 输出&…

grafana+prometheus+hiveserver2(jmx_exporter+metrics)

一、hiveserver2开启metrics&#xff0c;并启动jmx_exporter 1、修改hive-site.xml文件开启metrics <property><name>hive.server2.metrics.enabled</name><value>true</value> </property> <property><name>hive.service.m…

ChatGPT高效提问—prompt常见用法(续篇三)

ChatGPT高效提问—prompt常见用法&#xff08;续篇三&#xff09; 1.1 多选项 ​ 多选项技术为模型提供了一个清晰的问题或任务&#xff0c;并附带一组预先定义的潜在答案。这种方法在生成仅限于特定选项集的文本方面表现出色&#xff0c;适用于问答、文本补全和其他任务。利…

MySQL 日志管理

4.6&#xff09;日志管理 MySQL 支持丰富的日志类型&#xff0c;如下&#xff1a; 事务日志&#xff1a;transaction log 事务日志的写入类型为 "追加"&#xff0c;因此其操作为 "顺序IO"&#xff1b; 通常也被称为&#xff1a;预写式日志 write ahead…

《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)

文章目录 1.1 MySQL 概览&#xff1a;版本、特性和生态系统1.1.1 基础知识1.1.2 重点案例1.1.3 拓展案例 1.2 安装和配置 MySQL1.2.1 基础知识1.2.2 安装步骤1.2.3 重点案例1.2.4 拓展案例 1.3 基础命令和操作1.3.1 基础知识1.3.2 重点案例1.3.3 拓展案例 1.1 MySQL 概览&#…

【Web】vulhub Fastjson反序列化漏洞复现学习笔记

目录 1.2.24 RCE CVE-2017-18349 复现流程 原理分析 1.2.47 RCE CNVD-2019-22238 复现流程 原理分析 漏洞探测 1.2.24 RCE CVE-2017-18349 复现流程 vulhub启动靶场 用marshalsec启动LDAP/RMI服务 java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRef…

Redis篇之redis是单线程

一、redis是单线程 Redis是单线程的&#xff0c;但是为什么还那么快&#xff1f;主要原因有下面3点原因&#xff1a; 1. Redis是纯内存操作&#xff0c;执行速度非常快。 2. 采用单线程&#xff0c;避免不必要的上下文切换可竞争条件&#xff0c;多线程还要考虑线程安全问题。 …

联合体的深入了解

1.联合体类型的声明 像结构体一样&#xff0c;联合体也是由一个或者多个成员构成&#xff0c;这些成员可以不同的类型。 但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫&#xff1a;共用体。 给联合体其中一个成员赋值…

SpringBoot + Tess4J 实现本地与远程图片的文字识别

1 前言 1.1 概要 在本文中&#xff0c;我们将探讨如何在Spring Boot应用程序里集成Tess4J来实现OCR&#xff08;光学字符识别&#xff09;&#xff0c;以识别出本地和远程图片中的文字。 我们将从添加依赖说起&#xff0c;然后创建服务类以实现OCR&#xff0c;最后展示如何处…

Linux操作系统基础(一):操作系统概述

文章目录 操作系统概述 一、计算机分类 二、计算机组成 三、操作系统概述 四、操作系统分类 操作系统概述 一、计算机分类 计算机一般分为个人计算机&#xff08;笔记、台式机&#xff09;与 企业级服务器&#xff08;1U、2U、机柜、塔式、刀片&#xff09;两种形式。 二…

探索NLP中的N-grams:理解,应用与优化

简介 n-gram[1] 是文本文档中 n 个连续项目的集合&#xff0c;其中可能包括单词、数字、符号和标点符号。 N-gram 模型在许多与单词序列相关的文本分析应用中非常有用&#xff0c;例如情感分析、文本分类和文本生成。 N-gram 建模是用于将文本从非结构化格式转换为结构化格式的…