ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/map-tags.ext
Revision: 1.2
Committed: Tue Sep 11 13:27:53 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-2_2
Changes since 1.1: +21 -0 lines
Log Message:
progress

File Contents

# User Rev Content
1 root 1.1 #! perl # mandatory
2    
3     our $SCHEDULE_INTERVAL = $cf::CFG{extractor_schedule_interval} || 3600;
4    
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     cf::async_ext {
106     $Coro::current->prio (Coro::PRIO_MIN);
107    
108     while () {
109     my $start = Event::time;
110    
111     # 1. check for maps no longer existing
112    
113     # 2. scan all static maps
114     scan_static $cf::MAPDIR, "/";
115    
116     # 3. scan all dynamic maps
117     for my $path (@{ cf::map::tmp_maps or [] }, @{ cf::map::random_maps or [] }) {
118     # my $map = cf::map::find $path;
119     # extract_map_tags "t/$map", $path;
120     }
121    
122     # now hunt for all per-player maps
123     # scan_dir $cf::PLAYERDIR
124     # for my $login (@{ cf::player::list_logins or [] }) {
125     # for my $path (@{ cf::player::maps $login or [] }) {
126     # cf::cede_to_tick;
127     #
128     # $path =~ /^~[^\/]+(\/.*)$/
129     # or next; # doh
130     #
131     # my $base = cf::map::find $1;
132     #
133     # # skip maps without base maps on the assumption
134     # # that those are old, unresettable maps
135     # next unless $base;
136     #
137     # # skip unresettable maps, for speed
138     # next if $base->{deny_reset};
139     #
140     # my $map = cf::map::find $path;
141     #
142     # if ($map->{deny_reset}) {
143     # warn "found noreset map with resettable base map, resetting: $path\n";
144     # delete $map->{deny_reset};
145     # }
146     # }
147     # }
148    
149     warn sprintf "map-tag scan (%fs)", Event::time - $start;
150     Coro::Timer::sleep $SCHEDULE_INTERVAL;
151     }
152     };
153    
154 root 1.2 sub find($) {
155     my ($tag) = @_;
156 root 1.1
157 root 1.2 my @res;
158    
159     utf8::encode $tag;
160     BDB::db_get $db_target, undef, $tag, my $data;
161     utf8::decode $data;
162    
163     for my $map (
164     grep $_,
165     map { cf::map::find $_ }
166     grep s/^s//,
167     split /\x00/, $data
168     ) {
169     $map->load;
170    
171     warn "tag<$tag>map<$map>\n";#d#
172     }
173    
174     @res
175     }