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.355 by root, Sun Sep 2 12:45:44 2007 UTC vs.
Revision 1.359 by root, Sat Sep 8 18:15:55 2007 UTC

87our %CFG; 87our %CFG;
88 88
89our $UPTIME; $UPTIME ||= time; 89our $UPTIME; $UPTIME ||= time;
90our $RUNTIME; 90our $RUNTIME;
91 91
92our %PLAYER; # all users 92our (%PLAYER, %PLAYER_LOADING); # all users
93our %MAP; # all maps 93our (%MAP, %MAP_LOADING ); # all maps
94our $LINK_MAP; # the special {link} map, which is always available 94our $LINK_MAP; # the special {link} map, which is always available
95 95
96# used to convert map paths into valid unix filenames by replacing / by ∕ 96# used to convert map paths into valid unix filenames by replacing / by ∕
97our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons 97our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
98 98
285Return true if the lock is currently active, i.e. somebody has locked it. 285Return true if the lock is currently active, i.e. somebody has locked it.
286 286
287=cut 287=cut
288 288
289our %LOCK; 289our %LOCK;
290our %LOCKER;#d#
290 291
291sub lock_wait($) { 292sub lock_wait($) {
292 my ($key) = @_; 293 my ($key) = @_;
294
295 if ($LOCKER{$key} == $Coro::current) {#d#
296 Carp::cluck "lock_wait($key) for already-acquired lock";#d#
297 return;#d#
298 }#d#
293 299
294 # wait for lock, if any 300 # wait for lock, if any
295 while ($LOCK{$key}) { 301 while ($LOCK{$key}) {
296 push @{ $LOCK{$key} }, $Coro::current; 302 push @{ $LOCK{$key} }, $Coro::current;
297 Coro::schedule; 303 Coro::schedule;
303 309
304 # wait, to be sure we are not locked 310 # wait, to be sure we are not locked
305 lock_wait $key; 311 lock_wait $key;
306 312
307 $LOCK{$key} = []; 313 $LOCK{$key} = [];
314 $LOCKER{$key} = $Coro::current;#d#
308 315
309 Coro::guard { 316 Coro::guard {
317 delete $LOCKER{$key};#d#
310 # wake up all waiters, to be on the safe side 318 # wake up all waiters, to be on the safe side
311 $_->ready for @{ delete $LOCK{$key} }; 319 $_->ready for @{ delete $LOCK{$key} };
312 } 320 }
313} 321}
314 322
1005); 1013);
1006 1014
1007sub object_freezer_save { 1015sub object_freezer_save {
1008 my ($filename, $rdata, $objs) = @_; 1016 my ($filename, $rdata, $objs) = @_;
1009 1017
1018 my $guard = cf::lock_acquire "io";
1019
1010 sync_job { 1020 sync_job {
1011 if (length $$rdata) { 1021 if (length $$rdata) {
1012 warn sprintf "saving %s (%d,%d)\n", 1022 warn sprintf "saving %s (%d,%d)\n",
1013 $filename, length $$rdata, scalar @$objs; 1023 $filename, length $$rdata, scalar @$objs;
1014 1024
1037 } 1047 }
1038 } else { 1048 } else {
1039 aio_unlink $filename; 1049 aio_unlink $filename;
1040 aio_unlink "$filename.pst"; 1050 aio_unlink "$filename.pst";
1041 } 1051 }
1042 } 1052 };
1053
1054 undef $guard;
1043} 1055}
1044 1056
1045sub object_freezer_as_string { 1057sub object_freezer_as_string {
1046 my ($rdata, $objs) = @_; 1058 my ($rdata, $objs) = @_;
1047 1059
1052 1064
1053sub object_thawer_load { 1065sub object_thawer_load {
1054 my ($filename) = @_; 1066 my ($filename) = @_;
1055 1067
1056 my ($data, $av); 1068 my ($data, $av);
1069
1070 my $guard = cf::lock_acquire "io";
1057 1071
1058 (aio_load $filename, $data) >= 0 1072 (aio_load $filename, $data) >= 0
1059 or return; 1073 or return;
1060 1074
1061 unless (aio_stat "$filename.pst") { 1075 unless (aio_stat "$filename.pst") {
1062 (aio_load "$filename.pst", $av) >= 0 1076 (aio_load "$filename.pst", $av) >= 0
1063 or return; 1077 or return;
1078
1079 undef $guard;
1064 $av = eval { (Storable::thaw $av)->{objs} }; 1080 $av = eval { (Storable::thaw $av)->{objs} };
1065 } 1081 }
1066 1082
1067 warn sprintf "loading %s (%d)\n", 1083 warn sprintf "loading %s (%d)\n",
1068 $filename, length $data, scalar @{$av || []}; 1084 $filename, length $data, scalar @{$av || []};
1085
1069 return ($data, $av); 1086 ($data, $av)
1070} 1087}
1071 1088
1072=head2 COMMAND CALLBACKS 1089=head2 COMMAND CALLBACKS
1073 1090
1074=over 4 1091=over 4
1304 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst"; 1321 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1305 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata"; 1322 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1306 aio_unlink +(playerdir $login) . "/$login.pl.pst"; 1323 aio_unlink +(playerdir $login) . "/$login.pl.pst";
1307 aio_unlink +(playerdir $login) . "/$login.pl"; 1324 aio_unlink +(playerdir $login) . "/$login.pl";
1308 1325
1309 my $pl = load_pl path $login 1326 my $f = new_from_file cf::object::thawer path $login
1310 or return; 1327 or return;
1328
1329 $f->next;
1330 my $pl = cf::player::load_pl $f
1331 or return;
1332 local $cf::PLAYER_LOADING{$login} = $pl;
1333 $f->resolve_delayed_derefs;
1311 $cf::PLAYER{$login} = $pl 1334 $cf::PLAYER{$login} = $pl
1312 } 1335 }
1313 } 1336 }
1314} 1337}
1315 1338
1755 1778
1756sub load_header_from($) { 1779sub load_header_from($) {
1757 my ($self, $path) = @_; 1780 my ($self, $path) = @_;
1758 1781
1759 utf8::encode $path; 1782 utf8::encode $path;
1760 #aio_open $path, O_RDONLY, 0 1783 my $f = new_from_file cf::object::thawer $path
1761 # or return;
1762
1763 $self->_load_header ($path)
1764 or return; 1784 or return;
1785
1786 $self->_load_header ($f)
1787 or return;
1788
1789 local $MAP_LOADING{$self->{path}} = $self;
1790 $f->resolve_delayed_derefs;
1765 1791
1766 $self->{load_path} = $path; 1792 $self->{load_path} = $path;
1767 1793
1768 1 1794 1
1769} 1795}
1823sub find { 1849sub find {
1824 my ($path, $origin) = @_; 1850 my ($path, $origin) = @_;
1825 1851
1826 $path = normalise $path, $origin && $origin->path; 1852 $path = normalise $path, $origin && $origin->path;
1827 1853
1854 cf::lock_wait "map_data:$path";#d#remove
1828 cf::lock_wait "map_find:$path"; 1855 cf::lock_wait "map_find:$path";
1829 1856
1830 $cf::MAP{$path} || do { 1857 $cf::MAP{$path} || do {
1831 my $guard = cf::lock_acquire "map_find:$path"; 1858 my $guard1 = cf::lock_acquire "map_find:$path";
1859 my $guard2 = cf::lock_acquire "map_data:$path"; # just for the fun of it
1860
1832 my $map = new_from_path cf::map $path 1861 my $map = new_from_path cf::map $path
1833 or return; 1862 or return;
1834 1863
1835 $map->{last_save} = $cf::RUNTIME; 1864 $map->{last_save} = $cf::RUNTIME;
1836 1865
1838 or return; 1867 or return;
1839 1868
1840 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?) 1869 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1841 # doing this can freeze the server in a sync job, obviously 1870 # doing this can freeze the server in a sync job, obviously
1842 #$cf::WAIT_FOR_TICK->wait; 1871 #$cf::WAIT_FOR_TICK->wait;
1872 undef $guard1;
1873 undef $guard2;
1843 $map->reset; 1874 $map->reset;
1844 undef $guard;
1845 return find $path; 1875 return find $path;
1846 } 1876 }
1847 1877
1848 $cf::MAP{$path} = $map 1878 $cf::MAP{$path} = $map
1849 } 1879 }
1858 local $self->{deny_reset} = 1; # loading can take a long time 1888 local $self->{deny_reset} = 1; # loading can take a long time
1859 1889
1860 my $path = $self->{path}; 1890 my $path = $self->{path};
1861 1891
1862 { 1892 {
1863 my $guard1 = cf::lock_acquire "map_data:$path"; 1893 my $guard = cf::lock_acquire "map_data:$path";
1864 my $guard2 = cf::lock_acquire "map_load:$path";
1865 1894
1895 return unless $self->valid;
1866 return if $self->in_memory != cf::MAP_SWAPPED; 1896 return if $self->in_memory != cf::MAP_SWAPPED;
1867 1897
1868 $self->in_memory (cf::MAP_LOADING); 1898 $self->in_memory (cf::MAP_LOADING);
1869 1899
1870 $self->alloc; 1900 $self->alloc;
1871 1901
1872 $self->pre_load; 1902 $self->pre_load;
1873 cf::cede_to_tick; 1903 cf::cede_to_tick;
1874 1904
1905 my $f = new_from_file cf::object::thawer $self->{load_path};
1906 $f->skip_block;
1875 $self->_load_objects ($self->{load_path}, 1) 1907 $self->_load_objects ($f)
1876 or return; 1908 or return;
1877 1909
1878 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) 1910 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1879 if delete $self->{load_original}; 1911 if delete $self->{load_original};
1880 1912
1881 if (my $uniq = $self->uniq_path) { 1913 if (my $uniq = $self->uniq_path) {
1882 utf8::encode $uniq; 1914 utf8::encode $uniq;
1883 if (aio_open $uniq, O_RDONLY, 0) { 1915 unless (aio_stat $uniq) {
1916 if (my $f = new_from_file cf::object::thawer $uniq) {
1884 $self->clear_unique_items; 1917 $self->clear_unique_items;
1885 $self->_load_objects ($uniq, 0); 1918 $self->_load_objects ($f);
1919 $f->resolve_delayed_derefs;
1920 }
1886 } 1921 }
1887 } 1922 }
1923
1924 $f->resolve_delayed_derefs;
1888 1925
1889 cf::cede_to_tick; 1926 cf::cede_to_tick;
1890 # now do the right thing for maps 1927 # now do the right thing for maps
1891 $self->link_multipart_objects; 1928 $self->link_multipart_objects;
1892 $self->difficulty ($self->estimate_difficulty) 1929 $self->difficulty ($self->estimate_difficulty)
2036 2073
2037 return if $self->players; 2074 return if $self->players;
2038 return if $self->in_memory != cf::MAP_IN_MEMORY; 2075 return if $self->in_memory != cf::MAP_IN_MEMORY;
2039 return if $self->{deny_save}; 2076 return if $self->{deny_save};
2040 2077
2078 $self->in_memory (cf::MAP_SWAPPED);
2079
2080 $self->deactivate;
2081 $_->clear_links_to ($self) for values %cf::MAP;
2041 $self->clear; 2082 $self->clear;
2042 $self->in_memory (cf::MAP_SWAPPED);
2043} 2083}
2044 2084
2045sub reset_at { 2085sub reset_at {
2046 my ($self) = @_; 2086 my ($self) = @_;
2047 2087
2079 if $uniq; 2119 if $uniq;
2080 } 2120 }
2081 2121
2082 delete $cf::MAP{$self->path}; 2122 delete $cf::MAP{$self->path};
2083 2123
2124 $self->deactivate;
2125 $_->clear_links_to ($self) for values %cf::MAP;
2084 $self->clear; 2126 $self->clear;
2085
2086 $_->clear_links_to ($self) for values %cf::MAP;
2087 2127
2088 $self->unlink_save; 2128 $self->unlink_save;
2089 $self->destroy; 2129 $self->destroy;
2090} 2130}
2091 2131
2190 map { $_, inv_recursive_ $_->inv } @_ 2230 map { $_, inv_recursive_ $_->inv } @_
2191} 2231}
2192 2232
2193sub inv_recursive { 2233sub inv_recursive {
2194 inv_recursive_ inv $_[0] 2234 inv_recursive_ inv $_[0]
2235}
2236
2237=item $ref = $ob->ref
2238
2239creates and returns a persistent reference to an objetc that can be stored as a string.
2240
2241=item $ob = cf::object::deref ($refstring)
2242
2243returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2244even if the object actually exists. May block.
2245
2246=cut
2247
2248sub deref {
2249 my ($ref) = @_;
2250
2251 # temporary compatibility#TODO#remove
2252 $ref =~ s{^<}{player/<};
2253
2254 if ($ref =~ m{^player\/(<1\.\d+>)/(.*)$}) {
2255 my ($uuid, $name) = ($1, $2);
2256 my $pl = $cf::PLAYER_LOADING{$name} || cf::player::find $name
2257 or return;
2258 $pl->ob->uuid eq $uuid
2259 or return;
2260
2261 $pl->ob
2262 } else {
2263 warn "$ref: cannot resolve object reference\n";
2264 undef
2265 }
2195} 2266}
2196 2267
2197package cf; 2268package cf;
2198 2269
2199=back 2270=back
3374 or die; 3445 or die;
3375 3446
3376 $map->width (50); 3447 $map->width (50);
3377 $map->height (50); 3448 $map->height (50);
3378 $map->alloc; 3449 $map->alloc;
3379 $map->_load_objects ("/tmp/x.map", 1); 3450 $map->_load_objects ("/tmp/x.map", 1); #TODO: does not work
3380 my $t = Event::time - $t; 3451 my $t = Event::time - $t;
3381 3452
3382 #next unless $t < 0.0013;#d# 3453 #next unless $t < 0.0013;#d#
3383 if ($t < $min) { 3454 if ($t < $min) {
3384 $min = $t; 3455 $min = $t;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines