diff options
author | Stefan Xenos | 2016-11-24 02:49:54 +0000 |
---|---|---|
committer | Stefan Xenos | 2016-12-05 15:46:24 +0000 |
commit | b730972c517cea235783aa9d39103d9dea5bbbdf (patch) | |
tree | fb5bea44a40f734f6d3302ebaa541924f22b3bec | |
parent | 0b0f856ffea622a77c7ebc01bae802a409925214 (diff) | |
download | eclipse.jdt.core-b730972c517cea235783aa9d39103d9dea5bbbdf.tar.gz eclipse.jdt.core-b730972c517cea235783aa9d39103d9dea5bbbdf.tar.xz eclipse.jdt.core-b730972c517cea235783aa9d39103d9dea5bbbdf.zip |
Bug 508085 - Add a robust Database.createChunks(int) method
Change-Id: I7cd86b8113319f5ee77f7c66adc572720b63cc29
Signed-off-by: Stefan Xenos <sxenos@gmail.com>
-rw-r--r-- | org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java | 75 |
1 files changed, 28 insertions, 47 deletions
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java index 02060fe08c..c8067f41f9 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java @@ -90,7 +90,7 @@ public class Database { public static final int MIN_BLOCK_DELTAS = (FREE_BLOCK_HEADER_SIZE + BLOCK_SIZE_DELTA - 1) / BLOCK_SIZE_DELTA; // Must be enough multiples of BLOCK_SIZE_DELTA in order to fit the free block header public static final int MAX_BLOCK_DELTAS = CHUNK_SIZE / BLOCK_SIZE_DELTA; - public static final int MAX_MALLOC_SIZE = MAX_BLOCK_DELTAS * BLOCK_SIZE_DELTA - BLOCK_HEADER_SIZE; + public static final int MAX_MALLOC_SIZE = MAX_BLOCK_DELTAS * BLOCK_SIZE_DELTA - BLOCK_HEADER_SIZE; public static final int PTR_SIZE = 4; // size of a pointer in the database in bytes public static final int STRING_SIZE = PTR_SIZE; public static final int FLOAT_SIZE = INT_SIZE; @@ -128,7 +128,6 @@ public class Database { private final Chunk fHeaderChunk; private Chunk[] fChunks; private int fChunksUsed; - private int fChunksAllocated; private ChunkCache fCache; private long malloced; @@ -159,12 +158,12 @@ public class Database { if (nChunksOnDisk <= 0) { this.fVersion= version; this.fChunks= new Chunk[1]; - this.fChunksUsed = this.fChunksAllocated = this.fChunks.length; + this.fChunksUsed = this.fChunks.length; } else { this.fHeaderChunk.read(); this.fVersion= this.fHeaderChunk.getInt(VERSION_OFFSET); this.fChunks = new Chunk[nChunksOnDisk]; // chunk[0] is unused. - this.fChunksUsed = this.fChunksAllocated = nChunksOnDisk; + this.fChunksUsed = nChunksOnDisk; } } catch (IOException e) { throw new IndexException(new DBStatus(e)); @@ -292,7 +291,7 @@ public class Database { this.fHeaderChunk.clear(0, CHUNK_SIZE); // Chunks have been removed from the cache, so we may just reset the array of chunks. this.fChunks = new Chunk[] {null}; - this.fChunksUsed = this.fChunksAllocated = this.fChunks.length; + this.fChunksUsed = this.fChunks.length; try { wasCanceled = this.fHeaderChunk.flush() || wasCanceled; // Zero out header chunk. wasCanceled = performUninterruptableWrite(() -> { @@ -414,7 +413,7 @@ public class Database { Chunk chunk; if (freeblock == 0) { // Allocate a new chunk. - freeblock= createNewChunk(); + freeblock= createNewChunks(1); useDeltas = MAX_BLOCK_DELTAS; chunk = getChunk(freeblock); } else { @@ -442,27 +441,27 @@ public class Database { return result; } - private long createNewChunk() throws IndexException { + private long createNewChunks(int numChunks) throws IndexException { assert this.fExclusiveLock; synchronized (this.fCache) { - final int newChunkIndex = this.fChunksUsed; // fChunks.length; - - final Chunk chunk = new Chunk(this, newChunkIndex); - chunk.fDirty = true; - - if (newChunkIndex >= this.fChunksAllocated) { - int increment = Math.max(1024, this.fChunksAllocated / 20); - Chunk[] newchunks = new Chunk[this.fChunksAllocated + increment]; - System.arraycopy(this.fChunks, 0, newchunks, 0, this.fChunksAllocated); - - this.fChunks = newchunks; - this.fChunksAllocated += increment; + final int firstChunkIndex = this.fChunksUsed; + final int lastChunkIndex = firstChunkIndex + numChunks - 1; + + final Chunk lastChunk = new Chunk(this, lastChunkIndex); + lastChunk.fDirty = true; + + if (lastChunkIndex >= this.fChunks.length) { + int increment = Math.max(1024, this.fChunks.length / 20); + int newNumChunks = Math.max(lastChunkIndex + 1, this.fChunks.length + increment); + Chunk[] newChunks = new Chunk[newNumChunks]; + System.arraycopy(this.fChunks, 0, newChunks, 0, this.fChunks.length); + this.fChunks = newChunks; } - this.fChunksUsed += 1; - this.fChunks[newChunkIndex] = chunk; - this.fCache.add(chunk, true); - long address = (long) newChunkIndex * CHUNK_SIZE; + this.fChunksUsed = lastChunkIndex + 1; + this.fChunks[lastChunkIndex] = lastChunk; + this.fCache.add(lastChunk, true); + long result = (long) firstChunkIndex * CHUNK_SIZE; /* * Non-dense pointers are at most 31 bits dense pointers are at most 35 bits Check the sizes here and throw @@ -470,33 +469,15 @@ public class Database { * indexing operation should be stopped. This is desired since generally, once the max size is exceeded, * there are lots of errors. */ - if (address >= MAX_DB_SIZE) { + long endAddress = result + (numChunks * CHUNK_SIZE); + if (endAddress > MAX_DB_SIZE) { Object bindings[] = { this.getLocation().getAbsolutePath(), MAX_DB_SIZE }; throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, Package.STATUS_DATABASE_TOO_LARGE, - NLS.bind("Database too large! Address = " + address + ", max size = " + MAX_DB_SIZE, bindings), //$NON-NLS-1$ //$NON-NLS-2$ - null)); + NLS.bind("Database too large! Address = " + endAddress + ", max size = " + MAX_DB_SIZE, //$NON-NLS-1$ //$NON-NLS-2$ + bindings), null)); } - return address; - } - } - /** - * For testing purposes, only. - */ - private long createNewChunks(int numChunks) throws IndexException { - assert this.fExclusiveLock; - synchronized (this.fCache) { - final int oldLen= this.fChunks.length; - Chunk[] newchunks = new Chunk[oldLen + numChunks]; - System.arraycopy(this.fChunks, 0, newchunks, 0, oldLen); - final Chunk chunk= new Chunk(this, oldLen + numChunks - 1); - chunk.fDirty= true; - newchunks[ oldLen + numChunks - 1 ] = chunk; - this.fChunks= newchunks; - this.fCache.add(chunk, true); - this.fChunksAllocated=oldLen + numChunks; - this.fChunksUsed=oldLen + numChunks; - return (long) (oldLen + numChunks - 1) * CHUNK_SIZE; + return result; } } @@ -745,7 +726,7 @@ public class Database { this.memoryUsage.refresh(); this.fHeaderChunk.fDirty= false; this.fChunks= new Chunk[] { null }; - this.fChunksUsed = this.fChunksAllocated = this.fChunks.length; + this.fChunksUsed = this.fChunks.length; try { this.fFile.close(); } catch (IOException e) { |