2008年8月アーカイブ

アルフ再放送

思わず、勤務時間をずらしたくなったのは内緒。そして、小躍りして喜んだのはもっと内緒。

ふと思い出してググってみれば、再放送決定との事。結構前に発表されていたようですね。

今回はDVD化されるんでしょうかね?日本語吹き替え版は発売されていないようで、これをきっかけに発売してほしいものです。所ジョージの声じゃないと、きっと落ち着かない。そもそも、英語はわからないし(これを教材にするのはありかな)。

NHKはどうも映りが悪いので、DVD化してくれると嬉しいです。砂嵐手前の時とかもあって、なんでお金をとられているのか分からなくなったりします。夜になると落ち着いたりするんですけどね。甲子園の時期は腹がたってしかたありません。

放送時間がちょうど退勤時間なので、家でリアルタイムで観る事はできそうもありません。録画すればいいんですけどね。

ああ、こういうときにワンセグなのか。いや、会社にテレビを買ってもらって…。うん、コミュニケーションですね。

日本語吹き替え版のDVDが発売されれば、すべてが丸く収まるので、期待してます。


ネットで録画要望した動画をダウンロードできるサービスがあった気がしたんですが、違法でしたか(これとは別のだったかな?)。
東京地裁、テレビ番組録画サービス「録画ネット」にサービス停止の仮処分
個人利用でもコピー回数を制限するくらいだしね。

ソースをいじってコンパイルしたら動くんですね!
Issue 131 - phusion-passenger - Google Code

img要素をCSSのdisplay:noneで隠しても、src属性のURIにリクエストが飛ぶもんだと思ってた。面目ない。
display:noneな画像はOperaでPostされない at HouseTect, JavaScripter Blog

スタイルを、img要素ではなくimg要素を囲むdiv要素に当ててみても、結果は同じでした。

はぁ、今更こんな事実を知るってのはどうなんだろう。お恥ずかしいかぎりです。

ちなみに、画像を作るセンスがないので画像を隠したい場合、スタイルで位置をずらすとかになるんでしょうかね。


参考記事の"Post"というのは、多分"(HTTP)リクエスト"と同じ意味だと思いますが、そうですよね?

いろいろ良くわかっていないながら、選択肢としてそういう運用もあるかな、と。
koshigoe's jpmobile_with_crawler at master — GitHub

いくつかのプロジェクト(アプリ)で使いたいので、簡単に共有できるのがベストです。本当はforkしたjpmobileを丸ごとgemにしてしまうのが良い(簡単な)わけですが、本家の変更を追いかけて都度gemを作るというのも無駄すぎる気がします。さほど手間がかかるわけでもない気がしますが。

で、思いついたままプラグイン化してみたわけです。が、激しく無駄な事をした気がしています。何が無駄って、テスト用にjpmobileに習って用意したRSpec関連の仕掛けが、です。

クローラのUA判別とIP判定についてテストをしたいので、RSpecのあれこれも同梱してみたわけですが、本当に必要だったのかよくわかっていません。jpmobileのを丸パクリなので、あまり深く考えていなかったりします。

まだ、プラグインへの切り出しと用意したテストでのチェックしかしてません。Railsアプリとの連携については未確認なので、いろいろ問題が残っている様な気がしています。

1つの解決策としてどうなのかを探るためにプラグインにしてみましたが、もうちょっとうまくやれる気がしてしょうがありません。本家とクローラ対応版の差分からパッチを作って、それをプラグインのディレクトリに放り込んだ方がよいのでしょうか。プラグイン側でのテストは考えなくても良い気がしてきました。そもそも、一般に配布する事が目的ではないので。

んー、GitHubを使ってちょっとした変更をできるのは便利ですが、その変更を本家を活かしつつ反映させたい場合、どうするのが一般的なんでしょうか。mergeで追随して自分のリポジトリを使うべきなんでしょうか。

もうちょっと悩んでみます。

MySQLのUNIQUE KEY制約とNULL値

UNIQUE KEY制約において、NULL値は同一だと見なさないらしい。UNIQUEキーで「同一」と判断するために、"="演算を行っているのだろうか?

$ mysql --version
mysql5  Ver 14.12 Distrib 5.0.67, for apple-darwin9.4.0 (i686) using  EditLine wrapper
mysql@localhost> USE test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql@localhost> CREATE TABLE unique_key_test
    -> (
    ->   id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    ->   uniq VARCHAR(255) UNIQUE,
    ->   value VARCHAR(255)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test (uniq, value) VALUES ('xxx', '123');
Query OK, 1 row affected (0.18 sec)

mysql@localhost> INSERT INTO unique_key_test (uniq, value) VALUES ('xxx', '123');
ERROR 1062 (23000): Duplicate entry 'xxx' for key 2

mysql@localhost> SELECT * FROM unique_key_test;
+----+------+-------+
| id | uniq | value |
+----+------+-------+
|  1 | xxx  | 123   |
+----+------+-------+
1 row in set (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test (uniq, value) VALUES (NULL, '123');
Query OK, 1 row affected (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test (uniq, value) VALUES (NULL, '123');
Query OK, 1 row affected (0.00 sec)

mysql@localhost> SELECT * FROM unique_key_test;
+----+------+-------+
| id | uniq | value |
+----+------+-------+
|  1 | xxx  | 123   |
|  2 | NULL | 123   |
|  3 | NULL | 123   |
+----+------+-------+
3 rows in set (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test (uniq, value) VALUES (NULL, '123') ON DUPLICATE KEY UPDATE value='456';
Query OK, 1 row affected (0.00 sec)

mysql@localhost> SELECT * FROM unique_key_test;
+----+------+-------+
| id | uniq | value |
+----+------+-------+
|  1 | xxx  | 123   |
|  2 | NULL | 123   |
|  3 | NULL | 123   |
|  4 | NULL | 123   |
+----+------+-------+
4 rows in set (0.00 sec)

mysql@localhost> SHOW TABLE STATUS LIKE 'uniq%' \G
*************************** 1. row ***************************
           Name: unique_key_test
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 4
 Avg_row_length: 20
    Data_length: 80
Max_data_length: 281474976710655
   Index_length: 6144
      Data_free: 0
 Auto_increment: 5
    Create_time: 2008-08-26 23:49:05
    Update_time: 2008-08-26 23:52:14
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.00 sec)

ストレージエンジンによって挙動が違うとかいう話も見かけたので、次はInnoDB。

mysql@localhost> CREATE TABLE unique_key_test_innodb
    -> (
    ->   id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    ->   uniq VARCHAR(255) UNIQUE,
    ->   value VARCHAR(255)
    -> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test_innodb (uniq, value) VALUES ('xxx', '123');
Query OK, 1 row affected (0.01 sec)

mysql@localhost> INSERT INTO unique_key_test_innodb (uniq, value) VALUES ('xxx', '123');
ERROR 1062 (23000): Duplicate entry 'xxx' for key 2
mysql@localhost> INSERT INTO unique_key_test_innodb (uniq, value) VALUES (NULL, '123');
Query OK, 1 row affected (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test_innodb (uniq, value) VALUES (NULL, '123');
Query OK, 1 row affected (0.01 sec)

mysql@localhost> SELECT * FROM unique_key_test_innodb;
+----+------+-------+
| id | uniq | value |
+----+------+-------+
|  1 | xxx  | 123   |
|  2 | NULL | 123   |
|  3 | NULL | 123   |
+----+------+-------+
3 rows in set (0.00 sec)

mysql@localhost> INSERT INTO unique_key_test_innodb (uniq, value) VALUES (NULL, '123') ON DUPLICATE KEY UPDATE value='456';
Query OK, 1 row affected (0.00 sec)

mysql@localhost> SELECT * FROM unique_key_test_innodb;
+----+------+-------+
| id | uniq | value |
+----+------+-------+
|  1 | xxx  | 123   |
|  2 | NULL | 123   |
|  3 | NULL | 123   |
|  4 | NULL | 123   |
+----+------+-------+
4 rows in set (0.00 sec)

UNIQUE KEY制約とNULL値の関係が、ドキュメントのどこに書かれているのか、探せてません。

値の指定を省略(NULL)したら強制INSERT、指定ありなら重複を考慮してINSERT or UPDATE、という事をやるのにちょうど良いと思っているわけですが、仕様としてどうなのかがわからないので不安です。


MySQLは触るたびに発見があって、自分にがっかりしますね。知っとけよ、と。まあ、ボチボチ覚えていきます。

知らなかった。

ユニークな制約に違反した場合にUPDATE文に切り替えてくれるINSERTという事らしいですが、知りませんでした。さらに、ActiveRecord::Extensions.importが対応しているという事も知りませんでした。":on_duplicate_key_update"オプションで、UPDATE対象のフィールドを指定できるようです(Railsの拡張ライブラリの話)。

ひとまずは試しという事で、小さなモデルを使ってimportが作るSQLを見ていたわけですが、さっぱり"ON DUPLICATE"がつきません。コードを見ても、MySQL用アダプタは対応しているはずですが、さっぱりです。

requireの位置や作法が間違っているのかと、READMEやら何やらを見ていると、ありました。

I forgot to mention that ar-extensions no longer loads adapter specific functionality by itself. You need to tell it what you want. For example if you want to load import functionality for MySQL you’d have to require the right files, like so:

require 'ar-extensions/adapters/mysql'
require 'ar-extensions/import/mysql'

Continuous Thinking—

0.8.0ではアダプタの自動読み込みがされていないらしく、supports_on_duplicate_key_update?がfalseになる様です。そうすると、"ON DUPLICATE"なINSERTをサポートしない事になるので、当然SQLにもくっついてきません。ちなみに、上記のrequireはアダプタ読み込みのためのrequireの様で、別途事前に"ar-extensions"をrequireする必要があったはずです。

以下が、テストに使ったモデルのマイグレーションコードです。単純なテーブルです。

class CreateOnDuplicates < ActiveRecord::Migration
  def self.up
    create_table :on_duplicates do |t|
      t.string :name, :null => false
      t.string :value
      t.timestamps
    end
    add_index :on_duplicates, [:name], :unique => true, :name => 'uniq_key'
  end
 
  def self.down
    drop_table :on_duplicates
  end
end
 

準備ができたら、script/consoleからimportメソッドを実行してみます。

>> OnDuplicate.import [:name, :value], [['xxx', '123']], :on_duplicate_key_update => { :name => :name }
=> #<OpenStruct failed_instances=[], num_inserts=1>

上記に対応するログは以下の通りです。

INSERT INTO `on_duplicates` (`name`,`value`,`created_at`,`updated_at`)
  VALUES ('xxx','123','2008-08-25 12:55:43','2008-08-25 12:55:43')
  ON DUPLICATE KEY UPDATE
    `on_duplicates`.`name`=VALUES( `name` ),
    `on_duplicates`.`updated_at`=VALUES( `updated_at` )

実行してから気づきましたが、updated_atフィールドがあるので、くっついてくるようです。

"ON DUPLICATE"がActiveRecordから利用できる事はわかりましたが、もう一つ知りたい事があります。UPDATE時のコストです。今回は、「UPDATEしたくない」という隠し(?)要求があります。ユニークなキーの存在が確認できたら、「何もしない」というSQLが欲しいわけです("ON DUPLICATE"じゃない方法で良いものがあるのか知りませんが、このままいきます)。

UPDATEが実行されるかどうかは、実際にMySQLクライアントから実行してみればわかるはずです。"〜rows affected"という結果表示に見覚えがあります。あれの数を素直に愚直に信じる事にします。「変更されてないだけで、SQL(コマンド)は実行されてる」という事かもしれませんが、ひとまずは"0 rows affected"を見て安心したいと思います。

mysql@localhost> CREATE TABLE on_duplicate
    -> (
    ->   id int primary key not null auto_increment,
    ->   name varchar(255) unique key not null,
    ->   value varchar(255)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql@localhost> INSERT INTO on_duplicate (name, value) VALUES ('xxx', '123');
Query OK, 1 row affected (0.00 sec)

mysql@localhost> SELECT * FROM on_duplicate;
+----+------+-------+
| id | name | value |
+----+------+-------+
|  1 | xxx  | 123   |
+----+------+-------+
1 row in set (0.00 sec)

mysql@localhost> INSERT INTO on_duplicate (name, value) VALUES ('xxx', '123') ON DUPLICATE KEY UPDATE name=name;
Query OK, 0 rows affected (0.00 sec)

mysql@localhost> INSERT INTO on_duplicate (name, value) VALUES ('xxx', '123') ON DUPLICATE KEY UPDATE name=VALUES(name);
Query OK, 0 rows affected (0.00 sec)

ほっ。

というわけで、「"INSERT ON DUPLICATE KEY UPDATE"したい場合は、ActiveRecord::Extensions.importでもできる」というお話でした。


SELECTの場合、明らかにありえないWHERE句が与えられた場合は、オプティマイザか何かの段階で0件を返すというのはどこかで知りました。が、UPDATEに関して、明らかに変更がない場合にオプティマイザか何かが実行を回避する、という事はあるんでしょうか?あるとして、それはVALUES(field_name)を使う場合もありでしょうか?

Appleのワイヤレスのキーボードとマウスが、突然接続切れになる。

Time Machineで負荷があがったときに切れたので、ひょっとして関係あるんでしょうか?

勢い余って購入したワイヤレスですが、正直、使い勝手が悪いです。

コードがなくなったので、机の上が(多少)スッキリしたのは気に入ってます。ただ、使い勝手が微妙です。

マウスは、単三電池2本分だけ重くなっているため、ひどく違和感があります。今は大分慣れましたが、使い続けているのは意地です。

キーボードは、電池の収納部分が原因で、傾斜が大きくなっています。前の平べったい感じが好きだったので、これも違和感です。キーも少々深くなって、抵抗も増している気がします。持ち運びたいわけでもないので、自分にとってはいいとこなしです。

これは、Apple TVとか、リモコン的操作のためにあると考えるべきだったんでしょうかね。

ワイヤレスを使った事がなかったので、興味で買ってみたわけですが、高い買い物でした。

さて、どうしたもんでしょうかね。ひどい敗北感です。

とりあえず、明日にでも近所のSoftbankショップに行って、iPhoneが売ってたら買ってこようと思います。買えたらイーブン。

衝動買いの敗北を(作為的な)衝動買いで塗りつぶしてみます。

ipcount便利

今まで存在を知りませんでした。便利。暗算できるようになるべきなんでしょうけど。
Karetta|[misc] IPアドレスの範囲からネットマスクを計算する

例えば、Yahooのモバイル用クローラのIP範囲は「124.83.159.146 〜 124.83.159.185」として公開されています。これをネットマスクを使った表記にするために、ipcountを使ってみたのが以下。

$ ipcount 124.83.159.146 - 124.83.159.185
 124.83.159.146/31     124.83.159.146 - 124.83.159.147  [2]
 124.83.159.148/30     124.83.159.148 - 124.83.159.151  [4]
 124.83.159.152/29     124.83.159.152 - 124.83.159.159  [8]
 124.83.159.160/28     124.83.159.160 - 124.83.159.175  [16]
 124.83.159.176/29     124.83.159.176 - 124.83.159.183  [8]
 124.83.159.184/31     124.83.159.184 - 124.83.159.185  [2]

124.83.159.146/31,/30,/29,/28,/29,/31     124.83.159.146 - 124.83.159.185  [40]

逆にネットマスク表記から範囲を求めてみます。以下は、Gooのモバイル用クローラのIP範囲です。

$ ipcount 210.150.10.32/27
  210.150.10.32/27      210.150.10.32 - 210.150.10.63   [32]

以上。

jpmobileと検索クローラ

mobile?で検索クローラも真にしてしまえと。

一般的な用途に合うかどうかはさておき、モバイル用の検索クローラはモバイルとして扱えるようになってもよいかな、と。

正直、一番の目的はGitHubの利用です。forkしてcloneしてadd/commitしてpush。使い方がいまいちわからないので、本体に修正分が入ってしまいそうな恐怖と戦いながらの操作です。公開鍵が自分のしかないので、他人のリポジトリには書き込めないでしょうけど。

終わってみれば、安全に事を運べたように思います。本体を見ても、変更されていないようで一安心です。まあ、addせずに変更分がcommitできなかった事にpush後に気づいたのは内緒ですがね。

クローラ対応

さて、ここからは余談です。今回jpmobileをforkして修正した内容について、少しだけ書いておこうと思います。

  1. jpmobile便利に使わせていただいております!
  2. mobile?でtrueならモバイル用コンテンツを返したい
  3. 各キャリアの端末に対しては普通にできる
  4. クローラのインデクシングはどうなるんだろうか

このような流れで、モバイル用検索クローラからのリクエストも、モバイル端末からのリクエストとして扱いたいと思ったわけです。jpmobileでやる範囲のことなのか、深く考えていませんが、「mobile?」がひどく気に入っています。なので、「mobile?」を使いたいのです。

  • 有名どころはIPとUA情報を公開している
  • 簡単に見つかったのは、Google/Yahoo/Livedoor/Goo
  • 簡単に見つかったのだけ、とりあえず対応する

jpmobileの拡張(対応キャリア追加)は、IPアドレス情報とUA情報がわかれば簡単にできる様なので、上記の修正を加えてみました。ちなみに、4社の公開情報は以下です。

Googleの公開情報が、ブログでしか見つからなかったのが気になりますが、よしとしておきます。

適当な実装でごまかしましたが、端末とクローラの識別順序とでも言うのでしょうか、正規表現によるマッチングの実行順序をつけておきました。元々は、Jpmobile::Mobileが持っている定数をModule.constantsで取り出してeachしているわけですが、クローラのUAはDoCoMoから始まったりするので、クローラを優先的に処理しないと嘘になったりします。IPアドレスとセットでループさせても良かったかもしれませんが、定数名リストを明記して対応しました。

やった事はこんなところでしょうか。詳しくは"git://github.com/koshigoe/jpmobile.git"で。ここにも、forkしてからの差分を付けておきます。

赤はまだない。
携帯電話は、ソフトバンクオンラインショップで!|SoftBank iPhone 3G

今使ってる携帯も黒だし、黒でいい気がする。けど、もうちょっと待ったら、すてきにアップデート(ハード的に)したものが出てきそうな気もする。


そういえば、ハードのアップデートってできないのかな?契約で数年間の縛りがあっても、ハード交換はできるべきだと思うんだ。機種変更とはちょっと違った、ハードのアップデート。

ただ、本体価格が8万円とかするなら、無理だな。1年間使ったら1万円とか、今まで通りの感じでできたらいいね(通話料と端末価格のトレードオフの話は知らない)。

RaPTってのがある事を知った。

そもそも、プラグイン機構をよく理解してはいないので、"script/plugin"自体よくわかっていません。それでも、気になるので、とりあえず使ってみます。

gemを使ってインストール

$ sudo gem install gem
$ rehash

リポジトリ情報のキャッシュを作成

$ rapt discover --no-prompt

"~/.rails/plugin_source_cache.yml"にプラグインやらリポジトリやらの情報が書き込まれる様子。これは、"script/plugin"でも一緒でしょうか(手抜き)。ちなみに、ひどく時間がかかります。30分くらいかかった気がします。"script/plugin discover --no-prompt"としてみましたが、[Y/n]を聞かれたので強制終了しました。全部Yにするには、別のオプションを与える必要があるのでしょうか。

プラグインの情報を表示

$ rapt about engines
---
plugin: http://mattmccray.com/svn/rails/plugins/comatose
author: Matt McCray
license: MIT
rails_version: 1.2+
version: 0.8.1
homepage: http://mattmccray.com
summary: A micro CMS for embedding in Rails applications.

pluginの項目だけの場合もあるようですが、情報が用意されていれば、いろいろと情報が得られる様子。

余談

gitへの対応についてはよくわかりません。 0.2.2が2007-03-15にリリースされて以降、リリースされていないようです。

packなプラグインをインストールできたりするようですが、pluginpackというものが何なのか知りません。

ちなみに、RaPTのコマンド一覧。

  discover       Discover plugin repositories.
  list           List available plugins.
  search         Search for available plugins.
  about          Show basic info about a plugin.
  install        Install plugin(s) from known repositories or URLs.
  update         Update installed plugins.
  remove         Uninstall plugins.
  source         Add a plugin source repository.
  unsource       Remove a plugin repository.
  sources        List currently configured plugin repositories.
  pack:install   Install plugins from plugin pack file or URL
  pack:uninstall Uninstall plugins from plugin pack file or URL
  pack:about     Display plugin pack information

以下は、"script/plugin"のコマンド一覧(Rails 2.1.0)。

  discover   Discover plugin repositories.
  list       List available plugins.
  install    Install plugin(s) from known repositories or URLs.
  update     Update installed plugins.
  remove     Uninstall plugins.
  source     Add a plugin source repository.
  unsource   Remove a plugin repository.
  sources    List currently configured plugin repositories.

RaPTでは、search, about, pack:*が増えているようです。他も、discoverの--no-promptオプションの様に、いくらかの拡張がなされているのだろうと思います。

各コマンドのヘルプ(利用可能なオプションの確認)は、"rapt command -h"で見られるようです。これは、script/pluginでも同じようですね。RaPTのヘルプのEXAMPLESにはちゃんと以下の様なコマンドヘルプのサンプルがあったので気づけましたが、script/pluginの方はサンプルがないので気づけませんでした、という愚痴です。

  Show the options for the list command:
    rapt list -h

まあ、ソース読むなり、いろいろな情報を探れば気づけたんでしょうが、そもそも探る事すらできていないので。

というわけで、いつも通り、「とりあえず触ってみた」という報告まで。


プラグインのアップデート対応の為に、リリース情報を追いかけたいわけですが、GitHubのコミットログはアップデート判断としてはちょっと困ります。適度にバージョンXとしてリリースを打ってくれると助かるわけですが、それはどうしようもないですかね。subversionのtagsを使った管理をしてくれていれば、適当に"svn ls"の差分をとるなりして、まとまったアップデートチェックができる気がしますが、gitはよくわからないので諦め気味です。RubyForgeみたく、リリース管理を中央でやったりしないもんでしょうか。めんどくさいのはわかるけど。。。

間違って申し込んでしまいそう。

赤いのが出るらしいので、赤いのを買おうと思っているわけですが、何気なくクリックし続けて申し込んでしまいそうです。

さて、赤いのは日本でも販売されるんでしょうかね。そもそも、赤いのは販売されるんでしょうかね。

携帯文化はよくわからないので、とりあえずモバイルでインターネットをする生活に挑戦するためだけに、iPhoneを使おうとしているこのごろです。

ランチ時に甲子園が気になったり(ワンセグ)、ポスターからインターネットに飛んでみたくなったり(QRコード)、財布フリー?(モバイルSuica)してみたくはなかったりしますが、それでも、AppleというだけでiPhoneを選びます。Mac Book Proは重くて持ち歩く事を断念しましたが、iPhoneくらいなら持ち歩けますしね!

なにより、第2世代携帯はサービス終了間近ですからね。今の携帯は、Vodafone時代のKOTO。特に持ち歩きたい携帯に出会えず、iPhoneの可能性が出てからひたすら待ち続けました。

そんなこんなで、未だにうだうだしてます。つまり、通販に弱い自分へのとどめの一撃になりそうだな、という事です。

卓上電源タップ

コードすっきりタップ - T-KS126シリーズ

形に誘われて買ってしまいました。ちょうど、iPodの電源用に卓上の電源タップが欲しかったので、勢いで。

一般的な形の電源プラグ以外だと、2つで6つの口を占有してしまったりして非常に無駄の多いタップですが、形重視で選んだので問題なしです。

鑑賞目的8割くらいの気持ちで使い続けようと思います。

すてき。
Amazon.co.jp: MySQLデータベース構築バイブル: 志村 和彦, 松信 嘉範, 池田 徹郎: 本

MySQLのマニュアルを必要なときに必要な部分しか読んでいない自分には、Webよりも本が好きな自分には、非常にためになる本でした。

設定や機能の説明に、どのバージョンから使える様になっているか、使えない様になりそうかが書かれているのがうれしい。使った事がなく変更点をおいかけていないバージョンに関する情報が得られたのもうれしい。

FalconやMySQL Clusterに関して、名前だけをぼんやりと知っていた状態だったので、まとめて教えてもらえたのもうれしい。InnoDBやFalconの行ロックまわりの話も把握しきれていなかったのでためになった。

日本語の文字コード周りの注意点も教えてくれて助かる。内部でどのように扱っていて、どういう理由で問題になるかがわかりやすかった気がする。

ログの取り扱いに関する話も助かる。mysqlmanagerなどのツール類の話も知らなかったので助かる。チューニングに関するポイントもまとめられていて助かる。

まだ、ハックの章は読めてないながら助かる。有効活用できるかはなはだ疑問ながら、助かる。

とにもかくにも、なんちゃってMySQLユーザーな自分には救いの一冊。途中からぐいっと引き込まれてあっという間に読めた。久しぶりに通勤電車で眠気を振り切って読む気になれた。夏バテ?何、それ。

「マニュアルとソースと実験で十分」という人以外は、買って読んだ方がいいと思います。

一応、やろうと思えば出来ることまで確認した。

以下、やったことです。

  • caches_actionにフィルタチェインを強制的に継続させるオプションを追加
  • キャッシュヒット時にフィルタチェインを継続できる仕組みを実装
    • performed?でfalseを返すように内部変数をごまかす
    • beforeでtrueを返す
  • アクション内にキャッシュヒット時の処理を記述
    • performed?でtrueを返すように内部変数を戻す
    • (おまけで、Content-Typeなどのヘッダをいじくる)

以下のスクリプトを"config/initialize/action_cache.rb"などに書いて、アクションキャッシュを拡張します。

module ActionController::Caching::Actions::ClassMethods
 
  def caches_action(*actions)
    return unless cache_configured?
    options = actions.extract_options!
    around_filter(ActionController::Caching::Actions::ActionCacheFilter.new(:cache_path => options.delete(:cache_path), :continue => options.delete(:continue)), {:only => actions}.merge(options))
  end
 
end
 
class ActionController::Caching::Actions::ActionCacheFilter
 
  alias_method :before_origin, :before
 
  def before(controller)
    result = before_origin(controller)
    if result == false && @options[:continue]
      controller.instance_eval { @performed_render = false }
      return true
    end
    return result
  end
 
end

あとは、コントローラでcaches_actionを使ってキャッシュしてみたりします。

caches_action :action, :continue => true, :cache_path => Proc.new { |c|
  options = c.params.dup
  unless c.request.query_string.blank?
    query_key = Digest::SHA1.hexdigest(QueryString.new(c.request.query_string).to_s)
    options[:args] << "__query_hash__=#{query_key}"
  end
  ActionCachePath.path_for(c, options)
}

上記では、クエリストリングもキャッシュキーに含めるために:cache_pathオプションを与えていますが、本筋には関係ありません。QueryStringは正規化用に自前で書いたクラスです。これも気にしないでください。

アクション内でキャッシュヒットかどうかを判断するために以下のように書いてみたりしています。

if rendered_action_cache
  @performed_render = true
  return
end

以上。

稼働中プロセスのメモリの中身を知りたい。

/proc/[number]/memを開いて読み込んだらいい風な文書を見かけ、それらしいコードも見かけたので試しているわけですが、読み込み(read(2))で"No such process"(ESRCH)と言われてしまいます。参考にしたのは、以下。
How to read/write memory in an external process
ちなみに、(プロセスを停止させたりせずに)`cat /proc/pid/mem`した場合も同じメッセージでエラーになります。

Parallelsで作成したVMのDebian Etch("Linux debian 2.6.18-6-686 #1 SMP Sun Feb 10 22:11:31 UTC 2008 i686 GNU/Linux")で実験中。カーネルのパラメータは`sysctl -a`で見てみたけどよくわかりません。

実験でやろうとしている事は、無限ループでひたすら"hello"と出力するプログラムを実行しておいて、別のプログラムでそのpidの/proc/pid/memを読み込んで出力してみようと言う事です。両プログラムは同じユーザが実行します(screenで別画面にして両方をフォアグラウンドで実行)。

以下、/proc/pid/memを読み込んで出力しようとしているプログラム。

#include <assert.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
 
#define MAX_FILE_PATH 10000
 
int
main (int argc, char **argv)
{
 
  assert(argc == 2);
  pid_t pid = atoi(argv[1]);
  long result;
  char proc_pid_mem[MAX_FILE_PATH + 1];
  int errsv;
 
  // attach  proccess
  if (ptrace(PT_ATTACH, pid, NULL, NULL) == -1) {
    errsv = errno;
    fprintf(stderr, "PT_ATTACH: %s\n", strerror(errsv));
    exit(1);
  }
 
#if defined(__READ_BY_PTRACE__)
 
  /* ptrace API を使ってメモリを読みこむ */
  result = ptrace( PTRACE_PEEKDATA, pid, (void*)offset, NULL);
  printf("memory: %d\n", (int)result );
 
#else
 
  /* procfs 経由でメモリを読みこむ */
  sprintf(proc_pid_mem, "/proc/%d/mem", pid);
 
  int fd = open(proc_pid_mem, O_RDWR);
  if (fd == -1) {
    errsv = errno;
    fprintf(stderr, "OPEN: %s\n", strerror(errsv));
    exit(1);
  }
 
  off_t offset = 0;
  off_t p = lseek( fd, offset, SEEK_SET );
  if (p == -1) {
    errsv = errno;
    fprintf(stderr, "LSEEK: %s\n", strerror(errsv));
    exit(1);
  }
 
  if( p == offset ){
    char buffer[5];
    size_t size = read(fd, buffer, 4);
    if (size == -1) {
      errsv = errno;
      fprintf(stderr, "READ: %s\n", strerror(errsv));
      exit(1);
    }
    if(size == 4){
      printf("... dump ...");
      int i;
      for(i = 0; i < 4; i++) {
        printf("%02x", buffer[i]);
      }
      printf("\n");
    } else {
      printf("size<%d> is not 4.\n", size);
    }
  } else {
    printf("p<%d> is not offset<%d>.\n", p, offset);
  }
 
#endif
 
  // detach the proccess
  if (ptrace(PT_DETACH, pid, NULL, NULL) == -1) {
    errsv = errno;
    fprintf(stderr, "PT_DETACH: %s\n", strerror(errsv));
    exit(1);
  }
 
}
 

そもそも、メモリの内容がどんななのかよくわかっていないので、読み込めたとして役立てられるか不明です。が、実行中プロセスの問題解決手法として、メモリの中身をのぞく方法を知っておきたいわけです。procfsにこだわる気はなくて、とにかく、メモリをのぞく方法を知りたいということ。

GDBとか使うと、よいのでしょうかね。BINARY HACKSに、実行中プロセスを操る方法が書いてあるのはわかっているのですが、GDBの使い方がいまいちわからず躊躇しています。

そんなわけで、/proc/[number]/memの中身が気になって仕方がないこのごろです。


gdbを使ってcoreファイルを生成する方法を知りました。残念ながら、そこからメモリの内容を知るためにどうすればいいかは、まだわかっていません。
特選フリーソフト 「GDB」— プロセス動作中にcoreファイルを出力 —:ミラクル・リナックス

プロフィール

このアーカイブについて

このページには、2008年8月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2008年7月です。

次のアーカイブは2008年9月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。