1
|
1 package rep;
|
|
2
|
358
|
3 import java.io.IOException;
|
122
|
4 import java.util.LinkedList;
|
142
|
5 import java.util.List;
|
349
|
6
|
|
7 import rep.channel.REPSelectionKey;
|
131
|
8 import rep.channel.REPSocketChannel;
|
317
|
9 import rep.handler.PacketSet;
|
224
|
10 import rep.optimizers.*;
|
325
|
11 import rep.translator.Translator;
|
324
|
12 import rep.translator.TranslatorImpl;
|
131
|
13
|
316
|
14 public class Editor extends Forwarder {
|
|
15
|
325
|
16 private Translator translator;
|
316
|
17 private List<REPCommand> sentList = new LinkedList<REPCommand>();
|
315
|
18 // REPCommands we are going to send to the next editor
|
317
|
19 //private REPCommand quit2 = null;
|
|
20 private SessionManager manager;
|
318
|
21 private REPCommand quit2=null;
|
316
|
22
|
317
|
23 public Editor(SessionManager manager,boolean doOptimize,int editorNo){
|
|
24 super(manager);
|
|
25 this.manager = manager;
|
316
|
26 eid = editorNo;
|
326
|
27 REPCommandOptimizer optimizer;
|
224
|
28 if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ
|
|
29 else optimizer = new NullOptimizer(); //なにもしないけどOptimizer.
|
326
|
30 translator = new TranslatorImpl(eid,optimizer);
|
224
|
31
|
155
|
32 }
|
1
|
33
|
317
|
34 public Editor(SessionManager manager,int editorNo, REPSocketChannel<REPCommand> channel){
|
|
35 this(manager,false,editorNo);
|
319
|
36 this.channel = channel;
|
56
|
37 }
|
317
|
38
|
328
|
39 public void translate(REPCommand command){
|
349
|
40
|
|
41 if(command.eid == eid){
|
325
|
42 //エディタからの新たな編集コマンド
|
364
|
43 if (next==this) return; // singleton case
|
327
|
44 translator.transSendCmd(command);
|
|
45 sentList.add(new REPCommand(command));
|
325
|
46 assert(sentList.size()<limit);
|
328
|
47 next.send(command);
|
325
|
48 return;
|
366
|
49 } else if(command.eid == REP.MERGE_EID.id){
|
179
|
50 //マージコマンドが返ってきた
|
324
|
51 if(translator.checkMergeConflict(command)){
|
179
|
52 //マージ中にエディタからの割り込みがあった場合
|
326
|
53 translator.getMergeAgain(this);
|
|
54 }
|
373
|
55 checkEndMerge();
|
366
|
56 } else if(command.eid == next.getEID()){
|
349
|
57 // 次のEditorで一周するコマンドが来た
|
|
58 if(next==this) return; // singleton case
|
373
|
59 // これは、distributed case では、うまくいかないので、送り先のforwarder で処理する。
|
|
60 if (next.isDirect())
|
|
61 ((Editor) next).checkReturnedCommand(command);
|
|
62 else
|
|
63 next.send(command);
|
349
|
64 } else {
|
152
|
65 //他のエディタからの編集コマンド
|
349
|
66 assert (command.eid!=REP.MERGE_EID.id && command.eid!=eid );
|
|
67 if (manager.hasWaitingCommand(channel)) {
|
|
68 // We cannot do this operation before watingCommandQueue.
|
|
69 manager.addWaitingCommand(new PacketSet(channel, this, command));
|
|
70 return;
|
|
71 }
|
317
|
72 if(!isMerging()) {
|
328
|
73 translator.transReceiveCmd(next,command);
|
317
|
74 return;
|
|
75 }
|
328
|
76 manager.addWaitingCommand(new PacketSet(getChannel(), this, new REPCommand(command)));
|
142
|
77 }
|
317
|
78 return;
|
142
|
79 }
|
325
|
80
|
323
|
81 boolean merge(REPCommand command) {
|
313
|
82 //マージして送信
|
324
|
83 return translator.catchOwnCommand(this);
|
142
|
84 }
|
56
|
85
|
325
|
86 void checkReturnedCommand(REPCommand command) {
|
326
|
87 REPCommand prev = sentList.remove(0);
|
327
|
88 if (prev==null || prev.seq != command.seq || prev.eid!=command.eid) {
|
326
|
89 String err = "Editor.checkReturnedCommand() : command = " + command + " prev=";
|
|
90 err += prev==null?"null":prev.toString();
|
337
|
91 SessionManager.logger.writeLog(err);
|
326
|
92 assert(false);
|
142
|
93 }
|
326
|
94
|
325
|
95 // START_MERGE を送る
|
373
|
96 // 送らないで良い場合もある?
|
325
|
97 REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
|
|
98 send(cmd);
|
|
99 // Session Manager 側で、このeditorへの他のeditorからの
|
|
100 // 入力を止めて、merge にそなえる。merge は、eidtor 側から
|
|
101 // ACKが来てから始まる。
|
|
102 translator.startMerge(cmd);
|
|
103 return;
|
74
|
104 }
|
|
105
|
319
|
106 @Override
|
300
|
107 public void setQuit2(REPCommand cmd) {
|
327
|
108 quit2 = cmd;
|
|
109 checkQuit();
|
318
|
110 // do not send quit2 until we received all pending
|
|
111 // command
|
300
|
112 }
|
23
|
113
|
316
|
114 @Override
|
23
|
115 public void setEID(int eid) {
|
|
116 this.eid = eid;
|
324
|
117 translator.setEid(eid);
|
23
|
118 }
|
316
|
119
|
24
|
120 public String toString(){
|
304
|
121 return ("Editor eid="+eid+" sid="+sid+" " + host + ":" + file);
|
24
|
122 }
|
23
|
123
|
164
|
124 public boolean isMerging() {
|
324
|
125 return translator.isMerging();
|
164
|
126 }
|
324
|
127
|
315
|
128
|
164
|
129
|
373
|
130 void checkEndMerge() {
|
324
|
131 if(translator.isMerging()) return;
|
317
|
132 REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
|
326
|
133 send(mergeEnd);
|
|
134 if (quit2!=null) checkQuit();
|
|
135 }
|
|
136
|
|
137 private boolean checkQuit() {
|
|
138 if (sentList.size()==0&&!isMerging()) {
|
|
139 send(quit2);
|
327
|
140 quit2 = null;
|
326
|
141 return true;
|
|
142 }
|
|
143 return false;
|
317
|
144 }
|
|
145
|
319
|
146 @Override
|
|
147 public boolean manage(REPCommand receivedCommand) {
|
330
|
148
|
|
149
|
319
|
150 switch(receivedCommand.cmd){
|
|
151 // Editor Command
|
|
152
|
|
153 case REPCMD_DELETE:
|
|
154 case REPCMD_INSERT:
|
|
155 case REPCMD_NOP:
|
|
156 {
|
328
|
157 translate(receivedCommand);
|
319
|
158 break;
|
|
159 }
|
323
|
160
|
|
161 case SMCMD_START_MERGE_ACK:
|
|
162 {
|
|
163 // マージの処理と次のエディタへコマンドを送信する処理
|
324
|
164 translator.mergeAck();
|
323
|
165 if (!merge(receivedCommand)) {
|
|
166 // nothing to do, send END_MERGE
|
373
|
167 checkEndMerge();
|
323
|
168 }
|
|
169 break;
|
|
170 }
|
319
|
171 case SMCMD_QUIT:
|
|
172 {
|
|
173 next.send(receivedCommand);
|
|
174 break;
|
|
175 }
|
|
176 case SMCMD_QUIT_2:
|
|
177 {
|
328
|
178 // QUIT_2 is returned.
|
341
|
179 if (receivedCommand.eid!=eid) {
|
|
180 // stop this editor unless this is the start, starter will stopped
|
|
181 // by QUIT_2_ACK
|
|
182 manager.remove(this);
|
|
183 }
|
|
184 // don't send quit_2 directly to the editor until all pending
|
319
|
185 // merge is processed.
|
373
|
186 // this does not work in distributed case.
|
|
187 if (next.isDirect())
|
|
188 next.setQuit2(receivedCommand);
|
|
189 else
|
|
190 next.send(receivedCommand);
|
341
|
191 break;
|
|
192 }
|
|
193 case SMCMD_QUIT_2_ACK:
|
|
194 {
|
|
195 manager.remove(this);
|
319
|
196 break;
|
|
197 }
|
|
198 default:
|
|
199 return false;
|
|
200 }
|
|
201 return true;
|
|
202 }
|
|
203
|
349
|
204
|
|
205 @Override
|
358
|
206 public void handle(REPSelectionKey<REPCommand> key) throws IOException {
|
349
|
207 REPSocketChannel<REPCommand> channel = key.channel1();
|
|
208 REPCommand command = channel.read();
|
|
209 SessionManager.logger.writeLog("REPHandlerImpl.handle() read : command = " + command +" from "+channel);
|
353
|
210 if (manager.sessionManage(this, command)) return;
|
349
|
211 manage(command);
|
|
212 }
|
|
213
|
|
214 @Override
|
|
215 public void cancel(REPSocketChannel<REPCommand> socketChannel) {
|
|
216 manager.remove(socketChannel);
|
|
217 }
|
358
|
218
|
|
219 public boolean isMaster() {
|
|
220 return mode==REP.SMCMD_PUT;
|
|
221 }
|
378
|
222
|
|
223 /* Handle special case first, usually these cases
|
|
224 * are handled in the next Editor in a session manager, but
|
|
225 * it is forwarded here.
|
|
226 */
|
|
227 public void forwardedCommandManage(REPCommand command, Forwarder forwarder) {
|
|
228 if (command.cmd==REP.SMCMD_QUIT_2) {
|
|
229 // we have to wait next editor's finishing before sending this.
|
|
230 // this is odd, but the editor itself does not know it's merging
|
|
231 // state. Only this session manager knows it.
|
|
232 setQuit2(command);
|
|
233 } else if (command.eid==eid) {
|
|
234 // if we handle in editor.manage(), this editor cannot distinguish this
|
|
235 // and user input command from the editor.
|
|
236 switch(command.cmd) {
|
|
237 case REPCMD_DELETE:
|
|
238 case REPCMD_INSERT:
|
|
239 case REPCMD_NOP:
|
|
240 checkReturnedCommand(command);
|
|
241 return;
|
|
242 }
|
|
243 }
|
379
|
244 send(command);
|
378
|
245 }
|
1
|
246 }
|