システム・PC

aio_read

aio_read()というのは非同期にreadするという関数です。普通のreadは一定のデータを読み終わるまで戻ってこないんですが、こいつは即座に戻ってきます。

したがって、戻ってきた直後はデータがない可能性もあるわけですが、その間ベツな処理をあらかじめしておいて、その後に読んだデータの処理をすることができます・・・というような関数なのでしょう。

これが使い道があるのかどうかはおいといて、調査する必要が出てきたので、軽くFreeBSDで調査をしてみました。

まずは、カンタンなサンプルを作成して実行してみました。

するとENOSYSというエラーが。つまり、サポートされていないと・・・

うーむとばかりにカーネルソースをみてみたら、VFS_AIOが定義されていないときは、全てエラーとなるようにコーディングされてました。

というわけで、早速

options VFS_AIO

を追加してカーネル再コンパイル。無事動きました。ソースがあるって素敵ですね。ふぅ

って本来の目的は全然進んでないやん・・・・

日付からEpochを求める

Epochとは FreeBSDのman 3 time で見てみると

1970/1/1 00:00:00 (UTC)からの経過秒数

と定義されているようです。

UTCには閏秒があったりして厄介です。また初期実装エンジニアの勘違い(!?)もあって上記のように実装されていないシステムが一般的で、閏秒はなかったこととして計算するのが主流のようです。いうなれば原子時(TAI)ベースといったところでしょうか?これについては語ると長くなりますので割愛します。詳細はここみてください。

今回は現在の日付からepochを求めるお話です。

ローカルタイムからepochを求めるには mktime()という関数を使えばよろしい。これはマニュアルに書いてあります。日本の場合はこれで終了です。

問題はサマータイムのある地域の場合です。業務で必要なので調べてみました。

簡単のためロンドンについて書きます。

ロンドンでは3月の最終日曜日の深夜1時から 10月の最終日曜日の1時までがサマータイムとなります。(どちらもGMT)

入るときは1時間だけ時間が飛びます。つまり00:59:59の次が02:00:00となります。その間の時刻は存在しません。

戻るときは1時間だけ時間が巻き戻ります。01:59:59の次が01:00:00になります。

厄介なのは後者です。前者は mktimeライブラリがよろしくやってくれますが、後者は時刻だけからでは、サマータイム終了前なのか後なのか判断できないので、わかりません。

これはプログラマが責任を持って渡してやらなければなりません。それが struct tmのtm_isdstメンバです。

tm_isdstを正にするとサマータイム内、0にするとサマータイム外として判断します。負の値を設定するとよろしくやってくれるようで、中間の30分の前後でわけてくれるようです。

なお、JSTで実行する場合はサマータイムが存在しないので、tm_isdstを正にしておくと、常にエラー(-1)になります。年月日、時分秒だけ代入しておいて変換しても一向に-1しかmktimeが返さないので、ちゃんと0とか-1を代入してからmktimeを実行しましょう。

通電。サーバ再起動

サーバのうちの1つ(FreeBSD)のシャットダウン画面を見ていたら

552d5h6m44s

と出ました。

どうもこのマシンは552日間も連続稼動していたもようです。ここまで、電源が切られていないと、起動時に何かトラブルがあるんじゃないかとおそるおそる起動したら・・・・

案の定起動後固まりやがりました。_| ̄|○ なんてお約束な・・・ 泣く泣くリセットして再起動したらなにやら安定した模様ですが・・・画面にHDのCRCエラーが。危険なニオイがします。CRCエラーが出ているところはRAID組んでてミラーになってるところなんですが、うーむ・・・・ とりあえずそろそろリプレースを考慮すべきですね。 続いて、次に問題が発覚したのがISDN。いまさらISDNかよ!といわれそうですが、問題になってるのは電話とFAXがつながっているISDN機器でして・・・こちらが電源が入らない!! 古今東西電源が入らないときは、しばらく休ませて、叩けばよいの風習により斜め45度よりチョップをかまし、無事電源が入りました。 こっちもリプレースせんといかんか・・・・(ホントいまさらながらなんですが・・・)

VAIO-Uで今時2万円

DSC00464.jpg


VAIO-Uの外付けのDVD-ROMドライブを買ってしまいました。というのも普通のiLinkで繋ぐドライブだとそのドライブから起動しないんです。まぁ普通iLinkからは起動しないので、そりゃそうかと思えばそうなんですが、例えば完全にパーティションをぶっ壊してしまった場合など、希にドライブから起動したいときというのがあります。

でもってこの専用ドライブ(PCGA-DVD1/A)の値段が2万円。高いですねぇ。

しかも、iLinkのコネクタの横に電源取得用のコネクタもくっついててACアダプタなしでも動くようなケーブルになってるんですが、これが使えるのは当然VAIOのノートだけ。

しかもこのケーブル以外のケーブルが同梱されていないから(別売りか?)VAIO以外では電源を取る手段がなく、使えないという・・・_| ̄|○

これでCDから起動しなければ暴れるところですが、試しにFreeBSDのインストールCDをつっこんでみたら、無事起動しました。

とりあえずよかったよかった・・・・でもFreeBSDはインストールしないけどね。

ところで、このACアダプタどこでうってるんでしょ?AC10Vとは書いていますが、SonyStyleでは売ってないようだし・・・別に買う気はないんですが、気になります。

慣れてないrubyプログラム

rubyの正規表現の^の挙動について数時間悩みました。詳しい人には既知なんでしょうが、perlと挙動が違うんですねぇ。

rubyの^は文字列の先頭および改行コードの次にマッチする。(確かに行頭だ!!)
perlは文字列の先頭だけ。

ですので、文字列のなかに改行コードがあると動作が異なります。私自信、perlスタイルで動作することを期待して何度もプログラムを書いているので、まさかこんな違いがあるとはヤラレました。

例えば次のプログラムはマッチします。


a = "123¥n456¥n789¥n"
p /^7/.match(a)


では、文字列の先頭で確実にマッチさせたいときはどうするのか?というと¥Aを使えば全て解決です。ちなみに後ろは¥zまたは¥z。大文字と小文字で最後の文字が改行のときの挙動が違います。

でもってperlのマニュアルの該当部分も読んでみました。rubyと同じ挙動にするにはmをつければいいようです。例えば次のプログラムはマッチします。


"123¥n456¥n789¥n" =~ /^7/m && print "match¥n"


perlにはまだまだ知らない機能が隠されているようです。奥深いですねぇ。

RMagickを使ってみた


フリーソフトにかかわらず、最近のドキュメントはhtmlで書いてあるのがあたりまえみたいです。というわけでman大好きのワタシはカナリ悲しい思いをしています。使いにくいったらありゃしない。w3mとかも入れてみましたが、TABで移動してリンクをたどるのがやっぱメンドい。結局HTMLをgrepしてキーワードをサーチしてlessで見ているワタシが気がついたらいました。



さて今日の目的はRMagickつかってイメージのwidthとheightを取得すること。まぁこんなカンタンなことくらいカンタンにできるでしょう。だいたいにおいてfileコマンドですらできます。


BTW。チャレンジすること1時間、どうにもカンタンに出来ませぬ。ドキュメントすみからすみまで読んでみましたが、らしきものがない・・・・

例えばこんな例

#!/usr/local/bin/ruby

require 'RMagick'

p Magick::Image.ping('wotaku2.gif')[0]

で、これを実行すると

"wotaku2.gif GIF 1188x910+0+0 PseudoClass 256c 8-bit 563172b"

となるわけでイメージのサイズの文字列は取得できます。しかし、どこを探してもズバリこの情報を取得する手法がなくて、結局この文字列から変換するしかないような・・・いやワタシが単純に間違っているだけかもしれませんが・・・

と再度ドキュメントを丹念に眺めていたらcolumnsとrowsというアヤシゲなメソッドが。。。ずばりこれでした。。。。ドキュメント単に見逃してた・・・_| ̄|○

Ruby1.8+DBI::SQLite その2

このまえの続き


結局、SQLite.cをのぞいてみたら、どこにも last_insert_rowid()らしきものはなし。ということで、どうあがいても使えないという結論になりました。


しゃーないので、自力でセコセコつくることに。といっても前後を眺めて、見よう見まねです。で、気がついたら、Rubyプログラムを始めたのに、Cプログラムばっかり眺めている自分がいました。(笑)


個人的にワタシは最終的なアプリを作ることに快感を感じるほうなんで、この手の言語とかモジュールの開発はしないに越したことはないと思うほうなんですが、こういう現状じゃ、しゃーないですね。


とりあえず、パッチもできたので、そのまま作者に報告。以外とこころよい返事が頂けたのが唯一の救いです。


パッチ

*** SQLite.c- Mon Jun 21 21:53:35 2004
--- SQLite.c Mon Jun 21 23:40:38 2004
***************
*** 317,322 ****
--- 317,334 ----
}

static VALUE
+ Database_last_insert_rowid(int argc, VALUE *argv, VALUE self)
+ {
+ int state;
+ struct sDatabase *db;
+
+ Data_Get_Struct(self, struct sDatabase, db);
+ state = sqlite_last_insert_rowid(db->conn);
+
+ return INT2FIX(state);
+ }
+
+ static VALUE
Database_do(int argc, VALUE *argv, VALUE self)
{
/* argv[0] = stmt
***************
*** 857,862 ****
--- 869,876 ----
rb_define_method(cDatabase, "[]", Database_aref, 1);
rb_define_method(cDatabase, "[]=", Database_aset, 2);
rb_define_method(cDatabase, "columns", Database_columns, 1);
+ rb_define_method(cDatabase, "__last_insert_rowid", Database_last_insert_rowid, -1);
+

rb_include_module(cDatabase, rb_eval_string("DBI::SQL::BasicBind"));

サンプル

#!/usr/local/bin/ruby

require 'dbi'
dbh = DBI.connect('DBI:SQLite:mydb')

begin
dbh.do('create table test (test_id integer not null primary key, test_num integer)')
rescue
end

(1..10).each{|i|
dbh.do("insert into test (test_num) VALUES(#{i})")
p dbh.func('last_insert_rowid', nil)
}

dbh.do('commit')
dbh.disconnect

追記

前回のBlogでAutoCommit => trueとするとロックされてブロックされると記述しましたが、実際は逆です。(単純なプログラムコードのケアレスミス)]

このあたりの仕組みもソースをざっと眺めたので、気が向いたら詳しく書こうと思います。

Ruby1.8+DBI::SQLite

Ruby言語体系を理解してきたので、さっそくDBあたりのプログラムを作ろうと思い立ったわけですが、どうにもうまくいかない。

ケッキョク、この組み合わせのケースのドキュメントが殆どなく、試行錯誤の限界に達したので、ソースを読んでみました。以下そのメモ

まず採番の問題。SQLiteでは not null primary key属性のあるカラムは自動的に insertするときにオートインクリメントするらしい(FAQより)。したがって insert するときにプライマリキーだけinsertしなければ採番の問題はとりあえず解決です。まぁこれはこれでヨシとしましょう。 さて、問題はここでinsertしたレコードに一体どのようなユニークなIDが振られたか?を取得するのが非常に悩ましいということです。 当然のことながらinsertした直後に selectというのはアトミックに動作しないから、却下です。で、SQLiteのFAQには 「sqlite_last_insert_rowid()」を使えとあります。SQLiteはCのライブラリベースのRDBなんでまぁこれはこれでよいんでしょうが、rubyのこのインタフェースを使おうとしたときには問題になります。 そのようなインタフェースがないので、ニントモカントモ正しく取得できそうにない・・・いや、ワタシが間違っているだけで、やり方あるのかもしれませんが・・・ 次に、AutioCommitを trueにして beginでロックをするという手法に挑戦。ですが、これをやってしまうと、他のクライアントが同時にDBにアクセスできずconnectでエラーに・・・これじゃWebアプリとかで使えませんね。せめて他が手放すまでブロックしてもらわないと・・・いや、ワタシが間違っているだけで、やり方があるのかもしれませんが・・・ とりあえず、もうちょっと調べてみようと思います。まずは最新バージョンにするところからかな。 まぁruby-dbiのバージョンみたら0.0.23って書いてあるから、まだまだこれからですかね。すなおに、この構成をアキラメルというのが正しい解法のような気もしますが、こんな構成で頑張っている人は世の中に何人いるんだろうか・・・ To be continued

日曜、休日を赤くするようにしてみた

昔の日記のスタイルにできるだけ近づけたい・・・
ということで、自分でモジュールつくりました。

最近は休日のルールが難しくて自分でもよく理解してないんですが、まぁちゃんと動いているかどうかは、次の祝日のある7月になればわかるでしょう。

ところで、春分の日と秋分の日だけは激しくどうにもならないです。この日を決めるルールは、「暦の科学」(ブルーバックス)によると

「太陽が日本標準時で春分点、秋分点を通過する日」

と書かれています。天体の運行は思いのほか不規則なので、この値は観測によって決め、るわけで、0時付近にこの時間が来ると激しく大変なわけです。実際には一年前の2/1の官報で決められるそうです。

昔の日記では計算で求めてましたが、今回は直接指定するようにしました。

ちなみにこの春分、秋分は400年周期で移動し、春分は3/19~3/21、秋分は9/22~9/24の間になるようです。

9/22の秋分というのはあまり聞いたことがないですが、2012年に登場する予定だそうな。

日付に曜日を出すようにしてみた

MTでテンプレートいじって日付の横に曜日を出すようにしてみました。マニュアルを見ると、

<$MTEntryDate format="%x"(%a)>

とすればよさげなんですが、&#2;とか妙な文字が入ってどうにもうまくいきません。で、さっそくソースを見る羽目に。

問題点はUtil.pmの72行目あたりの

$f{a} = substr $L->[0][$f{w}] || '', 0, 3

というところ。ようするに曜日の文字列の先頭3文字を取ってくるとここでコーディングされているわけです。でもって曜日の文字列は同じファイルの852行目あたりで直接Unicodeで

'jp' => [
[ '&#26085;&#26332;&#26085;', '&#26376;&#26332;&#26085;',
'&#28779;&#26332;&#26085;', '&#26408;&#26332;&#26085;',
'&#27700;&#26332;&#26085;', '&#37329;&#26332;&#26085;',
'&#22303;&#26332;&#26085;'],

とかかれているわけで、これでは最初の3文字はたしかに&#2なりますな・・トホホというわけです。

ちゅうわけで省略形を意味する%aではなく、略さない%Aを使うことしました。
ただ%Aを使うと「日曜日」とかなって気持ち悪いので、Util.pmをextlibにコピーして雛型とし、モジュールを書き換えることに。

まぁ作業といっても、とりあえず「曜日」という言葉をあらわした[
「&#26332;&#26085;」を削除するだけですから簡単です、リビルドしてスッキリ解決、ズバット終了。

とおもったんですが、水曜日と木曜日が逆に表示されるやんけ~ オリジナルの曜日の文字列が水と木逆なってますがな。 というわけで、3番目と4番目の要素を入れ替えて、本当に終了。 以外と苦労しました。 これだけMTは日本に普及してるのに誰もこの機能つかってないんかな? (追記) すでに同様の問題にぶちあたっていて、解決されている方を発見しました。さすがにいないってことはないか(笑)