/[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.2 - (hide annotations) (download)
Thu Jan 2 02:15:32 2003 UTC (23 years, 8 months ago) by w
Branch: MAIN
Changes since 1.1: +1 -1 lines
*** empty log message ***

1 w 1.1 ###
2     ### $Id: YukiWikiDB2.pm,v 1.36 2002/11/30 10:41:35 dune Exp $
3     ###
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     #
10     # 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     ($VERSION) = q($Revision: 1.36 $) =~ m/\x20([\d.]+)\x20/;
16     #use strict;
17    
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     # ���å��ե����뤬���Ĥ���ʤ���
446     if(not defined $nglock){
447     $self->_die(qq{TIEHASH : lockfile not found. "$lock"});
448     }
449    
450     # ��¸���å��򹹿����ƥ��å�
451     if($self->{-timeout} < $duration){
452     # �۾�ʥ��å�
453     $self->_warn(qq{TIEHASH : dated lock found ($duration). "$nglock"});
454     last TRY if $self->_force_lock($mode,$nglock);
455     $self->_warn(qq{TIEHASH : force lock failure. "$nglock"});
456     }else{
457     # ����ʥ��å�
458     last TRY if $self->_lock($mode,$nglock);
459     }
460    
461     # ��������
462     $self->_warn(qq{TIEHASH : retry lock ($try/$trytime). "$nglock"});
463     sleep 1;
464     }
465     }
466    
467     if(not $self->{-lock}){
468     # ���å�����
469     $self->_warn(qq{TIEHASH : lock failure. "$lock"});
470     return;
471     }else{
472     return $self;
473     }
474     }
475    
476    
477    
478     #
479     # UNTIE
480     # ������ץȤ�λ�����˥ǡ����١������Ĥ������
481     # untie %db; �ʤɤȤ��롣
482     # UNTIE �� untie ��˺���ȸƤФ�ʤ��ʥ��å�����������
483     # ���ˤΤǡ����֥������ȤΥǥ��ȥ饯������⼫ưŪ�˸ƤӽФ�
484     # ���褦�ˤ�����
485     #
486     sub UNTIE{
487     my($self) = @_;
488     my $mode = $self->{-mode};
489     my $lock = $self->{-lock};
490    
491     if(!$mode or $self->_unlock($lock)){
492     # ������å������ʤ����Ƥ��������Ǵ�λ�����
493     ;;;
494     }else{
495     # ������å����ԡ����å��ե������õ���ʶ�ͭ���å�����
496     chop(my $dbname = $self->{-dir});
497     my $trytime = $self->{-trytime};
498     TRY:foreach(my $try = 0;$try < $trytime;++$try){
499     opendir(DIR,"$dbname/..") or $self->_die(qq{UNTIE : $! "$dbname/.."});
500     my @nglock = readdir DIR;
501     closedir DIR;
502    
503     my($nglock,$duration);
504     foreach(@nglock){
505     if(m/^\Q$dbname\E\.(\d*)\.(\d*)\.lock$/){
506     $nglock = qq($dbname.$1.$2.lock);
507     $duration = time - $2 if $2;
508     last;
509     }
510     }
511     last TRY if $self->_unlock($nglock);
512    
513     if($nglock eq "$dbname...lock"){
514     # ���ꤨ�ʤ��Ϥ��������ʤ����Ȥ��ɤ����롣
515     $self->_warn(qq{UNTIE : not locked. "$nglock"});
516     last TRY;
517     }
518    
519     # ��������(sleep �ʤ�)
520     $self->_warn(qq{UNTIE : retry unlock ($try/$trytime). "$nglock"});
521     }
522    
523     if($self->{-lock} eq $lock){
524     $self->_warn(qq{UNTIE : unlock failure. "$lock"});
525     }
526     }
527     return;
528     }
529    
530    
531    
532     #
533     # �ǥ��ȥ饯��
534     #
535     # DESTROY �� untie ��˺��Ƥ�ƤФ�롣
536     # new �ޤ��� tie �Υ������פγ��˽Ф��Ȥ���perl ��λ���Ȥ���
537     # �˸ƤФ�뤫�����뤤������ͤ�ȤäƤ����硢���֥�������
538     # �����Ȥ���ʤ��ʤä��Ȥ����ޤ�������Ū�� untie ��³���� undef
539     # �����Ȥ��˸ƤФ�롣�Ȥˤ��������Ĥ���ɬ���ƤФ��ߤ�������
540     #
541     sub DESTROY{
542     my($self) = @_;
543     if($self->{-mode}){
544     # untie ˺��ο�����
545     $self->_warn(qq{DESTROY : invoke untie method.}) if 0;
546     $self->UNTIE();
547     }
548     return;
549     }
550    
551    
552    
553     #
554     # �񤭹���
555     #
556     sub STORE{
557     my($self,$key,$val) = @_;
558     my $mode = $self->{-mode};
559     $self->_die(qq{STORE : method not allowd, mode="$mode"}) if $mode == 1;
560     my $file = $self->filename($key);
561     my $temp = "$file.".time;
562     my $bkup = $self->bkupname($key);
563     open(FILE,">$temp") or $self->_die(qq{STORE : $! "$temp"});
564     binmode FILE;
565     print FILE $val;
566     close FILE;
567     if($self->{-bkup_next}){
568     if(-e $bkup){
569     unlink $bkup or $self->_die(qq{STORE : $! "$bkup"});
570     }
571     if(-e $file){
572     rename($file => $bkup) or $self->_die(qq{STORE : $! "$file" => "$bkup"});
573     }
574     }else{
575     if(-e $file){
576     unlink $file or $self->_die(qq{STORE : $! "$file"});
577     }
578     }
579     rename($temp => $file) or $self->_die(qq{STORE : $! "$temp" => "$file"});
580     $self->{-bkup_next} = $self->{-bkup};
581     $self->{-cache}->{-key} = $key;
582     $self->{-cache}->{-val} = $val;
583     delete $self->{-headline}->{$key};
584     return $val;
585     }
586    
587    
588    
589     #
590     # �ɤ߽Ф�
591     #
592     sub FETCH{
593     my($self,$key) = @_;
594     if($self->{-cache}->{-key} eq $key){
595     return $self->{-cache}->{-val};
596     }
597     my $file = $self->filename($key);
598     if(-e $file){
599     open(FILE,$file) or $self->_die(qq{FETCH : $! "$file"});
600     binmode FILE;
601     local $/ = undef;
602     my $val = <FILE>;
603     close FILE;
604     $self->{-cache}->{-key} = $key;
605     $self->{-cache}->{-val} = $val;
606     return $val;
607     }else{
608     return;
609     }
610     }
611    
612    
613    
614     #
615     # ���
616     #
617     sub DELETE{
618     my($self,$key) = @_;
619     my $file = $self->filename($key);
620     my $bkup = $self->bkupname($key);
621     my $mode = $self->{-mode};
622     $self->_die(qq{DELETE : method not allowd, mode="$mode"}) if $mode == 1;
623     if($self->{-bkup_next}){
624     if(-e $bkup){
625     unlink $bkup or $self->_die(qq{DELETE : $! "$bkup"});
626     }
627     if(-e $file){
628     rename($file => $bkup)
629     or $self->_die(qq{DELETE : $! "$file" => "$bkup"});
630     }
631     }else{
632     if(-e $file){
633     unlink $file or $self->_die(qq{DELETE : $! "$file"});
634     }
635     }
636     $self->{-bkup_next} = $self->{-bkup};
637     $self->{-cache}->{-key} = undef;
638     $self->{-cache}->{-val} = undef;
639     delete $self->{-headline}->{$key};
640     return;
641     }
642    
643    
644    
645     #
646     # ¸�ߥ����å�
647     #
648     sub EXISTS{
649     my($self,$key) = @_;
650     my $file = $self->filename($key);
651     return -e $file;
652     }
653    
654    
655    
656     #
657     # ���ƥ졼��
658     #
659     sub FIRSTKEY{
660     my($self) = @_;
661     @{$self->{-keys}} = $self->_list_all();
662     my $tmp = shift @{$self->{-keys}};
663     return defined $tmp ? &{$self->{-decode}}($tmp) : undef;
664     }
665     sub NEXTKEY{
666     my($self) = @_;
667     my $tmp = shift @{$self->{-keys}};
668     return defined $tmp ? &{$self->{-decode}}($tmp) : undef;
669     }
670    
671    
672    
673     #
674     # �ϥå������Τκ��
675     #
676     # �ե��������Ȥ���ˤ���ʶ��ϥå���ˤ���ˤ����ǡ��ǥ���
677     # ���ȥ����å��ե����롢���������֤ϻĤ��ʻ��͡��ˡ�
678     #
679     sub CLEAR{
680     my($self) = @_;
681     my $mode = $self->{-mode};
682     $self->_die(qq{CLEAR : method not allowd, mode="$mode"}) if $mode == 1;
683     my $dbname = $self->{-dir};
684     my @key = $self->_list_all();
685     foreach(@key){
686     my $file = $dbname.$_.$self->{-extension};
687     unlink $file or $self->_die(qq{CLEAR : $! "$file".});
688     }
689     if(0){
690     my $file = $self->{-logfile};
691     if(-e $file){
692     unlink $file or $self->_die(qq{CLEAR : $! "$file".});
693     }
694     }
695     if(0){
696     my $lock = $self->{-lock};
697     rmdir $dbname or $self->_die(qq{CLEAR : $! "$dbname".});
698     unlink $lock or $self->_die(qq{CLEAR : $! "$lock".});
699     $self->{-mode} = 0;
700     }
701     $self->{-cache}->{-key} = undef;
702     $self->{-cache}->{-val} = undef;
703     $self->{-headline} = {};
704     return;
705     }
706    
707    
708    
709     #
710     # ���ꤷ�������Υǡ����������� [byte] ���֤��ޤ���
711     # ��������ꤷ�ʤ��ȡ����ƤΥǡ����ι�ץ��������֤��ޤ�
712     # �ʤ������Хå����å��ѤΥǡ����䡢-extension �dz�ĥ�Ҥ�
713     # �Ѥ����ǡ����Ϸ׾夷�ޤ���ˡ�
714     #
715     sub size{
716     my $self = shift or die qq(size : usage error.);
717     my $dbname = $self->{-dir};
718     my @key = @_;
719     if(not @key){
720     @key = $self->_list_all();
721     }else{
722     foreach(@key){
723     &{$self->{-encode}}($_);
724     }
725     }
726     my $size;
727     foreach(@key){
728     $size += -s $dbname.$_.$self->{-extension};
729     }
730     return $size;
731     }
732    
733    
734    
735     #
736     # ������ ListAll
737     #
738     sub _list_all{
739     my $self = shift or die qq(_list_all : usage error.);
740     my $dbname = $self->{-dir};
741     my $ext = $self->{-extension};
742     my $extlen = length $ext;
743     opendir(DIR,$dbname) or $self->_die(qq{_list_all : $! "$dbname".});
744     my @key = grep(-f $dbname.$_,readdir DIR);
745     closedir DIR;
746     if($extlen){
747     @key = grep(index("$_/","$ext/") != -1,@key);
748     foreach(@key){
749     substr($_,-$extlen) = ''
750     }
751     }
752     return @key;
753     }
754     sub list_all{
755     my $self = shift or die qq(list_all : usage error.);
756     my @key = $self->_list_all();
757     foreach(@key){
758     &{$self->{-decode}}($_);
759     }
760     return @key;
761     }
762    
763    
764    
765     #
766     # ������̾�����Ѥ���
767     # ���������� 1 ���֤���
768     #
769     sub rename{
770     my $self = shift or die qq(rename : usage error.);
771     my($from,$to) = @_;
772     my $mode = $self->{-mode};
773     $self->_die(qq{rename : method not allowd, mode="$mode"}) if $mode == 1;
774     if(rename($self->filename($from) => $self->filename($to))){
775     if($self->{-cache}->{-key} eq $from
776     or $self->{-cache}->{-key} eq $to){
777     $self->{-cache}->{-key} = undef;
778     $self->{-cache}->{-val} = undef;
779     }
780     delete $self->{-headline}->{$from};
781     delete $self->{-headline}->{$to};
782     return 1;
783     }else{
784     $self->_warn(qq{rename : $! "$from" => "$to"});
785     return 0;
786     }
787     }
788    
789    
790    
791     #
792     # �����Υꥹ�Ȥ򡢹���������¤٤��֤��ʺǶ�Τ�Τ���Ƭ�ˡ�
793     #
794     sub sort_by_mtime{
795     my $self = shift or die qq(sort_by_mtime : usage error.);
796     my $dbname = $self->{-dir};
797     my @key = @_;
798     if(not @key){
799     @key = $self->_list_all();
800     }else{
801     foreach(@key){
802     &{$self->{-encode}}($_);
803     }
804     }
805     return map(&{$self->{-decode}}($_->[1]),
806     sort({$a->[0] <=> $b->[0] or $a->[1] cmp $b->[1]}
807     map([-M $dbname.$_.$self->{-extension},$_],@key)));
808     }
809    
810    
811    
812     #
813     # �����Υꥹ�Ȥ򡢥ǡ�������������¤٤��֤��ʾ�������Τ���Ƭ�ˡ�
814     #
815     sub sort_by_size{
816     my $self = shift or die qq(sort_by_size : usage error.);
817     my $dbname = $self->{-dir};
818     my @key = @_;
819     if(not @key){
820     @key = $self->_list_all();
821     }else{
822     foreach(@key){
823     &{$self->{-encode}}($_);
824     }
825     }
826     return map(&{$self->{-decode}}($_->[1]),
827     sort({$a->[0] <=> $b->[0] or $a->[1] cmp $b->[1]}
828     map([-s $dbname.$_.$self->{-extension},$_],@key)));
829     }
830    
831    
832    
833     #
834     # ���ΤΤʤ��Хå����åץե�����κ��
835     #
836     sub clean{
837     my $self = shift or die qq(clean : usage error.);
838     my $mode = $self->{-mode};
839     $self->_die(qq{clean : method not allowd, mode="$mode"}) if $mode == 1;
840     my $dbname = $self->{-dir};
841     my @key = @_;
842     if(not @key){
843     @key = $self->_list_all();
844     }else{
845     foreach(@key){
846     &{$self->{-encode}}($_);
847    
848     }
849     }
850     my $err;
851     foreach(@key){
852     if(-e $dbname.$_.".bak"){
853     unlink $dbname.$_.".bak" || ++$err;
854     }
855     }
856     return $err;
857     }
858    
859    
860    
861     #
862     # �ǡ����򥢡������֤��롣
863     # ��������ȥ��������֤Υ����� [byte] ���֤��ޤ���
864     # ���Ԥ���� undef ���֤��ޤ���
865     #
866     sub archive{
867     my $self = shift or die qq(archive : usage error.);
868     my $mode = $self->{-mode};
869     $self->_die(qq{archive : method not allowd, mode="$mode"}) if $mode == 1;
870     my(@key) = @_;
871     my $dir = $self->{-dir};
872     (my $archive = $dir) =~ s/\/$/.zip/;
873     eval <<' ###__CODE__###';
874     use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
875     use Archive::Zip::Tree;
876     my $zip = Archive::Zip->new();
877     if(@key){
878     foreach(@key){
879     my $member = $zip->addFile($self->filename($_),$dir.$_);
880     $member->desiredCompressionMethod(COMPRESSION_DEFLATED);
881     $member->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
882     }
883     }else{
884     $zip->addTreeMatching($dir,$dir,$self->{-extension}.'$');
885     foreach my $member ($zip->members()){
886     $member->desiredCompressionMethod(COMPRESSION_DEFLATED);
887     $member->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
888     }
889     }
890     $zip->zipfileComment(
891     "created by Yuki::YukiWikiDB2 $Yuki::YukiWikiDB2::VERSION"
892     ." with Archive::Zip $Archive::Zip::VERSION");
893     die(qq{write error "$archive"})
894     if $zip->writeToFileNamed("$archive") != AZ_OK;
895     ###__CODE__###
896     if($@){
897     $self->_warn(qq{archive : $@});
898     return undef;
899     }else{
900     return -s "$archive";
901     }
902     }
903    
904    
905    
906     #
907     # ������ RecentChanges(WhatsNew)
908     # $db->recent_changes() - sort_by_mtime() ��Ʊ�������ƤΥ������֤���
909     # $db->recent_changes(+n) - �ǿ��� n ����֤���
910     # $db->recent_changes(-n) - �ǸŤ� n ����֤���
911     #
912     sub recent_changes{
913     my $self = shift or die qq(recent_changes : usage error.);
914     my($n,$m) = @_;
915     my @key = $self->sort_by_mtime();
916     if($m){
917     return @key[$n..$m];
918     }elsif($n == 0){
919     return @key;
920     }elsif($n < 0){
921     $n = -$n - 1;
922     @key = reverse @key;
923     }else{
924     --$n;
925     }
926     return @key[0..$n];
927     }
928    
929    
930    
931     #
932     # �Хå����åץե饰�ΰ�����å�
933     #
934     # ���åȤ���ȼ��Υǡ����������˥Хå����åפ�Ȥ롣
935     # �Хå����åפ�Ȥä���ե饰�ϥꥻ�åȤ���롣
936     #
937     # ex. $DB->bkup_next(1); # ����Хå����åפ�Ȥ롣
938     # ex. $DB->bkup_next(0); # ����Хå����åפ�Ȥ�ʤ���
939     #
940     sub bkup_next{
941     my $self = shift or die qq(bkup_next : usage error.);
942     my($flag) = @_;
943     return defined $flag ?
944     ($self->{-bkup_next} = $flag) :
945     $self->{-bkup_next};
946     # $self->{-bkup_next} = $flag || 1
947     }
948    
949    
950    
951     #
952     # ���ߤΥǡ����ȥХå����åץǡ����Ȥδ֤κ�ʬ����롣
953     # ex. $diff = $DB->diff('foo');
954     # ex. @diff = $DB->diff('foo');
955     #
956     sub diff{
957     my $self = shift or die qq(diff : usage error.);
958     my($key) = @_;
959     my $diff;
960     eval <<' ###__CODE__###';
961     use Algorithm::Diff;
962     my $file = $self->filename($key);
963     my $bkup = $self->bkupname($key);
964     my(@old,@new);
965     local $/ = undef;
966    
967     if(-e $bkup){
968     open(FILE,$bkup) or die(qq{$! "$bkup"});
969     binmode FILE;
970     @old = split(m/[\x0D\x0A\x00]+/,<FILE>);
971     close FILE;
972     }
973     if(-e $file){
974     open(FILE,$file) or die(qq{$! "$file"});
975     binmode FILE;
976     @new = split(m/[\x0D\x0A\x00]+/,<FILE>);
977     close FILE;
978     }
979    
980     foreach(Algorithm::Diff::diff(\@old,\@new)){
981     foreach(@{$_}){
982     my($sign,$lineno,$text) = @{$_};
983     $diff .= qq($sign$text\n);
984     }
985     $diff .= "\n";
986     }
987     $diff =~ s/\n+$/\n/;
988     return $diff;
989     ###__CODE__###
990     if($@){
991     $self->_warn(qq{diff : $@});
992     return undef;
993     }else{
994     return $diff;
995     }
996     }
997     sub traverse_diff{
998     my $self = shift or die qq(traverse_diff : usage error.);
999     my($key) = @_;
1000     my $diff;
1001     eval <<' ###__CODE__###';
1002     # http://www.stonehenge.com/merlyn/UnixReview/col35.html
1003     use Algorithm::Diff;
1004     my $file = $self->filename($key);
1005     my $bkup = $self->bkupname($key);
1006     my(@old,@new);
1007     local $/ = undef;
1008    
1009     if(-e $bkup){
1010     open(FILE,$bkup) or die(qq{$! "$bkup"});
1011     binmode FILE;
1012     @old = split(m/[\x0D\x0A\x00]+/,<FILE>);
1013     close FILE;
1014     }
1015     if(-e $file){
1016     open(FILE,$file) or die(qq{$! "$file"});
1017     binmode FILE;
1018     @new = split(m/[\x0D\x0A\x00]+/,<FILE>);
1019     close FILE;
1020     }
1021    
1022     Algorithm::Diff::traverse_sequences(\@old,\@new,{
1023     MATCH => sub{ $diff .= qq/=$new[$_[1]]\n/ },
1024     DISCARD_A => sub{ $diff .= qq/-$old[$_[0]]\n/ },
1025     DISCARD_B => sub{ $diff .= qq/+$new[$_[1]]\n/ },
1026     });
1027     return $diff;
1028     ###__CODE__###
1029     if($@){
1030     $self->_warn(qq{traverse_diff : $@});
1031     return undef;
1032     }else{
1033     return $diff;
1034     }
1035     }
1036    
1037    
1038    
1039     #
1040     # �ǡ����κǽ����������� localtime �ǵ��롣
1041     #
1042     sub stat{
1043     my $self = shift or die qq(stat : usage error.);
1044     my($key) = @_;
1045     my $file = $self->filename($key);
1046     return CORE::stat($file);
1047     }
1048     sub mtime{
1049     my $self = shift or die qq(mtime : usage error.);
1050     my($key) = @_;
1051     my $file = $self->filename($key);
1052     return ( (CORE::stat($file))[9] );
1053     }
1054     sub localtime{
1055     my $self = shift or die qq(localtime : usage error.);
1056     my($key) = @_;
1057     my $file = $self->filename($key);
1058     return localtime( (CORE::stat($file))[9] );
1059     }
1060    
1061    
1062    
1063     #
1064     # ������ɤ߽Ф�
1065     #
1066     sub info{
1067     my $self = shift or die qq(info : usage error.);
1068     my $info;
1069     $info .= qq(Yuki::YukiWikiDB2\t: $Yuki::YukiWikiDB2::VERSION\n);
1070     $info .= qq(Algorithm::Diff\t: )
1071     .eval('use Algorithm::Diff; $Algorithm::Diff::VERSION')."\n";
1072     $info .= qq(Archive::Zip\t: )
1073     .eval('use Archive::Zip; $Archive::Zip::VERSION')."\n";
1074     foreach my $key (sort keys %{$self}){
1075     my $val = $self->{$key};
1076     $info .= qq($key\t: $val\n);
1077     if(ref($val) eq 'ARRAY' and @{$val}){
1078     $info .= join("\n",@{$val})."\n"
1079     }
1080     }
1081     return $info;
1082     }
1083    
1084    
1085    
1086     #
1087     # �إåɥ饤���ɤ߽Ф�
1088     # �ǽ�ιԤ��֤��ޤ��������β��Ԥ� chomp ����ޤ���
1089     #
1090     sub headline{
1091     my $self = shift or die qq(headline : usage error.);
1092     my($key) = @_;
1093     my $file = $self->filename($key);
1094     if(exists $self->{-headline}->{$key}){
1095     ;;;
1096     }elsif(-e $file){
1097     open(FILE,$file) or $self->_die(qq{headline : $! "$file"});
1098     binmode FILE;
1099     local $/ = "\n";
1100     while(<FILE>){
1101     s/^[\s\t]+//;
1102     s/[\s\t]+$//;
1103     next unless length;
1104     $self->{-headline}->{$key} = $_;
1105     last;
1106     }
1107     close FILE;
1108     }else{
1109     $self->{-headline}->{$key} = undef;
1110     }
1111     return $self->{-headline}->{$key};
1112     }
1113    
1114     1;;;
1115    
1116     __END__

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24