1classdef JobClass < NetworkElement
2 % An abstract
class for a collection of indistinguishable jobs
4 % Copyright (c) 2012-2026, Imperial College London
9 deadline; % relative deadline from arrival (Inf = no deadline)
10 refstat; % reference station
11 isrefclass; %
is this a reference
class within a chain?
14 completes; %
true if passage through reference station
is a completion
15 replySignalClass; % Signal
class that will unblock servers waiting for reply (for synchronous call semantics)
16 spawnClass; % Class of
the job injected at
the same station on each service completion of
this class (LQN phase-2 continuation)
17 patience; % Global patience distribution
for this class (customers abandon queues after patience time)
18 impatienceType; % Global impatience type
for this class (ImpatienceType.RENEGING or ImpatienceType.BALKING)
19 immediateFeedback; % Boolean:
true if this class uses immediate feedback on self-loops globally
24 function self = JobClass(type, name)
25 % SELF = JOBCLASS(TYPE, NAME)
27 self@NetworkElement(name);
30 self.refstat = Node(
'Unallocated');
31 self.isrefclass =
false;
34 self.completes =
true;
35 self.replySignalClass = [];
38 self.impatienceType = [];
39 self.immediateFeedback =
false;
42 function self = setReferenceStation(self, source)
43 % SELF = SETREFERENCESTATION(SOURCE)
45 self.refstat = source;
48 function self = setReferenceClass(self,
bool)
49 % SELF = SETREFERENCECLASS(BOOL)
50 self.isrefclass = bool;
53 function boolIsa = isReferenceStation(self, node)
54 % BOOLISA = ISREFERENCESTATION(NODE)
56 boolIsa = strcmp(self.refstat.name,node.name);
59 function boolIsa = isReferenceClass(self)
60 % BOOLISA = ISREFERENCECLASS()
62 boolIsa = self.isrefclass;
65 % function self = set.priority(self, priority)
66 % SELF = SET.PRIORITY(PRIORITY)
68 % if ~(rem(priority,1) == 0 && priority >= 0)
69 % line_error(mfilename,'Priority must be an integer.\n');
71 % self.priority = priority;
75 methods (Access=public)
76 function ind = subsindex(self)
79 ind =
double(self.index)-1; % 0 based
82 function summary(self)
84 line_printf('Class (%s): <strong>%s</strong>',self.type,self.getName);
87 function self = setPriority(self, priority)
88 % SELF = SETPRIORITY(PRIORITY)
89 % Set
the priority of this class (0 = highest). Used by
the
90 % line-opt ClassPriority decision variable.
91 if ~(rem(priority,1) == 0 && priority >= 0)
92 line_error(mfilename,'Priority must be a non-negative integer.\n');
94 self.priority = priority;
97 function self = setReplySignalClass(self, replyClass)
98 % SETREPLYSIGNALCLASS Set
the Signal class for synchronous call reply
100 % self = SETREPLYSIGNALCLASS(self, replyClass) configures this job
101 % class to expect a reply signal from
the specified Signal class.
102 % When a job of this class completes service,
the server will block
103 % until receiving a REPLY signal from
the specified class.
105 % This implements LQN-style synchronous call semantics where a
106 % client sends a request, blocks waiting for a reply, and then
107 % continues processing after
the reply arrives.
109 % @param replyClass Signal
object with SignalType.REPLY that will unblock
the server
110 % @return self The modified JobClass instance
112 if ~isa(replyClass, 'Signal')
113 line_error(mfilename, 'Reply class must be a Signal.');
115 if replyClass.signalType ~= SignalType.REPLY
116 line_error(mfilename, 'Reply class must have SignalType.REPLY.');
118 self.replySignalClass = replyClass;
121 function idx = getReplySignalClassIndex(self)
122 % GETREPLYSIGNALCLASSINDEX Get
the index of
the reply signal class
124 % idx = GETREPLYSIGNALCLASSINDEX(self) returns
the index of
the
125 % Signal class that will unblock servers waiting for this class,
126 % or -1 if no reply
is expected.
128 % @return idx Index of reply signal class, or -1 if none
130 if isempty(self.replySignalClass)
133 idx = self.replySignalClass.index;
137 function self = setSpawnClass(self, spawnCls)
138 % SELF = SETSPAWNCLASS(SPAWNCLS)
140 % On each service completion of a job of this class, a new job
141 % of class SPAWNCLS
is injected at
the same station. Used for
142 % LQN phase-2 continuations, where
the reply token returns to
143 %
the caller while
the served task continues its second phase.
145 if ~isa(spawnCls, 'JobClass')
146 line_error(mfilename, 'Spawn class must be a JobClass.');
148 self.spawnClass = spawnCls;
151 function tf = expectsReply(self)
152 % EXPECTSREPLY Check if this class expects a reply signal
154 % tf = EXPECTSREPLY(self) returns true if this class has been
155 % configured to expect a reply signal (via setReplySignalClass).
157 % @return tf True if a reply signal
is expected
159 tf = ~isempty(self.replySignalClass);
162 function self = setPatience(self, varargin)
163 % SELF = SETPATIENCE(DISTRIBUTION) - Backwards compatible
164 % SELF = SETPATIENCE(IMPATIENCETYPE, DISTRIBUTION) - Explicit type
166 % Sets
the global impatience type and distribution for this job class.
167 % This applies to all queues unless overridden by queue-specific settings.
170 % impatienceType - (Optional) ImpatienceType constant (RENEGING or BALKING)
171 % If omitted, defaults to ImpatienceType.RENEGING
172 % distribution - Any LINE distribution (Exp, Erlang, HyperExp, etc.)
173 % excluding modulated processes (BMAP, MAP, MMPP2)
176 %
jobclass.setPatience(Exp(0.1)) % Defaults to RENEGING
177 %
jobclass.setPatience(ImpatienceType.RENEGING, Exp(0.1))
178 %
jobclass.setPatience(ImpatienceType.BALKING, Det(5.0))
180 % Handle backwards compatibility: 1 or 2 arguments
181 if length(varargin) == 1
182 % Old signature: setPatience(distribution)
183 distribution = varargin{1};
184 impatienceType = ImpatienceType.RENEGING; % Default to RENEGING
185 elseif length(varargin) == 2
186 % New signature: setPatience(impatienceType, distribution)
187 impatienceType = varargin{1};
188 distribution = varargin{2};
190 line_error(mfilename,
'Invalid number of arguments. Use setPatience(distribution) or setPatience(impatienceType, distribution)');
193 if isa(distribution,
'BMAP') || isa(distribution,
'MAP') || isa(distribution,
'MMPP2')
194 line_error(mfilename, 'Modulated processes (BMAP, MAP, MMPP2) are not supported for patience distributions.');
197 % Validate impatience type
198 if impatienceType ~= ImpatienceType.RENEGING && impatienceType ~= ImpatienceType.BALKING
199 line_error(mfilename, 'Invalid impatience type. Use ImpatienceType.RENEGING or ImpatienceType.BALKING.');
202 % Only RENEGING
is currently supported
203 if impatienceType == ImpatienceType.BALKING
204 line_error(mfilename, 'BALKING impatience type
is not yet supported. Use ImpatienceType.RENEGING.');
208 self.patience = distribution;
209 self.impatienceType = impatienceType;
211 self.obj.setPatience(impatienceType, distribution.obj);
215 function distribution = getPatience(self)
216 % DISTRIBUTION = GETPATIENCE()
218 % Returns
the global patience distribution for this job class.
221 % distribution - The patience distribution, or [] if not set
224 if ~isempty(self.patience)
225 distribution = self.patience;
230 distObj = self.obj.getPatience();
234 % Convert Java
object to MATLAB Distribution
235 distribution = Distribution.fromJavaObject(distObj);
240 function impatienceType = getImpatienceType(self)
241 % IMPATIENCETYPE = GETIMPATIENCETYPE()
243 % Returns
the global impatience type for this job class.
246 % impatienceType - The impatience type (ImpatienceType constant), or [] if not set
249 if ~isempty(self.impatienceType)
250 impatienceType = self.impatienceType;
255 impatienceTypeObj = self.obj.getImpatienceType();
256 if isempty(impatienceTypeObj)
259 impatienceType = ImpatienceType.fromId(impatienceTypeObj.getID());
264 function tf = hasPatience(self)
267 % Returns true if this class has a patience distribution set.
269 dist = self.getPatience();
270 tf = ~isempty(dist) && ~isa(dist, 'Disabled');
273 function self = setImmediateFeedback(self, value)
274 % SETIMMEDIATEFEEDBACK Set immediate feedback for self-loops
276 % SETIMMEDIATEFEEDBACK(true) enables immediate feedback for this class globally
277 % SETIMMEDIATEFEEDBACK(false) disables immediate feedback for this class
279 % When enabled, a job of this class that self-loops at any station stays
280 % in service instead of going back to
the queue.
283 self.immediateFeedback = logical(value);
285 self.obj.setImmediateFeedback(logical(value));
289 function tf = hasImmediateFeedback(self)
290 % HASIMMEDIATEFEEDBACK Check if immediate feedback
is enabled
292 % TF = HASIMMEDIATEFEEDBACK() returns true if immediate feedback
is enabled
295 tf = self.immediateFeedback;
297 tf = self.obj.hasImmediateFeedback();