1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
package net.sf.statsvn.input; |
25 | |
|
26 | |
import java.io.FileInputStream; |
27 | |
import java.io.FileNotFoundException; |
28 | |
import java.io.IOException; |
29 | |
import java.io.InputStream; |
30 | |
import java.util.ArrayList; |
31 | |
import java.util.Collection; |
32 | |
import java.util.Collections; |
33 | |
import java.util.Date; |
34 | |
import java.util.HashMap; |
35 | |
import java.util.HashSet; |
36 | |
import java.util.Iterator; |
37 | |
import java.util.List; |
38 | |
import java.util.Map; |
39 | |
import java.util.Vector; |
40 | |
|
41 | |
import javax.xml.parsers.ParserConfigurationException; |
42 | |
import javax.xml.parsers.SAXParser; |
43 | |
import javax.xml.parsers.SAXParserFactory; |
44 | |
|
45 | |
import net.sf.statcvs.input.LogSyntaxException; |
46 | |
import net.sf.statsvn.output.SvnConfigurationOptions; |
47 | |
import net.sf.statsvn.util.BinaryDiffException; |
48 | |
import net.sf.statsvn.util.FilenameComparator; |
49 | |
import net.sf.statsvn.util.SvnDiffUtils; |
50 | |
import net.sf.statsvn.util.XMLUtil; |
51 | |
|
52 | |
import org.xml.sax.SAXException; |
53 | |
|
54 | |
import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService; |
55 | |
import edu.emory.mathcs.backport.java.util.concurrent.Executors; |
56 | |
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; |
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | 0 | |
67 | 0 | public class SvnLogfileParser { |
68 | |
private static final int INTERMEDIARY_SAVE_INTERVAL_MS = 120000; |
69 | |
|
70 | |
private static final String REPOSITORIES_XML = "repositories.xml"; |
71 | |
|
72 | |
private final SvnLogBuilder builder; |
73 | |
|
74 | |
private final InputStream logFile; |
75 | |
|
76 | |
private final RepositoryFileManager repositoryFileManager; |
77 | |
|
78 | |
private CacheBuilder cacheBuilder; |
79 | 3 | |
80 | 27 | private HashSet revsForNewDiff = null; |
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | 3 | |
92 | 30 | public SvnLogfileParser(final RepositoryFileManager repositoryFileManager, final InputStream logFile, final SvnLogBuilder builder) { |
93 | 30 | this.logFile = logFile; |
94 | 30 | this.builder = builder; |
95 | 30 | this.repositoryFileManager = repositoryFileManager; |
96 | 27 | } |
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | 3 | protected void handleLineCounts(final SAXParserFactory factory) throws IOException { |
110 | 30 | long startTime = System.currentTimeMillis(); |
111 | 27 | final String xmlFile = SvnConfigurationOptions.getCacheDir() + REPOSITORIES_XML; |
112 | 3 | |
113 | 30 | final RepositoriesBuilder repositoriesBuilder = readAndParseXmlFile(factory, xmlFile); |
114 | 30 | cacheFileName = SvnConfigurationOptions.getCacheDir() + repositoriesBuilder.getFileName(repositoryFileManager.getRepositoryUuid()); |
115 | 30 | XMLUtil.writeXmlFile(repositoriesBuilder.getDocument(), xmlFile); |
116 | 30 | SvnConfigurationOptions.getTaskLogger().log("parsing repositories finished in " + (System.currentTimeMillis() - startTime) + " ms."); |
117 | 27 | startTime = System.currentTimeMillis(); |
118 | 3 | |
119 | 30 | readCache(factory); |
120 | 30 | SvnConfigurationOptions.getTaskLogger().log("parsing line counts finished in " + (System.currentTimeMillis() - startTime) + " ms."); |
121 | 27 | startTime = System.currentTimeMillis(); |
122 | |
|
123 | |
|
124 | 3 | |
125 | 27 | cacheBuilder.updateBinaryStatus(builder.getFileBuilders().values(), repositoryFileManager.getRootRevisionNumber()); |
126 | 3 | |
127 | 27 | final Collection fileBuilders = builder.getFileBuilders().values(); |
128 | 3 | |
129 | 27 | calculateNumberRequiredCalls(fileBuilders); |
130 | |
|
131 | 3 | |
132 | 30 | ExecutorService poolService = null; |
133 | 30 | if (SvnConfigurationOptions.getNumberSvnDiffThreads() > 1) { |
134 | 27 | poolService = Executors.newFixedThreadPool(SvnConfigurationOptions.getNumberSvnDiffThreads()); |
135 | |
} |
136 | 3 | |
137 | 30 | boolean isFirstDiff = true; |
138 | 30 | calls = 0; |
139 | 30 | groupStart = System.currentTimeMillis(); |
140 | 27 | boolean poolUseRequired = false; |
141 | 3 | |
142 | 27 | if (SvnConfigurationOptions.isLegacyDiff()) { |
143 | 0 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
144 | 0 | final FileBuilder fileBuilder = (FileBuilder) iter.next(); |
145 | 0 | final String fileName = fileBuilder.getName(); |
146 | 0 | if (fileBuilder.isBinary() || !builder.matchesPatterns(fileName)) { |
147 | 0 | continue; |
148 | 0 | } |
149 | 0 | final List revisions = fileBuilder.getRevisions(); |
150 | 0 | for (int i = 0; i < revisions.size(); i++) { |
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | 0 | |
163 | 0 | if (i + 1 < revisions.size() && ((RevisionData) revisions.get(i)).hasNoLines() && !((RevisionData) revisions.get(i)).isDeletion()) { |
164 | 0 | if (((RevisionData) revisions.get(i + 1)).isDeletion()) { |
165 | 0 | continue; |
166 | 0 | } |
167 | 0 | final String revNrNew = ((RevisionData) revisions.get(i)).getRevisionNumber(); |
168 | 0 | if (cacheBuilder.isBinary(fileName, revNrNew)) { |
169 | 0 | continue; |
170 | 0 | } |
171 | 0 | final String revNrOld = ((RevisionData) revisions.get(i + 1)).getRevisionNumber(); |
172 | 0 | |
173 | 0 | if (isFirstDiff) { |
174 | 0 | SvnConfigurationOptions.getTaskLogger().info("Contacting server to obtain line count information."); |
175 | 0 | SvnConfigurationOptions.getTaskLogger().info( |
176 | |
"This information will be cached so that the next time you run StatSVN, results will be returned more quickly."); |
177 | 0 | |
178 | 0 | if (SvnConfigurationOptions.isLegacyDiff()) { |
179 | 0 | SvnConfigurationOptions.getTaskLogger().info("Using the legacy Subversion 1.3 diff mechanism: one diff per file per revision."); |
180 | 0 | } else { |
181 | 0 | SvnConfigurationOptions.getTaskLogger().info("Using the Subversion 1.4 diff mechanism: one diff per revision."); |
182 | |
} |
183 | 0 | |
184 | 0 | isFirstDiff = false; |
185 | |
} |
186 | 0 | |
187 | 0 | final DiffTask diff = new DiffTask(fileName, revNrNew, revNrOld, fileBuilder); |
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | 0 | |
193 | 0 | poolUseRequired = executeTask(poolService, poolUseRequired, diff); |
194 | |
} |
195 | 0 | } |
196 | 0 | } |
197 | 3 | } else { |
198 | 27 | for (final Iterator iter = revsForNewDiff.iterator(); iter.hasNext();) { |
199 | 0 | final String revNrNew = (String) iter.next(); |
200 | 0 | final PerRevDiffTask diff = new PerRevDiffTask(revNrNew, builder.getFileBuilders()); |
201 | 0 | |
202 | 0 | poolUseRequired = executeTask(poolService, poolUseRequired, diff); |
203 | 0 | } |
204 | |
|
205 | 3 | } |
206 | 30 | waitForPoolIfRequired(poolService); |
207 | 30 | SvnConfigurationOptions.getTaskLogger().log("parsing svn diff"); |
208 | 30 | XMLUtil.writeXmlFile(cacheBuilder.getDocument(), cacheFileName); |
209 | 30 | SvnConfigurationOptions.getTaskLogger().log("parsing svn diff finished in " + (System.currentTimeMillis() - startTime) + " ms."); |
210 | 27 | } |
211 | |
|
212 | 0 | private boolean executeTask(final ExecutorService poolService, boolean poolUseRequired, final DiffTask diff) { |
213 | 0 | if (poolUseRequired && SvnConfigurationOptions.getNumberSvnDiffThreads() > 1) { |
214 | 0 | poolService.execute(diff); |
215 | 0 | } else { |
216 | 0 | final long start = System.currentTimeMillis(); |
217 | 0 | diff.run(); |
218 | 0 | final long end = System.currentTimeMillis(); |
219 | 0 | poolUseRequired = (end - start) > SvnConfigurationOptions.getThresholdInMsToUseConcurrency(); |
220 | 0 | } |
221 | 0 | return poolUseRequired; |
222 | |
} |
223 | |
|
224 | 3 | private void waitForPoolIfRequired(final ExecutorService poolService) { |
225 | 30 | if (SvnConfigurationOptions.getNumberSvnDiffThreads() > 1 && poolService != null) { |
226 | 27 | SvnConfigurationOptions.getTaskLogger().info( |
227 | |
"Scheduled " + requiredDiffCalls + " svn diff calls on " + Math.min(requiredDiffCalls, SvnConfigurationOptions.getNumberSvnDiffThreads()) |
228 | 3 | + " threads."); |
229 | 27 | poolService.shutdown(); |
230 | 3 | try { |
231 | 30 | SvnConfigurationOptions.getTaskLogger().log("================ Wait for completion ========================="); |
232 | 27 | if (!poolService.awaitTermination(2, TimeUnit.DAYS)) { |
233 | 0 | SvnConfigurationOptions.getTaskLogger().log("================ TIME OUT!!! ========================="); |
234 | 0 | } |
235 | 0 | } catch (final InterruptedException e) { |
236 | 3 | SvnConfigurationOptions.getTaskLogger().error(e.toString()); |
237 | 27 | } |
238 | 3 | } |
239 | 27 | } |
240 | |
|
241 | |
private void calculateNumberRequiredCalls(final Collection fileBuilders) { |
242 | 3 | |
243 | 27 | requiredDiffCalls = 0; |
244 | 3 | |
245 | 30 | if (!SvnConfigurationOptions.isLegacyDiff()) { |
246 | 27 | revsForNewDiff = new HashSet(); |
247 | |
} |
248 | 3 | |
249 | 3180 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
250 | 31530 | final FileBuilder fileBuilder = (FileBuilder) iter.next(); |
251 | 31530 | final String fileName = fileBuilder.getName(); |
252 | 31092 | if (!fileBuilder.isBinary() && builder.matchesPatterns(fileName)) { |
253 | 42972 | final List revisions = fileBuilder.getRevisions(); |
254 | 182655 | for (int i = 0; i < revisions.size(); i++) { |
255 | 142941 | if (i + 1 < revisions.size() && ((RevisionData) revisions.get(i)).hasNoLines() && !((RevisionData) revisions.get(i)).isDeletion()) { |
256 | 5430 | if (((RevisionData) revisions.get(i + 1)).isDeletion()) { |
257 | 4887 | continue; |
258 | 0 | } |
259 | 0 | final String revNrNew = ((RevisionData) revisions.get(i)).getRevisionNumber(); |
260 | 0 | if (cacheBuilder.isBinary(fileName, revNrNew)) { |
261 | 0 | continue; |
262 | |
} |
263 | |
|
264 | 0 | |
265 | 0 | if (revsForNewDiff == null || !revsForNewDiff.contains(revNrNew)) { |
266 | 0 | requiredDiffCalls++; |
267 | 0 | |
268 | 0 | if (revsForNewDiff != null) { |
269 | 0 | revsForNewDiff.add(revNrNew); |
270 | |
} |
271 | |
} |
272 | |
} |
273 | |
} |
274 | 3153 | } |
275 | 25224 | } |
276 | 3 | |
277 | 27 | } |
278 | |
|
279 | 3 | private void readCache(final SAXParserFactory factory) throws IOException { |
280 | 30 | cacheBuilder = new CacheBuilder(builder, repositoryFileManager); |
281 | 27 | FileInputStream cacheFile = null; |
282 | 3 | try { |
283 | 30 | cacheFile = new FileInputStream(cacheFileName); |
284 | 30 | final SAXParser parser = factory.newSAXParser(); |
285 | 30 | parser.parse(cacheFile, new SvnXmlCacheFileHandler(cacheBuilder)); |
286 | 27 | cacheFile.close(); |
287 | 0 | } catch (final ParserConfigurationException e) { |
288 | 0 | SvnConfigurationOptions.getTaskLogger().error("Cache: " + e.toString()); |
289 | 0 | } catch (final SAXException e) { |
290 | 0 | SvnConfigurationOptions.getTaskLogger().error("Cache: " + e.toString()); |
291 | 0 | } catch (final FileNotFoundException e) { |
292 | 0 | SvnConfigurationOptions.getTaskLogger().log("Cache: " + e.toString()); |
293 | 0 | } catch (final IOException e) { |
294 | 0 | SvnConfigurationOptions.getTaskLogger().error("Cache: " + e.toString()); |
295 | 3 | } finally { |
296 | 30 | if (cacheFile != null) { |
297 | 27 | cacheFile.close(); |
298 | |
} |
299 | 3 | } |
300 | 27 | } |
301 | |
|
302 | 3 | private RepositoriesBuilder readAndParseXmlFile(final SAXParserFactory factory, final String xmlFile) throws IOException { |
303 | 30 | final RepositoriesBuilder repositoriesBuilder = new RepositoriesBuilder(); |
304 | 27 | FileInputStream repositoriesFile = null; |
305 | 3 | try { |
306 | 30 | repositoriesFile = new FileInputStream(xmlFile); |
307 | 30 | final SAXParser parser = factory.newSAXParser(); |
308 | 30 | parser.parse(repositoriesFile, new SvnXmlRepositoriesFileHandler(repositoriesBuilder)); |
309 | 27 | repositoriesFile.close(); |
310 | 0 | } catch (final ParserConfigurationException e) { |
311 | 0 | SvnConfigurationOptions.getTaskLogger().error("Repositories: " + e.toString()); |
312 | 0 | } catch (final SAXException e) { |
313 | 0 | SvnConfigurationOptions.getTaskLogger().error("Repositories: " + e.toString()); |
314 | 0 | } catch (final FileNotFoundException e) { |
315 | 0 | SvnConfigurationOptions.getTaskLogger().log("Repositories: " + e.toString()); |
316 | 0 | } catch (final IOException e) { |
317 | 0 | SvnConfigurationOptions.getTaskLogger().error("Repositories: " + e.toString()); |
318 | 3 | } finally { |
319 | 30 | if (repositoriesFile != null) { |
320 | 27 | repositoriesFile.close(); |
321 | |
} |
322 | 3 | } |
323 | 27 | return repositoriesBuilder; |
324 | |
} |
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | |
|
333 | |
|
334 | |
|
335 | |
public void parse() throws LogSyntaxException, IOException { |
336 | 3 | |
337 | 27 | final SAXParserFactory factory = parseSvnLog(); |
338 | 3 | |
339 | 27 | verifyImplicitActions(); |
340 | |
|
341 | 3 | |
342 | 27 | removeDirectories(); |
343 | 3 | |
344 | 27 | handleLineCounts(factory); |
345 | 3 | |
346 | 27 | } |
347 | |
|
348 | |
|
349 | |
|
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
|
355 | |
|
356 | |
|
357 | |
|
358 | |
|
359 | |
|
360 | |
protected void verifyImplicitActions() { |
361 | |
|
362 | |
|
363 | 3 | |
364 | 30 | final long startTime = System.currentTimeMillis(); |
365 | 27 | SvnConfigurationOptions.getTaskLogger().log("verifying implicit actions ..."); |
366 | 3 | |
367 | 27 | final HashSet implicitActions = new HashSet(); |
368 | |
|
369 | 3 | |
370 | 30 | final ArrayList files = new ArrayList(); |
371 | 27 | final Collection fileBuilders = fetchAllFileNames(files); |
372 | |
|
373 | |
|
374 | |
|
375 | 3 | |
376 | 27 | Collections.sort(files, new FilenameComparator()); |
377 | |
|
378 | 3444 | |
379 | 34437 | for (int i = 0; i < files.size(); i++) { |
380 | 34410 | final String parent = files.get(i).toString(); |
381 | 30969 | final FileBuilder parentBuilder = (FileBuilder) builder.getFileBuilders().get(parent); |
382 | |
|
383 | 17682 | |
384 | 159138 | for (int j = i + 1; j < files.size() && files.get(j).toString().indexOf(parent + "/") == 0; j++) { |
385 | 14241 | |
386 | 128169 | repositoryFileManager.addDirectory(parent); |
387 | 14241 | |
388 | 142410 | final String child = files.get(j).toString(); |
389 | 128169 | final FileBuilder childBuilder = (FileBuilder) builder.getFileBuilders().get(child); |
390 | 14241 | |
391 | 143463 | for (final Iterator iter = parentBuilder.getRevisions().iterator(); iter.hasNext();) { |
392 | 137646 | final RevisionData parentData = (RevisionData) iter.next(); |
393 | |
int parentRevision; |
394 | 15294 | try { |
395 | 137646 | parentRevision = Integer.parseInt(parentData.getRevisionNumber()); |
396 | 0 | } catch (final Exception e) { |
397 | 15294 | continue; |
398 | 137646 | } |
399 | |
|
400 | 15294 | |
401 | 137646 | if (parentData.isCreationOrRestore() || parentData.isDeletion()) { |
402 | |
int k; |
403 | |
|
404 | |
|
405 | 15282 | |
406 | 137538 | k = detectActionOnChildGivenActionOnParent(childBuilder, parentRevision); |
407 | |
|
408 | 15282 | |
409 | 138255 | if (k < childBuilder.getRevisions().size()) { |
410 | 6453 | createImplicitAction(implicitActions, child, childBuilder, parentData, k); |
411 | |
} |
412 | 15294 | } |
413 | 122352 | } |
414 | |
} |
415 | |
} |
416 | |
|
417 | |
|
418 | |
|
419 | 3 | |
420 | 27 | cleanPotentialDuplicateImplicitActions(fileBuilders); |
421 | |
|
422 | |
|
423 | |
|
424 | |
|
425 | |
|
426 | |
|
427 | |
|
428 | |
|
429 | |
|
430 | |
|
431 | |
|
432 | 3 | |
433 | 30 | removePotentialInconsistencies(implicitActions, fileBuilders); |
434 | 30 | SvnConfigurationOptions.getTaskLogger().log("verifying implicit actions finished in " + (System.currentTimeMillis() - startTime) + " ms."); |
435 | 27 | } |
436 | |
|
437 | |
private void createImplicitAction(final HashSet implicitActions, final String child, final FileBuilder childBuilder, final RevisionData parentData, |
438 | |
final int k) { |
439 | 717 | |
440 | 7170 | final RevisionData implicit = parentData.createCopy(); |
441 | 6453 | implicitActions.add(implicit); |
442 | |
|
443 | 717 | |
444 | 7170 | final List toMove = new ArrayList(); |
445 | 9729 | for (final Iterator it = childBuilder.getRevisions().subList(k, childBuilder.getRevisions().size()).iterator(); it.hasNext();) { |
446 | 29484 | final RevisionData revToMove = (RevisionData) it.next(); |
447 | |
|
448 | |
|
449 | 3276 | |
450 | 29484 | toMove.add(revToMove); |
451 | 3276 | |
452 | 26208 | } |
453 | |
|
454 | 717 | |
455 | 6453 | childBuilder.getRevisions().removeAll(toMove); |
456 | |
|
457 | |
|
458 | 717 | |
459 | 6453 | builder.buildFile(child, false, false, new HashMap(), new HashMap()); |
460 | |
|
461 | |
|
462 | |
|
463 | |
|
464 | 717 | |
465 | 6453 | builder.buildRevision(implicit); |
466 | |
|
467 | |
|
468 | 717 | |
469 | 9729 | for (final Iterator it = toMove.iterator(); it.hasNext();) { |
470 | 29484 | builder.buildRevision((RevisionData) it.next()); |
471 | 717 | } |
472 | 6453 | } |
473 | |
|
474 | |
private int detectActionOnChildGivenActionOnParent(final FileBuilder childBuilder, final int parentRevision) { |
475 | 83664 | int k; |
476 | 824901 | for (k = 0; k < childBuilder.getRevisions().size(); k++) { |
477 | 719250 | final RevisionData childData = (RevisionData) childBuilder.getRevisions().get(k); |
478 | 647325 | final int childRevision = Integer.parseInt(childData.getRevisionNumber()); |
479 | |
|
480 | |
|
481 | 71925 | |
482 | 650151 | if (parentRevision == childRevision) { |
483 | 28260 | k = childBuilder.getRevisions().size(); |
484 | 25434 | break; |
485 | |
} |
486 | 69099 | |
487 | 622608 | if (parentRevision > childRevision) { |
488 | 6453 | break; |
489 | |
} |
490 | 15282 | } |
491 | 137538 | return k; |
492 | |
} |
493 | |
|
494 | 3 | private void removePotentialInconsistencies(final HashSet implicitActions, final Collection fileBuilders) { |
495 | 3468 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
496 | 30969 | final FileBuilder filebuilder = (FileBuilder) iter.next(); |
497 | |
|
498 | |
|
499 | 3441 | |
500 | 31791 | if (!repositoryFileManager.existsInWorkingCopy(filebuilder.getName())) { |
501 | 7398 | builder.addToAttic(filebuilder.getName()); |
502 | |
} |
503 | |
|
504 | 3441 | |
505 | 30999 | if (!repositoryFileManager.existsInWorkingCopy(filebuilder.getName()) && !filebuilder.finalRevisionIsDead()) { |
506 | 366 | int earliestDelete = -1; |
507 | 960 | for (int i = 0; i < filebuilder.getRevisions().size(); i++) { |
508 | 864 | final RevisionData data = (RevisionData) filebuilder.getRevisions().get(i); |
509 | 96 | |
510 | 897 | if (data.isDeletion()) { |
511 | 297 | earliestDelete = i; |
512 | |
} |
513 | 96 | |
514 | 873 | if ((!data.isCreationOrRestore() && data.isChange()) || !implicitActions.contains(data)) { |
515 | 81 | break; |
516 | |
} |
517 | |
} |
518 | 30 | |
519 | 270 | if (earliestDelete > 0) { |
520 | 30 | |
521 | 300 | final List toRemove = new ArrayList(); |
522 | 306 | for (final Iterator it = filebuilder.getRevisions().subList(0, earliestDelete).iterator(); it.hasNext();) { |
523 | 324 | toRemove.add(it.next()); |
524 | 30 | } |
525 | 270 | filebuilder.getRevisions().removeAll(toRemove); |
526 | |
} |
527 | 3441 | } |
528 | 27531 | } |
529 | 27 | } |
530 | |
|
531 | 3 | private void cleanPotentialDuplicateImplicitActions(final Collection fileBuilders) { |
532 | 3468 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
533 | 30969 | final FileBuilder filebuilder = (FileBuilder) iter.next(); |
534 | 3441 | |
535 | 34410 | boolean previousIsDelete = false; |
536 | 30969 | final List toRemove = new ArrayList(); |
537 | |
|
538 | |
|
539 | 3441 | |
540 | 47940 | for (final Iterator it = filebuilder.getRevisions().iterator(); it.hasNext();) { |
541 | 169710 | final RevisionData data = (RevisionData) it.next(); |
542 | 152754 | if (data.isDeletion() && previousIsDelete) { |
543 | 135 | toRemove.add(data); |
544 | 16971 | } |
545 | 169710 | previousIsDelete = data.isDeletion(); |
546 | 135768 | } |
547 | |
|
548 | 3441 | |
549 | 30984 | if (!toRemove.isEmpty()) { |
550 | 135 | filebuilder.getRevisions().removeAll(toRemove); |
551 | 3441 | } |
552 | 27531 | } |
553 | 27 | } |
554 | |
|
555 | 3 | private Collection fetchAllFileNames(final ArrayList files) { |
556 | 30 | final Collection fileBuilders = builder.getFileBuilders().values(); |
557 | 3468 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
558 | 34410 | final FileBuilder fileBuilder = (FileBuilder) iter.next(); |
559 | 34410 | files.add(fileBuilder.getName()); |
560 | 27531 | } |
561 | 27 | return fileBuilders; |
562 | |
} |
563 | |
|
564 | |
|
565 | |
|
566 | |
|
567 | |
|
568 | |
|
569 | |
|
570 | |
|
571 | |
|
572 | |
|
573 | |
|
574 | 3 | protected void removeDirectories() { |
575 | 30 | final Collection fileBuilders = builder.getFileBuilders().values(); |
576 | 30 | final ArrayList toRemove = new ArrayList(); |
577 | 3468 | for (final Iterator iter = fileBuilders.iterator(); iter.hasNext();) { |
578 | 34410 | final FileBuilder fileBuilder = (FileBuilder) iter.next(); |
579 | 31257 | if (repositoryFileManager.isDirectory(fileBuilder.getName())) { |
580 | 2592 | toRemove.add(fileBuilder.getName()); |
581 | 3441 | } |
582 | 27528 | } |
583 | 3 | |
584 | 315 | for (final Iterator iter = toRemove.iterator(); iter.hasNext();) { |
585 | 2592 | builder.getFileBuilders().remove(iter.next()); |
586 | |
} |
587 | 3 | |
588 | 27 | } |
589 | |
|
590 | |
|
591 | |
|
592 | |
|
593 | |
|
594 | |
|
595 | |
|
596 | |
|
597 | |
|
598 | |
|
599 | 3 | protected SAXParserFactory parseSvnLog() throws IOException, LogSyntaxException { |
600 | 30 | final long startTime = System.currentTimeMillis(); |
601 | 27 | SvnConfigurationOptions.getTaskLogger().log("starting to parse..."); |
602 | 3 | |
603 | 27 | final SAXParserFactory factory = SAXParserFactory.newInstance(); |
604 | 3 | try { |
605 | 30 | final SAXParser parser = factory.newSAXParser(); |
606 | 27 | parser.parse(logFile, new SvnXmlLogFileHandler(builder, repositoryFileManager)); |
607 | 0 | } catch (final ParserConfigurationException e) { |
608 | 0 | throw new LogSyntaxException("svn log: " + e.getMessage()); |
609 | 0 | } catch (final SAXException e) { |
610 | 3 | throw new LogSyntaxException("svn log: " + e.getMessage()); |
611 | 27 | } |
612 | 3 | |
613 | 30 | SvnConfigurationOptions.getTaskLogger().log("parsing svn log finished in " + (System.currentTimeMillis() - startTime) + " ms."); |
614 | 27 | return factory; |
615 | |
} |
616 | 3 | |
617 | 27 | private long totalTime = 0; |
618 | 3 | |
619 | 27 | private long groupStart = 0; |
620 | 3 | |
621 | 27 | private int calls = 0; |
622 | 3 | |
623 | 27 | private int requiredDiffCalls = 0; |
624 | |
|
625 | |
private String cacheFileName; |
626 | |
|
627 | |
protected class DiffTask implements Runnable { |
628 | |
private String fileName; |
629 | |
private String newRevision; |
630 | |
private String oldRevision; |
631 | |
private FileBuilder fileBuilder; |
632 | |
|
633 | 0 | protected DiffTask() { |
634 | 0 | } |
635 | 0 | |
636 | 0 | protected DiffTask(final String newRevision) { |
637 | 0 | super(); |
638 | 0 | this.newRevision = newRevision; |
639 | 0 | } |
640 | 0 | |
641 | 0 | public DiffTask(final String fileName, final String newRevision, final String oldRevision, final FileBuilder fileBuilder) { |
642 | 0 | super(); |
643 | 0 | this.fileName = fileName; |
644 | 0 | this.newRevision = newRevision; |
645 | 0 | this.oldRevision = oldRevision; |
646 | 0 | this.fileBuilder = fileBuilder; |
647 | 0 | } |
648 | |
|
649 | |
|
650 | 0 | |
651 | |
|
652 | |
public String getFileName() { |
653 | 0 | return fileName; |
654 | |
} |
655 | |
|
656 | |
|
657 | |
|
658 | 0 | |
659 | 0 | |
660 | |
public void setFileName(final String fileName) { |
661 | 0 | this.fileName = fileName; |
662 | 0 | } |
663 | |
|
664 | |
|
665 | 0 | |
666 | |
|
667 | |
public String getNewRevision() { |
668 | 0 | return newRevision; |
669 | |
} |
670 | |
|
671 | |
|
672 | |
|
673 | 0 | |
674 | 0 | |
675 | |
public void setNewRevision(final String newRevision) { |
676 | 0 | this.newRevision = newRevision; |
677 | 0 | } |
678 | |
|
679 | |
|
680 | 0 | |
681 | |
|
682 | |
public String getOldRevision() { |
683 | 0 | return oldRevision; |
684 | |
} |
685 | |
|
686 | |
|
687 | |
|
688 | 0 | |
689 | 0 | |
690 | |
public void setOldRevision(final String oldRevision) { |
691 | 0 | this.oldRevision = oldRevision; |
692 | 0 | } |
693 | 0 | |
694 | |
public void run() { |
695 | |
int[] lineDiff; |
696 | 0 | long end = 0L; |
697 | 0 | try { |
698 | 0 | |
699 | 0 | |
700 | 0 | final long start = System.currentTimeMillis(); |
701 | 0 | lineDiff = repositoryFileManager.getLineDiff(oldRevision, newRevision, fileName); |
702 | 0 | end = System.currentTimeMillis(); |
703 | 0 | synchronized (cacheBuilder) { |
704 | 0 | totalTime += (end - start); |
705 | 0 | } |
706 | |
|
707 | 0 | SvnConfigurationOptions.getTaskLogger().info( |
708 | 0 | "svn diff " + (++calls) + "/" + requiredDiffCalls + ": " + fileName + ", r" + oldRevision + " to r" + newRevision + ", +" + lineDiff[0] |
709 | 0 | + " -" + lineDiff[1] + " (" + (end - start) + " ms.) " + Thread.currentThread().getName()); |
710 | 0 | } catch (final BinaryDiffException e) { |
711 | 0 | calls++; |
712 | 0 | trackBinaryFile(); |
713 | 0 | return; |
714 | 0 | } catch (final IOException e) { |
715 | 0 | SvnConfigurationOptions.getTaskLogger() |
716 | |
.error("" + (++calls) + "/" + requiredDiffCalls + " IOException: Unable to obtain diff: " + e.toString()); |
717 | 0 | return; |
718 | 0 | } |
719 | 0 | |
720 | 0 | trackFileDiff(lineDiff); |
721 | |
|
722 | 0 | performIntermediarySave(end); |
723 | 0 | } |
724 | 0 | |
725 | 0 | protected void trackBinaryFile() { |
726 | 0 | |
727 | 0 | cacheBuilder.newRevision(fileName, newRevision, "0", "0", true); |
728 | 0 | fileBuilder.setBinary(true); |
729 | 0 | } |
730 | 0 | |
731 | 0 | protected void trackFileDiff(final int[] lineDiff) { |
732 | 0 | if (lineDiff[0] != -1 && lineDiff[1] != -1) { |
733 | 0 | builder.updateRevision(fileName, newRevision, lineDiff[0], lineDiff[1]); |
734 | 0 | cacheBuilder.newRevision(fileName, newRevision, lineDiff[0] + "", lineDiff[1] + "", false); |
735 | 0 | } else { |
736 | 0 | SvnConfigurationOptions.getTaskLogger().info("unknown behaviour; to be investigated:" + fileName + " r:" + oldRevision + "/r:" + newRevision); |
737 | |
} |
738 | 0 | } |
739 | 0 | |
740 | 0 | protected void performIntermediarySave(long end) { |
741 | 0 | synchronized (cacheBuilder) { |
742 | 0 | if (end - groupStart > INTERMEDIARY_SAVE_INTERVAL_MS) { |
743 | 0 | final long start = System.currentTimeMillis(); |
744 | 0 | XMLUtil.writeXmlFile(cacheBuilder.getDocument(), cacheFileName); |
745 | 0 | groupStart = System.currentTimeMillis(); |
746 | 0 | final double estimateLeftInMs = ((double) totalTime / (double) calls * (requiredDiffCalls - calls) / SvnConfigurationOptions |
747 | |
.getNumberSvnDiffThreads()); |
748 | 0 | end = System.currentTimeMillis(); |
749 | 0 | SvnConfigurationOptions.getTaskLogger().info( |
750 | 0 | System.getProperty("line.separator") + new Date() + " Intermediary save took " + (end - start) + " ms. Estimated completion=" |
751 | 0 | + new Date(end + (long) estimateLeftInMs) + System.getProperty("line.separator")); |
752 | |
} |
753 | 0 | } |
754 | 0 | } |
755 | |
|
756 | |
protected FileBuilder getFileBuilder() { |
757 | 0 | return fileBuilder; |
758 | 0 | } |
759 | 0 | |
760 | 0 | protected void setFileBuilder(final FileBuilder fileBuilder) { |
761 | 0 | this.fileBuilder = fileBuilder; |
762 | 0 | } |
763 | |
|
764 | |
} |
765 | |
|
766 | 0 | protected class PerRevDiffTask extends DiffTask { |
767 | |
private Map fileBuilders; |
768 | |
|
769 | 0 | public PerRevDiffTask(final String newRevision, final Map fileBuilders) { |
770 | 0 | super(newRevision); |
771 | 0 | this.fileBuilders = fileBuilders; |
772 | 0 | } |
773 | 0 | |
774 | 0 | public void run() { |
775 | 0 | int[] lineDiff; |
776 | |
Vector results; |
777 | 0 | long end = 0L; |
778 | |
try { |
779 | |
|
780 | |
|
781 | 0 | final long start = System.currentTimeMillis(); |
782 | 0 | results = repositoryFileManager.getRevisionDiff(getNewRevision()); |
783 | 0 | end = System.currentTimeMillis(); |
784 | 0 | synchronized (cacheBuilder) { |
785 | 0 | totalTime += (end - start); |
786 | 0 | } |
787 | 0 | |
788 | 0 | SvnConfigurationOptions.getTaskLogger().info( |
789 | |
"svn diff " + (++calls) + "/" + requiredDiffCalls + " on r" + getNewRevision() + " (" + (end - start) + " ms.) " |
790 | 0 | + Thread.currentThread().getName()); |
791 | 0 | |
792 | 0 | for (int i = 0; i < results.size(); i++) { |
793 | 0 | final Object[] element = (Object[]) results.get(i); |
794 | |
|
795 | 0 | if (element.length == SvnDiffUtils.RESULT_SIZE && fileBuilders.containsKey(element[0].toString())) { |
796 | 0 | setFileName(element[0].toString()); |
797 | 0 | setFileBuilder((FileBuilder) fileBuilders.get(getFileName())); |
798 | 0 | lineDiff = (int[]) element[1]; |
799 | 0 | setOldRevision("?"); |
800 | |
|
801 | 0 | final Boolean isBinary = (Boolean) element[2]; |
802 | 0 | if (isBinary.booleanValue()) { |
803 | 0 | trackBinaryFile(); |
804 | |
} |
805 | 0 | |
806 | 0 | SvnConfigurationOptions.getTaskLogger().info( |
807 | 0 | "\t " + getFileName() + ", on r" + getNewRevision() + ", +" + lineDiff[0] + " -" + lineDiff[1]); |
808 | |
|
809 | 0 | trackFileDiff(lineDiff); |
810 | 0 | } else { |
811 | 0 | SvnConfigurationOptions.getTaskLogger().error("Problem with diff " + i + " for revision " + getNewRevision() + "."); |
812 | 0 | } |
813 | 0 | } |
814 | |
|
815 | 0 | } catch (final BinaryDiffException e) { |
816 | |
|
817 | 0 | return; |
818 | 0 | } catch (final IOException e) { |
819 | 0 | SvnConfigurationOptions.getTaskLogger() |
820 | |
.error("" + (++calls) + "/" + requiredDiffCalls + " IOException: Unable to obtain diff: " + e.toString()); |
821 | 0 | return; |
822 | 0 | } |
823 | |
|
824 | 0 | performIntermediarySave(end); |
825 | 0 | } |
826 | |
} |
827 | &n |