package disk;
import java.util.TreeMap;
import java.util.LinkedList;
import events.DiskSimInternalEvent;
import simulation.Simulation;
public class DiskSimNative extends DiskSim {
class InternalRequestInfo {
public long externalRequestID;
public long diskBlock;
public InternalRequestInfo(long externalRequestID, long diskBlock) {
this.externalRequestID = externalRequestID;
this.diskBlock = diskBlock;
}
}
String pfile, ofile;
DiskSimInternalEvent nextEvent = null;
long currentRequestID = 0;
TreeMap<Long,InternalRequestInfo> pendingRequests;
public DiskSimNative(Simulation sim, String pfile, String ofile) {
super(sim);
this.pfile = pfile;
this.ofile = ofile;
initDisksim(pfile, ofile);
pendingRequests = new TreeMap<Long,InternalRequestInfo>();
}
@Override
public void runInternalEvent(DiskSimInternalEvent e) {
assert e == nextEvent;
LinkedList<Long> readyReqIDs = new LinkedList<Long>();
double newTime = runInternalEventHelper(e.getTime(), readyReqIDs);
assert (newTime < 0) || (newTime > e.getTime());
scheduleNewInternalEvent(newTime);
deliverReadyBlocks(readyReqIDs);
}
@Override
public void submitReadRequest(double now, long externalRequestID, long disknum, long diskBlock) {
LinkedList<Long> readyReqIDs = new LinkedList<Long>();
currentRequestID++;
pendingRequests.put(currentRequestID, new InternalRequestInfo(externalRequestID, diskBlock));
double newTime = submitReadRequestHelper(now, currentRequestID, disknum, diskBlock, readyReqIDs);
assert newTime > now: "newTime: " + newTime + " now: " + now;
if (null == nextEvent) {
// Fresh request, no pending internal events.
assert !shouldDeschedule();
scheduleNewInternalEvent(newTime);
} else {
// There is an old internal event pending in the SimDriver.
double oldTime = nextEvent.getTime();
assert oldTime >= now: "oldTime: " + oldTime + " now: " + now;
if (shouldDeschedule())
deschedule();
if (newTime < 0) {
// DiskSim has handled all pending internal events.
// There should be none present in the SimDriver.
assert null == nextEvent;
} else if (newTime < oldTime) {
// A new event is now the earliest.
// DiskSim should have told us to deschedule the old event.
assert null == nextEvent;
scheduleNewInternalEvent(newTime);
} else if (newTime == oldTime) {
// The next event is an internal event that is already registered with the SimDriver.
// However, we need to handle the case where DiskSim told us to
// deschedule and then reschedule it.
if (null == nextEvent) {
scheduleNewInternalEvent(newTime);
}
} else if (newTime > oldTime) {
// It seems to be possible for DiskSim to cancel a pending event and then
// schedule a new one for a later time.
// That's okay, as long as DiskSim told us to deschedule the old event.
assert null == nextEvent;
scheduleNewInternalEvent(newTime);
}
}
deliverReadyBlocks(readyReqIDs);
}
private void deliverReadyBlocks(LinkedList<Long> reqIDs) {
while (!reqIDs.isEmpty()) {
long reqID = reqIDs.pop();
assert reqID > 0;
assert pendingRequests.containsKey(reqID);
InternalRequestInfo req = pendingRequests.get(reqID);
deliverBlock(req.externalRequestID, req.diskBlock);
pendingRequests.remove(reqID);
}
}
private void deschedule() {
if (nextEvent != null) {
sim.simDriver.deschedule(nextEvent);
}
nextEvent = null;
}
private void scheduleNewInternalEvent(double nextEventTime) {
if (nextEventTime > 0) {
nextEvent = new DiskSimInternalEvent(sim, nextEventTime);
sim.simDriver.schedule(nextEvent);
} else {
nextEvent = null;
}
}
@Override
public native long ndisks();
@Override
public native long maxBlocks();
public native void endSimulation(double time);
private native void initDisksim(String pfile, String ofile);
private native double runInternalEventHelper(double time, LinkedList<Long> readyReqIDs);
private native double submitReadRequestHelper(double time, long reqID, long disknum, long diskBlock, LinkedList<Long> readyReqIDs);
private native boolean shouldDeschedule();
static {
System.loadLibrary("disk_DiskSimNative");
}
}