/[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.12 - (hide annotations) (download)
Mon Sep 21 09:10:40 2009 UTC (15 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.11: +46 -12 lines
++ swe/lib/SWE/DB/ChangeLog	21 Sep 2009 09:05:45 -0000
2009-09-21  Wakaba  <wakaba@suika.fam.cx>

	* Lock.pm (check_lockability): Don't allow the same level of lock
	type being locked twice to avoid deadlocks caused by same level of
	locks.

++ swe/lib/SWE/Object/ChangeLog	21 Sep 2009 09:10:06 -0000
	* Document.pm (repo, prop_untainted, untainted_prop, save_prop,
	locked): New method.  Introduced the concept of "tainted" such
	that we can access to the property in the locked code fragment
	without being afraid to update the property using old values.
	(get_or_create_graph_node): Updated to utilize |prop| family of
	method with locks.

	* Graph.pm (repo, lock, unlock): New methods.
	(add_nodes, create_node, schelling_update): Locks the database
	before the modifications.

	* Repository.pm (graph, get_document_by_id): New methods.

	* Node.pm (repo): New method.

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

++ swe/lib/suikawiki/ChangeLog	21 Sep 2009 09:10:27 -0000
	* main.pl: Made the graph node view to lock the database.

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

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24  
Google Analytics is used in this page; Cookies are used. 忍者AdMax is used in this page; Cookies are used. Privacy policy.