### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: search/org/eclipse/jdt/internal/core/search/processing/JobManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java,v retrieving revision 1.93 diff -u -r1.93 JobManager.java --- search/org/eclipse/jdt/internal/core/search/processing/JobManager.java 15 Jan 2008 10:01:31 -0000 1.93 +++ search/org/eclipse/jdt/internal/core/search/processing/JobManager.java 17 Jan 2008 14:24:44 -0000 @@ -327,6 +327,7 @@ long idlingStart = -1; activateProcessing(); + IJob currentJob = null; try { class ProgressJob extends Job { ProgressJob(String name) { @@ -354,13 +355,12 @@ this.progressJob = null; while (this.processingThread != null) { try { - IJob job; synchronized (this) { // handle shutdown case when notifyAll came before the wait but after the while loop was entered if (this.processingThread == null) continue; // must check for new job inside this sync block to avoid timing hole - if ((job = currentJob()) == null) { + if ((currentJob = currentJob()) == null) { if (this.progressJob != null) { this.progressJob.cancel(); this.progressJob = null; @@ -374,7 +374,7 @@ idlingStart = -1; } } - if (job == null) { + if (currentJob == null) { notifyIdle(System.currentTimeMillis() - idlingStart); // just woke up, delay before processing any new jobs, allow some time for the active thread to finish Thread.sleep(500); @@ -382,7 +382,7 @@ } if (VERBOSE) { Util.verbose(awaitingJobsCount() + " awaiting jobs"); //$NON-NLS-1$ - Util.verbose("STARTING background job - " + job); //$NON-NLS-1$ + Util.verbose("STARTING background job - " + currentJob); //$NON-NLS-1$ } try { this.executing = true; @@ -392,12 +392,12 @@ this.progressJob.setSystem(true); this.progressJob.schedule(); } - /*boolean status = */job.execute(null); + /*boolean status = */currentJob.execute(null); //if (status == FAILED) request(job); } finally { this.executing = false; if (VERBOSE) - Util.verbose("FINISHED background job - " + job); //$NON-NLS-1$ + Util.verbose("FINISHED background job - " + currentJob); //$NON-NLS-1$ moveToNextJob(); if (this.awaitingClients == 0) Thread.sleep(50); @@ -408,7 +408,12 @@ } catch (RuntimeException e) { if (this.processingThread != null) { // if not shutting down // log exception - Util.log(e, "Background Indexer Crash Recovery"); //$NON-NLS-1$ + StringBuffer buffer = new StringBuffer("Background Indexer Crash Recovery while performing job '"); //$NON-NLS-1$ + buffer.append(currentJob); + buffer.append('\''); + String msg = buffer.toString(); + System.err.println(msg); + Util.log(e, msg); // keep job manager alive this.discardJobs(null); @@ -419,7 +424,12 @@ } catch (Error e) { if (this.processingThread != null && !(e instanceof ThreadDeath)) { // log exception - Util.log(e, "Background Indexer Crash Recovery"); //$NON-NLS-1$ + StringBuffer buffer = new StringBuffer("Background Indexer Crash Recovery while performing job '"); //$NON-NLS-1$ + buffer.append(currentJob); + buffer.append('\''); + String msg = buffer.toString(); + System.err.println(msg); + Util.log(e, msg); // keep job manager alive this.discardJobs(null); Index: search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java,v retrieving revision 1.86 diff -u -r1.86 IndexAllProject.java --- search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java 13 Jun 2006 13:00:43 -0000 1.86 +++ search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java 17 Jan 2008 14:24:44 -0000 @@ -85,7 +85,7 @@ // nothing to index but want to save an empty index file so its not 'rebuilt' when part of a search request Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/); if (index != null) - this.manager.saveIndex(index); + this.manager.saveIndex(index, true/*indexing is finished*/); return true; } if (sourceEntriesNumber != length) Index: search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java,v retrieving revision 1.73 diff -u -r1.73 AddJarFileToIndex.java --- search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java 19 Oct 2007 15:57:22 -0000 1.73 +++ search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java 17 Jan 2008 14:24:44 -0000 @@ -170,7 +170,7 @@ org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index is consistent with library) for " //$NON-NLS-1$ + zip.getName() + " (" //$NON-NLS-1$ + (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$ - this.manager.saveIndex(index); // to ensure its placed into the saved state + this.manager.saveIndex(index, true/*indexing is finished*/); // to ensure its placed into the saved state return true; } } @@ -187,6 +187,8 @@ } index.separator = JAR_SEPARATOR; + Runtime runtime = Runtime.getRuntime(); + this.manager.temporarySaveCount = 0; for (Enumeration e = zip.entries(); e.hasMoreElements();) { if (this.isCancelled) { if (JobManager.VERBOSE) @@ -201,8 +203,19 @@ JavaSearchDocument entryDocument = new JavaSearchDocument(ze, zipFilePath, classFileBytes, participant); this.manager.indexDocument(entryDocument, participant, index, this.containerPath); } + + // Save the index if the free memory is too low + // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=215376 + long free = IndexManager.MAX_MEMORY - runtime.totalMemory() + runtime.freeMemory(); + if (free < IndexManager.MEMORY_THRESHOLD) { + if (JobManager.VERBOSE) { + org.eclipse.jdt.internal.core.util.Util.verbose("Free memory is less than 10% while building "+index+" => save it and garbage..."); //$NON-NLS-1$ //$NON-NLS-2$ + } + this.manager.saveIndex(index, false/*indexing is not finished*/); + runtime.gc(); + } } - this.manager.saveIndex(index); + this.manager.saveIndex(index, true/*indexing is finished*/); if (JobManager.VERBOSE) org.eclipse.jdt.internal.core.util.Util.verbose("-> done indexing of " //$NON-NLS-1$ + zip.getName() + " (" //$NON-NLS-1$ 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.155 diff -u -r1.155 IndexManager.java --- search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java 1 Mar 2007 18:38:55 -0000 1.155 +++ search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java 17 Jan 2008 14:24:44 -0000 @@ -58,6 +58,12 @@ public static Integer UNKNOWN_STATE = new Integer(2); public static Integer REBUILDING_STATE = new Integer(3); + // Memory management + static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + static final long MEMORY_THRESHOLD = (long) (MAX_MEMORY * 0.15); + static final long MAX_SAVE = 4; + int temporarySaveCount; + 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 @@ -576,6 +582,9 @@ this.javaPluginLocation = null; } public void saveIndex(Index index) throws IOException { + saveIndex(index, true); +} +public void saveIndex(Index index, boolean finished) throws IOException { // must have permission to write from the write monitor if (index.hasChanged()) { if (VERBOSE) @@ -592,7 +601,12 @@ } } IPath indexLocation = computeIndexLocation(containerPath); - updateIndexState(indexLocation, SAVED_STATE); + if (!finished) { + if (++temporarySaveCount > MAX_SAVE) { + throw new OutOfMemoryError("Giving up after "+MAX_SAVE+" tries to get more memory space."); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + updateIndexState(indexLocation, finished ? SAVED_STATE : UNKNOWN_STATE); } } /** @@ -622,7 +636,7 @@ if (index.hasChanged()) { if (monitor.exitReadEnterWrite()) { try { - saveIndex(index); + saveIndex(index, true/*indexing is finished*/); } catch(IOException e) { if (VERBOSE) { Util.verbose("-> got the following exception while saving:", System.err); //$NON-NLS-1$ Index: search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java,v retrieving revision 1.15 diff -u -r1.15 SaveIndex.java --- search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java 10 May 2006 18:03:43 -0000 1.15 +++ search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java 17 Jan 2008 14:24:44 -0000 @@ -37,7 +37,7 @@ try { monitor.enterWrite(); // ask permission to write - this.manager.saveIndex(index); + this.manager.saveIndex(index, true/*indexing is finished*/); } catch (IOException e) { if (JobManager.VERBOSE) { Util.verbose("-> failed to save index " + this.containerPath + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$