このページでは主に Apache Module 関連のメモを書いています。
環境構築
CentOS 5.8 (x86_64) 上で開発します。
yum で httpd (2.2.x系) と httpd-devel をインストールしておきます。
僕の場合は以下のような環境になっています。
$ httpd -V Server version: Apache/2.2.17 (Unix) Server built: Dec 17 2010 11:58:46 Server's Module Magic Number: 20051115:25 Server loaded: APR 1.3.12, APR-Util 1.3.9 Compiled using: APR 1.3.12, APR-Util 1.3.9 Architecture: 64-bit Server MPM: Prefork threaded: no forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/prefork" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=128 -D HTTPD_ROOT="/etc/httpd" -D SUEXEC_BIN="/usr/sbin/suexec" -D DEFAULT_PIDLOG="logs/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_LOCKFILE="logs/accept.lock" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf"
$ httpd -l Compiled in modules: core.c prefork.c http_core.c mod_so.c
Apache Module の作成
hello_module の作成手順。
$ apxs -g -n hello Creating [DIR] hello Creating [FILE] hello/Makefile Creating [FILE] hello/modules.mk Creating [FILE] hello/mod_hello.c Creating [FILE] hello/.deps $ cd hello $ make $ sudo make install
mod_hello.conf の作成
LoadModule hello_module modules/mod_hello.so <Location /hello> SetHandler hello </Location>
動作確認
作成した mod_hello.conf をApacheのconfディレクトリにコピー後、Apacheを再起動。
$ sudo cp ./mod_hello.conf /etc/httpd/conf.d/ $ sudo apachectl configtest $ sudo apachectl restart
/hello にアクセスして
The sample page from mod_hello.c
と表示されればOKです。
C++でのモジュール開発
C++でApacheモジュールを開発する際に気をつける点のひとつに、生成したインスタンスのリソース解放処理があります。
基本的に以下のような手順でリソース解放処理を記述します。
拡張モジュールについて
mod_deflate
コンテンツを圧縮してクライアントに返すモジュール。Apache モジュール mod_deflate
圧縮するためCPU資源は使いますが、レスポンスのサイズはかなり小さくなります。
rest-term.com に設定していたディレクティブは以下のとおり (現在はApacheからNginxに移行しています)。
# DEFLATEフィルタをセット SetOutputFilter DEFLATE # 一部のブラウザで圧縮の制限を行う BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # 画像は元々圧縮されているのでCPU資源節約のため圧縮しない SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary # DEFLATEフィルタをかける MIME-type を指定 # text/plain text/html ... のように1行で続けて書いてもOK AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/atom_xml AddOutputFilterByType DEFLATE application/x-javascript AddOutputFilterByType DEFLATE application/x-httpd-php
mod_dbd
データベースへのコネクション管理機能を提供するモジュール。
mod_dbd manages SQL database connections using APR.
Apache Module mod_dbd
mod_dbd はコネクション管理のみを行うモジュールなので公開されているのは以下の関数のみ。
内部で apr_dbd を用いてコネクションプール機能を提供するラッパーモジュールとなっていて、
データベースへの各問い合わせは apr_dbd のAPIを利用します。
DBD routines
構築に際して、古いバージョンのApacheにはMySQL用のドライバ(apr_dbd_mysql.c)が同梱されていないため別途追加が必要です。
ディレクティブ
- ''DBDExptime''
データベース接続のアイドル時間
デフォルト値 300 - ''DBDKeep''
データベース接続のオフピーク接続数
デフォルト値 2 - ''DBDMax''
データベース接続の最大接続数
デフォルト値 10 - ''DBDMin''
データベース接続の初期接続数
デフォルト値 1 - ''DBDParams''
データベースの接続パラメータ
MySQLの場合は、host, port, user, pass, dbname を指定します。
例) "host=localhost port=3306 user=foo pass=bar dbname=dbd_test" - ''DBDPersist''
データベース接続にコネクションプールを利用するか
Apache 2.2.2から引数の形式は 1/0 ではなく On/Off で指定
デフォルト値はないため、明示的にきちんと指定しないと
"seg fault or similar nasty error detected in the parent process"
と言われて落ちます。configtest でも怒られないので気付きにくいです。 - ''DBDPrepareSQL''
プリペアドステートメントの定義 - ''DBDriver''
ドライバの指定
MySQLなら "mysql", PostgresSQLなら "pgsql" と指定します。
サンプル
mod_dbd を用いたサンプルモジュール(dbdtest_module)を作成します。
対象のテーブル(user)は以下のような簡素なユーザーテーブルです。
''id'' | ''name'' | ''age'' |
1 | foo | 25 |
2 | bar | 26 |
- ap_dbd_acquire 関数を用いてコネクションハンドラを取得
(ap_dbd_t 構造体の中の apr_dbd_t がコネクションハンドラ) - apr_dbd の各APIを用いてデータベースを操作
型名が ap_dbd だったり、apr_dbd だったり紛らわしいので注意しましょう。。
r が付いていないのが mod_dbd が提供するAPIです。
- 出力結果
The sample page from mod_dbdtest.c DBD driver name is mysql id: 1, name: foo, age: 25 id: 2, name: bar, age: 26
- 問題点(?
普通のSQL文を発行する場合は問題なかったけど、ストアドプロシージャをコールすると、
"Error 1312 (0A000): PROCEDURE '''proc_name''' can't return a result set inn the given context."
というエラーが発生した。要調査。