アーカイブ
Tyzohブログ - ikarashiさんのエントリ
 ikarashiさんのエントリ配信

2007/07/26
[Secure-SBM:027] データベースのバックアップ

執筆者: ikarashi (12:54 pm)
こんにちは,五十嵐です.サービスを閉塞した後にデータベースのバックアップを行えるようにします.今のところ Linux/PostgreSQL のみ対応しています.

sub makebackup : Local {
        my ( $self, $c ) = @_;

        $_ = $c->config->{'Model::SecureSBMDB'}->{connect_info}[0];
        my ( $dbi, $dbd, $dbparams ) = split( ':' );
        my ( @dbparams ) = split( ';', $dbparams );
        my %dbparams;
        foreach my $d (@dbparams){
                my ( $name, $data ) = split( '=', $d );
                $dbparams{$name} = $data;
        }

        my $dbname = (defined $dbparams{dbname})?$dbparams{dbname}:'';

        my $dbuser = $c->config->{'Model::SecureSBMDB'}->{connect_info}[1];
        my $dbpwd = $c->config->{'Model::SecureSBMDB'}->{connect_info}[2];
初期設定の config から dbname などを切り出します.connect_info 配列の 0 番目は dbname など,1 番目はデータベースのユーザ名,2 番目はパスワードになります.

        if( $dbd eq 'Pg' ){
                my $dbhostopt = (defined $dbparams{host})?
"-h $dbparams{host}":'';
                my $dbportopt = (defined $dbparams{port})?
"-p $dbparams{port}":'';
                my $dbfileopt = "-f $backuppath";

                system( "pg_dump -U $dbuser -F t $dbhostopt $dbportopt 
$dbfileopt $dbname" );
                my ( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 
                      $atime, $mtime, $ctime, $blksize, $blocks ) 
                        = stat($backuppath);
                my ( $sec, $min, $hour, $mday, $mon, 
                      $year, $wday, $yday, $isdst ) 
                        = localtime($mtime);
                my $filestat 
                        = sprintf( '%s <br />owner:%s group:%s size:%s 
                          <br />mtime: %4d/%02d/%02d %02d:%02d:%02d',
                            $backupfilename, $uid, $gid, $size,
                            $year + 1900, $mon + 1, $mday, $hour, $min, $sec
                        );
                $c->stash->{backupfileinfo} = $filestat;
                $c->stash->{backupfilename} = $backupfilename;
        }else{
                # Not implimented
                $c->stash->{resultmessage} = 'Not implimented yet';
        }
        $c->forward('index');

} # end of makebackup()
dbname が "Pg" かどうかを判断していますが,PostgreSQL の場合に "Pg" を設定していますので,この場合にのみ "pg_dump" を利用してバックアップファイルを作成します.他のデータベースの場合には対応していません.それから,このままだと Windows でも動きません.これは今後の課題.

ファイルを作成したら,ダウンロードできるようにします.
sub getbackup : Local {
        my ( $self, $c, $bfname ) = @_;

        if( $bfname ne $backupfilename ){
                $c->forward('index');
                return 0;
        }

        my $backupfilepath = $backupdir . '/' . $bfname;
        my ( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 
$atime, $mtime, $ctime, $blksize, $blocks ) = stat($backupfilepath);

        my $bfcontents = '';

        if( open( BFH, $backupfilepath ) ){
                my $rsize = 1;
                while( $rsize && $size > 0){
                        my $tmp;
                        $rsize = read( BFH, $tmp, $size );
                        $bfcontents .= $tmp;
                        $size -= $rsize;
                }
                close( BFH );
        }

        $c->res->headers->header(
                'Content-Type' => 'application/x-tar;'
                        . 'name="' . $bfname . '";' );

        $c->res->body( $bfcontents );
        $c->forward('index');

} # end of getbackup()
ファイルを読み込んで, body に格納するだけです.ポイントは HTML ヘッダで "Content-Type" を設定することです.

2007/07/14 記

参考:

Keyword: Perl Catalyst Secure-SBM SSBM セキュア・ソーシャル・ブックマーク オープンソース
ikarashiさんのブログを読む | コメント (2) | トラックバック数 (0) | 閲覧数 (5038)
Trackback is not accepted now.
印刷用ページ 友達に送る
 
投稿された内容の著作権はコメントの投稿者に帰属します。

投稿者 スレッド
watanabe
投稿日時: 2007-7-26 16:46  更新日時: 2007-7-26 16:49
管理人
登録日: 2004-12-28
居住地:
投稿数: 116
 Re: [Secure-SBM:027] データベースのバックアップ
私も今直面していますが、Webアプリケーションでこの手の時間がかかりそうな処理をする場合、ユーザビリティの観点で何らかの対応をさせたいですよね。

Ajaxを使ってこまめにポーリングをするんでしょうね。
そうした場合、裏で走っている時間のかかる処理はどうやってやらせればいいのでしょう?

直感的には Catalyst のプロセスから切り離して、そのプロセスへのハンドルを付加して、すぐに結果を返すことになると思いますが、上記の場合は、pg_dump を system 関数で呼んでいますね。system に渡すコマンド名に & を付けてあがればいいのでしょうかね。そのときに起動したプロセスの実行状況をモニタする方法が必要ですね。

いろいろ大変そうです...


あと、
  while( $rsize && $size > 0){
my $tmp;
$rsize = read( BFH, $tmp, $size );
$bfcontents .= $tmp;
}
:
$c->res->body( $bfcontents );


とするより、

  while( $rsize && $size > 0){
:
$c->write( $tmp );
}


のほうがよいのではないでしょうか。もちろんヘッダは先に設定しておきます。

参考
http://www.catalystframework.org/calendar/2006/15
http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Streaming/lib/Streaming.pm
返信

投稿者 スレッド
ikarashi
投稿日時: 2007-7-27 10:05  更新日時: 2007-7-27 17:24
熟練者
登録日: 2004-12-30
居住地: さいたま市
投稿数: 792
 Re: [Secure-SBM:027] データベースのバックアップ
そうですね,今回はかなり手抜きでやっつけてしまいました.

ちゃんとやるなら,fork させて子プロセスを監視,Ajax でポーリングとなるでしょう.ところで,Perl で意識的に thread を生成する方法をご存じないですか?

ループの件は,Controller で出力の際に Content-Length がわからないといけないと思ってループの外に出したのですが,View に渡る前にサイズは決定されるのですね.

それならば,watanabe さんが指摘したやり方の方がいいかもしれません.しかし,$c->write() で書き出したサイズが気になるので,そこでもループさせなければならないですね.コード上ではループでもおそらく一回の書き込みで済みそうですけれども.提示いただいたサンプルだとなにもチェックしていないようですけれど...

ストリーミングと同様の手順でよいのか,ここは少し試験してみて,コードの改良を検討してみます.どうもありがとうございます.
返信
サイト内検索
ブログ カレンダー
«  «  2008 3月  »  »
24 25 26 27 28 29 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5