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.596 by root, Fri Nov 9 20:37:57 2012 UTC vs.
Revision 1.600 by root, Sun Nov 11 04:31:57 2012 UTC

58use BDB (); 58use BDB ();
59use Data::Dumper; 59use Data::Dumper;
60use Fcntl; 60use Fcntl;
61use YAML::XS (); 61use YAML::XS ();
62use IO::AIO (); 62use IO::AIO ();
63use Time::HiRes;
64use Compress::LZF; 63use Compress::LZF;
65use Digest::MD5 (); 64use Digest::MD5 ();
66 65
67AnyEvent::detect; 66AnyEvent::detect;
68 67
252Configuration for the server, loaded from C</etc/deliantra-server/config>, or 251Configuration for the server, loaded from C</etc/deliantra-server/config>, or
253from wherever your confdir points to. 252from wherever your confdir points to.
254 253
255=item cf::wait_for_tick, cf::wait_for_tick_begin 254=item cf::wait_for_tick, cf::wait_for_tick_begin
256 255
257These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only 256These are functions that inhibit the current coroutine one tick.
258returns directly I<after> the tick processing (and consequently, can only wake one thread 257cf::wait_for_tick_begin only returns directly I<after> the tick
258processing (and consequently, can only wake one thread per tick), while
259per tick), while cf::wait_for_tick wakes up all waiters after tick processing. 259cf::wait_for_tick wakes up all waiters after tick processing.
260 260
261Note that cf::Wait_for_tick will immediately return when the server is not 261Note that cf::wait_for_tick will immediately return when the server is not
262ticking, making it suitable for small pauses in threads that need to run 262ticking, making it suitable for small pauses in threads that need to run
263when the server is paused. If that is not applicable (i.e. you I<really> 263when the server is paused. If that is not applicable (i.e. you I<really>
264want to wait, use C<$cf::WAIT_FOR_TICK>). 264want to wait, use C<$cf::WAIT_FOR_TICK>).
265 265
266=item $cf::WAIT_FOR_TICK 266=item $cf::WAIT_FOR_TICK
901 901
902 return db_get cache => "$id/data"; 902 return db_get cache => "$id/data";
903 } 903 }
904 } 904 }
905 905
906 my $t1 = Time::HiRes::time; 906 my $t1 = EV::time;
907 my $data = $process->(\@data); 907 my $data = $process->(\@data);
908 my $t2 = Time::HiRes::time; 908 my $t2 = EV::time;
909 909
910 info "cache: '$id' processed in ", $t2 - $t1, "s\n"; 910 info "cache: '$id' processed in ", $t2 - $t1, "s\n";
911 911
912 db_put cache => "$id/data", $data; 912 db_put cache => "$id/data", $data;
913 db_put cache => "$id/md5" , $md5; 913 db_put cache => "$id/md5" , $md5;
3520 3520
3521############################################################################# 3521#############################################################################
3522# the server's init and main functions 3522# the server's init and main functions
3523 3523
3524our %FACEHASH; # hash => idx, #d# HACK for http server 3524our %FACEHASH; # hash => idx, #d# HACK for http server
3525our @FACEDATA; # dynamically-created facedata
3525 3526
3526# internal api, not fianlised 3527# internal api, not fianlised
3527sub set_face { 3528sub set_face {
3528 my ($name, $type, $data) = @_; 3529 my ($name, $type, $data) = @_;
3529 3530
3536 } 3537 }
3537 3538
3538 my $hash = cf::face::mangle_chksum Digest::MD5::md5 $data; 3539 my $hash = cf::face::mangle_chksum Digest::MD5::md5 $data;
3539 3540
3540 cf::face::set_type $idx, $type; 3541 cf::face::set_type $idx, $type;
3541 cf::face::set_data $idx, 0, $data, $hash; 3542 cf::face::set_data $idx, 0, (length $data), 0, $hash;
3542 cf::face::set_meta $idx, $type & 1 ? undef : undef; 3543 cf::face::set_meta $idx, $type & 1 ? undef : undef;
3544
3545 # we need to destroy the SV itself, not just overwrite,
3546 # as a running ix might hold a reference to it.
3547 # delete achieves that.
3548 delete $FACEDATA[$idx];
3549 $FACEDATA[$idx] = $data;
3543 $FACEHASH{$hash} = $idx;#d# 3550 $FACEHASH{$hash} = $idx;#d#
3544 3551
3545 $idx 3552 $idx
3553}
3554
3555our $FACEDATA; # facedata filehandle
3556
3557sub _face_get_data($$$$) {
3558 my ($idx, $size, $fofs, $cb) = @_;
3559
3560 if (defined $FACEDATA[$idx]) {
3561 $cb->($FACEDATA[$idx]);
3562 } elsif ($fofs) {
3563 my $buf;
3564 IO::AIO::aio_read $FACEDATA, $fofs, $size, $buf, 0, sub {
3565 if ($_[0] == $size) {
3566 #cf::debug "read face $idx, $size from $fofs as ", length $buf;#d#
3567 $cb->($buf);
3568 } else {
3569 cf::error "INTERNAL ERROR: unable to read facedata for face $idx ($size, $fofs), ignoring request.";
3570 }
3571 };
3572 } else {
3573 cf::error "requested facedata for unknown face $idx ($size, $fofs), ignoring.";
3574 }
3575}
3576
3577# rather ineffient
3578sub cf::face::get_data($;$) {
3579 my ($idx, $faceset) = @_;
3580
3581 my $size = cf::face::get_size $idx, $faceset;
3582 my $fofs = cf::face::get_fofs $idx, $faceset;
3583
3584 _face_get_data $idx, $size, $fofs, Coro::rouse_cb;
3585 Coro::rouse_wait
3586}
3587
3588sub cf::face::ix {
3589 my ($ns, $idx, $pri, $size, $fofs) = @_;
3590
3591 _face_get_data $idx, $size, $fofs, sub {
3592 $ns->ix_send ($idx, $pri, $_[0]);
3593 };
3546} 3594}
3547 3595
3548sub load_facedata($) { 3596sub load_facedata($) {
3549 my ($path) = @_; 3597 my ($path) = @_;
3550 3598
3551 # HACK to clear player env face cache, we need some signal framework
3552 # for this (global event?)
3553 %ext::player_env::MUSIC_FACE_CACHE = ();
3554
3555 my $enc = JSON::XS->new->utf8->canonical->relaxed; 3599 my $enc = JSON::XS->new->utf8->canonical->relaxed;
3556 3600
3557 trace "loading facedata from $path\n"; 3601 trace "loading facedata from $path\n";
3558 3602
3559 my $facedata = decode_storable load_file $path; 3603 my $facedata = decode_storable load_file "$path/faceinfo";
3560 3604
3561 $facedata->{version} == 2 3605 $facedata->{version} == 2
3562 or cf::cleanup "$path: version mismatch, cannot proceed."; 3606 or cf::cleanup "$path/faceinfo: version mismatch, cannot proceed.";
3563 3607
3564 cf::cede_to_tick; 3608 my $fh = aio_open "$DATADIR/facedata", IO::AIO::O_RDONLY, 0
3609 or cf::cleanup "$path/facedata: $!, cnanot proceed.";
3610
3611 get_slot 1, -100, "load_facedata"; # make sure we get a very big slot
3612
3613 # BEGIN ATOMIC
3614 # from here on, everything must be atomic - no thread switch allowed
3615 my $t1 = EV::time;
3565 3616
3566 { 3617 {
3567 my $faces = $facedata->{faceinfo}; 3618 my $faces = $facedata->{faceinfo};
3568 3619
3569 for my $face (sort keys %$faces) { 3620 for my $face (sort keys %$faces) {
3570 my $info = $faces->{$face}; 3621 my $info = $faces->{$face};
3571 my $idx = (cf::face::find $face) || cf::face::alloc $face; 3622 my $idx = (cf::face::find $face) || cf::face::alloc $face;
3572 3623
3573 cf::face::set_visibility $idx, $info->{visibility}; 3624 cf::face::set_visibility $idx, $info->{visibility};
3574 cf::face::set_magicmap $idx, $info->{magicmap}; 3625 cf::face::set_magicmap $idx, $info->{magicmap};
3575 cf::face::set_data $idx, 0, $info->{data32}, $info->{hash32}; 3626 cf::face::set_data $idx, 0, $info->{size32}, $info->{fofs32}, $info->{hash32};
3576 cf::face::set_data $idx, 1, $info->{data64}, $info->{hash64}; 3627 cf::face::set_data $idx, 1, $info->{size64}, $info->{fofs64}, $info->{hash64};
3577 cf::face::set_data $idx, 2, $info->{glyph} , $info->{glyph} ; 3628 #cf::face::set_data $idx, 2, $info->{glyph} , $info->{glyph}; # glyphs no longer downloadable via ix
3578 $FACEHASH{$info->{hash64}} = $idx;#d# 3629 $FACEHASH{$info->{hash64}} = $idx;#d#
3579
3580 cf::cede_to_tick;
3581 } 3630 }
3582 3631
3583 while (my ($face, $info) = each %$faces) { 3632 while (my ($face, $info) = each %$faces) {
3584 next unless $info->{smooth}; 3633 next unless $info->{smooth};
3585 3634
3590 cf::face::set_smooth $idx, $smooth; 3639 cf::face::set_smooth $idx, $smooth;
3591 cf::face::set_smoothlevel $idx, $info->{smoothlevel}; 3640 cf::face::set_smoothlevel $idx, $info->{smoothlevel};
3592 } else { 3641 } else {
3593 error "smooth face '$info->{smooth}' not found for face '$face'"; 3642 error "smooth face '$info->{smooth}' not found for face '$face'";
3594 } 3643 }
3595
3596 cf::cede_to_tick;
3597 } 3644 }
3598 } 3645 }
3599 3646
3600 { 3647 {
3601 my $anims = $facedata->{animinfo}; 3648 my $anims = $facedata->{animinfo};
3602 3649
3603 while (my ($anim, $info) = each %$anims) { 3650 while (my ($anim, $info) = each %$anims) {
3604 cf::anim::set $anim, $info->{frames}, $info->{facings}; 3651 cf::anim::set $anim, $info->{frames}, $info->{facings};
3605 cf::cede_to_tick;
3606 } 3652 }
3607 3653
3608 cf::anim::invalidate_all; # d'oh 3654 cf::anim::invalidate_all; # d'oh
3609 } 3655 }
3610 3656
3615 if (defined (my $type = $info->{type})) { 3661 if (defined (my $type = $info->{type})) {
3616 # TODO: different hash - must free and use new index, or cache ixface data queue 3662 # TODO: different hash - must free and use new index, or cache ixface data queue
3617 my $idx = (cf::face::find $name) || cf::face::alloc $name; 3663 my $idx = (cf::face::find $name) || cf::face::alloc $name;
3618 3664
3619 cf::face::set_type $idx, $type; 3665 cf::face::set_type $idx, $type;
3620 cf::face::set_data $idx, 0, $info->{data}, $info->{hash}; 3666 cf::face::set_data $idx, 0, $info->{size}, $info->{fofs}, $info->{hash};
3621 cf::face::set_meta $idx, $type & 1 ? undef : $info->{meta}; # preserve meta unless prepended already 3667 cf::face::set_meta $idx, $type & 1 ? undef : $info->{meta}; # preserve meta unless prepended already
3622 $FACEHASH{$info->{hash}} = $idx;#d# 3668 $FACEHASH{$info->{hash}} = $idx;#d#
3623 } else { 3669 } else {
3624# $RESOURCE{$name} = $info; # unused 3670# $RESOURCE{$name} = $info; # unused
3625 } 3671 }
3626
3627 cf::cede_to_tick;
3628 } 3672 }
3629 } 3673 }
3674
3675 ($fh, $FACEDATA) = ($FACEDATA, $fh);
3676
3677 # HACK to clear player env face cache, we need some signal framework
3678 # for this (global event?)
3679 %ext::player_env::MUSIC_FACE_CACHE = ();
3680
3681 # END ATOMIC
3682
3683 cf::debug "facedata atomic update time ", EV::time - $t1;
3630 3684
3631 cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE); 3685 cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE);
3686
3687 aio_close $fh if $fh; # close old facedata
3632 3688
3633 1 3689 1
3634} 3690}
3635 3691
3636register_exticmd fx_want => sub { 3692register_exticmd fx_want => sub {
3677 if exists $_->{match}; 3733 if exists $_->{match};
3678 } 3734 }
3679} 3735}
3680 3736
3681sub reload_facedata { 3737sub reload_facedata {
3682 load_facedata "$DATADIR/facedata" 3738 load_facedata $DATADIR
3683 or die "unable to load facedata\n"; 3739 or die "unable to load facedata\n";
3684} 3740}
3685 3741
3686sub reload_archetypes { 3742sub reload_archetypes {
3687 load_resource_file "$DATADIR/archetypes" 3743 load_resource_file "$DATADIR/archetypes"

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines