【问题标题】:Developing Cross Platform Apache Modules using ap_retained_data_create/get in Post Read Config在 Post Read Config 中使用 ap_retained_data_create/get 开发跨平台 Apache 模块
【发布时间】:2012-06-01 06:08:50
【问题描述】:

在构建跨平台模块的同时,我非常高兴地调试了 Apache 2.4 设计中的一个怪癖。

我遇到的问题是 Apache 在启动时会加载配置文件两次,从而加载模块本身两次。一旦我猜测要测试配置并读取命令结构,然后接下来填写空白以供服务器运行。这通常不会有任何问题,但我需要在加载时加载我的模块配置,然后再为任何客户端提供服务,并且只解析我的模块的需求一次和一次。

由于我使用了包括数据库等在内的大量资源,我认为多次运行并不是最好的主意,尤其是在访问数据库服务器时。

在线手册(“Developer API 2.5”)说不要使用旧方法(我将让读者自行查找),而是使用 ap_retained_data_get 和 ap_retained_data_create 在模块卸载期间保留数据。最好将标志传递给您已经通过测试阶段的下一阶段。

这就是令人头疼的地方。这不是它在 Windows 上的工作方式。

【问题讨论】:

    标签: c++ apache2 cross-platform apache-modules


    【解决方案1】:

    Linux 确实需要两次运行,但 Windows 需要四次运行。

    在配置后读取挂钩中使用此方法适用于 Linux,但不适用于 Windows

        // variables for base config start
        const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
        void        *init_flag = NULL;
        int         dbl = APLOG_TRACE4;
        // logger
        logging logger(NULL, s, p);     
        // determine if this is the first time we have loaded
        init_flag = ap_retained_data_get(flag);
        // check flag result
        if (init_flag == NULL) 
        {
            // breakpoint
            stdLog(logger, INFX_LOG_DATA, dbl);
            // set first time flag local
            ap_retained_data_create(flag, 1);
        }
        // call initization routine
        else
        {
            // do something here
    
        }
    

    请注意,我在我的模块中导出 C++ 代码,因此使用类。为简洁起见,还缺少一些变量声明。

    所以这对于 Windows 来说应该足够了吧?错误的。我必须倒着学习这个,因为我首先在 Windows 上构建,但 Windows 有四遍而不是两遍。在那里你的初始化仍然会运行两次。

    我的下一个解决方案如下:

        // variables for base config start
        const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
        void        *init_flag = NULL;
        char        *pidname;
        int         dbl = APLOG_TRACE4;
        pid_t       pidNKey;
        apr_file_t  *pidfile;       
        // logger
        logging logger(NULL, s, p);     
        // determine if this is the first time we have loaded
        init_flag = ap_retained_data_get(flag);
        // check flag result
        if (init_flag == NULL) 
        {
            // breakpoint
            stdLog(logger, INFX_LOG_DATA, dbl);
            // set first time flag local
            ap_retained_data_create(flag, 1);
        }
        else
        {
            // break point
            stdLog(logger, INFX_LOG_DATA, dbl);
            // create a pid if not exists
            if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // create a pid especially for our setup
                pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
                // if pidfile does not exist then create it
                if (!fileExists(pidname, ptemp))
                {
                    // break point
                    stdLog(logger, INFX_LOG_DATA, dbl);
                    // create the pid
                    apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
                    // add nonsensical data to it
                    apr_file_puts("1", pidfile);
                    // cllose the file and wait for run 2
                    apr_file_close(pidfile);
                }
                // begin work
                else 
                {
                    // break point
                    stdLog(logger, INFX_LOG_DATA, dbl);
                    // we no longer require the pid file
                    apr_file_remove(pidname, ptemp);
                }
            }
        }
    

    似乎工作....好吧,我已经完成了那部分,对吧?错误的!我来到了 Linux 机器和 segfault 城市。我敢肯定,很多经验丰富的 Apache 开发人员现在可能正在摇头,但这些人没有记录这些问题。

    我最后的解决办法是将 Windows 代码包装在定义块中。我不确定是否有更好的方法,但它对我有用。因此,以下在两个平台上都可以正常工作,而不会出现段错误。

        // variables for base config start
        const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
        void        *init_flag = NULL;
        int         dbl = APLOG_TRACE4;
        // logger
        logging logger(NULL, s, p);     
        // determine if this is the first time we have loaded
        init_flag = ap_retained_data_get(flag);
        // check flag result
        if (init_flag == NULL) 
        {
            // breakpoint
            stdLog(logger, INFX_LOG_DATA, dbl);
            // set first time flag local
            ap_retained_data_create(flag, 1);
        }
        // call initization routine
        else
        {
            // break point
            stdLog(logger, INFX_LOG_DATA, dbl);
            #if defined(WIN32)
            // create a pid if not exists
            if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // create a pid especially for our setup
                pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
                // if pidfile does not exist then create it
                if (!fileExists(pidname, ptemp))
                {
                    // break point
                    stdLog(logger, INFX_LOG_DATA, dbl);
                    // create the pid
                    apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
                    // add nonsensical data to it
                    apr_file_puts("1", pidfile);
                    // cllose the file and wait for run 2
                    apr_file_close(pidfile);
                }
                // begin work
                else 
                {
                    // break point
                    stdLog(logger, INFX_LOG_DATA, dbl);
                    // we no longer require the pid file
                    apr_file_remove(pidname, ptemp);
            #endif
                    // do something here for both platforms
            #if defined(WIN32)
                }
            }
            // crash if we do get a proper pid
            else
            {
                // breakpoint
                stdLog(logger, INFX_LOG_DATA, APLOG_CRIT, "HTTPD File not found? A Bug?");
                // set status
                return HTTP_INTERNAL_SERVER_ERROR;
            }
            #endif
        }           
    

    希望其他人可以从中受益。

    【讨论】:

    • 函数 fileExists 是各种 apr_io 例程的包装器,用于确定文件是否存在。
    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多