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;
|
315
|
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 }
|
|
55 endMerge();
|
349
|
56 }else if(command.eid == next.getEID()){
|
|
57 // 次のEditorで一周するコマンドが来た
|
|
58 if(next==this) return; // singleton case
|
|
59 ((Editor) next).checkReturnedCommand(command);
|
|
60 } else {
|
152
|
61 //他のエディタからの編集コマンド
|
349
|
62 assert (command.eid!=REP.MERGE_EID.id && command.eid!=eid );
|
|
63 if (manager.hasWaitingCommand(channel)) {
|
|
64 // We cannot do this operation before watingCommandQueue.
|
|
65 manager.addWaitingCommand(new PacketSet(channel, this, command));
|
|
66 return;
|
|
67 }
|
317
|
68 if(!isMerging()) {
|
328
|
69 translator.transReceiveCmd(next,command);
|
317
|
70 return;
|
|
71 }
|
328
|
72 manager.addWaitingCommand(new PacketSet(getChannel(), this, new REPCommand(command)));
|
142
|
73 }
|
317
|
74 return;
|
142
|
75 }
|
325
|
76
|
323
|
77 boolean merge(REPCommand command) {
|
313
|
78 //マージして送信
|
324
|
79 return translator.catchOwnCommand(this);
|
142
|
80 }
|
56
|
81
|
325
|
82 void checkReturnedCommand(REPCommand command) {
|
326
|
83 REPCommand prev = sentList.remove(0);
|
327
|
84 if (prev==null || prev.seq != command.seq || prev.eid!=command.eid) {
|
326
|
85 String err = "Editor.checkReturnedCommand() : command = " + command + " prev=";
|
|
86 err += prev==null?"null":prev.toString();
|
337
|
87 SessionManager.logger.writeLog(err);
|
326
|
88 assert(false);
|
142
|
89 }
|
326
|
90
|
325
|
91 // START_MERGE を送る
|
|
92 REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
|
|
93 send(cmd);
|
|
94 // Session Manager 側で、このeditorへの他のeditorからの
|
|
95 // 入力を止めて、merge にそなえる。merge は、eidtor 側から
|
|
96 // ACKが来てから始まる。
|
|
97 translator.startMerge(cmd);
|
|
98 return;
|
74
|
99 }
|
|
100
|
319
|
101 @Override
|
300
|
102 public void setQuit2(REPCommand cmd) {
|
327
|
103 quit2 = cmd;
|
|
104 checkQuit();
|
318
|
105 // do not send quit2 until we received all pending
|
|
106 // command
|
300
|
107 }
|
23
|
108
|
316
|
109 @Override
|
23
|
110 public void setEID(int eid) {
|
|
111 this.eid = eid;
|
324
|
112 translator.setEid(eid);
|
23
|
113 }
|
316
|
114
|
24
|
115 public String toString(){
|
304
|
116 return ("Editor eid="+eid+" sid="+sid+" " + host + ":" + file);
|
24
|
117 }
|
23
|
118
|
164
|
119 public boolean isMerging() {
|
324
|
120 return translator.isMerging();
|
164
|
121 }
|
324
|
122
|
315
|
123
|
164
|
124
|
317
|
125 void endMerge() {
|
324
|
126 if(translator.isMerging()) return;
|
317
|
127 REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
|
326
|
128 send(mergeEnd);
|
|
129 if (quit2!=null) checkQuit();
|
|
130 }
|
|
131
|
|
132 private boolean checkQuit() {
|
|
133 if (sentList.size()==0&&!isMerging()) {
|
|
134 send(quit2);
|
327
|
135 quit2 = null;
|
326
|
136 return true;
|
|
137 }
|
|
138 return false;
|
317
|
139 }
|
|
140
|
319
|
141 @Override
|
|
142 public boolean manage(REPCommand receivedCommand) {
|
330
|
143
|
|
144
|
319
|
145 switch(receivedCommand.cmd){
|
|
146 // Editor Command
|
|
147
|
|
148 case REPCMD_DELETE:
|
|
149 case REPCMD_INSERT:
|
|
150 case REPCMD_NOP:
|
|
151 {
|
328
|
152 translate(receivedCommand);
|
319
|
153 break;
|
|
154 }
|
323
|
155
|
|
156 case SMCMD_START_MERGE_ACK:
|
|
157 {
|
|
158 // マージの処理と次のエディタへコマンドを送信する処理
|
324
|
159 translator.mergeAck();
|
323
|
160 if (!merge(receivedCommand)) {
|
|
161 // nothing to do, send END_MERGE
|
|
162 endMerge();
|
|
163 }
|
|
164 break;
|
|
165 }
|
319
|
166 case SMCMD_QUIT:
|
|
167 {
|
|
168 next.send(receivedCommand);
|
|
169 break;
|
|
170 }
|
|
171 case SMCMD_QUIT_2:
|
|
172 {
|
328
|
173 // QUIT_2 is returned.
|
341
|
174 if (receivedCommand.eid!=eid) {
|
|
175 // stop this editor unless this is the start, starter will stopped
|
|
176 // by QUIT_2_ACK
|
|
177 manager.remove(this);
|
|
178 }
|
|
179 // don't send quit_2 directly to the editor until all pending
|
319
|
180 // merge is processed.
|
341
|
181 next.setQuit2(receivedCommand);
|
|
182 break;
|
|
183 }
|
|
184 case SMCMD_QUIT_2_ACK:
|
|
185 {
|
|
186 manager.remove(this);
|
319
|
187 break;
|
|
188 }
|
|
189 default:
|
|
190 return false;
|
|
191 }
|
|
192 return true;
|
|
193 }
|
|
194
|
349
|
195
|
|
196 @Override
|
358
|
197 public void handle(REPSelectionKey<REPCommand> key) throws IOException {
|
349
|
198 REPSocketChannel<REPCommand> channel = key.channel1();
|
|
199 REPCommand command = channel.read();
|
|
200 SessionManager.logger.writeLog("REPHandlerImpl.handle() read : command = " + command +" from "+channel);
|
353
|
201 if (manager.sessionManage(this, command)) return;
|
349
|
202 manage(command);
|
|
203 }
|
|
204
|
|
205 @Override
|
|
206 public void cancel(REPSocketChannel<REPCommand> socketChannel) {
|
|
207 manager.remove(socketChannel);
|
|
208 }
|
358
|
209
|
|
210 public boolean isMaster() {
|
|
211 return mode==REP.SMCMD_PUT;
|
|
212 }
|
1
|
213 }
|