ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.432 by root, Mon May 5 22:38:47 2008 UTC vs.
Revision 1.457 by root, Wed Oct 1 05:50:19 2008 UTC

19# The authors can be reached via e-mail to <support@deliantra.net> 19# The authors can be reached via e-mail to <support@deliantra.net>
20# 20#
21 21
22package cf; 22package cf;
23 23
24use 5.10.0;
24use utf8; 25use utf8;
25use strict; 26use strict "vars", "subs";
26 27
27use Symbol; 28use Symbol;
28use List::Util; 29use List::Util;
29use Socket; 30use Socket;
30use EV 3.2; 31use EV;
31use Opcode; 32use Opcode;
32use Safe; 33use Safe;
33use Safe::Hole; 34use Safe::Hole;
34use Storable (); 35use Storable ();
35 36
36use Coro 4.50 (); 37use Coro ();
37use Coro::State; 38use Coro::State;
38use Coro::Handle; 39use Coro::Handle;
39use Coro::EV; 40use Coro::EV;
41use Coro::AnyEvent;
40use Coro::Timer; 42use Coro::Timer;
41use Coro::Signal; 43use Coro::Signal;
42use Coro::Semaphore; 44use Coro::Semaphore;
45use Coro::AnyEvent;
43use Coro::AIO; 46use Coro::AIO;
44use Coro::BDB; 47use Coro::BDB 1.6;
45use Coro::Storable; 48use Coro::Storable;
46use Coro::Util (); 49use Coro::Util ();
47 50
48use JSON::XS 2.01 (); 51use JSON::XS 2.01 ();
49use BDB (); 52use BDB ();
50use Data::Dumper; 53use Data::Dumper;
51use Digest::MD5; 54use Digest::MD5;
52use Fcntl; 55use Fcntl;
53use YAML (); 56use YAML ();
54use IO::AIO 2.51 (); 57use IO::AIO ();
55use Time::HiRes; 58use Time::HiRes;
56use Compress::LZF; 59use Compress::LZF;
57use Digest::MD5 (); 60use Digest::MD5 ();
61
62AnyEvent::detect;
58 63
59# configure various modules to our taste 64# configure various modules to our taste
60# 65#
61$Storable::canonical = 1; # reduce rsync transfers 66$Storable::canonical = 1; # reduce rsync transfers
62Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator 67Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
68
69$Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
70
71# make sure c-lzf reinitialises itself
72Compress::LZF::set_serializer "Storable", "Storable::net_mstore", "Storable::mretrieve";
63Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later 73Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
64
65$Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
66 74
67sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload 75sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
68 76
69our %COMMAND = (); 77our %COMMAND = ();
70our %COMMAND_TIME = (); 78our %COMMAND_TIME = ();
73our %EXTCMD = (); 81our %EXTCMD = ();
74our %EXTICMD = (); 82our %EXTICMD = ();
75our %EXT_CORO = (); # coroutines bound to extensions 83our %EXT_CORO = (); # coroutines bound to extensions
76our %EXT_MAP = (); # pluggable maps 84our %EXT_MAP = (); # pluggable maps
77 85
78our $RELOAD; # number of reloads so far 86our $RELOAD; # number of reloads so far, non-zero while in reload
79our @EVENT; 87our @EVENT;
80 88
81our $CONFDIR = confdir; 89our $CONFDIR = confdir;
82our $DATADIR = datadir; 90our $DATADIR = datadir;
83our $LIBDIR = "$DATADIR/ext"; 91our $LIBDIR = "$DATADIR/ext";
84our $PODDIR = "$DATADIR/pod"; 92our $PODDIR = "$DATADIR/pod";
85our $MAPDIR = "$DATADIR/" . mapdir; 93our $MAPDIR = "$DATADIR/" . mapdir;
86our $LOCALDIR = localdir; 94our $LOCALDIR = localdir;
87our $TMPDIR = "$LOCALDIR/" . tmpdir; 95our $TMPDIR = "$LOCALDIR/" . tmpdir;
88our $UNIQUEDIR = "$LOCALDIR/" . uniquedir; 96our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
89our $PLAYERDIR = "$LOCALDIR/" . playerdir; 97our $PLAYERDIR = "$LOCALDIR/" . playerdir;
90our $RANDOMDIR = "$LOCALDIR/random"; 98our $RANDOMDIR = "$LOCALDIR/random";
91our $BDBDIR = "$LOCALDIR/db"; 99our $BDBDIR = "$LOCALDIR/db";
100our $PIDFILE = "$LOCALDIR/pid";
101our $RUNTIMEFILE = "$LOCALDIR/runtime";
102
92our %RESOURCE; 103our %RESOURCE;
93 104
94our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!) 105our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
95our $AIO_POLL_WATCHER;
96our $NEXT_RUNTIME_WRITE; # when should the runtime file be written 106our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
97our $NEXT_TICK; 107our $NEXT_TICK;
98our $USE_FSYNC = 1; # use fsync to write maps - default off 108our $USE_FSYNC = 1; # use fsync to write maps - default off
99 109
100our $BDB_POLL_WATCHER;
101our $BDB_DEADLOCK_WATCHER; 110our $BDB_DEADLOCK_WATCHER;
102our $BDB_CHECKPOINT_WATCHER; 111our $BDB_CHECKPOINT_WATCHER;
103our $BDB_TRICKLE_WATCHER; 112our $BDB_TRICKLE_WATCHER;
104our $DB_ENV; 113our $DB_ENV;
105 114
119our $LOAD; # a number between 0 (idle) and 1 (too many objects) 128our $LOAD; # a number between 0 (idle) and 1 (too many objects)
120our $LOADAVG; # same thing, but with alpha-smoothing 129our $LOADAVG; # same thing, but with alpha-smoothing
121our $JITTER; # average jitter 130our $JITTER; # average jitter
122our $TICK_START; # for load detecting purposes 131our $TICK_START; # for load detecting purposes
123 132
133our @POST_INIT;
134
135our $REATTACH_ON_RELOAD; # ste to true to force object reattach on reload (slow)
136
124binmode STDOUT; 137binmode STDOUT;
125binmode STDERR; 138binmode STDERR;
126 139
127# read virtual server time, if available 140# read virtual server time, if available
128unless ($RUNTIME || !-e "$LOCALDIR/runtime") { 141unless ($RUNTIME || !-e $RUNTIMEFILE) {
129 open my $fh, "<", "$LOCALDIR/runtime" 142 open my $fh, "<", $RUNTIMEFILE
130 or die "unable to read runtime file: $!"; 143 or die "unable to read $RUNTIMEFILE file: $!";
131 $RUNTIME = <$fh> + 0.; 144 $RUNTIME = <$fh> + 0.;
132} 145}
133 146
134mkdir $_ 147mkdir $_
135 for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR; 148 for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR;
242for my $pkg (qw( 255for my $pkg (qw(
243 cf::global cf::attachable 256 cf::global cf::attachable
244 cf::object cf::object::player 257 cf::object cf::object::player
245 cf::client cf::player 258 cf::client cf::player
246 cf::arch cf::living 259 cf::arch cf::living
260 cf::map cf::mapspace
247 cf::map cf::party cf::region 261 cf::party cf::region
248)) { 262)) {
249 no strict 'refs';
250 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 263 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
251} 264}
252 265
253$EV::DIED = sub { 266$EV::DIED = sub {
254 warn "error in event callback: @_"; 267 warn "error in event callback: @_";
296our $json_coder = JSON::XS->new->utf8->max_size (1e6); # accept ~1mb max 309our $json_coder = JSON::XS->new->utf8->max_size (1e6); # accept ~1mb max
297 310
298sub encode_json($) { $json_coder->encode ($_[0]) } 311sub encode_json($) { $json_coder->encode ($_[0]) }
299sub decode_json($) { $json_coder->decode ($_[0]) } 312sub decode_json($) { $json_coder->decode ($_[0]) }
300 313
314=item cf::post_init { BLOCK }
315
316Execute the given codeblock, I<after> all extensions have been (re-)loaded,
317but I<before> the server starts ticking again.
318
319The cdoeblock will have a single boolean argument to indicate whether this
320is a reload or not.
321
322=cut
323
324sub post_init(&) {
325 push @POST_INIT, shift;
326}
327
301=item cf::lock_wait $string 328=item cf::lock_wait $string
302 329
303Wait until the given lock is available. See cf::lock_acquire. 330Wait until the given lock is available. See cf::lock_acquire.
304 331
305=item my $lock = cf::lock_acquire $string 332=item my $lock = cf::lock_acquire $string
332 return;#d# 359 return;#d#
333 }#d# 360 }#d#
334 361
335 # wait for lock, if any 362 # wait for lock, if any
336 while ($LOCK{$key}) { 363 while ($LOCK{$key}) {
364 #local $Coro::current->{desc} = "$Coro::current->{desc} <waiting for lock $key>";
337 push @{ $LOCK{$key} }, $Coro::current; 365 push @{ $LOCK{$key} }, $Coro::current;
338 Coro::schedule; 366 Coro::schedule;
339 } 367 }
340} 368}
341 369
724 752
725############################################################################# 753#############################################################################
726 754
727=head2 ATTACHABLE OBJECTS 755=head2 ATTACHABLE OBJECTS
728 756
729Many objects in crossfire are so-called attachable objects. That means you can 757Many objects in deliantra are so-called attachable objects. That means you can
730attach callbacks/event handlers (a collection of which is called an "attachment") 758attach callbacks/event handlers (a collection of which is called an "attachment")
731to it. All such attachable objects support the following methods. 759to it. All such attachable objects support the following methods.
732 760
733In the following description, CLASS can be any of C<global>, C<object> 761In the following description, CLASS can be any of C<global>, C<object>
734C<player>, C<client> or C<map> (i.e. the attachable objects in 762C<player>, C<client> or C<map> (i.e. the attachable objects in
784=item cf::CLASS::attachment $name, ... 812=item cf::CLASS::attachment $name, ...
785 813
786Register an attachment by C<$name> through which attachable objects of the 814Register an attachment by C<$name> through which attachable objects of the
787given CLASS can refer to this attachment. 815given CLASS can refer to this attachment.
788 816
789Some classes such as crossfire maps and objects can specify attachments 817Some classes such as deliantra maps and objects can specify attachments
790that are attached at load/instantiate time, thus the need for a name. 818that are attached at load/instantiate time, thus the need for a name.
791 819
792These calls expect any number of the following handler/hook descriptions: 820These calls expect any number of the following handler/hook descriptions:
793 821
794=over 4 822=over 4
1085 1113
1086sub reattach { 1114sub reattach {
1087 # basically do the same as instantiate, without calling instantiate 1115 # basically do the same as instantiate, without calling instantiate
1088 my ($obj) = @_; 1116 my ($obj) = @_;
1089 1117
1118 # no longer needed after getting rid of delete_package?
1090 bless $obj, ref $obj; # re-bless in case extensions have been reloaded 1119 #bless $obj, ref $obj; # re-bless in case extensions have been reloaded
1091 1120
1092 my $registry = $obj->registry; 1121 my $registry = $obj->registry;
1093 1122
1094 @$registry = (); 1123 @$registry = ();
1095 1124
1160 } else { 1189 } else {
1161 aio_unlink "$filename.pst"; 1190 aio_unlink "$filename.pst";
1162 } 1191 }
1163 1192
1164 aio_rename "$filename~", $filename; 1193 aio_rename "$filename~", $filename;
1194
1195 $filename =~ s%/[^/]+$%%;
1196 aio_pathsync $filename if $cf::USE_FSYNC;
1165 } else { 1197 } else {
1166 warn "FATAL: $filename~: $!\n"; 1198 warn "FATAL: $filename~: $!\n";
1167 } 1199 }
1168 } else { 1200 } else {
1169 aio_unlink $filename; 1201 aio_unlink $filename;
1262 my ($name, $cb) = @_; 1294 my ($name, $cb) = @_;
1263 1295
1264 $EXTICMD{$name} = $cb; 1296 $EXTICMD{$name} = $cb;
1265} 1297}
1266 1298
1299use File::Glob ();
1300
1267cf::player->attach ( 1301cf::player->attach (
1268 on_command => sub { 1302 on_command => sub {
1269 my ($pl, $name, $params) = @_; 1303 my ($pl, $name, $params) = @_;
1270 1304
1271 my $cb = $COMMAND{$name} 1305 my $cb = $COMMAND{$name}
1303 1337
1304 cf::override; 1338 cf::override;
1305 }, 1339 },
1306); 1340);
1307 1341
1342# "readahead" all extensions
1343sub cache_extensions {
1344 my $grp = IO::AIO::aio_group;
1345
1346 add $grp IO::AIO::aio_readdir $LIBDIR, sub {
1347 for (grep /\.ext$/, @{$_[0]}) {
1348 add $grp IO::AIO::aio_load "$LIBDIR/$_", my $data;
1349 }
1350 };
1351
1352 $grp
1353}
1354
1308sub load_extensions { 1355sub load_extensions {
1309 cf::sync_job { 1356 cf::sync_job {
1310 my %todo; 1357 my %todo;
1311 1358
1312 for my $path (<$LIBDIR/*.ext>) { 1359 for my $path (<$LIBDIR/*.ext>) {
1331 1378
1332 $ext{meta} = { map { (split /=/, $_, 2)[0, 1] } split /\s+/, $1 } 1379 $ext{meta} = { map { (split /=/, $_, 2)[0, 1] } split /\s+/, $1 }
1333 if $source =~ /\A#!.*?perl.*?#\s*(.*)$/m; 1380 if $source =~ /\A#!.*?perl.*?#\s*(.*)$/m;
1334 1381
1335 $ext{source} = 1382 $ext{source} =
1336 "package $pkg; use strict; use utf8;\n" 1383 "package $pkg; use 5.10.0; use strict 'vars', 'subs'; use utf8;\n"
1337 . "#line 1 \"$path\"\n{\n" 1384 . "#line 1 \"$path\"\n{\n"
1338 . $source 1385 . $source
1339 . "\n};\n1"; 1386 . "\n};\n1";
1340 1387
1341 $todo{$base} = \%ext; 1388 $todo{$base} = \%ext;
1381 1428
1382=back 1429=back
1383 1430
1384=head2 CORE EXTENSIONS 1431=head2 CORE EXTENSIONS
1385 1432
1386Functions and methods that extend core crossfire objects. 1433Functions and methods that extend core deliantra objects.
1387 1434
1388=cut 1435=cut
1389 1436
1390package cf::player; 1437package cf::player;
1391 1438
1434 1481
1435sub exists($) { 1482sub exists($) {
1436 my ($login) = @_; 1483 my ($login) = @_;
1437 1484
1438 $cf::PLAYER{$login} 1485 $cf::PLAYER{$login}
1439 or cf::sync_job { !aio_stat path $login } 1486 or !aio_stat path $login
1440} 1487}
1441 1488
1442sub find($) { 1489sub find($) {
1443 return $cf::PLAYER{$_[0]} || do { 1490 return $cf::PLAYER{$_[0]} || do {
1444 my $login = $_[0]; 1491 my $login = $_[0];
1519 my ($pl) = @_; 1566 my ($pl) = @_;
1520 1567
1521 my $name = $pl->ob->name; 1568 my $name = $pl->ob->name;
1522 1569
1523 $pl->{deny_save} = 1; 1570 $pl->{deny_save} = 1;
1524 $pl->password ("*"); # this should lock out the player until we nuked the dir 1571 $pl->password ("*"); # this should lock out the player until we have nuked the dir
1525 1572
1526 $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active; 1573 $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1527 $pl->deactivate; 1574 $pl->deactivate;
1528 my $killer = cf::arch::get "killer_quit"; $pl->killer ($killer); $killer->destroy; 1575 my $killer = cf::arch::get "killer_quit"; $pl->killer ($killer); $killer->destroy;
1529 $pl->ob->check_score; 1576 $pl->ob->check_score;
1615 } 1662 }
1616 1663
1617 \@paths 1664 \@paths
1618} 1665}
1619 1666
1620=item $protocol_xml = $player->expand_cfpod ($crossfire_pod) 1667=item $protocol_xml = $player->expand_cfpod ($cfpod)
1621 1668
1622Expand crossfire pod fragments into protocol xml. 1669Expand deliantra pod fragments into protocol xml.
1623
1624=cut
1625
1626use re 'eval';
1627
1628my $group;
1629my $interior; $interior = qr{
1630 # match a pod interior sequence sans C<< >>
1631 (?:
1632 \ (.*?)\ (?{ $group = $^N })
1633 | < (??{$interior}) >
1634 )
1635}x;
1636
1637sub expand_cfpod {
1638 my ($self, $pod) = @_;
1639
1640 my $xml;
1641
1642 while () {
1643 if ($pod =~ /\G( (?: [^BCGHITU]+ | .(?!<) )+ )/xgcs) {
1644 $group = $1;
1645
1646 $group =~ s/&/&amp;/g;
1647 $group =~ s/</&lt;/g;
1648
1649 $xml .= $group;
1650 } elsif ($pod =~ m%\G
1651 ([BCGHITU])
1652 <
1653 (?:
1654 ([^<>]*) (?{ $group = $^N })
1655 | < $interior >
1656 )
1657 >
1658 %gcsx
1659 ) {
1660 my ($code, $data) = ($1, $group);
1661
1662 if ($code eq "B") {
1663 $xml .= "<b>" . expand_cfpod ($self, $data) . "</b>";
1664 } elsif ($code eq "I") {
1665 $xml .= "<i>" . expand_cfpod ($self, $data) . "</i>";
1666 } elsif ($code eq "U") {
1667 $xml .= "<u>" . expand_cfpod ($self, $data) . "</u>";
1668 } elsif ($code eq "C") {
1669 $xml .= "<tt>" . expand_cfpod ($self, $data) . "</tt>";
1670 } elsif ($code eq "T") {
1671 $xml .= "<big><b>" . expand_cfpod ($self, $data) . "</b></big>";
1672 } elsif ($code eq "G") {
1673 my ($male, $female) = split /\|/, $data;
1674 $data = $self->gender ? $female : $male;
1675 $xml .= expand_cfpod ($self, $data);
1676 } elsif ($code eq "H") {
1677 $xml .= ("<fg name=\"lightblue\">[" . expand_cfpod ($self, $data) . " (Use hintmode to suppress hints)]</fg>",
1678 "<fg name=\"lightblue\">[Hint suppressed, see hintmode]</fg>",
1679 "")
1680 [$self->{hintmode}];
1681 } else {
1682 $xml .= "error processing '$code($data)' directive";
1683 }
1684 } else {
1685 if ($pod =~ /\G(.+)/) {
1686 warn "parse error while expanding $pod (at $1)";
1687 }
1688 last;
1689 }
1690 }
1691
1692 for ($xml) {
1693 # create single paragraphs (very hackish)
1694 s/(?<=\S)\n(?=\w)/ /g;
1695
1696 # compress some whitespace
1697 s/\s+\n/\n/g; # ws line-ends
1698 s/\n\n+/\n/g; # double lines
1699 s/^\n+//; # beginning lines
1700 s/\n+$//; # ending lines
1701 }
1702
1703 $xml
1704}
1705
1706no re 'eval';
1707
1708sub hintmode {
1709 $_[0]{hintmode} = $_[1] if @_ > 1;
1710 $_[0]{hintmode}
1711}
1712 1670
1713=item $player->ext_reply ($msgid, @msg) 1671=item $player->ext_reply ($msgid, @msg)
1714 1672
1715Sends an ext reply to the player. 1673Sends an ext reply to the player.
1716 1674
2085 my $f = new_from_file cf::object::thawer $self->{load_path}; 2043 my $f = new_from_file cf::object::thawer $self->{load_path};
2086 $f->skip_block; 2044 $f->skip_block;
2087 $self->_load_objects ($f) 2045 $self->_load_objects ($f)
2088 or return; 2046 or return;
2089 2047
2090 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) 2048 $self->post_load_original
2091 if delete $self->{load_original}; 2049 if delete $self->{load_original};
2092 2050
2093 if (my $uniq = $self->uniq_path) { 2051 if (my $uniq = $self->uniq_path) {
2094 utf8::encode $uniq; 2052 utf8::encode $uniq;
2095 unless (aio_stat $uniq) { 2053 unless (aio_stat $uniq) {
2530 2488
2531=item $player_object->enter_link 2489=item $player_object->enter_link
2532 2490
2533Freezes the player and moves him/her to a special map (C<{link}>). 2491Freezes the player and moves him/her to a special map (C<{link}>).
2534 2492
2535The player should be reasonably safe there for short amounts of time. You 2493The player should be reasonably safe there for short amounts of time (e.g.
2536I<MUST> call C<leave_link> as soon as possible, though. 2494for loading a map). You I<MUST> call C<leave_link> as soon as possible,
2495though, as the palyer cannot control the character while it is on the link
2496map.
2537 2497
2538Will never block. 2498Will never block.
2539 2499
2540=item $player_object->leave_link ($map, $x, $y) 2500=item $player_object->leave_link ($map, $x, $y)
2541 2501
2599 2559
2600 $map->load; 2560 $map->load;
2601 $map->load_neighbours; 2561 $map->load_neighbours;
2602 2562
2603 return unless $self->contr->active; 2563 return unless $self->contr->active;
2564 $self->flag (cf::FLAG_DEBUG, 0);#d# temp
2604 $self->activate_recursive; 2565 $self->activate_recursive;
2605 2566
2606 local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext 2567 local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2607 $self->enter_map ($map, $x, $y); 2568 $self->enter_map ($map, $x, $y);
2608} 2569}
2612Moves the player to the given map-path and coordinates by first freezing 2573Moves the player to the given map-path and coordinates by first freezing
2613her, loading and preparing them map, calling the provided $check callback 2574her, loading and preparing them map, calling the provided $check callback
2614that has to return the map if sucecssful, and then unfreezes the player on 2575that has to return the map if sucecssful, and then unfreezes the player on
2615the new (success) or old (failed) map position. In either case, $done will 2576the new (success) or old (failed) map position. In either case, $done will
2616be called at the end of this process. 2577be called at the end of this process.
2578
2579Note that $check will be called with a potentially non-loaded map, so if
2580it needs a loaded map it has to call C<< ->load >>.
2617 2581
2618=cut 2582=cut
2619 2583
2620our $GOTOGEN; 2584our $GOTOGEN;
2621 2585
2768 $self->contr->savebed ($map, $x, $y) 2732 $self->contr->savebed ($map, $x, $y)
2769 if $exit->flag (cf::FLAG_DAMNED); 2733 if $exit->flag (cf::FLAG_DAMNED);
2770 2734
2771 1 2735 1
2772 }) { 2736 }) {
2773 $self->message ("Something went wrong deep within the crossfire server. " 2737 $self->message ("Something went wrong deep within the deliantra server. "
2774 . "I'll try to bring you back to the map you were before. " 2738 . "I'll try to bring you back to the map you were before. "
2775 . "Please report this to the dungeon master!", 2739 . "Please report this to the dungeon master!",
2776 cf::NDI_UNIQUE | cf::NDI_RED); 2740 cf::NDI_UNIQUE | cf::NDI_RED);
2777 2741
2778 warn "ERROR in enter_exit: $@"; 2742 warn "ERROR in enter_exit: $@";
2844 id => "infobox", 2808 id => "infobox",
2845 title => "Body Parts", 2809 title => "Body Parts",
2846 reply => undef, 2810 reply => undef,
2847 tooltip => "Shows which body parts you posess and are available", 2811 tooltip => "Shows which body parts you posess and are available",
2848 }, 2812 },
2813 "c/skills" => {
2814 id => "infobox",
2815 title => "Skills",
2816 reply => undef,
2817 tooltip => "Shows your experience per skill and item power",
2818 },
2849 "c/uptime" => { 2819 "c/uptime" => {
2850 id => "infobox", 2820 id => "infobox",
2851 title => "Uptime", 2821 title => "Uptime",
2852 reply => undef, 2822 reply => undef,
2853 tooltip => "How long the server has been running since last restart", 2823 tooltip => "How long the server has been running since last restart",
2867); 2837);
2868 2838
2869sub cf::client::send_msg { 2839sub cf::client::send_msg {
2870 my ($self, $channel, $msg, $color, @extra) = @_; 2840 my ($self, $channel, $msg, $color, @extra) = @_;
2871 2841
2872 $msg = $self->pl->expand_cfpod ($msg); 2842 $msg = $self->pl->expand_cfpod ($msg)
2843 unless $color & cf::NDI_VERBATIM;
2873 2844
2874 $color &= cf::NDI_CLIENT_MASK; # just in case... 2845 $color &= cf::NDI_CLIENT_MASK; # just in case...
2875 2846
2876 # check predefined channels, for the benefit of C 2847 # check predefined channels, for the benefit of C
2877 if ($CHANNEL{$channel}) { 2848 if ($CHANNEL{$channel}) {
2898 if ($self->can_msg) { 2869 if ($self->can_msg) {
2899 # default colour, mask it out 2870 # default colour, mask it out
2900 $color &= ~(cf::NDI_COLOR_MASK | cf::NDI_DEF) 2871 $color &= ~(cf::NDI_COLOR_MASK | cf::NDI_DEF)
2901 if $color & cf::NDI_DEF; 2872 if $color & cf::NDI_DEF;
2902 2873
2903 $self->send_packet ("msg " . $self->{json_coder}->encode ( 2874 my $pkt = "msg "
2875 . $self->{json_coder}->encode (
2904 [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra])); 2876 [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra]
2877 );
2878
2879 # try lzf for large packets
2880 $pkt = "lzf " . Compress::LZF::compress $pkt
2881 if 1024 <= length $pkt and $self->{can_lzf};
2882
2883 # split very large packets
2884 if (8192 < length $pkt and $self->{can_lzf}) {
2885 $self->send_packet ("frag $_") for unpack "(a8192)*", $pkt;
2886 $pkt = "frag";
2887 }
2888
2889 $self->send_packet ($pkt);
2905 } else { 2890 } else {
2906 if ($color >= 0) { 2891 if ($color >= 0) {
2907 # replace some tags by gcfclient-compatible ones 2892 # replace some tags by gcfclient-compatible ones
2908 for ($msg) { 2893 for ($msg) {
2909 1 while 2894 1 while
3124=cut 3109=cut
3125 3110
3126for ( 3111for (
3127 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y 3112 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
3128 insert remove inv nrof name archname title slaying race 3113 insert remove inv nrof name archname title slaying race
3129 decrease split destroy)], 3114 decrease split destroy change_exp)],
3130 ["cf::object::player" => qw(player)], 3115 ["cf::object::player" => qw(player)],
3131 ["cf::player" => qw(peaceful)], 3116 ["cf::player" => qw(peaceful)],
3132 ["cf::map" => qw(trigger)], 3117 ["cf::map" => qw(trigger)],
3133) { 3118) {
3134 no strict 'refs'; 3119 no strict 'refs';
3392 reload_treasures; 3377 reload_treasures;
3393 3378
3394 warn "finished reloading resource files\n"; 3379 warn "finished reloading resource files\n";
3395} 3380}
3396 3381
3397sub init {
3398 my $guard = freeze_mainloop;
3399
3400 reload_resources;
3401}
3402
3403sub reload_config { 3382sub reload_config {
3404 open my $fh, "<:utf8", "$CONFDIR/config" 3383 open my $fh, "<:utf8", "$CONFDIR/config"
3405 or return; 3384 or return;
3406 3385
3407 local $/; 3386 local $/;
3419 }; 3398 };
3420 warn $@ if $@; 3399 warn $@ if $@;
3421 } 3400 }
3422} 3401}
3423 3402
3403sub pidfile() {
3404 sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT
3405 or die "$PIDFILE: $!";
3406 flock $fh, &Fcntl::LOCK_EX
3407 or die "$PIDFILE: flock: $!";
3408 $fh
3409}
3410
3411# make sure only one server instance is running at any one time
3412sub atomic {
3413 my $fh = pidfile;
3414
3415 my $pid = <$fh>;
3416 kill 9, $pid if $pid > 0;
3417
3418 seek $fh, 0, 0;
3419 print $fh $$;
3420}
3421
3424sub main { 3422sub main {
3423 cf::init_globals; # initialise logging
3424
3425 LOG llevInfo, "Welcome to Deliantra, v" . VERSION;
3426 LOG llevInfo, "Copyright (C) 2005-2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team.";
3427 LOG llevInfo, "Copyright (C) 1994 Mark Wedel.";
3428 LOG llevInfo, "Copyright (C) 1992 Frank Tore Johansen.";
3429
3430 cf::init_experience;
3431 cf::init_anim;
3432 cf::init_attackmess;
3433 cf::init_dynamic;
3434 cf::init_block;
3435
3436 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3437
3425 # we must not ever block the main coroutine 3438 # we must not ever block the main coroutine
3426 local $Coro::idle = sub { 3439 local $Coro::idle = sub {
3427 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d# 3440 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
3428 (async { 3441 (async {
3429 $Coro::current->{desc} = "IDLE BUG HANDLER"; 3442 $Coro::current->{desc} = "IDLE BUG HANDLER";
3430 EV::loop EV::LOOP_ONESHOT; 3443 EV::loop EV::LOOP_ONESHOT;
3431 })->prio (Coro::PRIO_MAX); 3444 })->prio (Coro::PRIO_MAX);
3432 }; 3445 };
3433 3446
3434 { 3447 evthread_start IO::AIO::poll_fileno;
3435 my $guard = freeze_mainloop; 3448
3449 cf::sync_job {
3450 reload_resources;
3436 reload_config; 3451 reload_config;
3437 db_init; 3452 db_init;
3453
3454 cf::load_settings;
3455 cf::load_materials;
3456 cf::init_uuid;
3457 cf::init_signals;
3458 cf::init_commands;
3459 cf::init_skills;
3460
3461 cf::init_beforeplay;
3462
3463 atomic;
3464
3438 load_extensions; 3465 load_extensions;
3439 3466
3440 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority 3467 utime time, time, $RUNTIMEFILE;
3441 evthread_start IO::AIO::poll_fileno; 3468
3469 # no (long-running) fork's whatsoever before this point(!)
3470 POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD};
3471
3472 (pop @POST_INIT)->(0) while @POST_INIT;
3442 } 3473 };
3443 3474
3444 EV::loop; 3475 EV::loop;
3445} 3476}
3446 3477
3447############################################################################# 3478#############################################################################
3456 }; 3487 };
3457 } 3488 }
3458} 3489}
3459 3490
3460sub write_runtime_sync { 3491sub write_runtime_sync {
3461 my $runtime = "$LOCALDIR/runtime";
3462
3463 # first touch the runtime file to show we are still running: 3492 # first touch the runtime file to show we are still running:
3464 # the fsync below can take a very very long time. 3493 # the fsync below can take a very very long time.
3465 3494
3466 IO::AIO::aio_utime $runtime, undef, undef; 3495 IO::AIO::aio_utime $RUNTIMEFILE, undef, undef;
3467 3496
3468 my $guard = cf::lock_acquire "write_runtime"; 3497 my $guard = cf::lock_acquire "write_runtime";
3469 3498
3470 my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644 3499 my $fh = aio_open "$RUNTIMEFILE~", O_WRONLY | O_CREAT, 0644
3471 or return; 3500 or return;
3472 3501
3473 my $value = $cf::RUNTIME + 90 + 10; 3502 my $value = $cf::RUNTIME + 90 + 10;
3474 # 10 is the runtime save interval, for a monotonic clock 3503 # 10 is the runtime save interval, for a monotonic clock
3475 # 60 allows for the watchdog to kill the server. 3504 # 60 allows for the watchdog to kill the server.
3485 aio_utime $fh, undef, undef; 3514 aio_utime $fh, undef, undef;
3486 3515
3487 close $fh 3516 close $fh
3488 or return; 3517 or return;
3489 3518
3490 aio_rename "$runtime~", $runtime 3519 aio_rename "$RUNTIMEFILE~", $RUNTIMEFILE
3491 and return; 3520 and return;
3492 3521
3493 warn "runtime file written.\n"; 3522 warn "runtime file written.\n";
3494 3523
3495 1 3524 1
3507 my $uuid = "$LOCALDIR/uuid"; 3536 my $uuid = "$LOCALDIR/uuid";
3508 3537
3509 my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644 3538 my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644
3510 or return; 3539 or return;
3511 3540
3512 my $value = uuid_str $uuid_skip + uuid_seq uuid_cur; 3541 my $value = uuid_seq uuid_cur;
3542
3543 unless ($value) {
3544 warn "cowardly refusing to write zero uuid value!\n";
3545 return;
3546 }
3547
3548 my $value = uuid_str $value + $uuid_skip;
3513 $uuid_skip = 0; 3549 $uuid_skip = 0;
3514 3550
3515 (aio_write $fh, 0, (length $value), $value, 0) <= 0 3551 (aio_write $fh, 0, (length $value), $value, 0) <= 0
3516 and return; 3552 and return;
3517 3553
3539} 3575}
3540 3576
3541sub emergency_save() { 3577sub emergency_save() {
3542 my $freeze_guard = cf::freeze_mainloop; 3578 my $freeze_guard = cf::freeze_mainloop;
3543 3579
3544 warn "enter emergency perl save\n"; 3580 warn "emergency_perl_save: enter\n";
3545 3581
3546 cf::sync_job { 3582 cf::sync_job {
3583 # this is a trade-off: we want to be very quick here, so
3584 # save all maps without fsync, and later call a global sync
3585 # (which in turn might be very very slow)
3586 local $USE_FSYNC = 0;
3587
3547 # use a peculiar iteration method to avoid tripping on perl 3588 # use a peculiar iteration method to avoid tripping on perl
3548 # refcount bugs in for. also avoids problems with players 3589 # refcount bugs in for. also avoids problems with players
3549 # and maps saved/destroyed asynchronously. 3590 # and maps saved/destroyed asynchronously.
3550 warn "begin emergency player save\n"; 3591 warn "emergency_perl_save: begin player save\n";
3551 for my $login (keys %cf::PLAYER) { 3592 for my $login (keys %cf::PLAYER) {
3552 my $pl = $cf::PLAYER{$login} or next; 3593 my $pl = $cf::PLAYER{$login} or next;
3553 $pl->valid or next; 3594 $pl->valid or next;
3554 delete $pl->{unclean_save}; # not strictly necessary, but cannot hurt 3595 delete $pl->{unclean_save}; # not strictly necessary, but cannot hurt
3555 $pl->save; 3596 $pl->save;
3556 } 3597 }
3557 warn "end emergency player save\n"; 3598 warn "emergency_perl_save: end player save\n";
3558 3599
3559 warn "begin emergency map save\n"; 3600 warn "emergency_perl_save: begin map save\n";
3560 for my $path (keys %cf::MAP) { 3601 for my $path (keys %cf::MAP) {
3561 my $map = $cf::MAP{$path} or next; 3602 my $map = $cf::MAP{$path} or next;
3562 $map->valid or next; 3603 $map->valid or next;
3563 $map->save; 3604 $map->save;
3564 } 3605 }
3565 warn "end emergency map save\n"; 3606 warn "emergency_perl_save: end map save\n";
3566 3607
3567 warn "begin emergency database checkpoint\n"; 3608 warn "emergency_perl_save: begin database checkpoint\n";
3568 BDB::db_env_txn_checkpoint $DB_ENV; 3609 BDB::db_env_txn_checkpoint $DB_ENV;
3569 warn "end emergency database checkpoint\n"; 3610 warn "emergency_perl_save: end database checkpoint\n";
3570 3611
3571 warn "begin write uuid\n"; 3612 warn "emergency_perl_save: begin write uuid\n";
3572 write_uuid_sync 1; 3613 write_uuid_sync 1;
3573 warn "end write uuid\n"; 3614 warn "emergency_perl_save: end write uuid\n";
3574 }; 3615 };
3575 3616
3617 warn "emergency_perl_save: starting sync()\n";
3618 IO::AIO::aio_sync sub {
3619 warn "emergency_perl_save: finished sync()\n";
3620 };
3621
3576 warn "leave emergency perl save\n"; 3622 warn "emergency_perl_save: leave\n";
3577} 3623}
3578 3624
3579sub post_cleanup { 3625sub post_cleanup {
3580 my ($make_core) = @_; 3626 my ($make_core) = @_;
3581 3627
3582 warn Carp::longmess "post_cleanup backtrace" 3628 warn Carp::longmess "post_cleanup backtrace"
3583 if $make_core; 3629 if $make_core;
3630
3631 my $fh = pidfile;
3632 unlink $PIDFILE if <$fh> == $$;
3633}
3634
3635# a safer delete_package, copied from Symbol
3636sub clear_package($) {
3637 my $pkg = shift;
3638
3639 # expand to full symbol table name if needed
3640 unless ($pkg =~ /^main::.*::$/) {
3641 $pkg = "main$pkg" if $pkg =~ /^::/;
3642 $pkg = "main::$pkg" unless $pkg =~ /^main::/;
3643 $pkg .= '::' unless $pkg =~ /::$/;
3644 }
3645
3646 my($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;
3647 my $stem_symtab = *{$stem}{HASH};
3648
3649 defined $stem_symtab and exists $stem_symtab->{$leaf}
3650 or return;
3651
3652 # clear all symbols
3653 my $leaf_symtab = *{$stem_symtab->{$leaf}}{HASH};
3654 for my $name (keys %$leaf_symtab) {
3655 _gv_clear *{"$pkg$name"};
3656# use PApp::Util; PApp::Util::sv_dump *{"$pkg$name"};
3657 }
3658 warn "cleared package $pkg\n";#d#
3584} 3659}
3585 3660
3586sub do_reload_perl() { 3661sub do_reload_perl() {
3587 # can/must only be called in main 3662 # can/must only be called in main
3588 if ($Coro::current != $Coro::main) { 3663 if ($Coro::current != $Coro::main) {
3589 warn "can only reload from main coroutine"; 3664 warn "can only reload from main coroutine";
3590 return; 3665 return;
3591 } 3666 }
3592 3667
3668 return if $RELOAD++;
3669
3670 my $t1 = EV::time;
3671
3672 while ($RELOAD) {
3593 warn "reloading..."; 3673 warn "reloading...";
3594 3674
3595 warn "entering sync_job"; 3675 warn "entering sync_job";
3596 3676
3597 cf::sync_job { 3677 cf::sync_job {
3598 cf::write_runtime_sync; # external watchdog should not bark 3678 cf::write_runtime_sync; # external watchdog should not bark
3599 cf::emergency_save; 3679 cf::emergency_save;
3600 cf::write_runtime_sync; # external watchdog should not bark 3680 cf::write_runtime_sync; # external watchdog should not bark
3601 3681
3602 warn "syncing database to disk"; 3682 warn "syncing database to disk";
3603 BDB::db_env_txn_checkpoint $DB_ENV; 3683 BDB::db_env_txn_checkpoint $DB_ENV;
3604 3684
3605 # if anything goes wrong in here, we should simply crash as we already saved 3685 # if anything goes wrong in here, we should simply crash as we already saved
3606 3686
3607 warn "flushing outstanding aio requests"; 3687 warn "flushing outstanding aio requests";
3608 for (;;) {
3609 BDB::flush;
3610 IO::AIO::flush;
3611 Coro::cede_notself;
3612 last unless IO::AIO::nreqs || BDB::nreqs; 3688 while (IO::AIO::nreqs || BDB::nreqs) {
3613 warn "iterate..."; 3689 Coro::EV::timer_once 0.01; # let the sync_job do it's thing
3614 }
3615
3616 ++$RELOAD;
3617
3618 warn "cancelling all extension coros";
3619 $_->cancel for values %EXT_CORO;
3620 %EXT_CORO = ();
3621
3622 warn "removing commands";
3623 %COMMAND = ();
3624
3625 warn "removing ext/exti commands";
3626 %EXTCMD = ();
3627 %EXTICMD = ();
3628
3629 warn "unloading/nuking all extensions";
3630 for my $pkg (@EXTS) {
3631 warn "... unloading $pkg";
3632
3633 if (my $cb = $pkg->can ("unload")) {
3634 eval {
3635 $cb->($pkg);
3636 1
3637 } or warn "$pkg unloaded, but with errors: $@";
3638 } 3690 }
3639 3691
3640 warn "... nuking $pkg"; 3692 warn "cancelling all extension coros";
3641 Symbol::delete_package $pkg; 3693 $_->cancel for values %EXT_CORO;
3642 } 3694 %EXT_CORO = ();
3643 3695
3644 warn "unloading all perl modules loaded from $LIBDIR"; 3696 warn "removing commands";
3645 while (my ($k, $v) = each %INC) { 3697 %COMMAND = ();
3646 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
3647 3698
3699 warn "removing ext/exti commands";
3700 %EXTCMD = ();
3701 %EXTICMD = ();
3702
3703 warn "unloading/nuking all extensions";
3704 for my $pkg (@EXTS) {
3648 warn "... unloading $k"; 3705 warn "... unloading $pkg";
3649 delete $INC{$k};
3650 3706
3651 $k =~ s/\.pm$//;
3652 $k =~ s/\//::/g;
3653
3654 if (my $cb = $k->can ("unload_module")) { 3707 if (my $cb = $pkg->can ("unload")) {
3708 eval {
3655 $cb->(); 3709 $cb->($pkg);
3710 1
3711 } or warn "$pkg unloaded, but with errors: $@";
3712 }
3713
3714 warn "... clearing $pkg";
3715 clear_package $pkg;
3656 } 3716 }
3657 3717
3658 Symbol::delete_package $k; 3718 warn "unloading all perl modules loaded from $LIBDIR";
3719 while (my ($k, $v) = each %INC) {
3720 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
3721
3722 warn "... unloading $k";
3723 delete $INC{$k};
3724
3725 $k =~ s/\.pm$//;
3726 $k =~ s/\//::/g;
3727
3728 if (my $cb = $k->can ("unload_module")) {
3729 $cb->();
3730 }
3731
3732 clear_package $k;
3659 } 3733 }
3660 3734
3661 warn "getting rid of safe::, as good as possible"; 3735 warn "getting rid of safe::, as good as possible";
3662 Symbol::delete_package "safe::$_" 3736 clear_package "safe::$_"
3663 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region); 3737 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
3664 3738
3665 warn "unloading cf.pm \"a bit\""; 3739 warn "unloading cf.pm \"a bit\"";
3666 delete $INC{"cf.pm"}; 3740 delete $INC{"cf.pm"};
3667 delete $INC{"cf/pod.pm"}; 3741 delete $INC{"cf/pod.pm"};
3668 3742
3669 # don't, removes xs symbols, too, 3743 # don't, removes xs symbols, too,
3670 # and global variables created in xs 3744 # and global variables created in xs
3671 #Symbol::delete_package __PACKAGE__; 3745 #clear_package __PACKAGE__;
3672 3746
3673 warn "unload completed, starting to reload now"; 3747 warn "unload completed, starting to reload now";
3674 3748
3675 warn "reloading cf.pm"; 3749 warn "reloading cf.pm";
3676 require cf; 3750 require cf;
3677 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt 3751 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
3678 3752
3679 warn "loading config and database again"; 3753 warn "loading config and database again";
3680 cf::reload_config; 3754 cf::reload_config;
3681 3755
3682 warn "loading extensions"; 3756 warn "loading extensions";
3683 cf::load_extensions; 3757 cf::load_extensions;
3684 3758
3759 if ($REATTACH_ON_RELOAD) {
3685 warn "reattaching attachments to objects/players"; 3760 warn "reattaching attachments to objects/players";
3686 _global_reattach; # objects, sockets 3761 _global_reattach; # objects, sockets
3687 warn "reattaching attachments to maps"; 3762 warn "reattaching attachments to maps";
3688 reattach $_ for values %MAP; 3763 reattach $_ for values %MAP;
3689 warn "reattaching attachments to players"; 3764 warn "reattaching attachments to players";
3690 reattach $_ for values %PLAYER; 3765 reattach $_ for values %PLAYER;
3766 }
3691 3767
3768 warn "running post_init jobs";
3769 (pop @POST_INIT)->(1) while @POST_INIT;
3770
3692 warn "leaving sync_job"; 3771 warn "leaving sync_job";
3693 3772
3694 1 3773 1
3695 } or do { 3774 } or do {
3696 warn $@; 3775 warn $@;
3697 cf::cleanup "error while reloading, exiting."; 3776 cf::cleanup "error while reloading, exiting.";
3698 }; 3777 };
3699 3778
3700 warn "reloaded"; 3779 warn "reloaded";
3780 --$RELOAD;
3781 }
3782
3783 $t1 = EV::time - $t1;
3784 warn "reload completed in ${t1}s\n";
3701}; 3785};
3702 3786
3703our $RELOAD_WATCHER; # used only during reload 3787our $RELOAD_WATCHER; # used only during reload
3704 3788
3705sub reload_perl() { 3789sub reload_perl() {
3706 # doing reload synchronously and two reloads happen back-to-back, 3790 # doing reload synchronously and two reloads happen back-to-back,
3707 # coro crashes during coro_state_free->destroy here. 3791 # coro crashes during coro_state_free->destroy here.
3708 3792
3793 $RELOAD_WATCHER ||= cf::async {
3794 Coro::AIO::aio_wait cache_extensions;
3795
3709 $RELOAD_WATCHER ||= EV::timer 0, 0, sub { 3796 $RELOAD_WATCHER = EV::timer $TICK * 1.5, 0, sub {
3710 do_reload_perl; 3797 do_reload_perl;
3711 undef $RELOAD_WATCHER; 3798 undef $RELOAD_WATCHER;
3799 };
3712 }; 3800 };
3713} 3801}
3714 3802
3715register_command "reload" => sub { 3803register_command "reload" => sub {
3716 my ($who, $arg) = @_; 3804 my ($who, $arg) = @_;
3787{ 3875{
3788 # configure BDB 3876 # configure BDB
3789 3877
3790 BDB::min_parallel 8; 3878 BDB::min_parallel 8;
3791 BDB::max_poll_reqs $TICK * 0.1; 3879 BDB::max_poll_reqs $TICK * 0.1;
3792 $Coro::BDB::WATCHER->priority (1); 3880 $AnyEvent::BDB::WATCHER->priority (1);
3793 3881
3794 unless ($DB_ENV) { 3882 unless ($DB_ENV) {
3795 $DB_ENV = BDB::db_env_create; 3883 $DB_ENV = BDB::db_env_create;
3796 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC 3884 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT);
3797 | BDB::LOG_AUTOREMOVE, 1); 3885 $DB_ENV->set_flags (&BDB::LOG_AUTOREMOVE ) if BDB::VERSION v0, v4.7;
3886 $DB_ENV->log_set_config (&BDB::LOG_AUTO_REMOVE) if BDB::VERSION v4.7;
3798 $DB_ENV->set_timeout (30, BDB::SET_TXN_TIMEOUT); 3887 $DB_ENV->set_timeout (30, BDB::SET_TXN_TIMEOUT);
3799 $DB_ENV->set_timeout (30, BDB::SET_LOCK_TIMEOUT); 3888 $DB_ENV->set_timeout (30, BDB::SET_LOCK_TIMEOUT);
3800 3889
3801 cf::sync_job { 3890 cf::sync_job {
3802 eval { 3891 eval {
3828{ 3917{
3829 # configure IO::AIO 3918 # configure IO::AIO
3830 3919
3831 IO::AIO::min_parallel 8; 3920 IO::AIO::min_parallel 8;
3832 IO::AIO::max_poll_time $TICK * 0.1; 3921 IO::AIO::max_poll_time $TICK * 0.1;
3833 $Coro::AIO::WATCHER->priority (1); 3922 undef $AnyEvent::AIO::WATCHER;
3834} 3923}
3835 3924
3836my $_log_backtrace; 3925my $_log_backtrace;
3837 3926
3838sub _log_backtrace { 3927sub _log_backtrace {
3841 $msg =~ s/\n//; 3930 $msg =~ s/\n//;
3842 3931
3843 # limit the # of concurrent backtraces 3932 # limit the # of concurrent backtraces
3844 if ($_log_backtrace < 2) { 3933 if ($_log_backtrace < 2) {
3845 ++$_log_backtrace; 3934 ++$_log_backtrace;
3935 my $perl_bt = Carp::longmess $msg;
3846 async { 3936 async {
3847 $Coro::current->{desc} = "abt $msg"; 3937 $Coro::current->{desc} = "abt $msg";
3848 3938
3849 my @bt = fork_call { 3939 my @bt = fork_call {
3850 @addr = map { sprintf "%x", $_ } @addr; 3940 @addr = map { sprintf "%x", $_ } @addr;
3861 } 3951 }
3862 3952
3863 @funcs 3953 @funcs
3864 }; 3954 };
3865 3955
3866 LOG llevInfo, "[ABT] $msg\n"; 3956 LOG llevInfo, "[ABT] $perl_bt\n";
3957 LOG llevInfo, "[ABT] --- C backtrace follows ---\n";
3867 LOG llevInfo, "[ABT] $_\n" for @bt; 3958 LOG llevInfo, "[ABT] $_\n" for @bt;
3868 --$_log_backtrace; 3959 --$_log_backtrace;
3869 }; 3960 };
3870 } else { 3961 } else {
3871 LOG llevInfo, "[ABT] $msg\n"; 3962 LOG llevInfo, "[ABT] $msg\n";

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines