From: Alexey Tourbin <at@altlinux.ru> To: devel@lists.altlinux.org Subject: Re: [devel] вопрос про BDB и блокировки. Date: Fri, 27 Apr 2007 14:20:34 +0400 Message-ID: <20070427102034.GB11839@solemn.turbinal> (raw) In-Reply-To: <200704271505.10158.asy@altlinux.ru> [-- Attachment #1.1: Type: text/plain, Size: 1734 bytes --] On Fri, Apr 27, 2007 at 03:05:09PM +0500, Sergey Y. Afonin wrote: > Хочется, в данной ситации, "добить" проблему с mailfromd. В документации > http://www.oracle.com/technology/documentation/berkeley-db/db/ref/lock/intro.html > утверждается, что The Lock subsystem is created, initialized, and opened by > calls to DB_ENV->open with the DB_INIT_LOCK or DB_INIT_CDB flags specified. > То есть, что встроенные блокировки в BDB начинают работать только в случае > использования флагов DB_INIT_LOCK или DB_INIT_CDB. По некоторой причине (в DB_INIT_CDB дает "прозрачный" локинг для каждой операции. То есто операция начинается берётся блокировка. Операция заканчивает блокировка снимается. DB_INIT_LOCK по идее специально указывать не надо, если указано DB_INIT_CDB|DB_INIT_MPOOL. Там есть ещё другой режим вместо локинга, он log может писать. > эти подробноcти я не вдавался, утверждается, что не всё гладко) автор > mailfromd решил делать блокировки самостоятельно. Я, вроде как, единственный > из нарвавшихся на проблему с его блокировками. Используя метод научного тыка > и по совету человека, который кое-где bdb сам использовал, я просто убрал > блокировку (про то, что она активируется при использовании DB_INIT_LOCK или > DB_INIT_CDB, я ещё не дочитал на тот момент). Вот кусок перлового кода. Тут есть две тонкости: открывать env надо через exclusive lock, иначе там глюкало. Я это делаю через flock на дескрипторе каталога (круто!). И ещё одна тонкость что нужно сигналы обязательно блокировать на время взятия блокировки. Кажется, факт блокировки фиксируется физически в самой базе. Поэтому если по пришествии сигнала блокировку не снять, то база останется залоченной "надолго". [-- Attachment #1.2: cache.pm --] [-- Type: text/plain, Size: 4355 bytes --] package qa::cache; use strict; use BerkeleyDB; our $topdir = "$ENV{HOME}/.qa-cache"; my $topdir_fd; my $dbenv; sub init_dbenv () { use Fcntl qw(:flock O_DIRECTORY); -d $topdir or mkdir $topdir; sysopen $topdir_fd, $topdir, O_DIRECTORY or die "$topdir: $!"; if (flock $topdir_fd, LOCK_EX | LOCK_NB) { $dbenv = BerkeleyDB::Env->new(-Home => $topdir, -Verbose => 1, -ErrFile => *STDERR, -Flags => DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL) or die $BerkeleyDB::Error; # TODO: drop all locks flock $topdir_fd, LOCK_SH; } else { flock $topdir_fd, LOCK_SH; $dbenv = BerkeleyDB::Env->new(-Home => $topdir, -Verbose => 1, -ErrFile => *STDERR, -Flags => DB_JOINENV) or die $BerkeleyDB::Error; } } my %blessed; my $pagesize; sub TIEHASH ($$) { my ($class, $id) = @_; return $blessed{$id} if $blessed{$id}; init_dbenv() unless $dbenv; my $dir = "$topdir/$id"; -d $dir or mkdir $dir; my $db = BerkeleyDB::Hash->new(-Filename => "$id/cache.db", -Env => $dbenv, -Flags => DB_CREATE) or die $BerkeleyDB::Error; $pagesize ||= $db->db_stat->{hash_pagesize}; my $self = bless [ $dir, $db ] => $class; $blessed{$id} = $self; use Scalar::Util qw(weaken); weaken $blessed{$id}; return $self; } use Storable qw(freeze thaw); use Compress::LZO qw(compress decompress); use Digest::SHA1 qw(sha1); use constant { V_STO => 2**1, # STO is Special Theory of Relativity V_LZO => 2**2, # LZO is real-time compressor }; my $today = int($^T / 3600 / 24); sub STORE ($$$) { my ($self, $k, $v) = @_; $k = freeze($k) if ref $k; $k = sha1($k); my $vflags = 0; if (ref $v) { $v = freeze($v); $vflags |= V_STO; } if (length($v) > 768) { $v = compress($v); $vflags |= V_LZO; } my ($dir, $db) = @$self; if (length($v) > $pagesize / 2) { my ($subdir, $file) = unpack "H2H*", $k; $subdir = "$dir/$subdir"; $file = "$subdir/$file"; -d $subdir or mkdir $subdir; open my $fh, ">", "$file.$$" or die $!; syswrite $fh, pack("S", $vflags); syswrite $fh, $v; close $fh; rename "$file.$$", $file; } else { # SSS: mtime, atime, vflags $db->db_put($k, pack("SSS", $today, 0, $vflags) . $v); } } sub FETCH ($$) { my ($self, $k) = @_; $k = freeze($k) if ref $k; $k = sha1($k); my ($dir, $db) = @$self; my ($vflags, $v); if ($db->db_get($k, $v) == 0) { (my $m, my $a, $vflags) = unpack "SSS", $v; substr $v, 0, 6, ""; $db->db_put($k, pack("SSS", $m, $today, $vflags) . $v) if $a != $today; # XXX not atomic } else { my ($subdir, $file) = unpack "H2H*", $k; $subdir = "$dir/$subdir"; $file = "$subdir/$file"; open my $fh, "<", $file or return; local $/; $v = <$fh>; $vflags = unpack "S", $v; substr $v, 0, 2, ""; } $v = decompress($v) if $vflags & V_LZO; $v = thaw($v) if $vflags & V_STO; return $v; } sub EXISTS ($$) { my ($self, $k) = @_; $k = freeze($k) if ref($k); $k = sha1($k); my ($dir, $db) = @$self; return 1 if $db->db_get($k, my $v) == 0; my ($subdir, $file) = unpack "H2H*", $k; $subdir = "$dir/$subdir"; $file = "$subdir/$file"; return -f $file; } sub DELETE ($$) { my ($self, $k) = @_; $k = freeze($k) if ref($k); $k = sha1($k); my ($dir, $db) = @$self; $db->db_del($k); my ($subdir, $file) = unpack "H2H*", $k; $subdir = "$dir/$subdir"; $file = "$subdir/$file"; unlink $file; } # BerkeleyDB cleans up at the END, so do I my $global_destruction; # execute the END when interrupted by a signal -- # it is VERY important to release all locks and shut down gracefully use sigtrap qw(die normal-signals); our $expire = 33; sub DESTROY ($) { return if $global_destruction; my $self = shift; my ($dir, $db) = @$self; my $cur = $db->_db_write_cursor() or return; if ($db->db_get("cleanup", my $cleanup) != 0) { $db->db_put("cleanup", $today); return; } elsif ($cleanup == $today) { return; } while ($cur->c_get(my $k, my $v, DB_NEXT) == 0) { next if $k eq "cleanup"; my ($m, $a, $vflags) = unpack "SSS", $v; next if $a + 33 > $today; next if $m + 33 > $today; $cur->c_del(); } my $wanted = sub { stat or return; -f _ and -M _ > $expire and -A _ > $expire and unlink; -d _ and rmdir; }; require File::Find; File::Find::finddepth($wanted, $dir); } END { undef $dbenv; while (my ($id, $self) = each %blessed) { next unless $self; $self->DESTROY(); undef @$self; } $global_destruction = 1; } 1; [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
next prev parent reply other threads:[~2007-04-27 10:20 UTC|newest] Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top 2007-04-27 10:05 Sergey Y. Afonin 2007-04-27 10:20 ` Alexey Tourbin [this message] 2007-04-27 10:38 ` Sergey Y. Afonin 2007-04-27 11:02 ` Alexey Tourbin 2007-04-27 12:00 ` Sergey Y. Afonin 2007-04-27 12:07 ` Sergey Y. Afonin 2007-04-27 11:19 ` Alexey Tourbin 2007-04-27 11:40 ` Sergey Y. Afonin 2007-04-27 10:24 ` Sergey Y. Afonin
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20070427102034.GB11839@solemn.turbinal \ --to=at@altlinux.ru \ --cc=devel@lists.altlinux.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
ALT Linux Team development discussions This inbox may be cloned and mirrored by anyone: git clone --mirror http://lore.altlinux.org/devel/0 devel/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 devel devel/ http://lore.altlinux.org/devel \ devel@altlinux.org devel@altlinux.ru devel@lists.altlinux.org devel@lists.altlinux.ru devel@linux.iplabs.ru mandrake-russian@linuxteam.iplabs.ru sisyphus@linuxteam.iplabs.ru public-inbox-index devel Example config snippet for mirrors. Newsgroup available over NNTP: nntp://lore.altlinux.org/org.altlinux.lists.devel AGPL code for this site: git clone https://public-inbox.org/public-inbox.git