ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/map-tags.ext
Revision: 1.5
Committed: Thu Sep 13 08:35:24 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
Changes since 1.4: +22 -16 lines
Log Message:
rent was calling blocking functions in the main coro. doh.; also, do some cleanups

File Contents

# User Rev Content
1 root 1.1 #! perl # mandatory
2    
3 root 1.3 our $SCHEDULE_INTERVAL = $cf::CFG{extractor_schedule_interval} || 3600;
4 root 1.1
5     use JSON::XS;
6    
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
9    
10     sub remove_tag_target {
11     my ($txn, $tag, $target) = @_;
12     # - U O
13    
14     utf8::encode $tag;
15     BDB::db_get $db_target, $txn, $tag, my $data;
16     my @tags = split /\x00/, $data;
17     @tags = grep $_ ne $target, @tags;
18    
19     if (@tags) {
20     BDB::db_put $db_target, $txn, $tag, join "\x00", @tags;
21     } else {
22     BDB::db_del $db_target, $txn, $tag;
23     }
24     }
25    
26     sub add_tag_target {
27     my ($txn, $tag, $target) = @_;
28    
29     utf8::encode $tag;
30     BDB::db_put $db_target, $txn, $tag, my $data;
31     my @tags = split /\x00/, $data;
32     push @tags, $target;
33     BDB::db_put $db_target, $txn, $tag, join "\x00", @tags;
34     }
35    
36     sub scan_map($$) {
37     my ($key, $file) = @_;
38     # unicode key, octets file
39    
40     Coro::AIO::aio_stat $file
41     and next;
42    
43     my $hash = join ",", 1, (stat _)[7,9], $file;
44    
45     my $old_tags;
46    
47     my $txn = $cf::DB_ENV->txn_begin;
48    
49     utf8::encode $key;
50     BDB::db_get $db_mapinfo, $txn, $key, my $data;
51    
52     unless ($!) {
53     $data = from_json $data;
54     return if $data->{hash} eq $hash;
55     $old_tags = $data->{tags};
56     }
57    
58     $old_tags ||= [];
59    
60     my $f = new_from_file cf::object::thawer $file
61     or return;
62    
63     my @tags = sort $f->extract_tags;
64     $data = to_json { hash => $hash, tags => \@tags };
65    
66     BDB::db_put $db_mapinfo, $txn, $key, $data;
67    
68     # 1. remove tags no longer existing
69     for my $tag (@$old_tags) {
70     next if grep $_ eq $tag, @tags;
71     remove_tag_target $txn, $tag, $key;
72     }
73    
74     # 2. add tags that are new
75     for my $tag (@tags) {
76     next if grep $_ eq $tag, @$old_tags;
77     add_tag_target $txn, $tag, $key;
78     }
79    
80     # we don't actually care if it succeeds or not, as we
81     # will just retry an hour later
82     BDB::db_txn_commit $txn;
83    
84     # warn "tag-updated $file (= $key) $hash\n";#d#
85     }
86    
87     sub scan_static {
88     my ($dir, $map) = @_;
89    
90     my ($dirs, $files) = Coro::AIO::aio_scandir $dir, 2
91     or return;
92    
93     for my $file (@$files) {
94     my $name = $file;
95     next unless $name =~ s/\.map$//;
96     utf8::decode $name;
97    
98     scan_map "s$map$name", "$dir/$file";
99     }
100    
101     &scan_static ("$dir/$_", "$map$_/")
102     for @$dirs;
103     }
104    
105 root 1.5 sub reload {
106     my $start = Event::time;
107 root 1.1
108 root 1.5 # 1. check for maps no longer existing
109 root 1.1
110 root 1.5 # 2. scan all static maps
111     scan_static $cf::MAPDIR, "/";
112 root 1.1
113 root 1.5 # 3. scan all dynamic maps
114     for my $path (@{ cf::map::tmp_maps or [] }, @{ cf::map::random_maps or [] }) {
115 root 1.1 # my $map = cf::map::find $path;
116     # extract_map_tags "t/$map", $path;
117 root 1.5 }
118    
119 root 1.1 # now hunt for all per-player maps
120     # scan_dir $cf::PLAYERDIR
121     # for my $login (@{ cf::player::list_logins or [] }) {
122     # for my $path (@{ cf::player::maps $login or [] }) {
123     # cf::cede_to_tick;
124     #
125     # $path =~ /^~[^\/]+(\/.*)$/
126     # or next; # doh
127     #
128     # my $base = cf::map::find $1;
129     #
130     # # skip maps without base maps on the assumption
131     # # that those are old, unresettable maps
132     # next unless $base;
133     #
134     # # skip unresettable maps, for speed
135     # next if $base->{deny_reset};
136     #
137     # my $map = cf::map::find $path;
138     #
139     # if ($map->{deny_reset}) {
140     # warn "found noreset map with resettable base map, resetting: $path\n";
141     # delete $map->{deny_reset};
142     # }
143     # }
144     # }
145    
146 root 1.5 warn sprintf "map-tag scan (%fs)", Event::time - $start;
147     }
148    
149     our $RELOAD_SCHEDULER = Event->timer (
150     after => 0,
151     interval => $SCHEDULE_INTERVAL,
152     data => cf::WF_AUTOCANCEL,
153     cb => Coro::unblock_sub {
154     $Coro::current->prio (Coro::PRIO_MIN);
155     reload;
156     },
157     );
158 root 1.1
159 root 1.5 # find all objects with the given tag, or at least try to
160 root 1.2 sub find($) {
161     my ($tag) = @_;
162 root 1.1
163 root 1.3 utf8::encode (my $key = $tag);
164     BDB::db_get $db_target, undef, $key, my $data;
165 root 1.2 utf8::decode $data;
166    
167 root 1.4 map { $_->load; $_->find_tagged_objects ($tag) }
168 root 1.2 grep $_,
169     map { cf::map::find $_ }
170     grep s/^s//,
171     split /\x00/, $data
172     }