1 | #! perl # mandatory |
1 | #! perl # mandatory |
2 | |
2 | |
3 | our $SCHEDULE_INTERVAL = $cf::CFG{extractor_schedule_interval} || 3600; |
3 | our $SCHEDULE_INTERVAL = $cf::CFG{extractor_schedule_interval} || 3600; |
4 | |
4 | |
5 | use JSON::XS; |
5 | use JSON::XS; |
6 | |
6 | |
7 | my $db_mapinfo = cf::sync_job { cf::db_table "tag-mapinfo" }; # info/cache for maps |
7 | my $db_mapinfo = cf::sync_job { cf::db_table "tag-mapinfo" }; # info/cache for maps |
8 | my $db_target = cf::sync_job { cf::db_table "tag-target" }; # tag => maps |
8 | my $db_target = cf::sync_job { cf::db_table "tag-target" }; # tag => maps |
… | |
… | |
77 | add_tag_target $txn, $tag, $key; |
77 | add_tag_target $txn, $tag, $key; |
78 | } |
78 | } |
79 | |
79 | |
80 | # we don't actually care if it succeeds or not, as we |
80 | # we don't actually care if it succeeds or not, as we |
81 | # will just retry an hour later |
81 | # will just retry an hour later |
82 | BDB::db_txn_commit $txn; |
82 | BDB::db_txn_finish $txn; |
83 | |
83 | |
84 | # warn "tag-updated $file (= $key) $hash\n";#d# |
84 | # warn "tag-updated $file (= $key) $hash\n";#d# |
85 | } |
85 | } |
86 | |
86 | |
87 | sub scan_static { |
87 | sub scan_static { |
… | |
… | |
100 | |
100 | |
101 | &scan_static ("$dir/$_", "$map$_/") |
101 | &scan_static ("$dir/$_", "$map$_/") |
102 | for @$dirs; |
102 | for @$dirs; |
103 | } |
103 | } |
104 | |
104 | |
105 | cf::async_ext { |
105 | sub reload { |
106 | $Coro::current->prio (Coro::PRIO_MIN); |
106 | my $start = Event::time; |
107 | |
107 | |
108 | while () { |
108 | # 1. check for maps no longer existing |
109 | my $start = Event::time; |
109 | { |
|
|
110 | my @delkeys; |
110 | |
111 | |
111 | # 1. check for maps no longer existing |
112 | my $cursor = $db_mapinfo->cursor; |
|
|
113 | for (;;) { |
|
|
114 | BDB::db_c_get $cursor, my $key, my $data, BDB::NEXT; |
|
|
115 | last if $!; |
112 | |
116 | |
113 | # 2. scan all static maps |
117 | my $data = JSON::XS::from_json $data; |
114 | scan_static $cf::MAPDIR, "/"; |
118 | my ($ver, undef, undef, $path) = split /,/, $data->{hash}, 4; |
|
|
119 | push @delkeys, [$key, $data->{tags}] |
|
|
120 | if $ver != 1 || Coro::AIO::aio_stat $path; |
|
|
121 | } |
|
|
122 | BDB::db_c_close $cursor; |
115 | |
123 | |
|
|
124 | for (@delkeys) { |
|
|
125 | my ($key, $tags) = @$_; |
|
|
126 | my $txn = $cf::DB_ENV->txn_begin; |
|
|
127 | BDB::db_del $db_mapinfo, $txn, $key; |
|
|
128 | for my $tag (@{ $tags || [] }) { |
|
|
129 | remove_tag_target $txn, $tag, $key; |
|
|
130 | } |
|
|
131 | BDB::db_txn_finish $txn; |
|
|
132 | } |
|
|
133 | } |
|
|
134 | |
|
|
135 | # 2. scan all static maps |
|
|
136 | scan_static $cf::MAPDIR, "/"; |
|
|
137 | |
116 | # 3. scan all dynamic maps |
138 | # 3. scan all dynamic maps |
117 | for my $path (@{ cf::map::tmp_maps or [] }, @{ cf::map::random_maps or [] }) { |
139 | for my $path (@{ cf::map::tmp_maps or [] }, @{ cf::map::random_maps or [] }) { |
118 | # my $map = cf::map::find $path; |
140 | # my $map = cf::map::find $path; |
119 | # extract_map_tags "t/$map", $path; |
141 | # extract_map_tags "t/$map", $path; |
120 | } |
142 | } |
121 | |
143 | |
122 | # now hunt for all per-player maps |
144 | # now hunt for all per-player maps |
123 | # scan_dir $cf::PLAYERDIR |
145 | # scan_dir $cf::PLAYERDIR |
124 | # for my $login (@{ cf::player::list_logins or [] }) { |
146 | # for my $login (@{ cf::player::list_logins or [] }) { |
125 | # for my $path (@{ cf::player::maps $login or [] }) { |
147 | # for my $path (@{ cf::player::maps $login or [] }) { |
126 | # cf::cede_to_tick; |
148 | # cf::cede_to_tick; |
… | |
… | |
144 | # delete $map->{deny_reset}; |
166 | # delete $map->{deny_reset}; |
145 | # } |
167 | # } |
146 | # } |
168 | # } |
147 | # } |
169 | # } |
148 | |
170 | |
149 | warn sprintf "map-tag scan (%fs)", Event::time - $start; |
171 | warn sprintf "map-tag scan (%fs)", Event::time - $start; |
150 | Coro::Timer::sleep $SCHEDULE_INTERVAL; |
172 | } |
151 | } |
|
|
152 | }; |
|
|
153 | |
173 | |
|
|
174 | our $RELOAD_SCHEDULER = Event->timer ( |
|
|
175 | after => 0, |
|
|
176 | interval => $SCHEDULE_INTERVAL, |
|
|
177 | data => cf::WF_AUTOCANCEL, |
|
|
178 | cb => Coro::unblock_sub { |
|
|
179 | $Coro::current->prio (Coro::PRIO_MIN); |
|
|
180 | reload; |
|
|
181 | }, |
|
|
182 | ); |
|
|
183 | |
|
|
184 | # find all objects with the given tag, or at least try to |
154 | sub find($) { |
185 | sub find($) { |
155 | my ($tag) = @_; |
186 | my ($tag) = @_; |
156 | |
187 | |
157 | my @res; |
|
|
158 | |
|
|
159 | utf8::encode $tag; |
188 | utf8::encode (my $key = $tag); |
160 | BDB::db_get $db_target, undef, $tag, my $data; |
189 | BDB::db_get $db_target, undef, $key, my $data; |
161 | utf8::decode $data; |
190 | utf8::decode $data; |
162 | |
191 | |
163 | for my $map ( |
192 | map { $_->load; $_->find_tagged_objects ($tag) } |
164 | grep $_, |
193 | grep $_, |
165 | map { cf::map::find $_ } |
194 | map { cf::map::find $_ } |
166 | grep s/^s//, |
195 | grep s/^s//, |
167 | split /\x00/, $data |
196 | split /\x00/, $data |
168 | ) { |
|
|
169 | $map->load; |
|
|
170 | |
|
|
171 | warn "tag<$tag>map<$map>\n";#d# |
|
|
172 | } |
|
|
173 | |
|
|
174 | @res |
|
|
175 | } |
197 | } |