Sunday, November 6, 2011

ImageMagick を使って画像縮小

mixi のログイン用画像が大きいので、ImageMagick を使って縮小する
$ wget "http://developer.mixi.co.jp/about-platform/policies/image_guidelines/m_balloon_icon.png"
$ sudo yum install ImageMagick --exclude=*.i386
$ convert -geometry 32x32 m_balloon_icon.png mixi.png

yum 使用時、64bit環境で i386パッケージをインストールしない

exclude をつける
sudo yum install ImageMagick --exclude=*.i386

Sunday, August 7, 2011

PHP の parse_ini_file 調査

parse_ini_file が遅い気がするので、調べてみた。 以下、サンプルコード。
[192.168.162.128] cat parse_ini.php
<?php
$ret1 = parse_ini_file("sample.ini");
$ret2 = parse_ini_file("sample.ini");

[192.168.162.128] cat sample.ini
[first_section]
one = 1
five = 5
animal = BIRD

[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username"
parsekit にかけてみると、
[192.168.162.128] php -r 'var_dump( parsekit_compile_file("parse_ini.php", $error, PARSEKIT_SIMPLE));'
array(10) {
  [0]=>
  string(37) "ZEND_SEND_VAL UNUSED 'sample.ini' 0x1"
  [1]=>
  string(42) "ZEND_DO_FCALL T(0) 'parse_ini_file' UNUSED"
  [2]=>
  string(26) "ZEND_ASSIGN T(1) T(0) T(0)"
  [3]=>
  string(37) "ZEND_SEND_VAL UNUSED 'sample.ini' 0x1"
  [4]=>
  string(42) "ZEND_DO_FCALL T(2) 'parse_ini_file' UNUSED"
  [5]=>
  string(26) "ZEND_ASSIGN T(3) T(0) T(2)"
  [6]=>
  string(27) "ZEND_RETURN UNUSED 1 UNUSED"
  [7]=>
  string(42) "ZEND_HANDLE_EXCEPTION UNUSED UNUSED UNUSED"
  ["function_table"]=>
  NULL
  ["class_table"]=>
  NULL
}
当たり前かもしれないが、INI ファイルは、opコードに展開されない。つまり、APCではキャッシュしない。
strace してみると、
[192.168.162.128] strace php parse_ini.php 2>&1
open("/home/sikaku/dev/fuwarin/trunk/php/exp/ini/sample.ini", O_RDONLY) = 8
fstat(8, {st_mode=S_IFREG|0664, st_size=130, ...}) = 0
lseek(8, 0, SEEK_CUR)                   = 0
read(8, "[first_section]\none = 1\nfive = 5"..., 8192) = 130
read(8, "", 8192)                       = 0
read(8, "", 8192)                       = 0
close(8)                                = 0
getcwd("/home/sikaku/dev/fuwarin/trunk/php/exp/ini", 4096) = 43
open("/home/sikaku/dev/fuwarin/trunk/php/exp/ini/sample.ini", O_RDONLY) = 8
fstat(8, {st_mode=S_IFREG|0664, st_size=130, ...}) = 0
lseek(8, 0, SEEK_CUR)                   = 0
read(8, "[first_section]\none = 1\nfive = 5"..., 8192) = 130
read(8, "", 8192)                       = 0
read(8, "", 8192)                       = 0
close(8)                                = 0
どうやら、同じファイルにも関わらず毎回パースしてるようだ。

Wednesday, March 9, 2011

mysql で永続接続するか、毎回 connect するか

mysql で永続接続するか、毎回 connect するかの stack overflow リンク集 mysql_ping だけなら結構速いので、ping に失敗した時に close して connect し直せば良い。 以下のようなコードで良さそう。
bool MysqlUtil::init(const char *host, const char *user, const char *pass, const char *dbname){
  if( _isInit ){
    if(0 == mysql_ping(_mysql) ){
      return true;
    }
    mysql_close(_mysql);
  }

  _mysql = mysql_init(NULL);
  if( !mysql_real_connect(_mysql, host, user, pass, dbname, 0, NULL, 0) ){
    fprintf(stderr, "ERROR:mysql_real_connect()\n");
    return false;
  }
  if( 0 != mysql_set_character_set(_mysql, "utf8") ){
    fprintf(stderr, "ERROR:mysql_set_character_set()\n");
    return false;
  }

  _isInit = true;
  return true;
}
mysql 側の設定

Saturday, February 26, 2011

apache libapreq のソース読み


apacheモジュールでGETやPOSTのパラメータを処理するときは、libapreq2 を使って、 以下のように書けばよいが、
    apreq_handle_t *hl = apreq_handle_cgi(r->pool);
    apr_table_t *params = apreq_params(hl, pool);
どこでquery string をパースしてるのかを調べてみた。
  1. apreq_handle_t の初期化
    library/module_cgi.c
        655 APREQ_DECLARE(apreq_handle_t *)apreq_handle_cgi(apr_pool_t *pool)
        671     req->handle.module        = &cgi_module;
        677     req->args_status =
        678         req->jar_status =
        679             req->body_status = APR_EINIT;
    
    cgi_module がどこにも定義されていないと思ったら以下のMACROが
        653 static APREQ_MODULE(cgi, 20050425);
    
    以下に展開される
    static const apreq_module_t cgi_module = { "cgi", 20050425, cgi_jar, cgi_args, cgi_body, cgi_jar_get, cgi_args_get, cgi_body_get, cgi_parser_get, cgi_parser_set, cgi_hook_add, cgi_brigade_limit_get, cgi_brigade_limit_set, cgi_read_limit_get, cgi_read_limit_set, cgi_temp_dir_get, cgi_temp_dir_set, };
    
  2. apreq_params の中身
    library/module.c
         32 APREQ_DECLARE(apr_table_t *)apreq_params(apreq_handle_t *req, apr_pool_t *p)
         33 {
         34     const apr_table_t *args, *body;
         35     apreq_args(req, &args);
         36     apreq_body(req, &body);
         37
         38     if (args != NULL)
         39         if (body != NULL)
         40             return apr_table_overlay(p, args, body);
         41         else
         42             return apr_table_copy(p, args);
         43     else
         44         if (body != NULL)
         45             return apr_table_copy(p, body);
         46         else
         47             return NULL;
         48
         49 }
    
    apreq_args が cgi_argsを呼んでGETパラメータ, apreq_body が cgi_body, cgi_read を呼んでPOSTパラメータに対応する
  3. cgi_args でGETパラメータ初期化
    ./library/param.c
        140 APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
        141                                                      apr_table_t *t,
        142                                                      const char *qs)
    
  4. cgi_body cgi_read でPOSTパラメータ初期化 mod_apreq を使う場合や、apreq_initialize() を呼んだときに、 以下のパース用関数が、content-type にあわせて用意されている。
    library/parser.c
        114     default_parsers = apr_hash_make(default_parser_pool);
        115
        116     apreq_register_parser("application/x-www-form-urlencoded",
        117                           apreq_parse_urlencoded);
        118     apreq_register_parser("multipart/form-data", apreq_parse_multipart);
        119     apreq_register_parser("multipart/related", apreq_parse_multipart);
    
    URL エンコードされた POST に対しては以下の関数で処理される。
    ./library/parser_urlencoded.c
        158 APREQ_DECLARE_PARSER(apreq_parse_urlencoded)
    

Friday, December 24, 2010

HipHop for PHP をインストールして apache で proxy してみた


依存関係が相当面倒なので、rpm が用意されている CentOS 5 にインストールすることにした。
CentoOS 5系であれば、以下のようなページも用意されている。
https://github.com/facebook/hiphop-php/wiki/Installing-or-Building-HipHop-PHP-via-RPM-on-CentOS-5
それでも相当いろんなパッケージを入れないといけない。

説明のとおり、yum の設定用パッケージなどを以下のとおり実行
[sikaku@localhost hiphop_rpm]$ sudo rpm -ivh http://epel.osuosl.org/5/x86_64/epel-release-5-4.noarch.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/x86_64/ius-release-1.0-6.ius.el5.noarch.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -ivh http://pkg.tag1consulting.com/hphp/x86_64/hphp-release-1.0-2.el5.noarch.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-3.noarch.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -Uvh http://centos.alt.ru/repository/centos/5/x86_64/centalt-release-5-3.noarch.rpm
[sikaku@localhost hiphop_rpm]$ sudo rpm -Uvh http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm
[sikaku@localhost hiphop_rpm]$ sudo yum update
以下のとおり、大量に yum でパッケージを入れる。 何度もエラーと戦い続けて、以下が必要なことがわかった。
[sikaku@localhost hiphop_rpm]$ sudo yum install libidn-devel openssl-devel cvs cvsps gcc gcc-c++ libmcrypt zlib-devel automake libmcrypt mhash libtidy mysql
[sikaku@localhost hiphop_rpm]$ sudo yum install cmake mysql-devel pcre-devel gd-devel expat-devel libmcrypt-devel libcap-devel binutils-devel flex tbb-devel
以下に用意されているパッケージを全部ダウンロードする。
http://sourceforge.net/projects/hphp/files/CentOS%205%2064bit/
このダウンロードは、Irvine などでリンクインポートして一括ダウンロードすると良い。
mysqlのライブラリが古いと、エラーが出るので以下だけ、直接 mysql からダウンロードしてくる。
[sikaku@localhost hiphop_rpm]$ wget "http://dev.mysql.com/get/Downloads/MySQL-5.1/MySQL-shared-community-5.1.54-1.rhel5.x86_64.rpm/from/http://ftp.jaist.ac.jp/pub/mysql/"
で、以下のとおりインストール。一部ダウンロードしたファイルで、依存関係が問題で入らないのがあったので、除外している。
[sikaku@localhost hiphop_rpm]$ sudo rpm -Uvh hiphop-php-1.0-2.x86_64.rpm  boost-1.37.0-1.x86_64.rpm libicu-4.2.1-6.x86_64.rpm oniguruma-5.9.2-1.x86_64.rpm php52-5.2.12-1.ius.x86_64.rpm php52-cli-5.2.12-1.ius.x86_64.rpm php52-common-5.2.12-1.ius.x86_64.rpm tbb-2.2-1.20090809.x86_64.rpm php52-mysql-5.2.12-1.ius.x86_64.rpm MySQL-shared-community-5.1.54-1.rhel5.x86_64.rpm php52-pdo-5.2.12-1.ius.x86_64.rpm libxml2-*.rpm boost-devel-1.37.0-1.x86_64.rpm libevent-*.rpm php52-gd-5.2.12-1.ius.x86_64.rpm curl-devel-7.20.0-1hiphop.x86_64.rpm curl-7.20.0-1hiphop.x86_64.rpm icu-4.2.1-6.x86_64.rpm libicu-devel-4.2.1-6.x86_64.rpm oniguruma-devel-5.9.2-1.x86_64.rpm flex-2.5.35-7.x86_64.rpm
実際に実行してみた。vm環境で 256M しか割り当ててなかったからか、スワップしまくって7分もかかった。
[sikaku@localhost dev]$ cat test.php
<?php
 echo "hello world!";
?>
[sikaku@localhost dev]$ time hphp test.php
hello world!
real    7m8.916s
user    1m2.269s
sys     0m33.538s
[sikaku@localhost dev]$
ポート8999 で起動してみる。
[sikaku@localhost dev]$ mkdir bin
[sikaku@localhost dev]$ time hphp test.php --keep-tempdir=1 -o bin
hello world!
real    9m0.035s
user    1m5.599s
sys     0m34.827s
[sikaku@localhost dev]$ bin/program -m server -p 8999
Could not mlockall
loading static content...
loading static content took 0'00" (0 ms) wall time
page server started
admin server started
all servers started
以下のようにアクセスできる。
[sikaku@localhost ~]$ curl "http://localhost:8999/test.php"
hello world!
続いて、apache の設定を以下のように追加する。mod_rewrite か、mod_proxy で proxy 設定を書く。
[sikaku@localhost dev]$ cat /etc/httpd/conf.d/custom.conf
#RewriteEngine on
#RewriteRule /(.*) http://localhost:8999/$1 [P,L]
ProxyPassMatch ^/(.*)$ http://localhost:8999/$1
[sikaku@localhost dev]$ sudo /etc/init.d/httpd restart
80 ポートからアクセスできた。
[sikaku@localhost ~]$ curl "http://localhost/test.php"
hello world!

Sunday, December 5, 2010

libev を使った web server Lighttz を make してみた

まずは、libev のインストール

[192.168.162.128] cvs -z3 -d :pserver:anonymous@cvs.schmorp.de/schmorpforge co libev
[192.168.162.128] cd libev
[192.168.162.128] autoheader
[192.168.162.128] aclocal
[192.168.162.128] autoconf
[192.168.162.128] touch ltmain.sh
[192.168.162.128] automake -a
[192.168.162.128] ./configure --prefix=$HOME/local
[192.168.162.128] rm libtool
[192.168.162.128] ln -s /usr/bin/libtool libtool
[192.168.162.128] make
[192.168.162.128] make install
libtool がうまく動かなかったので置き換え lighttz の方では、以下のように Makefile を書き換えて gmake
[192.168.162.128] cat Makefile
lighttz: lighttz.o
        gcc -o lighttz ./lighttz.o -L$$HOME/local/lib -lev -u is_default_loop

lighttz.o: lighttz.c
        gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"lighttz.d" -MT"lighttz.d" -I../libev -o $@ ./lighttz.c

clean:
        rm -f lighttz.o lighttz

start:
        LD_LIBRARY_PATH=/home/sikaku/local/lib/ ./lighttz &
起動してみる。
[192.168.162.128] LD_LIBRARY_PATH=/home/sikaku/local/lib/ ./lighttz &

[192.168.162.128] curl http://localhost:8002/
curl: (18) transfer closed with 1 bytes remaining to read
Hello World

Hello World

[192.168.162.128]
どうやら、1byte 書き出しが少ないようだ。
以下のように修正するとうまくいく
Index: lighttz.c
===================================================================
--- lighttz.c   (revision 103)
+++ lighttz.c   (working copy)
@@ -76,7 +76,7 @@
        char superjared[]="HTTP/1.1 200 OK\r\nContent-Length: 336\r\nConnection: close\r\nContent-Type: text/html\r\nDate: Sat, 26 Apr 2008 01:13:35 GMT\r\nServer: lighttz/0.1\r\n\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\" version=\"-//W3C//DTD XHTML 1.1//EN\" xml:lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>Hello World</title></head><body><p>Hello World</p></body></html>";

        if (revents & EV_WRITE){
-               write(cli->fd,superjared,strlen(superjared));
+               write(cli->fd,superjared,strlen(superjared)+1);
                ev_io_stop(EV_A_ w);
        }
        close(cli->fd);