1 | |
package org.apache.maven.index.context; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import java.io.File; |
23 | |
import java.io.IOException; |
24 | |
import java.util.Arrays; |
25 | |
import java.util.Collection; |
26 | |
import java.util.Collections; |
27 | |
import java.util.Date; |
28 | |
import java.util.LinkedHashSet; |
29 | |
import java.util.List; |
30 | |
import java.util.Set; |
31 | |
import java.util.concurrent.locks.ReadWriteLock; |
32 | |
import java.util.concurrent.locks.ReentrantReadWriteLock; |
33 | |
|
34 | |
import org.apache.lucene.analysis.Analyzer; |
35 | |
import org.apache.lucene.document.Document; |
36 | |
import org.apache.lucene.document.Field; |
37 | |
import org.apache.lucene.index.CorruptIndexException; |
38 | |
import org.apache.lucene.index.IndexFileNameFilter; |
39 | |
import org.apache.lucene.index.IndexReader; |
40 | |
import org.apache.lucene.index.IndexWriter; |
41 | |
import org.apache.lucene.index.SerialMergeScheduler; |
42 | |
import org.apache.lucene.index.Term; |
43 | |
import org.apache.lucene.search.IndexSearcher; |
44 | |
import org.apache.lucene.search.TermQuery; |
45 | |
import org.apache.lucene.search.TopDocs; |
46 | |
import org.apache.lucene.search.TopScoreDocCollector; |
47 | |
import org.apache.lucene.store.Directory; |
48 | |
import org.apache.lucene.store.FSDirectory; |
49 | |
import org.apache.maven.index.ArtifactInfo; |
50 | |
import org.apache.maven.index.artifact.GavCalculator; |
51 | |
import org.apache.maven.index.artifact.M2GavCalculator; |
52 | |
import org.codehaus.plexus.util.StringUtils; |
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | 410 | public class DefaultIndexingContext |
61 | |
extends AbstractIndexingContext |
62 | |
{ |
63 | |
|
64 | |
|
65 | |
|
66 | |
private static final String INDEX_DIRECTORY = ".index"; |
67 | |
|
68 | |
public static final String FLD_DESCRIPTOR = "DESCRIPTOR"; |
69 | |
|
70 | |
private static final String FLD_DESCRIPTOR_CONTENTS = "NexusIndex"; |
71 | |
|
72 | |
private static final String FLD_IDXINFO = "IDXINFO"; |
73 | |
|
74 | |
private static final String VERSION = "1.0"; |
75 | |
|
76 | 1 | private static final Term DESCRIPTOR_TERM = new Term( FLD_DESCRIPTOR, FLD_DESCRIPTOR_CONTENTS ); |
77 | |
|
78 | |
private Directory indexDirectory; |
79 | |
|
80 | |
private File indexDirectoryFile; |
81 | |
|
82 | |
private String id; |
83 | |
|
84 | |
private boolean searchable; |
85 | |
|
86 | |
private String repositoryId; |
87 | |
|
88 | |
private File repository; |
89 | |
|
90 | |
private String repositoryUrl; |
91 | |
|
92 | |
private String indexUpdateUrl; |
93 | |
|
94 | |
private IndexReader indexReader; |
95 | |
|
96 | |
private NexusIndexSearcher indexSearcher; |
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
private NexusIndexWriter indexWriter; |
102 | |
|
103 | |
private Date timestamp; |
104 | |
|
105 | |
private List<? extends IndexCreator> indexCreators; |
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
|
111 | |
|
112 | |
private GavCalculator gavCalculator; |
113 | |
|
114 | 475 | private ReadWriteLock indexMaintenanceLock = new ReentrantReadWriteLock(); |
115 | |
|
116 | |
private Thread bottleWarmerThread; |
117 | |
|
118 | |
private DefaultIndexingContext( String id, |
119 | |
String repositoryId, |
120 | |
File repository, |
121 | |
String repositoryUrl, String indexUpdateUrl, |
122 | |
List<? extends IndexCreator> indexCreators, Directory indexDirectory, |
123 | |
boolean reclaimIndex ) |
124 | |
throws UnsupportedExistingLuceneIndexException, IOException |
125 | 475 | { |
126 | 475 | this.id = id; |
127 | |
|
128 | 475 | this.searchable = true; |
129 | |
|
130 | 475 | this.repositoryId = repositoryId; |
131 | |
|
132 | 475 | this.repository = repository; |
133 | |
|
134 | 475 | this.repositoryUrl = repositoryUrl; |
135 | |
|
136 | 475 | this.indexUpdateUrl = indexUpdateUrl; |
137 | |
|
138 | 475 | this.indexReader = null; |
139 | |
|
140 | 475 | this.indexWriter = null; |
141 | |
|
142 | 475 | this.indexCreators = indexCreators; |
143 | |
|
144 | 475 | this.indexDirectory = indexDirectory; |
145 | |
|
146 | |
|
147 | |
|
148 | |
|
149 | |
|
150 | 475 | for ( IndexCreator indexCreator : indexCreators ) |
151 | |
{ |
152 | 1300 | indexCreator.getIndexerFields(); |
153 | |
} |
154 | |
|
155 | 475 | this.gavCalculator = new M2GavCalculator(); |
156 | |
|
157 | 475 | prepareIndex( reclaimIndex ); |
158 | |
|
159 | 475 | installBottleWarmer(); |
160 | 475 | } |
161 | |
|
162 | |
public DefaultIndexingContext( String id, String repositoryId, File repository, File indexDirectoryFile, |
163 | |
String repositoryUrl, String indexUpdateUrl, |
164 | |
List<? extends IndexCreator> indexCreators, boolean reclaimIndex ) |
165 | |
throws IOException, UnsupportedExistingLuceneIndexException |
166 | |
{ |
167 | 102 | this( id, repositoryId, repository, repositoryUrl, indexUpdateUrl, indexCreators, |
168 | |
FSDirectory.open( indexDirectoryFile ), reclaimIndex ); |
169 | |
|
170 | 102 | this.indexDirectoryFile = indexDirectoryFile; |
171 | 102 | } |
172 | |
|
173 | |
public DefaultIndexingContext( String id, String repositoryId, File repository, Directory indexDirectory, |
174 | |
String repositoryUrl, String indexUpdateUrl, |
175 | |
List<? extends IndexCreator> indexCreators, boolean reclaimIndex ) |
176 | |
throws IOException, UnsupportedExistingLuceneIndexException |
177 | |
{ |
178 | 373 | this( id, repositoryId, repository, repositoryUrl, indexUpdateUrl, indexCreators, indexDirectory, reclaimIndex ); |
179 | |
|
180 | 373 | if ( indexDirectory instanceof FSDirectory ) |
181 | |
{ |
182 | 222 | this.indexDirectoryFile = ( (FSDirectory) indexDirectory ).getFile(); |
183 | |
} |
184 | 373 | } |
185 | |
|
186 | |
public void lock() |
187 | |
{ |
188 | 416343 | indexMaintenanceLock.readLock().lock(); |
189 | 416343 | } |
190 | |
|
191 | |
public void unlock() |
192 | |
{ |
193 | 416343 | indexMaintenanceLock.readLock().unlock(); |
194 | 416343 | } |
195 | |
|
196 | |
public void lockExclusively() |
197 | |
{ |
198 | 14031 | indexMaintenanceLock.writeLock().lock(); |
199 | 14031 | } |
200 | |
|
201 | |
public void unlockExclusively() |
202 | |
{ |
203 | 14031 | indexMaintenanceLock.writeLock().unlock(); |
204 | 14031 | } |
205 | |
|
206 | |
public Directory getIndexDirectory() |
207 | |
{ |
208 | 1007 | return indexDirectory; |
209 | |
} |
210 | |
|
211 | |
public File getIndexDirectoryFile() |
212 | |
{ |
213 | 293 | return indexDirectoryFile; |
214 | |
} |
215 | |
|
216 | |
private void prepareIndex( boolean reclaimIndex ) |
217 | |
throws IOException, UnsupportedExistingLuceneIndexException |
218 | |
{ |
219 | 480 | if ( IndexReader.indexExists( indexDirectory ) ) |
220 | |
{ |
221 | |
try |
222 | |
{ |
223 | |
|
224 | 27 | if ( IndexWriter.isLocked( indexDirectory ) ) |
225 | |
{ |
226 | 5 | IndexWriter.unlock( indexDirectory ); |
227 | |
} |
228 | |
|
229 | 27 | openAndWarmup(); |
230 | |
|
231 | 27 | checkAndUpdateIndexDescriptor( reclaimIndex ); |
232 | |
} |
233 | 0 | catch ( IOException e ) |
234 | |
{ |
235 | 0 | if ( reclaimIndex ) |
236 | |
{ |
237 | 0 | prepareCleanIndex( true ); |
238 | |
} |
239 | |
else |
240 | |
{ |
241 | 0 | throw e; |
242 | |
} |
243 | 27 | } |
244 | |
} |
245 | |
else |
246 | |
{ |
247 | 453 | prepareCleanIndex( false ); |
248 | |
} |
249 | |
|
250 | 480 | timestamp = IndexUtils.getTimestamp( indexDirectory ); |
251 | 480 | } |
252 | |
|
253 | |
private void prepareCleanIndex( boolean deleteExisting ) |
254 | |
throws IOException |
255 | |
{ |
256 | 453 | if ( deleteExisting ) |
257 | |
{ |
258 | 0 | closeReaders(); |
259 | |
|
260 | |
|
261 | 0 | if ( IndexWriter.isLocked( indexDirectory ) ) |
262 | |
{ |
263 | 0 | IndexWriter.unlock( indexDirectory ); |
264 | |
} |
265 | |
|
266 | 0 | deleteIndexFiles( true ); |
267 | |
} |
268 | |
|
269 | 453 | openAndWarmup(); |
270 | |
|
271 | 453 | if ( StringUtils.isEmpty( getRepositoryId() ) ) |
272 | |
{ |
273 | 0 | throw new IllegalArgumentException( "The repositoryId cannot be null when creating new repository!" ); |
274 | |
} |
275 | |
|
276 | 453 | storeDescriptor(); |
277 | 453 | } |
278 | |
|
279 | |
private void checkAndUpdateIndexDescriptor( boolean reclaimIndex ) |
280 | |
throws IOException, UnsupportedExistingLuceneIndexException |
281 | |
{ |
282 | 27 | if ( reclaimIndex ) |
283 | |
{ |
284 | |
|
285 | 15 | storeDescriptor(); |
286 | 15 | return; |
287 | |
} |
288 | |
|
289 | |
|
290 | 12 | if ( getIndexReader().numDocs() > 0 ) |
291 | |
{ |
292 | 12 | TopScoreDocCollector collector = TopScoreDocCollector.create( 1, false ); |
293 | |
|
294 | 12 | getIndexSearcher().search( new TermQuery( DESCRIPTOR_TERM ), collector ); |
295 | |
|
296 | 12 | if ( collector.getTotalHits() == 0 ) |
297 | |
{ |
298 | 0 | throw new UnsupportedExistingLuceneIndexException( "The existing index has no NexusIndexer descriptor" ); |
299 | |
} |
300 | |
|
301 | 12 | if ( collector.getTotalHits() > 1 ) |
302 | |
{ |
303 | |
|
304 | 0 | storeDescriptor(); |
305 | 0 | return; |
306 | |
} |
307 | |
else |
308 | |
{ |
309 | |
|
310 | 12 | Document descriptor = getIndexSearcher().doc( collector.topDocs().scoreDocs[0].doc ); |
311 | 12 | String[] h = StringUtils.split( descriptor.get( FLD_IDXINFO ), ArtifactInfo.FS ); |
312 | |
|
313 | 12 | String repoId = h[1]; |
314 | |
|
315 | |
|
316 | |
|
317 | |
|
318 | |
|
319 | |
|
320 | |
|
321 | |
|
322 | 12 | if ( getRepositoryId() == null ) |
323 | |
{ |
324 | 0 | repositoryId = repoId; |
325 | |
} |
326 | 12 | else if ( !getRepositoryId().equals( repoId ) ) |
327 | |
{ |
328 | 0 | throw new UnsupportedExistingLuceneIndexException( "The existing index is for repository " |
329 | |
+ "[" + repoId + "] and not for repository [" + getRepositoryId() + "]" ); |
330 | |
} |
331 | |
} |
332 | |
} |
333 | 12 | } |
334 | |
|
335 | |
private void storeDescriptor() |
336 | |
throws IOException |
337 | |
{ |
338 | 721 | Document hdr = new Document(); |
339 | |
|
340 | 721 | hdr.add( new Field( FLD_DESCRIPTOR, FLD_DESCRIPTOR_CONTENTS, Field.Store.YES, Field.Index.NOT_ANALYZED ) ); |
341 | |
|
342 | 721 | hdr.add( new Field( FLD_IDXINFO, VERSION + ArtifactInfo.FS + getRepositoryId(), Field.Store.YES, Field.Index.NO ) ); |
343 | |
|
344 | 721 | IndexWriter w = getIndexWriter(); |
345 | |
|
346 | 721 | w.updateDocument( DESCRIPTOR_TERM, hdr ); |
347 | |
|
348 | 721 | w.commit(); |
349 | 721 | } |
350 | |
|
351 | |
private void deleteIndexFiles( boolean full ) |
352 | |
throws IOException |
353 | |
{ |
354 | 556 | if ( indexDirectory != null ) |
355 | |
{ |
356 | 556 | String[] names = indexDirectory.listAll(); |
357 | |
|
358 | 556 | if ( names != null ) |
359 | |
{ |
360 | 556 | IndexFileNameFilter filter = IndexFileNameFilter.getFilter(); |
361 | |
|
362 | 6912 | for ( int i = 0; i < names.length; i++ ) |
363 | |
{ |
364 | 6356 | if ( filter.accept( null, names[i] ) ) |
365 | |
{ |
366 | 5848 | indexDirectory.deleteFile( names[i] ); |
367 | |
} |
368 | |
} |
369 | |
} |
370 | |
|
371 | 556 | if ( full ) |
372 | |
{ |
373 | 303 | if ( indexDirectory.fileExists( INDEX_PACKER_PROPERTIES_FILE ) ) |
374 | |
{ |
375 | 21 | indexDirectory.deleteFile( INDEX_PACKER_PROPERTIES_FILE ); |
376 | |
} |
377 | |
|
378 | 303 | if ( indexDirectory.fileExists( INDEX_UPDATER_PROPERTIES_FILE ) ) |
379 | |
{ |
380 | 11 | indexDirectory.deleteFile( INDEX_UPDATER_PROPERTIES_FILE ); |
381 | |
} |
382 | |
} |
383 | |
|
384 | 556 | IndexUtils.deleteTimestamp( indexDirectory ); |
385 | |
} |
386 | 556 | } |
387 | |
|
388 | |
public boolean isSearchable() |
389 | |
{ |
390 | 204 | return searchable; |
391 | |
} |
392 | |
|
393 | |
public void setSearchable( boolean searchable ) |
394 | |
{ |
395 | 8 | this.searchable = searchable; |
396 | 8 | } |
397 | |
|
398 | |
public String getId() |
399 | |
{ |
400 | 69115 | return id; |
401 | |
} |
402 | |
|
403 | |
public void updateTimestamp() |
404 | |
throws IOException |
405 | |
{ |
406 | 11575 | updateTimestamp( false ); |
407 | 11575 | } |
408 | |
|
409 | |
public void updateTimestamp( boolean save ) |
410 | |
throws IOException |
411 | |
{ |
412 | 11998 | updateTimestamp( save, new Date() ); |
413 | 11998 | } |
414 | |
|
415 | |
public void updateTimestamp( boolean save, Date timestamp ) |
416 | |
throws IOException |
417 | |
{ |
418 | 12260 | this.timestamp = timestamp; |
419 | |
|
420 | 12260 | if ( save ) |
421 | |
{ |
422 | 685 | IndexUtils.updateTimestamp( indexDirectory, getTimestamp() ); |
423 | |
} |
424 | 12260 | } |
425 | |
|
426 | |
public Date getTimestamp() |
427 | |
{ |
428 | 2667 | return timestamp; |
429 | |
} |
430 | |
|
431 | |
public int getSize() |
432 | |
throws IOException |
433 | |
{ |
434 | 0 | return getIndexReader().numDocs(); |
435 | |
} |
436 | |
|
437 | |
public String getRepositoryId() |
438 | |
{ |
439 | 78263 | return repositoryId; |
440 | |
} |
441 | |
|
442 | |
public File getRepository() |
443 | |
{ |
444 | 28501 | return repository; |
445 | |
} |
446 | |
|
447 | |
public String getRepositoryUrl() |
448 | |
{ |
449 | 216 | return repositoryUrl; |
450 | |
} |
451 | |
|
452 | |
public String getIndexUpdateUrl() |
453 | |
{ |
454 | 232 | if ( repositoryUrl != null ) |
455 | |
{ |
456 | 28 | if ( indexUpdateUrl == null || indexUpdateUrl.trim().length() == 0 ) |
457 | |
{ |
458 | 20 | return repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + INDEX_DIRECTORY; |
459 | |
} |
460 | |
} |
461 | 212 | return indexUpdateUrl; |
462 | |
} |
463 | |
|
464 | |
public Analyzer getAnalyzer() |
465 | |
{ |
466 | 20 | return new NexusAnalyzer(); |
467 | |
} |
468 | |
|
469 | |
protected void openAndWarmup() |
470 | |
throws IOException |
471 | |
{ |
472 | |
|
473 | 738 | if ( indexWriter != null ) |
474 | |
{ |
475 | 5 | indexWriter.close(); |
476 | |
|
477 | 5 | indexWriter = null; |
478 | |
} |
479 | |
|
480 | 738 | if ( indexSearcher != null ) |
481 | |
{ |
482 | 5 | indexSearcher.close(); |
483 | |
|
484 | 5 | indexSearcher = null; |
485 | |
} |
486 | |
|
487 | 738 | if ( indexReader != null ) |
488 | |
{ |
489 | 5 | indexReader.close(); |
490 | |
|
491 | 5 | indexReader = null; |
492 | |
} |
493 | |
|
494 | |
|
495 | 738 | final boolean create = !IndexReader.indexExists( indexDirectory ); |
496 | |
|
497 | 738 | indexWriter = new NexusIndexWriter( getIndexDirectory(), new NexusAnalyzer(), create ); |
498 | |
|
499 | 738 | indexWriter.setRAMBufferSizeMB( 2 ); |
500 | |
|
501 | 738 | indexWriter.setMergeScheduler( new SerialMergeScheduler() ); |
502 | |
|
503 | 738 | indexWriter.commit(); |
504 | |
|
505 | 738 | openAndWarmupReaders(); |
506 | 738 | } |
507 | |
|
508 | |
protected void openAndWarmupReaders() |
509 | |
throws IOException |
510 | |
{ |
511 | 7071 | if ( indexReader != null && indexReader.isCurrent() ) |
512 | |
{ |
513 | 63 | return; |
514 | |
} |
515 | |
|
516 | |
|
517 | 7008 | IndexReader newIndexReader = IndexReader.open( indexDirectory, true ); |
518 | |
|
519 | |
|
520 | 7008 | NexusIndexSearcher newIndexSearcher = new NexusIndexSearcher( this, newIndexReader ); |
521 | |
|
522 | |
|
523 | 7008 | warmUp( newIndexSearcher ); |
524 | |
|
525 | 7008 | lockExclusively(); |
526 | |
|
527 | |
try |
528 | |
{ |
529 | |
|
530 | 7008 | if ( indexSearcher != null ) |
531 | |
{ |
532 | 6270 | indexSearcher.close(); |
533 | |
} |
534 | |
|
535 | 7008 | if ( indexReader != null ) |
536 | |
{ |
537 | 6270 | indexReader.close(); |
538 | |
} |
539 | |
|
540 | 7008 | indexReader = newIndexReader; |
541 | |
|
542 | 7008 | indexSearcher = newIndexSearcher; |
543 | |
} |
544 | |
finally |
545 | |
{ |
546 | 7008 | unlockExclusively(); |
547 | 7008 | } |
548 | 7008 | } |
549 | |
|
550 | |
protected void warmUp( NexusIndexSearcher searcher ) |
551 | |
throws IOException |
552 | |
{ |
553 | |
try |
554 | |
{ |
555 | |
|
556 | 7008 | searcher.search( new TermQuery( new Term( "g", "org.apache" ) ), 1000 ); |
557 | |
} |
558 | 0 | catch ( IOException e ) |
559 | |
{ |
560 | 0 | close( false ); |
561 | |
|
562 | 0 | throw e; |
563 | 7008 | } |
564 | 7008 | } |
565 | |
|
566 | |
public IndexWriter getIndexWriter() |
567 | |
throws IOException |
568 | |
{ |
569 | 20357 | lock(); |
570 | |
|
571 | |
try |
572 | |
{ |
573 | 20357 | return indexWriter; |
574 | |
} |
575 | |
finally |
576 | |
{ |
577 | 20357 | unlock(); |
578 | |
} |
579 | |
} |
580 | |
|
581 | |
public IndexReader getIndexReader() |
582 | |
throws IOException |
583 | |
{ |
584 | 283212 | lock(); |
585 | |
|
586 | |
try |
587 | |
{ |
588 | 283212 | return indexReader; |
589 | |
} |
590 | |
finally |
591 | |
{ |
592 | 283212 | unlock(); |
593 | |
} |
594 | |
} |
595 | |
|
596 | |
public IndexSearcher getIndexSearcher() |
597 | |
throws IOException |
598 | |
{ |
599 | 96674 | lock(); |
600 | |
|
601 | |
try |
602 | |
{ |
603 | 96674 | return indexSearcher; |
604 | |
} |
605 | |
finally |
606 | |
{ |
607 | 96674 | unlock(); |
608 | |
} |
609 | |
} |
610 | |
|
611 | |
public void commit() |
612 | |
throws IOException |
613 | |
{ |
614 | |
|
615 | |
if ( true ) |
616 | |
{ |
617 | 5641 | if ( BLOCKING_COMMIT ) |
618 | |
{ |
619 | 5105 | lockExclusively(); |
620 | |
} |
621 | |
else |
622 | |
{ |
623 | 536 | lock(); |
624 | |
} |
625 | |
|
626 | |
try |
627 | |
{ |
628 | 5641 | doCommit( BLOCKING_COMMIT ); |
629 | |
} |
630 | |
finally |
631 | |
{ |
632 | 5641 | if ( BLOCKING_COMMIT ) |
633 | |
{ |
634 | 5105 | unlockExclusively(); |
635 | |
} |
636 | |
else |
637 | |
{ |
638 | 536 | unlock(); |
639 | |
} |
640 | 536 | } |
641 | |
} |
642 | 5641 | } |
643 | |
|
644 | |
protected void doCommit( boolean blocking ) |
645 | |
throws IOException |
646 | |
{ |
647 | |
try |
648 | |
{ |
649 | |
|
650 | |
|
651 | 6851 | synchronized ( this ) |
652 | |
{ |
653 | 6851 | getIndexWriter().commit(); |
654 | 6851 | } |
655 | |
|
656 | |
|
657 | |
|
658 | |
|
659 | |
if ( true ) |
660 | |
{ |
661 | 6851 | if ( blocking ) |
662 | |
{ |
663 | 6315 | openAndWarmupReaders(); |
664 | |
} |
665 | |
else |
666 | |
{ |
667 | 536 | flagNeedsReopen(); |
668 | |
} |
669 | |
} |
670 | |
} |
671 | 0 | catch ( CorruptIndexException e ) |
672 | |
{ |
673 | 0 | close( false ); |
674 | |
|
675 | 0 | throw e; |
676 | |
} |
677 | 0 | catch ( IOException e ) |
678 | |
{ |
679 | 0 | close( false ); |
680 | |
|
681 | 0 | throw e; |
682 | 6851 | } |
683 | 6851 | } |
684 | |
|
685 | |
public void rollback() |
686 | |
throws IOException |
687 | |
{ |
688 | |
|
689 | |
if ( true ) |
690 | |
{ |
691 | 0 | lock(); |
692 | |
|
693 | |
try |
694 | |
{ |
695 | 0 | IndexWriter w = getIndexWriter(); |
696 | |
|
697 | |
try |
698 | |
{ |
699 | 0 | synchronized ( this ) |
700 | |
{ |
701 | 0 | w.rollback(); |
702 | 0 | } |
703 | |
} |
704 | 0 | catch ( CorruptIndexException e ) |
705 | |
{ |
706 | 0 | close( false ); |
707 | |
|
708 | 0 | throw e; |
709 | |
} |
710 | 0 | catch ( IOException e ) |
711 | |
{ |
712 | 0 | close( false ); |
713 | |
|
714 | 0 | throw e; |
715 | 0 | } |
716 | |
} |
717 | |
finally |
718 | |
{ |
719 | 0 | unlock(); |
720 | 0 | } |
721 | |
} |
722 | 0 | } |
723 | |
|
724 | |
public void optimize() |
725 | |
throws CorruptIndexException, IOException |
726 | |
{ |
727 | 696 | lockExclusively(); |
728 | |
|
729 | |
try |
730 | |
{ |
731 | 696 | IndexWriter w = getIndexWriter(); |
732 | |
|
733 | |
try |
734 | |
{ |
735 | 696 | w.optimize(); |
736 | |
|
737 | 696 | doCommit( true ); |
738 | |
} |
739 | 0 | catch ( CorruptIndexException e ) |
740 | |
{ |
741 | 0 | close( false ); |
742 | |
|
743 | 0 | throw e; |
744 | |
} |
745 | 0 | catch ( IOException e ) |
746 | |
{ |
747 | 0 | close( false ); |
748 | |
|
749 | 0 | throw e; |
750 | 696 | } |
751 | |
} |
752 | |
finally |
753 | |
{ |
754 | 696 | unlockExclusively(); |
755 | 696 | } |
756 | 696 | } |
757 | |
|
758 | |
public void close( boolean deleteFiles ) |
759 | |
throws IOException |
760 | |
{ |
761 | 437 | lockExclusively(); |
762 | |
|
763 | |
try |
764 | |
{ |
765 | 437 | if ( indexDirectory != null ) |
766 | |
{ |
767 | 437 | IndexUtils.updateTimestamp( indexDirectory, getTimestamp() ); |
768 | |
|
769 | 437 | closeReaders(); |
770 | |
|
771 | 437 | if ( deleteFiles ) |
772 | |
{ |
773 | 298 | deleteIndexFiles( true ); |
774 | |
} |
775 | |
|
776 | 437 | indexDirectory.close(); |
777 | |
} |
778 | |
|
779 | |
|
780 | |
|
781 | 437 | indexDirectory = null; |
782 | |
} |
783 | |
finally |
784 | |
{ |
785 | 437 | unlockExclusively(); |
786 | 437 | } |
787 | 437 | } |
788 | |
|
789 | |
public void purge() |
790 | |
throws IOException |
791 | |
{ |
792 | 5 | lockExclusively(); |
793 | |
|
794 | |
try |
795 | |
{ |
796 | 5 | closeReaders(); |
797 | |
|
798 | 5 | deleteIndexFiles( true ); |
799 | |
|
800 | 5 | openAndWarmup(); |
801 | |
|
802 | |
try |
803 | |
{ |
804 | 5 | prepareIndex( true ); |
805 | |
} |
806 | 0 | catch ( UnsupportedExistingLuceneIndexException e ) |
807 | |
{ |
808 | |
|
809 | 5 | } |
810 | |
|
811 | 5 | rebuildGroups(); |
812 | |
|
813 | 5 | updateTimestamp( true, null ); |
814 | |
} |
815 | |
finally |
816 | |
{ |
817 | 5 | unlockExclusively(); |
818 | 5 | } |
819 | 5 | } |
820 | |
|
821 | |
public void replace( Directory directory ) |
822 | |
throws IOException |
823 | |
{ |
824 | 253 | lockExclusively(); |
825 | |
|
826 | |
try |
827 | |
{ |
828 | 253 | Date ts = IndexUtils.getTimestamp( directory ); |
829 | |
|
830 | 253 | closeReaders(); |
831 | |
|
832 | 253 | deleteIndexFiles( false ); |
833 | |
|
834 | 253 | IndexUtils.copyDirectory( directory, indexDirectory ); |
835 | |
|
836 | 253 | openAndWarmup(); |
837 | |
|
838 | |
|
839 | 253 | storeDescriptor(); |
840 | |
|
841 | 253 | updateTimestamp( true, ts ); |
842 | |
|
843 | 253 | optimize(); |
844 | |
} |
845 | |
finally |
846 | |
{ |
847 | 253 | unlockExclusively(); |
848 | 253 | } |
849 | 253 | } |
850 | |
|
851 | |
public void merge( Directory directory ) |
852 | |
throws IOException |
853 | |
{ |
854 | 8 | merge( directory, null ); |
855 | 8 | } |
856 | |
|
857 | |
public void merge( Directory directory, DocumentFilter filter ) |
858 | |
throws IOException |
859 | |
{ |
860 | 8 | lockExclusively(); |
861 | |
|
862 | |
try |
863 | |
{ |
864 | 8 | IndexWriter w = getIndexWriter(); |
865 | |
|
866 | 8 | IndexSearcher s = getIndexSearcher(); |
867 | |
|
868 | 8 | IndexReader directoryReader = IndexReader.open( directory, true ); |
869 | |
|
870 | 8 | TopScoreDocCollector collector = null; |
871 | |
|
872 | |
try |
873 | |
{ |
874 | 8 | int numDocs = directoryReader.maxDoc(); |
875 | |
|
876 | 60 | for ( int i = 0; i < numDocs; i++ ) |
877 | |
{ |
878 | 52 | if ( directoryReader.isDeleted( i ) ) |
879 | |
{ |
880 | 2 | continue; |
881 | |
} |
882 | |
|
883 | 50 | Document d = directoryReader.document( i ); |
884 | |
|
885 | 50 | if ( filter != null && !filter.accept( d ) ) |
886 | |
{ |
887 | 0 | continue; |
888 | |
} |
889 | |
|
890 | 50 | String uinfo = d.get( ArtifactInfo.UINFO ); |
891 | |
|
892 | 50 | if ( uinfo != null ) |
893 | |
{ |
894 | 27 | collector = TopScoreDocCollector.create( 1, false ); |
895 | |
|
896 | 27 | s.search( new TermQuery( new Term( ArtifactInfo.UINFO, uinfo ) ), collector ); |
897 | |
|
898 | 27 | if ( collector.getTotalHits() == 0 ) |
899 | |
{ |
900 | 17 | w.addDocument( IndexUtils.updateDocument( d, this, false ) ); |
901 | |
} |
902 | |
} |
903 | |
else |
904 | |
{ |
905 | 23 | String deleted = d.get( ArtifactInfo.DELETED ); |
906 | |
|
907 | 23 | if ( deleted != null ) |
908 | |
{ |
909 | |
|
910 | |
|
911 | |
|
912 | 2 | w.deleteDocuments( new Term( ArtifactInfo.UINFO, deleted ) ); |
913 | 2 | w.addDocument( d ); |
914 | |
} |
915 | |
} |
916 | |
} |
917 | |
|
918 | |
} |
919 | |
finally |
920 | |
{ |
921 | 8 | directoryReader.close(); |
922 | |
|
923 | 8 | doCommit( true ); |
924 | 8 | } |
925 | |
|
926 | 8 | rebuildGroups(); |
927 | |
|
928 | 8 | Date mergedTimestamp = IndexUtils.getTimestamp( directory ); |
929 | |
|
930 | 8 | if ( getTimestamp() != null && mergedTimestamp != null && mergedTimestamp.after( getTimestamp() ) ) |
931 | |
{ |
932 | |
|
933 | 4 | updateTimestamp( true, mergedTimestamp ); |
934 | |
} |
935 | |
else |
936 | |
{ |
937 | 4 | updateTimestamp( true ); |
938 | |
} |
939 | |
|
940 | 8 | optimize(); |
941 | |
} |
942 | |
finally |
943 | |
{ |
944 | 8 | unlockExclusively(); |
945 | 8 | } |
946 | 8 | } |
947 | |
|
948 | |
private void closeReaders() |
949 | |
throws CorruptIndexException, IOException |
950 | |
{ |
951 | 695 | if ( indexWriter != null ) |
952 | |
{ |
953 | 695 | indexWriter.close(); |
954 | |
|
955 | 695 | indexWriter = null; |
956 | |
} |
957 | 695 | if ( indexSearcher != null ) |
958 | |
{ |
959 | 695 | indexSearcher.close(); |
960 | |
|
961 | 695 | indexSearcher = null; |
962 | |
} |
963 | 695 | if ( indexReader != null ) |
964 | |
{ |
965 | 695 | indexReader.close(); |
966 | |
|
967 | 695 | indexReader = null; |
968 | |
} |
969 | 695 | } |
970 | |
|
971 | |
public GavCalculator getGavCalculator() |
972 | |
{ |
973 | 21945 | return gavCalculator; |
974 | |
} |
975 | |
|
976 | |
public List<IndexCreator> getIndexCreators() |
977 | |
{ |
978 | 438019 | return Collections.unmodifiableList( indexCreators ); |
979 | |
} |
980 | |
|
981 | |
|
982 | |
|
983 | |
public void rebuildGroups() |
984 | |
throws IOException |
985 | |
{ |
986 | 13 | lockExclusively(); |
987 | |
|
988 | |
try |
989 | |
{ |
990 | 13 | IndexReader r = getIndexReader(); |
991 | |
|
992 | 13 | Set<String> rootGroups = new LinkedHashSet<String>(); |
993 | 13 | Set<String> allGroups = new LinkedHashSet<String>(); |
994 | |
|
995 | 13 | int numDocs = r.maxDoc(); |
996 | |
|
997 | 83 | for ( int i = 0; i < numDocs; i++ ) |
998 | |
{ |
999 | 70 | if ( r.isDeleted( i ) ) |
1000 | |
{ |
1001 | 3 | continue; |
1002 | |
} |
1003 | |
|
1004 | 67 | Document d = r.document( i ); |
1005 | |
|
1006 | 67 | String uinfo = d.get( ArtifactInfo.UINFO ); |
1007 | |
|
1008 | 67 | if ( uinfo != null ) |
1009 | |
{ |
1010 | 41 | ArtifactInfo info = IndexUtils.constructArtifactInfo( d, this ); |
1011 | 41 | rootGroups.add( info.getRootGroup() ); |
1012 | 41 | allGroups.add( info.groupId ); |
1013 | |
} |
1014 | |
} |
1015 | |
|
1016 | 13 | setRootGroups( rootGroups ); |
1017 | 13 | setAllGroups( allGroups ); |
1018 | |
|
1019 | 13 | optimize(); |
1020 | |
} |
1021 | |
finally |
1022 | |
{ |
1023 | 13 | unlockExclusively(); |
1024 | 13 | } |
1025 | 13 | } |
1026 | |
|
1027 | |
public Set<String> getAllGroups() |
1028 | |
throws IOException |
1029 | |
{ |
1030 | 5631 | lock(); |
1031 | |
|
1032 | |
try |
1033 | |
{ |
1034 | 5631 | return getGroups( ArtifactInfo.ALL_GROUPS, ArtifactInfo.ALL_GROUPS_VALUE, ArtifactInfo.ALL_GROUPS_LIST ); |
1035 | |
} |
1036 | |
finally |
1037 | |
{ |
1038 | 5631 | unlock(); |
1039 | |
} |
1040 | |
} |
1041 | |
|
1042 | |
public void setAllGroups( Collection<String> groups ) |
1043 | |
throws IOException |
1044 | |
{ |
1045 | 255 | lockExclusively(); |
1046 | |
|
1047 | |
try |
1048 | |
{ |
1049 | 255 | setGroups( groups, ArtifactInfo.ALL_GROUPS, ArtifactInfo.ALL_GROUPS_VALUE, ArtifactInfo.ALL_GROUPS_LIST ); |
1050 | |
|
1051 | 255 | doCommit( true ); |
1052 | |
} |
1053 | |
finally |
1054 | |
{ |
1055 | 255 | unlockExclusively(); |
1056 | 255 | } |
1057 | 255 | } |
1058 | |
|
1059 | |
public Set<String> getRootGroups() |
1060 | |
throws IOException |
1061 | |
{ |
1062 | 5602 | lock(); |
1063 | |
|
1064 | |
try |
1065 | |
{ |
1066 | 5602 | return getGroups( ArtifactInfo.ROOT_GROUPS, ArtifactInfo.ROOT_GROUPS_VALUE, ArtifactInfo.ROOT_GROUPS_LIST ); |
1067 | |
} |
1068 | |
finally |
1069 | |
{ |
1070 | 5602 | unlock(); |
1071 | |
} |
1072 | |
} |
1073 | |
|
1074 | |
public void setRootGroups( Collection<String> groups ) |
1075 | |
throws IOException |
1076 | |
{ |
1077 | 251 | lockExclusively(); |
1078 | |
|
1079 | |
try |
1080 | |
{ |
1081 | 251 | setGroups( groups, ArtifactInfo.ROOT_GROUPS, ArtifactInfo.ROOT_GROUPS_VALUE, ArtifactInfo.ROOT_GROUPS_LIST ); |
1082 | |
|
1083 | 251 | doCommit( true ); |
1084 | |
} |
1085 | |
finally |
1086 | |
{ |
1087 | 251 | unlockExclusively(); |
1088 | 251 | } |
1089 | 251 | } |
1090 | |
|
1091 | |
protected Set<String> getGroups( String field, String filedValue, String listField ) |
1092 | |
throws IOException, CorruptIndexException |
1093 | |
{ |
1094 | 11233 | TopScoreDocCollector collector = TopScoreDocCollector.create( 1, false ); |
1095 | |
|
1096 | 11233 | getIndexSearcher().search( new TermQuery( new Term( field, filedValue ) ), collector ); |
1097 | |
|
1098 | 11233 | TopDocs topDocs = collector.topDocs(); |
1099 | |
|
1100 | 11233 | Set<String> groups = new LinkedHashSet<String>( Math.max( 10, topDocs.totalHits ) ); |
1101 | |
|
1102 | 11233 | if ( topDocs.totalHits > 0 ) |
1103 | |
{ |
1104 | 11201 | Document doc = getIndexSearcher().doc( topDocs.scoreDocs[0].doc ); |
1105 | |
|
1106 | 11201 | String groupList = doc.get( listField ); |
1107 | |
|
1108 | 11201 | if ( groupList != null ) |
1109 | |
{ |
1110 | 11201 | groups.addAll( Arrays.asList( groupList.split( "\\|" ) ) ); |
1111 | |
} |
1112 | |
} |
1113 | |
|
1114 | 11233 | return groups; |
1115 | |
} |
1116 | |
|
1117 | |
protected void setGroups( Collection<String> groups, String groupField, String groupFieldValue, |
1118 | |
String groupListField ) |
1119 | |
throws IOException, CorruptIndexException |
1120 | |
{ |
1121 | 506 | IndexWriter w = getIndexWriter(); |
1122 | |
|
1123 | 506 | w.updateDocument( new Term( groupField, groupFieldValue ), |
1124 | |
createGroupsDocument( groups, groupField, groupFieldValue, groupListField ) ); |
1125 | 506 | } |
1126 | |
|
1127 | |
protected Document createGroupsDocument( Collection<String> groups, String field, String fieldValue, |
1128 | |
String listField ) |
1129 | |
{ |
1130 | 506 | Document groupDoc = new Document(); |
1131 | |
|
1132 | 506 | groupDoc.add( new Field( field, |
1133 | |
fieldValue, Field.Store.YES, Field.Index.NOT_ANALYZED ) ); |
1134 | |
|
1135 | 506 | groupDoc.add( new Field( listField, |
1136 | |
ArtifactInfo.lst2str( groups ), Field.Store.YES, Field.Index.NO ) ); |
1137 | |
|
1138 | 506 | return groupDoc; |
1139 | |
} |
1140 | |
|
1141 | |
@Override |
1142 | |
public String toString() |
1143 | |
{ |
1144 | 0 | return id + " : " + timestamp; |
1145 | |
} |
1146 | |
|
1147 | |
|
1148 | |
|
1149 | 475 | private volatile boolean needsReaderReopen = false; |
1150 | |
|
1151 | |
protected void flagNeedsReopen() |
1152 | |
{ |
1153 | 536 | needsReaderReopen = true; |
1154 | 536 | } |
1155 | |
|
1156 | |
protected void unflagNeedsReopen() |
1157 | |
{ |
1158 | 18 | needsReaderReopen = false; |
1159 | 18 | } |
1160 | |
|
1161 | |
protected boolean isReopenNeeded() |
1162 | |
{ |
1163 | 390 | return needsReaderReopen; |
1164 | |
} |
1165 | |
|
1166 | |
protected void installBottleWarmer() |
1167 | |
{ |
1168 | 475 | if ( BLOCKING_COMMIT ) |
1169 | |
{ |
1170 | 447 | return; |
1171 | |
} |
1172 | |
|
1173 | 28 | Runnable bottleWarmer = new Runnable() |
1174 | 28 | { |
1175 | |
public void run() |
1176 | |
{ |
1177 | |
|
1178 | 410 | while ( indexDirectory != null ) |
1179 | |
{ |
1180 | |
try |
1181 | |
{ |
1182 | 390 | if ( isReopenNeeded() ) |
1183 | |
{ |
1184 | 18 | openAndWarmupReaders(); |
1185 | |
|
1186 | 18 | unflagNeedsReopen(); |
1187 | |
} |
1188 | |
|
1189 | 390 | Thread.sleep( 1000 ); |
1190 | |
} |
1191 | 0 | catch ( Exception e ) |
1192 | |
{ |
1193 | 0 | e.printStackTrace(); |
1194 | 382 | } |
1195 | |
} |
1196 | 20 | } |
1197 | |
}; |
1198 | |
|
1199 | 28 | bottleWarmerThread = new Thread( bottleWarmer, "Index-BottleWarmer-" + id ); |
1200 | 28 | bottleWarmerThread.setDaemon( true ); |
1201 | 28 | bottleWarmerThread.start(); |
1202 | 28 | } |
1203 | |
|
1204 | |
|
1205 | |
|
1206 | |
|
1207 | |
|
1208 | |
|
1209 | |
|
1210 | 1 | public static boolean BLOCKING_COMMIT = false; |
1211 | |
} |