Gitweb - Adding option to disable forking
[git/gitweb-warthdog9.git] / gitweb / cache.pm
blobc771b02d5b7715d08e2a6ae71b328a1ae13508e0
1 # gitweb - simple web interface to track changes in git repositories
3 # (C) 2006, John 'Warthog9' Hawley <warthog19@eaglescrag.net>
5 # This program is licensed under the GPLv2
8 # Gitweb caching engine
11 #package gitweb::cache;
12 #use strict;
13 #use warnings;
15 #my $VERSION = "0.00";
17 sub cache_fetch {
18 my ($action) = @_;
19 my $cacheTime = 0;
21 # Deal with cache being disabled
22 if( $cache_enable == 0 ){
23 undef $backgroundCache;
24 $fullhashpath = \$nocachedata;
25 $fullhashbinpath = \$nocachedatabin;
26 }elsif( $cache_enable == 1 ){
27 #obvious we are using file based caching
29 #print "Action: $action\n";
30 if(! -d $cachedir){
31 print "*** Warning ***: Caching enabled but cache directory does not exsist. ($cachedir)\n";
32 mkdir ("cache", 0665) || die "Cannot create cache dir - you will need to manually create";
33 print "Cache directory created successfully\n";
36 #our $local_url = "". $ENV{'HTTP_HOST'} ." + ". $ENV{'PATH_INFO'} ." + ". $ENV{'QUERY_STRING'} ."\n";
37 #print "URL: $local_url\n";
38 our $full_url = "$my_url?". $ENV{'QUERY_STRING'};
39 our $urlhash = md5_hex($full_url);
40 our $fullhashdir = "$cachedir/". substr( $urlhash, 0, 2) ."/";
42 #if( $] < 5.010000 ) {
43 eval { mkpath( $fullhashdir, 0777 ) };
44 if ($@) {
45 die_error(500, "Internal Server Error", "Could not create cache directory: $@");
47 #} else {
48 # my $numdirs = make_path( $fullhashdir, { mode => 0777, error => \my $mkdirerr, } ); # This is only used with the newer File::Path
49 # if( @$mkdirerr ){
50 # my $mkdirerrmsg = "";
51 # for my $diag (@$mkdirerr) {
52 # my ($file, $message) = %$diag;
53 # if($file eq '' ){
54 # $mkdirerrmsg .= "general error: $message\n";
55 # }else{
56 # $mkdirerrmsg .= "problem unlinking $file: $message\n";
57 # }
58 # }
59 # die_error(500, "Internal Server Error", "Could not create cache directory | $mkdirerrmsg");
60 # }
61 #} # End figuring out File::Path usage
62 $fullhashpath = "$fullhashdir/". substr( $urlhash, 2 );
63 $fullhashbinpath = "$fullhashpath.bin";
64 } # done dealing with cache enabled / disabled
66 if(! -e "$fullhashpath" ){
67 if( ! $cache_enable || ! $cacheDoFork || ! defined(my $childPid = fork()) ){
68 cacheUpdate($action,0);
69 cacheDisplay($action);
70 } elsif ( $childPid == 0 ){
71 #run the updater
72 cacheUpdate($action,1);
73 }else{
74 cacheWaitForUpdate($action);
76 }else{
77 #if cache is out dated, update
78 #else displayCache();
79 open(cacheFile, '<', "$fullhashpath");
80 stat(cacheFile);
81 close(cacheFile);
82 $cacheTime = get_loadavg() * 60;
83 if( $cacheTime > $maxCacheTime ){
84 $cacheTime = $maxCacheTime;
86 if( $cacheTime < $minCacheTime ){
87 $cacheTime = $minCacheTime;
89 if( (stat(_))[9] < (time - $cacheTime) ){
90 if( ! $cacheDoFork || ! defined(my $childPid = fork()) ){
91 cacheUpdate($action,0);
92 cacheDisplay($action);
93 } elsif ( $childPid == 0 ){
94 #run the updater
95 #print "Running updater\n";
96 cacheUpdate($action,1);
97 }else{
98 #print "Waiting for update\n";
99 cacheWaitForUpdate($action);
101 } else {
102 cacheDisplay($action);
109 # If all of the caching failes - lets go ahead and press on without it and fall back to 'default'
110 # non-caching behavior. This is the softest of the failure conditions.
112 #$actions{$action}->();
115 sub cacheUpdate {
116 my ($action,$areForked) = @_;
117 my $lockingStatus;
118 my $fileData = "";
120 if($backgroundCache){
121 open(cacheFileBG, '>:utf8', "$fullhashpath.bg");
122 my $lockStatBG = flock(cacheFileBG,LOCK_EX|LOCK_NB);
124 $lockStatus = $lockStatBG;
125 }else{
126 open(cacheFile, '>:utf8', "$fullhashpath") if ($cache_enable > 0);
127 open(cacheFile, '>:utf8', \$fullhashpath) if ($cache_enable == 0);
128 my $lockStat = flock(cacheFile,LOCK_EX|LOCK_NB);
130 $lockStatus = $lockStat;
132 #print "lock status: $lockStat\n";
135 if ($cache_enable != 0 && ! $lockStatus ){
136 if ( $areForked ){
137 exit(0);
138 }else{
139 return;
144 $fileData = "". $actions{$action}->() ."";
146 if($backgroundCache){
147 open(cacheFile, '>:utf8', "$fullhashpath");
148 $lockStat = flock(cacheFile,LOCK_EX);
150 if (! $lockStat ){
151 if ( $areForked ){
152 exit(0);
153 }else{
154 return;
159 print cacheFile "$fileData";
161 flock(cacheFile,LOCK_UN);
162 close(cacheFile);
164 if($backgroundCache){
165 flock(cacheFileBG,LOCK_UN);
166 close(cacheFileBG);
169 if ( $areForked ){
170 exit(0);
171 } else {
172 return;
177 sub cacheWaitForUpdate {
178 my ($action) = @_;
179 my $x = 0;
180 my $max = 10;
181 my $lockStat = 0;
183 if( $backgroundCache ){
184 if( -e "$fullhashpath" ){
185 open(cacheFile, '<:utf8', "$fullhashpath") if ($cache_enable > 0);
186 open(cacheFile, '<:utf8', \$fullhashpath) if ($cache_enable == 0);
187 $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
188 stat(cacheFile);
189 close(cacheFile);
191 if( $lockStat && ( (stat(_))[9] > (time - $maxCacheLife) ) ){
192 cacheDisplay($action);
193 return;
198 #our $headerRefresh = 1;
199 #print git_header_html();
202 $action eq "atom"
204 $action eq "rss"
206 $action eq "opml"
208 do {
209 sleep 2 if $x > 0;
210 open(cacheFile, '<:utf8', "$fullhashpath") if ($cache_enable > 0);
211 open(cacheFile, '<:utf8', \$fullhashpath) if ($cache_enable == 0);
212 $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
213 close(cacheFile);
214 $x++;
215 $combinedLockStat = $lockStat;
216 } while ((! $combinedLockStat) && ($x < $max));
218 if( $x != $max ){
219 cacheDisplay($action);
221 return;
224 $| = 1;
226 print $::cgi->header(
227 -type=>'text/html',
228 -charset => 'utf-8',
229 -status=> 200,
230 -expires => 'now',
231 # HTTP/1.0
232 -Pragma => 'no-cache',
233 # HTTP/1.1
234 -Cache_Control => join(
235 ', ',
237 private
238 no-cache
239 no-store
240 must-revalidate
241 max-age=0
242 pre-check=0
243 post-check=0
248 print <<EOF;
249 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www/w3.porg/TR/html4/strict.dtd">
250 <!-- git web interface version $version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
251 <!-- git core binaries version $git_version -->
252 <head>
253 <meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
254 <meta name="generator" content="gitweb/$version git/$git_version"/>
255 <meta name="robots" content="index, nofollow"/>
256 <meta http-equiv="refresh" content="0"/>
257 <title>$title</title>
258 </head>
259 <body>
262 print "Generating..";
263 do {
264 print ".";
265 sleep 2 if $x > 0;
266 open(cacheFile, '<:utf8', "$fullhashpath") if ($cache_enable > 0);
267 open(cacheFile, '<:utf8', \$fullhashpath) if ($cache_enable == 0);
268 $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
269 close(cacheFile);
270 #$lockStatbg = flock(cacheFilebg,LOCK_SH|LOCK_NB) if $backgroundCache;
271 #print "Lock State: $lockStat\n";
272 #if( ! $lockStat ){
273 # print "Error: ". $! ."\n";
275 $x++;
276 $combinedLockStat = $lockStat;
277 #$combinedLockStat = $lockStat & $lockStatbg if $backgroundCache;
278 } while ((! $combinedLockStat) && ($x < $max));
279 #} while ($x < $max);
280 #close(cacheFile);
281 #close(cacheFilebg) if $backgroundCache;
282 #print git_footer_html();
283 print <<EOF;
284 </body>
285 </html>
287 #exit(0);
288 return;
289 #cacheDisplay();
292 sub cacheDisplay {
293 my ($action) = @_;
294 open(cacheFile, '<:utf8', "$fullhashpath") if ($cache_enable > 0);
295 open(cacheFile, '<:utf8', \$fullhashpath) if ($cache_enable == 0);
296 $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
297 if ($cache_enable != 0 && ! $lockStat ){
298 close(cacheFile);
299 cacheWaitForUpdate($action);
302 while( <cacheFile> ){
303 print $_;
306 $action eq "snapshot"
308 $action eq "blob_plain"
310 open(cacheFileBin, '<', "$fullhashbinpath");
311 binmode STDOUT, ':raw';
312 print <cacheFileBin>;
313 binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
314 close(cacheFileBin);
316 close(cacheFile);