Perlの変数に文字数制限(容量制限)はあるか

このQ&Aのポイント
  • Perlの変数には文字数制限(容量制限)はありますか?
  • Perlで書かれた自作の掲示板で、突然データが欠けてしまいました。データ容量が1.5MBほどあり、容量制限が関係しているのか疑問です。
  • 他にも似たような問題が発生した経験がある方、アドバイスをお願いします。
回答を見る
  • ベストアンサー

Perlの変数に文字数制限(容量制限)はあるか

Perlの変数に文字数制限(容量制限)はあるか Perlで書いた自作の掲示板なのですが、ずっと普通に動いていたのですが 急にデータが欠けてしまいました。書き込みデータはテキスト形式で、 ↓の様な形で保存しています。 <div>1つの書き込みの中身</div>\n <div>1つの書き込みの中身</div>\n <div>1つの書き込みの中身</div>\n <div>1つの書き込みの中身</div>\n <div>1つの書き込みの中身</div>\n 1つの書き込みは1行に収まっていて、書き込み時に \n を付けて保存して、 読み込み時は配列に読み込んで、べろっと出すだけの処理です。 掲示板書き込みなので unshift で上が新しい書き込みにしてあります。 通常のタグ禁止処理や、改行コード処理はしてあります。Perl5.6.1です。 数日前、容量が減っていることに気付き、調べてみると、 <div>1つの書き込みの中身</div>\n <div>1つの書き込みの中身</div>\n <div>1つの書き のような形でデータが欠けていました。欠けていると言っても9割方消えていました。 残っていたのは新しい側の書き込みです。 いつ消えたのか、何をした時に消えたのかが不明のため、原因を探っている段階です。 もちろん、一番怪しいのはプログラムのミスなのですが、それも調べつつ、 ちょっと前から気になっていた点として、データ容量が1.5MBぐらいまで ふくらんでいて重くなっていたんです。 data.dat のような1ファイルにテキストばかり1.5MB、そして内部の処理でも 普通にその容量を一つの変数に入れたりしています。 データが唐突にぶつっと切れていることと、容量が多くて気になっていたこと、 この辺りでちょっと怪しいのですが、変数の容量制限、ファイルの容量制限が 調べても出てきません。知っている方いましたら教えてください。 他にも、そういうバグの時こういうミスがあったよ、など、ありましたら アドバイスをお願いします。 自分が作った物のデバッグで恐縮なのですが、よろしくお願いします。

  • Perl
  • 回答数8
  • ありがとう数17

質問者が選んだベストアンサー

  • ベストアンサー
  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.8

No.3&6です。 > flock してません・・・・・・。 > つまり、読み込み時に競合があって書き込まれたため、開いたままのデータが > 変なところで書き込み処理に割り込まれて、おかしくなったということでしょうか。 > でしょうか、というか、その可能性があった、というところですかね? ちょっと説明が足りなかったので補足します。 読み込み時にflock()しなかった場合ですが、書き込みが純粋に追記だけの場合は(記事表示で途中で切れることはあるかもしれませんが)データファイルの破損までは至らないかなと思います。もちろん、読み込み内容が壊れるには違いないですので、読み込みルーチンにもflock()は追加すべきです。 データファイルが壊れるケースですが、既存記事の修正機能が実装されている場合などで、読み込みルーチンで取得した@BbsDataの値を使った書き込みルーチンが別にあった場合には、たとえその書き込みでファイルロックがされていたとしてもデータファイルが壊れることになります。 もっともその場合、データ変更に関する一連のロジック自体を見直す必要があるかもしれません。 既存記事の変更を行う場合には、「一度のファイルオープン+ファイルロックの間に、読み書きを全て済ませる」という処理に置き換えないと、ほぼ同時に複数の書き込みが発生した場合に一部のデータが失われるという別の不具合が発生する恐れがあります。ご参考まで。

toragara-tiger
質問者

お礼

別の質問になってしまったので立て直します。 回答してくれた皆様、ありがとうございました。

toragara-tiger
質問者

補足

読み込み時、flock処理を追加してみます。 # 書き込みデータの読み込み open( BBS, "< ../data/bbs.dat" ); flock( BBS, 1 );# ロック @BbsData = <BBS>; $BbsCount = @BbsData; close ( BBS ); 修正機能は付いていません。 でもそのうち付けようと思っていたので、付ける時にロック系、気を付けたいと思います。 とりあえず再開に向けて、処理するデータを小さくし、読み込み時に flock処理を追加してみます。 あと今回のことを一応、サーバー会社に聞いて返事を待つと。 それからもうちょっと頻繁にバックアップを取ります。。。 Googleにキャッシュが残っていたので少しサルベージしましたが、抜けが出てしまいました。 Google以外でそういうキャッシュが自動的に残っている可能性のあるサイトってありませんかね? xxx.cgi に最初の20件、 xxx.cgi?page=1 だと21件~40件、 xxx.cgi?page=2 だと41件~60件、 xxx.cgi?page=3 だと61件~80件 という感じで表示させていたのですが、別ページ扱いなのでキャッシュが残ってたりするんですよね。

その他の回答 (7)

回答No.7

CGIを動かしているのがレンタルサーバ(などの第三者が設定した環境)であって、 壊れたファイルが0や8192バイトなどの切りの良い(?)サイズで切れているなら、 ファイル書き込み中にシグナルで殺されている可能性も考えられそうです。 時間のかかるCGIを制限しているレンタルサーバだと、 比較的短い時間でタイムアウトして、CGIにSIGTERMやSIGILLLが飛んできて、 プロセスが殺されることがあります。 ファイルサイズが増えれば、書き込みに要する時間も長くなるので。 もしそうだとすると、解決策は・・・ SIGTERMを無視してみても、最後にはSIGKILLが飛んでくると思うので、 処理を早く終わらせるしかなさそうです。 例えば、一定行数ごとにファイルをわけて、表示時はページ制御するとか。 表示&保存する件数を、全部はあきらめて最新何件などに減らすとか。 他には、limitでメモリ制限されてる、なんて可能性もありますが、 それだとファイル書き出しより前の時点で落ちるでしょうから、 今回の原因としては考えにくいですね。

toragara-tiger
質問者

補足

回答ありがとうございます。 サーバーはレンタルサーバーですが、壊れたファイルは 114,898バイトでした。 キリのいい数値ではなさそうです(たぶん)。 一応サーバーに、そういうことをすることもあるか聞いてみます。 動いていた時も書き込みに1秒ぐらいかかっていたので、これまでの累積を いっぺんに開いている状態はやめて、もうちょっとすっきりさせたいと思います。

  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.6

No.3で回答した者です。 追加書き込みのロジック自体は問題ないように見えます。 # 強いて指摘するなら、追記のみの場合はファイルサイズが小さくなることはありませんので、truncate()によるファイル全消去が不要なくらいでしょうか。 # seek(WRITE, 0, 0)だけで十分です。 # 余談ですが、ファイルサイズが減る可能性がある場合においても # ファイルを全消去してから書き込むよりは、先頭へシーク+全データ書き込み後に # truncate(WRITE, tell(WRITE)); # とした方が、ディスク処理のオーバーヘッドが少ないです。 で、書き込みが問題ないとなると、やはり読み込み処理に問題があるのではないでしょうか。 公開して頂いたサブルーチンを見る限り、おそらく「読み込み用」サブルーチンが別にあるのではないかと推測します。 # でないと、追記しない限り読めないことになりますから・・ Perlのflock()による排他処理は(OSにもよりますが)flock()を利用したファイルオープンに対してしか機能しません。従って、ファイル読み込み時にも open(HANDLE, ...); flock(HANDLE, 1); # リードオンリーモードでロック といった処理が必要になります。 これを忘れた場合、質問者さんのような症状が発生する可能性があります。

toragara-tiger
質問者

補足

おっしゃる通り、全書き換えの時のロジックを、追記の時も使い回して、 まあ、余計な動きをしているけど動くからいいか、とそのままにしていました。 余計な部分は省くように参考にさせていただきます。 読み込み部分ですが、そのまま貼り付けます。 1ページに20件表示とかする用に行数($BbsCount)も取得しています。 # 書き込みデータの読み込み open( BBS, "< ../data/bbs.dat" ); @BbsData = <BBS>; $BbsCount = @BbsData; close ( BBS ); flock してません・・・・・・。 つまり、読み込み時に競合があって書き込まれたため、開いたままのデータが 変なところで書き込み処理に割り込まれて、おかしくなったということでしょうか。 でしょうか、というか、その可能性があった、というところですかね?

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

現在の Perl の実装では, 文字列を「長さ+内容」という形で記憶します (C とは異なり「終端に特定の文字がある」という形ではない). この「長さ」を確か int で記憶しているはずなので, 「1つのスカラーに記憶できる文字列の長さ」は限界があります. 現状ではシステムによらず 32ビット符号付きで上限は 2GiB-1 だったかな? 配列やハッシュの要素数にも同じような制限があるはず. ただ, #2 の最後にもちょろっと書いたけどそれとは無関係で #3 にいわれる排他制御の問題だと思いますよ. 「競合はしていませんでした」と書かれていますが, 「複数人が (ほぼ) 同時に掲示板に書き込む」状況を想定して調べましたか? ああ, もう 1つ「遅延書き込み」という問題もあり得るか. 「同期書き込み不可能」とかいう腐った OS だと考えられなくもない.

toragara-tiger
質問者

補足

たびたびありがとうございます。 やはり聞く限り、2ギガビットとか全然行ってないですし、その辺の容量オーバーは 違う感じですね。排他制御ですが、本に書かれていたロックをかけるやり方をしていた だけです。回答番号:No.3の補足にその部分を載せました。 同時書き込みや非常に重い時にも大丈夫かと言われると、flock に任せているだけで 少なくともテストはしていませんし、実行環境もそんな混み合ってはいませんでした。 そういう状況に耐えうる堅牢なロジックがあるなら念のため入れ替えておきたいところです。 でもその前に今回のデバッグですね・・・・・・。

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.4

ファイルの排他制御に失敗した可能性が高いんじゃないかと思います。 2つのプロセスが同時に書き込んだりしたら、例えば、 あるプロセスが書き込んでいる途中のタイミングで、次のプロセスだデータ読み込みを実行    →書き込み途中までのでデータしかしか読み込めない ということになります。その後、最初のプロセス側では書き込み完了すれば、ファイルは正しい状態になりますが、 後のプロセス側で読み込んだデータは、その中途半端に読み込んだ壊れた状態になっているので、 後のプロセス側が書き込みを行えば、ファイルが壊れた状態に更新されることになります。 排他処理はファイルサイズに依存した問題ではありませんが、 ファイルサイズが大きくなると読み書きに時間がかかるようになるので、 タイミング的に問題が発生する確率は高くなります。

toragara-tiger
質問者

補足

回答ありがとうございます。 書き込み処理を行っている部分のソースを、回答番号:No.3 さんへの補足に載せました。 詳しく知識があるわけではありませんが、「flockでロックしているから大丈夫」、 という認識でした。解説本にもそうあったと思います。 それで、それがデータサイズが大きすぎて時間がかかった時とかのイレギュラー時の 処理なんですよね。。。

  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.3

ファイル読み書き時の排他制御が適切でなかった場合によく起こる症状に見えます。 flock()などでファイルロックをかけるのが一般的な排他制御ですが、書き込み時にopen(HANDLE, '>', ...)で新規書き込みオープンしてしまうのが最も典型的なミスです。 この場合、ロックがかかる直前に他のプロセスから読み込み処理が行われると空ファイルが読まれてしまうので、意図した動作にならずにファイル内容が失われる恐れがあります。 読み込み/書き込みのファイルオープン・クローズ処理に問題がないか確認されてはいかがでしょうか。 該当部分のスクリプトを公開して頂ければ、具体的なアドバイスが出来ると思います。

toragara-tiger
質問者

補足

回答ありがとうございます。 取り急ぎ書き込み部分を載せます。紙谷歌寿彦氏の本のやり方だったと思います。 $WriteComment に今回の書き込みデータが入っている状態です。 # ファイルの追加書き込み処理 open( WRITE, "+< ../data/bbs.dat" ); # 開く flock( WRITE, 2 ); # ロック @OldBbsData = <WRITE>; unshift( @OldBbsData, $WriteComment ); truncate( WRITE, 0 ); # サイズを0に変更する(消す) seek( WRITE, 0, 0 ); # ファイルのカーソル位置の変更 print WRITE @OldBbsData; close( WRITE );

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

「ファイル容量の制限」は OS やら設定やらによるけど Perl は無関係. 「変数の容量制限」は, 「Perl言語」としては「int の大きさ」が影響したはず. あと, 当然だけど「1つのプロセスで使うことのできるメモリ量」にも依存する. だから, Perl処理系に (この辺の) バグがなければ 1.5 MB くらいでは死なない. 手元では Perl 5.10.1 だけど, $a = join('', 'a' .. 'z') x 1000000; くらいならまったく問題なく動きます. ファイルの読み書きで競合しているって可能性はないか?

toragara-tiger
質問者

補足

回答ありがとうございます。 ファイルハンドラを見てみましたけど競合はしていませんでした。 ずっと問題なく動いていたんですよね。それでいきなり壊れたので 「ついに処理できる容量が限界を超えた」のかと思ったのですが。 「ファイル容量の制限」は違うんですね。 となると変数かメモリなのですが、変数の「intの大きさ」というのは どの部分のことでしょうか?  書き込みデータ処理には、変数や配列を使っていますが結構そのまま ガンガン入れている状態です。

noname#119957
noname#119957
回答No.1

変数なら、型により長さが規定されているでしょうね。 型で規定されている長さを超えるとダメでしょう。 Perl5.6.1 言語の仕様では?

toragara-tiger
質問者

補足

回答ありがとうございます。 型は……、ないです(よね?)。 その仕様がちょっと見つけられなくて。 今、教えてgoo内で「文字数の規定はありません」と答えている回答を 見つけました。メモリ関連は影響するようです。

関連するQ&A

  • perlで変数の中身を変数とみなす方法ってありますか?

    perlで、変数の中身を変数とみなし、その中身を知る方法ってありますか? 具体的に言うと、 $abc = "$xyz"; $xyz = "test"; なる状況だったとして、$abc から "test" という文字列にたどりつく 方法ってあるのでしょうか? 何をしたいのかというと、テキストファイル上に "$xyz" と書かれてたと します。そのテキストファイルを perl で解読したとき、その時点での 実行中の $xyz に何が入っているかを得たいのです。 もちろん、連想配列を使えば似たようなことができるのは知っていますが、 性質上、できればスタティック変数を使いたいのです。 そのような方法は、perl には用意されているのでしょうか?

    • ベストアンサー
    • Perl
  • ファイル容量の制限

    PHPを使って大量のテキストデータ(100Mくらい)を処理しようとしていますが、PHPで扱える容量の制限を越えているようで、処理ができません。 以前同じような現象でphp.iniを修正することで回避した記憶があるのですが、どのように回避すればよろしいでしょうか。 #ローカルのパソコンで処理するので、多少重くても問題ありません。

    • ベストアンサー
    • PHP
  • perlからphpを実行して結果を得る方法

    perlのプログラムから同一サーバー内のphpを実行してその結果を取得したいのですが、うまくいきません。 print.phpというファイルの中身が <? echo "<div>1234567890</div>"; ?> だとして、これをブラウザで見た場合のソースは <div>1234567890</div> となるわけで、この1234567890をperlのプログラム内で表示するために main.cgiというプログラム内で $data = '/***/www/print.php'; open(FH,$data); @list = <FH>; foreach $data_line ( @list ) { if ($data_line =~/<div>/ ){ $data_line =~ s/<div>//i; $data_line =~ s/<\/div>//i; print = $data_line; } } close(FH); のような処理をすると echo "1234567890"; という実行前のphpの中身が表示されてしまいます。 表示したい結果はこの場合ブラウザでphpを実行した時のソースからdivタグをperl側で抜き取った 1234567890 なのですが、同じ事をperlの書き換えで実現する上手い方法があればご教授いただけますと助かります。

    • ベストアンサー
    • CGI
  • PHPスクリプトでperlスクリプト

    はじめまして。PHP初心者です。助け舟をお願いします。 PHPスクリプトで、formの表示からデータの受け取り→ファイルに書込み→終了画面の表示ができるスクリプトを書くことが出来ました。 これをphpスクリプト1とします。 POSTで受け取った変数を元に処理した変数を返すperlスクリプトがあります。 これをperlスクリプト1とします。 perlスクリプト1をphpスクリプトにすることは私には困難なため、phpスクリプト1のファイルに書き込む前に、perlスクリプト1を実行→返った変数をphpスクリプトで使用しファイルに書込み→終了画面の表示を行いたいです。 こんなことってできますか?

    • 締切済み
    • PHP
  • 変数の中に変数を使うには?

    いつもお世話になっております。 CSVファイルを読み込んで、 list($id,$title,$name,$note,$date) = explode(",", $value); といった形で変数に割り当て、 print <<<_EOT_ <DIV class="title">$title</DIV> <DIV class="note">$note</DIV> _EOT_; のようにレイアウトしています。 $noteの中に変数が混ざったテキストを使いたいのですが、なかなか思うように置き換わりません。 <?php echo $hensu; ?>などと試してみたりもしたのですが… ファイルから読み込んだデータの中に、変数を使う事は、可能なのでしょうか? どうぞご教示をお願いいたします。

    • ベストアンサー
    • PHP
  • OE6.0で、フォルダの容量制限はあるのでしょうか?

    OE6.0です。 テキスト形式ばかりのメールを10,000通ほど1つのフォルダに保存しておりまして、そのメールを1,000通づつ振り分けようとしたら、ディスクの容量が足りないとエラーが表示されました。 フォルダの制限を越えたのでしょうか? PCの環境は、 Windows2000 ドライブの空き容量が4MBです←これが原因??

  • perlのcgiで、変数の中身を表示させたい

    cgiで変数の中身を表示させたい perlのcgiで変数の中身を表示させたいのですが、うまくいきません ▽環境   レンタルサーバ ▽やりたいこと   通常のブラウザ画面に、変数の中身を表示させたい ▽現状   use Data::Dumper;   print Dumper($hoge));もしくは、warn Dumper $hoge;   とすると、下記エラーとなります Script Error The script did not produce proper HTTP headers. Please see the error log to see the detail of the errors. Depending on the server configuration, you can also run thisscript under CGIWrap debugging. Usually, either rename or linkthe script temporarily to a file which ends with .cgidextension, or add a AddHandler cgi-script-debug .cgiline to your .htaccess file. 指示に従い、.htaccessへ、AddHandler cgi-script-debug .cgiを追記すると、ズラズラ出てきたと何か出てきた中の一行に、変数の中身が表示されます ■質問事項   ▼変数の中身を確認する際、いちいち.htaccessへ追記するのが面倒なのですが、どうやって回避するのでしょうか?   ▼なぜ、変数の中身を確認しようとしただけで、Script Errorとなるのでしょうか?   ・書き方を間違えている?   ・書く場所を間違えている?   ・レンタルサーバの仕様?   ・perlのcgiだから? イメージしてるのは、PHPのvar_dumpなのですが…

    • ベストアンサー
    • Perl
  • 【Access2010】 改行数および文字数の制限

    下記リンクを参考に、更新前処理とキー入力時に改行数の制限をかけました。 ※テキストボックス名「申請理由」 参考リンク → http://www.accessclub.jp/bbs3/0064/superbeg24259.html ここに、さらに1行当たりの文字数を「35」(バイト数70)という制限を追加したいのですが、どうすればよろしいでしょうか?

  • アップロードの完了前に容量を取得したいのですが・・・

    Perlで簡易なアップロード掲示板を作成しています。 アップロードできるファイルの容量を制限したいのですが、アップロードデータを全てサーバ側で受け取ってからstatやlengthなどで容量オーバーかどうかを調べるのではなく、ユーザがアップロードを開始した時点で、Perl側でユーザがこれからアップロードしようとしているファイルの容量を取得する方法などはあるでしょうか? もしPerlだけでは不可能といったことであれば、代替方法の大枠でも教えていただければ幸いです。 よろしくお願い致します。

    • ベストアンサー
    • Perl
  • Perlの処理について

    Perlの処理について分からない事があります。 ご存知の方アドバイスを頂けますよう よろしくお願い致します。 (分からない処理内容) 下記処理内容で、$hensuがどういう時に &errs()をコールするのか分かりません。 アドバイスを頂けますよう よろしくお願い致します。 $hensuは、変数です。 &errs()は、個別で作成した関数です。 $Errorpathは、Errorファイル名です。 ( $hensu !~ /^( | |\\n)*$/ ) || ( &errs( 11, $Errorpath ) and exit );

    • ベストアンサー
    • Perl

専門家に質問してみよう