2011年12月6日星期二

[PerlChina] 2011 CN Perl Advent Day 6: BerkeleyDB

http://perlchina.github.com/advent.perlchina.org/2011/BerkeleyDB.html 

=for advent_year 2011

=for advent_day 6

=for advent_title BerkeleyDB

=for advent_author Fayland Lam

M<BerkeleyDB> 是个高性能的数据库。

当您需要操作一个极其巨大的文件,需要构造一个 super big 的 hash 或者 array 的时候,内存可能就是您最大的烦恼所在。而 BerkeleyDB 可以通过硬盘空间来保存该 hash 或者 array,到时候可以快速定位和 sort 之类,来完成您的需求。

BerkeleyDB 的详细介绍和设计可以参阅 A<http://www.aosabook.org/en/bdb.html|The Architecture of Open Source Applications> 的章节。

在 Ubuntu 之类的系统下可以通过 $ sudo apt-get install libberkeleydb-perl 来安装,FreeBSD 可以到 /usr/ports/databases/p5-BerkeleyDB 来 make install, Win32 下不支持,其它的可以 Google 得到安装指南。

在单线程的情况下,一个简单的例子如下:

=begin code

use FindBin qw/$Bin/;
use BerkeleyDB;

my $berkeleydb_temp_file = "$Bin/tmp.berkeleydb"; # temp file for BerkeleyDB
tie my %data, 'BerkeleyDB::Hash',
    -Filename => $berkeleydb_temp_file,
    -Flags    => DB_CREATE|DB_TRUNCATE
        or die "Cannot create file: $! $BerkeleyDB::Error\n";
open(my $fh, '<', 'RealBigFile.log') or die "Can't open: $!";
while (my $line = <$fh>) {
    ## some code that %data will be a real very big hash
    ## we just need the first line and the last line which matches the $pattern
    my $pattern = get_pattern($line);
    if (exists $data{"start_$pattern"}) {
        $data{"end_$pattern"} = $line;
    } else {
        $data{"start_$pattern"} = $line;
    }
}
close($fh);
# now working on the %data

=end code

你可以不停的 ls -ls 来查看 tmp.berkeleydb 的大小,顺便 monitor 下内存。

BerkeleyDB 对多线程的支持也很不错,支持数千并发线程,最大 256TB 数据。在多线程的情况下,需要使用 BerkeleyDB::Env cds_lock 保证数据安全。简单的例子如下:

=begin code

my $env = new BerkeleyDB::Env
    -Home   => $tmp_dir,
    -Flags  => DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL
        or die "cannot open environment: $BerkeleyDB::Error\n";
my $db = tie my %data, 'BerkeleyDB::Hash',
    -Filename => $berkeleydb_temp_file,
    -Flags    => DB_CREATE,
    -Env      => $env
        or die "Cannot create file: $! $BerkeleyDB::Error\n";

my $pm = new Parallel::ForkManager(4);
foreach my $i (1 .. 1000) {
    $pm->start and next; # do the fork
    
    my $lock = $db->cds_lock();
    $data{$i} = $i * 2;
    $db->db_sync();
    $lock->cds_unlock();
    
    $pm->finish; # Terminates the child process
}

$pm->wait_all_children;

=end code

更多的使用方法请参阅 perldoc M<BerkeleyDB>。

谢谢。


--
Fayland Lam // http://www.fayland.org/

--
您收到此邮件是因为您订阅了 Google 网上论坛的“PerlChina Mongers 讨论组”论坛。
要向此网上论坛发帖,请发送电子邮件至 perlchina@googlegroups.com。
要取消订阅此网上论坛,请发送电子邮件至 perlchina+unsubscribe@googlegroups.com。
若有更多问题,请通过 http://groups.google.com/group/perlchina?hl=zh-CN 访问此网上论坛。

没有评论: