KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > search > indexing > IndexManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.search.indexing;
12
13 import java.io.*;
14 import java.util.*;
15 import java.util.zip.CRC32 JavaDoc;
16
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.runtime.IPath;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.Path;
21 import org.eclipse.jdt.core.*;
22 import org.eclipse.jdt.core.compiler.CharOperation;
23 import org.eclipse.jdt.core.search.*;
24 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
25 import org.eclipse.jdt.internal.compiler.SourceElementParser;
26 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
27 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
28 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
29 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
30 import org.eclipse.jdt.internal.core.*;
31 import org.eclipse.jdt.internal.core.index.*;
32 import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
33 import org.eclipse.jdt.internal.core.search.PatternSearchJob;
34 import org.eclipse.jdt.internal.core.search.processing.IJob;
35 import org.eclipse.jdt.internal.core.search.processing.JobManager;
36 import org.eclipse.jdt.internal.core.util.Messages;
37 import org.eclipse.jdt.internal.core.util.Util;
38
39 public class IndexManager extends JobManager implements IIndexConstants {
40
41     // key = containerPath, value = indexLocation path
42
// indexLocation path is created by appending an index file name to the getJavaPluginWorkingLocation() path
43
public SimpleLookupTable indexLocations = new SimpleLookupTable();
44     // key = indexLocation path, value = an index
45
private SimpleLookupTable indexes = new SimpleLookupTable();
46
47     /* need to save ? */
48     private boolean needToSave = false;
49     private static final CRC32 JavaDoc checksumCalculator = new CRC32 JavaDoc();
50     private IPath javaPluginLocation = null;
51
52     /* can only replace a current state if its less than the new one */
53     // key = indexLocation path, value = index state integer
54
private SimpleLookupTable indexStates = null;
55     private File savedIndexNamesFile = new File(getSavedIndexesDirectory(), "savedIndexNames.txt"); //$NON-NLS-1$
56
public static Integer JavaDoc SAVED_STATE = new Integer JavaDoc(0);
57     public static Integer JavaDoc UPDATING_STATE = new Integer JavaDoc(1);
58     public static Integer JavaDoc UNKNOWN_STATE = new Integer JavaDoc(2);
59     public static Integer JavaDoc REBUILDING_STATE = new Integer JavaDoc(3);
60
61 public synchronized void aboutToUpdateIndex(IPath containerPath, Integer JavaDoc newIndexState) {
62     // newIndexState is either UPDATING_STATE or REBUILDING_STATE
63
// must tag the index as inconsistent, in case we exit before the update job is started
64
IPath indexLocation = computeIndexLocation(containerPath);
65     Object JavaDoc state = getIndexStates().get(indexLocation);
66     Integer JavaDoc currentIndexState = state == null ? UNKNOWN_STATE : (Integer JavaDoc) state;
67     if (currentIndexState.equals(REBUILDING_STATE)) return; // already rebuilding the index
68

69     int compare = newIndexState.compareTo(currentIndexState);
70     if (compare > 0) {
71         // so UPDATING_STATE replaces SAVED_STATE and REBUILDING_STATE replaces everything
72
updateIndexState(indexLocation, newIndexState);
73     } else if (compare < 0 && this.indexes.get(indexLocation) == null) {
74         // if already cached index then there is nothing more to do
75
rebuildIndex(indexLocation, containerPath);
76     }
77 }
78 /**
79  * Trigger addition of a resource to an index
80  * Note: the actual operation is performed in background
81  */

82 public void addBinary(IFile resource, IPath containerPath) {
83     if (JavaCore.getPlugin() == null) return;
84     SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
85     SearchDocument document = participant.getDocument(resource.getFullPath().toString());
86     IPath indexLocation = computeIndexLocation(containerPath);
87     scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
88 }
89 /**
90  * Trigger addition of a resource to an index
91  * Note: the actual operation is performed in background
92  */

93 public void addSource(IFile resource, IPath containerPath, SourceElementParser parser) {
94     if (JavaCore.getPlugin() == null) return;
95     SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
96     SearchDocument document = participant.getDocument(resource.getFullPath().toString());
97     ((InternalSearchDocument) document).parser = parser;
98     IPath indexLocation = computeIndexLocation(containerPath);
99     scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
100 }
101 /*
102  * Removes unused indexes from disk.
103  */

104 public void cleanUpIndexes() {
105     SimpleSet knownPaths = new SimpleSet();
106     IJavaSearchScope scope = BasicSearchEngine.createWorkspaceScope();
107     PatternSearchJob job = new PatternSearchJob(null, SearchEngine.getDefaultSearchParticipant(), scope, null);
108     Index[] selectedIndexes = job.getIndexes(null);
109     for (int i = 0, l = selectedIndexes.length; i < l; i++) {
110         String JavaDoc path = selectedIndexes[i].getIndexFile().getAbsolutePath();
111         knownPaths.add(path);
112     }
113
114     if (this.indexStates != null) {
115         Object JavaDoc[] keys = this.indexStates.keyTable;
116         IPath[] locations = new IPath[this.indexStates.elementSize];
117         int count = 0;
118         for (int i = 0, l = keys.length; i < l; i++) {
119             IPath key = (IPath) keys[i];
120             if (key != null && !knownPaths.includes(key.toOSString()))
121                 locations[count++] = key;
122         }
123         if (count > 0)
124             removeIndexesState(locations);
125     }
126     deleteIndexFiles(knownPaths);
127 }
128 public IPath computeIndexLocation(IPath containerPath) {
129     IPath indexLocation = (IPath) this.indexLocations.get(containerPath);
130     if (indexLocation == null) {
131         String JavaDoc pathString = containerPath.toOSString();
132         checksumCalculator.reset();
133         checksumCalculator.update(pathString.getBytes());
134         String JavaDoc fileName = Long.toString(checksumCalculator.getValue()) + ".index"; //$NON-NLS-1$
135
if (VERBOSE)
136             Util.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$
137
// to share the indexLocation between the indexLocations and indexStates tables, get the key from the indexStates table
138
indexLocation = (IPath) getIndexStates().getKey(getJavaPluginWorkingLocation().append(fileName));
139         this.indexLocations.put(containerPath, indexLocation);
140     }
141     return indexLocation;
142 }
143 public void deleteIndexFiles() {
144     this.savedIndexNamesFile.delete(); // forget saved indexes & delete each index file
145
deleteIndexFiles(null);
146 }
147 private void deleteIndexFiles(SimpleSet pathsToKeep) {
148     File[] indexesFiles = getSavedIndexesDirectory().listFiles();
149     if (indexesFiles == null) return;
150
151     for (int i = 0, l = indexesFiles.length; i < l; i++) {
152         String JavaDoc fileName = indexesFiles[i].getAbsolutePath();
153         if (pathsToKeep != null && pathsToKeep.includes(fileName)) continue;
154         String JavaDoc suffix = ".index"; //$NON-NLS-1$
155
if (fileName.regionMatches(true, fileName.length() - suffix.length(), suffix, 0, suffix.length())) {
156             if (VERBOSE)
157                 Util.verbose("Deleting index file " + indexesFiles[i]); //$NON-NLS-1$
158
indexesFiles[i].delete();
159         }
160     }
161 }
162 /*
163  * Creates an empty index at the given location, for the given container path, if none exist.
164  */

165 public void ensureIndexExists(IPath indexLocation, IPath containerPath) {
166     SimpleLookupTable states = getIndexStates();
167     Object JavaDoc state = states.get(indexLocation);
168     if (state == null) {
169         updateIndexState(indexLocation, REBUILDING_STATE);
170         getIndex(containerPath, indexLocation, true, true);
171     }
172 }
173 public SourceElementParser getSourceElementParser(IJavaProject project, ISourceElementRequestor requestor) {
174     // disable task tags to speed up parsing
175
Map options = project.getOptions(true);
176     options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
177

178     SourceElementParser parser = new IndexingParser(
179         requestor,
180         new DefaultProblemFactory(Locale.getDefault()),
181         new CompilerOptions(options),
182         true, // index local declarations
183
true, // optimize string literals
184
false); // do not use source javadoc parser to speed up parsing
185
parser.reportOnlyOneSyntaxError = true;
186
187     // Always check javadoc while indexing
188
parser.javadocParser.checkDocComment = true;
189     parser.javadocParser.reportProblems = false;
190         
191     return parser;
192 }
193 /**
194  * Returns the index for a given project, according to the following algorithm:
195  * - if index is already in memory: answers this one back
196  * - if (reuseExistingFile) then read it and return this index and record it in memory
197  * - if (createIfMissing) then create a new empty index and record it in memory
198  *
199  * Warning: Does not check whether index is consistent (not being used)
200  */

201 public synchronized Index getIndex(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
202     IPath indexLocation = computeIndexLocation(containerPath);
203     return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
204 }
205 /**
206  * Returns the index for a given project, according to the following algorithm:
207  * - if index is already in memory: answers this one back
208  * - if (reuseExistingFile) then read it and return this index and record it in memory
209  * - if (createIfMissing) then create a new empty index and record it in memory
210  *
211  * Warning: Does not check whether index is consistent (not being used)
212  */

213 public synchronized Index getIndex(IPath containerPath, IPath indexLocation, boolean reuseExistingFile, boolean createIfMissing) {
214     // Path is already canonical per construction
215
Index index = getIndex(indexLocation);
216     if (index == null) {
217         Object JavaDoc state = getIndexStates().get(indexLocation);
218         Integer JavaDoc currentIndexState = state == null ? UNKNOWN_STATE : (Integer JavaDoc) state;
219         if (currentIndexState == UNKNOWN_STATE) {
220             // should only be reachable for query jobs
221
// IF you put an index in the cache, then AddJarFileToIndex fails because it thinks there is nothing to do
222
rebuildIndex(indexLocation, containerPath);
223             return null;
224         }
225
226         // index isn't cached, consider reusing an existing index file
227
String JavaDoc containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
228         String JavaDoc indexLocationString = indexLocation.toOSString();
229         if (reuseExistingFile) {
230             File indexFile = new File(indexLocationString);
231             if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing
232
try {
233                     index = new Index(indexLocationString, containerPathString, true /*reuse index file*/);
234                     this.indexes.put(indexLocation, index);
235                     return index;
236                 } catch (IOException e) {
237                     // failed to read the existing file or its no longer compatible
238
if (currentIndexState != REBUILDING_STATE) { // rebuild index if existing file is corrupt, unless the index is already being rebuilt
239
if (VERBOSE)
240                             Util.verbose("-> cannot reuse existing index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
241
rebuildIndex(indexLocation, containerPath);
242                         return null;
243                     }
244                     /*index = null;*/ // will fall thru to createIfMissing & create a empty index for the rebuild all job to populate
245
}
246             }
247             if (currentIndexState == SAVED_STATE) { // rebuild index if existing file is missing
248
rebuildIndex(indexLocation, containerPath);
249                 return null;
250             }
251         }
252         // index wasn't found on disk, consider creating an empty new one
253
if (createIfMissing) {
254             try {
255                 if (VERBOSE)
256                     Util.verbose("-> create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
257
index = new Index(indexLocationString, containerPathString, false /*do not reuse index file*/);
258                 this.indexes.put(indexLocation, index);
259                 return index;
260             } catch (IOException e) {
261                 if (VERBOSE)
262                     Util.verbose("-> unable to create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
263
// The file could not be created. Possible reason: the project has been deleted.
264
return null;
265             }
266         }
267     }
268     //System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());
269
return index;
270 }
271 public synchronized Index getIndex(IPath indexLocation) {
272     return (Index) this.indexes.get(indexLocation); // is null if unknown, call if the containerPath must be computed
273
}
274 public synchronized Index getIndexForUpdate(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
275     IPath indexLocation = computeIndexLocation(containerPath);
276     if (getIndexStates().get(indexLocation) == REBUILDING_STATE)
277         return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
278
279     return null; // abort the job since the index has been removed from the REBUILDING_STATE
280
}
281 private SimpleLookupTable getIndexStates() {
282     if (this.indexStates != null) return this.indexStates;
283
284     this.indexStates = new SimpleLookupTable();
285     IPath indexesDirectoryPath = getJavaPluginWorkingLocation();
286     char[][] savedNames = readIndexState(indexesDirectoryPath.toOSString());
287     if (savedNames != null) {
288         for (int i = 1, l = savedNames.length; i < l; i++) { // first name is saved signature, see readIndexState()
289
char[] savedName = savedNames[i];
290             if (savedName.length > 0) {
291                 IPath indexLocation = indexesDirectoryPath.append(new String JavaDoc(savedName)); // shares indexesDirectoryPath's segments
292
if (VERBOSE)
293                     Util.verbose("Reading saved index file " + indexLocation); //$NON-NLS-1$
294
this.indexStates.put(indexLocation, SAVED_STATE);
295             }
296         }
297     } else {
298         deleteIndexFiles();
299     }
300     return this.indexStates;
301 }
302 private IPath getJavaPluginWorkingLocation() {
303     if (this.javaPluginLocation != null) return this.javaPluginLocation;
304
305     IPath stateLocation = JavaCore.getPlugin().getStateLocation();
306     return this.javaPluginLocation = stateLocation;
307 }
308 private File getSavedIndexesDirectory() {
309     return new File(getJavaPluginWorkingLocation().toOSString());
310 }
311 public void indexDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) {
312     try {
313         ((InternalSearchDocument) searchDocument).index = index;
314         searchParticipant.indexDocument(searchDocument, indexLocation);
315     } finally {
316         ((InternalSearchDocument) searchDocument).index = null;
317     }
318 }
319 /**
320  * Trigger addition of the entire content of a project
321  * Note: the actual operation is performed in background
322  */

323 public void indexAll(IProject project) {
324     if (JavaCore.getPlugin() == null) return;
325
326     // Also request indexing of binaries on the classpath
327
// determine the new children
328
try {
329         JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
330         JavaProject javaProject = (JavaProject) model.getJavaProject(project);
331         // only consider immediate libraries - each project will do the same
332
// NOTE: force to resolve CP variables before calling indexer - 19303, so that initializers
333
// will be run in the current thread.
334
IClasspathEntry[] entries = javaProject.getResolvedClasspath();
335         for (int i = 0; i < entries.length; i++) {
336             IClasspathEntry entry= entries[i];
337             if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
338                 this.indexLibrary(entry.getPath(), project);
339         }
340     } catch(JavaModelException e){ // cannot retrieve classpath info
341
}
342
343     // check if the same request is not already in the queue
344
IndexRequest request = new IndexAllProject(project, this);
345     if (!isJobWaiting(request))
346         this.request(request);
347 }
348 /**
349  * Trigger addition of a library to an index
350  * Note: the actual operation is performed in background
351  */

352 public void indexLibrary(IPath path, IProject requestingProject) {
353     // requestingProject is no longer used to cancel jobs but leave it here just in case
354
if (JavaCore.getPlugin() == null) return;
355
356     Object JavaDoc target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true);
357     IndexRequest request = null;
358     if (target instanceof IFile) {
359         request = new AddJarFileToIndex((IFile) target, this);
360     } else if (target instanceof File) {
361         if (((File) target).isFile()) {
362             request = new AddJarFileToIndex(path, this);
363         } else {
364             return;
365         }
366     } else if (target instanceof IContainer) {
367         request = new IndexBinaryFolder((IContainer) target, this);
368     } else {
369         return;
370     }
371
372     // check if the same request is not already in the queue
373
if (!isJobWaiting(request))
374         this.request(request);
375 }
376 /**
377  * Index the content of the given source folder.
378  */

379 public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
380     IProject project = javaProject.getProject();
381     if (this.jobEnd > this.jobStart) {
382         // skip it if a job to index the project is already in the queue
383
IndexRequest request = new IndexAllProject(project, this);
384         if (isJobWaiting(request)) return;
385     }
386
387     this.request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this));
388 }
389 public synchronized void jobWasCancelled(IPath containerPath) {
390     IPath indexLocation = computeIndexLocation(containerPath);
391     Index index = getIndex(indexLocation);
392     if (index != null) {
393         index.monitor = null;
394         this.indexes.removeKey(indexLocation);
395     }
396     updateIndexState(indexLocation, UNKNOWN_STATE);
397 }
398 /**
399  * Advance to the next available job, once the current one has been completed.
400  * Note: clients awaiting until the job count is zero are still waiting at this point.
401  */

402 protected synchronized void moveToNextJob() {
403     // remember that one job was executed, and we will need to save indexes at some point
404
needToSave = true;
405     super.moveToNextJob();
406 }
407 /**
408  * No more job awaiting.
409  */

410 protected void notifyIdle(long idlingTime){
411     if (idlingTime > 1000 && needToSave) saveIndexes();
412 }
413 /**
414  * Name of the background process
415  */

416 public String JavaDoc processName(){
417     return Messages.process_name;
418 }
419 private void rebuildIndex(IPath indexLocation, IPath containerPath) {
420     IWorkspace workspace = ResourcesPlugin.getWorkspace();
421     if (workspace == null) return;
422     Object JavaDoc target = JavaModel.getTarget(workspace.getRoot(), containerPath, true);
423     if (target == null) return;
424
425     if (VERBOSE)
426         Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath); //$NON-NLS-1$ //$NON-NLS-2$
427

428     updateIndexState(indexLocation, REBUILDING_STATE);
429     IndexRequest request = null;
430     if (target instanceof IProject) {
431         IProject p = (IProject) target;
432         if (JavaProject.hasJavaNature(p))
433             request = new IndexAllProject(p, this);
434     } else if (target instanceof IFolder) {
435         request = new IndexBinaryFolder((IFolder) target, this);
436     } else if (target instanceof IFile) {
437         request = new AddJarFileToIndex((IFile) target, this);
438     } else if (target instanceof File) {
439         request = new AddJarFileToIndex(containerPath, this);
440     }
441     if (request != null)
442         request(request);
443 }
444 /**
445  * Recreates the index for a given path, keeping the same read-write monitor.
446  * Returns the new empty index or null if it didn't exist before.
447  * Warning: Does not check whether index is consistent (not being used)
448  */

449 public synchronized Index recreateIndex(IPath containerPath) {
450     // only called to over write an existing cached index...
451
String JavaDoc containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
452     try {
453         // Path is already canonical
454
IPath indexLocation = computeIndexLocation(containerPath);
455         Index index = getIndex(indexLocation);
456         ReadWriteMonitor monitor = index == null ? null : index.monitor;
457
458         if (VERBOSE)
459             Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
460
index = new Index(indexLocation.toOSString(), containerPathString, false /*reuse index file*/);
461         this.indexes.put(indexLocation, index);
462         index.monitor = monitor;
463         return index;
464     } catch (IOException e) {
465         // The file could not be created. Possible reason: the project has been deleted.
466
if (VERBOSE) {
467             Util.verbose("-> failed to recreate index for path: "+containerPathString); //$NON-NLS-1$
468
e.printStackTrace();
469         }
470         return null;
471     }
472 }
473 /**
474  * Trigger removal of a resource to an index
475  * Note: the actual operation is performed in background
476  */

477 public void remove(String JavaDoc containerRelativePath, IPath indexedContainer){
478     request(new RemoveFromIndex(containerRelativePath, indexedContainer, this));
479 }
480 /**
481  * Removes the index for a given path.
482  * This is a no-op if the index did not exist.
483  */

484 public synchronized void removeIndex(IPath containerPath) {
485     if (VERBOSE)
486         Util.verbose("removing index " + containerPath); //$NON-NLS-1$
487
IPath indexLocation = computeIndexLocation(containerPath);
488     Index index = getIndex(indexLocation);
489     File indexFile = null;
490     if (index != null) {
491         index.monitor = null;
492         indexFile = index.getIndexFile();
493     }
494     if (indexFile == null)
495         indexFile = new File(indexLocation.toOSString()); // index is not cached yet, but still want to delete the file
496
if (indexFile.exists())
497         indexFile.delete();
498     this.indexes.removeKey(indexLocation);
499     updateIndexState(indexLocation, null);
500 }
501 /**
502  * Removes all indexes whose paths start with (or are equal to) the given path.
503  */

504 public synchronized void removeIndexPath(IPath path) {
505     Object JavaDoc[] keyTable = this.indexes.keyTable;
506     Object JavaDoc[] valueTable = this.indexes.valueTable;
507     IPath[] locations = null;
508     int max = this.indexes.elementSize;
509     int count = 0;
510     for (int i = 0, l = keyTable.length; i < l; i++) {
511         IPath indexLocation = (IPath) keyTable[i];
512         if (indexLocation == null)
513             continue;
514         if (path.isPrefixOf(indexLocation)) {
515             Index index = (Index) valueTable[i];
516             index.monitor = null;
517             if (locations == null)
518                 locations = new IPath[max];
519             locations[count++] = indexLocation;
520             File indexFile = index.getIndexFile();
521             if (indexFile.exists())
522                 indexFile.delete();
523         } else {
524             max--;
525         }
526     }
527     if (locations != null) {
528         for (int i = 0; i < count; i++)
529             this.indexes.removeKey(locations[i]);
530         removeIndexesState(locations);
531     }
532 }
533 /**
534  * Removes all indexes whose paths start with (or are equal to) the given path.
535  */

536 public synchronized void removeIndexFamily(IPath path) {
537     // only finds cached index files... shutdown removes all non-cached index files
538
ArrayList toRemove = null;
539     Object JavaDoc[] containerPaths = this.indexLocations.keyTable;
540     for (int i = 0, length = containerPaths.length; i < length; i++) {
541         IPath containerPath = (IPath) containerPaths[i];
542         if (containerPath == null) continue;
543         if (path.isPrefixOf(containerPath)) {
544             if (toRemove == null)
545                 toRemove = new ArrayList();
546             toRemove.add(containerPath);
547         }
548     }
549     if (toRemove != null)
550         for (int i = 0, length = toRemove.size(); i < length; i++)
551             this.removeIndex((IPath) toRemove.get(i));
552 }
553 /**
554  * Remove the content of the given source folder from the index.
555  */

556 public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
557     IProject project = javaProject.getProject();
558     if (this.jobEnd > this.jobStart) {
559         // skip it if a job to index the project is already in the queue
560
IndexRequest request = new IndexAllProject(project, this);
561         if (isJobWaiting(request)) return;
562     }
563
564     this.request(new RemoveFolderFromIndex(sourceFolder, inclusionPatterns, exclusionPatterns, project, this));
565 }
566 /**
567  * Flush current state
568  */

569 public synchronized void reset() {
570     super.reset();
571     if (this.indexes != null) {
572         this.indexes = new SimpleLookupTable();
573         this.indexStates = null;
574     }
575     this.indexLocations = new SimpleLookupTable();
576     this.javaPluginLocation = null;
577 }
578 public void saveIndex(Index index) throws IOException {
579     // must have permission to write from the write monitor
580
if (index.hasChanged()) {
581         if (VERBOSE)
582             Util.verbose("-> saving index " + index.getIndexFile()); //$NON-NLS-1$
583
index.save();
584     }
585     synchronized (this) {
586         IPath containerPath = new Path(index.containerPath);
587         if (this.jobEnd > this.jobStart) {
588             for (int i = this.jobEnd; i > this.jobStart; i--) { // skip the current job
589
IJob job = this.awaitingJobs[i];
590                 if (job instanceof IndexRequest)
591                     if (((IndexRequest) job).containerPath.equals(containerPath)) return;
592             }
593         }
594         IPath indexLocation = computeIndexLocation(containerPath);
595         updateIndexState(indexLocation, SAVED_STATE);
596     }
597 }
598 /**
599  * Commit all index memory changes to disk
600  */

601 public void saveIndexes() {
602     // only save cached indexes... the rest were not modified
603
ArrayList toSave = new ArrayList();
604     synchronized(this) {
605         Object JavaDoc[] valueTable = this.indexes.valueTable;
606         for (int i = 0, l = valueTable.length; i < l; i++) {
607             Index index = (Index) valueTable[i];
608             if (index != null)
609                 toSave.add(index);
610         }
611     }
612
613     boolean allSaved = true;
614     for (int i = 0, length = toSave.size(); i < length; i++) {
615         Index index = (Index) toSave.get(i);
616         ReadWriteMonitor monitor = index.monitor;
617         if (monitor == null) continue; // index got deleted since acquired
618
try {
619             // take read lock before checking if index has changed
620
// don't take write lock yet since it can cause a deadlock (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=50571)
621
monitor.enterRead();
622             if (index.hasChanged()) {
623                 if (monitor.exitReadEnterWrite()) {
624                     try {
625                         saveIndex(index);
626                     } catch(IOException e) {
627                         if (VERBOSE) {
628                             Util.verbose("-> got the following exception while saving:", System.err); //$NON-NLS-1$
629
e.printStackTrace();
630                         }
631                         allSaved = false;
632                     } finally {
633                         monitor.exitWriteEnterRead();
634                     }
635                 } else {
636                     allSaved = false;
637                 }
638             }
639         } finally {
640             monitor.exitRead();
641         }
642     }
643     this.needToSave = !allSaved;
644 }
645 public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final IPath indexLocation, final SearchParticipant searchParticipant) {
646     request(new IndexRequest(container, this) {
647         public boolean execute(IProgressMonitor progressMonitor) {
648             if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
649             
650             /* ensure no concurrent write access to index */
651             Index index = getIndex(this.containerPath, indexLocation, true, /*reuse index file*/ true /*create if none*/);
652             if (index == null) return true;
653             ReadWriteMonitor monitor = index.monitor;
654             if (monitor == null) return true; // index got deleted since acquired
655

656             try {
657                 monitor.enterWrite(); // ask permission to write
658
indexDocument(searchDocument, searchParticipant, index, indexLocation);
659             } finally {
660                 monitor.exitWrite(); // free write lock
661
}
662             return true;
663         }
664         public String JavaDoc toString() {
665             return "indexing " + searchDocument.getPath(); //$NON-NLS-1$
666
}
667     });
668 }
669
670 public String JavaDoc toString() {
671     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(10);
672     buffer.append(super.toString());
673     buffer.append("In-memory indexes:\n"); //$NON-NLS-1$
674
int count = 0;
675     Object JavaDoc[] valueTable = this.indexes.valueTable;
676     for (int i = 0, l = valueTable.length; i < l; i++) {
677         Index index = (Index) valueTable[i];
678         if (index != null)
679             buffer.append(++count).append(" - ").append(index.toString()).append('\n'); //$NON-NLS-1$
680
}
681     return buffer.toString();
682 }
683
684 private char[][] readIndexState(String JavaDoc dirOSString) {
685     try {
686         char[] savedIndexNames = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(savedIndexNamesFile, null);
687         if (savedIndexNames.length > 0) {
688             char[][] names = CharOperation.splitOn('\n', savedIndexNames);
689             if (names.length > 1) {
690                 // First line is DiskIndex signature + saved plugin working location (see writeSavedIndexNamesFile())
691
String JavaDoc savedSignature = DiskIndex.SIGNATURE + "+" + dirOSString; //$NON-NLS-1$
692
if (savedSignature.equals(new String JavaDoc(names[0])))
693                     return names;
694             }
695         }
696     } catch (IOException ignored) {
697         if (VERBOSE)
698             Util.verbose("Failed to read saved index file names"); //$NON-NLS-1$
699
}
700     return null;
701 }
702 private synchronized void removeIndexesState(IPath[] locations) {
703     getIndexStates(); // ensure the states are initialized
704
int length = locations.length;
705     boolean changed = false;
706     for (int i=0; i<length; i++) {
707         if (locations[i] == null) continue;
708         if ((indexStates.removeKey(locations[i]) != null)) {
709             changed = true;
710             if (VERBOSE) {
711                 Util.verbose("-> index state updated to: ? for: "+locations[i]); //$NON-NLS-1$
712
}
713         }
714     }
715     if (!changed) return;
716
717     writeSavedIndexNamesFile();
718 }
719 private synchronized void updateIndexState(IPath indexLocation, Integer JavaDoc indexState) {
720     if (indexLocation.isEmpty())
721         throw new IllegalArgumentException JavaDoc();
722
723     getIndexStates(); // ensure the states are initialized
724
if (indexState != null) {
725         if (indexState.equals(indexStates.get(indexLocation))) return; // not changed
726
indexStates.put(indexLocation, indexState);
727     } else {
728         if (!indexStates.containsKey(indexLocation)) return; // did not exist anyway
729
indexStates.removeKey(indexLocation);
730     }
731
732     writeSavedIndexNamesFile();
733
734     if (VERBOSE) {
735         String JavaDoc state = "?"; //$NON-NLS-1$
736
if (indexState == SAVED_STATE) state = "SAVED"; //$NON-NLS-1$
737
else if (indexState == UPDATING_STATE) state = "UPDATING"; //$NON-NLS-1$
738
else if (indexState == UNKNOWN_STATE) state = "UNKNOWN"; //$NON-NLS-1$
739
else if (indexState == REBUILDING_STATE) state = "REBUILDING"; //$NON-NLS-1$
740
Util.verbose("-> index state updated to: " + state + " for: "+indexLocation); //$NON-NLS-1$ //$NON-NLS-2$
741
}
742 }
743 private void writeSavedIndexNamesFile() {
744     BufferedWriter writer = null;
745     try {
746         writer = new BufferedWriter(new FileWriter(savedIndexNamesFile));
747         writer.write(DiskIndex.SIGNATURE);
748         writer.write('+');
749         writer.write(getJavaPluginWorkingLocation().toOSString());
750         writer.write('\n');
751         Object JavaDoc[] keys = indexStates.keyTable;
752         Object JavaDoc[] states = indexStates.valueTable;
753         for (int i = 0, l = states.length; i < l; i++) {
754             IPath key = (IPath) keys[i];
755             if (key != null && !key.isEmpty() && states[i] == SAVED_STATE) {
756                 writer.write(key.lastSegment());
757                 writer.write('\n');
758             }
759         }
760     } catch (IOException ignored) {
761         if (VERBOSE)
762             Util.verbose("Failed to write saved index file names", System.err); //$NON-NLS-1$
763
} finally {
764         if (writer != null) {
765             try {
766                 writer.close();
767             } catch (IOException e) {
768                 // ignore
769
}
770         }
771     }
772 }
773 }
774
Popular Tags