Create the whole second cache table. This is a lot of changes :)
[viewsvn.git] / includes / cachev.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # ViewSVN [#]version[#]
5 || # Copyright ©2002-[#]year[#] Iris Studios, Inc.
6 || #
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version [#]gpl[#] of the License.
10 || #
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 || # more details.
15 || #
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
21
22 /**
23 * File container for cacheV class
24 *
25 * @package ViewSVN
26 */
27
28 /**
29 * cacheV
30 *
31 * This class is responsible for interacting with a given cacheV table.
32 * It controls rebuilding from scratch, updates, and querying the cache.
33 *
34 * @author Iris Studios, Inc.
35 * @copyright Copyright ©2002 - [#]year[#], Iris Studios, Inc.
36 * @version $Revision$
37 * @package ViewSVN
38 *
39 */
40 class cacheV
41 {
42 /**
43 * The registry
44 * @var object
45 */
46 var $registry = null;
47
48 /**
49 * cacheV hash
50 * @var string
51 */
52 var $hash;
53
54 /**
55 * Record count - the number of records in cacheV
56 * @var integer
57 */
58 var $count;
59
60 /**
61 * Memcache for all fetched revisions so we don't have to query-dupe
62 * @var array
63 */
64 var $memcache = array();
65
66 // ###################################################################
67 /**
68 * Constructor: initialies the registry
69 */
70 function cacheV()
71 {
72 global $viewsvn;
73 $this->registry =& $viewsvn;
74 }
75
76 // ###################################################################
77 /**
78 * Sets the hash so we know what table we're dealing with
79 *
80 * @access public
81 */
82 function set_hash()
83 {
84 $this->hash = md5($this->registry->repos->fetch_path($this->registry->paths->repos));
85 }
86
87 // ###################################################################
88 /**
89 * Returns a specific log entry
90 *
91 * @access public
92 *
93 * @param integer Revision number
94 *
95 * @return array Complete revision/commit entry
96 */
97 function fetch_revision($revision)
98 {
99 $revision = $this->registry->clean($revision, TYPE_UINT);
100
101 if (!isset($this->memcache["$revision"]))
102 {
103 $this->memcache["$revision"] = $this->registry->db->query_first("SELECT * FROM {$this->hash}_revs WHERE revision = $revision");
104 }
105
106 return $this->memcache["$revision"];
107 }
108
109 // ###################################################################
110 /**
111 * Checks to see if it's necessary to rebuild the cacheV table for the
112 * current repository. This is done by making sure $count > 0. If not,
113 * then rebuild() is run. This also checks against the cacheV table
114 * to make sure that it's up-to-date against the root repository.
115 *
116 * @access public
117 */
118 function exec_build()
119 {
120 $result = $this->registry->db->query_first("SELECT MAX(revision) AS max FROM {$this->hash}_revs");
121 $this->count = $result['max'];
122
123 // time to go from the start
124 if ($this->count == 0)
125 {
126 $this->build(null);
127 }
128 else
129 {
130 // send an Xquery to SVN to see if we need to update
131 $query = $this->registry->svn->svn('info --xml ' . $this->registry->repos->fetch_path($this->registry->paths->repos));
132 $query = implode("\n", $query);
133
134 $tree = $this->registry->xml->parse($query);
135
136 if ($tree['info']['entry']['revision'] != $this->count)
137 {
138 $this->build($this->count);
139 }
140 }
141 }
142
143 // ###################################################################
144 /**
145 * Builds the cacheV table. This can be used to build only part of the
146 * cache or the entire thing, if the revision is set to NULL.
147 *
148 * @access public
149 *
150 * @param integer Lower (current) revision
151 */
152 function build($revision)
153 {
154 $start = microtime();
155
156 // get _revs
157 $output = $this->registry->svn->svn('log --xml -v ' . ($revision !== null ? '-r' . $revision . ':HEAD ' : '') . $this->registry->repos->fetch_path($this->registry->paths->repos));
158 $output = implode("\n", $output);
159 $tree = $this->registry->xml->parse($output);
160
161 // get _nodes
162 $output = $this->registry->svn->svn('info --xml -R ' . ($revision !== null ? '-r' . $revision . ':HEAD ' : '') . $this->registry->repos->fetch_path($this->registry->paths->repos));
163 $output = implode("\n", $output);
164 $infolist = $this->registry->xml->parse($output);
165
166 // other part of _nodes
167 $output = $this->registry->svn->svn('proplist -v -R ' . ($revision !== null ? ' -r' . $revision . ':HEAD ' : '') . $this->registry->repos->fetch_path($this->registry->paths->repos));
168 foreach ($output AS $line)
169 {
170 if (preg_match('#^Properties on \'(.*?)\':$#', $line, $bits))
171 {
172 $proplist["$index"]["$curprop"] = trim($proplist["$index"]["$curprop"]);
173 $index = str_replace($this->registry->repos->fetch_path($this->registry->paths->repos), '', $bits[1]);
174 $capture = false;
175 }
176 else
177 {
178 if (preg_match('#^\s+(.*)\s:\s(.*)#', $line, $matches))
179 {
180 $curprop = $matches[1];
181 $proplist["$index"]["$curprop"] = $matches[2] . "\n";
182 $capture = true;
183 }
184 else if ($capture == true)
185 {
186 $proplist["$index"]["$curprop"] .= $line . "\n";
187 }
188 }
189 }
190
191 foreach ($tree['log']['logentry'] AS $log)
192 {
193 $this->registry->xml->unify_node($log['paths']['path']);
194
195 $inserts['revs'][] = "($log[revision], '{$log['author']['value']}', '{$log['date']['value']}', '" . $this->registry->escape($log['msg']['value']) . "', '" . $this->registry->escape(serialize($log['paths']['path'])) . "')";
196
197 foreach ($log['paths']['path'] AS $path)
198 {
199 if ($path['action'] == 'A')
200 {
201 $act = 'addrevs';
202 }
203 else if ($path['action'] == 'D')
204 {
205 $act = 'delrevs';
206 }
207 else
208 {
209 $act = 'revs';
210 }
211
212 $path['value'] = preg_replace('#^/#', '', $path['value']);
213 $pathlist["$path[value]"]["$act"][] = $log['revision'];
214 }
215 }
216
217 foreach ($infolist['info']['entry'] AS $node)
218 {
219 $inserts['nodes'][] = "('$node[path]', '{$node['repository']['uuid']['value']}', '" . implode(',', $pathlist["$node[path]"]['delrevs']) . "', '" . implode(',', $pathlist["$node[path]"]['addrevs']) . "', '" . implode(',', $pathlist["$node[path]"]['revs']) . "', '" . $this->registry->escape(serialize($proplist["$node[path]"])) . "')";
220 }
221
222 $this->registry->db->query("
223 REPLACE INTO {$this->hash}_revs
224 (revision, author, dateline, message, files)
225 VALUES
226 " . implode(",\n", $inserts['revs'])
227 );
228
229 $this->registry->db->query("
230 REPLACE INTO {$this->hash}_nodes
231 (name, uuid, delrevs, addrevs, revs, properties)
232 VALUES
233 " . implode(",\n", $inserts['nodes'])
234 );
235
236 /*
237 name VARCHAR(255) NOT NULL DEFAULT '',
238 uuid VARCHAR(50) NOT NULL DEFAULT '',
239 delrevs MEDIUMTEXT NOT NULL DEFAULT '',
240 addrevs MEDIUMTEXT NOT NULL DEFAULT '',
241 revs MEDIUMTEXT NOT NULL DEFAULT '',
242 properties MEDIUMTEXT NOT NULL DEFAULT '',*/
243
244 $this->registry->debug("TIME TO (RE)BUILD: " . $this->registry->funct->fetch_microtime_diff($start));
245 }
246 }
247
248 /*=====================================================================*\
249 || ###################################################################
250 || # $HeadURL$
251 || # $Id$
252 || ###################################################################
253 \*=====================================================================*/
254 ?>