/[suikacvs]/webroot/swe/lib/SWE/Object/Document.pm
Suika

Contents of /webroot/swe/lib/SWE/Object/Document.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations) (download)
Wed Sep 23 10:56:52 2009 UTC (15 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.13: +5 -4 lines
++ swe/lib/SWE/Object/ChangeLog	23 Sep 2009 10:56:11 -0000
	* Document.pm (lock): Typo; it did not lock in fact, orz.

	* Graph.pm (schelling_update): Reuse the |repo| object's child
	objects where possible to avoid locking timing problem and so on.

2009-09-23  Wakaba  <wakaba@suika.fam.cx>

++ swe/lib/suikawiki/ChangeLog	23 Sep 2009 10:56:43 -0000
2009-09-23  Wakaba  <wakaba@suika.fam.cx>

	* main.pl: Lock for the document ID at the beginning of the
	neighbors view processing.

1 wakaba 1.1 package SWE::Object::Document;
2     use strict;
3     use warnings;
4 wakaba 1.7 use SWE::Lang qw/%ContentMediaType/;
5     use UNIVERSAL::require;
6 wakaba 1.1
7     sub new ($%) {
8     my $class = shift;
9     my $self = bless {@_}, $class;
10    
11     return $self;
12     }
13    
14 wakaba 1.3 sub new_id ($%) {
15     my $self = shift->new (@_);
16    
17 wakaba 1.4 ## NOTE: MUST be executed in names_lock.
18    
19 wakaba 1.3 my $idgen = $self->db->id;
20     my $id = $idgen->get_next_id;
21     $self->{id} = $id;
22    
23     return $self;
24     } # new_id
25    
26 wakaba 1.12 sub db ($) { $_[0]->{db} }
27 wakaba 1.1
28 wakaba 1.12 sub repo ($) { $_[0]->{repo} }
29    
30     sub id ($) { $_[0]->{id} }
31 wakaba 1.1
32 wakaba 1.7 sub reblessed : lvalue { $_[0]->{reblessed} }
33    
34     sub rebless ($) {
35     my $self = shift;
36     return if $self->reblessed;
37    
38 wakaba 1.9 my $id = $self->id;
39     my $module;
40     if (defined $id) {
41     my $ct = $self->content_media_type;
42     $module = $ContentMediaType{$ct}->{module} || $ContentMediaType{'text/x-suikawiki'}->{module};
43     } else {
44     $module = 'SWE::Object::Document::NotYet';
45     }
46 wakaba 1.7 $module->require or die $@;
47     bless $self, $module;
48    
49     $self->reblessed = 1;
50     }
51    
52 wakaba 1.10 ## ------ Metadata ------
53    
54 wakaba 1.8 sub prop ($) {
55     my $self = shift;
56 wakaba 1.12 return $self->{prop} ||= do {
57     $self->prop_untainted = 0 unless $self->locked;
58     $self->db->id_prop->get_data ($self->id);
59     };
60 wakaba 1.8 } # prop
61    
62 wakaba 1.13 sub prop_untainted ($) : lvalue { $_[0]->{prop_untainted} }
63 wakaba 1.12
64     sub untainted_prop ($) {
65     my $self = shift;
66     delete $self->{prop} unless $self->prop_untainted;
67 wakaba 1.13 $self->prop_untainted = 1;
68 wakaba 1.12 return $self->prop;
69     } # untainted_prop
70    
71     sub save_prop ($) {
72     my $self = shift;
73    
74     $self->lock;
75    
76     unless ($self->prop_untainted) {
77 wakaba 1.14 require Carp;
78     die "Can't save a tainted prop object" . Carp::longmess ();
79 wakaba 1.12 }
80    
81     my $prop = $self->prop or die "Can't save an uncreated prop object";
82     $self->db->id_prop->set_data ($self->id => $prop);
83    
84     $self->unlock;
85     } # save_prop
86    
87 wakaba 1.7 sub content_media_type ($) {
88 wakaba 1.8 my $self = shift;
89     return $self->prop->{'content-type'} // 'text/x-suikawiki';
90     } # content_media_type
91 wakaba 1.7
92 wakaba 1.1 sub associate_names ($$%) {
93     my ($self, $names, %args) = @_;
94    
95     ## NOTE: names_lock MUST be executed before the invocation.
96    
97     my $id = $self->id;
98     my $time = $args{time} || time;
99     my $sw3_pages = $self->{sw3_pages}; ## TODO: ...
100    
101     my $vc = $self->db->vc;
102    
103     my $name_prop_db = $self->{name_prop_db}; ## TODO: ...
104     local $name_prop_db->{version_control} = $vc;
105    
106     my $name_history_db = $self->db->name_history;
107     local $name_history_db->{version_control} = $vc;
108    
109     for my $name (keys %$names) {
110     my $name_props = $name_prop_db->get_data ($name);
111     unless (defined $name_props) {
112     my $sw3id = $sw3_pages->get_data ($name);
113     main::convert_sw3_page ($sw3id => $name); ## TODO: ...
114    
115     $name_props = $name_prop_db->get_data ($name);
116     unless (defined $name_props) {
117     $name_history_db->append_data ($name => [$time, 'c']);
118     }
119     }
120    
121     push @{$name_props->{id} ||= []}, $id;
122     $name_props->{name} = $name;
123     $name_prop_db->set_data ($name => $name_props);
124    
125     $name_history_db->append_data ($name => [$time, 'a', $id]);
126     }
127    
128     my $user = $args{user} || '(anon)';
129     $vc->commit_changes ("id=$id created by $user");
130     } # associate_names
131    
132 wakaba 1.10 sub title ($) {
133     my $self = shift;
134    
135     my $prop = $self->prop;
136    
137     my $title = $prop->{title};
138     return $title if defined $title and length $title;
139    
140     $title = [keys %{$prop->{name}}]->[0] // ''; ## XXXTODO: title-type
141     return $title;
142     } # title
143    
144     ## ------ Indexing and Graph ------
145    
146 wakaba 1.2 sub update_tfidf ($$) {
147     my ($self, $doc) = @_; ## TODO: $doc should not be an argument
148    
149     ## It is REQUIRED to lock the $id before the invocation of this
150     ## method to keep the consistency of tfidf data for the $id.
151    
152     my $id = $self->id;
153    
154     my $tfidf_db = $self->db->id_tfidf;
155    
156     require SWE::Data::FeatureVector;
157    
158     my $deleted_terms = SWE::Data::FeatureVector->parse_stringref
159     ($tfidf_db->get_data ($id))->as_key_hashref;
160    
161     my $tc = $doc->document_element->text_content;
162    
163     ## TODO: use element semantics...
164    
165     my $orig_tfs = {};
166     my $all_terms = 0;
167     main::for_unique_words ($tc => sub {
168     $orig_tfs->{$_[0]} = $_[1];
169     $all_terms += $_[1];
170     }); ## TODO: XXX
171    
172     my $names_index_db = $self->db->name_inverted_index;
173     $names_index_db->lock;
174    
175     my $idgen = $self->db->id;
176     my $doc_number = $idgen->get_last_id;
177    
178     my $terms = SWE::Data::FeatureVector->new;
179     for my $term (keys %$orig_tfs) {
180     my $n_tf = $orig_tfs->{$term} / $all_terms;
181    
182     my $df = $names_index_db->get_count ($term);
183     my $idf = log ($doc_number / ($df + 1));
184    
185     my $tfidf = $n_tf * $idf;
186    
187     $terms->set_tfidf ($term, $tfidf);
188     $names_index_db->add_data ($term => $id => $tfidf);
189    
190     delete $deleted_terms->{$term};
191     }
192    
193     for my $term (keys %$deleted_terms) {
194     $names_index_db->delete_data ($term, $id);
195     }
196    
197     $tfidf_db->set_data ($id => \( $terms->stringify ));
198     } # update_tfidf
199    
200 wakaba 1.10 sub get_or_create_graph_node ($) {
201     my $self = shift;
202    
203 wakaba 1.12 $self->lock;
204 wakaba 1.10
205 wakaba 1.12 my $id_prop = $self->untainted_prop or do {
206     $self->unlock;
207 wakaba 1.14 die "Can't obtain untainted prop object";
208 wakaba 1.12 };
209 wakaba 1.10
210 wakaba 1.12 my $graph = $self->repo->graph;
211 wakaba 1.10 my $node;
212     my $node_id = $id_prop->{node_id};
213     if (defined $node_id) {
214     $node = $graph->get_node_by_id ($node_id);
215     } else {
216 wakaba 1.12 $node = $graph->create_node ($self->id);
217 wakaba 1.10 $node_id = $node->id;
218    
219     $id_prop->{node_id} = $node_id;
220 wakaba 1.12 $self->save_prop;
221 wakaba 1.10 }
222    
223 wakaba 1.12 $self->unlock;
224    
225 wakaba 1.10 return $node;
226     } # get_or_create_graph_node
227    
228     # ------ Locking ------
229    
230 wakaba 1.5 sub lock ($) {
231     my $self = shift;
232 wakaba 1.11 my $lock = $self->{lock} ||= $self->db->id_lock->get_lock ($self->id);
233 wakaba 1.14 $self->{lock_n}++ or $lock->lock;
234 wakaba 1.5 } # lock
235    
236     sub unlock ($) {
237     my $self = shift;
238     my $lock = $self->{lock};
239     $self->{lock_n}--;
240     if ($lock and $self->{lock_n} <= 0) {
241     $lock->unlock;
242     delete $self->{lock};
243     delete $self->{lock_n};
244 wakaba 1.12 delete $self->{prop_untainted};
245 wakaba 1.5 }
246     } # unlock
247 wakaba 1.12
248     sub locked ($) {
249 wakaba 1.14 return (($_[0]->{lock_n} // 0) > 0);
250 wakaba 1.12 } # locked
251 wakaba 1.10
252     # ------ Format Convertion ------
253 wakaba 1.5
254 wakaba 1.8 sub to_text ($) {
255     my $self = shift;
256    
257     return $self->{content_db}->get_data ($self->id); # XXX
258     } # to_text
259    
260     sub to_text_media_type ($) {
261     my $self = shift;
262     return $self->content_media_type;
263     } # to_text_media_type
264    
265     sub to_xml_media_type ($) {
266     return undef;
267     } # to_xml_media_type
268    
269     sub to_xml ($) {
270     return undef;
271     } # to_xml
272    
273     sub to_html_fragment ($) {
274     return (undef, undef);
275     } # to_html_fragment
276 wakaba 1.6
277 wakaba 1.1 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24