Mercurial > hg > RemoteEditor > REPSessionManager
annotate rep/SessionManager.java @ 492:d2afd4efdd2d
remove unMergedCmds, use sentList instead.
author | one |
---|---|
date | Sat, 23 Oct 2010 16:15:14 +0900 |
parents | cc262a519b8a |
children | ebfa3b05a8dd |
rev | line source |
---|---|
266 | 1 |
0 | 2 package rep; |
3 | |
4 import java.io.IOException; | |
5 import java.net.InetSocketAddress; | |
267 | 6 import java.nio.channels.ClosedChannelException; |
412 | 7 import java.util.LinkedList; |
0 | 8 |
346 | 9 import org.xml.sax.SAXException; |
10 | |
198 | 11 |
353 | 12 |
337 | 13 import rep.channel.REPLogger; |
133 | 14 import rep.channel.REPSocketChannel; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
15 import rep.gui.CloseButtonEvent; |
412 | 16 import rep.gui.DoGUIUpdate; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
17 import rep.gui.SelectButtonEvent; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
18 import rep.gui.SessionManagerEvent; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
19 import rep.gui.SessionManagerEventListener; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
20 import rep.gui.SessionManagerGUI; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
21 import rep.gui.SessionManagerGUIimpl; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
22 import rep.handler.Editor; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
23 import rep.handler.REPNode; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
24 import rep.handler.FirstConnector; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
25 import rep.handler.Forwarder; |
56 | 26 import rep.xml.SessionXMLDecoder; |
45 | 27 import rep.xml.SessionXMLEncoder; |
264 | 28 |
198 | 29 /* |
264 | 30 +-------+--------+--------+-------+--------+---------+------+ |
31 | cmd | session| editor | seqid | lineno | textsiz | text | | |
32 | | id | id | | | | | | |
33 +-------+--------+--------+-------+--------+---------+------+ | |
34 o---------- header section (network order) ----------o | |
35 | |
36 int cmd; kind of command | |
37 int sid; session ID : uniqu to editing file | |
38 int eid; editor ID : owner editor ID = 1。Session に対して unique | |
308 | 39 -1 session manager command |
40 -2 merge command | |
264 | 41 int seqno; Sequence number : sequence number はエディタごとに管理 |
42 int lineno; line number | |
43 int textsize; textsize : bytesize | |
44 byte[] text; | |
198 | 45 */ |
1 | 46 |
384 | 47 public class SessionManager extends ServerMainLoop |
48 implements SessionManagerEventListener { | |
49 SessionList sessionList = new SessionList(); | |
363 | 50 // Known Session Manager List, At most one parent. No parent means master. |
384 | 51 SessionManagerList smList = new SessionManagerList(); |
363 | 52 // Known Editor list. Connected Editor has a channel. |
53 // Session Manager Channel may have dummy editors. | |
391 | 54 public EditorList editorList = new EditorList(); |
363 | 55 // Queue limit for debugging purpose. |
387 | 56 static final int packetLimit = 400; |
358 | 57 |
363 | 58 // globalSessionID = SessionManagerID * MAXID + localSessionID |
358 | 59 private static final int MAXID = 10000; |
353 | 60 SessionXMLDecoder decoder = new SessionXMLDecoder(); |
358 | 61 SessionXMLEncoder encoder = new SessionXMLEncoder(); |
363 | 62 // SocketChannel for our parent. At most one parent is allowed. |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
63 private REPNode sm_join_channel; |
363 | 64 // Routing table for session and session manager. |
369 | 65 private RoutingTable routingTable = new RoutingTable(this); |
386 | 66 // sync option |
67 public boolean sync = true; | |
412 | 68 // list olny local editor in GUI |
69 protected boolean listLocalEditorOnly = false; | |
70 | |
384 | 71 static public REPLogger logger = REPLogger.singleton(); |
72 | |
316 | 73 public static void main(String[] args) throws InterruptedException, IOException { |
384 | 74 int port =ServerMainLoop.DEFAULT_PORT; |
75 int port_s = ServerMainLoop.DEFAULT_PORT; | |
316 | 76 //System.setProperty("file.encoding", "UTF-8"); |
77 if(args.length > 0){ | |
363 | 78 if (args.length!=2) { |
79 logger.writeLog("Usage: sessionManager our_port parent_port"); | |
80 return; | |
81 } | |
316 | 82 port = Integer.parseInt(args[0]); |
83 port_s = Integer.parseInt(args[1]); | |
84 } | |
85 SessionManager sm = new SessionManager(); | |
336 | 86 sm.setReceivePort(port); |
87 sm.setParentPort(port_s); | |
363 | 88 // Ok start main loop |
316 | 89 sm.init(port,new SessionManagerGUIimpl(sm)); |
90 } | |
91 | |
280 | 92 public void init(int port, SessionManagerGUI gui) throws IOException, InterruptedException { |
384 | 93 mainLoop(this, port, gui); |
2 | 94 } |
95 | |
363 | 96 /* |
97 * After loop detection, we give up session manager join. | |
98 */ | |
99 private void cancel_sm_join() { | |
364 | 100 logger.writeLog("Loop detected "+this); |
384 | 101 removeChannel(this, sm_join_channel); |
355 | 102 sm_join_channel=null; |
103 } | |
104 | |
105 | |
106 /** | |
363 | 107 * GUI から、呼ばれて、Session Managerに接続する。 |
355 | 108 * Host 名のSession Manager に SM_JOIN する。自分は、Session を持っていては |
109 * ならない。複数のSession Managerにjoinすることは出来ない。(NATを実装するまでは)。 | |
110 * @param host | |
412 | 111 * @return error massage, return null when no errors. |
355 | 112 */ |
412 | 113 public String connectSessionManager(String host, int port) { |
114 if (sm_join_channel!=null) return "No Channel of sessionManager, Network Error."; | |
115 if (!sessionList.isEmpty()) return "Cannot connect with sessions."; | |
116 if (!smList.isMaster()) return "Already connected to the master."; | |
363 | 117 /* |
118 * IPv6 対応では、複数のアドレスを取って、それのすべてに接続を試す必要が | |
119 * ある。 | |
120 */ | |
1 | 121 InetSocketAddress addr = new InetSocketAddress(host, port); |
122 try { | |
186 | 123 REPSocketChannel<REPCommand> sessionchannel = REPSocketChannel.<REPCommand>create(new REPCommandPacker()); |
1 | 124 sessionchannel.connect(addr); |
337 | 125 while(!sessionchannel.finishConnect()); |
387 | 126 REPNode sm = new FirstConnector(this,sessionchannel); |
355 | 127 registerChannel(sessionchannel, sm); |
349 | 128 sm_join(sm); |
1 | 129 }catch (IOException e) { |
130 } | |
412 | 131 return null; |
1 | 132 } |
364 | 133 |
378 | 134 public void connectSessionManager(String host) { |
135 connectSessionManager(host,parent_port); | |
364 | 136 } |
77 | 137 |
363 | 138 /** |
139 * channel に SMCMD_SM_JOIN command を送る。 | |
140 * @param channel | |
141 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
142 private void sm_join(REPNode channel){ |
355 | 143 sm_join_channel = channel; |
122 | 144 //SM_JOINコマンドを生成。 |
77 | 145 REPCommand command = new REPCommand(); |
146 command.setCMD(REP.SMCMD_SM_JOIN); | |
349 | 147 command.setEID(-1); // request Parent SessionManagerID |
148 command.setSID(-1); // request SessionManagerID | |
79 | 149 |
122 | 150 //hostnameをセット。 |
349 | 151 setMyHostName(channel.getLocalHostName()); |
82 | 152 |
355 | 153 String string = myHost; |
77 | 154 command.setString(string); |
155 | |
122 | 156 //SM_JOINコマンドを送信。 |
349 | 157 channel.send(command); |
363 | 158 // ack を受け取ったら、SessionManagerのListに追加。ここではやらない。 |
77 | 159 } |
349 | 160 |
361 | 161 /* |
162 * Select Session from Manager button | |
163 * selected editor is joined editor directly connected to this session | |
164 * manager. | |
165 */ | |
316 | 166 public void selectSession(SelectButtonEvent event) throws IOException { |
250 | 167 int sid = event.getSID(); |
358 | 168 Session session = sessionList.get(sid); |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
169 if (session==null) throw new IOException(); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
170 REPNode editor = event.getEditor(); |
324 | 171 if (editor.hasSession()) return; |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
172 // assert(getSMID(editor.eid)==smList.sessionManagerID()); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
173 // assert(editor.channel!=null); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
174 editor.setSID(sid); // mark as selected |
372 | 175 selectSession0(sid, session, editor.getEID(), editor); |
176 } | |
177 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
178 private void selectSession0(int sid, Session session, int eid, REPNode editor) { |
389 | 179 logger.writeLog("Select sid="+sid+" and "+editor); |
372 | 180 if (editor.isDirect()&&editor.getEID()==eid) { |
386 | 181 REPCommand command = new REPCommand(); |
182 command.setSID(sid); | |
183 command.setEID(eid); | |
184 command.setString(session.getName()); | |
389 | 185 if(session.hasOwner()){ |
186 editor.selectSession(command,session); | |
187 }else { | |
188 forwardSelect(sid, session, eid, editor); | |
189 } | |
372 | 190 } else { |
191 // we don't have this editor, search the editor first. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
192 REPNode next = routingTable.toSessionManager(getSMID(eid)); |
372 | 193 // pass the select command to the next path. |
194 REPCommand command = new REPCommand(); | |
195 command.setCMD(REP.SMCMD_SELECT0); | |
196 command.setSID(sid); | |
197 command.setEID(eid); | |
198 command.setString(editor.getHost()); | |
199 next.send(command); | |
200 } | |
358 | 201 } |
202 | |
386 | 203 public void forwardSelect(int sid, Session session, int eid, |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
204 REPNode editor) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
205 REPNode next; |
372 | 206 // session searching continue... |
207 next = routingTable.toSessionManager(getSMID(sid)); | |
208 // make a forwarding channel here | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
209 REPNode f = createSessionForwarder(sid, next); |
372 | 210 session.setFirstForwarder(f); |
211 session.addForwarder(editor); | |
212 // pass the select command to the next path. | |
213 REPCommand command = new REPCommand(); | |
214 command.setCMD(REP.SMCMD_SELECT); | |
215 command.setSID(sid); | |
216 command.setEID(eid); | |
217 command.setString(editor.getHost()); | |
218 next.send(command); | |
219 } | |
220 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
221 private REPNode createSessionForwarder(int sid, REPNode editor) { |
387 | 222 REPNode f = new Forwarder(this,editor.channel); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
223 f.setEID(makeID(editorList.newEid())); |
387 | 224 // f.setChannel(editor.channel); // incoming channel |
372 | 225 f.setHost(myHost); |
226 f.setSID(sid); | |
227 return f; | |
228 } | |
229 | |
363 | 230 /* |
231 * Create and send UPDATE command. | |
232 */ | |
386 | 233 public void sendUpdate(int sid) { |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
234 REPCommand command = makeREPCommandWithSessionList(REP.SMCMD_UPDATE); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
235 command.setSID(sid); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
236 command.setEID(REP.SM_EID.id); |
386 | 237 if (isMaster()) { |
238 command.setCMD(REP.SMCMD_UPDATE_ACK); | |
239 smList.sendToSlaves(command); | |
240 } else { | |
241 smList.sendToMaster(command); | |
242 } | |
358 | 243 } |
244 | |
363 | 245 /* |
246 * Create new editor in this sessin manager. A dummy editor | |
247 * is created also. | |
248 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
249 public REPNode newEditor(REPSocketChannel<REPCommand> channel) { |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
250 int eid = makeID(editorList.newEid()); |
387 | 251 REPNode editor = new Editor(eid, this, channel); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
252 editorList.add(editor); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
253 return editor; |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
254 } |
363 | 255 |
256 /* | |
257 * Create new session. | |
258 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
259 public Session newSession(REPNode master) { |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
260 int sid= makeID(sessionList.newSessionID()); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
261 Session session = new Session(sid, master); |
360 | 262 sessionList.put(sid, session); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
263 return session; |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
264 } |
358 | 265 |
363 | 266 /* |
267 * GUI command interface for close session. | |
268 */ | |
259 | 269 public void closeSession(SessionManagerEvent event) { |
270 Session session = ((CloseButtonEvent) event).getSession(); | |
271 session.closeSession(); | |
272 sessionList.remove(session); | |
412 | 273 manager.updateGUI(this); |
259 | 274 } |
275 | |
363 | 276 /* |
277 * Remove editors which has the cannel. | |
278 */ | |
274 | 279 public void remove(REPSocketChannel<REPCommand> channel) { |
358 | 280 int i = 0; |
281 for(Session s:sessionList.values()) { | |
274 | 282 if (s.deleteEditor(channel)) { |
358 | 283 i++; |
274 | 284 } |
285 } | |
358 | 286 assert(i==1); |
274 | 287 // can be other session manager? what should I do? |
288 } | |
289 | |
317 | 290 |
318 | 291 public void remove(Editor editor) { |
358 | 292 Session s = sessionList.get(editor.getSID()); |
362 | 293 if (s==null) { |
294 assert(false); | |
295 editorList.remove(editor); | |
296 } else if (editor.isMaster()) { | |
358 | 297 removeSession(s); |
298 } else { | |
299 s.deleteForwarder(editor); | |
300 editorList.remove(editor); | |
318 | 301 } |
412 | 302 manager.updateGUI(this); |
341 | 303 } |
304 | |
305 private void removeSession(Session s0) { | |
358 | 306 s0.remove(this); |
341 | 307 sessionList.remove(s0); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
308 sendUpdate(s0.getSID()); |
318 | 309 } |
310 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
311 public boolean sessionManage(REPNode forwarder, REPCommand command) throws ClosedChannelException, |
358 | 312 IOException { |
355 | 313 switch(command.cmd){ |
353 | 314 |
315 // Session Manager Command | |
316 | |
317 case SMCMD_JOIN: | |
318 { | |
358 | 319 // first connection or forwarded command |
367 | 320 routingTable.add(forwarder,getSMID(command.eid)); |
358 | 321 if(isMaster()) { |
322 REPCommand ackCommand = new REPCommand(); | |
323 ackCommand.setCMD(REP.SMCMD_JOIN_ACK); | |
324 ackCommand.setEID(command.eid); | |
360 | 325 ackCommand.setSID(command.sid); |
358 | 326 ackCommand.string = command.string; |
327 smList.sendToSlaves(ackCommand); | |
328 registEditor(forwarder,ackCommand); | |
329 } else { | |
330 smList.sendToMaster(command); | |
331 } | |
412 | 332 manager.updateGUI(this); |
353 | 333 } |
334 | |
335 break; | |
336 | |
361 | 337 case SMCMD_PUT_ACK: |
366 | 338 if (forwarder.isDirect()) { |
339 // send put_ack to the editor now. | |
340 command.setCMD(REP.SMCMD_PUT_ACK); | |
341 command.string = command.string; | |
342 command.setEID(command.eid); | |
343 command.setSID(command.sid); | |
344 forwarder.send(command); | |
345 } | |
353 | 346 case SMCMD_JOIN_ACK: |
358 | 347 registEditor(forwarder,command); |
412 | 348 manager.updateGUI(this); |
353 | 349 break; |
350 | |
351 case SMCMD_PUT: | |
352 { | |
358 | 353 // first connection or forwarded command |
367 | 354 routingTable.add(forwarder,getSMID(command.eid)); |
370 | 355 REPCommand ack = new REPCommand(command); ack.setCMD(REP.SMCMD_PUT_ACK); |
356 if(isMaster()) { | |
371 | 357 // Reached to the top of the tree, multicast the ack. |
370 | 358 smList.sendToSlaves(ack); |
359 registEditor(forwarder,ack); | |
371 | 360 if (forwarder.isDirect()) { |
361 // If put editor on the master, no SMCMD_PUT_ACK is | |
362 // generated. Send ack to the editor now. | |
363 forwarder.send(ack); | |
364 } | |
358 | 365 } else { |
371 | 366 // Pass this to the master. |
358 | 367 smList.sendToMaster(command); |
361 | 368 // registEditor will be done by SMCMD_PUT_ACK |
369 } | |
412 | 370 manager.updateGUI(this); |
353 | 371 |
372 } | |
373 break; | |
358 | 374 |
372 | 375 case SMCMD_SELECT0: |
376 /* | |
377 * finding joining editor, do not make the path. | |
378 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
379 REPNode editor = editorList.get(command.eid); |
372 | 380 if (editor==null|| !editor.isDirect()) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
381 REPNode next = routingTable.toSessionManager(getSMID(command.eid)); |
372 | 382 next.send(command); |
383 break; | |
384 } | |
385 // we've found the editor, fall thru. | |
353 | 386 case SMCMD_SELECT: |
361 | 387 { |
372 | 388 /* |
389 * finding active session ring from joined editor. | |
390 */ | |
361 | 391 Session session = sessionList.get(command.sid); |
392 if (session==null) { | |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
393 session = new Session(command.sid, command.string,null); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
394 sessionList.put(command.sid,session); |
361 | 395 } |
372 | 396 // Do not directly addForwarder(forwarder). It may be |
397 // shared among sessions. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
398 REPNode f = createSessionForwarder(command.sid, forwarder); |
372 | 399 session.addForwarder(f); // f.next is set up here. |
389 | 400 if(session.hasOwner()){ |
401 forwarder.selectSession(command,session); | |
402 }else { | |
403 forwardSelect(command.sid, session, command.eid, forwarder); | |
404 } | |
361 | 405 } |
406 break; | |
353 | 407 case SMCMD_SELECT_ACK: |
408 { | |
369 | 409 // Sessionが見つかったので、select したeditorに教える。 |
358 | 410 Session session = sessionList.get(command.sid); |
376 | 411 searchSelectedEditor(command,session.getForwarder(forwarder.channel)); |
353 | 412 } |
358 | 413 break; |
414 | |
353 | 415 case SMCMD_SM_JOIN: |
416 { | |
355 | 417 // SM_JOIN中にSMCMD_SM_JOINが来たら、これはループなので、 |
418 ///自分のSM_JOINを取り消す。 | |
419 if (sm_join_channel!=null) cancel_sm_join(); | |
353 | 420 // SMCMD_SM_JOIN は、master まで上昇する。 |
421 // masterでなければ、自分のparentに転送する。 | |
355 | 422 if(isMaster()) { |
353 | 423 // master であれば、SessionManager IDを決めて、 |
424 // 自分のsmList に登録 | |
377 | 425 registSessionManager(forwarder, command); |
355 | 426 } else { |
427 if (forwarder.sid==-1) { | |
428 // direct link の場合は、識別のために、EIDに直上の | |
429 // smid を入れておく。 | |
430 command.setEID(smList.sessionManagerID()); | |
431 } | |
432 smList.sendToMaster(command); | |
353 | 433 } |
434 } | |
435 break; | |
386 | 436 |
437 case SMCMD_SYNC_ACK: | |
438 break; | |
439 | |
355 | 440 case SMCMD_SM_JOIN_ACK: |
441 send_sm_join_ack(command.eid, command.sid, command); | |
353 | 442 break; |
443 | |
444 case SMCMD_UPDATE: | |
386 | 445 sendUpdate(command.sid); |
446 break; | |
353 | 447 case SMCMD_UPDATE_ACK: |
358 | 448 command.setString(mergeUpdate(command)); |
449 // 下に知らせる | |
355 | 450 smList.sendToSlaves(command); |
412 | 451 manager.updateGUI(this); |
353 | 452 break; |
453 default: | |
454 return false; | |
455 } | |
456 return true; | |
457 } | |
458 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
459 private void registSessionManager(REPNode forwarder, REPCommand command) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
460 REPNode sm; |
377 | 461 int psid = command.eid; |
462 if (forwarder.sid!=-1) { | |
463 // すでに channelはSessionManager Idを持っていて、 | |
464 // direct link ではないので、 | |
465 // channel を持たないForwarderとして登録する | |
387 | 466 sm = new Forwarder(this,null); |
377 | 467 } else { |
468 sm = forwarder; | |
469 } | |
470 int sid = smList.addNewSessionManager(sm,command); | |
471 routingTable.add(forwarder,sid); | |
472 | |
473 REPCommand sendCommand = makeREPCommandWithSessionList(REP.SMCMD_SM_JOIN_ACK); | |
474 // command.eid==smList.sesionManagerID() の場合は、 | |
475 // 待っている自分の下のsessionManagerにsidをassignする必要がある。 | |
476 sendCommand.setSID(sid); // new Session manager ID | |
477 // 複数のSM_JOIN_ACKを識別するには、最初にSM_JOINを受け付けた | |
478 // Session manager IDを使う。 | |
479 sendCommand.setEID(psid); | |
480 send_sm_join_ack(psid, sid, sendCommand); | |
481 } | |
482 | |
483 | |
484 void send_sm_join_ack(int psid, int sid,REPCommand sendCommand) { | |
485 if (psid==smList.sessionManagerID()) { | |
486 // 直下のsessionManagerにIDを割り振る必要がある。 | |
487 smList.assignSessionManagerIDtoWaitingSM(sid); | |
488 // ここで smList に一つだけ追加されるので | |
489 // 待っている最初のsm一つにだけ、sm_join_ackが新たに送られる。 | |
490 } | |
491 smList.sendToSlaves(sendCommand); | |
492 } | |
493 | |
372 | 494 /* |
495 * 指定されたeditorがlocalにあるかどうかを調べる。なければ、他に送る。戻って何回も探すことが | |
496 * あり得るので、よろしくない。 | |
497 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
498 private void searchSelectedEditor(REPCommand command, REPNode editor) { |
372 | 499 for(;editor.isDirect();editor = editor.getNextForwarder()) { |
500 if (editor.getEID()==command.eid) { | |
501 // select したeditor を見つけた | |
389 | 502 editor.joinAck(command,command.sid); |
372 | 503 return; |
504 } | |
505 } | |
506 // ここにはありませんでした。 | |
507 editor.send(command); | |
508 } | |
509 | |
355 | 510 |
363 | 511 /** |
512 * UPDATE/UPDATE_ACKにより送られてきたSessionの情報を追加する | |
513 * @param command | |
514 * @return | |
515 * @throws IOException | |
516 */ | |
358 | 517 private String mergeUpdate(REPCommand command) throws IOException { |
518 SessionList receivedSessionList; | |
519 try { | |
520 receivedSessionList = decoder.decode(command.string); | |
521 } catch (SAXException e) { | |
522 throw new IOException(); | |
523 } | |
363 | 524 // 受け取った情報と自分の情報を混ぜる。 |
525 sessionList.merge(receivedSessionList); | |
358 | 526 //XMLを生成。送信コマンドにセット。 |
527 return encoder.sessionListToXML(sessionList); | |
528 | |
529 } | |
530 | |
531 /* | |
532 * id has SessionManager ID part | |
533 */ | |
534 private int makeID(int newid) { | |
535 return newid+smList.sessionManagerID()*MAXID; | |
536 } | |
537 | |
384 | 538 int getSMID(int id) { |
358 | 539 return id/MAXID; |
540 } | |
541 | |
542 | |
361 | 543 /** |
544 * Register Editor to our editorList. No connection is made. | |
545 * @param forwarder Editor to be add | |
546 * @param command | |
547 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
548 public void registEditor(REPNode forwarder,REPCommand command) { |
358 | 549 // make ack for PUT/JOIN. Do not send this to the editor, |
550 // before select. After select, ack is sent to the editor. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
551 REPNode editor; |
367 | 552 if (getSMID(command.eid)==smList.sessionManagerID()) { |
553 if (forwarder.isDirect()) { | |
554 editor = (Editor)forwarder; | |
555 } else | |
556 return; | |
358 | 557 } else { |
387 | 558 editor = new Editor(manager, command.eid); |
358 | 559 } |
560 editor.setName(command.string); | |
561 editor.setSID(command.sid); | |
562 if (!editorList.hasEid(command.eid)) { | |
563 editorList.add(editor); | |
564 } | |
367 | 565 if (command.cmd==REP.SMCMD_PUT_ACK) { |
566 Session session = new Session(command.sid, command.string, editor); | |
567 sessionList.put(command.sid, session); | |
568 } | |
358 | 569 // we don't join ack to the direct linked editor. We |
570 // have to wait select command | |
571 } | |
572 | |
573 | |
355 | 574 private REPCommand makeREPCommandWithSessionList(REP cmd) { |
575 //SessionListからXMLを生成。 | |
576 //joinしてきたSessionManagerに対してACKを送信。 | |
577 REPCommand sendCommand = new REPCommand(); | |
578 sendCommand.setCMD(cmd); | |
358 | 579 sendCommand.setString(encoder.sessionListToXML(sessionList)); |
355 | 580 return sendCommand; |
581 } | |
582 | |
583 | |
584 public boolean isMaster() { | |
585 return smList.isMaster(); | |
586 } | |
587 | |
588 | |
589 public void setSessionManagerID(int sid) { | |
590 smList.setSessionManagerID(sid); | |
591 } | |
592 | |
358 | 593 |
594 public Session getSession(int sid) { | |
595 return sessionList.get(sid); | |
596 } | |
597 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
598 public void setParent(REPNode fw) { |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
599 smList.setParent(fw); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
600 } |
367 | 601 |
602 public String toString() { | |
603 int myId = 0; | |
604 if (smList!=null) myId = smList.sessionManagerID(); | |
384 | 605 return "rep.SessionManager-"+myId+"@"+super.toString(); |
367 | 606 } |
385 | 607 |
608 public void addWaitingSessionManager(REPNode fw, REPCommand command) { | |
609 smList.addWaitingSessionManager(fw, command); | |
610 } | |
389 | 611 |
391 | 612 public int getId() { |
613 return smList.sessionManagerID(); | |
614 } | |
615 | |
399 | 616 public void checkWaitingCommandInMerge() { |
617 for(REPNode e:editorList.values()) { | |
618 e.checkWaitingCommandInMerge(); | |
619 } | |
620 | |
621 } | |
622 | |
412 | 623 /** |
624 * Notify status change to our GUI | |
625 */ | |
626 protected void updateGUI(ServerMainLoop serverMainLoop) { | |
627 //リストのコピーをGUIに渡す | |
628 LinkedList<Session> sList = new LinkedList<Session>(sessionList.values()); | |
629 LinkedList<REPNode> eList; | |
630 if (listLocalEditorOnly ) { | |
631 // Do not list an editor or session outside of this session manager to | |
632 // avoid confusion. Actually we can joinSession to an editor outside of | |
633 // this manager, but is not secure to do this. | |
634 eList = new LinkedList<REPNode>(); | |
635 for(REPNode e:editorList.values()) { | |
636 if (getSMID(e.eid)==smList.sessionManagerID()) { | |
637 eList.add(e); | |
638 } | |
639 } | |
640 } else { | |
641 eList = new LinkedList<REPNode>(editorList.values()); | |
642 } | |
643 //GUIに反映 | |
644 Runnable doRun = new DoGUIUpdate(sList, eList, serverMainLoop.gui); | |
645 serverMainLoop.gui.invokeLater(doRun); | |
646 } | |
647 | |
485 | 648 @Override |
649 public void deadlockDetected() throws IOException { | |
650 logger.writeLog("Deadlock detected"); | |
651 for(REPNode e:editorList.values()) { | |
652 logger.writeLog(" "+e+"\n"+e.report()); | |
653 } | |
654 throw new IOException(); | |
655 } | |
458
c22f6833d736
synchronize Editor's waiting queue and Manager's writing queue
one
parents:
412
diff
changeset
|
656 |
0 | 657 } |