blob: 455060a53339f83fa3cb21d81c0b92ab5f891ec6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems, Inc. 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.internal.db.org.eclipse.cdt.internal.core.pdom.db;
public final class ChunkCache {
private static ChunkCache sSharedInstance= new ChunkCache();
private Chunk[] fPageTable;
private boolean fTableIsFull= false;
private int fPointer= 0;
public static ChunkCache getSharedInstance() {
return sSharedInstance;
}
public ChunkCache() {
this(5*1024*1024);
}
public ChunkCache(long maxSize) {
fPageTable= new Chunk[computeLength(maxSize)];
}
public synchronized void add(Chunk chunk, boolean locked) {
if (locked) {
chunk.fLocked= true;
}
if (chunk.fCacheIndex >= 0) {
chunk.fCacheHitFlag= true;
return;
}
if (fTableIsFull) {
evictChunk();
chunk.fCacheIndex= fPointer;
fPageTable[fPointer]= chunk;
}
else {
chunk.fCacheIndex= fPointer;
fPageTable[fPointer]= chunk;
fPointer++;
if (fPointer == fPageTable.length) {
fPointer= 0;
fTableIsFull= true;
}
}
}
/**
* Evicts a chunk from the page table and the chunk table.
* After this method returns, {@link #fPointer} will contain
* the index of the evicted chunk within the page table.
*/
private void evictChunk() {
/*
* Use the CLOCK algorithm to determine which chunk to evict.
* i.e., if the chunk in the current slot of the page table has been
* recently referenced (i.e. the reference flag is set), unset the
* reference flag and move to the next slot. Otherwise, evict the
* chunk in the current slot.
*/
while (true) {
Chunk chunk = fPageTable[fPointer];
if (chunk.fCacheHitFlag) {
chunk.fCacheHitFlag= false;
fPointer= (fPointer + 1) % fPageTable.length;
} else {
chunk.fDatabase.releaseChunk(chunk);
chunk.fCacheIndex= -1;
fPageTable[fPointer] = null;
return;
}
}
}
public synchronized void remove(Chunk chunk) {
final int idx= chunk.fCacheIndex;
if (idx >= 0) {
if (fTableIsFull) {
fPointer= fPageTable.length-1;
fTableIsFull= false;
}
else {
fPointer--;
}
chunk.fCacheIndex= -1;
final Chunk move= fPageTable[fPointer];
fPageTable[idx]= move;
move.fCacheIndex= idx;
fPageTable[fPointer]= null;
}
}
/**
* Returns the maximum size of the chunk cache in bytes.
*/
public synchronized long getMaxSize() {
return (long) fPageTable.length * Database.CHUNK_SIZE;
}
/**
* Clears the page table and changes it to hold chunks with
* maximum total memory of <code>maxSize</code>.
* @param maxSize the total size of the chunks in bytes.
*/
public synchronized void setMaxSize(long maxSize) {
final int newLength= computeLength(maxSize);
final int oldLength= fTableIsFull ? fPageTable.length : fPointer;
if (newLength > oldLength) {
Chunk[] newTable= new Chunk[newLength];
System.arraycopy(fPageTable, 0, newTable, 0, oldLength);
fTableIsFull= false;
fPointer= oldLength;
fPageTable= newTable;
}
else {
for (int i=newLength; i<oldLength; i++) {
final Chunk chunk= fPageTable[i];
chunk.fDatabase.releaseChunk(chunk);
chunk.fCacheIndex= -1;
}
Chunk[] newTable= new Chunk[newLength];
System.arraycopy(fPageTable, 0, newTable, 0, newLength);
fTableIsFull= true;
fPointer= 0;
fPageTable= newTable;
}
}
private int computeLength(long maxSize) {
long maxLength= Math.min(maxSize/Database.CHUNK_SIZE, Integer.MAX_VALUE);
return Math.max(1, (int)maxLength);
}
}