1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Fix for 193505, Unprotected read-operations can corrupt the index.

This commit is contained in:
Markus Schorn 2007-06-21 12:44:40 +00:00
parent a86a73a2e2
commit 3bad87738f
3 changed files with 104 additions and 53 deletions

View file

@ -21,7 +21,7 @@ import org.eclipse.core.runtime.CoreException;
* Caches the content of a piece of the database.
*/
final class Chunk {
final private ByteBuffer fBuffer;
final private byte[] fBuffer= new byte[Database.CHUNK_SIZE];
final Database fDatabase;
final int fSequenceNumber;
@ -33,14 +33,13 @@ final class Chunk {
Chunk(Database db, int sequenceNumber) {
fDatabase= db;
fBuffer= ByteBuffer.allocate(Database.CHUNK_SIZE);
fSequenceNumber= sequenceNumber;
}
void read() throws CoreException {
try {
fBuffer.position(0);
fDatabase.getChannel().read(fBuffer, fSequenceNumber*Database.CHUNK_SIZE);
final ByteBuffer buf= ByteBuffer.wrap(fBuffer);
fDatabase.getChannel().read(buf, fSequenceNumber*Database.CHUNK_SIZE);
} catch (IOException e) {
throw new CoreException(new DBStatus(e));
}
@ -48,87 +47,120 @@ final class Chunk {
void flush() throws CoreException {
try {
fBuffer.position(0);
fDatabase.getChannel().write(fBuffer, fSequenceNumber*Database.CHUNK_SIZE);
final ByteBuffer buf= ByteBuffer.wrap(fBuffer);
fDatabase.getChannel().write(buf, fSequenceNumber*Database.CHUNK_SIZE);
} catch (IOException e) {
throw new CoreException(new DBStatus(e));
}
fDirty= false;
}
public void putByte(int offset, byte value) {
public void putByte(final int offset, final byte value) {
assert fLocked;
fDirty= true;
fBuffer.put(offset % Database.CHUNK_SIZE, value);
fBuffer[offset % Database.CHUNK_SIZE]= value;
}
public byte getByte(int offset) {
return fBuffer.get(offset % Database.CHUNK_SIZE);
public byte getByte(final int offset) {
return fBuffer[offset % Database.CHUNK_SIZE];
}
public byte[] getBytes(int offset, int length) {
byte[] bytes = new byte[length];
fBuffer.position(offset % Database.CHUNK_SIZE);
fBuffer.get(bytes, 0, length);
public byte[] getBytes(final int offset, final int length) {
final byte[] bytes = new byte[length];
System.arraycopy(fBuffer, offset % Database.CHUNK_SIZE, bytes, 0, length);
return bytes;
}
public void putBytes(int offset, byte[] bytes) {
public void putBytes(final int offset, final byte[] bytes) {
assert fLocked;
fDirty= true;
fBuffer.position(offset % Database.CHUNK_SIZE);
fBuffer.put(bytes, 0, bytes.length);
System.arraycopy(bytes, 0, fBuffer, offset % Database.CHUNK_SIZE, bytes.length);
}
public void putInt(int offset, int value) {
public void putInt(final int offset, final int value) {
assert fLocked;
fDirty= true;
fBuffer.putInt(offset % Database.CHUNK_SIZE, value);
int idx= offset % Database.CHUNK_SIZE;
fBuffer[idx]= (byte)(value >> 24);
fBuffer[++idx]= (byte)(value >> 16);
fBuffer[++idx]= (byte)(value >> 8);
fBuffer[++idx]= (byte)(value);
}
public int getInt(int offset) {
return fBuffer.getInt(offset % Database.CHUNK_SIZE);
public int getInt(final int offset) {
int idx= offset % Database.CHUNK_SIZE;
return ((fBuffer[idx] & 0xff) << 24) |
((fBuffer[++idx] & 0xff) << 16) |
((fBuffer[++idx] & 0xff) << 8) |
((fBuffer[++idx] & 0xff) << 0);
}
public void putShort(int offset, short value) {
public void putShort(final int offset, final short value) {
assert fLocked;
fDirty= true;
fBuffer.putShort(offset % Database.CHUNK_SIZE, value);
int idx= offset % Database.CHUNK_SIZE;
fBuffer[idx]= (byte)(value >> 8);
fBuffer[++idx]= (byte)(value);
}
public short getShort(int offset) {
return fBuffer.getShort(offset % Database.CHUNK_SIZE);
public short getShort(final int offset) {
int idx= offset % Database.CHUNK_SIZE;
return (short) (((fBuffer[idx] << 8) | (fBuffer[++idx] & 0xff)));
}
public long getLong(int offset) {
return fBuffer.getLong(offset % Database.CHUNK_SIZE);
public long getLong(final int offset) {
int idx= offset % Database.CHUNK_SIZE;
return ((((long)fBuffer[idx] & 0xff) << 56) |
(((long)fBuffer[++idx] & 0xff) << 48) |
(((long)fBuffer[++idx] & 0xff) << 40) |
(((long)fBuffer[++idx] & 0xff) << 32) |
(((long)fBuffer[++idx] & 0xff) << 24) |
(((long)fBuffer[++idx] & 0xff) << 16) |
(((long)fBuffer[++idx] & 0xff) << 8) |
(((long)fBuffer[++idx] & 0xff) << 0));
}
public void putLong(int offset, long value) {
public void putLong(final int offset, final long value) {
assert fLocked;
fDirty= true;
fBuffer.putLong(offset % Database.CHUNK_SIZE, value);
int idx= offset % Database.CHUNK_SIZE;
fBuffer[idx]= (byte)(value >> 56);
fBuffer[++idx]= (byte)(value >> 48);
fBuffer[++idx]= (byte)(value >> 40);
fBuffer[++idx]= (byte)(value >> 32);
fBuffer[++idx]= (byte)(value >> 24);
fBuffer[++idx]= (byte)(value >> 16);
fBuffer[++idx]= (byte)(value >> 8);
fBuffer[++idx]= (byte)(value);
}
public void putChar(int offset, char value) {
public void putChar(final int offset, final char value) {
assert fLocked;
fDirty= true;
fBuffer.putChar(offset % Database.CHUNK_SIZE, value);
int idx= offset % Database.CHUNK_SIZE;
fBuffer[idx]= (byte)(value >> 8);
fBuffer[++idx]= (byte)(value);
}
public char getChar(int offset) {
return fBuffer.getChar(offset % Database.CHUNK_SIZE);
public char getChar(final int offset) {
int idx= offset % Database.CHUNK_SIZE;
return (char) (((fBuffer[idx] << 8) | (fBuffer[++idx] & 0xff)));
}
public void getCharArray(int offset, char[] result) {
fBuffer.position(offset % Database.CHUNK_SIZE);
fBuffer.asCharBuffer().get(result);
public void getCharArray(final int offset, final char[] result) {
final ByteBuffer buf= ByteBuffer.wrap(fBuffer);
buf.position(offset % Database.CHUNK_SIZE);
buf.asCharBuffer().get(result);
}
void clear(int offset, int length) {
void clear(final int offset, final int length) {
assert fLocked;
fDirty= true;
fBuffer.position(offset % Database.CHUNK_SIZE);
fBuffer.put(new byte[length]);
int idx= (offset % Database.CHUNK_SIZE);
final int end= idx + length;
for (; idx < end; idx++) {
fBuffer[idx]= 0;
}
}
}

View file

@ -138,6 +138,8 @@ public class Database {
Chunk header= getChunk(0);
header.clear(0, CHUNK_SIZE);
setVersion(version);
// chunks have been removed from the cache, so we are fine here.
chunks = new Chunk[] {header};
try {
getChannel().truncate(CHUNK_SIZE);
@ -252,16 +254,20 @@ public class Database {
}
private int createNewChunk() throws CoreException {
Chunk[] oldtoc = chunks;
int n = oldtoc.length;
int offset = n * CHUNK_SIZE;
chunks = new Chunk[n + 1];
System.arraycopy(oldtoc, 0, chunks, 0, n);
final Chunk chunk= new Chunk(this, n);
// prepare new chunk array
final int oldLen= chunks.length;
final Chunk chunk= new Chunk(this, oldLen);
chunk.fDirty= true;
chunks[n]= chunk;
fCache.add(chunk, true);
return offset;
Chunk[] newchunks = new Chunk[oldLen+1];
// the content of the chunk array may be modified by the cache, so sync it.
synchronized (fCache) {
System.arraycopy(chunks, 0, newchunks, 0, oldLen);
newchunks[oldLen]= chunk;
chunks= newchunks;
fCache.add(chunk, true);
}
return oldLen * CHUNK_SIZE;
}
private int getFirstBlock(int blocksize) throws CoreException {
@ -408,6 +414,8 @@ public class Database {
public void close() throws CoreException {
setReadOnly(true);
removeChunksFromCache();
// chunks have been removed from the cache, so we are fine
chunks= new Chunk[0];
try {
file.close();

View file

@ -77,6 +77,7 @@ public class IndexView extends ViewPart implements PDOM.IListener, IElementChang
private IndexAction findReferencesAction;
Filter filter = new Filter();
public boolean isLinking = false;
private volatile boolean fUpdateRequested= false;
public void toggleExternalDefs() {
if (!filter.showExternalDefs) {
@ -406,11 +407,21 @@ public class IndexView extends ViewPart implements PDOM.IListener, IElementChang
}
public void handleChange(PDOM pdom) {
viewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
viewer.refresh();
}
});
requestUpdate();
}
private void requestUpdate() {
if (!fUpdateRequested) {
fUpdateRequested= true;
viewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
fUpdateRequested= false;
if (!viewer.getControl().isDisposed()) {
viewer.refresh();
}
}
});
}
}
public void elementChanged(ElementChangedEvent event) {