/[pub]/suikawiki/script/lib/Yuki/YukiWikiDB2.pm
Suika

Contents of /suikawiki/script/lib/Yuki/YukiWikiDB2.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Thu Jan 2 04:23:52 2003 UTC (23 years, 8 months ago) by w
Branch: MAIN
Branch point for: branch-suikawiki-1
Changes since 1.3: +3 -3 lines
*** empty log message ***

1 w 1.1 ###
2 w 1.4 ### $Id: YukiWikiDB2.pm,v 1.3 2003/01/02 04:20:05 w Exp $
3 w 1.1 ###
4    
5     # Yuki::YukiWikiDB2.pm - Pure Perl database module, esp. for YukiWiki.
6     #
7     # Copyright (C) 2002 by Gokuaku.
8     # <[email protected]>, http://homepage1.nifty.com/dune/
9 w 1.4
10 w 1.1 # This program is free software; you can redistribute it and/or
11     # modify it under the same terms as Perl itself.
12    
13     require 5.004_71;
14     package Yuki::YukiWikiDB2;
15 w 1.4 ($VERSION) = q($Revision: 1.3 $) =~ m/\x20([\d.]+)\x20/;
16 w 1.3 use strict;
17 w 1.1
18    
19    
20     #
21     # _die - ��̿Ū�ʥ��顼ȯ�����˸ƤӽФ��ؿ���
22     # _warn - �ٹ�ȯ�����˸ƤӽФ��ؿ���
23     #
24     sub _die{
25     my $self = shift;
26     my $file = $self->{-logfile};
27     my $dir = $self->{-dir};
28     my $caller = join(" ",(caller 1)[1,2]);
29     my $msg = qq/ERR (@{[scalar localtime]}) $dir @_ $caller/;
30     push(@{$self->{-error}},$msg);
31     if($file){
32     # $file �ϲ���Ƥⵤ�ˤ��ʤ�
33     # �����������ˤʤ�Ȥ��� >> �� > ���Ѥ��롣
34     open(FILE,">>$file") or die qq(_die : $! "$file");
35     print FILE $msg,"\n";
36     close FILE;
37     }
38     die "$msg\n";
39     }
40     sub _warn{
41     my $self = shift;
42     my $file = $self->{-logfile};
43     my $dir = $self->{-dir};
44     my $caller = join(" ",(caller 1)[1,2]);
45     my $msg = qq/WRN (@{[scalar localtime]}) $dir @_ $caller/;
46     push(@{$self->{-error}},$msg);
47     if($file){
48     # $file �ϲ���Ƥⵤ�ˤ��ʤ�
49     # �����������ˤʤ�Ȥ��� >> �� > ���Ѥ��롣
50     open(FILE,">>$file") or die qq(_warn : $! "$file");
51     print FILE $msg,"\n";
52     close FILE;
53     }
54     return $msg;
55     }
56    
57    
58    
59     #
60     # ���顼��å������ν���
61     #
62     # errmsg - ���顼��å�������ʸ����ˤ�������ޤ���
63     # ���顼���ʤ����� undef ���֤��ޤ���
64     # clr_errmsg - ���顼��å�������õ�ޤ���
65     # ����ͤϾ�� undef �Ǥ���
66     #
67     # errlog - ���顼�����ʥե�����ˤ��ɤ߽Ф��ޤ���
68     # ���顼���ʤ����� undef ���֤��ޤ���
69     # clr_errlog - ���顼�����ʥե�����ˤ�õ�ޤ���
70     # ����ͤϾ�� undef �Ǥ���
71     #
72     sub errmsg{
73     my $self = shift or die qq(errmsg : usage error.);
74     my @log = @{$self->{-error}};
75     if(wantarray){
76     return @log;
77     }else{
78     return @log ? join("",@log) : undef;
79     }
80     }
81     sub errlog{
82     my $self = shift or die qq(errlog : usage error.);
83     my $file = $self->{-logfile} or return;
84     open(FILE,$file) or return;
85     my @log = <FILE>;
86     close FILE;
87     if(wantarray){
88     return @log;
89     }else{
90     return @log ? join("",@log) : undef;
91     }
92     }
93     sub clr_errmsg{
94     my $self = shift or die qq(clr_errmsg : usage error.);
95     $self->{-error} = [];
96     return undef;
97     }
98     sub clr_errlog{
99     my $self = shift or die qq(clr_errlog : usage error.);
100     my $file = $self->{-logfile};
101     -e $file and unlink $file;
102     return undef;
103     }
104    
105    
106    
107     #
108     # ���Υե�����̾������
109     #
110     # �ϥå�������Ƥϡ��㤨�� $hash{foo} = 'bar' ��¹Ԥ����
111     # foo.txt �Ȥ����ե������ bar �Ƚ񤭹��ޤ�ޤ��ʣ���ˤĤ�
112     # ���ե����뤬���������ˡ�
113     # filename �ǡ����Υե�����̾��foo�ˤ����뤳�Ȥ��Ǥ��ޤ���
114     # bkupname �ϥХå����åץե�����̾�����ޤ���
115     # �����ե������̵ͭ�˴ط��ʤ�������Ū�˥ե�����̾���֤��ޤ���
116     #
117     # ex. $filename = $DB->filename('foo');
118     # ex. $filename = $DB->bkupname('foo');
119     #
120     sub filename{
121     my($self,$key) = @_;
122     &{$self->{-encode}}($key);
123     return $self->{-dir}.$key.$self->{-extension};
124     }
125     sub bkupname{
126     my($self,$key) = @_;
127     &{$self->{-encode}}($key);
128     return $self->{-dir}.$key.'.bak';
129     }
130    
131    
132    
133     #
134     # ���å�
135     # ���å��������⡼�ɡ�0:���å����ʤ� 1:��ͭ 2:��¾�ˤȡ�
136     # ���å��ե�����̾�ʥ��å���������Τ�Ρˤ��Ϥ��ޤ���
137     # ���å�����������ȡ����������å��ե�����̾���֤��ޤ���
138     # ���Ԥ���� undef ���֤��ޤ���
139     # �̾���δؿ���桼�����ƤӽФ����ȤϤ���ޤ���
140     #
141     sub _lock{
142     my($self,$mode,$from) = @_;
143     my $to = $from;
144     if($mode == 0){
145     # ���⤻�������
146     return($self->{-lock} = $to);
147     }elsif($mode == 1){
148     # ��ͭ���å�
149     $to =~ s/\.\.\.lock$/.1.@{[time]}.lock/x
150     or
151     $to =~ s/\.(\d+)\.(\d+)\.lock$/.@{[$1+1]}.@{[time]}.lock/x
152     or
153     return; # ���֤���¾���å�����Ƥ��롣
154     }else{
155     # ��¾���å�
156     $to =~ s/\.\.\.lock$/..@{[time]}.lock/x
157     or
158     return; # ���֤󡢶�ͭ���å�����Ƥ��롣
159     }
160     if(rename($from => $to)){
161     # ���å�����
162     $self->{-mode} = $mode;
163     return($self->{-lock} = $to);
164     }else{
165     # ���å��Ǥ��ʤ��ä��� undef ���֤�
166     return;
167     }
168     }
169    
170    
171    
172     #
173     # �������å�
174     # ���å��������⡼�ɡ�0:���å����ʤ� 1:��ͭ 2:��¾�ˤȡ�
175     # ���å��ե�����̾���Ϥ��ޤ���
176     # ���δؿ��ϸ��ߤΥ��å����֤�̵�뤹��Τǡ��ʤ����餯�˾��
177     # ���å����������ޤ���
178     # ���å�����������ȡ����������å��ե�����̾���֤��ޤ���
179     # ���Ԥ���� undef ���֤��ޤ���
180     # �̾���δؿ���桼�����ƤӽФ����ȤϤ���ޤ���
181     #
182     sub _force_lock{
183     my($self,$mode,$from) = @_;
184     my $to = $from;
185     if($mode == 0){
186     # ���⤻�������
187     return($self->{-lock} = $to);
188     }elsif($mode == 1){
189     # ������ͭ���å�
190     $to =~ s/\.(\d*)\.(\d*)\.lock$/.1.@{[time]}.lock/x
191     or return;
192     }else{
193     # ������¾���å�
194     $to =~ s/\.(\d*)\.(\d*)\.lock$/..@{[time]}.lock/x
195     or return;
196     }
197     if(rename($from => $to)){
198     $self->{-mode} = $mode;
199     return($self->{-lock} = $to);
200     }
201     # ���å��Ǥ��ʤ��ä��� undef ���֤�
202     return;
203     }
204    
205    
206    
207     #
208     # ���å����
209     # ���å��ե�����̾���Ϥ��ޤ���
210     # ������å�����������ȡ����������å��ե�����̾���֤��ޤ���
211     # ���Ԥ���� undef ���֤��ޤ���
212     # �̾���δؿ���桼�����ƤӽФ����ȤϤ���ޤ���
213     #
214     sub _unlock{
215     my($self,$from) = @_;
216     my $mode = $self->{-mode};
217     my $to = $from;
218     if($mode == 0){
219     # ���⤷�ʤ�
220     return($self->{-lock} = $to);
221     }elsif($mode == 1){
222     # ��ͭ���å����
223     $to =~ s/\.(\d+)\.(\d+)\.lock$
224     /.@{[$1 == 1 ? "." : ($1-1).".".$2]}.lock/x
225     or return;
226     }else{
227     # ��¾���å����
228     $to =~ s/\.\.(\d+)\.lock$/...lock/x
229     or return;
230     }
231     if(rename($from => $to)){
232     # ������å�����
233     $self->{-mode} = 0;
234     return($self->{-lock} = $to);
235     }else{
236     # ������å��Ǥ��ʤ��ä��� undef ���֤�
237     return;
238     }
239     }
240    
241    
242    
243     #
244     # ���󥹥ȥ饯��
245     #
246     sub new{ shift->TIEHASH(@_) }
247    
248    
249    
250     #
251     # �����θ���
252     #
253     sub _check_opt{
254     my($dbname,$opt) = @_;
255    
256     $dbname ||= q(YukiWikiDB2);
257     (my $dir = $dbname) =~ s/[\\\/]/\//g;
258     $dir =~ s/[\/]*$/\//;
259    
260     my $self = {
261     -dir => $dir, # �ǡ����١���̾�ʥǥ��쥯�ȥ��
262     -mode => 0, # ���å������� 0 �ʳ����ͤˤʤ�
263     -lock => undef, # ���å��ե�����̾
264     -keys => [], # �����ꥹ��
265     -error => [], # ���顼��å�����
266     -bkup => $opt->{-backup}, # 1:�Хå����åפ���
267     -bkup_next => $opt->{-backup}, # 1:����Хå����åפ���
268     -trytime => $opt->{-trytime} || 8, # ��ȥ饤��� [����/��]
269     -timeout => $opt->{-timeout} || 20, # ��Ĺ���å����� [��]
270     -logfile => $opt->{-logfile}, # �����ե�����
271    
272     -extension => (exists $opt->{-extension} ?
273     $opt->{-extension} : '.txt'), # ��ĥ��
274    
275     -cache => {},
276     -headline => {},
277     };
278    
279    
280    
281     # �⡼�ɤΥ����å�
282     my $mode = $opt->{-lock};
283     if($mode == 0){
284     ;;;
285     }elsif($mode == 1 or $mode == 2 or $mode == 5 or $mode == 6){
286     ;;;
287     }else{
288     _die($self,qq{_check_opt : unknown lock mode "$mode"});
289     }
290    
291     # �����Υ��󥳡��ɥ᥽�å�
292     my $method = $opt->{-encode};
293     if("\U$method" eq 'YUKIWIKI' or not defined $method){
294     # YukiWiki �ߴ�
295     $self->{-encode} = sub{ $_[0] = uc unpack("H*",$_[0]) };
296     $self->{-decode} = sub{ $_[0] = pack("H*",$_[0]) };
297     }elsif("\U$method" eq 'NONE'){
298     # dune/wiki �ߴ��ʥ��󥳡��ɤ��ʤ���
299     $self->{-encode} = sub{ $_[0] };
300     $self->{-decode} = sub{ $_[0] };
301     }elsif($method eq 'RFC'){
302     # RFC2396/2732 [^A-Za-z0-9\-_.!~*'()]
303     $self->{-encode} = sub{
304     $_[0] =~ s/([^\w\-.!~()])/
305     sprintf('%%%02X',ord $1)/eg
306     };
307     $self->{-decode} = sub{
308     $_[0] =~ s/%([0-9A-Fa-f]{2})/chr(hex $1)/eg;
309     };
310     }elsif($method eq 'rfc'){
311     $self->{-encode} = sub{
312     $_[0] =~ s/([^\w\_!~()])/
313     sprintf('%%%02x',ord $1)/eg
314     };
315     $self->{-decode} = sub{
316     $_[0] =~ s/%([0-9A-Fa-f]{2})/chr(hex $1)/eg;
317     };
318     }else{
319     _die($self,qq{_check_opt : unkown encode method "$method"});
320     }
321    
322     # �ʰץ����å�
323     foreach(keys %{$opt}){
324     next if m/^-\w+$/;
325     _die($self,qq{_check_opt : unknown option "$_"});
326     }
327    
328     return $self;
329     }
330    
331    
332    
333     #
334     # �ǥ��쥯�ȥ�򷡤롣
335     # ���å��ե�������롣
336     #
337     sub _init{
338     my($self) = @_;
339     chop(my $dbname = $self->{-dir}); # �Ǹ�� / ����
340 w 1.2 my $path;
341 w 1.1 foreach(split(m/[\/\\]/,$dbname)){
342     if(not -d ($path .= "$_/")){
343     mkdir($path,0777) or $self->_die(qq{_init : $! "$path"});
344     }
345     }
346     opendir(DIR,"$dbname/..") or $self->_die(qq{_init : $! "$dbname/.."});
347     my @lockfile = readdir DIR;
348     closedir DIR;
349     my($lockfile);
350     foreach(@lockfile){
351     if(m/^\Q$dbname\E\.(\d*)\.(\d*)\.lock$/){
352     last;
353     }
354     }
355     if(not defined $lockfile){
356     $lockfile = "$dbname...lock";
357     open(FILE,">$lockfile") or $self->_die(qq{_init : $! "$lockfile"});
358     # print FILE scalar localtime,"\n";
359     close FILE;
360     }else{
361     $self->_die(qq{_init : lockfile already exists. "$lockfile"});
362     };
363     }
364    
365    
366    
367     #
368     # �ϥå��� %db ��ե�����˷�ӤĤ��롣
369     # tie(%db,"Yuki::YukiWikiDB2",$dbname,%opt)
370     #
371     # �ǽ�ΰ��� $dbname �ϥǡ����ʥե�����ˤ���¸����ǥ��쥯�ȥ�̾
372     #
373     # ����ʹߤϥ��ץ���ʥ�ΰ����ǡ��ϥå��� %opt �η��ǻ��ꤹ�롣
374     #
375     # -lock => ���å��⡼��
376     # 0 : ���å����ʤ�����ά���Υǥե����
377     # 1 : (LOCK_SH) ��ͭ���å�����ȥ饤����
378     # 2 : (LOCK_EX) ��¾���å�����ȥ饤����
379     # 5 : (LOCK_SH|LOCK_NB) ��ͭ���å�����ȥ饤�ʤ�
380     # 6 : (LOCK_EX|LOCK_NB) ��¾���å�����ȥ饤�ʤ�
381     # 8 : (LOCK_UN) �Ȥ�ʤ����ȡ�
382     # ���å��⡼�� 0 �ϡ����ߤΥ��å����֤˴ط��ʤ��ǡ����١�������³
383     # ���ޤ������Τ��ᶦͭ���å���Υǡ����١����˥��å��⡼�� 0 ��
384     # ��³���ƥǡ�����񤭹��ࡢ�Ȥ��ä����Ȥ��Ǥ��Ƥ��ޤ��ޤ��ʻ��͡ˡ�
385     # ���������å��⡼�� 0 ��¾�Υ��å��⡼�ɤΥ֥��å��⤷�ޤ���
386     #
387     # -trytime => ���å��ӥ������˥�ȥ饤��������[����/��]�ˤ����
388     # ���ޤ��������ȥ饤������ˣ��õٻߤ��ޤ���
389     # -timeout => ���å��򤫤��Ƥ������Ĺ���֡�ñ�� [��]�ˤ���ꤷ��
390     # �����ץ����������å����������˰۾ェλ������
391     # ����к��ѤǤ���
392     # -trytime < -timeout : ���å���ȥ饤�Ǽ��Ԥ����ǽ������
393     # -trytime = -timeout : ��ȥ饤���Ը�Ͼ�˶������å�
394     #
395     # -logfile => �����ե�����̾
396     # ���顼���˥󥰤�ȯ�������Ȥ��ˡ��������Ƥ��񤭹��ޤ�
397     # ��ե�����Ǥ���CGI ��ư���ʤ��Ȥ��Υҥ�Ȥˤʤ�ޤ�����
398     # �å���ȥ饤�����˥󥰤��񤭹��ޤ��Τǡ�����������
399     # ���λ��ͤˤʤ�ޤ���
400     #
401     # -extension => �ե�����ˤĤ����ĥ��
402     #
403     sub TIEHASH{
404     my($class,$dbname,%opt) = @_;
405     my $self = bless(_check_opt($dbname,\%opt) => $class);
406     my $mode = $opt{-lock} & ~4;
407     my $block = $opt{-lock} & 4;
408    
409     # �����
410     # rename �ǥǥ��쥯�ȥ�̾���ѹ����Ǥ��뤫�ɤ����ϼ�����¸�ʤΤǡ�
411     # ���å��ե�������ä� rename ���롣
412     if(not -d $self->{-dir}){
413     $self->_init();
414     }
415    
416     # ����������å�����
417     chop($dbname = $self->{-dir});
418     my $lock = "$dbname...lock";
419     if($self->_lock($mode,$lock)){
420     # ���å������ʤ����Ƥ��������Ǵ�λ�����
421     ;;;
422     }elsif($block){
423     # ���å����ԡʥ������Ȥʤ���
424     $self->_warn(qq{TIEHASH : lock blocked. "$lock"});
425     }else{
426     # ���å����ԡʥ������ȡ�
427     my $trytime = $self->{-trytime};
428     TRY:foreach(my $try = 0;$try < $trytime;++$try){
429    
430     # ���å��ե������õ��
431     opendir(DIR,"$dbname/..")
432     or $self->_die(qq{TIEHASH : $! "$dbname/.."});
433     my @nglock = readdir DIR;
434     closedir DIR;
435    
436     my($nglock,$duration);
437     foreach(@nglock){
438     if(m/^\Q$dbname\E\.(\d*)\.(\d*)\.lock$/){
439     $nglock = qq($dbname.$1.$2.lock);
440     $duration = time - $2 if $2;
441     last;
442     }
443     }
444    
445 w 1.3 # ���å��ե����뤬���Ĥ���ʤ�?
446 w 1.1 if(not defined $nglock){
447 w 1.3 ## Maybe it is the first time to use this DB
448     open NEWLOCK, "> $lock" or $self->_die(qq{TIEHASH : lockfile not found. "$lock"});
449     close NEWLOCK;
450     return TIEHASH (@_);
451 w 1.1 }
452    
453     # ��¸���å��򹹿����ƥ��å�
454     if($self->{-timeout} < $duration){
455     # �۾�ʥ��å�
456     $self->_warn(qq{TIEHASH : dated lock found ($duration). "$nglock"});
457     last TRY if $self->_force_lock($mode,$nglock);
458     $self->_warn(qq{TIEHASH : force lock failure. "$nglock"});
459     }else{
460     # ����ʥ��å�
461     last TRY if $self->_lock($mode,$nglock);
462     }
463    
464     # ��������
465     $self->_warn(qq{TIEHASH : retry lock ($try/$trytime). "$nglock"});
466     sleep 1;
467     }
468     }
469    
470     if(not $self->{-lock}){
471     # ���å�����
472     $self->_warn(qq{TIEHASH : lock failure. "$lock"});
473     return;
474     }else{
475     return $self;
476     }
477     }
478    
479    
480    
481     #
482     # UNTIE
483     # ������ץȤ�λ�����˥ǡ����١������Ĥ������
484     # untie %db; �ʤɤȤ��롣
485     # UNTIE �� untie ��˺���ȸƤФ�ʤ��ʥ��å�����������
486     # ���ˤΤǡ����֥������ȤΥǥ��ȥ饯������⼫ưŪ�˸ƤӽФ�
487     # ���褦�ˤ�����
488     #
489     sub UNTIE{
490     my($self) = @_;
491     my $mode = $self->{-mode};
492     my $lock = $self->{-lock};
493    
494     if(!$mode or $self->_unlock($lock)){
495     # ������å������ʤ����Ƥ��������Ǵ�λ�����
496     ;;;
497     }else{
498     # ������å����ԡ����å��ե������õ���ʶ�ͭ���å�����
499     chop(my $dbname = $self->{-dir});
500     my $trytime = $self->{-trytime};
501     TRY:foreach(my $try = 0;$try < $trytime;++$try){
502     opendir(DIR,"$dbname/..") or $self->_die(qq{UNTIE : $! "$dbname/.."});
503     my @nglock = readdir DIR;
504     closedir DIR;
505    
506     my($nglock,$duration);
507     foreach(@nglock){
508     if(m/^\Q$dbname\E\.(\d*)\.(\d*)\.lock$/){
509     $nglock = qq($dbname.$1.$2.lock);
510     $duration = time - $2 if $2;
511     last;
512     }
513     }
514     last TRY if $self->_unlock($nglock);
515    
516     if($nglock eq "$dbname...lock"){
517     # ���ꤨ�ʤ��Ϥ��������ʤ����Ȥ��ɤ����롣
518     $self->_warn(qq{UNTIE : not locked. "$nglock"});
519     last TRY;
520     }
521    
522     # ��������(sleep �ʤ�)
523     $self->_warn(qq{UNTIE : retry unlock ($try/$trytime). "$nglock"});
524     }
525    
526     if($self->{-lock} eq $lock){
527     $self->_warn(qq{UNTIE : unlock failure. "$lock"});
528     }
529     }
530     return;
531     }
532    
533    
534    
535     #
536     # �ǥ��ȥ饯��
537     #
538     # DESTROY �� untie ��˺��Ƥ�ƤФ�롣
539     # new �ޤ��� tie �Υ������פγ��˽Ф��Ȥ���perl ��λ���Ȥ���
540     # �˸ƤФ�뤫�����뤤������ͤ�ȤäƤ����硢���֥�������
541     # �����Ȥ���ʤ��ʤä��Ȥ����ޤ�������Ū�� untie ��³���� undef
542     # �����Ȥ��˸ƤФ�롣�Ȥˤ��������Ĥ���ɬ���ƤФ��ߤ�������
543     #
544     sub DESTROY{
545     my($self) = @_;
546     if($self->{-mode}){
547     # untie ˺��ο�����
548     $self->_warn(qq{DESTROY : invoke untie method.}) if 0;
549     $self->UNTIE();
550     }
551     return;
552     }
553    
554    
555    
556     #
557     # �񤭹���
558     #
559     sub STORE{
560     my($self,$key,$val) = @_;
561     my $mode = $self->{-mode};
562     $self->_die(qq{STORE : method not allowd, mode="$mode"}) if $mode == 1;
563     my $file = $self->filename($key);
564     my $temp = "$file.".time;
565     my $bkup = $self->bkupname($key);
566     open(FILE,">$temp") or $self->_die(qq{STORE : $! "$temp"});
567     binmode FILE;
568     print FILE $val;
569     close FILE;
570     if($self->{-bkup_next}){
571     if(-e $bkup){
572     unlink $bkup or $self->_die(qq{STORE : $! "$bkup"});
573     }
574     if(-e $file){
575     rename($file => $bkup) or $self->_die(qq{STORE : $! "$file" => "$bkup"});
576     }
577     }else{
578     if(-e $file){
579     unlink $file or $self->_die(qq{STORE : $! "$file"});
580     }
581     }
582     rename($temp => $file) or $self->_die(qq{STORE : $! "$temp" => "$file"});
583     $self->{-bkup_next} = $self->{-bkup};
584     $self->{-cache}->{-key} = $key;
585     $self->{-cache}->{-val} = $val;
586     delete $self->{-headline}->{$key};
587     return $val;
588     }
589    
590    
591    
592     #
593     # �ɤ߽Ф�
594     #
595     sub FETCH{
596     my($self,$key) = @_;
597     if($self->{-cache}->{-key} eq $key){
598     return $self->{-cache}->{-val};
599     }
600     my $file = $self->filename($key);
601     if(-e $file){
602     open(FILE,$file) or $self->_die(qq{FETCH : $! "$file"});
603     binmode FILE;
604     local $/ = undef;
605     my $val = <FILE>;
606     close FILE;
607     $self->{-cache}->{-key} = $key;
608     $self->{-cache}->{-val} = $val;
609     return $val;
610     }else{
611     return;
612     }
613     }
614    
615    
616    
617     #
618     # ���
619     #
620     sub DELETE{
621     my($self,$key) = @_;
622     my $file = $self->filename($key);
623     my $bkup = $self->bkupname($key);
624     my $mode = $self->{-mode};
625     $self->_die(qq{DELETE : method not allowd, mode="$mode"}) if $mode == 1;
626     if($self->{-bkup_next}){
627     if(-e $bkup){
628     unlink $bkup or $self->_die(qq{DELETE : $! "$bkup"});
629     }
630     if(-e $file){
631     rename($file => $bkup)
632     or $self->_die(qq{DELETE : $! "$file" => "$bkup"});
633     }
634     }else{
635     if(-e $file){
636     unlink $file or $self->_die(qq{DELETE : $! "$file"});
637     }
638     }
639     $self->{-bkup_next} = $self->{-bkup};
640     $self->{-cache}->{-key} = undef;
641     $self->{-cache}->{-val} = undef;
642     delete $self->{-headline}->{$key};
643     return;
644     }
645    
646    
647    
648     #
649     # ¸�ߥ����å�
650     #
651     sub EXISTS{
652     my($self,$key) = @_;
653     my $file = $self->filename($key);
654     return -e $file;
655     }
656    
657    
658    
659     #
660     # ���ƥ졼��
661     #
662     sub FIRSTKEY{
663     my($self) = @_;
664     @{$self->{-keys}} = $self->_list_all();
665     my $tmp = shift @{$self->{-keys}};
666     return defined $tmp ? &{$self->{-decode}}($tmp) : undef;
667     }
668     sub NEXTKEY{
669     my($self) = @_;
670     my $tmp = shift @{$self->{-keys}};
671     return defined $tmp ? &{$self->{-decode}}($tmp) : undef;
672     }
673    
674    
675    
676     #
677     # �ϥå������Τκ��
678     #
679     # �ե��������Ȥ���ˤ���ʶ��ϥå���ˤ���ˤ����ǡ��ǥ���
680     # ���ȥ����å��ե����롢���������֤ϻĤ��ʻ��͡��ˡ�
681     #
682     sub CLEAR{
683     my($self) = @_;
684     my $mode = $self->{-mode};
685     $self->_die(qq{CLEAR : method not allowd, mode="$mode"}) if $mode == 1;
686     my $dbname = $self->{-dir};
687     my @key = $self->_list_all();
688     foreach(@key){
689     my $file = $dbname.$_.$self->{-extension};
690     unlink $file or $self->_die(qq{CLEAR : $! "$file".});
691     }
692     if(0){
693     my $file = $self->{-logfile};
694     if(-e $file){
695     unlink $file or $self->_die(qq{CLEAR : $! "$file".});
696     }
697     }
698     if(0){
699     my $lock = $self->{-lock};
700     rmdir $dbname or $self->_die(qq{CLEAR : $! "$dbname".});
701     unlink $lock or $self->_die(qq{CLEAR : $! "$lock".});
702     $self->{-mode} = 0;
703     }
704     $self->{-cache}->{-key} = undef;
705     $self->{-cache}->{-val} = undef;
706     $self->{-headline} = {};
707     return;
708     }
709    
710    
711    
712     #
713     # ���ꤷ�������Υǡ����������� [byte] ���֤��ޤ���
714     # ��������ꤷ�ʤ��ȡ����ƤΥǡ����ι�ץ��������֤��ޤ�
715     # �ʤ������Хå����å��ѤΥǡ����䡢-extension �dz�ĥ�Ҥ�
716     # �Ѥ����ǡ����Ϸ׾夷�ޤ���ˡ�
717     #
718     sub size{
719     my $self = shift or die qq(size : usage error.);
720     my $dbname = $self->{-dir};
721     my @key = @_;
722     if(not @key){
723     @key = $self->_list_all();
724     }else{
725     foreach(@key){
726     &{$self->{-encode}}($_);
727     }
728     }
729     my $size;
730     foreach(@key){
731     $size += -s $dbname.$_.$self->{-extension};
732     }
733     return $size;
734     }
735    
736    
737    
738     #
739     # ������ ListAll
740     #
741     sub _list_all{
742     my $self = shift or die qq(_list_all : usage error.);
743     my $dbname = $self->{-dir};
744     my $ext = $self->{-extension};
745     my $extlen = length $ext;
746     opendir(DIR,$dbname) or $self->_die(qq{_list_all : $! "$dbname".});
747     my @key = grep(-f $dbname.$_,readdir DIR);
748     closedir DIR;
749     if($extlen){
750     @key = grep(index("$_/","$ext/") != -1,@key);
751     foreach(@key){
752     substr($_,-$extlen) = ''
753     }
754     }
755     return @key;
756     }
757     sub list_all{
758     my $self = shift or die qq(list_all : usage error.);
759     my @key = $self->_list_all();
760     foreach(@key){
761     &{$self->{-decode}}($_);
762     }
763     return @key;
764     }
765    
766    
767    
768     #
769     # ������̾�����Ѥ���
770     # ���������� 1 ���֤���
771     #
772     sub rename{
773     my $self = shift or die qq(rename : usage error.);
774     my($from,$to) = @_;
775     my $mode = $self->{-mode};
776     $self->_die(qq{rename : method not allowd, mode="$mode"}) if $mode == 1;
777     if(rename($self->filename($from) => $self->filename($to))){
778     if($self->{-cache}->{-key} eq $from
779     or $self->{-cache}->{-key} eq $to){
780     $self->{-cache}->{-key} = undef;
781     $self->{-cache}->{-val} = undef;
782     }
783     delete $self->{-headline}->{$from};
784     delete $self->{-headline}->{$to};
785     return 1;
786     }else{
787     $self->_warn(qq{rename : $! "$from" => "$to"});
788     return 0;
789     }
790     }
791    
792    
793    
794     #
795     # �����Υꥹ�Ȥ򡢹���������¤٤��֤��ʺǶ�Τ�Τ���Ƭ�ˡ�
796     #
797     sub sort_by_mtime{
798     my $self = shift or die qq(sort_by_mtime : usage error.);
799     my $dbname = $self->{-dir};
800     my @key = @_;
801     if(not @key){
802     @key = $self->_list_all();
803     }else{
804     foreach(@key){
805     &{$self->{-encode}}($_);
806     }
807     }
808     return map(&{$self->{-decode}}($_->[1]),
809     sort({$a->[0] <=> $b->[0] or $a->[1] cmp $b->[1]}
810     map([-M $dbname.$_.$self->{-extension},$_],@key)));
811     }
812    
813    
814    
815     #
816     # �����Υꥹ�Ȥ򡢥ǡ�������������¤٤��֤��ʾ�������Τ���Ƭ�ˡ�
817     #
818     sub sort_by_size{
819     my $self = shift or die qq(sort_by_size : usage error.);
820     my $dbname = $self->{-dir};
821     my @key = @_;
822     if(not @key){
823     @key = $self->_list_all();
824     }else{
825     foreach(@key){
826     &{$self->{-encode}}($_);
827     }
828     }
829     return map(&{$self->{-decode}}($_->[1]),
830     sort({$a->[0] <=> $b->[0] or $a->[1] cmp $b->[1]}
831     map([-s $dbname.$_.$self->{-extension},$_],@key)));
832     }
833    
834    
835    
836     #
837     # ���ΤΤʤ��Хå����åץե�����κ��
838     #
839     sub clean{
840     my $self = shift or die qq(clean : usage error.);
841     my $mode = $self->{-mode};
842     $self->_die(qq{clean : method not allowd, mode="$mode"}) if $mode == 1;
843     my $dbname = $self->{-dir};
844     my @key = @_;
845     if(not @key){
846     @key = $self->_list_all();
847     }else{
848     foreach(@key){
849     &{$self->{-encode}}($_);
850    
851     }
852     }
853     my $err;
854     foreach(@key){
855     if(-e $dbname.$_.".bak"){
856     unlink $dbname.$_.".bak" || ++$err;
857     }
858     }
859     return $err;
860     }
861    
862    
863    
864     #
865     # �ǡ����򥢡������֤��롣
866     # ��������ȥ��������֤Υ����� [byte] ���֤��ޤ���
867     # ���Ԥ���� undef ���֤��ޤ���
868     #
869     sub archive{
870     my $self = shift or die qq(archive : usage error.);
871     my $mode = $self->{-mode};
872     $self->_die(qq{archive : method not allowd, mode="$mode"}) if $mode == 1;
873     my(@key) = @_;
874     my $dir = $self->{-dir};
875     (my $archive = $dir) =~ s/\/$/.zip/;
876     eval <<' ###__CODE__###';
877     use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
878     use Archive::Zip::Tree;
879     my $zip = Archive::Zip->new();
880     if(@key){
881     foreach(@key){
882     my $member = $zip->addFile($self->filename($_),$dir.$_);
883     $member->desiredCompressionMethod(COMPRESSION_DEFLATED);
884     $member->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
885     }
886     }else{
887     $zip->addTreeMatching($dir,$dir,$self->{-extension}.'$');
888     foreach my $member ($zip->members()){
889     $member->desiredCompressionMethod(COMPRESSION_DEFLATED);
890     $member->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
891     }
892     }
893     $zip->zipfileComment(
894     "created by Yuki::YukiWikiDB2 $Yuki::YukiWikiDB2::VERSION"
895     ." with Archive::Zip $Archive::Zip::VERSION");
896     die(qq{write error "$archive"})
897     if $zip->writeToFileNamed("$archive") != AZ_OK;
898     ###__CODE__###
899     if($@){
900     $self->_warn(qq{archive : $@});
901     return undef;
902     }else{
903     return -s "$archive";
904     }
905     }
906    
907    
908    
909     #
910     # ������ RecentChanges(WhatsNew)
911     # $db->recent_changes() - sort_by_mtime() ��Ʊ�������ƤΥ������֤���
912     # $db->recent_changes(+n) - �ǿ��� n ����֤���
913     # $db->recent_changes(-n) - �ǸŤ� n ����֤���
914     #
915     sub recent_changes{
916     my $self = shift or die qq(recent_changes : usage error.);
917     my($n,$m) = @_;
918     my @key = $self->sort_by_mtime();
919     if($m){
920     return @key[$n..$m];
921     }elsif($n == 0){
922     return @key;
923     }elsif($n < 0){
924     $n = -$n - 1;
925     @key = reverse @key;
926     }else{
927     --$n;
928     }
929     return @key[0..$n];
930     }
931    
932    
933    
934     #
935     # �Хå����åץե饰�ΰ�����å�
936     #
937     # ���åȤ���ȼ��Υǡ����������˥Хå����åפ�Ȥ롣
938     # �Хå����åפ�Ȥä���ե饰�ϥꥻ�åȤ���롣
939     #
940     # ex. $DB->bkup_next(1); # ����Хå����åפ�Ȥ롣
941     # ex. $DB->bkup_next(0); # ����Хå����åפ�Ȥ�ʤ���
942     #
943     sub bkup_next{
944     my $self = shift or die qq(bkup_next : usage error.);
945     my($flag) = @_;
946     return defined $flag ?
947     ($self->{-bkup_next} = $flag) :
948     $self->{-bkup_next};
949     # $self->{-bkup_next} = $flag || 1
950     }
951    
952    
953    
954     #
955     # ���ߤΥǡ����ȥХå����åץǡ����Ȥδ֤κ�ʬ����롣
956     # ex. $diff = $DB->diff('foo');
957     # ex. @diff = $DB->diff('foo');
958     #
959     sub diff{
960     my $self = shift or die qq(diff : usage error.);
961     my($key) = @_;
962     my $diff;
963     eval <<' ###__CODE__###';
964     use Algorithm::Diff;
965     my $file = $self->filename($key);
966     my $bkup = $self->bkupname($key);
967     my(@old,@new);
968     local $/ = undef;
969    
970     if(-e $bkup){
971     open(FILE,$bkup) or die(qq{$! "$bkup"});
972     binmode FILE;
973     @old = split(m/[\x0D\x0A\x00]+/,<FILE>);
974     close FILE;
975     }
976     if(-e $file){
977     open(FILE,$file) or die(qq{$! "$file"});
978     binmode FILE;
979     @new = split(m/[\x0D\x0A\x00]+/,<FILE>);
980     close FILE;
981     }
982    
983     foreach(Algorithm::Diff::diff(\@old,\@new)){
984     foreach(@{$_}){
985     my($sign,$lineno,$text) = @{$_};
986     $diff .= qq($sign$text\n);
987     }
988     $diff .= "\n";
989     }
990     $diff =~ s/\n+$/\n/;
991     return $diff;
992     ###__CODE__###
993     if($@){
994     $self->_warn(qq{diff : $@});
995     return undef;
996     }else{
997     return $diff;
998     }
999     }
1000     sub traverse_diff{
1001     my $self = shift or die qq(traverse_diff : usage error.);
1002     my($key) = @_;
1003     my $diff;
1004     eval <<' ###__CODE__###';
1005     # http://www.stonehenge.com/merlyn/UnixReview/col35.html
1006     use Algorithm::Diff;
1007     my $file = $self->filename($key);
1008     my $bkup = $self->bkupname($key);
1009     my(@old,@new);
1010     local $/ = undef;
1011    
1012     if(-e $bkup){
1013     open(FILE,$bkup) or die(qq{$! "$bkup"});
1014     binmode FILE;
1015     @old = split(m/[\x0D\x0A\x00]+/,<FILE>);
1016     close FILE;
1017     }
1018     if(-e $file){
1019     open(FILE,$file) or die(qq{$! "$file"});
1020     binmode FILE;
1021     @new = split(m/[\x0D\x0A\x00]+/,<FILE>);
1022     close FILE;
1023     }
1024    
1025     Algorithm::Diff::traverse_sequences(\@old,\@new,{
1026     MATCH => sub{ $diff .= qq/=$new[$_[1]]\n/ },
1027     DISCARD_A => sub{ $diff .= qq/-$old[$_[0]]\n/ },
1028     DISCARD_B => sub{ $diff .= qq/+$new[$_[1]]\n/ },
1029     });
1030     return $diff;
1031     ###__CODE__###
1032     if($@){
1033     $self->_warn(qq{traverse_diff : $@});
1034     return undef;
1035     }else{
1036     return $diff;
1037     }
1038     }
1039    
1040    
1041    
1042     #
1043     # �ǡ����κǽ����������� localtime �ǵ��롣
1044     #
1045     sub stat{
1046     my $self = shift or die qq(stat : usage error.);
1047     my($key) = @_;
1048     my $file = $self->filename($key);
1049     return CORE::stat($file);
1050     }
1051     sub mtime{
1052     my $self = shift or die qq(mtime : usage error.);
1053     my($key) = @_;
1054     my $file = $self->filename($key);
1055     return ( (CORE::stat($file))[9] );
1056     }
1057     sub localtime{
1058     my $self = shift or die qq(localtime : usage error.);
1059     my($key) = @_;
1060     my $file = $self->filename($key);
1061     return localtime( (CORE::stat($file))[9] );
1062     }
1063    
1064    
1065    
1066     #
1067     # ������ɤ߽Ф�
1068     #
1069     sub info{
1070     my $self = shift or die qq(info : usage error.);
1071     my $info;
1072     $info .= qq(Yuki::YukiWikiDB2\t: $Yuki::YukiWikiDB2::VERSION\n);
1073     $info .= qq(Algorithm::Diff\t: )
1074     .eval('use Algorithm::Diff; $Algorithm::Diff::VERSION')."\n";
1075     $info .= qq(Archive::Zip\t: )
1076     .eval('use Archive::Zip; $Archive::Zip::VERSION')."\n";
1077     foreach my $key (sort keys %{$self}){
1078     my $val = $self->{$key};
1079     $info .= qq($key\t: $val\n);
1080     if(ref($val) eq 'ARRAY' and @{$val}){
1081     $info .= join("\n",@{$val})."\n"
1082     }
1083     }
1084     return $info;
1085     }
1086    
1087    
1088    
1089     #
1090     # �إåɥ饤���ɤ߽Ф�
1091     # �ǽ�ιԤ��֤��ޤ��������β��Ԥ� chomp ����ޤ���
1092     #
1093     sub headline{
1094     my $self = shift or die qq(headline : usage error.);
1095     my($key) = @_;
1096     my $file = $self->filename($key);
1097     if(exists $self->{-headline}->{$key}){
1098     ;;;
1099     }elsif(-e $file){
1100     open(FILE,$file) or $self->_die(qq{headline : $! "$file"});
1101     binmode FILE;
1102     local $/ = "\n";
1103     while(<FILE>){
1104     s/^[\s\t]+//;
1105     s/[\s\t]+$//;
1106     next unless length;
1107     $self->{-headline}->{$key} = $_;
1108     last;
1109     }
1110     close FILE;
1111     }else{
1112     $self->{-headline}->{$key} = undef;
1113     }
1114     return $self->{-headline}->{$key};
1115     }
1116    
1117     1;;;
1118    
1119     __END__

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24