変な性分
変な性分があることに気づいた。
「たぶん遅いだろうな」「もしかしたら遅くて使い物にならないかも」
そんな予感がしていても
「とりあえず実装してみよう」「遅いことが確認されたら直せばいい」「何が遅いのかを理解してから実装することが重要だ」
と考えてとりあえず実装してしまう。
そんなこんなでPerlの勉強を兼ねて書いてみたのがこれ。MySQLソース版をWindows上でビルドした場合に"make install"あるいは"make_binary_distribution"するツールが無いので(それらしき名前のファイルはあるが現在のファイル構成にあっていないため使えないので)、"make install"用のバッチファイルを生成するPerlスクリプト。
#!/usr/bin/perl $orig = "mysql-enterprise-gpl-5.0.58-win32"; $new = "mysql-5.0.58"; $list = "files.txt"; open(IN, $list); @file = <IN>; $i=0; while ($i < $#file) { $name = $file[$i]; chop $name; $longname=$orig . "/". $name; if (-d $longname) { print "mkdir $name\n"; } else { $pos = rindex($name, "/"); $shortname = substr($name, $pos+1); @res=qx[find $new -type f -name $shortname]; if (scalar @res == 1) { chop $res[0]; print "copy $res[0] $name\n"; } elsif (scalar @res == 0) { print "ERROR... cannot find matching file for $shortname\n"; } else { print "ERROR... more than one matching file found for $shortname\n"; } } $i++; } close(IN);
で、走らせてみるとやはり遅い。1ファイル分処理するのに10秒くらいかかってる。当たり前といえば当たり前。毎回findしてるのだもの。
そんなこんなで作り直すことにする。このPerlスクリプトを書く前にはすっかりPerlのことは忘れていただけれども、書くことでいろいろと思い出した&覚えた。1回だけfindして結果を全てPerlの配列で保持し、文字列検索とかさせるようにしてみる。
Perlの配列操作と文字列検索がどれくらいの速度なのかは分からないけれども、シェルでfind連発するのと比べると2桁くらいは速いのではないかと想像。
いろいろ改良した結果
hashが便利らしいということが分かり、hashを使った実装にしてみた。十分速い。
最初の実装だとREADMEとかerrmsg.sysとか複数のディレクトリにあるファイルの所在が不確定になってるけど、今回のはちゃんとパスを見て最も類似している場所からコピーするようにした。これでWindows版バイナリパッケージを作ってテストしてみたいと思う。
#!/usr/bin/perl $prefix="C:\\mysql"; $srcname = "mysql-5.0.58"; $refname = "mysql-enterprise-gpl-5.0.58-win32"; $COPY_COMMAND="cp"; $srclist = "src_" . $srcname . ".txt"; $reflist = "ref_" . $refname . ".txt"; $sed_from="\\/"; $sed_to="\\\\\\\\"; system "find $srcname | sed \"s/$srcname\\///g\" | sed \"s/$sed_from/$sed_to/g\" > $srclist"; system "find $refname | sed \"s/$refname\\///g\" | sed \"s/$sed_from/$sed_to/g\" > $reflist"; open(IN, $srclist); @src = <IN>; for ($i=1; $i < @src; $i++) { $value = $src[$i]; chop $value; $pos = rindex($value, "\\"); $key = substr($value, $pos+1); if (!(exists $src_hash{$key})) { $src_hash{$key} = $value; } else { $merged = $src_hash{$key} . "," . $value; $src_hash{$key} = $merged; } } close(IN); print "\@echo off\n"; print "mkdir $prefix\n"; open(IN, $reflist); @ref = <IN>; for ($i=1; $i < @ref; $i++) { $value = $ref[$i]; chop $value; $longname=$refname . "\\". $value; if (-d $longname) { print "mkdir $prefix\\$value\n"; } else { $pos = rindex($value, "\\"); $key = substr($value, $pos+1); if (exists $src_hash{$key}) { @token = split( /,/ , $src_hash{$key}); if (@token == 1) { print "$COPY_COMMAND $srcname\\$token[0] $prefix\\$value\n"; } else { $max = 0; $max_dup = 0; $token_id = 0; for ($j=0; $j < @token; $j++) { if ($token[$j] eq $value) { $max_dup = 0; $token_id = $j; last; } @token_ref = reverse(split( /\\/ , $value)); @token_src = reverse(split( /\\/ , $token[$j])); $cur = 0; for ($k=0; $k < @token_ref; $k++) { if (exists $token_src[$k] && $token_ref[$k] eq $token_src[$k]) { $cur++; } } if ($cur > $max) { $max = $cur; $max_dup = 0; $token_id = $j; } elsif ($cur == $max) { $max_dup = 1; } } if ($max_dup == 0) { print "$COPY_COMMAND $srcname\\$token[$token_id] $prefix\\$value\n"; } else { warn "[WARN] cannot decide src-file for $value\n"; } } } else { warn "[WARN] no proper file found for $value\n"; } } } close(IN); unlink $srclist, $reflist;