mod_dbd 모듈은 Database Interface의 Wrapper로 동작하며, Database Connection Pool을 제공한다. 단, Apache Process Model이 Worker일 경우(그러니까 Thread 모델에서)에만 Connection Pool에 대한 정확한 기능을 제공할 수 있겠다.
(글이 조금 많이 난잡하다;;)
mod_dbd 모듈의 Database Interface의 Wrapper 기능은, 사실 apr-uitil에서 제공하는 dbd 기능으로 되어 있다.
Apache 2.2.3과 함께 동봉되어 있는 apr-util-1.2.7에서 dbd 부분을 보자.
보시다시피, apr-util은 기본적으로, pgsql, sqlite2, sqlite3, 세개의 DB에 대해서 dbd 모듈을 제공한다. mysql에 제공되는 모듈도 있는데, 아마 검색으로 쉽게 찾을 수 있을 것이다.
이 중 apr_dbd.c는 Interface Function들을 제공하고, 다른 소스들이 Wrapper 안에 들어가는 Native function들을 제공한다. 이 Interface Function이 등록된 Driver 구조체의 Native function을 부르는 구조로 되어 있는데, 사실 Native에서 할 수 있는 많은 기능들이 생략되어 있고, 그럴 수 밖에 없다. (이것을 어느정도 보완하기 위해서 native handle을 리턴하는 부분도 존재하지만, dbd 기능의 철학하고는 조금 거리가 멀다고 하겠다.) 이 모듈은 현재도 조금 더 보완되어야 할 사항이 많아 보인다. 일례로, Apache 2.2.3 이후는 확인해보지 않았지만 Apache 2.2.3 까지의 apr-util에서는, Field의 이름을 받아오는 dbd 함수가 정의되어 있지 않았다. 이것은 별도의 패치로 해결했다.
다시 mod_dbd로 돌아오자. dbd_hooks 함수에서 시작해보면, 아래와 같은 내용들이 있다.
보다시피, 단순히 다른 모듈에게 추가 기능만을 제공해주는 모듈이기 떄문에, 복잡한 HOOK 구조를 가지고 있다거나 그런 점은 없다. 5개의 function이 OPTIONAL_FN으로 정의되어 외부로 export되어 있고, pre_config, post_config의 기본적인 hook, apr_dbd_init 함수가 호출되고, THREAD를 지원할 경우 child_init 하는 부분이 전부이다. apr_dbd_init 함수는 apr-util의 dbd 부분을 초기화 시켜주는 함수로, srclib/apr-util/dbd/apr_dbd.c에 포함되어 있다.
pre_config, post_config는 ap_dbd_prepare가 불릴 경우 사용되는 hash(dbd_prepared_defns)를 초기화 해주는 동작을 한다. (여기에 대해서는 설명을 생략하겠다.)
다른 함수들이 불리는 과정들은 조금 복잡하다.
core라고 불릴만한 함수는 dbd_setup와 dbd_construct가 있겠는데, dbd_setup은 Connection Pool을 초기화 하는 함수이며, dbd_construct는 직접 Connection을 만드는 함수이다.
dbd_setup은 두군데서 불리워지는데, dbd_setup_init과 dbd_setup_lock이다. dbd_setup_init는 THREAD를 지원할 경우 child_init hook 상에서 호출되며, dbd_setup_lock은 ap_dbd_open 함수에서, pool이 생성되지 않았을 경우 호출된다.
dbd_construct는 조금 더 복잡한데, 이 함수는 dbd_setup에서 이렇게 등록된다.
apr_reslist는 apr 함수로 resource 관리를 지원하는 목적으로 만들어진 api인것 같다. 함수 중간에 보면 construct와 destruct가 정의되어 있는데, 해당 reslist에 자원을 요청하게 되면, 자원이 없을 경우 등록된 construct를 호출하여 자원을 생성해서 리턴하게 된다. 실제로 ap_dbd_open 함수에서 이런 식으로 간접적으로 호출된다.
mod_dbd.c: line 456 rv = apr_reslist_acquire(svr->dbpool, &rec);
명시적으로 호출되는 부분도 있는데, persist 한 connection을 지원하는 것이 아닐 경우, 직접 construct를 호출하여 사용하고 자원을 되돌린다. 또한 Thread 구조를 지원할 필요가 없을때도 명시적으로 호출된다.
mod_dbd는 다섯개의 함수를 외부로 export 하는데, 각각 ap_dbd_open, ap_dbd_close, ap_dbd_acquire, ap_dbd_cacquire, ap_dbd_prepare이다. 이 함수를 다른 module에서 정의하여 사용하는 예를 보자.
mod_authn_dbd.c: line 66 authn_dbd_acquire_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
mod_authn_dbd.c: line 96 ap_dbd_t *dbd = authn_dbd_acquire_fn(r);
이런식으로 정의되고 사용된다.
ap_dbd_open 함수는 server_rec에 정의된 Database Pool에서 하나의 dbd 구조체를 받아와서 리턴해주는 역할을 한다. ap_dbd_close 함수는 open의 역으로, 할당된 구조체를 되돌린다. ap_dbd_acquire와 ap_dbd_cacquire 함수는 입력된 request_rec와 conn_rec에 dbd 구조체를 할당하거나, 이미 할당된 구조체를 리턴받는다. request_rec나 conn_rec당 Database Connection을 할당해야 할 경우 유용하게 쓸 수 있다. (내부적으로 ap_dbd_open 함수가 호출된다)
정리하자면, mod_dbd에서 제공되는 Database Pool 기능이 정상적으로 활용되려면 두가지 조건이 만족되어야 한다. 하나는 Apache가 Worker 모델로 동작해야 하고, config 상의 설정에서 DBDPersist 옵션이 켜져 있어야 한다.
Database Pool 기능이 켜지면 Process당 지정된 갯수만큼의 커넥션을 유지하며, 필요할 때 할당하며 필요하지 않으면 재사용 대기열에 넣거나 삭제한다. 이 갯수 제한은 config 상의 설정에서 가능하다.