Apache Module Deveope

Memory Mangement

Ref: http://www.apachetutor.org/dev/pools

mytype* myvar = apr_palloc(pool, sizeof(mytype)) ;
char* result = apr_psprintf(pool, fmt, ...) ;

mytype* myvar = malloc(sizeof(mytype)) ;
apr_pool_cleanup_register(pool, myvar, free, apr_pool_cleanup_null) ;

FILE* f = fopen(filename, "r") ;
apr_pool_cleanup_register(pool, f, fclose, apr_pool_cleanup_null) ;

Avoid Double Free

void poolclassCleanup(void* ptr) { delete (poolclass*)ptr ; }

class poolclass {
  private:
	  apr_pool_t* pool ;

  public:
    poolclass(apr_pool_t* p) : pool(p) {
      apr_pool_cleanup_register(pool, (void*)this,
        poolclassCleanup, apr_pool_cleanup_null) ;
    }

    virtual ~poolclass() {
      apr_pool_cleanup_kill(pool, (void*)this, poolclassCleanup) ;
    }
} ;

Connection Pooling

Ref: http://www.apachetutor.org/dev/reslist

// 构造器
static apr_status_t mysqlpool_construct(
  void** db, void* params, apr_pool_t* pool
) {
  svr_cfg* svr = (svr_cfg*) params ;
  MYSQL* sql = NULL ;
  sql = mysql_init(sql) ;
  if ( sql == NULL ) {
    ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, pool, "mysql_init failed") ;
    return APR_EGENERAL ;
  }
  *db = mysql_real_connect(sql, svr->host, svr->user, svr->pass,
        svr->db, svr->port, svr->sock, 0) ;

  if ( ! *db ) {
    ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, pool, "MySQL Error: %s",
        mysql_error(sql) ) ;
    return APR_EGENERAL ;
  }
  return APR_SUCCESS ;
}

// 析构器
static apr_status_t mysqlpool_destruct(
  void* sql, void* params, apr_pool_t* pool
)
{
  mysql_close((MYSQL*)sql) ;
  return APR_SUCCESS ;
}

// 创建连接池
static int setup_db_pool(
        apr_pool_t* p,
        apr_pool_t* plog,
        apr_pool_t* ptemp,
        server_rec* s
){
  svr_cfg* svr = (svr_cfg*)
        ap_get_module_config(s->module_config, &mysql_pool_module) ;

  if ( apr_reslist_create(&svr->dbpool,
        svr->nmin,
        svr->nkeep,
        svr->nmax,
        svr->exptime,
        mysqlpool_construct,    // 构造器
        mysqlpool_destruct,     // 析构器
        svr, p) != APR_SUCCESS ) {
    ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
        "MySQLPool: failed to initialise");
    return 500 ;
  }

  // 注册清理函数
  apr_pool_cleanup_register(p, svr->dbpool,
        (void*)apr_reslist_destroy,
        apr_pool_cleanup_null) ;
  return OK ;
}

给应该用程序提供接口。

MYSQL* mysql_acquire(request_rec* r, unsigned int flags) {
  mysql_request* req = (mysql_request*)
        ap_get_module_config(r->request_config, &mysql_module) ;

  if ( ! req ) {	/* use pool if and only if we haven't already got one */
    svr_cfg* svr = (svr_cfg*)
        ap_get_module_config(r->server->module_config, &mysql_module) ;
    req = (mysql_request*) apr_palloc(r->pool, sizeof(mysql_request) ) ;
    req->flags = flags ;
    req->dbpool = svr->dbpool ;
    if ( apr_reslist_acquire(svr->dbpool, (void**)&req->sql)
        != APR_SUCCESS ) {
      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
        "Failed to acquire MySQL connection from pool") ;
      return NULL ;
    }
    if ( mysql_ping(req->sql) != 0 ) {
      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MySQL: %s",
	mysql_error(req->sql) ) ;
      apr_reslist_invalidate(svr->dbpool, req->sql) ;
      return NULL ;
    }
    ap_set_module_config(r->request_config, &mysql_module, req) ;
    apr_pool_cleanup_register(r->pool, req,
        mysql_release, apr_pool_cleanup_null) ;
  } else {
    req->flags |= flags ;  /* ensure all required cleanups happen */
  }
  return req->sql ;
}