final move of files
[web.mtrack] / MTrack / cache.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 /* maintain cache */
5 function mtrack_cache_maintain()
6 {
7   $cachedir = MTrackConfig::get('core', 'vardir') . '/cmdcache';
8   $max_cache_life = MTrackConfig::get('core', 'max_cache_life');
9   if (!$max_cache_life) {
10     $max_cache_life = 14 * 86400;
11   }
12   foreach (scandir($cachedir) as $name) {
13     $filename = "$cachedir/$name";
14     if (!is_file($filename)) {
15       continue;
16     }
17     $st = stat($filename);
18     if ($st['mtime'] + $max_cache_life < time()) {
19       unlink($filename);
20     }
21   }
22 }
23
24 /* walks the cache; loads each element and examines the keys.
25  * if the key prefix matches $key, that element is removed */
26 function mtrack_cache_blow_matching($key)
27 {
28   $cachedir = MTrackConfig::get('core', 'vardir') . '/cmdcache';
29   foreach (scandir($cachedir) as $name) {
30     $filename = "$cachedir/$name";
31     if (!is_file($filename)) {
32       continue;
33     }
34     $fp = @fopen($filename, 'r');
35     if (!$fp) {
36       continue;
37     }
38     flock($fp, LOCK_SH);
39     $data = unserialize(stream_get_contents($fp));
40     flock($fp, LOCK_UN);
41     $fp = null;
42
43     $match = true;
44     foreach ($key as $i => $element) {
45       if ($data->key[$i] != $element) {
46         $match = false;
47         break;
48       }
49     }
50     if ($match) {
51       unlink("$cachedir/$name");
52     }
53   }
54 }
55
56 function mtrack_cache_blow($key)
57 {
58   $cachedir = MTrackConfig::get('core', 'vardir') . '/cmdcache';
59   foreach (scandir($cachedir) as $name) {
60     if (!is_file($name)) {
61       continue;
62     }
63     $fp = @fopen("$cachedir/$name", 'r');
64     if (!$fp) {
65       continue;
66     }
67     flock($fp, LOCK_SH);
68     $data = unserialize(stream_get_contents($fp));
69     flock($fp, LOCK_UN);
70     $fp = null;
71
72     if ($key == $data->key) {
73       unlink("$cachedir/$name");
74     }
75   }
76 }
77
78 function mtrack_cache($func, $args, $cache_life = 300, $key = null)
79 {
80   $cachedir = MTrackConfig::get('core', 'vardir') . '/cmdcache';
81   if (!is_dir($cachedir)) {
82     mkdir($cachedir);
83   }
84   if ($key === null) {
85     $fkey = var_export($args, true);
86     $key = $fkey;
87   } else {
88     $fkey = var_export($key, true);
89   }
90   if (is_string($func)) {
91     $fkey = "$func$fkey";
92   } else {
93     $fkey = var_export($func, true) . $fkey;
94   }
95
96   $cachefile = $cachedir . '/' .  sha1($fkey);
97
98   $updating = false;
99   for ($i = 0; $i < 10; $i++) {
100     $fp = @fopen($cachefile, 'r+');
101     if ($fp) {
102       flock($fp, LOCK_SH);
103       /* is it current? */
104       $st = fstat($fp);
105       if ($st['size'] == 0) {
106         /* not valid to have 0 size; we're likely racing with the
107          * creator */
108         flock($fp, LOCK_UN);
109         $fp = null;
110         usleep(100);
111         continue;
112       }
113       if ($st['mtime'] + $cache_life < time()) {
114         /* no longer current; we'll make it current */
115         $updating = true;
116         flock($fp, LOCK_EX);
117         /* we have exclusive access; someone else may have
118          * made it current in the meantime */
119         $st = fstat($fp);
120         if ($st['mtime'] + $cache_life >= time()) {
121           $updating = false;
122         }
123       }
124       break;
125     }
126     /* we're going to create it */
127     $fp = @fopen($cachefile, 'x+');
128     if ($fp) {
129       flock($fp, LOCK_EX);
130       $updating = true;
131       break;
132     }
133   }
134
135   if ($fp) {
136     if ($updating) {
137       ftruncate($fp, 0);
138
139       $result = call_user_func_array($func, $args);
140       $data = new stdclass;
141       $data->key = $key;
142       $data->res = $result;
143       fwrite($fp, serialize($data));
144       flock($fp, LOCK_UN);
145       return $result;
146     }
147
148     $data = unserialize(stream_get_contents($fp));
149     flock($fp, LOCK_UN);
150     return $data->res;
151   }
152   /* if we didn't get a file pointer, just run the command */
153   return call_user_func_array($func, $args);
154 }
155