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.415 by root, Thu Apr 10 15:35:16 2008 UTC vs.
Revision 1.424 by root, Sun Apr 20 05:24:55 2008 UTC

427 } 427 }
428 } 428 }
429}; 429};
430 430
431sub get_slot($;$$) { 431sub get_slot($;$$) {
432 return if tick_inhibit || $Coro::current == $Coro::main;
433
432 my ($time, $pri, $name) = @_; 434 my ($time, $pri, $name) = @_;
433 435
434 $time = $TICK * .6 if $time > $TICK * .6; 436 $time = $TICK * .6 if $time > $TICK * .6;
435 my $sig = new Coro::Signal; 437 my $sig = new Coro::Signal;
436 438
1473 1475
1474 return if $pl->{deny_save}; 1476 return if $pl->{deny_save};
1475 1477
1476 aio_mkdir playerdir $pl, 0770; 1478 aio_mkdir playerdir $pl, 0770;
1477 $pl->{last_save} = $cf::RUNTIME; 1479 $pl->{last_save} = $cf::RUNTIME;
1480
1481 cf::get_slot 0.01;
1478 1482
1479 $pl->save_pl ($path); 1483 $pl->save_pl ($path);
1480 cf::cede_to_tick; 1484 cf::cede_to_tick;
1481} 1485}
1482 1486
1775our $MAX_RESET = 3600; 1779our $MAX_RESET = 3600;
1776our $DEFAULT_RESET = 3000; 1780our $DEFAULT_RESET = 3000;
1777 1781
1778sub generate_random_map { 1782sub generate_random_map {
1779 my ($self, $rmp) = @_; 1783 my ($self, $rmp) = @_;
1784
1785 my $lock = cf::lock_acquire "generate_random_map"; # the random map generator is NOT reentrant ATM
1786
1780 # mit "rum" bekleckern, nicht 1787 # mit "rum" bekleckern, nicht
1781 $self->_create_random_map ( 1788 $self->_create_random_map (
1782 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle}, 1789 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1783 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle}, 1790 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1784 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map}, 1791 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1906 1913
1907# the temporary/swap location 1914# the temporary/swap location
1908sub save_path { 1915sub save_path {
1909 my ($self) = @_; 1916 my ($self) = @_;
1910 1917
1911 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g; 1918 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1912 "$TMPDIR/$path.map" 1919 "$TMPDIR/$path.map"
1913} 1920}
1914 1921
1915# the unique path, undef == no special unique path 1922# the unique path, undef == no special unique path
1916sub uniq_path { 1923sub uniq_path {
1917 my ($self) = @_; 1924 my ($self) = @_;
1918 1925
1919 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g; 1926 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1920 "$UNIQUEDIR/$path" 1927 "$UNIQUEDIR/$path"
1921} 1928}
1922 1929
1923# and all this just because we cannot iterate over 1930# and all this just because we cannot iterate over
1924# all maps in C++... 1931# all maps in C++...
2110 } 2117 }
2111 2118
2112 $self->{last_save} = $cf::RUNTIME; 2119 $self->{last_save} = $cf::RUNTIME;
2113 $self->last_access ($cf::RUNTIME); 2120 $self->last_access ($cf::RUNTIME);
2114 2121
2115 $self->in_memory (cf::MAP_IN_MEMORY); 2122 $self->in_memory (cf::MAP_ACTIVE);
2116 } 2123 }
2117 2124
2118 $self->post_load; 2125 $self->post_load;
2119} 2126}
2120 2127
2178 my ($path, $origin, $load) = @_; 2185 my ($path, $origin, $load) = @_;
2179 2186
2180 $path = normalise $path, $origin && $origin->{path}; 2187 $path = normalise $path, $origin && $origin->{path};
2181 2188
2182 if (my $map = $cf::MAP{$path}) { 2189 if (my $map = $cf::MAP{$path}) {
2183 return $map if !$load || $map->in_memory == cf::MAP_IN_MEMORY; 2190 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE;
2184 } 2191 }
2185 2192
2186 $MAP_PREFETCH{$path} |= $load; 2193 $MAP_PREFETCH{$path} |= $load;
2187 2194
2188 $MAP_PREFETCHER ||= cf::async { 2195 $MAP_PREFETCHER ||= cf::async {
2225 cf::async { 2232 cf::async {
2226 $Coro::current->{desc} = "map player save"; 2233 $Coro::current->{desc} = "map player save";
2227 $_->contr->save for $self->players; 2234 $_->contr->save for $self->players;
2228 }; 2235 };
2229 2236
2237 cf::get_slot 0.02;
2238
2230 if ($uniq) { 2239 if ($uniq) {
2231 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS); 2240 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
2232 $self->_save_objects ($uniq, cf::IO_UNIQUES); 2241 $self->_save_objects ($uniq, cf::IO_UNIQUES);
2233 } else { 2242 } else {
2234 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES); 2243 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
2242 $self->save; 2251 $self->save;
2243 2252
2244 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2253 my $lock = cf::lock_acquire "map_data:$self->{path}";
2245 2254
2246 return if $self->players; 2255 return if $self->players;
2247 return if $self->in_memory != cf::MAP_IN_MEMORY; 2256 return if $self->in_memory != cf::MAP_ACTIVE;
2248 return if $self->{deny_save}; 2257 return if $self->{deny_save};
2249 2258
2250 $self->in_memory (cf::MAP_SWAPPED); 2259 $self->in_memory (cf::MAP_SWAPPED);
2251 2260
2252 $self->deactivate; 2261 $self->deactivate;
2370 2379
2371sub unique_maps() { 2380sub unique_maps() {
2372 [ 2381 [
2373 map { 2382 map {
2374 utf8::decode $_; 2383 utf8::decode $_;
2375 /\.map$/ 2384 s/\.map$//; # TODO future compatibility hack
2385 /\.pst$/ || !/^$PATH_SEP/o # TODO unique maps apparebntly lack the .map suffix :/
2386 ? ()
2376 ? normalise $_ 2387 : normalise $_
2377 : ()
2378 } @{ aio_readdir $UNIQUEDIR or [] } 2388 } @{ aio_readdir $UNIQUEDIR or [] }
2379 ] 2389 ]
2380} 2390}
2381 2391
2382=back 2392=back
2389 2399
2390=over 4 2400=over 4
2391 2401
2392=item $ob->inv_recursive 2402=item $ob->inv_recursive
2393 2403
2394Returns the inventory of the object _and_ their inventories, recursively. 2404Returns the inventory of the object I<and> their inventories, recursively,
2405but I<not> the object itself.
2395 2406
2396=cut 2407=cut
2397 2408
2398sub inv_recursive_; 2409sub inv_recursive_;
2399sub inv_recursive_ { 2410sub inv_recursive_ {
2404 inv_recursive_ inv $_[0] 2415 inv_recursive_ inv $_[0]
2405} 2416}
2406 2417
2407=item $ref = $ob->ref 2418=item $ref = $ob->ref
2408 2419
2409creates and returns a persistent reference to an objetc that can be stored as a string. 2420Creates and returns a persistent reference to an object that can be stored as a string.
2410 2421
2411=item $ob = cf::object::deref ($refstring) 2422=item $ob = cf::object::deref ($refstring)
2412 2423
2413returns the objetc referenced by refstring. may return undef when it cnanot find the object, 2424returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2414even if the object actually exists. May block. 2425even if the object actually exists. May block.
2688 $rmp->{origin_y} = $exit->y; 2699 $rmp->{origin_y} = $exit->y;
2689 } 2700 }
2690 2701
2691 $rmp->{random_seed} ||= $exit->random_seed; 2702 $rmp->{random_seed} ||= $exit->random_seed;
2692 2703
2693 my $data = cf::encode_json $rmp; 2704 my $data = JSON::XS->new->utf8->pretty->canonical->encode ($rmp);
2694 my $md5 = Digest::MD5::md5_hex $data; 2705 my $md5 = Digest::MD5::md5_hex $data;
2695 my $meta = "$RANDOMDIR/$md5.meta"; 2706 my $meta = "$RANDOMDIR/$md5.meta";
2696 2707
2697 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) { 2708 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2698 aio_write $fh, 0, (length $data), $data, 0; 2709 aio_write $fh, 0, (length $data), $data, 0;
3301 while (my ($k, $v) = each %$want) { 3312 while (my ($k, $v) = each %$want) {
3302 $ns->fx_want ($k, $v); 3313 $ns->fx_want ($k, $v);
3303 } 3314 }
3304}; 3315};
3305 3316
3317sub load_resource_file($) {
3318 my $guard = lock_acquire "load_resource_file";
3319
3320 my $status = load_resource_file_ $_[0];
3321 get_slot 0.1, 100;
3322 cf::arch::commit_load;
3323
3324 $status
3325}
3326
3306sub reload_regions { 3327sub reload_regions {
3307 # HACK to clear player env face cache, we need some signal framework 3328 # HACK to clear player env face cache, we need some signal framework
3308 # for this (global event?) 3329 # for this (global event?)
3309 %ext::player_env::MUSIC_FACE_CACHE = (); 3330 %ext::player_env::MUSIC_FACE_CACHE = ();
3310 3331
3323} 3344}
3324 3345
3325sub reload_archetypes { 3346sub reload_archetypes {
3326 load_resource_file "$DATADIR/archetypes" 3347 load_resource_file "$DATADIR/archetypes"
3327 or die "unable to load archetypes\n"; 3348 or die "unable to load archetypes\n";
3328 #d# NEED to laod twice to resolve forward references
3329 # this really needs to be done in an extra post-pass
3330 # (which needs to be synchronous, so solve it differently)
3331 load_resource_file "$DATADIR/archetypes"
3332 or die "unable to load archetypes\n";
3333} 3349}
3334 3350
3335sub reload_treasures { 3351sub reload_treasures {
3336 load_resource_file "$DATADIR/treasures" 3352 load_resource_file "$DATADIR/treasures"
3337 or die "unable to load treasurelists\n"; 3353 or die "unable to load treasurelists\n";
3338} 3354}
3339 3355
3340sub reload_resources { 3356sub reload_resources {
3341 warn "reloading resource files...\n"; 3357 warn "reloading resource files...\n";
3342 3358
3359 reload_facedata;
3360 reload_archetypes;
3343 reload_regions; 3361 reload_regions;
3344 reload_facedata;
3345 #reload_archetypes;#d#
3346 reload_archetypes;
3347 reload_treasures; 3362 reload_treasures;
3348 3363
3349 warn "finished reloading resource files\n"; 3364 warn "finished reloading resource files\n";
3350} 3365}
3351 3366
3352sub init { 3367sub init {
3368 my $guard = freeze_mainloop;
3369
3353 reload_resources; 3370 reload_resources;
3354} 3371}
3355 3372
3356sub reload_config { 3373sub reload_config {
3357 open my $fh, "<:utf8", "$CONFDIR/config" 3374 open my $fh, "<:utf8", "$CONFDIR/config"
3382 $Coro::current->{desc} = "IDLE BUG HANDLER"; 3399 $Coro::current->{desc} = "IDLE BUG HANDLER";
3383 EV::loop EV::LOOP_ONESHOT; 3400 EV::loop EV::LOOP_ONESHOT;
3384 })->prio (Coro::PRIO_MAX); 3401 })->prio (Coro::PRIO_MAX);
3385 }; 3402 };
3386 3403
3404 {
3405 my $guard = freeze_mainloop;
3387 reload_config; 3406 reload_config;
3388 db_init; 3407 db_init;
3389 load_extensions; 3408 load_extensions;
3390 3409
3391 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority 3410 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3392 evthread_start IO::AIO::poll_fileno; 3411 evthread_start IO::AIO::poll_fileno;
3412 }
3413
3393 EV::loop; 3414 EV::loop;
3394} 3415}
3395 3416
3396############################################################################# 3417#############################################################################
3397# initialisation and cleanup 3418# initialisation and cleanup
3404 cf::cleanup "SIG$signal"; 3425 cf::cleanup "SIG$signal";
3405 }; 3426 };
3406 } 3427 }
3407} 3428}
3408 3429
3409sub write_runtime { 3430sub write_runtime_sync {
3410 my $runtime = "$LOCALDIR/runtime"; 3431 my $runtime = "$LOCALDIR/runtime";
3411 3432
3412 # first touch the runtime file to show we are still running: 3433 # first touch the runtime file to show we are still running:
3413 # the fsync below can take a very very long time. 3434 # the fsync below can take a very very long time.
3414 3435
3440 and return; 3461 and return;
3441 3462
3442 warn "runtime file written.\n"; 3463 warn "runtime file written.\n";
3443 3464
3444 1 3465 1
3466}
3467
3468our $uuid_lock;
3469our $uuid_skip;
3470
3471sub write_uuid_sync($) {
3472 $uuid_skip ||= $_[0];
3473
3474 return if $uuid_lock;
3475 local $uuid_lock = 1;
3476
3477 my $uuid = "$LOCALDIR/uuid";
3478
3479 my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644
3480 or return;
3481
3482 my $value = uuid_str $uuid_skip + uuid_seq uuid_cur;
3483 $uuid_skip = 0;
3484
3485 (aio_write $fh, 0, (length $value), $value, 0) <= 0
3486 and return;
3487
3488 # always fsync - this file is important
3489 aio_fsync $fh
3490 and return;
3491
3492 close $fh
3493 or return;
3494
3495 aio_rename "$uuid~", $uuid
3496 and return;
3497
3498 warn "uuid file written ($value).\n";
3499
3500 1
3501
3502}
3503
3504sub write_uuid($$) {
3505 my ($skip, $sync) = @_;
3506
3507 $sync ? write_uuid_sync $skip
3508 : async { write_uuid_sync $skip };
3445} 3509}
3446 3510
3447sub emergency_save() { 3511sub emergency_save() {
3448 my $freeze_guard = cf::freeze_mainloop; 3512 my $freeze_guard = cf::freeze_mainloop;
3449 3513
3471 warn "end emergency map save\n"; 3535 warn "end emergency map save\n";
3472 3536
3473 warn "begin emergency database checkpoint\n"; 3537 warn "begin emergency database checkpoint\n";
3474 BDB::db_env_txn_checkpoint $DB_ENV; 3538 BDB::db_env_txn_checkpoint $DB_ENV;
3475 warn "end emergency database checkpoint\n"; 3539 warn "end emergency database checkpoint\n";
3540
3541 warn "begin write uuid\n";
3542 write_uuid_sync 1;
3543 warn "end write uuid\n";
3476 }; 3544 };
3477 3545
3478 warn "leave emergency perl save\n"; 3546 warn "leave emergency perl save\n";
3479} 3547}
3480 3548
3495 warn "reloading..."; 3563 warn "reloading...";
3496 3564
3497 warn "entering sync_job"; 3565 warn "entering sync_job";
3498 3566
3499 cf::sync_job { 3567 cf::sync_job {
3500 cf::write_runtime; # external watchdog should not bark 3568 cf::write_runtime_sync; # external watchdog should not bark
3501 cf::emergency_save; 3569 cf::emergency_save;
3502 cf::write_runtime; # external watchdog should not bark 3570 cf::write_runtime_sync; # external watchdog should not bark
3503 3571
3504 warn "syncing database to disk"; 3572 warn "syncing database to disk";
3505 BDB::db_env_txn_checkpoint $DB_ENV; 3573 BDB::db_env_txn_checkpoint $DB_ENV;
3506 3574
3507 # if anything goes wrong in here, we should simply crash as we already saved 3575 # if anything goes wrong in here, we should simply crash as we already saved
3632 3700
3633our @WAIT_FOR_TICK; 3701our @WAIT_FOR_TICK;
3634our @WAIT_FOR_TICK_BEGIN; 3702our @WAIT_FOR_TICK_BEGIN;
3635 3703
3636sub wait_for_tick { 3704sub wait_for_tick {
3637 return if tick_inhibit;
3638 return if $Coro::current == $Coro::main; 3705 return if tick_inhibit || $Coro::current == $Coro::main;
3639 3706
3640 my $signal = new Coro::Signal; 3707 my $signal = new Coro::Signal;
3641 push @WAIT_FOR_TICK, $signal; 3708 push @WAIT_FOR_TICK, $signal;
3642 $signal->wait; 3709 $signal->wait;
3643} 3710}
3644 3711
3645sub wait_for_tick_begin { 3712sub wait_for_tick_begin {
3646 return if tick_inhibit;
3647 return if $Coro::current == $Coro::main; 3713 return if tick_inhibit || $Coro::current == $Coro::main;
3648 3714
3649 my $signal = new Coro::Signal; 3715 my $signal = new Coro::Signal;
3650 push @WAIT_FOR_TICK_BEGIN, $signal; 3716 push @WAIT_FOR_TICK_BEGIN, $signal;
3651 $signal->wait; 3717 $signal->wait;
3652} 3718}
3662 3728
3663 if ($NOW >= $NEXT_RUNTIME_WRITE) { 3729 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3664 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 3730 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
3665 Coro::async_pool { 3731 Coro::async_pool {
3666 $Coro::current->{desc} = "runtime saver"; 3732 $Coro::current->{desc} = "runtime saver";
3667 write_runtime 3733 write_runtime_sync
3668 or warn "ERROR: unable to write runtime file: $!"; 3734 or warn "ERROR: unable to write runtime file: $!";
3669 }; 3735 };
3670 } 3736 }
3671 3737
3672 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 3738 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines