// Copyright 2009 Google Inc. All Rights Reserved.
package org.waveprotocol.wave.model.util;
import org.waveprotocol.wave.model.util.FuzzingBackOffGenerator.BackOffParameters;
/**
* Schedules a task with fuzzing fibonacci backoff schedule. The
* Actual scheduling is delegated to a native scheduler.
* This class does not interpret the delay values, but simply passes
* them through to the native scheduler.
*
* @author zdwang@google.com (David Wang)
*/
public class FuzzingBackOffScheduler implements Scheduler {
/** The scheduled task that can be cancelled */
public interface Cancellable {
/**
* Cancel this task.
*/
void cancel();
}
/**
* Allows injection of actually defer executing a task. This because the
* client and server has different scheduling implementations. A collective
* scheduler tries to executed the task at the given targetTimeMs, but may
* execute the task at minAllowedMs if it is more efficient to do so.
*/
public interface CollectiveScheduler {
/**
* Schedule a task to be executed between minAllowedMs and millisec later
*
* @param task the task to execute
* @param minAllowedMs the minimum amount of time to wait.
* @param targetTimeMs the target delay to wait
*/
Cancellable schedule(Command task, int minAllowedMs, int targetTimeMs);
}
private final FuzzingBackOffGenerator generator;
private final CollectiveScheduler scheduler;
private Cancellable scheduledTask;
/**
* @param initialBackOffMs Initial value to back off. This class does not interpret the meaning of
* this value.
* @param maxBackOffMs Max value to back off
* @param randomisationFactor between 0 and 1 to control the range of randomness.
* @param scheduler assumed not null.
*/
private FuzzingBackOffScheduler(int initialBackOffMs, int maxBackOffMs,
double randomisationFactor, CollectiveScheduler scheduler) {
this.generator = new FuzzingBackOffGenerator(initialBackOffMs, maxBackOffMs,
randomisationFactor);
this.scheduler = scheduler;
}
@Override
public void reset() {
generator.reset();
if (scheduledTask != null) {
scheduledTask.cancel();
}
scheduledTask = null;
}
@Override
public void schedule(Command task) {
if (scheduledTask != null) {
scheduledTask.cancel();
}
BackOffParameters parameters = generator.next();
scheduledTask = scheduler.schedule(task, parameters.minimumDelay, parameters.targetDelay);
}
/**
* Builder for FuzzingBackOffSchedulers.
*/
public static class Builder {
private int initialBackOffMs = 10;
private int maxBackOffMs = 5000;
private double randomisationFactor = 0.5;
private final CollectiveScheduler scheduler;
/**
* Constructor.
*
* @param scheduler the underlying scheduler to use to actually execute tasks.
*/
public Builder(CollectiveScheduler scheduler) {
this.scheduler = scheduler;
}
/**
* Build the scheduler.
*
* @return the newly created scheduler
*/
public Scheduler build() {
return new FuzzingBackOffScheduler(initialBackOffMs, maxBackOffMs, randomisationFactor,
scheduler);
}
public Builder setInitialBackOffMs(int initialBackOffMs) {
this.initialBackOffMs = initialBackOffMs;
return this;
}
public Builder setMaxBackOffMs(int maxBackOffMs) {
this.maxBackOffMs = maxBackOffMs;
return this;
}
public Builder setRandomisationFactor(double randomisationFactor) {
this.randomisationFactor = randomisationFactor;
return this;
}
}
}