Index: search/org/eclipse/jdt/internal/core/index/DiskIndex.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java,v retrieving revision 1.54 diff -u -r1.54 DiskIndex.java --- search/org/eclipse/jdt/internal/core/index/DiskIndex.java 11 Jan 2007 11:45:16 -0000 1.54 +++ search/org/eclipse/jdt/internal/core/index/DiskIndex.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -19,10 +19,11 @@ import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; import org.eclipse.jdt.internal.compiler.util.SimpleSet; +import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray; public class DiskIndex { -String fileName; +File indexFile; private int headerInfoOffset; private int numberOfChunks; @@ -45,6 +46,8 @@ private static final int CHUNK_SIZE = 100; +private static final SimpleSetOfCharArray INTERNED_CATEGORY_NAMES = new SimpleSetOfCharArray(20); + static class IntList { int size; @@ -71,7 +74,9 @@ DiskIndex(String fileName) { - this.fileName = fileName; + if (fileName == null) + throw new java.lang.IllegalArgumentException(); + this.indexFile = new File(fileName); // clear cached items this.headerInfoOffset = -1; @@ -204,7 +209,7 @@ private void cacheDocumentNames() throws IOException { // will need all document names so get them now this.cachedChunks = new String[this.numberOfChunks][]; - DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), this.numberOfChunks > 5 ? 4096 : 2048)); + DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(this.indexFile), this.numberOfChunks > 5 ? 4096 : 2048)); try { stream.skip(this.chunkOffsets[0]); for (int i = 0; i < this.numberOfChunks; i++) { @@ -335,16 +340,10 @@ } } } -File getIndexFile() { - if (this.fileName == null) return null; - - return new File(this.fileName); -} void initialize(boolean reuseExistingFile) throws IOException { - File indexFile = getIndexFile(); - if (indexFile.exists()) { + if (this.indexFile.exists()) { if (reuseExistingFile) { - RandomAccessFile file = new RandomAccessFile(this.fileName, "r"); //$NON-NLS-1$ + RandomAccessFile file = new RandomAccessFile(this.indexFile, "r"); //$NON-NLS-1$ try { String signature = file.readUTF(); if (!signature.equals(SIGNATURE)) @@ -358,14 +357,14 @@ } return; } - if (!indexFile.delete()) { + if (!this.indexFile.delete()) { if (DEBUG) - System.out.println("initialize - Failed to delete index " + this.fileName); //$NON-NLS-1$ - throw new IOException("Failed to delete index " + this.fileName); //$NON-NLS-1$ + System.out.println("initialize - Failed to delete index " + this.indexFile); //$NON-NLS-1$ + throw new IOException("Failed to delete index " + this.indexFile); //$NON-NLS-1$ } } - if (indexFile.createNewFile()) { - RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$ + if (this.indexFile.createNewFile()) { + RandomAccessFile file = new RandomAccessFile(this.indexFile, "rw"); //$NON-NLS-1$ try { file.writeUTF(SIGNATURE); file.writeInt(-1); // file is empty @@ -374,18 +373,18 @@ } } else { if (DEBUG) - System.out.println("initialize - Failed to create new index " + this.fileName); //$NON-NLS-1$ - throw new IOException("Failed to create new index " + this.fileName); //$NON-NLS-1$ + System.out.println("initialize - Failed to create new index " + this.indexFile); //$NON-NLS-1$ + throw new IOException("Failed to create new index " + this.indexFile); //$NON-NLS-1$ } } private void initializeFrom(DiskIndex diskIndex, File newIndexFile) throws IOException { if (newIndexFile.exists() && !newIndexFile.delete()) { // delete the temporary index file if (DEBUG) - System.out.println("initializeFrom - Failed to delete temp index " + this.fileName); //$NON-NLS-1$ + System.out.println("initializeFrom - Failed to delete temp index " + this.indexFile); //$NON-NLS-1$ } else if (!newIndexFile.createNewFile()) { if (DEBUG) - System.out.println("initializeFrom - Failed to create temp index " + this.fileName); //$NON-NLS-1$ - throw new IOException("Failed to create temp index " + this.fileName); //$NON-NLS-1$ + System.out.println("initializeFrom - Failed to create temp index " + this.indexFile); //$NON-NLS-1$ + throw new IOException("Failed to create temp index " + this.indexFile); //$NON-NLS-1$ } int size = diskIndex.categoryOffsets == null ? 8 : diskIndex.categoryOffsets.elementSize; @@ -465,16 +464,15 @@ if (previousLength == 0) return this; // nothing to do... memory index contained deleted documents that had never been saved // index is now empty since all the saved documents were removed - DiskIndex newDiskIndex = new DiskIndex(this.fileName); + DiskIndex newDiskIndex = new DiskIndex(this.indexFile.getPath()); newDiskIndex.initialize(false); return newDiskIndex; } - DiskIndex newDiskIndex = new DiskIndex(this.fileName + ".tmp"); //$NON-NLS-1$ - File newIndexFile = newDiskIndex.getIndexFile(); + DiskIndex newDiskIndex = new DiskIndex(this.indexFile.getPath() + ".tmp"); //$NON-NLS-1$ try { - newDiskIndex.initializeFrom(this, newIndexFile); - DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newIndexFile, false), 2048)); + newDiskIndex.initializeFrom(this, newDiskIndex.indexFile); + DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newDiskIndex.indexFile, false), 2048)); int offsetToHeader = -1; try { newDiskIndex.writeAllDocumentNames(docNames, stream); @@ -487,8 +485,7 @@ for (int i = 0, l = names.length; i < l; i++) if (names[i] != null) newDiskIndex.copyQueryResults( - (HashtableOfObject) memoryIndex.docsToReferences.get(names[i]), - ((Integer) integerPositions[i]).intValue()); + (HashtableOfObject) memoryIndex.docsToReferences.get(names[i]), ((Integer) integerPositions[i]).intValue()); } indexedDocuments = null; // free up the space @@ -506,32 +503,31 @@ newDiskIndex.writeOffsetToHeader(offsetToHeader); // rename file by deleting previous index file & renaming temp one - File old = getIndexFile(); - if (old.exists() && !old.delete()) { + if (this.indexFile.exists() && !this.indexFile.delete()) { if (DEBUG) - System.out.println("mergeWith - Failed to delete " + this.fileName); //$NON-NLS-1$ - throw new IOException("Failed to delete index file " + this.fileName); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to delete " + this.indexFile); //$NON-NLS-1$ + throw new IOException("Failed to delete index file " + this.indexFile); //$NON-NLS-1$ } - if (!newIndexFile.renameTo(old)) { + if (!newDiskIndex.indexFile.renameTo(this.indexFile)) { if (DEBUG) - System.out.println("mergeWith - Failed to rename " + this.fileName); //$NON-NLS-1$ - throw new IOException("Failed to rename index file " + this.fileName); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to rename " + this.indexFile); //$NON-NLS-1$ + throw new IOException("Failed to rename index file " + this.indexFile); //$NON-NLS-1$ } } catch (IOException e) { - if (newIndexFile.exists() && !newIndexFile.delete()) + if (newDiskIndex.indexFile.exists() && !newDiskIndex.indexFile.delete()) if (DEBUG) - System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.fileName); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.indexFile); //$NON-NLS-1$ throw e; } - newDiskIndex.fileName = this.fileName; + newDiskIndex.indexFile = this.indexFile; return newDiskIndex; } private synchronized String[] readAllDocumentNames() throws IOException { if (this.numberOfChunks <= 0) return CharOperation.NO_STRINGS; - DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), this.numberOfChunks > 5 ? 4096 : 2048)); + DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(this.indexFile), this.numberOfChunks > 5 ? 4096 : 2048)); try { stream.skip(this.chunkOffsets[0]); int lastIndex = this.numberOfChunks - 1; @@ -564,7 +560,7 @@ } } - DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048)); + DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(this.indexFile), 2048)); HashtableOfObject categoryTable = null; char[][] matchingWords = null; int count = 0; @@ -575,7 +571,7 @@ try { if (size < 0) { // DEBUG System.err.println("-------------------- DEBUG --------------------"); //$NON-NLS-1$ - System.err.println("file = "+getIndexFile()); //$NON-NLS-1$ + System.err.println("file = "+this.indexFile); //$NON-NLS-1$ System.err.println("offset = "+offset); //$NON-NLS-1$ System.err.println("size = "+size); //$NON-NLS-1$ System.err.println("-------------------- END --------------------"); //$NON-NLS-1$ @@ -585,7 +581,7 @@ // DEBUG oom.printStackTrace(); System.err.println("-------------------- DEBUG --------------------"); //$NON-NLS-1$ - System.err.println("file = "+getIndexFile()); //$NON-NLS-1$ + System.err.println("file = "+this.indexFile); //$NON-NLS-1$ System.err.println("offset = "+offset); //$NON-NLS-1$ System.err.println("size = "+size); //$NON-NLS-1$ System.err.println("-------------------- END --------------------"); //$NON-NLS-1$ @@ -615,16 +611,16 @@ categoryTable.put(word, new Integer(arrayOffset)); // offset to array in the file } } - this.categoryTables.put(categoryName, categoryTable); + this.categoryTables.put(INTERNED_CATEGORY_NAMES.get(categoryName), categoryTable); // cache the table as long as its not too big // in practice, some tables can be greater than 500K when they contain more than 10K elements - this.cachedCategoryName = categoryTable.elementSize < 10000 ? categoryName : null; + this.cachedCategoryName = categoryTable.elementSize < 20000 ? categoryName : null; } finally { stream.close(); } if (matchingWords != null && count > 0) { - stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048)); + stream = new DataInputStream(new BufferedInputStream(new FileInputStream(this.indexFile), 2048)); try { stream.skip(firstOffset); for (int i = 0; i < count; i++) // each array follows the previous one @@ -688,7 +684,7 @@ if (numberOfBytes < 0) throw new IllegalArgumentException(); byte[] bytes = new byte[numberOfBytes]; - FileInputStream file = new FileInputStream(getIndexFile()); + FileInputStream file = new FileInputStream(this.indexFile); try { file.skip(start); if (file.read(bytes, 0, numberOfBytes) != numberOfBytes) @@ -708,7 +704,7 @@ if (arrayOffset instanceof int[]) return (int[]) arrayOffset; - DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048)); + DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(this.indexFile), 2048)); try { stream.skip(((Integer) arrayOffset).intValue()); return readDocumentArray(stream, stream.readInt()); @@ -733,7 +729,7 @@ int size = file.readInt(); this.categoryOffsets = new HashtableOfIntValues(size); for (int i = 0; i < size; i++) - this.categoryOffsets.put(Util.readUTF(file), file.readInt()); // cache offset to category table + this.categoryOffsets.put(INTERNED_CATEGORY_NAMES.get(Util.readUTF(file)), file.readInt()); // cache offset to category table this.categoryTables = new HashtableOfObject(3); } synchronized void startQuery() { @@ -909,7 +905,7 @@ } private void writeOffsetToHeader(int offsetToHeader) throws IOException { if (offsetToHeader > 0) { - RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$ + RandomAccessFile file = new RandomAccessFile(this.indexFile, "rw"); //$NON-NLS-1$ try { file.seek(this.headerInfoOffset); // offset to position in header file.writeInt(offsetToHeader); Index: search/org/eclipse/jdt/internal/core/index/Index.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java,v retrieving revision 1.24 diff -u -r1.24 Index.java --- search/org/eclipse/jdt/internal/core/index/Index.java 10 May 2006 18:03:51 -0000 1.24 +++ search/org/eclipse/jdt/internal/core/index/Index.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -105,9 +105,7 @@ return documentPath.substring(index + 1); } public File getIndexFile() { - if (this.diskIndex == null) return null; - - return this.diskIndex.getIndexFile(); + return this.diskIndex == null ? null : this.diskIndex.indexFile; } public boolean hasChanged() { return this.memoryIndex.hasChanged(); Index: search/org/eclipse/jdt/internal/core/search/IndexSelector.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java,v retrieving revision 1.35 diff -u -r1.35 IndexSelector.java --- search/org/eclipse/jdt/internal/core/search/IndexSelector.java 7 Sep 2006 07:27:16 -0000 1.35 +++ search/org/eclipse/jdt/internal/core/search/IndexSelector.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,7 +11,6 @@ package org.eclipse.jdt.internal.core.search; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; @@ -197,7 +196,7 @@ int count = 0; for (int i = values.length; --i >= 0;) if (values[i] != null) - this.indexLocations[count++] = new Path((String) values[i]); + this.indexLocations[count++] = (IPath) values[i]; } public IPath[] getIndexLocations() { if (this.indexLocations == null) { Index: search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java,v retrieving revision 1.46 diff -u -r1.46 PatternSearchJob.java --- search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java 10 May 2006 18:03:48 -0000 1.46 +++ search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -85,7 +85,7 @@ for (int i = 0; i < length; i++) { if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); // may trigger some index recreation work - String indexLocation = indexLocations[i].toOSString(); + IPath indexLocation = indexLocations[i]; Index index = indexManager.getIndex(indexLocation); if (index == null) { // only need containerPath if the index must be built Index: search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java,v retrieving revision 1.152 diff -u -r1.152 IndexManager.java --- search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java 24 Nov 2006 01:32:07 -0000 1.152 +++ search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -26,8 +26,9 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; +import org.eclipse.jdt.internal.compiler.util.SimpleSet; import org.eclipse.jdt.internal.core.*; -import org.eclipse.jdt.internal.core.index.Index; +import org.eclipse.jdt.internal.core.index.*; import org.eclipse.jdt.internal.core.search.BasicSearchEngine; import org.eclipse.jdt.internal.core.search.PatternSearchJob; import org.eclipse.jdt.internal.core.search.processing.IJob; @@ -37,11 +38,11 @@ public class IndexManager extends JobManager implements IIndexConstants { + // key = containerPath, value = indexLocation path + // indexLocation path is created by appending an index file name to the getJavaPluginWorkingLocation() path public SimpleLookupTable indexLocations = new SimpleLookupTable(); - /* - * key = an IPath, value = an Index - */ - private Map indexes = new HashMap(5); + // key = indexLocation path, value = an index + private SimpleLookupTable indexes = new SimpleLookupTable(); /* need to save ? */ private boolean needToSave = false; @@ -49,9 +50,9 @@ private IPath javaPluginLocation = null; /* can only replace a current state if its less than the new one */ + // key = indexLocation path, value = index state integer private SimpleLookupTable indexStates = null; - private File savedIndexNamesFile = - new File(getJavaPluginWorkingLocation().append("savedIndexNames.txt").toOSString()); //$NON-NLS-1$ + private File savedIndexNamesFile = new File(getSavedIndexesDirectory(), "savedIndexNames.txt"); //$NON-NLS-1$ public static Integer SAVED_STATE = new Integer(0); public static Integer UPDATING_STATE = new Integer(1); public static Integer UNKNOWN_STATE = new Integer(2); @@ -60,7 +61,7 @@ public synchronized void aboutToUpdateIndex(IPath containerPath, Integer newIndexState) { // newIndexState is either UPDATING_STATE or REBUILDING_STATE // must tag the index as inconsistent, in case we exit before the update job is started - String indexLocation = computeIndexLocation(containerPath); + IPath indexLocation = computeIndexLocation(containerPath); Object state = getIndexStates().get(indexLocation); Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state; if (currentIndexState.equals(REBUILDING_STATE)) return; // already rebuilding the index @@ -82,7 +83,7 @@ if (JavaCore.getPlugin() == null) return; SearchParticipant participant = SearchEngine.getDefaultSearchParticipant(); SearchDocument document = participant.getDocument(resource.getFullPath().toString()); - String indexLocation = computeIndexLocation(containerPath); + IPath indexLocation = computeIndexLocation(containerPath); scheduleDocumentIndexing(document, containerPath, indexLocation, participant); } /** @@ -94,56 +95,38 @@ SearchParticipant participant = SearchEngine.getDefaultSearchParticipant(); SearchDocument document = participant.getDocument(resource.getFullPath().toString()); ((InternalSearchDocument) document).parser = parser; - String indexLocation = computeIndexLocation(containerPath); + IPath indexLocation = computeIndexLocation(containerPath); scheduleDocumentIndexing(document, containerPath, indexLocation, participant); } /* * Removes unused indexes from disk. */ public void cleanUpIndexes() { - SimpleLookupTable knownPaths = new SimpleLookupTable(); + SimpleSet knownPaths = new SimpleSet(); IJavaSearchScope scope = BasicSearchEngine.createWorkspaceScope(); PatternSearchJob job = new PatternSearchJob(null, SearchEngine.getDefaultSearchParticipant(), scope, null); Index[] selectedIndexes = job.getIndexes(null); - for (int j = 0, max = selectedIndexes.length; j < max; j++) { - // TODO should use getJavaPluginWorkingLocation()+index simple name to avoid bugs such as https://bugs.eclipse.org/bugs/show_bug.cgi?id=62267 - String path = selectedIndexes[j].getIndexFile().getAbsolutePath(); - knownPaths.put(path, path); + for (int i = 0, l = selectedIndexes.length; i < l; i++) { + String path = selectedIndexes[i].getIndexFile().getAbsolutePath(); + knownPaths.add(path); } - if (indexStates != null) { - Object[] keys = indexStates.keyTable; - int keysLength = keys.length; - int updates = 0; - String locations[] = new String[keysLength]; + if (this.indexStates != null) { + Object[] keys = this.indexStates.keyTable; + IPath[] locations = new IPath[this.indexStates.elementSize]; + int count = 0; for (int i = 0, l = keys.length; i < l; i++) { - String key = (String) keys[i]; - if (key != null && !knownPaths.containsKey(key)) { - locations[updates++] = key; - } + IPath key = (IPath) keys[i]; + if (key != null && !knownPaths.includes(key.toOSString())) + locations[count++] = key; } - if (updates > 0) { + if (count > 0) removeIndexesState(locations); - } - } - - File indexesDirectory = new File(getJavaPluginWorkingLocation().toOSString()); - if (indexesDirectory.isDirectory()) { - File[] indexesFiles = indexesDirectory.listFiles(); - if (indexesFiles != null) { - for (int i = 0, indexesFilesLength = indexesFiles.length; i < indexesFilesLength; i++) { - String fileName = indexesFiles[i].getAbsolutePath(); - if (!knownPaths.containsKey(fileName) && fileName.toLowerCase().endsWith(".index")) { //$NON-NLS-1$ - if (VERBOSE) - Util.verbose("Deleting index file " + indexesFiles[i]); //$NON-NLS-1$ - indexesFiles[i].delete(); - } - } - } } + deleteIndexFiles(knownPaths); } -public String computeIndexLocation(IPath containerPath) { - String indexLocation = (String) this.indexLocations.get(containerPath); +public IPath computeIndexLocation(IPath containerPath) { + IPath indexLocation = (IPath) this.indexLocations.get(containerPath); if (indexLocation == null) { String pathString = containerPath.toOSString(); checksumCalculator.reset(); @@ -151,15 +134,31 @@ String fileName = Long.toString(checksumCalculator.getValue()) + ".index"; //$NON-NLS-1$ if (VERBOSE) Util.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$ - indexLocation = getJavaPluginWorkingLocation().append(fileName).toOSString(); + // to share the indexLocation between the indexLocations and indexStates tables, get the key from the indexStates table + indexLocation = (IPath) getIndexStates().getKey(getJavaPluginWorkingLocation().append(fileName)); this.indexLocations.put(containerPath, indexLocation); } return indexLocation; } +private void deleteIndexFiles(SimpleSet pathsToKeep) { + File[] indexesFiles = getSavedIndexesDirectory().listFiles(); + if (indexesFiles == null) return; + + for (int i = 0, l = indexesFiles.length; i < l; i++) { + String fileName = indexesFiles[i].getAbsolutePath(); + if (pathsToKeep != null && pathsToKeep.includes(fileName)) continue; + String suffix = ".index"; //$NON-NLS-1$ + if (fileName.regionMatches(true, fileName.length() - suffix.length(), suffix, 0, suffix.length())) { + if (VERBOSE) + Util.verbose("Deleting index file " + indexesFiles[i]); //$NON-NLS-1$ + indexesFiles[i].delete(); + } + } +} /* * Creates an empty index at the given location, for the given container path, if none exist. */ -public void ensureIndexExists(String indexLocation, IPath containerPath) { +public void ensureIndexExists(IPath indexLocation, IPath containerPath) { SimpleLookupTable states = getIndexStates(); Object state = states.get(indexLocation); if (state == null) { @@ -196,7 +195,7 @@ * Warning: Does not check whether index is consistent (not being used) */ public synchronized Index getIndex(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) { - String indexLocation = computeIndexLocation(containerPath); + IPath indexLocation = computeIndexLocation(containerPath); return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing); } /** @@ -207,9 +206,9 @@ * * Warning: Does not check whether index is consistent (not being used) */ -public synchronized Index getIndex(IPath containerPath, String indexLocation, boolean reuseExistingFile, boolean createIfMissing) { +public synchronized Index getIndex(IPath containerPath, IPath indexLocation, boolean reuseExistingFile, boolean createIfMissing) { // Path is already canonical per construction - Index index = (Index) indexes.get(indexLocation); + Index index = getIndex(indexLocation); if (index == null) { Object state = getIndexStates().get(indexLocation); Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state; @@ -222,18 +221,19 @@ // index isn't cached, consider reusing an existing index file String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); + String indexLocationString = indexLocation.toOSString(); if (reuseExistingFile) { - File indexFile = new File(indexLocation); + File indexFile = new File(indexLocationString); if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing try { - index = new Index(indexLocation, containerPathString, true /*reuse index file*/); - indexes.put(indexLocation, index); + index = new Index(indexLocationString, containerPathString, true /*reuse index file*/); + this.indexes.put(indexLocation, index); return index; } catch (IOException e) { // failed to read the existing file or its no longer compatible if (currentIndexState != REBUILDING_STATE) { // rebuild index if existing file is corrupt, unless the index is already being rebuilt if (VERBOSE) - Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + Util.verbose("-> cannot reuse existing index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ rebuildIndex(indexLocation, containerPath); return null; } @@ -249,13 +249,13 @@ if (createIfMissing) { try { if (VERBOSE) - Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ - index = new Index(indexLocation, containerPathString, false /*do not reuse index file*/); - indexes.put(indexLocation, index); + Util.verbose("-> create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + index = new Index(indexLocationString, containerPathString, false /*do not reuse index file*/); + this.indexes.put(indexLocation, index); return index; } catch (IOException e) { if (VERBOSE) - Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + Util.verbose("-> unable to create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ // The file could not be created. Possible reason: the project has been deleted. return null; } @@ -264,49 +264,35 @@ //System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName()); return index; } -public synchronized Index getIndex(String indexLocation) { - return (Index) indexes.get(indexLocation); // is null if unknown, call if the containerPath must be computed +public synchronized Index getIndex(IPath indexLocation) { + return (Index) this.indexes.get(indexLocation); // is null if unknown, call if the containerPath must be computed } public synchronized Index getIndexForUpdate(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) { - String indexLocation = computeIndexLocation(containerPath); + IPath indexLocation = computeIndexLocation(containerPath); if (getIndexStates().get(indexLocation) == REBUILDING_STATE) return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing); return null; // abort the job since the index has been removed from the REBUILDING_STATE } private SimpleLookupTable getIndexStates() { - if (indexStates != null) return indexStates; + if (this.indexStates != null) return this.indexStates; this.indexStates = new SimpleLookupTable(); - char[] savedIndexNames = readIndexState(); - if (savedIndexNames.length > 0) { - char[][] names = CharOperation.splitOn('\n', savedIndexNames); - if (names.length > 0) { - // check to see if workspace has moved, if so then do not trust saved indexes - File indexesDirectory = new File(getJavaPluginWorkingLocation().toOSString()); - char[] dirName = indexesDirectory.getAbsolutePath().toCharArray(); - int delimiterPos = dirName.length; - if (CharOperation.match(names[0], 0, delimiterPos, dirName, 0, delimiterPos, true)) { - for (int i = 0, l = names.length; i < l; i++) { - char[] name = names[i]; - if (name.length > 0) - this.indexStates.put(new String(name), SAVED_STATE); - } - } else { - savedIndexNamesFile.delete(); // forget saved indexes & delete each index file - File[] files = indexesDirectory.listFiles(); - if (files != null) { - for (int i = 0, l = files.length; i < l; i++) { - String fileName = files[i].getAbsolutePath(); - if (fileName.toLowerCase().endsWith(".index")) { //$NON-NLS-1$ - if (VERBOSE) - Util.verbose("Deleting index file " + files[i]); //$NON-NLS-1$ - files[i].delete(); - } - } - } + IPath indexesDirectoryPath = getJavaPluginWorkingLocation(); + char[][] savedNames = readIndexState(indexesDirectoryPath.toOSString()); + if (savedNames != null) { + for (int i = 1, l = savedNames.length; i < l; i++) { // first name is saved signature, see readIndexState() + char[] savedName = savedNames[i]; + if (savedName.length > 0) { + IPath indexLocation = indexesDirectoryPath.append(new String(savedName)); // shares indexesDirectoryPath's segments + if (VERBOSE) + Util.verbose("Reading saved index file " + indexLocation); //$NON-NLS-1$ + this.indexStates.put(indexLocation, SAVED_STATE); } } + } else { + this.savedIndexNamesFile.delete(); // forget saved indexes & delete each index file + deleteIndexFiles(null); } return this.indexStates; } @@ -316,6 +302,9 @@ IPath stateLocation = JavaCore.getPlugin().getStateLocation(); return this.javaPluginLocation = stateLocation; } +private File getSavedIndexesDirectory() { + return new File(getJavaPluginWorkingLocation().toOSString()); +} public void indexDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) { try { ((InternalSearchDocument) searchDocument).index = index; @@ -365,8 +354,8 @@ IndexRequest request = null; if (target instanceof IFile) { request = new AddJarFileToIndex((IFile) target, this); - } else if (target instanceof java.io.File) { - if (((java.io.File) target).isFile()) { + } else if (target instanceof File) { + if (((File) target).isFile()) { request = new AddJarFileToIndex(path, this); } else { return; @@ -394,12 +383,12 @@ this.request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this)); } -public void jobWasCancelled(IPath containerPath) { - String indexLocation = computeIndexLocation(containerPath); - Object o = this.indexes.get(indexLocation); - if (o instanceof Index) { - ((Index) o).monitor = null; - this.indexes.remove(indexLocation); +public synchronized void jobWasCancelled(IPath containerPath) { + IPath indexLocation = computeIndexLocation(containerPath); + Index index = getIndex(indexLocation); + if (index != null) { + index.monitor = null; + this.indexes.removeKey(indexLocation); } updateIndexState(indexLocation, UNKNOWN_STATE); } @@ -424,14 +413,14 @@ public String processName(){ return Messages.process_name; } -private void rebuildIndex(String indexLocation, IPath containerPath) { +private void rebuildIndex(IPath indexLocation, IPath containerPath) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace == null) return; Object target = JavaModel.getTarget(workspace.getRoot(), containerPath, true); if (target == null) return; if (VERBOSE) - Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$ + Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath); //$NON-NLS-1$ //$NON-NLS-2$ updateIndexState(indexLocation, REBUILDING_STATE); IndexRequest request = null; @@ -443,7 +432,7 @@ request = new IndexBinaryFolder((IFolder) target, this); } else if (target instanceof IFile) { request = new AddJarFileToIndex((IFile) target, this); - } else if (target instanceof java.io.File) { + } else if (target instanceof File) { request = new AddJarFileToIndex(containerPath, this); } if (request != null) @@ -459,14 +448,13 @@ String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); try { // Path is already canonical - String indexLocation = computeIndexLocation(containerPath); - - Index index = (Index) this.indexes.get(indexLocation); + IPath indexLocation = computeIndexLocation(containerPath); + Index index = getIndex(indexLocation); ReadWriteMonitor monitor = index == null ? null : index.monitor; if (VERBOSE) Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ - index = new Index(indexLocation, containerPathString, false /*reuse index file*/); + index = new Index(indexLocation.toOSString(), containerPathString, false /*reuse index file*/); this.indexes.put(indexLocation, index); index.monitor = monitor; return index; @@ -493,46 +481,49 @@ public synchronized void removeIndex(IPath containerPath) { if (VERBOSE) Util.verbose("removing index " + containerPath); //$NON-NLS-1$ - String indexLocation = computeIndexLocation(containerPath); - File indexFile = new File(indexLocation); + IPath indexLocation = computeIndexLocation(containerPath); + Index index = getIndex(indexLocation); + File indexFile = null; + if (index != null) { + index.monitor = null; + indexFile = index.getIndexFile(); + } + if (indexFile == null) + indexFile = new File(indexLocation.toOSString()); // index is not cached yet, but still want to delete the file if (indexFile.exists()) indexFile.delete(); - Object o = this.indexes.get(indexLocation); - if (o instanceof Index) - ((Index) o).monitor = null; - this.indexes.remove(indexLocation); + this.indexes.removeKey(indexLocation); updateIndexState(indexLocation, null); } /** * Removes all indexes whose paths start with (or are equal to) the given path. */ public synchronized void removeIndexPath(IPath path) { - Set entrySet = this.indexes.entrySet(); - Iterator entries = entrySet.iterator(); - String[] locations = null; - int max = entrySet.size(); - int ptr = 0; - while (entries.hasNext()) { - Map.Entry entry = (Map.Entry) entries.next(); - String indexLocation = (String) entry.getKey(); - IPath indexPath = new Path(indexLocation); - if (path.isPrefixOf(indexPath)) { - Index index = (Index) entry.getValue(); - if (index != null) index.monitor = null; - if (locations == null) locations = new String[max]; - locations[ptr++] = indexLocation; - File indexFile = new File(indexLocation); - if (indexFile.exists()) { + Object[] keyTable = this.indexes.keyTable; + Object[] valueTable = this.indexes.valueTable; + IPath[] locations = null; + int max = this.indexes.elementSize; + int count = 0; + for (int i = 0, l = keyTable.length; i < l; i++) { + IPath indexLocation = (IPath) keyTable[i]; + if (indexLocation == null) + continue; + if (path.isPrefixOf(indexLocation)) { + Index index = (Index) valueTable[i]; + index.monitor = null; + if (locations == null) + locations = new IPath[max]; + locations[count++] = indexLocation; + File indexFile = index.getIndexFile(); + if (indexFile.exists()) indexFile.delete(); - } - } else if (locations == null) { + } else { max--; } } if (locations != null) { - for (int i=0; i saving index " + index.getIndexFile()); //$NON-NLS-1$ index.save(); } - // TODO should use getJavaPluginWorkingLocation()+index simple name to avoid bugs such as https://bugs.eclipse.org/bugs/show_bug.cgi?id=62267 - String indexLocation = index.getIndexFile().getPath(); - if (this.jobEnd > this.jobStart) { - Object containerPath = this.indexLocations.keyForValue(indexLocation); - if (containerPath != null) { - synchronized(this) { - for (int i = this.jobEnd; i > this.jobStart; i--) { // skip the current job - IJob job = this.awaitingJobs[i]; - if (job instanceof IndexRequest) - if (((IndexRequest) job).containerPath.equals(containerPath)) return; - } + synchronized (this) { + IPath containerPath = new Path(index.containerPath); + if (this.jobEnd > this.jobStart) { + for (int i = this.jobEnd; i > this.jobStart; i--) { // skip the current job + IJob job = this.awaitingJobs[i]; + if (job instanceof IndexRequest) + if (((IndexRequest) job).containerPath.equals(containerPath)) return; } } + IPath indexLocation = computeIndexLocation(containerPath); + updateIndexState(indexLocation, SAVED_STATE); } - updateIndexState(indexLocation, SAVED_STATE); } /** * Commit all index memory changes to disk @@ -611,10 +599,11 @@ // only save cached indexes... the rest were not modified ArrayList toSave = new ArrayList(); synchronized(this) { - for (Iterator iter = this.indexes.values().iterator(); iter.hasNext();) { - Object o = iter.next(); - if (o instanceof Index) - toSave.add(o); + Object[] valueTable = this.indexes.valueTable; + for (int i = 0, l = valueTable.length; i < l; i++) { + Index index = (Index) valueTable[i]; + if (index != null) + toSave.add(index); } } @@ -650,7 +639,7 @@ } this.needToSave = !allSaved; } -public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final String indexLocation, final SearchParticipant searchParticipant) { +public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final IPath indexLocation, final SearchParticipant searchParticipant) { request(new IndexRequest(container, this) { public boolean execute(IProgressMonitor progressMonitor) { if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true; @@ -663,7 +652,7 @@ try { monitor.enterWrite(); // ask permission to write - indexDocument(searchDocument, searchParticipant, index, new Path(indexLocation)); + indexDocument(searchDocument, searchParticipant, index, indexLocation); } finally { monitor.exitWrite(); // free write lock } @@ -680,22 +669,34 @@ buffer.append(super.toString()); buffer.append("In-memory indexes:\n"); //$NON-NLS-1$ int count = 0; - for (Iterator iter = this.indexes.values().iterator(); iter.hasNext();) { - buffer.append(++count).append(" - ").append(iter.next().toString()).append('\n'); //$NON-NLS-1$ + Object[] valueTable = this.indexes.valueTable; + for (int i = 0, l = valueTable.length; i < l; i++) { + Index index = (Index) valueTable[i]; + if (index != null) + buffer.append(++count).append(" - ").append(index.toString()).append('\n'); //$NON-NLS-1$ } return buffer.toString(); } -private char[] readIndexState() { +private char[][] readIndexState(String dirOSString) { try { - return org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(savedIndexNamesFile, null); + char[] savedIndexNames = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(savedIndexNamesFile, null); + if (savedIndexNames.length > 0) { + char[][] names = CharOperation.splitOn('\n', savedIndexNames); + if (names.length > 1) { + // First line is DiskIndex signature + saved plugin working location (see writeSavedIndexNamesFile()) + String savedSignature = DiskIndex.SIGNATURE + "+" + dirOSString; //$NON-NLS-1$ + if (savedSignature.equals(new String(names[0]))) + return names; + } + } } catch (IOException ignored) { if (VERBOSE) Util.verbose("Failed to read saved index file names"); //$NON-NLS-1$ - return CharOperation.NO_CHAR; } + return null; } -private synchronized void removeIndexesState(String[] locations) { +private synchronized void removeIndexesState(IPath[] locations) { getIndexStates(); // ensure the states are initialized int length = locations.length; boolean changed = false; @@ -712,7 +713,7 @@ writeSavedIndexNamesFile(); } -private synchronized void updateIndexState(String indexLocation, Integer indexState) { +private synchronized void updateIndexState(IPath indexLocation, Integer indexState) { getIndexStates(); // ensure the states are initialized if (indexState != null) { if (indexState.equals(indexStates.get(indexLocation))) return; // not changed @@ -737,11 +738,15 @@ BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(savedIndexNamesFile)); + writer.write(DiskIndex.SIGNATURE); + writer.write('+'); + writer.write(getJavaPluginWorkingLocation().toOSString()); + writer.write('\n'); Object[] keys = indexStates.keyTable; Object[] states = indexStates.valueTable; for (int i = 0, l = states.length; i < l; i++) { if (states[i] == SAVED_STATE) { - writer.write((String) keys[i]); + writer.write(((IPath) keys[i]).lastSegment()); writer.write('\n'); } } Index: compiler/org/eclipse/jdt/internal/compiler/util/SimpleSetOfCharArray.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleSetOfCharArray.java,v retrieving revision 1.1 diff -u -r1.1 SimpleSetOfCharArray.java --- compiler/org/eclipse/jdt/internal/compiler/util/SimpleSetOfCharArray.java 3 Nov 2006 12:52:17 -0000 1.1 +++ compiler/org/eclipse/jdt/internal/compiler/util/SimpleSetOfCharArray.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006 IBM Corporation and others. + * Copyright (c) 2006, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -76,6 +76,21 @@ return result; } +public char[] get(char[] object) { + int length = this.values.length; + int index = (CharOperation.hashCode(object) & 0x7FFFFFFF) % length; + char[] current; + while ((current = this.values[index]) != null) { + if (CharOperation.equals(current, object)) return current; + if (++index == length) index = 0; + } + this.values[index] = object; + + // assumes the threshold is never equal to the size of the table + if (++this.elementSize > this.threshold) rehash(); + return object; +} + public boolean includes(char[] object) { int length = values.length; int index = (CharOperation.hashCode(object) & 0x7FFFFFFF) % length; Index: compiler/org/eclipse/jdt/internal/compiler/util/SimpleLookupTable.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleLookupTable.java,v retrieving revision 1.5 diff -u -r1.5 SimpleLookupTable.java --- compiler/org/eclipse/jdt/internal/compiler/util/SimpleLookupTable.java 10 May 2006 18:03:51 -0000 1.5 +++ compiler/org/eclipse/jdt/internal/compiler/util/SimpleLookupTable.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -74,6 +74,17 @@ return null; } +public Object getKey(Object key) { + int length = keyTable.length; + int index = (key.hashCode() & 0x7FFFFFFF) % length; + Object currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.equals(key)) return currentKey; + if (++index == length) index = 0; + } + return key; +} + public Object keyForValue(Object valueToMatch) { if (valueToMatch != null) for (int i = 0, l = keyTable.length; i < l; i++) Index: search/org/eclipse/jdt/core/search/SearchParticipant.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java,v retrieving revision 1.22 diff -u -r1.22 SearchParticipant.java --- search/org/eclipse/jdt/core/search/SearchParticipant.java 29 Mar 2006 03:14:01 -0000 1.22 +++ search/org/eclipse/jdt/core/search/SearchParticipant.java 23 Jan 2007 20:29:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -205,10 +205,9 @@ containerPath = documentPath.removeLastSegments(documentPath.segmentCount()-1); } IndexManager manager = JavaModelManager.getJavaModelManager().getIndexManager(); - String osIndexLocation = indexLocation.toOSString(); // TODO (frederic) should not have to create index manually, should expose API that recreates index instead - manager.ensureIndexExists(osIndexLocation, containerPath); - manager.scheduleDocumentIndexing(document, containerPath, osIndexLocation, this); + manager.ensureIndexExists(indexLocation, containerPath); + manager.scheduleDocumentIndexing(document, containerPath, indexLocation, this); } /**