#文件管理
YFS 提供两种管理接口:
- 命令行下通过
yfscmd
管理文件。 - 通过 C API 在程序中操作 YFS 文件。
指定YFS文件路径:
/
开头为本地文件系统路径。+
开头为YFS路径,例如'+DG0/data'。
# 通过 yfscmd 管理
通过yfscmd工具,用户可以使用与Linux shell类似的文件操作命令,对YFS中的文件进行查询和管理。
# 启动yfscmd shell
成功启动yfscmd shell的前提:
- YFS服务已启动(通过ycsctl status查看)。
YASCS_HOME
环境变量已正确设置。
$ yfscmd
成功进入shell后即可执行下述命令。
# 查看当前目录
通过 pwd
查看当前工作目录。
yfscmd
启动时的工作路径为YFS的根目录 +
。
YFSCMD > pwd
+
# 切换目录
通过 cd
命令切换工作目录,可以指定 YFS 绝对路径或相对路径。
YFSCMD > cd +DG2
# 创建目录
通过 mkdir
创建目录,新目录不能与同级的任何文件或目录同名。
注意:根目录 +
下一级目录是diskgroup的虚拟目录,不能通过 mkdir
在此创建目录。仅可以通过创建diskgroup实现在此创建目录的目的。
YFSCMD > mkdir data1
YFSCMD > ls
data1
# 复制
通过 cp
命令复制文件或目录。如果第一个参数是目录,则递归复制。
cp
不仅支持YFS内部文件、目录的复制,也可以YFS和本地文件系统互相复制。
cp 命令通过参数的第一个字符识别文件系统:
/
开始为本地文件系统路径,+
开始为YFS路径,- 相对路径为YFS路径。
# 系统复制到YFS
YFSCMD > cp /home/yashan/data2.dat data2
cp OK: SYS:/home/yashan/data2.dat --> YFS:+DG2/data2
YFSCMD > ls
data1
data2
# YFS复制到系统
YFSCMD > cp data1 /home/yashan/data1
cp OK: YFS:+DG2/data1 --> SYS:/home/yashan/data1
# YFS内复制
YFSCMD > cp data2 data3.dat
cp OK: YFS:+DG2/data2 --> YFS:+DG2/data3.dat
Note:
与一般文件系统缺省创建同名对象不同,
cp
命令的第二个参数需明确指明新名称。
# 查看文件清单
通过 ls
指令查看文件清单,详细使用请参考yfscmd说明文档。
YFSCMD > ls
data1
data2
data3.dat
# 删除
通过 rm
命令删除文件或目录。
默认不能删除非空目录,但可以指定 -r
参数递归删除非空目录。
注意:根目录 +
下一级目录是diskgroup的虚拟目录,不能通过rm删除。只能通过删除diskgroup,删除对应的虚拟目录。
YFSCMD > rm data1
Delelte +DG2/data1
# 重命名
通过 mv
重命名文件或目录。第二个参数必须明确指定新名称。
注意:根目录 +
下一级目录是diskgroup的虚拟目录,不能被重命名。
YFSCMD > mv data2 data1
mv: YFS:+DG2/data2 --> YFS:+DG2/data1.
YFSCMD > ls
data1
data3.dat
# 通过C API管理
# 基本概念
YFS提供了一组C API(以下简称API),方便通过程序访问YFS。
通过API访问YFS的程序,称为YFS的客户端。YFS通过UDS和共享内存提供服务,仅允许客户端访问本地(部署在同一服务器上)的YFS服务,且要求客户端进程具备该UDS和共享内存的访问权限。
API通过YfsiConn
抽象客户端与YFS服务间的连接,每个线程必须独立使用一个YfsiConn
以获得更高的数据安全保障。所有API都需要传入YfsiConn
,并确保开始操作前先创建连接,所有操作结束时及时关闭并释放连接,不要重复释放连接。
YFS通过uint32_t
表示打开的文件fd。
YFS仅支持DIRECT IO,因此文件IO的offset、length及buffer的地址,都需按YFS_ALIGN_SIZE
字节对齐,其定义为:
#define YFS_ALIGN_SIZE 512
请按以下流程操作YFS文件:
- 打开文件
- 任意次数读写文件
- 关闭文件
YFS是高性能集群文件系统,各节点IO完全并行,客户端应妥善处理并发IO、并发文件增删等操作,避免出错。
API均为yfsi
前缀的C函数,采用驼峰命名规范。
除返回void
的函数外,返回int
的函数遵循以下规范:
- 返回0,表示执行成功。
- 返回非零,表示执行失败,可以通过
codGetErrorCode
获取错误码,通过codGetErrorMsg
获取错误信息。
# API说明
# yfsiAllocConn
int yfsiAllocConn(YfsiConn** conn);
创建连接对象,必须在不同线程使用独立的连接。
参数 | 描述 |
---|---|
conn | 连接对象二级指针 |
# yfsiFreeConn
void yfsiFreeConn(YfsiConn* conn);
释放连接对象。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
# yfsiConnect
int yfsiConnect(YfsiConn* conn, const char* url);
连接到服务。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
url | 连接地址,请通过yfsiFormatUrl 格式化该URL |
示例
char linkUrl[1024] = {0};
yfsiFormatUrl("/YFS/home", linkUrl, 1024);
if (yfsiConnect(conn, linkUrl) != 0) {
printf("failed connect to YFS server. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
// error handling
}
# yfsiDisconnect
void yfsiDisconnect(YfsiConn* conn);
断开连接。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
# yfsiOpenFile
int yfsiOpenFile(YfsiConn* conn, const char* fileName, uint32_t* fd);
打开文件。仅支持打开YFS文件,试图打开目录或非YFS文件都会失败。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
fileName | 文件的绝对路径,仅支持YFS路径,格式为+磁盘组名称/目录/文件名 |
fd | fd指针 |
示例
uint32_t fd = 0;
if (yfsiOpenFile(conn, "+DG0/testdir/testfile", &fd) != 0) {
printf("failed open file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
// error handling
}
# yfsiCloseFile
int yfsiCloseFile(YfsiConn* conn, uint32_t fd);
关闭文件。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
fd | 通过yfsiOpenFile 打开的fd |
示例
(void) yfsiCloseFile(conn, fd);
# yfsiWriteFile
int yfsiWriteFile(YfsiConn* conn, uint32_t fd, char* buf, uint64_t offset, uint32_t size);
向已打开的文件写入数据。YFS不支持文件自动扩展,请确保文件有足够的空间写入数据。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
fd | 通过yfsiOpenFile 打开的fd |
buf | 待写入数据所在buffer,该buffer地址必须YFS_ALIGN_SIZE 字节对齐 |
offset | 写入文件的偏移,按YFS_ALIGN_SIZE 字节对齐 |
size | 写入数据大小,按YFS_ALIGN_SIZE 字节对齐 |
示例
if (yfsiWriteFile(conn, fd, buffer, 0, 1024) != 0) {
printf("failed write file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
// error handling
}
# yfsiReadFile
int yfsiReadFile(YfsiConn* conn, uint32_t fd, char* buf, uint64_t offset, uint32_t size, uint32_t* actualSize);
读取已打开的文件。YFS 不允许超出文件末尾的读操作。
参数 | 描述 |
---|---|
conn | 连接对象指针 |
fd | 通过yfsiOpenFile 打开的fd |
buf | 用于保存读出数据的buffer,该buff地址必须YFS_ALIGN_SIZE 字节对齐 |
offset | 写入文件的偏移,按YFS_ALIGN_SIZE 字节对齐 |
size | 写入数据大小,按YFS_ALIGN_SIZE 字节对齐 |
actualSize | 实际读入数据长度 |
示例
uint32_t realLen = 0;
if (yfsiReadFile(conn, fd, buffer, 0, 1024, &realLen) != 0) {
printf("failed read file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
// error handling
}
# yfsiFormatUrl
void yfsiFormatUrl(const char *home, char *url, int len);
格式化 YFS 连接的 url。
参数 | 描述 |
---|---|
home | YFS的home路径,通常为YASCS_HOME 环境变量的值,即YFS配置文件所在目录的父目录 |
url | 输出url的buffer |
len | url buffer的长度 |
示例
char linkUrl[1024] = {0};
yfsiFormatUrl("/YFS/home", linkUrl, 1024);
# 错误信息
uint32_t codGetErrorCode();
char* codGetErrorMsg();
获取错误码和错误信息。
# 完整示例
#include <stdio.h>
#include <stdlib.h>
// 引入YFS API头文件
#include "yfsi_include.h"
int main(int argc, const char ** argv)
{
if (argc < 2 || argv[1][0] != '+') {
printf("expecting YFS path, like: +DG0/file/path\n");
return 1;
}
const char* path = argv[1];
/*
* 获取YFS的home路径,通常为YASCS_HOME环境变量、yascs或yasfs进程的-D参数。
* 这里以YASCS_HOME环境变量为例。
*/
const char* home = getenv("YASCS_HOME");
if (home == NULL || strlen(home) == 0) {
printf("YASCS_HOME not set yet.\n");
return 1;
}
/**
* 申请buffer,必须按YFS_ALIGN_SIZE对齐.
*/
char* buffer = NULL;
if (posix_memalign((void **)&buffer, YFS_ALIGN_SIZE, 1024) != 0 ) {
printf("failed alloc buffer.\n");
return 1;
}
/**
* 创建连接
*/
YfsiConn *conn = NULL;
if (yfsiAllocConn(&conn) != 0) {
printf("failed alloc connection. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
free(buffer);
return 1;
}
/**
* 生成连接url
*/
char linkUrl[1024] = {0};
yfsiFormatUrl(home, linkUrl, 1024);
/**
* 连接到服务
*/
if (yfsiConnect(conn, linkUrl) != 0) {
printf("failed connect to the yfs server. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
yfsiFreeConn(conn);
free(buffer);
return 1;
}
/**
* 打开文件,获得fd
*/
uint32_t fd;
if (yfsiOpenFile(conn, path, &fd) != 0) {
printf("failed open file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
yfsiDisconnect(conn);
yfsiFreeConn(conn);
free(buffer);
return 1;
}
printf("open file.\n");
/**
* 读取文件,应确保读范围在文件大小内,否则失败。
*/
uint32_t realLen = 0;
if (yfsiReadFile(conn, fd, buffer, 0, 1024, &realLen) != 0) {
printf("failed read file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
yfsiCloseFile(conn, fd);
yfsiDisconnect(conn);
yfsiFreeConn(conn);
free(buffer);
return 1;
}
printf("read file, len = %u.\n", realLen);
/**
* 写入文件,应确保写入范围在文件大小内,否则失败。
*/
if (yfsiWriteFile(conn, fd, buffer, 0, 1024) != 0) {
printf("failed write file. [%u] %s\n", codGetErrorCode(), codGetErrorMsg());
yfsiCloseFile(conn, fd);
yfsiDisconnect(conn);
yfsiFreeConn(conn);
free(buffer);
return 1;
}
printf("write file, len = %u.\n", 1024);
/**
* 关闭打开的文件
* 断开连接
* 释放连接
* 释放buffer内存
*/
yfsiCloseFile(conn, fd);
yfsiDisconnect(conn);
yfsiFreeConn(conn);
free(buffer);
return 0;
}