--- deliantra/Deliantra-Client/DC/DB.pm 2008/03/30 04:59:42 1.34 +++ deliantra/Deliantra-Client/DC/DB.pm 2008/12/24 04:09:27 1.41 @@ -17,6 +17,7 @@ use strict; use utf8; +use File::Path (); use Carp (); use Storable (); use Config; @@ -24,18 +25,23 @@ use DC; -our $ODBDIR = "cfplus-" . BDB::VERSION . "-$Config{archname}"; -our $DBDIR = "client-" . BDB::VERSION . "-$Config{archname}"; +our $ODBDIR = "cfplus-" . BDB::VERSION_MAJOR . "." . BDB::VERSION_MINOR . "-$Config{archname}"; +our $DBDIR = "client-" . BDB::VERSION_MAJOR . "." . BDB::VERSION_MINOR . "-$Config{archname}"; our $DB_HOME = "$Deliantra::VARDIR/$DBDIR"; -if (!-e $DB_HOME and -e "$Deliantra::VARDIR/$ODBDIR") { - rename "$Deliantra::VARDIR/$ODBDIR", $DB_HOME; - print STDERR "INFO: moved old database from $Deliantra::VARDIR/$ODBDIR to $DB_HOME\n"; -} +sub FIRST_TILE_ID () { 64 } -if (!-e $DB_HOME and -e "$Deliantra::OLDDIR/$ODBDIR") { - rename "$Deliantra::OLDDIR/$DBDIR", $DB_HOME; - print STDERR "INFO: moved old database from $Deliantra::OLDDIR/$ODBDIR to $DB_HOME\n"; +unless (-d $DB_HOME) { + if (-d "$Deliantra::VARDIR/$ODBDIR") { + rename "$Deliantra::VARDIR/$ODBDIR", $DB_HOME; + print STDERR "INFO: moved old database from $Deliantra::VARDIR/$ODBDIR to $DB_HOME\n"; + } elsif (-d "$Deliantra::OLDDIR/$ODBDIR") { + rename "$Deliantra::OLDDIR/$DBDIR", $DB_HOME; + print STDERR "INFO: moved old database from $Deliantra::OLDDIR/$ODBDIR to $DB_HOME\n"; + } else { + File::Path::mkpath [$DB_HOME] + or die "unable to create database directory $DB_HOME: $!"; + } } BDB::max_poll_time 0.03; @@ -44,25 +50,34 @@ our $DB_ENV; our $DB_STATE; our %DB_TABLE; +our $TILE_SEQ; sub try_open_db { - mkdir $DB_HOME, 0777; + File::Path::mkpath [$DB_HOME]; + + my $env = db_env_create; + + $env->set_errfile (\*STDERR); + $env->set_msgfile (\*STDERR); + $env->set_verbose (-1, 1); - $DB_ENV = db_env_create; + $env->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT); + $env->set_flags (&BDB::LOG_AUTOREMOVE ) if BDB::VERSION v0, v4.7; + $env->log_set_config (&BDB::LOG_AUTO_REMOVE) if BDB::VERSION v4.7; - $DB_ENV->set_errfile (\*STDERR); - $DB_ENV->set_msgfile (\*STDERR); - $DB_ENV->set_verbose (-1, 1); + $env->set_timeout (3, BDB::SET_TXN_TIMEOUT); + $env->set_timeout (3, BDB::SET_LOCK_TIMEOUT); - $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::LOG_AUTOREMOVE | BDB::TXN_WRITE_NOSYNC); - $DB_ENV->set_cachesize (0, 2048 * 1024, 0); + $env->set_cachesize (0, 2048 * 1024, 0); - db_env_open $DB_ENV, $DB_HOME, + db_env_open $env, $DB_HOME, BDB::CREATE | BDB::REGISTER | BDB::RECOVER | BDB::INIT_MPOOL | BDB::INIT_LOCK | BDB::INIT_TXN, 0666; $! and die "cannot open database environment $DB_HOME: " . BDB::strerror; + $DB_ENV = $env; + 1 } @@ -72,6 +87,9 @@ $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge; + $DB_ENV#d# + or return ::clienterror ("trying to create table $_[0] with empty db_env $DB_ENV" => 1);#d# + my $db = db_create $DB_ENV; $db->set_flags (BDB::CHKSUM); @@ -110,7 +128,6 @@ sub put($$$$) { my ($db, $key, $data, $cb) = @_; - warn "put $key ",(length $data),"\n";#d# db_put table $db, undef, $key, $data, 0, sub { $cb->($!); @@ -141,30 +158,24 @@ my $table = table "facemap"; my $id; - db_get $table, undef, $name, $id, 0; + db_get $table, undef, $name => $id, 0; $! or return $cb->($id); - for (1..100) { - my $txn = $DB_ENV->txn_begin; - db_get $table, $txn, id => $id, 0; - - $id = 64 if $id < 64; - - ++$id; - - db_put $table, $txn, id => $id, 0; - db_txn_finish $txn; + unless ($TILE_SEQ) { + $TILE_SEQ = $table->sequence; + $TILE_SEQ->initial_value (FIRST_TILE_ID); + $TILE_SEQ->set_cachesize (0); + db_sequence_open $TILE_SEQ, undef, "id", BDB::CREATE; + } - unless ($!) { - db_put $table, undef, $name => $id; - $SYNC->again unless $SYNC->is_active; - return $cb->($id); - } + db_sequence_get $TILE_SEQ, undef, 1, my $id; - select undef, undef, undef, 0.01 * rand; - } + die "unable to allocate tile id: $!" + if $!; + + db_put $table, undef, $name => $id, 0; + $cb->($id); - die "maximum number of transaction retries reached - database problems?"; } sub get_tile_id_sync($) { @@ -405,10 +416,15 @@ package DC::DB; +sub nuke_db { + File::Path::mkpath [$DB_HOME]; + eval { File::Path::rmtree $DB_HOME }; +} + sub open_db { unless (eval { try_open_db }) { warn "$@";#d# - eval { File::Path::rmtree $DB_HOME }; + eval { nuke_db }; try_open_db; } @@ -427,13 +443,16 @@ $WATCHER = EV::io BDB::poll_fileno, EV::READ, \&BDB::poll_cb; $SYNC = EV::timer_ns 0, 60, sub { - warn "SYNC\n";#d# $_[0]->stop; db_env_txn_checkpoint $DB_ENV, 0, 0, 0, sub { }; }; } END { + db_env_txn_checkpoint $DB_ENV, 0, 0, 0 + if $DB_ENV; + + undef $TILE_SEQ; %DB_TABLE = (); undef $DB_ENV; }