#文件管理

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文件:

  1. 打开文件
  2. 任意次数读写文件
  3. 关闭文件

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;
}