package dovetaildb.fileaccessor;
import java.io.File;
import gnu.trove.TLongLongHashMap;
import gnu.trove.TLongLongProcedure;
import gnu.trove.TLongProcedure;
public class FreePageTracker {
BitFieldFile freePages;
TLongLongHashMap userToUsageTs = new TLongLongHashMap();
TLongLongHashMap freePageToFreedTs = new TLongLongHashMap();
long earliestTimestamp = Long.MAX_VALUE;
public FreePageTracker(File freeFile) {
freePages = new BitFieldFile(freeFile);
while(true) {
int freePage = freePages.getNextSet(0);
if (freePage == -1) break;
freePageToFreedTs.put(freePage, 0L);
}
}
public synchronized void markPageFree(long page) {
freePages.setOn(page);
freePageToFreedTs.put(page, System.currentTimeMillis());
}
final class PageFinder implements TLongLongProcedure {
long result=-1;
public boolean execute(long page, long freedTs) {
if (freedTs < earliestTimestamp) {
result = page;
return false;
}
return true;
}
}
public synchronized long findFreePage() {
PageFinder finder = new PageFinder();
freePageToFreedTs.forEachEntry(finder);
long page = finder.result;
if (page != -1) {
freePageToFreedTs.remove(page);
freePages.setOff(page);
}
return finder.result;
}
public synchronized void markInUse(long asOfTimestamp, long userId) {
if (userToUsageTs.isEmpty()) earliestTimestamp = asOfTimestamp;
userToUsageTs.put(userId, asOfTimestamp);
}
public synchronized void markNotInUse(long userId) {
long ts = userToUsageTs.remove(userId);
if (ts <= earliestTimestamp) {
earliestTimestamp = Long.MAX_VALUE;
userToUsageTs.forEachValue(new TLongProcedure() {
public boolean execute(long curTs) {
if (curTs < earliestTimestamp) {
earliestTimestamp = curTs;
}
return true;
}
});
}
}
}