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.411 by root, Fri Feb 1 15:54:07 2008 UTC vs.
Revision 1.415 by root, Thu Apr 10 15:35:16 2008 UTC

1#
2# This file is part of Deliantra, the Roguelike Realtime MMORPG.
3#
4# Copyright (©) 2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5#
6# Deliantra is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# The authors can be reached via e-mail to <support@deliantra.net>
20#
21
1package cf; 22package cf;
2 23
3use utf8; 24use utf8;
4use strict; 25use strict;
5 26
6use Symbol; 27use Symbol;
7use List::Util; 28use List::Util;
8use Socket; 29use Socket;
9use EV 1.86; 30use EV 3.2;
10use Opcode; 31use Opcode;
11use Safe; 32use Safe;
12use Safe::Hole; 33use Safe::Hole;
13use Storable (); 34use Storable ();
14 35
15use Coro 4.32 (); 36use Coro 4.50 ();
16use Coro::State; 37use Coro::State;
17use Coro::Handle; 38use Coro::Handle;
18use Coro::EV; 39use Coro::EV;
19use Coro::Timer; 40use Coro::Timer;
20use Coro::Signal; 41use Coro::Signal;
69our $RANDOMDIR = "$LOCALDIR/random"; 90our $RANDOMDIR = "$LOCALDIR/random";
70our $BDBDIR = "$LOCALDIR/db"; 91our $BDBDIR = "$LOCALDIR/db";
71our %RESOURCE; 92our %RESOURCE;
72 93
73our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!) 94our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
74our $TICK_WATCHER;
75our $AIO_POLL_WATCHER; 95our $AIO_POLL_WATCHER;
76our $NEXT_RUNTIME_WRITE; # when should the runtime file be written 96our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
77our $NEXT_TICK; 97our $NEXT_TICK;
78our $USE_FSYNC = 1; # use fsync to write maps - default off 98our $USE_FSYNC = 1; # use fsync to write maps - default off
79 99
96# used to convert map paths into valid unix filenames by replacing / by ∕ 116# used to convert map paths into valid unix filenames by replacing / by ∕
97our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons 117our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
98 118
99our $LOAD; # a number between 0 (idle) and 1 (too many objects) 119our $LOAD; # a number between 0 (idle) and 1 (too many objects)
100our $LOADAVG; # same thing, but with alpha-smoothing 120our $LOADAVG; # same thing, but with alpha-smoothing
121our $JITTER; # average jitter
101our $tick_start; # for load detecting purposes 122our $TICK_START; # for load detecting purposes
102 123
103binmode STDOUT; 124binmode STDOUT;
104binmode STDERR; 125binmode STDERR;
105 126
106# read virtual server time, if available 127# read virtual server time, if available
339 360
340 ! ! $LOCK{$key} 361 ! ! $LOCK{$key}
341} 362}
342 363
343sub freeze_mainloop { 364sub freeze_mainloop {
344 return unless $TICK_WATCHER->is_active; 365 tick_inhibit_inc;
345 366
346 my $guard = Coro::guard { 367 Coro::guard \&tick_inhibit_dec;
347 $TICK_WATCHER->start;
348 };
349 $TICK_WATCHER->stop;
350 $guard
351} 368}
352 369
353=item cf::periodic $interval, $cb 370=item cf::periodic $interval, $cb
354 371
355Like EV::periodic, but randomly selects a starting point so that the actions 372Like EV::periodic, but randomly selects a starting point so that the actions
456 # this is the main coro, too bad, we have to block 473 # this is the main coro, too bad, we have to block
457 # till the operation succeeds, freezing the server :/ 474 # till the operation succeeds, freezing the server :/
458 475
459 LOG llevError, Carp::longmess "sync job";#d# 476 LOG llevError, Carp::longmess "sync job";#d#
460 477
461 # TODO: use suspend/resume instead
462 # (but this is cancel-safe)
463 my $freeze_guard = freeze_mainloop; 478 my $freeze_guard = freeze_mainloop;
464 479
465 my $busy = 1; 480 my $busy = 1;
466 my @res; 481 my @res;
467 482
478 } else { 493 } else {
479 EV::loop EV::LOOP_ONESHOT; 494 EV::loop EV::LOOP_ONESHOT;
480 } 495 }
481 } 496 }
482 497
483 $time = EV::time - $time; 498 my $time = EV::time - $time;
484 499
485 LOG llevError | logBacktrace, Carp::longmess "long sync job"
486 if $time > $TICK * 0.5 && $TICK_WATCHER->is_active;
487
488 $tick_start += $time; # do not account sync jobs to server load 500 $TICK_START += $time; # do not account sync jobs to server load
489 501
490 wantarray ? @res : $res[0] 502 wantarray ? @res : $res[0]
491 } else { 503 } else {
492 # we are in another coroutine, how wonderful, everything just works 504 # we are in another coroutine, how wonderful, everything just works
493 505
535 reset_signals; 547 reset_signals;
536 &$cb 548 &$cb
537 }, @args; 549 }, @args;
538 550
539 wantarray ? @res : $res[-1] 551 wantarray ? @res : $res[-1]
552}
553
554=item $coin = coin_from_name $name
555
556=cut
557
558our %coin_alias = (
559 "silver" => "silvercoin",
560 "silvercoin" => "silvercoin",
561 "silvercoins" => "silvercoin",
562 "gold" => "goldcoin",
563 "goldcoin" => "goldcoin",
564 "goldcoins" => "goldcoin",
565 "platinum" => "platinacoin",
566 "platinumcoin" => "platinacoin",
567 "platinumcoins" => "platinacoin",
568 "platina" => "platinacoin",
569 "platinacoin" => "platinacoin",
570 "platinacoins" => "platinacoin",
571 "royalty" => "royalty",
572 "royalties" => "royalty",
573);
574
575sub coin_from_name($) {
576 $coin_alias{$_[0]}
577 ? cf::arch::find $coin_alias{$_[0]}
578 : undef
540} 579}
541 580
542=item $value = cf::db_get $family => $key 581=item $value = cf::db_get $family => $key
543 582
544Returns a single value from the environment database. 583Returns a single value from the environment database.
2337 ? normalise $_ 2376 ? normalise $_
2338 : () 2377 : ()
2339 } @{ aio_readdir $UNIQUEDIR or [] } 2378 } @{ aio_readdir $UNIQUEDIR or [] }
2340 ] 2379 ]
2341} 2380}
2342
2343package cf;
2344 2381
2345=back 2382=back
2346 2383
2347=head3 cf::object 2384=head3 cf::object
2348 2385
3349 3386
3350 reload_config; 3387 reload_config;
3351 db_init; 3388 db_init;
3352 load_extensions; 3389 load_extensions;
3353 3390
3354 $TICK_WATCHER->start;
3355 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority 3391 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3392 evthread_start IO::AIO::poll_fileno;
3356 EV::loop; 3393 EV::loop;
3357} 3394}
3358 3395
3359############################################################################# 3396#############################################################################
3360# initialisation and cleanup 3397# initialisation and cleanup
3595 3632
3596our @WAIT_FOR_TICK; 3633our @WAIT_FOR_TICK;
3597our @WAIT_FOR_TICK_BEGIN; 3634our @WAIT_FOR_TICK_BEGIN;
3598 3635
3599sub wait_for_tick { 3636sub wait_for_tick {
3600 return unless $TICK_WATCHER->is_active; 3637 return if tick_inhibit;
3601 return if $Coro::current == $Coro::main; 3638 return if $Coro::current == $Coro::main;
3602 3639
3603 my $signal = new Coro::Signal; 3640 my $signal = new Coro::Signal;
3604 push @WAIT_FOR_TICK, $signal; 3641 push @WAIT_FOR_TICK, $signal;
3605 $signal->wait; 3642 $signal->wait;
3606} 3643}
3607 3644
3608sub wait_for_tick_begin { 3645sub wait_for_tick_begin {
3609 return unless $TICK_WATCHER->is_active; 3646 return if tick_inhibit;
3610 return if $Coro::current == $Coro::main; 3647 return if $Coro::current == $Coro::main;
3611 3648
3612 my $signal = new Coro::Signal; 3649 my $signal = new Coro::Signal;
3613 push @WAIT_FOR_TICK_BEGIN, $signal; 3650 push @WAIT_FOR_TICK_BEGIN, $signal;
3614 $signal->wait; 3651 $signal->wait;
3615} 3652}
3616 3653
3617$TICK_WATCHER = EV::periodic_ns 0, $TICK, 0, sub { 3654sub tick {
3618 if ($Coro::current != $Coro::main) { 3655 if ($Coro::current != $Coro::main) {
3619 Carp::cluck "major BUG: server tick called outside of main coro, skipping it" 3656 Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
3620 unless ++$bug_warning > 10; 3657 unless ++$bug_warning > 10;
3621 return; 3658 return;
3622 } 3659 }
3623 3660
3624 $NOW = $tick_start = EV::now;
3625
3626 cf::server_tick; # one server iteration 3661 cf::server_tick; # one server iteration
3627
3628 $RUNTIME += $TICK;
3629 $NEXT_TICK = $_[0]->at;
3630 3662
3631 if ($NOW >= $NEXT_RUNTIME_WRITE) { 3663 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3632 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 3664 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
3633 Coro::async_pool { 3665 Coro::async_pool {
3634 $Coro::current->{desc} = "runtime saver"; 3666 $Coro::current->{desc} = "runtime saver";
3642 } 3674 }
3643 while (my $sig = shift @WAIT_FOR_TICK) { 3675 while (my $sig = shift @WAIT_FOR_TICK) {
3644 $sig->send; 3676 $sig->send;
3645 } 3677 }
3646 3678
3647 $LOAD = ($NOW - $tick_start) / $TICK; 3679 $LOAD = ($NOW - $TICK_START) / $TICK;
3648 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25; 3680 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
3649 3681
3650 _post_tick; 3682 if (0) {
3651}; 3683 if ($NEXT_TICK) {
3652$TICK_WATCHER->priority (EV::MAXPRI); 3684 my $jitter = $TICK_START - $NEXT_TICK;
3685 $JITTER = $JITTER * 0.75 + $jitter * 0.25;
3686 warn "jitter $JITTER\n";#d#
3687 }
3688 }
3689}
3653 3690
3654{ 3691{
3655 # configure BDB 3692 # configure BDB
3656 3693
3657 BDB::min_parallel 8; 3694 BDB::min_parallel 8;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines