題名:Java Diary-8章

五郎の入り口に戻る

日付:1998/7/3

目次に戻る


SETI@Support-part2(ver0.1)

さて、なんとかプログラムをだましだまし試験など行っている間にその「データが新しくなる」機会が訪れた。プログラムを作って3日後の夜のこと、解析プログラムが「データを送るためにインターネットに接続してもよござんすか」と聞いてきたのである。私は私が作ったプログラムを立ち上げて、自動データ更新モードにしたまま"Connect Now"というボタンを押した。

 

さて通常このボタンを押すと、おこることは以下のようである。まず"Sending Data.."とかいう表示がされる。それが終わると"All data sent, receiving data.."と言って受け取ったデータの値が表示される。ところがこの日は様子が違っていた。"receiving data.."と言う代わりに別のメッセージがほんの短い間表示され(たぶん"work unit found"とかなにかだったと思うが)いきなり再び解析が始まったのである。データの内容をみてみたが、当然のことながら新しいデータではなくて、それまで数十時間えっちらおっちらと解析をしてきたデータだ。

なんと。何を間違えたのかわからないが、とにかく解析プログラムはそれまで2日間にわたってうんうんうなって終えた解析をまた一からやり直そうとしている。一体これはどういうことだ?

しばらくの間私は呆然と解析を始めたプログラムの画面を見ていた。しょうがない。とりあえず今日は寝よう。「行き詰まった時には仕事を止めて休む」ってのは私にとっての鉄則だ。

 

翌日プログラムのソースをフロッピーにおさめて会社に持っていった。一つは昨日起こったことの原因を確かめたいのと、もう一つは本当に同じプログラムをWindows上のJavaでコンパイルして動かすことができるかどうか確認したかったからだ。

どきどきしながらソースファイルをコピーしてコンパイルをかけるといくつかメッセージがでてきた。ありゃ。やっぱり難しいことなのかしらと思って表示された文字をよめば、一つは「プログラム中に全角スペースをつかうんじゃない」というものであり、もう一つは「この関数は古い」というものだった。そりゃMacintoshはJDK1.1.7,WindowsではJava2だからそうも言われるだろう。

おとなしく言われたところをなおして再度トライすると見事に全天の絵が表示された。すばらしい。ちゃんと動くではないか。Javaの神様に感謝である。あたりまえとは言いながら、こうした光景を実際に見るのは感動的だ。これならばMacOSのAPIを覚え、WindowsのAPIを覚え、UNIX/MotifのAPIを覚え、、といった苦労から解放されるではないか。所詮デバッグはそれぞれのプラットフォームごとに行わなくてはならないが、少なくともWrite Onceは事実のようだ。

それから主に会社のほうではグラフィックスの表示の改良を行い、Macintoshの方では全体の制御を行うことにした。

さてこの日家のMacintoshから持ってきたのはJavaのソースばかりではなかった。最近になって「UNIX,WindowsNT,MAC OS-X用の画面表示なし解析プログラム」なるものが配布されていたのである。これであれば私のプログラムと組み合わせて使えば結構いいかもしれない。

しかしながら、会社のマシンからはFTPができないのである。何故FTPを許可していないか、ということについてずいぶん長い説明を聞いたが、何を言っているのかはさっぱりわからなかった。しかし私が理解できようができまいがとにかくFTPはできない。一方プログラムの配布はすべてFTPによって実施されている。となれば会社からのダウンロードは無理だ。

しかたがないから家でダウンロードしたものをフロッピで持ってきた、というわけである。これをちょこちょこと動かしてみると、見事にBerkeleyに接続し、データの解析が始まった。起動したコンソール画面では「X.xx%終了」とかなんとか文字が流れているが、確かにこれではどこまで進んだかわからない。私が作ったプログラムも少しは存在価値がでるかもしれない。

G3@240MHzに対し、会社で使っているPentium II @ 400MHzはさすがにすばらしいスピードで動く。1ユニットの解析に約11時間しか要しない。翌火曜日の朝には2ユニット目の解析が終わろうとしていた。これぞ私が何度も待ち望んだ「新しいデータが来たときの更新処理」の試験をするチャンスである。私はどきどきとしながら、"Update"というメニューを選択した。

その瞬間、確かに画面の表示は更新された。解析データの位置を示すシンボルは確かに別のところに表示されている。しかし何か様子が変だ。Analysis Startedの値が1970年とかになっている。おまけに解析データが指し示している位置は、縦も横も0。つまり図のちょうど中央である。これはいかなることか。

うげげげげと思って、あれこれしらべてみると、work_unit.txtがきれいさっぱりなくなっている。解析の内容と言うのはSETI@Homeのクライアントが作成する二つのファイルを参照している。一つはwork_unit.txtであり、これには解析中のデータの名前、あるいはどこを見ているか、というデータが書き込まれている。(解析の対象となるデータもこちらに記録されているが暗号化されていて、さっぱり内容はわからない)

もう一つはstate.txtであり、これには時々刻々と更新されていくやれCPU Timeをどれだけ使ったの、解析は何%終わったの、というデータが書き込まれている。ところが今みてみるとこのwork_unit.txtがどこにも見つからない。存在しないファイルからデータを読もうとしていたのだから、解析開始年月日が0つまり1970年になり、またデータの位置が原点、になってしまっていたわけだ。

それとともに私は家で起こった「いきなり同じデータで解析再開」の原因が分かった気がした。それからあれやこれやとやった結果、今のところデータ解析終了間際から新しく解析を始めるまでに起こることは以下の通りではないかと推測している。

SETI@Homeのクライアントは、一つのワークユニットの解析が終了するとwork_unit.txtを消してしまう。そしてその後に解析結果データをBerkeleyに向けて送信する。ここでwork_unit.txtがあるかどうかをチェックする。もしなければ新たなwork_unit.txtを受信し始める。(受信途中はtempworkとかなんとかいう名前で保存しているようだ)

ところがこの時点でwork_unit.txtが存在すると「あら。もうデータあるじゃない」ってなもんでまたもや解析を再開してしまうのである。では何故work_unit.txtが正常に削除されなかったか?

推定される原因のうちもっとも有力なのは「SETI@homeの解析プログラムがwork_unit.txtを消そうとしたときに、SETI@Supportがwork_unit.txtを読んでいた」である。自分が読んでいるときにいきなり横からデータを消されてはたまった物ではない。逆に言えば自分がファイルを消そうとしているのに、そのデータを「使用中。勝手にさわるべからず」と言われてはたまった物ではない。たぶん起こったことはそうしたデータの取り合いだったのである。

ではそんなにしょっちゅうwork_unit.txtを読まなければいいじゃないか、と思うかもしれないがこれがそうもいかない。今回のプログラムの売りは「解析データが新しくなったら自動的にデータも更新する」ことにある。ところがデータが新しくなったことの判定はデータ名が変わったかどうかで判定している。そしてデータ名は(今のところは)work_unit.txtの中にしか存在していない。従って毎度毎度それを読まざるをえないのである。

しばらく腕を組んだ私は沈思黙考3分の後にすべてを忘れることにした。というか正確に言えばwork_unit.txtが消えることは考慮にいれなくてはいけない。しかし解析プログラムとファイルの読み書きがかちあうのを避けるのは少なくとも今のところはどうやっても解決できるとは思えない。となれば「使う人の責任で使ってね」と大書きしてとりあえず忘れることにしよう。

 

さて翌水曜日は私の引っ越しの日である。新しい職場-といっても二つ隣のビルだが-に移動せねばならない。従って会社でのプログラム開発はしばらくお休みになった。家に戻れば寝る間はちゃんと確保した上でプログラムをあれこれいじるのに余念がない。それでなくても問題は山積しているのだ。work_unit.txtが消えることの対処がなんとかできたかな、、と思った時にまたもやデータの解析が終了に近づいた。二日か三日にいっぺんしか訪れない「データ更新機能」試験のチャンスである。

解析プログラムが解析結果を送信し、新しいデータを受け取ったのを慎重に確認した後でUpdateボタンを押した。その瞬間確かにデータの更新は起こった。そして今度はデータの位置が地図の真ん中にくることも、Analysis Startedの日付が1970年になることもなかった。一瞬私は喝采を叫び賭けたが、そのうち妙なことに気がついた。

先ほど解析を終了したはずのデータがリストの中に存在していないのである。なんだこれは?と思ってテキストファイルであるss_past_data.txtを参照してみるとちゃんと追加されている。????何がおかしいんだ?

あれこれしらべてみるとデータは見かけ上ちゃんと出力されているのだが、読み込みの時にデータの先頭にあるキーワードをちゃんと認識していないようである。私は「ふっ」と薄い笑いを浮かべた。(ろくに原因を考えもせずに)こうしたことは今まで何度も経験している。二つの文字列をequalsで比較しているときにこういう妙なことがおこるのは、たいていの場合どちらかに余分な空白か何かが含まれている時なのだ。

さてさてと思い、読み込んだ文字列にtrim()をかけてみたが状況は変わらない。何?trim()をかければ目に見えない余分な空白は削除されるはずなのだが。。。そろそろ頭が煮詰まってきた私は次に馬鹿な事をやった。equalsではなくindexOfを使いだしたのである。つまり周りにどんだけ余分な文字列が存在していようと、とにかくその文字列が存在していれば検知できるようにしたのだ。しかし結果は変わらなかった。これはどういうことだ?

煮詰まった頭にしてはめずらしく私は解決に向けて一歩踏み出すことを次にやった。つまり両方の文字列の長さを表示させてみたのである。予想としてはどちらかに削除できなく、かつ目に見えない文字が残っていて、文字数が違うのが発見できるのではないかと思ったからだ。しかし結果は意外なものだった。

プログラム中に記述してある文字列の長さに対して、読み込んだ文字列の長さが2倍近いのである。なんだこれは?しかし確かにss_past_data.txtにはおかしな点があった。テキストエディタで読み込んで、カーソルを移動させようとするとどうにも遅いのである。つまり→キーを2回おさないと一文字移動しないのだ。

今までの私だったら、ここで布団をかぶってねてしまうところだ。ところがこの日は布団をかぶる前にすることがあった。風呂にはいることである。湯船につかりながらふにゃふにゃと考えているうちにあることに思いついた。

 

今まで結構いい加減に考えていたが、このss_past_data.txtだけは他のファイルとは違う書き方をしていたのである。他のファイルはすべて書くときは頭から書き込んでしまい、それまで何が存在していても無視していた。しかしこのファイルだけは、順次内容を追加していかなくてはならない。どうすんべと思ったあげくに、本を見た限りでは唯一書き込む位置を指定できるRandomAccessFileを使ったのである。

ところがこのクラスはそれまで使っていたクラスとはちょっと書き込むさいの趣が違う。他のファイルはすべてPrinterWriterを使っていた。これだとコンソールに表示するのと同じ形式でprintln()を使って書き込める。

ところがこのRandomAccessFileにはそんな便利な関数は存在しない。よく考えればそれなりに理由はあるのだろうが、私はそんなことは考えず、とりあえず目についたwriteChars(String)という関数に飛びついた。とにかくStringを引数にとってくれるから問題なかろうと思ったのである。そして結果の見た目は良好だった。

ところがぎっちょん。私はJavaを使っていたのである。JavaではCharはなんでもかんでも2バイトだ。そしてwriteCharsというのは実は2バイトで書き込んでいたのである。どうりでテキストエディタで開いたときにカーソルの動きが遅いわけだ。エディタは見かけは一文字でも2バイト分の労力をかけて移動をしていたのである。そして読み込んだ結果は見かけは一緒でも実に2倍の長さを持っていたのである。equalsで比較しようが、indexOfで検知しようがひっかからないわけだ。

風呂から上がってちょこちょことプログラムの改修である。調べてみるとwriteBytesという関数が存在していて、それはその名の通り、一バイトづつ書き込んでくれそうだ。逆にこの関数は上位8ビットをすててしまうが、今回書き出すのはすべてASCII文字だから所詮1バイトしか使っていない。なんとかならあなと思ってプログラムを動かしてみれば見事に読み込みに成功した。

 

さて、これからもあやしげなトラブルのとの戦いは続いている。相変わらずデータ更新は二日か三日おきにしかテストができないから、ちょっと問題が起こればその対処を考えるのは結構大変だ。しかし最近ようやく収束の気配がみえてきた。未だに残っていて解決できない問題は「Macintosh上で時刻を得ようとしたときに、何をやってもグリニッジ標準時で表示する」という問題だが、まあこれは今のところを目をつぶろうと思っている。しかし皮肉なことにMRJ(Macintosh Runtime for Java)に付属してきたサンプルアプレットの時計までもが間違った時間を表示するのである。

さてこうしてプログラムのほうが落ち着くと今度は本当にアップロードする準備を進めなくてはならない。こうしたホームページからのプログラムの配布、というのは今までやったことがない。あちこちのサイトからプログラムをダウンロードしようと思えば、なんだかクリックすると自動的に落ちてくるがあれはいったいどうやっているのだろう。。と思ってあれこれ見てみたが、とりあえずHTTPで送るならば単にファイルにリンクするだけのようである。やれこれでうまくいくかしら、と思ってやってみた最初のトライは見事に水泡に帰した。

Visual Cafeが作り出したアプリケーションファイルをそのままサーバー上に置いてみたのだが、ダウンロードした結果を解凍(最初のファイルはCompact Proで関連ファイルと一緒に圧縮してあった)しようとしたら「テキストファイルは解凍できません」と言ってきた。なんと親愛なる解凍プログラムは圧縮ファイルをテキストファイルと思っているのである。

 

しばらく頭をひねった後に、普段わすれかけていた事実に気がついた。Macintoshではファイルにはデータフォークとリソースフォークなるものが存在しており、バイナリで他のシステムに渡した瞬間にリソースフォークのほうはふっとんでしまうということを。そしてすべてを失った解凍ファイルは「おめえみたいなテキストファイルはしらねえよ」と解凍プログラムに蹴られてしまうのだ。

これは困った。。と思ってまたもやあれこれのサイトを見てみると、Macintoshのファイルをバイナリで送ろうと思ったら、MacBinaryというものに変換する必要があるようだ。ところがこのMacBinaryから余分な情報を削除するアプリケーションは山ほど存在するのだが、普通のファイルをMacBinaryに変換するプログラムはなかなみつからない。あれこれ探してやっとMacBinaryII+というユーティリティを発見して事なきを得た。そしてこれまた「基本的にはテキストしか通さないインターネット」のご機嫌をそこねないようにと、Bin-Hexというユーティリティでテキスト変換したバージョンも作成してこれでMacintoshのほうはようやくめどがたった。

さて次は難関のWindows/Ohter Platformのバージョンである。これの何が問題といって、まず最初にダブルクリックで起動するJava Applicationにするところから面倒だった。なんでもManifestなるあやしげな名前をもったファイルをしかるべく設定して追加すればいいらしいのだが、そのためにはjarファイルをつくるユーティリティの使い方を覚える必要があり、Manifestファイルの書き方を調べる必要があり、、と苦労は果てしなく続いた。このころの私は新しい職場に配属されたばかりでやることが「全く」何もなかったのは少なくともこのプログラム作成の面からみれば幸いだったかもしれない。日長あたかもインターネットでなにか業務に関係あることを調べる様な顔をしながら、実はそんなことばかり調べていたのである。あれやこれやの試行錯誤を乗り越えて、最後にようやくダブルクリックしてアプリケーションが立ち上がったときには私はあやうく歓喜の雄叫びをあげそうになった。とはいっても本当に吠えた訳ではない。暇であろうが何であろうがとにかく仕事中だったのである。

 

さて、こうしてできあがったファイルはダウンロードページからダウンロード出来るようになるはずだ。まだまだバグは山ほど残っているだろうし、だいたいこんなプログラムを誰が使うのだろう、という問題ものこる。しかし私にとってはこれが世の中に発表するプログラムの第一号になるわけだ。少なくとも自分自身の趣味の為に作ったプログラムが少しでも人の役に立てば幸いと言う物。願わくば人の怒りをかうようなバグはなるべく少なくあってほしいものだが。

次の章へ


注釈

行き詰まった時には仕事を止めて休む:(トピック一覧)煮詰まった頭で何をしたって絶対にうまくいかない。本文に戻る