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.567 by root, Mon May 2 16:16:00 2011 UTC vs.
Revision 1.574 by root, Sun May 8 21:51:27 2011 UTC

131our @EXTRA_MODULES = qw(pod match mapscript incloader); 131our @EXTRA_MODULES = qw(pod match mapscript incloader);
132 132
133our %CFG; 133our %CFG;
134 134
135our $UPTIME; $UPTIME ||= time; 135our $UPTIME; $UPTIME ||= time;
136our $RUNTIME; 136our $RUNTIME = 0;
137our $SERVER_TICK = 0;
137our $NOW; 138our $NOW;
138 139
139our (%PLAYER, %PLAYER_LOADING); # all users 140our (%PLAYER, %PLAYER_LOADING); # all users
140our (%MAP, %MAP_LOADING ); # all maps 141our (%MAP, %MAP_LOADING ); # all maps
141our $LINK_MAP; # the special {link} map, which is always available 142our $LINK_MAP; # the special {link} map, which is always available
150 151
151our @POST_INIT; 152our @POST_INIT;
152 153
153our $REATTACH_ON_RELOAD; # set to true to force object reattach on reload (slow) 154our $REATTACH_ON_RELOAD; # set to true to force object reattach on reload (slow)
154our $REALLY_UNLOOP; # never set to true, please :) 155our $REALLY_UNLOOP; # never set to true, please :)
156
157our $WAIT_FOR_TICK = new Coro::Signal;
158our @WAIT_FOR_TICK_BEGIN;
155 159
156binmode STDOUT; 160binmode STDOUT;
157binmode STDERR; 161binmode STDERR;
158 162
159# read virtual server time, if available 163# read virtual server time, if available
193 197
194=over 4 198=over 4
195 199
196=item $cf::UPTIME 200=item $cf::UPTIME
197 201
198The timestamp of the server start (so not actually an uptime). 202The timestamp of the server start (so not actually an "uptime").
203
204=item $cf::SERVER_TICK
205
206An unsigned integer that starts at zero when the server is started and is
207incremented on every tick.
208
209=item $cf::NOW
210
211The (real) time of the last (current) server tick - updated before and
212after tick processing, so this is useful only as a rough "what time is it
213now" estimate.
214
215=item $cf::TICK
216
217The interval between each server tick, in seconds.
199 218
200=item $cf::RUNTIME 219=item $cf::RUNTIME
201 220
202The time this server has run, starts at 0 and is increased by $cf::TICK on 221The time this server has run, starts at 0 and is increased by $cf::TICK on
203every server tick. 222every server tick.
209Various directories - "/etc", read-only install directory, perl-library 228Various directories - "/etc", read-only install directory, perl-library
210directory, pod-directory, read-only maps directory, "/var", "/var/tmp", 229directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
211unique-items directory, player file directory, random maps directory and 230unique-items directory, player file directory, random maps directory and
212database environment. 231database environment.
213 232
214=item $cf::NOW
215
216The time of the last (current) server tick.
217
218=item $cf::TICK
219
220The interval between server ticks, in seconds.
221
222=item $cf::LOADAVG 233=item $cf::LOADAVG
223 234
224The current CPU load on the server (alpha-smoothed), as a value between 0 235The current CPU load on the server (alpha-smoothed), as a value between 0
225(none) and 1 (overloaded), indicating how much time is spent on processing 236(none) and 1 (overloaded), indicating how much time is spent on processing
226objects per tick. Healthy values are < 0.5. 237objects per tick. Healthy values are < 0.5.
237=item cf::wait_for_tick, cf::wait_for_tick_begin 248=item cf::wait_for_tick, cf::wait_for_tick_begin
238 249
239These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only 250These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
240returns directly I<after> the tick processing (and consequently, can only wake one thread 251returns directly I<after> the tick processing (and consequently, can only wake one thread
241per tick), while cf::wait_for_tick wakes up all waiters after tick processing. 252per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
253
254Note that cf::Wait_for_tick will immediately return when the server is not
255ticking, making it suitable for small pauses in threads that need to run
256when the server is paused. If that is not applicable (i.e. you I<really>
257want to wait, use C<$cf::WAIT_FOR_TICK>).
258
259=item $cf::WAIT_FOR_TICK
260
261Note that C<cf::wait_for_tick> is probably the correct thing to use. This
262variable contains a L<Coro::Signal> that is broadcats after every server
263tick. Calling C<< ->wait >> on it will suspend the caller until after the
264next server tick.
242 265
243=cut 266=cut
244 267
245sub wait_for_tick(); 268sub wait_for_tick();
246sub wait_for_tick_begin(); 269sub wait_for_tick_begin();
545 } 568 }
546 } 569 }
547 570
548 if (@SLOT_QUEUE) { 571 if (@SLOT_QUEUE) {
549 # we do not use wait_for_tick() as it returns immediately when tick is inactive 572 # we do not use wait_for_tick() as it returns immediately when tick is inactive
550 push @cf::WAIT_FOR_TICK, $signal; 573 $WAIT_FOR_TICK->wait;
551 $signal->wait;
552 } else { 574 } else {
553 $busy = 0; 575 $busy = 0;
554 Coro::schedule; 576 Coro::schedule;
555 } 577 }
556 } 578 }
2171 2193
2172 { 2194 {
2173 my $guard = cf::lock_acquire "map_data:$path"; 2195 my $guard = cf::lock_acquire "map_data:$path";
2174 2196
2175 return unless $self->valid; 2197 return unless $self->valid;
2176 return unless $self->in_memory == cf::MAP_SWAPPED; 2198 return unless $self->state == cf::MAP_SWAPPED;
2177
2178 $self->in_memory (cf::MAP_LOADING);
2179 2199
2180 $self->alloc; 2200 $self->alloc;
2181 2201
2182 $self->pre_load; 2202 $self->pre_load;
2183 cf::cede_to_tick; 2203 cf::cede_to_tick;
2206 } else { 2226 } else {
2207 $self->post_load_original 2227 $self->post_load_original
2208 if delete $self->{load_original}; 2228 if delete $self->{load_original};
2209 } 2229 }
2210 2230
2231 $self->state (cf::MAP_INACTIVE);
2232
2211 cf::cede_to_tick; 2233 cf::cede_to_tick;
2212 # now do the right thing for maps 2234 # now do the right thing for maps
2213 $self->link_multipart_objects; 2235 $self->link_multipart_objects;
2214 $self->difficulty ($self->estimate_difficulty) 2236 $self->difficulty ($self->estimate_difficulty)
2215 unless $self->difficulty; 2237 unless $self->difficulty;
2218 unless ($self->{deny_activate}) { 2240 unless ($self->{deny_activate}) {
2219 $self->decay_objects; 2241 $self->decay_objects;
2220 $self->fix_auto_apply; 2242 $self->fix_auto_apply;
2221 $self->update_buttons; 2243 $self->update_buttons;
2222 cf::cede_to_tick; 2244 cf::cede_to_tick;
2223 $self->activate; 2245 #$self->activate; # no longer activate maps automatically
2224 } 2246 }
2225 2247
2226 $self->{last_save} = $cf::RUNTIME; 2248 $self->{last_save} = $cf::RUNTIME;
2227 $self->last_access ($cf::RUNTIME); 2249 $self->last_access ($cf::RUNTIME);
2228
2229 $self->in_memory (cf::MAP_ACTIVE);
2230 } 2250 }
2231 2251
2232 $self->post_load; 2252 $self->post_load;
2233 2253
2234 1 2254 1
2247# if $self->per_party; 2267# if $self->per_party;
2248 2268
2249 $self 2269 $self
2250} 2270}
2251 2271
2252# find and load all maps in the 3x3 area around a map
2253sub load_neighbours {
2254 my ($map) = @_;
2255
2256 my @neigh; # diagonal neighbours
2257
2258 for (0 .. 3) {
2259 my $neigh = $map->tile_path ($_)
2260 or next;
2261 $neigh = find $neigh, $map
2262 or next;
2263 $neigh->load;
2264
2265 # now find the diagonal neighbours
2266 push @neigh,
2267 [$neigh->tile_path (($_ + 3) % 4), $neigh],
2268 [$neigh->tile_path (($_ + 1) % 4), $neigh];
2269 }
2270
2271 for (grep defined $_->[0], @neigh) {
2272 my ($path, $origin) = @$_;
2273 my $neigh = find $path, $origin
2274 or next;
2275 $neigh->load;
2276 }
2277}
2278
2279sub find_sync { 2272sub find_sync {
2280 my ($path, $origin) = @_; 2273 my ($path, $origin) = @_;
2281 2274
2275 # it's a bug to call this from the main context
2282 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync" 2276 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync"
2283 if $Coro::current == $Coro::main; 2277 if $Coro::current == $Coro::main;
2284 2278
2285 find $path, $origin 2279 find $path, $origin
2286} 2280}
2287 2281
2288sub do_load_sync { 2282sub do_load_sync {
2289 my ($map) = @_; 2283 my ($map) = @_;
2290 2284
2285 # it's a bug to call this from the main context
2291 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync" 2286 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync"
2292 if $Coro::current == $Coro::main; 2287 if $Coro::current == $Coro::main;
2293 2288
2294 $map->load; 2289 $map->load;
2295} 2290}
2301 my ($path, $origin, $load) = @_; 2296 my ($path, $origin, $load) = @_;
2302 2297
2303 $path = normalise $path, $origin; 2298 $path = normalise $path, $origin;
2304 2299
2305 if (my $map = $cf::MAP{$path}) { 2300 if (my $map = $cf::MAP{$path}) {
2306 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE; 2301 return $map if !$load || $map->linkable;
2307 } 2302 }
2308 2303
2309 $MAP_PREFETCH{$path} |= $load; 2304 $MAP_PREFETCH{$path} |= $load;
2310 2305
2311 $MAP_PREFETCHER ||= cf::async { 2306 $MAP_PREFETCHER ||= cf::async {
2370sub swap_out { 2365sub swap_out {
2371 my ($self) = @_; 2366 my ($self) = @_;
2372 2367
2373 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2368 my $lock = cf::lock_acquire "map_data:$self->{path}";
2374 2369
2375 return if $self->in_memory != cf::MAP_ACTIVE; 2370 return if !$self->linkable;
2376 return if $self->{deny_save}; 2371 return if $self->{deny_save};
2377 return if $self->players; 2372 return if $self->players;
2378 2373
2379 # first deactivate the map and "unlink" it from the core 2374 # first deactivate the map and "unlink" it from the core
2380 $self->deactivate; 2375 $self->deactivate;
2381 $_->clear_links_to ($self) for values %cf::MAP; 2376 $_->clear_links_to ($self) for values %cf::MAP;
2382 $self->in_memory (cf::MAP_SWAPPED); 2377 $self->state (cf::MAP_SWAPPED);
2383 2378
2384 # then atomically save 2379 # then atomically save
2385 $self->_save; 2380 $self->_save;
2386 2381
2387 # then free the map 2382 # then free the map
2413 2408
2414 return if $self->players; 2409 return if $self->players;
2415 2410
2416 cf::trace "resetting map ", $self->path, "\n"; 2411 cf::trace "resetting map ", $self->path, "\n";
2417 2412
2418 $self->in_memory (cf::MAP_SWAPPED); 2413 $self->state (cf::MAP_SWAPPED);
2419 2414
2420 # need to save uniques path 2415 # need to save uniques path
2421 unless ($self->{deny_save}) { 2416 unless ($self->{deny_save}) {
2422 my $uniq = $self->uniq_path; utf8::encode $uniq; 2417 my $uniq = $self->uniq_path; utf8::encode $uniq;
2423 2418
2753 # use -1 or undef as default coordinates, not 0, 0 2748 # use -1 or undef as default coordinates, not 0, 0
2754 ($x, $y) = ($map->enter_x, $map->enter_y) 2749 ($x, $y) = ($map->enter_x, $map->enter_y)
2755 if $x <= 0 && $y <= 0; 2750 if $x <= 0 && $y <= 0;
2756 2751
2757 $map->load; 2752 $map->load;
2758 $map->load_neighbours;
2759 2753
2760 return unless $self->contr->active; 2754 return unless $self->contr->active;
2761 2755
2762 local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext 2756 local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2763 if ($self->enter_map ($map, $x, $y)) { 2757 if ($self->enter_map ($map, $x, $y)) {
2931 # special map handling 2925 # special map handling
2932 if ($slaying eq "/!") { 2926 if ($slaying eq "/!") {
2933 my $guard = cf::lock_acquire "exit_prepare:$exit"; 2927 my $guard = cf::lock_acquire "exit_prepare:$exit";
2934 2928
2935 prepare_random_map $exit 2929 prepare_random_map $exit
2936 if $slaying eq "/!"; # need to re-check after getting the lock 2930 if $exit->slaying eq "/!"; # need to re-check after getting the lock
2931
2932 $map = $exit->slaying;
2937 2933
2938 } elsif ($slaying eq '!up') { 2934 } elsif ($slaying eq '!up') {
2939 $map = $exit->map->tile_path (cf::TILE_UP); 2935 $map = $exit->map->tile_path (cf::TILE_UP);
2940 $x = $exit->x; 2936 $x = $exit->x;
2941 $y = $exit->y; 2937 $y = $exit->y;
4091 4087
4092############################################################################# 4088#############################################################################
4093 4089
4094my $bug_warning = 0; 4090my $bug_warning = 0;
4095 4091
4096our @WAIT_FOR_TICK;
4097our @WAIT_FOR_TICK_BEGIN;
4098
4099sub wait_for_tick() { 4092sub wait_for_tick() {
4100 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4093 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4101 4094
4102 my $signal = new Coro::Signal; 4095 $WAIT_FOR_TICK->wait;
4103 push @WAIT_FOR_TICK, $signal;
4104 $signal->wait;
4105} 4096}
4106 4097
4107sub wait_for_tick_begin() { 4098sub wait_for_tick_begin() {
4108 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4099 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4109 4100
4110 my $signal = new Coro::Signal; 4101 my $signal = new Coro::Signal;
4111 push @WAIT_FOR_TICK_BEGIN, $signal; 4102 push @WAIT_FOR_TICK_BEGIN, $signal;
4112 $signal->wait; 4103 $signal->wait;
4113} 4104}
4117 Carp::cluck "major BUG: server tick called outside of main coro, skipping it" 4108 Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
4118 unless ++$bug_warning > 10; 4109 unless ++$bug_warning > 10;
4119 return; 4110 return;
4120 } 4111 }
4121 4112
4122 cf::server_tick; # one server iteration 4113 cf::one_tick; # one server iteration
4123 4114
4124 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d# 4115 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d#
4125 4116
4126 if ($NOW >= $NEXT_RUNTIME_WRITE) { 4117 if ($NOW >= $NEXT_RUNTIME_WRITE) {
4127 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 4118 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
4133 } 4124 }
4134 4125
4135 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 4126 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
4136 $sig->send; 4127 $sig->send;
4137 } 4128 }
4138 while (my $sig = shift @WAIT_FOR_TICK) { 4129 $WAIT_FOR_TICK->broadcast;
4139 $sig->send;
4140 }
4141 4130
4142 $LOAD = ($NOW - $TICK_START) / $TICK; 4131 $LOAD = ($NOW - $TICK_START) / $TICK;
4143 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25; 4132 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
4144 4133
4145 if (0) { 4134 if (0) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines