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.423 by root, Sun Apr 20 00:44:13 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 $status = load_resource_file_ $_[0];
3319 get_slot 0.1, 100;
3320 cf::arch::commit_load;
3321 $status
3322}
3323
3306sub reload_regions { 3324sub reload_regions {
3307 # HACK to clear player env face cache, we need some signal framework 3325 # HACK to clear player env face cache, we need some signal framework
3308 # for this (global event?) 3326 # for this (global event?)
3309 %ext::player_env::MUSIC_FACE_CACHE = (); 3327 %ext::player_env::MUSIC_FACE_CACHE = ();
3310 3328
3323} 3341}
3324 3342
3325sub reload_archetypes { 3343sub reload_archetypes {
3326 load_resource_file "$DATADIR/archetypes" 3344 load_resource_file "$DATADIR/archetypes"
3327 or die "unable to load archetypes\n"; 3345 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} 3346}
3334 3347
3335sub reload_treasures { 3348sub reload_treasures {
3336 load_resource_file "$DATADIR/treasures" 3349 load_resource_file "$DATADIR/treasures"
3337 or die "unable to load treasurelists\n"; 3350 or die "unable to load treasurelists\n";
3338} 3351}
3339 3352
3340sub reload_resources { 3353sub reload_resources {
3341 warn "reloading resource files...\n"; 3354 warn "reloading resource files...\n";
3342 3355
3356 reload_facedata;
3357 reload_archetypes;
3343 reload_regions; 3358 reload_regions;
3344 reload_facedata;
3345 #reload_archetypes;#d#
3346 reload_archetypes;
3347 reload_treasures; 3359 reload_treasures;
3348 3360
3349 warn "finished reloading resource files\n"; 3361 warn "finished reloading resource files\n";
3350} 3362}
3351 3363
3352sub init { 3364sub init {
3365 my $guard = freeze_mainloop;
3366
3353 reload_resources; 3367 reload_resources;
3354} 3368}
3355 3369
3356sub reload_config { 3370sub reload_config {
3357 open my $fh, "<:utf8", "$CONFDIR/config" 3371 open my $fh, "<:utf8", "$CONFDIR/config"
3382 $Coro::current->{desc} = "IDLE BUG HANDLER"; 3396 $Coro::current->{desc} = "IDLE BUG HANDLER";
3383 EV::loop EV::LOOP_ONESHOT; 3397 EV::loop EV::LOOP_ONESHOT;
3384 })->prio (Coro::PRIO_MAX); 3398 })->prio (Coro::PRIO_MAX);
3385 }; 3399 };
3386 3400
3401 {
3402 my $guard = freeze_mainloop;
3387 reload_config; 3403 reload_config;
3388 db_init; 3404 db_init;
3389 load_extensions; 3405 load_extensions;
3390 3406
3391 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority 3407 $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3392 evthread_start IO::AIO::poll_fileno; 3408 evthread_start IO::AIO::poll_fileno;
3409 }
3410
3393 EV::loop; 3411 EV::loop;
3394} 3412}
3395 3413
3396############################################################################# 3414#############################################################################
3397# initialisation and cleanup 3415# initialisation and cleanup
3404 cf::cleanup "SIG$signal"; 3422 cf::cleanup "SIG$signal";
3405 }; 3423 };
3406 } 3424 }
3407} 3425}
3408 3426
3409sub write_runtime { 3427sub write_runtime_sync {
3410 my $runtime = "$LOCALDIR/runtime"; 3428 my $runtime = "$LOCALDIR/runtime";
3411 3429
3412 # first touch the runtime file to show we are still running: 3430 # first touch the runtime file to show we are still running:
3413 # the fsync below can take a very very long time. 3431 # the fsync below can take a very very long time.
3414 3432
3440 and return; 3458 and return;
3441 3459
3442 warn "runtime file written.\n"; 3460 warn "runtime file written.\n";
3443 3461
3444 1 3462 1
3463}
3464
3465our $uuid_lock;
3466our $uuid_skip;
3467
3468sub write_uuid_sync($) {
3469 $uuid_skip ||= $_[0];
3470
3471 return if $uuid_lock;
3472 local $uuid_lock = 1;
3473
3474 my $uuid = "$LOCALDIR/uuid";
3475
3476 my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644
3477 or return;
3478
3479 my $value = uuid_str $uuid_skip + uuid_seq uuid_cur;
3480 $uuid_skip = 0;
3481
3482 (aio_write $fh, 0, (length $value), $value, 0) <= 0
3483 and return;
3484
3485 # always fsync - this file is important
3486 aio_fsync $fh
3487 and return;
3488
3489 close $fh
3490 or return;
3491
3492 aio_rename "$uuid~", $uuid
3493 and return;
3494
3495 warn "uuid file written ($value).\n";
3496
3497 1
3498
3499}
3500
3501sub write_uuid($$) {
3502 my ($skip, $sync) = @_;
3503
3504 $sync ? write_uuid_sync $skip
3505 : async { write_uuid_sync $skip };
3445} 3506}
3446 3507
3447sub emergency_save() { 3508sub emergency_save() {
3448 my $freeze_guard = cf::freeze_mainloop; 3509 my $freeze_guard = cf::freeze_mainloop;
3449 3510
3471 warn "end emergency map save\n"; 3532 warn "end emergency map save\n";
3472 3533
3473 warn "begin emergency database checkpoint\n"; 3534 warn "begin emergency database checkpoint\n";
3474 BDB::db_env_txn_checkpoint $DB_ENV; 3535 BDB::db_env_txn_checkpoint $DB_ENV;
3475 warn "end emergency database checkpoint\n"; 3536 warn "end emergency database checkpoint\n";
3537
3538 warn "begin write uuid\n";
3539 write_uuid_sync 1;
3540 warn "end write uuid\n";
3476 }; 3541 };
3477 3542
3478 warn "leave emergency perl save\n"; 3543 warn "leave emergency perl save\n";
3479} 3544}
3480 3545
3495 warn "reloading..."; 3560 warn "reloading...";
3496 3561
3497 warn "entering sync_job"; 3562 warn "entering sync_job";
3498 3563
3499 cf::sync_job { 3564 cf::sync_job {
3500 cf::write_runtime; # external watchdog should not bark 3565 cf::write_runtime_sync; # external watchdog should not bark
3501 cf::emergency_save; 3566 cf::emergency_save;
3502 cf::write_runtime; # external watchdog should not bark 3567 cf::write_runtime_sync; # external watchdog should not bark
3503 3568
3504 warn "syncing database to disk"; 3569 warn "syncing database to disk";
3505 BDB::db_env_txn_checkpoint $DB_ENV; 3570 BDB::db_env_txn_checkpoint $DB_ENV;
3506 3571
3507 # if anything goes wrong in here, we should simply crash as we already saved 3572 # if anything goes wrong in here, we should simply crash as we already saved
3632 3697
3633our @WAIT_FOR_TICK; 3698our @WAIT_FOR_TICK;
3634our @WAIT_FOR_TICK_BEGIN; 3699our @WAIT_FOR_TICK_BEGIN;
3635 3700
3636sub wait_for_tick { 3701sub wait_for_tick {
3637 return if tick_inhibit;
3638 return if $Coro::current == $Coro::main; 3702 return if tick_inhibit || $Coro::current == $Coro::main;
3639 3703
3640 my $signal = new Coro::Signal; 3704 my $signal = new Coro::Signal;
3641 push @WAIT_FOR_TICK, $signal; 3705 push @WAIT_FOR_TICK, $signal;
3642 $signal->wait; 3706 $signal->wait;
3643} 3707}
3644 3708
3645sub wait_for_tick_begin { 3709sub wait_for_tick_begin {
3646 return if tick_inhibit;
3647 return if $Coro::current == $Coro::main; 3710 return if tick_inhibit || $Coro::current == $Coro::main;
3648 3711
3649 my $signal = new Coro::Signal; 3712 my $signal = new Coro::Signal;
3650 push @WAIT_FOR_TICK_BEGIN, $signal; 3713 push @WAIT_FOR_TICK_BEGIN, $signal;
3651 $signal->wait; 3714 $signal->wait;
3652} 3715}
3662 3725
3663 if ($NOW >= $NEXT_RUNTIME_WRITE) { 3726 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3664 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 3727 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
3665 Coro::async_pool { 3728 Coro::async_pool {
3666 $Coro::current->{desc} = "runtime saver"; 3729 $Coro::current->{desc} = "runtime saver";
3667 write_runtime 3730 write_runtime_sync
3668 or warn "ERROR: unable to write runtime file: $!"; 3731 or warn "ERROR: unable to write runtime file: $!";
3669 }; 3732 };
3670 } 3733 }
3671 3734
3672 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 3735 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines