--- deliantra/server/lib/cf.pm 2006/12/30 16:56:16 1.104 +++ deliantra/server/lib/cf.pm 2006/12/31 17:17:23 1.105 @@ -15,8 +15,10 @@ use Coro::Timer; use Coro::Signal; use Coro::Semaphore; +use Coro::AIO; -use IO::AIO 2.3; +use Fcntl; +use IO::AIO 2.31 (); use YAML::Syck (); use Time::HiRes; @@ -174,6 +176,36 @@ JSON::Syck::Dump $_[0] } +# main coro must never ever "block" except in Event +# sync_job ensures this by running the job in a coroutine +# and waiting in Event while the server is otherwise frozen +sub sync_job(&) { + my ($job) = @_; + + my $busy = 1; + my @res; + + local $FREEZE = 1; + + my $coro = Coro::async { + @res = eval { $job->() }; + warn $@ if $@; + undef $busy; + }; + + if ($Coro::current == $Coro::main) { + $coro->prio (Coro::PRIO_MAX); + while ($busy) { + Coro::cede_notself; + Event::one_event unless Coro::nready; + } + } else { + $coro->join; + } + + wantarray ? @res : $res[0] +} + =item $coro = cf::coro { BLOCK } Creates and returns a new coro. This coro is automcatially being canceled @@ -565,31 +597,38 @@ sub object_freezer_save { my ($filename, $rdata, $objs) = @_; - if (length $$rdata) { - warn sprintf "saving %s (%d,%d)\n", - $filename, length $$rdata, scalar @$objs; - - if (open my $fh, ">:raw", "$filename~") { - chmod SAVE_MODE, $fh; - syswrite $fh, $$rdata; - close $fh; + sync_job { + if (length $$rdata) { + warn sprintf "saving %s (%d,%d)\n", + $filename, length $$rdata, scalar @$objs; - if (@$objs && open my $fh, ">:raw", "$filename.pst~") { + if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) { chmod SAVE_MODE, $fh; - syswrite $fh, Storable::nfreeze { version => 1, objs => $objs }; + aio_write $fh, 0, (length $$rdata), $$rdata, 0; + aio_fsync $fh; close $fh; - rename "$filename.pst~", "$filename.pst"; + + if (@$objs) { + if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) { + chmod SAVE_MODE, $fh; + my $data = Storable::nfreeze { version => 1, objs => $objs }; + aio_write $fh, 0, (length $data), $data, 0; + aio_fsync $fh; + close $fh; + aio_rename "$filename.pst~", "$filename.pst"; + } + } else { + aio_unlink "$filename.pst"; + } + + aio_rename "$filename~", $filename; } else { - unlink "$filename.pst"; + warn "FATAL: $filename~: $!\n"; } - - rename "$filename~", $filename; } else { - warn "FATAL: $filename~: $!\n"; + aio_unlink $filename; + aio_unlink "$filename.pst"; } - } else { - unlink $filename; - unlink "$filename.pst"; } } @@ -604,20 +643,18 @@ sub object_thawer_load { my ($filename) = @_; - local $/; + my ($data, $av); - my $av; + (aio_load $filename, $data) >= 0 + or return; - #TODO: use sysread etc. - if (open my $data, "<:raw:perlio", $filename) { - $data = <$data>; - if (open my $pst, "<:raw:perlio", "$filename.pst") { - $av = eval { (Storable::thaw <$pst>)->{objs} }; - } - return ($data, $av); + unless (aio_stat "$filename.pst") { + (aio_load "$filename.pst", $av) >= 0 + or return; + $av = eval { (Storable::thaw <$av>)->{objs} }; } - () + return ($data, $av); } #############################################################################