<?php
define(_A_CONSTANT, 'this is a constant');
if(defined(_A_CONSTANT)){
print("Hello");
}
?>
超特殊な場合を除き、絶対に「Hello」は出力されない。なぜなら、ちゃんとマニュアルにも記載されているが、上のコードは
<?php
define(_A_CONSTANT, 'this is a constant');
if(defined('this is a constant')){
print("Hello");
}
?>
と等価になってしまう。
でも他人のコードをデバッグしているときは、これはなかなか見つからない。
<?php
define(_A_CONSTANT, 'this is a constant');
if(defined('_A_CONSTANT')){
print("Hello");
}
?>
もちろん、これなら動く。
このパターンのバグが今日、職場で発見されたのでメモ。
Popularity: 3% [?]
PostgreSQLの運用では、システム停止をともなう定期的なメンテナンスが必要とされている。
が、じゃあいったいどれくらい、何のためにシステム停止とVACUUM処理をやらなければいけないのかは、いまいちはっきりしたところはわからなかった。たとえば、データ領域が大きくなりすぎてディスク容量を圧迫しているとか、なんとなくパフォーマンスが低下しているとか、そんなタイミングで実施するようなアバウトな運用をしている人も結構いるのではないか。
マニュアルにも明記されているが、上に挙げた理由の他に、PostgreSQLのVACUUMにはもうひとつ重要な機能がある。といっても、通常のVACUUMやVACUUM FULLでは実行されず、psqlから「VACUUM F」まで入力してtabを押しても出てこないのでやっかいなのだが、長期間運用されるPostgreSQLではVACUUM FREEZEを定期的に実行してやる必要がある。
VACUUMというのは、PostgreSQLが削除フラグを立てて未使用となったデータ領域を回収してあげるもので、ANALYZEはプランナが利用する統計情報を更新することで利用効率を向上させるものという理解で基本的には間違いないようなのだが、このFREEZEというのは正直なところこれまでその存在も全く知らなかった。今日、たまたま隣席で7.3系のPostgreSQLでVACUUM作業中の人がログに変なメッセージを見つけたのがきっかけで発見した。
同じような警告メッセージがPostgreSQL7.2のChangelogにある。
NOTICE: Some databases have not been vacuumed in 1613770184 transactions.
Better vacuum them within 533713463 transactions,
or you may have a wraparound failure.
PostgreSQLのトランザクションには一意のID(XID)が振られていて、そのIDは32ビットのシステムでは40億くらい(2の32乗)が上限になっている。この上限値を超えると、トランザクションのIDはリセットされて0に戻ってしまう。数字が循環して0に戻ると、突然自分より前のトランザクションが存在しない状態になってしまい、逆に過去のトランザクションが未来のものに見えるようになるため、データ破壊を引き起こす。上のメッセージは、メンテナンス忘れなどでトランザクション数の累計が15億を超えるとVACUUM時に出てくるものだ。
VACUUM FREEZEはこの循環を回避するための機能で、現在のトランザクション以外のトランザクションにFrozenXIDというのを追加して、周回違いのIDを見間違わずに過去のものと判別できるようにする。何がなんだかわからないので、イメージしかわかないのだが、きっとPostgreSQLのトランザクションデータは構造体みたいなもので、そこにXIDというメンバ変数があって、そいつを更新してくれる、みたいなものなのだろう。
ちなみにVACUUM FREEZEはPostgreSQL 7.2から導入された機能で、上の説明もだいたいそれに合わせたものになっている。というのも、8.3のマニュアルではVACUUM FREEZEは廃止予定となっており、VACUUMの実行はpostgres.confのvacuum_freeze_min_ageの値を0に設定したものと同じことになる。つまり、VACUUMで代用できるわけだ。どうりでpsqlからもちゃんと出てこないわけだ。
PostgreSQLの7系で無停止運転が出来ないのは、こういう理由もあったからだ。
Popularity: 6% [?]
といってもコーヒーの話ではない。
会社の同僚が帰省中に読むのにちょうどいい本はないかというので、たまたま思い出した「ルーツ」はどうかと勧めてみた。
ちょっと前に、ブックオフがけしからんのは「ルーツ」のハードカバー版が100円コーナーで叩き売りされているところだ、と話していたので思い出したのだ。
しかしながら、他の同僚たちに聞いてみると、ほとんど誰も「ルーツ」のことを知らないのに驚いた。一過性のベストセラーとして歴史に葬られたような売られ方をしている本だから仕方がないのかもしれない。
ただし、同世代の中には、読んだことはなくてもこのテレビドラマ版“ルーツ コレクターズBOX” のことを覚えている人なら少しはいた。といっても、1977年に放映されたものなのであらすじなどは誰も覚えていなかったが、逃亡を図って捕まった主人公クンタ・キンテが白人たちに木に縛られ、足の先を斧で切り落とされるという強烈なシーンだけははっきりと覚えていると皆が口を揃えていた。確かに、子供の頃、このシーンを観て、父にどうしてこんなことをしているの?と尋ねると、父が黙ってニヤリと笑ったのでもっと怖くなったのを今でもはっきりと覚えている。そして10年以上経ってこの本を読み、ああ、これがあのときのあの場面か、と不意の再会に驚いたのも今では思い出だ。
著者のアレックス・ヘイリーの名前はジャズが好きな人ならどこかで目にしたことがあるかもしれない。マイルズ・デイヴィスの自伝“マイルス・デイビス自叙伝”を読んだ人は、マイルズにインタビューを申し込んで、当時ボクシングで体を鍛えていたマイルスにじゃあリングに上がれといわれてボコボコにされ、それでも引き下がらなかったので根性を認められて晴れてインタビューを取れたジャーナリストの逸話を覚えているだろう。その哀れなインタビュアーこそが、著者のアレックス・ヘイリーその人だ。
「ルーツ」は、そんな型破りのジャーナリストが、奴隷としてアフリカで誘拐されアメリカに連れ去られてきた祖先に至までの自分の血縁を遡り、数世代に渡るスケールの大きなドラマとして再構成した物語だ。その時間軸、受け継がれていく血脈というあたりは、“橋のない川” や“百年の孤独” に通じ、苦難の歴史を経た一家の物語が、やがて著者自身の誕生の瞬間にたどり着くあたりは読んでいて思わず身震いしてしまうほどだ。
一部が盗作であった(65万ドルを支払って和解)ことにより非難を浴び、そのためトニ・モリソンのような評価を受けることもないまま、著者の病死もあって歴史の中に埋もれてしまいそうな本なのだが、それでも読む価値はある本だと断言できる。
Popularity: 3% [?]
PEARのNet_POP3でGmailからメールを受信するのはこんな感じでできる。実行環境で「ssl://」で始まるデータストリーム型がサポートされていれば問題ない。調べるには
$ php -i | grep "Stream Socket" Registered Stream Socket Transports => tcp, udp, unix, udg, ssl, sslv3, sslv2, tls
このようにsslが表示されていればいい。
スクリプトは、例えば
<?php
require_once 'Net/POP3.php';
$host = 'ssl://pop.gmail.com';
$port = '995';
$user = 'Gmailのメールアドレス';
$pass = 'パスワード';
$pop = new Net_POP3();
$pop->connect($host, $port);
$pop->login($user, $pass, USER);
//成功したら配列が、失敗したらfalseが返る
$messages = $pop->getListing();
if($messages){
foreach($messages as $k => $row){
$id = $row['msg_id'];
//特にやることもないのでとりあえず配列に入れる
$mail[] = $pop->getMsg($id);
}
}
$pop->disconnect();
print_r($mail);
exit;
?>
こんな風になる。
今さらなんだよ、という向きもあるかもしれないが、例えばGoogleのメールサーバを使って独自ドメインサービスをやっている場合、これで自分のサーバで空メールのサービスを立ち上げるときなどに使えるので、まあメモということで。
Popularity: 5% [?]
いろいろ気づいたことのメモ。
まずは目玉機能のオンラインリカバリについて。プロジェクトのページによれば
1. CHECKPOINT 実行
2. ファーストステージの実施
3. 接続がすべて切断されるまで待機
4. CHECKPOINT 実行
5. セカンドステージの実施
6. postmaster の起動(pgpool_remote_start の実行)
7. ノードの復帰
という手順でリカバリされるのだが、手元の環境でまず引っかかったのが3の「接続がすべて切断されるまで待機」のところ。というのも、pgpool-IIにpgpoolを経由して接続するという変な環境だったのだが、child_life_timeを0に設定していたために接続がいつまで経っても切れずにここで失敗してしまったのだ。
で、pgpool-IIのソース(現時点でrev.1.21)を調べると(これは会社の同僚がやっていた)、まだ接続が切れていなければ3秒待ってから最大30回ループすることになっている。
/*
* Wait all connections are closed.
*/
static int wait_connection_closed(void)
{
int i = 0;
do {
if (Req_info->conn_counter == 0)
return 0;
if (WAIT_RETRY_COUNT != 0)
sleep(3);
} while (i++ < WAIT_RETRY_COUNT);
pool_error("wait_connection_closed: existing connections did not close in %d sec.", pool_config->recovery_timeout);
return 1;
}
なぜかしびれた。これはプログラム内に意味深な数字を見つけたときのプログラマの健康な反応なのだろう。まあ、根拠はよくわからないが、まあそういう数字であると。ふむふむ。
で、接続元がpgpoolだとコネクションを張りっぱなしになるのでこのループで終了してしまう。負荷の高いサービスだと、pgpool経由でpgpoolにつないだ状態では、child_life_timeを下げてもなかなかチャンスがこないかもしれない。というわけで現在ここを試験中。
接続の問題が解消されると、あっさり動作した。PostgreSQLは7系なのでrsyncで動作している。
Popularity: 6% [?]
まめぞうの大きさがわかる写真。
猫との比較。
凶暴化する猫。
