2 * Copyright (c) 2003-2005 The BISON Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 package peersim.edsim;
21 import peersim.core.*;
22 import peersim.cdsim.CDProtocol;
23 import peersim.config.*;
24 import peersim.dynamics.NodeInitializer;
27 * Schedules the first execution of the cycle based protocol instances in the
28 * event driven engine. It implements {@link Control} but it will most often be
29 * invoked only once for each protocol as an initializer, since the scheduled
30 * events schedule themselves for the consecutive executions (see
31 * {@link NextCycleEvent}).
34 * All {@link CDProtocol} specifications in the configuration need to contain a
35 * {@link Scheduler} specification at least for the step size (see config
36 * parameter {@value peersim.core.Scheduler#PAR_STEP} of {@link Scheduler}).
37 * This value is used as the cycle length for the corresponding protocol.
41 public class CDScheduler implements Control, NodeInitializer {
43 // ============================== fields ==============================
44 // ====================================================================
47 * Parameter that is used to define the class that is used to schedule the
48 * next cycle. Its type is (or extends) {@link NextCycleEvent}. Defaults to
49 * {@link NextCycleEvent}.
53 private static final String PAR_NEXTC = "nextcycle";
56 * The protocols that this scheduler schedules for the first execution. It
57 * might contain several protocol names, separated by whitespace. All
58 * protocols will be scheduled based on the common parameter set for this
59 * scheduler and the parameters of the protocol (cycle length). Protocols
60 * are scheduled independently of each other.
64 private static final String PAR_PROTOCOL = "protocol";
67 * If set, it means that the initial execution of the given protocol is
68 * scheduled for a different random time for all nodes. The random time is a
69 * sample between the current time (inclusive) and the cycle length
70 * (exclusive), the latter being specified by the step parameter (see
71 * {@link Scheduler}) of the assigned protocol.
76 private static final String PAR_RNDSTART = "randstart";
79 * Contains the scheduler objects for all {@link CDProtocol}s defined in the
80 * configuration. The length of the array is the number of protocols
81 * defined, but those entries that belong to protocols that are not
82 * {@link CDProtocol}s are null.
84 public static final Scheduler[] sch;
86 private final NextCycleEvent[] nce;
88 private final int[] pid;
90 private final boolean randstart;
92 // =============================== initialization ======================
93 // =====================================================================
96 * Loads protocol schedulers for all protocols.
100 String[] names = Configuration.getNames(Node.PAR_PROT);
101 sch = new Scheduler[names.length];
102 for (int i = 0; i < names.length; ++i) {
103 if (Network.prototype.getProtocol(i) instanceof CDProtocol)
104 // with no default values for step to avoid
105 // "overscheduling" due to lack of step option.
106 sch[i] = new Scheduler(names[i], false);
110 // --------------------------------------------------------------------
113 * Initialization based on configuration parameters.
115 public CDScheduler(String n) {
116 String[] prots = Configuration.getString(n + "." + PAR_PROTOCOL).split("\\s");
117 pid = new int[prots.length];
118 nce = new NextCycleEvent[prots.length];
119 for (int i = 0; i < prots.length; ++i) {
120 pid[i] = Configuration.lookupPid(prots[i]);
121 if (!(Network.prototype.getProtocol(pid[i]) instanceof CDProtocol)) {
122 throw new IllegalParameterException(n + "." + PAR_PROTOCOL,
123 "Only CDProtocols are accepted here");
125 nce[i] = (NextCycleEvent) Configuration.getInstance(n + "."
126 + PAR_NEXTC, new NextCycleEvent(null));
128 randstart = Configuration.contains(n + "." + PAR_RNDSTART);
131 // ========================== methods ==================================
132 // =====================================================================
135 * Schedules the protocol at all nodes for the first execution adding it to
136 * the priority queue of the event driven simulation. The time of the first
137 * execution is determined by {@link #firstDelay}. The implementation calls
138 * {@link #initialize} for all nodes.
142 public boolean execute() {
144 for (int i = 0; i < Network.size(); ++i) {
145 initialize(Network.get(i));
151 // --------------------------------------------------------------------
154 * Schedules the protocol at given node for the first execution adding it to
155 * the priority queue of the event driven simulation. The time of the first
156 * execution is determined by a reference point in time and
157 * {@link #firstDelay}, which defines the delay from the reference point.
158 * The reference point is the maximum of the current time, and the value of
159 * parameter {@value peersim.core.Scheduler#PAR_FROM} of the protocol being
160 * scheduled. If the calculated time of the first execution is not valid
161 * according to the schedule of the protocol then no execution is scheduled
164 * A final note: for performance reasons, the recommended practice is not to
165 * use parameter {@value peersim.core.Scheduler#PAR_FROM} in protocols, but
166 * to schedule {@link CDScheduler} itself for the desired time, whenever
167 * possible (e.g., it is not possible if {@link CDScheduler} is used as a
168 * {@link NodeInitializer}).
170 public void initialize(Node n) {
172 * XXX If "from" is not the current time and this is used as a control
173 * (not node initializer) then we dump _lots_ of events in the queue
174 * that are just stored there until "from" comes. This reduces
175 * performance, and should be fixed. When fixed, the final comment can
176 * be removed from the docs.
179 final long time = CommonState.getTime();
180 for (int i = 0; i < pid.length; ++i) {
181 Object nceclone = null;
183 nceclone = nce[i].clone();
184 } catch (CloneNotSupportedException e) {
185 } // cannot possibly happen
187 final long delay = firstDelay(sch[pid[i]].step);
188 final long nexttime = Math.max(time, sch[pid[i]].from) + delay;
189 if (nexttime < sch[pid[i]].until)
190 EDSimulator.add(nexttime - time, nceclone, n, pid[i]);
194 // --------------------------------------------------------------------
197 * Returns the time (through giving the delay from the current time) when
198 * this even is first executed. If {@value #PAR_RNDSTART} is not set, it
199 * returns zero, otherwise a random value between 0, inclusive, and
200 * cyclelength, exclusive.
203 * The cycle length of the cycle based protocol for which this
206 protected long firstDelay(long cyclelength) {
209 return CommonState.r.nextLong(cyclelength);