File Coverage

blib/lib/Apache2/FileHash.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package Apache2::FileHash;
2              
3 1     1   25558 use strict;
  1         4  
  1         50  
4 1     1   5 use warnings;
  1         3  
  1         52  
5              
6             our $VERSION = '0.01';
7              
8 1     1   5 use Carp;
  1         6  
  1         126  
9 1     1   6 use Digest::MD5;
  1         2  
  1         56  
10 1     1   7565 use Math::BigInt;
  1         31276  
  1         6  
11 1     1   59979 use File::Temp;
  1         57986  
  1         108  
12 1     1   3372 use File::Copy;
  1         7321  
  1         75  
13 1     1   1124 use YAML::Tiny;
  0            
  0            
14             use File::Basename;
15              
16             use Apache2::RequestRec ();
17             use Apache2::Const -compile => qw(DECLINED OK REDIRECT);
18              
19             our $ConfigFile = "FileHash.yml";
20             our $Config;
21              
22             sub hashing_function
23             {
24             my ($r, $path) = @_;
25              
26             my $hex = &Digest::MD5::md5_hex($path);
27             my $filename = "0x$hex";
28              
29             my (undef, undef, $suffix) = &File::Basename::fileparse($path, qr/\.(.*?)$/);
30              
31             $filename .= $suffix;
32              
33             return($filename);
34             }
35              
36             sub file_exists
37             {
38             my ($r, $headers) = @_;
39              
40             my $filename = &hashing_function($r, $headers);
41              
42             if (-e "/$$Config[0]{GLOBALS}{base_dir}/$filename") {
43             return(Apache2::Const::DECLINED);
44             }
45             else {
46             return(Apache2::Const::OK);
47             }
48             }
49              
50             sub netloc
51             {
52             my ($r, $filename) = @_;
53              
54             my (undef, undef, $suffix) = &File::Basename::fileparse($filename, qr/\.(.*?)$/);
55              
56             my ($package) = (caller(0))[0];
57             $package =~ s#^.*:##;
58              
59             my $orig_filename = $filename;
60             $filename =~ s/$suffix$//;
61              
62             my $num = Math::BigInt->new($filename);
63             my $num_buckets = scalar(@{ $Config->[0]{BUCKETS} });
64             my $bucket_index = $num % $num_buckets;
65             my $bucket = $Config->[0]{BUCKETS}[$bucket_index];
66              
67             my ($location, $name, $method, $port);
68              
69             $location = $Config->[0]{METHOD}{$package}{root_uri};
70             $name = $bucket->{name};
71             $method = $bucket->{method};
72             $port = $bucket->{port};
73              
74             # warn("${method}://${name}:$port/$location/$orig_filename");
75             return("${method}://${name}:$port/$location/$orig_filename");
76             }
77              
78             sub getbucket
79             {
80             my ($r, $filename) = @_;
81              
82             my (undef, undef, $suffix) = &File::Basename::fileparse($filename, qr/\.(.*?)$/);
83              
84             my $orig_filename = $filename;
85             $filename =~ s/$suffix$//;
86              
87             my $num = Math::BigInt->new($filename);
88             my $num_buckets = scalar(@{ $Config->[0]{BUCKETS} });
89             my $bucket_index = $num % $num_buckets;
90             my $bucket = $Config->[0]{BUCKETS}[$bucket_index];
91              
92             return($bucket);
93             }
94              
95             sub inbucket
96             {
97             my ($r, $path) = @_;
98              
99             my $uri = $r->uri();
100             my $server_name = $r->get_server_name();
101             my $port = $r->get_server_port();
102             my $cur_netloc = "http://$server_name:$port/$uri"; # ugh.. hardcoded
103              
104             my $filename = &hashing_function($r, $path);
105             # my $new_netloc = &netloc($r, $filename);
106              
107             my $bucket = &getbucket($r, $filename);
108              
109             my $location = $bucket->{location};
110             my $name = $bucket->{name};
111             my $method = $bucket->{method};
112             $port = $bucket->{port};
113              
114             my $new_netloc = "${method}://${name}:$port/$uri";
115              
116             # warn(qq(return($cur_netloc eq $new_netloc)));
117             return($cur_netloc eq $new_netloc);
118             }
119              
120             sub save_file
121             {
122             my ($r, $path) = @_;
123              
124             my $filename = &Apache2::FileHash::hashing_function($r, $path);
125            
126             my $yaml = YAML::Tiny->new;
127             $yaml->[0] = {
128             path => $path,
129             hashed => $filename,
130             };
131             $yaml->write( "/$$Config[0]{GLOBALS}{base_dir}/yaml/$filename.yml" );
132             undef($yaml);
133              
134             my $tmpfh = File::Temp->new(UNLINK => 0);
135             my $tmpname = $tmpfh->filename;
136              
137             my $buffer;
138             my $len = 1024;
139             while ($r->read($buffer, $len)) {
140             last unless $len;
141             print($tmpfh $buffer);
142             }
143              
144             undef($tmpfh);
145              
146             &File::Copy::move($tmpname, "/$$Config[0]{GLOBALS}{base_dir}/$filename") or return(Apache2::Const::DECLINED);
147              
148             return(Apache2::Const::OK);
149             }
150              
151             =head1 NAME
152              
153             Apache2::FileHash - Methods to store and retrieve files using a hashing methodology.
154              
155             =head1 SYNOPSIS
156              
157             use Apache2::FileHash;
158              
159            
160            
161             PerlHeaderParserHandler Apache2::FileHash::PUT
162            
163             order deny,allow
164             deny from all
165             allow from 192.168.5.5
166            
167            
168            
169            
170             PerlHeaderParserHandler Apache2::FileHash::GET
171            
172            
173              
174            
175            
176             PerlHeaderParserHandler Apache2::FileHash::PUT
177            
178             order deny,allow
179             deny from all
180             allow from 192.168.5.5
181            
182            
183              
184            
185             PerlHeaderParserHandler Apache2::FileHash::GET
186            
187            
188              
189             *** startup.pl ***
190             #!/opt/perl
191              
192             use strict;
193             use warnings;
194              
195             use lib qw(/opt/mod_perl);
196             use lib qw(/opt/mod_perl/lib);
197             use lib qw(/opt/Apache2);
198             use lib qw(/opt/Apache2/FileHash);
199              
200             use Apache2::FileHash;
201             use Apache2::FileHash::PUT;
202             use Apache2::FileHash::GET;
203              
204             use MIME::Types;
205              
206             my @array = ();
207             foreach my $dir (@INC) {
208             my $file = "$dir/$Apache2::FileHash::ConfigFile";
209             eval {
210             @array = &YAML::Tiny::LoadFile($file) or die("LoadFile($YAML::Tiny::errstr)");
211             };
212             unless ($@) {
213             last;
214             }
215             }
216              
217             $Apache2::FileHash::Config = \@array;
218              
219             BEGIN { MIME::Types->new() };
220              
221             1;
222             *** startup.pl ***
223              
224             *** FileHash.yml **
225             ---
226             GLOBALS:
227             base_dir: '/tmp'
228             BUCKETS:
229             -
230             method: http
231             name: localhost
232             port: 80
233             -
234             method: http
235             name: localhost
236             port: 8080
237             METHOD:
238             GET:
239             root_uri: '/getFile'
240             PUT:
241             root_uri: '/storeFile'
242             *** FileHash.yml ***
243              
244             =head1 DESCRIPTION
245              
246             This is an attempt at solving a problem with hosting millions
247             of static files. It should be straight forward enough to take
248             a suite of n servers and store x files across them.
249              
250             It is assumed that each bucket is publically accessible and that
251             the disks may or may not be. It is non-trivial to add a bucket
252             later.
253              
254             =head1 SEE ALSO
255              
256             Apaceh2:::RequestRec
257              
258             =head1 AUTHOR
259              
260             Brian Medley, Efreesoftware@bmedley.org
261              
262             =head1 COPYRIGHT AND LICENSE
263              
264             Copyright (C) 2012 by Brian Medley
265              
266             This library is free software; you can redistribute it and/or modify
267             it under the same terms as Perl itself, either Perl version 5.8.8 or,
268             at your option, any later version of Perl 5 you may have available.
269              
270              
271             =cut
272              
273             1;