openGauss线程管理-aiocompleter

 完整代码解读 ⬇

openGauss线程管理-aiocompleter

主要功能

aiocompleter.cpp文件的整体功能是用于AIO 完成器线程完成预取(Prefetch后端写入(BackWrite )I/O操作

  • 处理异步IO请求

    • AIO 完成器线程使用 Linux Native AIO 完成 AIO 请求。

    • 单个 AIO 完成器线程为与特定 AIO 上下文和 I/O 优先级相关联的 AIO 队列提供服务。

  • 启动与停止

    • 启动

      postmaster启动子进程结束或是在执行归档恢复的开始,AIO完成器线程会立即启动,并且持续保持开启状态,直到postemaster下达终止命令

      • 正常终止 -> SIGTERM指令:指示线程等待任何挂起的 AIO 并做好退出准备。

      • 紧急终止 -> SIGQUIT指令:当AIO完成器线程意外退出,postmaster会将其视为“后端崩溃”状态,共享内存可能遭受损坏,此时通过SIGQUIT指令终止剩余的后端后启动恢复循环

    • 停止

      只能在所有工作线程或后台数据写(bgwriter)线程都已停止后,AIO完成器线程才能停止。

部分函数

1. Compltrfork_exec

功能启动异步I/O Completer线程,但是在当前的实现中,OpenGauss并不支持异步I/O,因此该函数只会发出错误消息表示不支持,并返回无效的线程ID。

在传统的设计中,进程启动时可以通过命令行参数和共享内存传递参数。而异步I/O线程是通过命令行参数传递 compltrIdx(异步I/O线程的索引),并允许运行中的线程在全局上下文中根据这个参数在 compltrArray 中找到自己的描述符,而不会改变所有。Compltrfork_exec 函数通过格式化参数列表来准备执行异步I/O Completer线程的命令。然后使用 forkexec 函数来创建一个新的线程来执行异步I/O Completer线程的处理。在这过程中,compltrIdx 会被转换为一个3字符的字符串,依次避免特殊处理该参数。

ThreadId Compltrfork_exec(int compltrIdx)
{
    // 发出错误消息,表示不支持异步I/O
    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("openGauss current do not support AIO")));
    // 返回无效的线程ID
    return InvalidTid;
}

2.  AioCompltrStart

功能设置 Aio Completer 线程描述符并启动所有 Aio 完成器线程,确保它们能够处理异步I/O请求并提供响应。

  1. 检查要启动的异步I/O Completer线程数量是否超过了最大限制。

  2. 初始化compltrArray线程数组。

  3. 遍历,处理每个要启动的异步I/O Completer线程:

    • 为线程分配对应的compltrDescp元素参数,以确定线程的处理方式和参数。

    • 创建I/O队列并填充上下文,以便监视和处理I/O事件。

    • 为线程分配事件数组内存,以便存储异步I/O事件的信息。

  4. 调用Compltrfork_exec函数启动异步I/O Completer线程,并将线程标识符存储在线程描述符中。

  5. 将全局变量AioCompltrReady设置为true,表示异步I/O Completer线程已经准备就绪。

如果在上述步骤中出现任何错误,函数将调用AioCompltrStop函数停止已启动的线程并清理资源,然后返回错误码。

int AioCompltrStart(void)
{
    int error = 0;// 错误码初始化
    int try_times = 0;// 尝试次数初始化
​
    //检查当前配置的 AIO Completer 线程数量是否超过了预定义的最大数量 MAX_AIOCOMPLTR_THREADS
    if (AioCompltrThreads > MAX_AIOCOMPLTR_THREADS) {
        error = 1;// 设置错误码
        return error;// 返回错误码,中断函数执行
    }
    // 调用安全内存函数memset_s 初始化 compltrArray,将内存设置为零
    errno_t rc = memset_s(&compltrArray,
        sizeof(AioCompltrThread_t) * MAX_AIOCOMPLTR_THREADS,
        0,
        sizeof(AioCompltrThread_t) * MAX_AIOCOMPLTR_THREADS);
    //错误检查,用于确保 memset_s 函数是否执行成功。如果 rc(返回值)不为零,表示内存初始化出现了错误
    securec_check(rc, "\0", "\0");
​
    //初始化 compltrArray 数组
    for (int i = 0; i < AioCompltrThreads; i++) {
        try_times = 0;// 尝试次数归零
        /* Assign a template to the thread descriptor */
        compltrArray[i].compltrDescp = AIOCOMPLTR_TEMPLATE(i);// 为线程描述符分配对应的模板
​
        /* Create the i/o queue and fill in the context */
        do {
            // 使用 io_setup 函数创建异步 I/O 队列,参数为当前线程的最大事件数和队列上下文。
            error = io_setup(compltrArray[i].compltrDescp->maxevents, &compltrArray[i].context);
            // 如果成功创建队列或者遇到的错误不是 EAGAIN(表示资源暂时不可用),则跳出循环。
            if (error == 0 || error != -EAGAIN) {
                break;
            }
​
            try_times++; // 尝试次数增加
            // 打印日志,记录当前尝试的线程ID、尝试次数和错误码。
            ereport(LOG, (errmsg("AIO Startup, Completer thread id =%d try times=%d, error=%d", i, try_times, error)));
            pg_usleep(100000L);// 延迟 100,000 微秒(0.1 秒),然后继续下一次尝试。
        } while (try_times < 5);// 循环继续,直到成功创建队列或者尝试次数达到 5 次。
​
        if (error != 0) {
            goto AioCompltrStartError;// 发生错误时跳转到错误处理标签
        }
​
        /* 为线程分配事件数组的内存 用于存储事件数组
         compltrArray[i].compltrDescp->max_nr 表示事件数组的最大大小,sizeof(struct io_event) 表示单个事件的大小。*/
        compltrArray[i].eventsp = (io_event*)malloc(compltrArray[i].compltrDescp->max_nr * sizeof(struct io_event));
        // 检查内存分配是否成功,失败则进入if语句内部
        if (compltrArray[i].eventsp == (struct io_event*)NULL) {
​
            /* malloc failed for some reason... */
            error = 2;// 设置错误码为 2,表示内存分配失败
            //打印日志,记录内存分配失败的详细信息,包括最大事件数和错误码。
            ereport(LOG,
                (errmsg("AIO Startup malloc io_event failed: max_nr(%d), %d",
                    compltrArray[i].compltrDescp->max_nr,
                    error)));
            // 跳转到错误处理标签 AioCompltrStartError,执行错误处理操作
            goto AioCompltrStartError;
        }
​
        //使用 Compltrfork_exec(i) 函数启动一个异步 I/O 完成线程,并将线程索引 i 作为参数传递给函数。函数返回线程的 ID。
        compltrArray[i].tid = Compltrfork_exec(i);
​
        // 检查线程是否成功启动。如果启动失败,会进入条件内部。
        if (compltrArray[i].tid == (ThreadId)-1) {
            /* starting a thread failed */
            error = 3;// 设置错误码为 3,表示启动线程失败
            // 打印日志,记录启动线程失败的详细信息,包括错误码。
            ereport(LOG, (errmsg("Start AIO Completer thread failed: %d", error)));
            goto AioCompltrStartError; // 发生错误时跳转到错误处理标签
        }
    };
​
    AioCompltrReady = true;// AIO Completers 准备就绪
​
    return 0;
​
//错误处理标签 AioCompltrStartError 标识错误处理的起始位置
AioCompltrStartError:
    /*
     * If anything went wrong, then stop any threads started
     * and deallocate the resources.
     */
    AioCompltrStop(SIGTERM);// 停止已启动的异步 I/O 完成线程并释放资源
    ereport(LOG, (errmsg("AIO Startup Failed,error=%d", error)));// 记录启动失败的错误日志
​
    return error;// 返回错误码
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值