… | |
… | |
197 | =cut |
197 | =cut |
198 | |
198 | |
199 | sub sync_job(&) { |
199 | sub sync_job(&) { |
200 | my ($job) = @_; |
200 | my ($job) = @_; |
201 | |
201 | |
202 | my $busy = 1; |
|
|
203 | my @res; |
|
|
204 | |
|
|
205 | my $coro = Coro::async { |
|
|
206 | @res = eval { $job->() }; |
|
|
207 | warn $@ if $@; |
|
|
208 | undef $busy; |
|
|
209 | }; |
|
|
210 | |
|
|
211 | if ($Coro::current == $Coro::main) { |
202 | if ($Coro::current == $Coro::main) { |
|
|
203 | # this is the main coro, too bad, we have to block |
|
|
204 | # till the operation succeeds, freezing the server :/ |
|
|
205 | |
212 | # TODO: use suspend/resume instead |
206 | # TODO: use suspend/resume instead |
|
|
207 | # (but this is cancel-safe) |
213 | local $FREEZE = 1; |
208 | local $FREEZE = 1; |
|
|
209 | |
|
|
210 | my $busy = 1; |
|
|
211 | my @res; |
|
|
212 | |
|
|
213 | (Coro::async { |
|
|
214 | @res = eval { $job->() }; |
|
|
215 | warn $@ if $@; |
|
|
216 | undef $busy; |
214 | $coro->prio (Coro::PRIO_MAX); |
217 | })->prio (Coro::PRIO_MAX); |
|
|
218 | |
215 | while ($busy) { |
219 | while ($busy) { |
216 | Coro::cede_notself; |
220 | Coro::cede_notself; |
217 | Event::one_event unless Coro::nready; |
221 | Event::one_event unless Coro::nready; |
218 | } |
222 | } |
|
|
223 | |
|
|
224 | wantarray ? @res : $res[0] |
219 | } else { |
225 | } else { |
220 | $coro->join; |
226 | # we are in another coroutine, how wonderful, everything just works |
|
|
227 | |
|
|
228 | $job->() |
221 | } |
229 | } |
222 | |
|
|
223 | wantarray ? @res : $res[0] |
|
|
224 | } |
230 | } |
225 | |
231 | |
226 | =item $coro = cf::coro { BLOCK } |
232 | =item $coro = cf::coro { BLOCK } |
227 | |
233 | |
228 | Creates and returns a new coro. This coro is automcatially being canceled |
234 | Creates and returns a new coro. This coro is automcatially being canceled |
… | |
… | |
252 | my $runtime = cf::localdir . "/runtime"; |
258 | my $runtime = cf::localdir . "/runtime"; |
253 | |
259 | |
254 | my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644 |
260 | my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644 |
255 | or return; |
261 | or return; |
256 | |
262 | |
257 | my $value = $cf::RUNTIME; |
263 | my $value = $cf::RUNTIME + 1 + 10; # 10 is the runtime save interval, for a monotonic clock |
258 | (aio_write $fh, 0, (length $value), $value, 0) <= 0 |
264 | (aio_write $fh, 0, (length $value), $value, 0) <= 0 |
259 | and return; |
265 | and return; |
260 | |
266 | |
261 | aio_fsync $fh |
267 | aio_fsync $fh |
262 | and return; |
268 | and return; |
… | |
… | |
1046 | use Fcntl; |
1052 | use Fcntl; |
1047 | use Coro::AIO; |
1053 | use Coro::AIO; |
1048 | |
1054 | |
1049 | our $MAX_RESET = 7200; |
1055 | our $MAX_RESET = 7200; |
1050 | our $DEFAULT_RESET = 3600; |
1056 | our $DEFAULT_RESET = 3600; |
1051 | $MAX_RESET = 10;#d# |
|
|
1052 | $DEFAULT_RESET = 10;#d# |
|
|
1053 | |
1057 | |
1054 | sub generate_random_map { |
1058 | sub generate_random_map { |
1055 | my ($path, $rmp) = @_; |
1059 | my ($path, $rmp) = @_; |
1056 | |
1060 | |
1057 | # mit "rum" bekleckern, nicht |
1061 | # mit "rum" bekleckern, nicht |
… | |
… | |
1090 | |
1094 | |
1091 | $map->load_header ($path) |
1095 | $map->load_header ($path) |
1092 | or return; |
1096 | or return; |
1093 | |
1097 | |
1094 | $map->{load_path} = $path; |
1098 | $map->{load_path} = $path; |
1095 | use Data::Dumper; warn Dumper $map;#d# |
|
|
1096 | |
1099 | |
1097 | $map |
1100 | $map |
1098 | } |
1101 | } |
1099 | |
1102 | |
1100 | sub find_map { |
1103 | sub find_map { |
1101 | my ($path, $origin) = @_; |
1104 | my ($path, $origin) = @_; |
1102 | |
1105 | |
1103 | #warn "find_map<$path,$origin>\n";#d# |
1106 | #warn "find_map<$path,$origin>\n";#d# |
1104 | |
1107 | |
1105 | $path = ref $path ? $path : new cf::path $path, $origin && $origin->path; |
1108 | $path = new cf::path $path, $origin && $origin->path; |
1106 | my $key = $path->as_string; |
1109 | my $key = $path->as_string; |
1107 | |
1110 | |
1108 | $cf::MAP{$key} || do { |
1111 | $cf::MAP{$key} || do { |
1109 | # do it the slow way |
1112 | # do it the slow way |
1110 | my $map = try_load_header $path->save_path; |
1113 | my $map = try_load_header $path->save_path; |
… | |
… | |
1132 | |
1135 | |
1133 | $map->path ($key); |
1136 | $map->path ($key); |
1134 | $map->{path} = $path; |
1137 | $map->{path} = $path; |
1135 | $map->last_access ($cf::RUNTIME); |
1138 | $map->last_access ($cf::RUNTIME); |
1136 | |
1139 | |
1137 | $map->reset if $map->should_reset; |
1140 | if ($map->should_reset) { |
|
|
1141 | $map->reset; |
|
|
1142 | $map = find_map $path; |
|
|
1143 | } |
1138 | |
1144 | |
1139 | $cf::MAP{$key} = $map |
1145 | $cf::MAP{$key} = $map |
1140 | } |
1146 | } |
1141 | } |
1147 | } |
1142 | |
1148 | |
… | |
… | |
1151 | |
1157 | |
1152 | $self->alloc; |
1158 | $self->alloc; |
1153 | $self->load_objects ($self->{load_path}, 1) |
1159 | $self->load_objects ($self->{load_path}, 1) |
1154 | or return; |
1160 | or return; |
1155 | |
1161 | |
1156 | $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) if delete $self->{load_original}; |
1162 | $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) |
|
|
1163 | if delete $self->{load_original}; |
1157 | |
1164 | |
1158 | if (my $uniq = $path->uniq_path) { |
1165 | if (my $uniq = $path->uniq_path) { |
1159 | utf8::encode $uniq; |
1166 | utf8::encode $uniq; |
1160 | if (aio_open $uniq, O_RDONLY, 0) { |
1167 | if (aio_open $uniq, O_RDONLY, 0) { |
1161 | $self->clear_unique_items; |
1168 | $self->clear_unique_items; |
… | |
… | |
1207 | |
1214 | |
1208 | $self->{load_path} = $save; |
1215 | $self->{load_path} = $save; |
1209 | |
1216 | |
1210 | return if $self->{deny_save}; |
1217 | return if $self->{deny_save}; |
1211 | |
1218 | |
1212 | warn "saving map ", $self->path; |
|
|
1213 | |
|
|
1214 | if ($uniq) { |
1219 | if ($uniq) { |
1215 | $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS); |
1220 | $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS); |
1216 | $self->save_objects ($uniq, cf::IO_UNIQUES); |
1221 | $self->save_objects ($uniq, cf::IO_UNIQUES); |
1217 | } else { |
1222 | } else { |
1218 | $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES); |
1223 | $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES); |
… | |
… | |
1229 | $self->save; |
1234 | $self->save; |
1230 | $self->clear; |
1235 | $self->clear; |
1231 | $self->in_memory (cf::MAP_SWAPPED); |
1236 | $self->in_memory (cf::MAP_SWAPPED); |
1232 | } |
1237 | } |
1233 | |
1238 | |
|
|
1239 | sub reset_at { |
|
|
1240 | my ($self) = @_; |
|
|
1241 | |
|
|
1242 | # TODO: safety, remove and allow resettable per-player maps |
|
|
1243 | return 1e100 if $self->{path}{user_rel}; |
|
|
1244 | return 1e100 if $self->{deny_reset}; |
|
|
1245 | |
|
|
1246 | my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access; |
|
|
1247 | my $to = $self->reset_timeout || $DEFAULT_RESET; |
|
|
1248 | $to = $MAX_RESET if $to > $MAX_RESET; |
|
|
1249 | |
|
|
1250 | $time + $to |
|
|
1251 | } |
|
|
1252 | |
1234 | sub should_reset { |
1253 | sub should_reset { |
1235 | my ($map) = @_; |
1254 | my ($self) = @_; |
1236 | |
1255 | |
1237 | # TODO: safety, remove and allow resettable per-player maps |
1256 | $self->reset_at <= $cf::RUNTIME |
1238 | return if $map->{path}{user_rel};#d# |
|
|
1239 | return if $map->{deny_reset}; |
|
|
1240 | #return unless $map->reset_timeout; |
|
|
1241 | |
|
|
1242 | my $time = $map->fixed_resettime ? $map->{instantiate_time} : $map->last_access; |
|
|
1243 | my $to = $map->reset_timeout || $DEFAULT_RESET; |
|
|
1244 | $to = $MAX_RESET if $to > $MAX_RESET; |
|
|
1245 | |
|
|
1246 | $time + $to < $cf::RUNTIME |
|
|
1247 | } |
1257 | } |
1248 | |
1258 | |
1249 | sub unlink_save { |
1259 | sub unlink_save { |
1250 | my ($self) = @_; |
1260 | my ($self) = @_; |
1251 | |
1261 | |