-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathtrainsTutorial.html
More file actions
279 lines (204 loc) · 19.6 KB
/
trainsTutorial.html
File metadata and controls
279 lines (204 loc) · 19.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
<html>
<head>
<title>Trains algorithm middleware interface tutorial</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="trainsTutorial.css"/>
</head>
<body id="top">
<h1>Trains algorithm middleware interface tutorial</h1>
<h2>Table of contents</h2>
<ol>
<li><a href="#addr_file">Managing the addr_file</a></li>
<li><a href="#initialization">Initialization</a></li>
<li><a href="#sendMessage">Sending messages</a></li>
<li><a href="#oDeliver">Receiving messages</a></li>
<li><a href="#circuitChange">Using the CallbackCircuitChange</a></li>
</ol>
<hr/>
<h2 id="introduction">Introduction</h2>
<p>This tutorial explains how an application can use the interface of the trains (algorithm) middleware. Using the interface, the application will take advantage of the broadcast ordering capabilities of the middleware. The order ensured can be causal order, total order, or uniform total order, depending on one of the parameter given to the middleware initialization function.</p>
<h2 id="addr_file">Managing the addr_file</h2>
<p> A file named <b>addr_file</b> must be located in the same directory than your binary. This file is used by the middleware to record the potential participants.</p>
<p>To add one participant, you should respect the <b>rank:hostname:port</b> syntax on each line of <b>addr_file</b>. The rank is a number between 0 and 15. Each rank must be unique, and each hostname:port pair should be unique too. Thus, the middleware cannot handle more than 16 participants.</p>
<p>You can add comments beginning the line with '#'. Empty lines are allowed too.</p>
<p>Before launching the application, be sure that the <b>TRAINS_PORT</b> environment variable has been set to the value you want to use as your port in the addr_file (e. g. with <tt>export TRAINS_PORT=1234</tt>, as in the examples below).</p>
<p>Here are some examples of addr_file :</p>
<pre class="codeblock">
<span class="title_ex">Example 1: comments on separate lines</span>
# Me
0:myHostname:1234
# MyFriend
1:hisHostname:4321
# Another Friend
2:herHostname.company.eu:3421
</pre>
<pre class="codeblock">
<span class="title_ex">Example 2: comments at the end of lines</span>
0:myHostname:1234 #Me
1:hisHostname:4321 #MyFriend
2:herHostname.company.eu:3421 #My Other Friend
</pre>
Note that you can just write "localhost" for the participant on your machine. It will be replaced by your complete hostname at execution.
<pre class="codeblock">
<span class="title_ex">Example 3: using localhost</span>
0:localhost:1234 #Me
1:aHostname:9876 #The other guy
</pre>
<h2 id="initialization">Initialization</h2>
<p>You should include <tt>"trains.h"</tt> when using the Trains middleware.</p>
<p>Before using the Trains middleware, you must call the <b>trInit</b> function with a number of arguments to initialize the middleware.</p>
<pre class="codeblock">
<span class="title_ex">trInit prototype :</span>
<span class="type">int</span> <span class="function">trInit</span><span class="operator">(</span>
<span class="type">int</span> trainsNumber<span class="operator">,</span> <span class="comment">/* The number of trains on the circuit (default 1) */</span>
<span class="type">int</span> wagonLength<span class="operator">,</span> <span class="comment">/* The wagons length during the execution (default 32KB) */</span>
<span class="type">int</span> waitNb<span class="operator">,</span> <span class="comment">/* The max number of waits (default 10) */</span>
<span class="type">int</span> waitTime<span class="operator">,</span> <span class="comment">/* The default time to wait, in microsec (default 2) */</span>
<span class="typedef">CallbackCircuitChange</span> callbackCircuitChange<span class="operator">,</span> <span class="comment">/* The function to call when the circuit change */</span>
<span class="typedef">CallbackODeliver</span> callbackODeliver, <span class="comment">/* The function to call upon receiving a message */</span>
<span class="operator"></span> <span class="typedef">t_reqOrder</span> reqOrder <span class="comment">/* Required order from the middleware. Can be <b>CAUSAL_ORDER</b> (0), <b>TOTAL_ORDER</b> (1) or <b>UNIFORM_TOTAL_ORDER</b> (2) */</span>
<span class="operator">);</span>
</pre>
<p>You can call <b>trInit</b> with some arguments to 0 if you want to let the corresponding arguments to default values.</p>
<pre class="codeblock">
<span class="title_ex">Example : initialization with 6 trains and 16KB wagons, with default waitNb and waitTime.</span>
<span class="preprocessor">#include</span> <span class="header">"trains.h"</span>
<span class="type">void</span> <span class="function">myCallbackCircuitChange</span><span class="operator">(</span><span class="typedef">circuitView</span><span class="operator"> *</span>cp<span class="operator">){</span>
<span class="comment">/* Your function to call when the circuit changes */</span><span class="operator">
}</span>
<span class="type">void</span> <span class="function">myCallbackODeliver</span><span class="operator">(</span><span class="typedef">address</span> sender<span class="operator">,</span> <span class="typedef">t_typ</span> messageTyp<span class="operator">,</span> <span class="typedef">message</span><span class="operator"> *</span>mp<span class="operator">){</span>
<span class="comment">/* Your function to call upon receiving a message */</span>
<span class="operator">}</span>
<span class="type">int</span><span class="function"> main</span><span class="operator"> (</span><span class="type">int</span> argc<span class="operator">,</span><span class="type"> char</span><span class="operator"> **</span> argv<span class="operator">){</span>
<span class="type">int</span> rc<span class="operator">;</span>
rc = trInit<span class="operator">(</span>6, <span class="comment">/* 6 trains */</span><span class="operator">,</span>
16384, <span class="comment">/* Size of wagons : 16KB */</span><span class="operator">,</span>
0, <span class="comment">/* Let waitNb at its default value (10) */</span><span class="operator">,</span>
0, <span class="comment">/* Let waitTime at its default value (2 microsec) */</span><span class="operator">,</span>
myCallbackCircuitChange, <span class="comment">/* Each time the circuit changes, myCallbackCircuitChange will be called */</span><span class="operator">,</span>
myCallbackODeliver, <span class="comment">/* Upon delivering a message, myCallbackODeliver will be called */</span><span class="operator"></span>
UNIFORM_TOTAL_ORDER <span class="comment">/* Messages will be delivered with uniform total order guarantees */</span><span class="operator">);</span>
<span class="flow">if</span><span class="operator"> (</span>rc<span class="operator"> <</span> 0<span class="operator">) {</span>
trError_at_line<span class="operator">(</span>rc<span class="operator">,</span> trErrno<span class="operator">,</span> __FILE__<span class="operator">,</span> __LINE__<span class="operator">,</span><span class="string"> "An error occurred in trInit\n"</span><span class="operator">);</span>
<span class="external">exit</span><span class="operator">(</span>EXIT_FAILURE<span class="operator">);
}</span>
...
...
...
<span class="operator">}</span>
</pre>
<h2 id="sendMessage">Sending messages</h2>
<p>Sending a message in the Trains middleware requires 4 steps :
<ol>
<li>Define type of messages which can be broadcast. First type of message takes value <b>FIRST_VALUE_AVAILABLE_FOR_MESS_TYP</b>. Second type of message takes value <b>(FIRST_VALUE_AVAILABLE_FOR_MESS_TYP + 1)</b>. Etc. In this manner, you can define as much as 250 different type of messages.
<li>Messages in the Trains middleware are created with <b>newmsg()</b>, where the size of the message must be specified.</li>
<li>Then, fill the message with whatever payload you need, respecting the maximum size of the message given in newmsg() (see details below).</li>
<li>The message can now be sent using the <b>oBroadcast()</b> function.</li>
</ol>
<pre class="codeblock">
<span class="title_ex">Message structure detail</span>
<span class="keyword">typedef struct</span> message<span class="operator">{</span>
<span class="typedef">messageHeader</span> <span class="field">header</span><span class="operator">;</span><span class="comment"> /* <b>RESERVED FOR INTERNAL USE</b> */</span>
<span class="type">char</span> <span class="field">payload</span><span class="operator">[];</span><span class="comment"> /* Payload (i.e. contents) of the message */</span><span class="operator">
}</span> <span class="keyword">__attribute__</span><span class="operator">((</span>packed<span class="operator">))</span> <span class="typedef">message</span><span class="operator">;</span>
</pre>
<p>The message payload is an array of char. Just cast it into whatever type or structure you need.</p>
<pre class="codeblock">
<span class="title_ex">Defining type of messages which are broadcast</span>
<span class="comment">/* Type of messages broadcast */</span>
<span class="preprocessor">
#define MESSAGE_TYPE_1 (FIRST_VALUE_AVAILABLE_FOR_MESS_TYP + 0)
#define MESSAGE_TYPE_2 (FIRST_VALUE_AVAILABLE_FOR_MESS_TYP + 1)
#define MESSAGE_TYPE_3 (FIRST_VALUE_AVAILABLE_FOR_MESS_TYP + 2)
...
...
...
</span>
</pre>
<pre class="codeblock">
<span class="title_ex">Sending a message with a simple payload (an int, here 7)</span>
<span class="type">int</span> rc<span class="operator">;</span>
<span class="type">int</span> myPayload <span class="operator">=</span><span class="int"> 7</span><span class="operator">;</span>
<span class="typedef">message</span><span class="operator"> *</span>mp<span class="operator"> =</span> NULL<span class="operator">;</span>
<span class="comment">/* Creating the message */</span>
mp<span class="operator"> =</span> newmsg<span class="operator">(</span><span class="keyword">sizeof</span><span class="operator">(</span>myPayload<span class="operator">)</span><span class="operator">);</span>
<span class="flow">if</span><span class="operator"> (</span>mp<span class="operator"> ==</span> NULL<span class="operator"> ) {</span>
trError_at_line<span class="operator">(</span>rc<span class="operator">,</span> trErrno<span class="operator">,</span> __FILE__<span class="operator">,</span> __LINE__<span class="operator">,</span><span class="string"> "An error occurred in newmsg()"</span><span class="operator">);</span>
<span class="external">exit</span><span class="operator">(</span>EXIT_FAILURE<span class="operator">);
}</span>
<span class="comment">/* Filling the message */</span>
<span class="operator">*((</span><span class="type">int</span><span class="operator">*) (</span>mp-><span class="field">payload</span><span class="operator">))</span> <span class="operator">=</span> myPayload<span class="operator">;</span>
<span class="comment">/* Sending the message */</span>
<span class="flow">if</span><span class="operator"> ( (</span>rc<span class="operator"> =</span> oBroadcast<span class="operator">(</span>MESSAGE_TYPE_2, mp<span class="operator">)) <</span> <span class="int">0</span><span class="operator">) {</span>
trError_at_line<span class="operator">(</span>rc<span class="operator">,</span> trErrno<span class="operator">,</span> __FILE__<span class="operator">,</span> __LINE__<span class="operator">,</span><span class="string"> "An error occurred in oBroadcast()"</span><span class="operator">);</span>
<span class="external">exit</span><span class="operator">(</span>EXIT_FAILURE<span class="operator">);
}</span>
...
...
...
</pre>
NB : To fill your messages properly (i. e. to cast the data the right way), you can either do it manually whenever you have to. To do so, make your own function (e. g. a function that creates the message and do the cast for you). Or you can use other technics like <a href="http://www.json.org/">JSON</a>.
<h2 id="oDeliver">Receiving messages</h2>
<p>Upon receiving a message, the trains middleware automatically calls the function previously specified as callbackODeliver parameter in <b>trInit()</b>.</p>
<p>To access a message content, use the <tt>payload</tt> field of the message. Following the <a href="#sendMessage">Sending messages section</a> example, if the payload is an int, you can access it by casting the payload into an <tt>int</tt>.</p>
<pre class="codeblock">
<span class="title_ex">Example : printing the message sender and the content upon receiving a message</span>
<span class="type">void</span> <span class="function">myCallbackODeliver</span><span class="operator">(</span><span class="typedef">address</span> sender<span class="operator">, <span class="typedef">t_typ</span> messageTyp<span class="operator">,</span> <span class="typedef">message</span><span class="operator"> *</span>mp<span class="operator">){</span>
<span class="type">int</span> theContent <span class="operator">=</span> <span class="operator">*((</span><span class="type">int</span><span class="operator">*) (</span>mp-><span class="field">payload</span><span class="operator">));</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"I received a message from %s\n"</span><span class="operator">,</span> addrToHostname<span class="operator">(</span>sender<span class="operator">));</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"The content size is : %d\n"</span><span class="operator">,</span> payloadSize(mp)<span class="operator">);</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"The message type is : %u\n"</span><span class="operator">,</span> messageTyp<span class="operator">);</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"The content is : %d\n"</span><span class="operator">,</span> theContent<span class="operator">);</span>
<span class="comment">/* Any other treatment */</span>
<span class="operator">}</span>
</pre>
<p><b>NB : Be sure to initialize trInit with this function !</b></p>
<h2 id="circuitChange">Using the CallbackCircuitChange</h2>
Whenever the trains middleware detects a participant arrival or departure in the trains algorithm, the function set in trInit as the callbackCircuitChange is called with a circuitView* argument. A circuitView is a structure providing the circuit state.
<pre class="codeblock">
<span class="title_ex">circuitView structure detail</span>
<span class="keyword">typedef struct</span> <span class="operator">{</span>
<span class="type">short</span> <span class="field">cv_nmemb</span><span class="operator">;</span> <span class="comment">/* Number of members */</span>
<span class="typedef">address</span> <span class="field">cv_members</span><span class="operator">[</span>MAX_MEMB<span class="operator">]</span><span class="operator">;</span> <span class="comment">/* List of members */</span>
<span class="typedef">address</span> <span class="field">cv_joined</span><span class="operator">;</span> <span class="comment">/* New member, if any */</span>
<span class="typedef">address</span> <span class="field">cv_departed</span><span class="operator">;</span> <span class="comment">/* Departed member, if any */</span>
<span class="operator">}</span> <span class="typedef">circuitView</span><span class="operator">;</span>
</pre>
<ul>
<li><tt>cv_nmemb</tt> is the number of participants when the function is called.</li>
<li><tt>cv_members</tt> is an array whose cells contains the addresses of the participants.</li>
<li><tt>cv_joined</tt> is the address of the participant that just joined the algorithm. If callbackCircuitChange was called because of a departure, it contains a null address.</li>
<li><tt>cv_departed</tt> is the address of the participant that just left the algorithm. If callbackCircuitChange was called because of an arrival, it contains a null address.</li>
</ul>
<b><u>Example</u> :</b><br/>The addr_file contains 16 participants (rank 0 to 15), the rank 5 participant is connected and rank 8 joins. The trains middleware detects this arrival and calls the callbackCircuitChange.<br/>
<ul>
<li><tt>cv_nmemb</tt> = 2.</li>
<li><tt>cv_members[0]</tt> contains the address of the rank 5 participant.</li>
<li><tt>cv_members[1]</tt> contains the address of the rank 8 participant.</li>
<li>The other cells are empty.</li>
<li><tt>cv_joined</tt> contains the address of the rank 8 participant.</li>
<li><tt>cv_departed</tt> contains a null address.</li>
</ul>
<p>The following example shows how to print the circuit modifications whenever a participant either joins or leaves the circuit.</p>
<pre class="codeblock">
<span class="title_ex">Example : printing the circuit modifications</span>
<span class="type">void</span> <span class="function">myCallbackCircuitChange</span><span class="operator">(</span><span class="typedef">circuitView</span> <span class="operator">*</span>cv<span class="operator">){</span>
<span class="comment">/* Printing the new/departed participant */</span>
<span class="flow">if</span> <span class="operator">(!</span>addrIsNull<span class="operator">(</span>cp<span class="operator">-></span>cv_joined<span class="operator">)) {</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"%s has arrived\n"</span><span class="operator">,</span> addrToHostname<span class="operator">(</span>cp<span class="operator">-></span><span class="field">cv_joined</span><span class="operator">));
}</span> <span class="flow">else</span> <span class="operator">{</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"%s is gone\n"</span><span class="operator">,</span> addrToHostname<span class="operator">(</span>cp<span class="operator">-></span><span class="field">cv_departed</span><span class="operator">));
}</span>
<span class="comment">/* Printing the current number of members */</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"Currently %hd members in the circuit\n"</span><span class="operator">,</span> cp<span class="operator">-></span><span class="field">cv_nmemb</span><span class="operator">));</span>
<span class="comment">/* Printing your rank among the participants */</span>
<span class="type">int</span> myRank<span class="operator">;</span>
<span class="flow">for</span><span class="operator"> (</span>rank<span class="operator"> =</span><span class="int"> 0</span><span class="operator">; !</span>addrIsMine<span class="operator">(</span>cv<span class="operator">-></span><span class="field">cv_members</span><span class="operator">[</span>rank<span class="operator">]);</span> rank<span class="operator">++);</span>
<span class="external">printf</span><span class="operator">(</span><span class="string">"My rank is %d\n"</span><span class="operator">,</span> myRank<span class="operator">);</span>
<span class="comment">/* Any other treatment */</span>
<span class="operator">}</span>
</pre>
<p><b>NB :</b> Your rank among the participants may change whenever callbackCircuitChange is called.</p>
<a href="#top">Return to top</a>
</body>
</html>