package lsr.paxos.recovery;
import lsr.paxos.CatchUpListener;
import lsr.paxos.core.CatchUp;
import lsr.paxos.storage.Storage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents <code>CatchUp</code> wrapper used in recovery algorithms to
* retrieve all decided instances up to specified value. The
* <code>CatchUp</code> mechanism is used to retrieve instances from other
* replicas and save them to <code>Storage</code>.
*/
public class RecoveryCatchUp {
private final Storage storage;
private final CatchUp catchUp;
/**
* Creates new instance of <code>RecoveryCatchUp</code> class.
*
* @param catchUp - the catch-up mechanism used to retrieve required
* instances
* @param storage - the storage with paxos state
*/
public RecoveryCatchUp(CatchUp catchUp, Storage storage) {
this.storage = storage;
this.catchUp = catchUp;
}
/**
* Retrieves all instances before <code>firstUncommitted</code> from other
* replicas and save them to storage. The <code>callback</code> is executed
* when all required instances are retrieved (when first uncommitted
* instance in storage is greater or equal than
* <code>firstUncommitted</code>).
*
* @param firstUncommitted - the minimum required value of first uncommitted
* @param callback - the callback executed when recovering is finished
*/
public void recover(final int firstUncommitted, final Runnable callback) {
if (storage.getFirstUncommitted() >= firstUncommitted) {
logger.info("Recovery catch-up unnecessary, running callback");
callback.run();
return;
}
storage.getLog().getInstance(firstUncommitted - 1);
catchUp.addListener(new CatchUpListener() {
public void catchUpAdvanced() {
if (storage.getFirstUncommitted() >= firstUncommitted) {
logger.info("Recovery catch-up succeeded");
catchUp.removeListener(this);
callback.run();
} else {
catchUp.forceCatchup();
}
}
});
logger.info("Starting recovery catch-up up to {}", firstUncommitted);
catchUp.forceCatchup();
}
private final static Logger logger = LoggerFactory.getLogger(RecoveryCatchUp.class);
}