From da9aa45994b0f58ad68a76b2898e30b815a33e54 Mon Sep 17 00:00:00 2001 From: Chris Recoskie Date: Thu, 30 Nov 2006 15:46:09 +0000 Subject: [PATCH] fix for 164019 by Jason Montojo --- .../eclipse/cdt/internal/core/pdom/PDOM.java | 3 +- .../cdt/internal/core/pdom/db/Chunk.java | 23 +++++- .../cdt/internal/core/pdom/db/Database.java | 70 +++++++++++++++++-- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 7e4c53550f1..71885fb90a2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -8,6 +8,7 @@ * Contributors: * QNX - Initial API and implementation * Markus Schorn (Wind River Systems) + * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; @@ -174,7 +175,7 @@ public class PDOM extends PlatformObject implements IIndexFragment, IPDOM { protected void clear() throws CoreException { Database db = getDB(); // Clear out the database - db.clear(); + db.clear(0); // Zero out the File Index and Linkages db.putInt(FILE_INDEX, 0); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java index 2926e9f27ff..76d509c6b5d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java @@ -8,13 +8,17 @@ * Contributors: * QNX - Initial API and implementation * Markus Schorn (Wind River Systems) + * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.db; import java.io.IOException; import java.io.RandomAccessFile; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; +import java.util.Set; import org.eclipse.core.runtime.CoreException; @@ -101,8 +105,21 @@ public class Chunk { buffer.put(new byte[length]); } - void free() { - db.toc[index] = null; + /** + * Allow this Chunk to be reclaimed. Objects allocated by thus Chunk + * may be registered with a ReferenceQueue to allow for notification + * on deallocation. References registered with the queue are added to + * the Set references. + * + * @param queue ReferenceQueue to register allocated objects with, or + * null if notification is not required. + * @param references Populated with references which were registered + * with the queue. + */ + void reclaim(ReferenceQueue queue, Set references) { + if (queue != null) { + references.add(new WeakReference(buffer, queue)); + } + buffer = null; } - } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java index 25979c566eb..427dfc7f259 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java @@ -9,12 +9,16 @@ * QNX - Initial API and implementation * Symbian - Add some non-javadoc implementation notes * Markus Schorn (Wind River Systems) + * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.db; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.lang.ref.ReferenceQueue; +import java.util.HashSet; +import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.core.runtime.CoreException; @@ -106,16 +110,74 @@ public class Database { * Empty the contents of the Database, make it ready to start again * @throws CoreException */ - public void clear() throws CoreException { + public void clear(long timeout) throws CoreException { // Clear out the memory headers toc[0].clear(4, DATA_AREA - 4); - // Add the remainder of the chunks backwards - for (int block = (toc.length - 1) * CHUNK_SIZE; block > 0; block -= CHUNK_SIZE) { - addBlock(getChunk(block), CHUNK_SIZE, block); + + if (!truncate(timeout)) { + // Truncation timed out so the database size couldn't be changed. + // The best we can do is mark all chunks as unallocated blocks. + + // Since the block list grows at the head, add all non-header + // chunks backwards to ensure list of blocks is ordered first + // to last. + for (int block = (toc.length - 1) * CHUNK_SIZE; block > 0; block -= CHUNK_SIZE) { + addBlock(getChunk(block), CHUNK_SIZE, block); + } } malloced = freed = 0; } + /** + * Truncate the database as small as possible to reclaim disk space. + * This method returns false if truncation does not succeed within the + * given timeout period (in milliseconds). A timeout of 0 will cause + * this method to block until the database is successfully truncated. + * + * @param timeout maximum amount of milliseconds to wait before giving up; + * 0 means wait indefinitely. + * @return true if truncation succeeds; false if the operation times out. + * @throws CoreException if an IO error occurs during truncation + */ + private boolean truncate(long timeout) throws CoreException { + // Queue all the chunks to be reclaimed. + ReferenceQueue queue = new ReferenceQueue(); + Set references = new HashSet(); + for (int i = 0; i < toc.length; i++) { + if (toc[i] != null) { + toc[i].reclaim(queue, references); + toc[i] = null; + } + } + + System.gc(); + try { + // Wait for each chunk to be reclaimed. + int totalReclaimed = references.size(); + while (totalReclaimed > 0) { + queue.remove(timeout); + totalReclaimed--; + } + + // Truncate everything but the header chunk. + try { + file.getChannel().truncate(CHUNK_SIZE); + } catch (IOException e) { + throw new CoreException(new DBStatus(e)); + } + // Reinitialize header chunk. + toc = new Chunk[] { new Chunk(file, 0) }; + return true; + } + catch (InterruptedException e) { + // Truncation took longer than we wanted, so we'll + // reinitialize the header chunk and leave the file + // size alone. + toc[0] = new Chunk(file, 0); + return false; + } + } + /** * Return the Chunk that contains the given offset. *