001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.hadoop.hdfs.server.namenode;
019
020 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_ADD;
021 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_ALLOCATE_BLOCK_ID;
022 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_ALLOW_SNAPSHOT;
023 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_CANCEL_DELEGATION_TOKEN;
024 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_CLEAR_NS_QUOTA;
025 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_CLOSE;
026 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_CONCAT_DELETE;
027 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_CREATE_SNAPSHOT;
028 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_DELETE;
029 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_DELETE_SNAPSHOT;
030 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_DISALLOW_SNAPSHOT;
031 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_END_LOG_SEGMENT;
032 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_GET_DELEGATION_TOKEN;
033 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_INVALID;
034 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_MKDIR;
035 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_REASSIGN_LEASE;
036 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME;
037 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_OLD;
038 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_SNAPSHOT;
039 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENEW_DELEGATION_TOKEN;
040 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V1;
041 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V2;
042 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_NS_QUOTA;
043 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_OWNER;
044 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_PERMISSIONS;
045 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_QUOTA;
046 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_REPLICATION;
047 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_START_LOG_SEGMENT;
048 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SYMLINK;
049 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_TIMES;
050 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_UPDATE_BLOCKS;
051 import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_UPDATE_MASTER_KEY;
052
053 import java.io.DataInput;
054 import java.io.DataInputStream;
055 import java.io.DataOutput;
056 import java.io.DataOutputStream;
057 import java.io.EOFException;
058 import java.io.IOException;
059 import java.util.Arrays;
060 import java.util.EnumMap;
061 import java.util.List;
062 import java.util.zip.CheckedInputStream;
063 import java.util.zip.Checksum;
064
065 import org.apache.commons.codec.DecoderException;
066 import org.apache.commons.codec.binary.Hex;
067 import org.apache.hadoop.classification.InterfaceAudience;
068 import org.apache.hadoop.classification.InterfaceStability;
069 import org.apache.hadoop.fs.ChecksumException;
070 import org.apache.hadoop.fs.Options.Rename;
071 import org.apache.hadoop.fs.permission.FsPermission;
072 import org.apache.hadoop.fs.permission.PermissionStatus;
073 import org.apache.hadoop.hdfs.DFSConfigKeys;
074 import org.apache.hadoop.hdfs.DeprecatedUTF8;
075 import org.apache.hadoop.hdfs.protocol.Block;
076 import org.apache.hadoop.hdfs.protocol.ClientProtocol;
077 import org.apache.hadoop.hdfs.protocol.HdfsConstants;
078 import org.apache.hadoop.hdfs.protocol.LayoutVersion;
079 import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
080 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
081 import org.apache.hadoop.hdfs.util.XMLUtils;
082 import org.apache.hadoop.hdfs.util.XMLUtils.InvalidXmlException;
083 import org.apache.hadoop.hdfs.util.XMLUtils.Stanza;
084 import org.apache.hadoop.io.ArrayWritable;
085 import org.apache.hadoop.io.BytesWritable;
086 import org.apache.hadoop.io.DataOutputBuffer;
087 import org.apache.hadoop.io.IOUtils;
088 import org.apache.hadoop.io.Text;
089 import org.apache.hadoop.io.Writable;
090 import org.apache.hadoop.io.WritableFactories;
091 import org.apache.hadoop.io.WritableFactory;
092 import org.apache.hadoop.ipc.ClientId;
093 import org.apache.hadoop.ipc.RpcConstants;
094 import org.apache.hadoop.security.token.delegation.DelegationKey;
095 import org.apache.hadoop.util.PureJavaCrc32;
096 import org.xml.sax.ContentHandler;
097 import org.xml.sax.SAXException;
098 import org.xml.sax.helpers.AttributesImpl;
099
100 import com.google.common.base.Preconditions;
101
102 /**
103 * Helper classes for reading the ops from an InputStream.
104 * All ops derive from FSEditLogOp and are only
105 * instantiated from Reader#readOp()
106 */
107 @InterfaceAudience.Private
108 @InterfaceStability.Unstable
109 public abstract class FSEditLogOp {
110 public final FSEditLogOpCodes opCode;
111 long txid;
112 byte[] rpcClientId = RpcConstants.DUMMY_CLIENT_ID;
113 int rpcCallId = RpcConstants.INVALID_CALL_ID;
114
115 @SuppressWarnings("deprecation")
116 final public static class OpInstanceCache {
117 private EnumMap<FSEditLogOpCodes, FSEditLogOp> inst =
118 new EnumMap<FSEditLogOpCodes, FSEditLogOp>(FSEditLogOpCodes.class);
119
120 public OpInstanceCache() {
121 inst.put(OP_ADD, new AddOp());
122 inst.put(OP_CLOSE, new CloseOp());
123 inst.put(OP_SET_REPLICATION, new SetReplicationOp());
124 inst.put(OP_CONCAT_DELETE, new ConcatDeleteOp());
125 inst.put(OP_RENAME_OLD, new RenameOldOp());
126 inst.put(OP_DELETE, new DeleteOp());
127 inst.put(OP_MKDIR, new MkdirOp());
128 inst.put(OP_SET_GENSTAMP_V1, new SetGenstampV1Op());
129 inst.put(OP_SET_PERMISSIONS, new SetPermissionsOp());
130 inst.put(OP_SET_OWNER, new SetOwnerOp());
131 inst.put(OP_SET_NS_QUOTA, new SetNSQuotaOp());
132 inst.put(OP_CLEAR_NS_QUOTA, new ClearNSQuotaOp());
133 inst.put(OP_SET_QUOTA, new SetQuotaOp());
134 inst.put(OP_TIMES, new TimesOp());
135 inst.put(OP_SYMLINK, new SymlinkOp());
136 inst.put(OP_RENAME, new RenameOp());
137 inst.put(OP_REASSIGN_LEASE, new ReassignLeaseOp());
138 inst.put(OP_GET_DELEGATION_TOKEN, new GetDelegationTokenOp());
139 inst.put(OP_RENEW_DELEGATION_TOKEN, new RenewDelegationTokenOp());
140 inst.put(OP_CANCEL_DELEGATION_TOKEN,
141 new CancelDelegationTokenOp());
142 inst.put(OP_UPDATE_MASTER_KEY, new UpdateMasterKeyOp());
143 inst.put(OP_START_LOG_SEGMENT,
144 new LogSegmentOp(OP_START_LOG_SEGMENT));
145 inst.put(OP_END_LOG_SEGMENT,
146 new LogSegmentOp(OP_END_LOG_SEGMENT));
147 inst.put(OP_UPDATE_BLOCKS, new UpdateBlocksOp());
148
149 inst.put(OP_ALLOW_SNAPSHOT, new AllowSnapshotOp());
150 inst.put(OP_DISALLOW_SNAPSHOT, new DisallowSnapshotOp());
151 inst.put(OP_CREATE_SNAPSHOT, new CreateSnapshotOp());
152 inst.put(OP_DELETE_SNAPSHOT, new DeleteSnapshotOp());
153 inst.put(OP_RENAME_SNAPSHOT, new RenameSnapshotOp());
154 inst.put(OP_SET_GENSTAMP_V2, new SetGenstampV2Op());
155 inst.put(OP_ALLOCATE_BLOCK_ID, new AllocateBlockIdOp());
156 }
157
158 public FSEditLogOp get(FSEditLogOpCodes opcode) {
159 return inst.get(opcode);
160 }
161 }
162
163 /**
164 * Constructor for an EditLog Op. EditLog ops cannot be constructed
165 * directly, but only through Reader#readOp.
166 */
167 private FSEditLogOp(FSEditLogOpCodes opCode) {
168 this.opCode = opCode;
169 this.txid = HdfsConstants.INVALID_TXID;
170 }
171
172 public long getTransactionId() {
173 Preconditions.checkState(txid != HdfsConstants.INVALID_TXID);
174 return txid;
175 }
176
177 public String getTransactionIdStr() {
178 return (txid == HdfsConstants.INVALID_TXID) ? "(none)" : "" + txid;
179 }
180
181 public boolean hasTransactionId() {
182 return (txid != HdfsConstants.INVALID_TXID);
183 }
184
185 public void setTransactionId(long txid) {
186 this.txid = txid;
187 }
188
189 public boolean hasRpcIds() {
190 return rpcClientId != RpcConstants.DUMMY_CLIENT_ID
191 && rpcCallId != RpcConstants.INVALID_CALL_ID;
192 }
193
194 /** this has to be called after calling {@link #hasRpcIds()} */
195 public byte[] getClientId() {
196 Preconditions.checkState(rpcClientId != RpcConstants.DUMMY_CLIENT_ID);
197 return rpcClientId;
198 }
199
200 public void setRpcClientId(byte[] clientId) {
201 this.rpcClientId = clientId;
202 }
203
204 /** this has to be called after calling {@link #hasRpcIds()} */
205 public int getCallId() {
206 Preconditions.checkState(rpcCallId != RpcConstants.INVALID_CALL_ID);
207 return rpcCallId;
208 }
209
210 public void setRpcCallId(int callId) {
211 this.rpcCallId = callId;
212 }
213
214 abstract void readFields(DataInputStream in, int logVersion)
215 throws IOException;
216
217 public abstract void writeFields(DataOutputStream out)
218 throws IOException;
219
220 static interface BlockListUpdatingOp {
221 Block[] getBlocks();
222 String getPath();
223 boolean shouldCompleteLastBlock();
224 }
225
226 private static void writeRpcIds(final byte[] clientId, final int callId,
227 DataOutputStream out) throws IOException {
228 FSImageSerialization.writeBytes(clientId, out);
229 FSImageSerialization.writeInt(callId, out);
230 }
231
232 void readRpcIds(DataInputStream in, int logVersion)
233 throws IOException {
234 if (LayoutVersion.supports(Feature.EDITLOG_SUPPORT_RETRYCACHE,
235 logVersion)) {
236 this.rpcClientId = FSImageSerialization.readBytes(in);
237 this.rpcCallId = FSImageSerialization.readInt(in);
238 }
239 }
240
241 void readRpcIdsFromXml(Stanza st) {
242 this.rpcClientId = st.hasChildren("RPC_CLIENTID") ?
243 ClientId.toBytes(st.getValue("RPC_CLIENTID"))
244 : RpcConstants.DUMMY_CLIENT_ID;
245 this.rpcCallId = st.hasChildren("RPC_CALLID") ?
246 Integer.valueOf(st.getValue("RPC_CALLID"))
247 : RpcConstants.INVALID_CALL_ID;
248 }
249
250 private static void appendRpcIdsToString(final StringBuilder builder,
251 final byte[] clientId, final int callId) {
252 builder.append(", RpcClientId=");
253 builder.append(ClientId.toString(clientId));
254 builder.append(", RpcCallId=");
255 builder.append(callId);
256 }
257
258 private static void appendRpcIdsToXml(ContentHandler contentHandler,
259 final byte[] clientId, final int callId) throws SAXException {
260 XMLUtils.addSaxString(contentHandler, "RPC_CLIENTID",
261 ClientId.toString(clientId));
262 XMLUtils.addSaxString(contentHandler, "RPC_CALLID",
263 Integer.valueOf(callId).toString());
264 }
265
266 @SuppressWarnings("unchecked")
267 static abstract class AddCloseOp extends FSEditLogOp implements BlockListUpdatingOp {
268 int length;
269 long inodeId;
270 String path;
271 short replication;
272 long mtime;
273 long atime;
274 long blockSize;
275 Block[] blocks;
276 PermissionStatus permissions;
277 String clientName;
278 String clientMachine;
279
280 private AddCloseOp(FSEditLogOpCodes opCode) {
281 super(opCode);
282 assert(opCode == OP_ADD || opCode == OP_CLOSE);
283 }
284
285 <T extends AddCloseOp> T setInodeId(long inodeId) {
286 this.inodeId = inodeId;
287 return (T)this;
288 }
289
290 <T extends AddCloseOp> T setPath(String path) {
291 this.path = path;
292 return (T)this;
293 }
294
295 @Override
296 public String getPath() {
297 return path;
298 }
299
300 <T extends AddCloseOp> T setReplication(short replication) {
301 this.replication = replication;
302 return (T)this;
303 }
304
305 <T extends AddCloseOp> T setModificationTime(long mtime) {
306 this.mtime = mtime;
307 return (T)this;
308 }
309
310 <T extends AddCloseOp> T setAccessTime(long atime) {
311 this.atime = atime;
312 return (T)this;
313 }
314
315 <T extends AddCloseOp> T setBlockSize(long blockSize) {
316 this.blockSize = blockSize;
317 return (T)this;
318 }
319
320 <T extends AddCloseOp> T setBlocks(Block[] blocks) {
321 if (blocks.length > MAX_BLOCKS) {
322 throw new RuntimeException("Can't have more than " + MAX_BLOCKS +
323 " in an AddCloseOp.");
324 }
325 this.blocks = blocks;
326 return (T)this;
327 }
328
329 @Override
330 public Block[] getBlocks() {
331 return blocks;
332 }
333
334 <T extends AddCloseOp> T setPermissionStatus(PermissionStatus permissions) {
335 this.permissions = permissions;
336 return (T)this;
337 }
338
339 <T extends AddCloseOp> T setClientName(String clientName) {
340 this.clientName = clientName;
341 return (T)this;
342 }
343
344 <T extends AddCloseOp> T setClientMachine(String clientMachine) {
345 this.clientMachine = clientMachine;
346 return (T)this;
347 }
348
349 @Override
350 public void writeFields(DataOutputStream out) throws IOException {
351 FSImageSerialization.writeLong(inodeId, out);
352 FSImageSerialization.writeString(path, out);
353 FSImageSerialization.writeShort(replication, out);
354 FSImageSerialization.writeLong(mtime, out);
355 FSImageSerialization.writeLong(atime, out);
356 FSImageSerialization.writeLong(blockSize, out);
357 new ArrayWritable(Block.class, blocks).write(out);
358 permissions.write(out);
359
360 if (this.opCode == OP_ADD) {
361 FSImageSerialization.writeString(clientName,out);
362 FSImageSerialization.writeString(clientMachine,out);
363 // write clientId and callId
364 writeRpcIds(rpcClientId, rpcCallId, out);
365 }
366 }
367
368 @Override
369 void readFields(DataInputStream in, int logVersion)
370 throws IOException {
371 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
372 this.length = in.readInt();
373 }
374 if (LayoutVersion.supports(Feature.ADD_INODE_ID, logVersion)) {
375 this.inodeId = in.readLong();
376 } else {
377 // The inodeId should be updated when this editLogOp is applied
378 this.inodeId = INodeId.GRANDFATHER_INODE_ID;
379 }
380 if ((-17 < logVersion && length != 4) ||
381 (logVersion <= -17 && length != 5 && !LayoutVersion.supports(
382 Feature.EDITLOG_OP_OPTIMIZATION, logVersion))) {
383 throw new IOException("Incorrect data format." +
384 " logVersion is " + logVersion +
385 " but writables.length is " +
386 length + ". ");
387 }
388 this.path = FSImageSerialization.readString(in);
389
390 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
391 this.replication = FSImageSerialization.readShort(in);
392 this.mtime = FSImageSerialization.readLong(in);
393 } else {
394 this.replication = readShort(in);
395 this.mtime = readLong(in);
396 }
397
398 if (LayoutVersion.supports(Feature.FILE_ACCESS_TIME, logVersion)) {
399 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
400 this.atime = FSImageSerialization.readLong(in);
401 } else {
402 this.atime = readLong(in);
403 }
404 } else {
405 this.atime = 0;
406 }
407
408 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
409 this.blockSize = FSImageSerialization.readLong(in);
410 } else {
411 this.blockSize = readLong(in);
412 }
413
414 this.blocks = readBlocks(in, logVersion);
415 this.permissions = PermissionStatus.read(in);
416
417 // clientname, clientMachine and block locations of last block.
418 if (this.opCode == OP_ADD) {
419 this.clientName = FSImageSerialization.readString(in);
420 this.clientMachine = FSImageSerialization.readString(in);
421 // read clientId and callId
422 readRpcIds(in, logVersion);
423 } else {
424 this.clientName = "";
425 this.clientMachine = "";
426 }
427 }
428
429 static final public int MAX_BLOCKS = 1024 * 1024 * 64;
430
431 private static Block[] readBlocks(
432 DataInputStream in,
433 int logVersion) throws IOException {
434 int numBlocks = in.readInt();
435 if (numBlocks < 0) {
436 throw new IOException("invalid negative number of blocks");
437 } else if (numBlocks > MAX_BLOCKS) {
438 throw new IOException("invalid number of blocks: " + numBlocks +
439 ". The maximum number of blocks per file is " + MAX_BLOCKS);
440 }
441 Block[] blocks = new Block[numBlocks];
442 for (int i = 0; i < numBlocks; i++) {
443 Block blk = new Block();
444 blk.readFields(in);
445 blocks[i] = blk;
446 }
447 return blocks;
448 }
449
450 public String stringifyMembers() {
451 StringBuilder builder = new StringBuilder();
452 builder.append("[length=");
453 builder.append(length);
454 builder.append(", inodeId=");
455 builder.append(inodeId);
456 builder.append(", path=");
457 builder.append(path);
458 builder.append(", replication=");
459 builder.append(replication);
460 builder.append(", mtime=");
461 builder.append(mtime);
462 builder.append(", atime=");
463 builder.append(atime);
464 builder.append(", blockSize=");
465 builder.append(blockSize);
466 builder.append(", blocks=");
467 builder.append(Arrays.toString(blocks));
468 builder.append(", permissions=");
469 builder.append(permissions);
470 builder.append(", clientName=");
471 builder.append(clientName);
472 builder.append(", clientMachine=");
473 builder.append(clientMachine);
474 if (this.opCode == OP_ADD) {
475 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
476 }
477 builder.append(", opCode=");
478 builder.append(opCode);
479 builder.append(", txid=");
480 builder.append(txid);
481 builder.append("]");
482 return builder.toString();
483 }
484
485 @Override
486 protected void toXml(ContentHandler contentHandler) throws SAXException {
487 XMLUtils.addSaxString(contentHandler, "LENGTH",
488 Integer.valueOf(length).toString());
489 XMLUtils.addSaxString(contentHandler, "INODEID",
490 Long.valueOf(inodeId).toString());
491 XMLUtils.addSaxString(contentHandler, "PATH", path);
492 XMLUtils.addSaxString(contentHandler, "REPLICATION",
493 Short.valueOf(replication).toString());
494 XMLUtils.addSaxString(contentHandler, "MTIME",
495 Long.valueOf(mtime).toString());
496 XMLUtils.addSaxString(contentHandler, "ATIME",
497 Long.valueOf(atime).toString());
498 XMLUtils.addSaxString(contentHandler, "BLOCKSIZE",
499 Long.valueOf(blockSize).toString());
500 XMLUtils.addSaxString(contentHandler, "CLIENT_NAME", clientName);
501 XMLUtils.addSaxString(contentHandler, "CLIENT_MACHINE", clientMachine);
502 for (Block b : blocks) {
503 FSEditLogOp.blockToXml(contentHandler, b);
504 }
505 FSEditLogOp.permissionStatusToXml(contentHandler, permissions);
506 if (this.opCode == OP_ADD) {
507 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
508 }
509 }
510
511 @Override
512 void fromXml(Stanza st) throws InvalidXmlException {
513 this.length = Integer.valueOf(st.getValue("LENGTH"));
514 this.inodeId = Long.valueOf(st.getValue("INODEID"));
515 this.path = st.getValue("PATH");
516 this.replication = Short.valueOf(st.getValue("REPLICATION"));
517 this.mtime = Long.valueOf(st.getValue("MTIME"));
518 this.atime = Long.valueOf(st.getValue("ATIME"));
519 this.blockSize = Long.valueOf(st.getValue("BLOCKSIZE"));
520 this.clientName = st.getValue("CLIENT_NAME");
521 this.clientMachine = st.getValue("CLIENT_MACHINE");
522 if (st.hasChildren("BLOCK")) {
523 List<Stanza> blocks = st.getChildren("BLOCK");
524 this.blocks = new Block[blocks.size()];
525 for (int i = 0; i < blocks.size(); i++) {
526 this.blocks[i] = FSEditLogOp.blockFromXml(blocks.get(i));
527 }
528 } else {
529 this.blocks = new Block[0];
530 }
531 this.permissions =
532 permissionStatusFromXml(st.getChildren("PERMISSION_STATUS").get(0));
533 readRpcIdsFromXml(st);
534 }
535 }
536
537 /**
538 * {@literal @AtMostOnce} for {@link ClientProtocol#startFile} and
539 * {@link ClientProtocol#appendFile}
540 */
541 static class AddOp extends AddCloseOp {
542 private AddOp() {
543 super(OP_ADD);
544 }
545
546 static AddOp getInstance(OpInstanceCache cache) {
547 return (AddOp)cache.get(OP_ADD);
548 }
549
550 @Override
551 public boolean shouldCompleteLastBlock() {
552 return false;
553 }
554
555 @Override
556 public String toString() {
557 StringBuilder builder = new StringBuilder();
558 builder.append("AddOp ");
559 builder.append(stringifyMembers());
560 return builder.toString();
561 }
562 }
563
564 /**
565 * Although {@link ClientProtocol#appendFile} may also log a close op, we do
566 * not need to record the rpc ids here since a successful appendFile op will
567 * finally log an AddOp.
568 */
569 static class CloseOp extends AddCloseOp {
570 private CloseOp() {
571 super(OP_CLOSE);
572 }
573
574 static CloseOp getInstance(OpInstanceCache cache) {
575 return (CloseOp)cache.get(OP_CLOSE);
576 }
577
578 @Override
579 public boolean shouldCompleteLastBlock() {
580 return true;
581 }
582
583 @Override
584 public String toString() {
585 StringBuilder builder = new StringBuilder();
586 builder.append("CloseOp ");
587 builder.append(stringifyMembers());
588 return builder.toString();
589 }
590 }
591
592 /**
593 * {@literal @AtMostOnce} for {@link ClientProtocol#updatePipeline}, but
594 * {@literal @Idempotent} for some other ops.
595 */
596 static class UpdateBlocksOp extends FSEditLogOp implements BlockListUpdatingOp {
597 String path;
598 Block[] blocks;
599
600 private UpdateBlocksOp() {
601 super(OP_UPDATE_BLOCKS);
602 }
603
604 static UpdateBlocksOp getInstance(OpInstanceCache cache) {
605 return (UpdateBlocksOp)cache.get(OP_UPDATE_BLOCKS);
606 }
607
608 UpdateBlocksOp setPath(String path) {
609 this.path = path;
610 return this;
611 }
612
613 @Override
614 public String getPath() {
615 return path;
616 }
617
618 UpdateBlocksOp setBlocks(Block[] blocks) {
619 this.blocks = blocks;
620 return this;
621 }
622
623 @Override
624 public Block[] getBlocks() {
625 return blocks;
626 }
627
628 @Override
629 public
630 void writeFields(DataOutputStream out) throws IOException {
631 FSImageSerialization.writeString(path, out);
632 FSImageSerialization.writeCompactBlockArray(blocks, out);
633 // clientId and callId
634 writeRpcIds(rpcClientId, rpcCallId, out);
635 }
636
637 @Override
638 void readFields(DataInputStream in, int logVersion) throws IOException {
639 path = FSImageSerialization.readString(in);
640 this.blocks = FSImageSerialization.readCompactBlockArray(
641 in, logVersion);
642 readRpcIds(in, logVersion);
643 }
644
645 @Override
646 public boolean shouldCompleteLastBlock() {
647 return false;
648 }
649
650 @Override
651 public String toString() {
652 StringBuilder sb = new StringBuilder();
653 sb.append("UpdateBlocksOp [path=")
654 .append(path)
655 .append(", blocks=")
656 .append(Arrays.toString(blocks));
657 appendRpcIdsToString(sb, rpcClientId, rpcCallId);
658 sb.append("]");
659 return sb.toString();
660 }
661
662 @Override
663 protected void toXml(ContentHandler contentHandler) throws SAXException {
664 XMLUtils.addSaxString(contentHandler, "PATH", path);
665 for (Block b : blocks) {
666 FSEditLogOp.blockToXml(contentHandler, b);
667 }
668 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
669 }
670
671 @Override void fromXml(Stanza st) throws InvalidXmlException {
672 this.path = st.getValue("PATH");
673 List<Stanza> blocks = st.getChildren("BLOCK");
674 this.blocks = new Block[blocks.size()];
675 for (int i = 0; i < blocks.size(); i++) {
676 this.blocks[i] = FSEditLogOp.blockFromXml(blocks.get(i));
677 }
678 readRpcIdsFromXml(st);
679 }
680 }
681
682 /** {@literal @Idempotent} for {@link ClientProtocol#setReplication} */
683 static class SetReplicationOp extends FSEditLogOp {
684 String path;
685 short replication;
686
687 private SetReplicationOp() {
688 super(OP_SET_REPLICATION);
689 }
690
691 static SetReplicationOp getInstance(OpInstanceCache cache) {
692 return (SetReplicationOp)cache.get(OP_SET_REPLICATION);
693 }
694
695 SetReplicationOp setPath(String path) {
696 this.path = path;
697 return this;
698 }
699
700 SetReplicationOp setReplication(short replication) {
701 this.replication = replication;
702 return this;
703 }
704
705 @Override
706 public
707 void writeFields(DataOutputStream out) throws IOException {
708 FSImageSerialization.writeString(path, out);
709 FSImageSerialization.writeShort(replication, out);
710 }
711
712 @Override
713 void readFields(DataInputStream in, int logVersion)
714 throws IOException {
715 this.path = FSImageSerialization.readString(in);
716 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
717 this.replication = FSImageSerialization.readShort(in);
718 } else {
719 this.replication = readShort(in);
720 }
721 }
722
723 @Override
724 public String toString() {
725 StringBuilder builder = new StringBuilder();
726 builder.append("SetReplicationOp [path=");
727 builder.append(path);
728 builder.append(", replication=");
729 builder.append(replication);
730 builder.append(", opCode=");
731 builder.append(opCode);
732 builder.append(", txid=");
733 builder.append(txid);
734 builder.append("]");
735 return builder.toString();
736 }
737
738 @Override
739 protected void toXml(ContentHandler contentHandler) throws SAXException {
740 XMLUtils.addSaxString(contentHandler, "PATH", path);
741 XMLUtils.addSaxString(contentHandler, "REPLICATION",
742 Short.valueOf(replication).toString());
743 }
744
745 @Override void fromXml(Stanza st) throws InvalidXmlException {
746 this.path = st.getValue("PATH");
747 this.replication = Short.valueOf(st.getValue("REPLICATION"));
748 }
749 }
750
751 /** {@literal @AtMostOnce} for {@link ClientProtocol#concat} */
752 static class ConcatDeleteOp extends FSEditLogOp {
753 int length;
754 String trg;
755 String[] srcs;
756 long timestamp;
757 final static public int MAX_CONCAT_SRC = 1024 * 1024;
758
759 private ConcatDeleteOp() {
760 super(OP_CONCAT_DELETE);
761 }
762
763 static ConcatDeleteOp getInstance(OpInstanceCache cache) {
764 return (ConcatDeleteOp)cache.get(OP_CONCAT_DELETE);
765 }
766
767 ConcatDeleteOp setTarget(String trg) {
768 this.trg = trg;
769 return this;
770 }
771
772 ConcatDeleteOp setSources(String[] srcs) {
773 if (srcs.length > MAX_CONCAT_SRC) {
774 throw new RuntimeException("ConcatDeleteOp can only have " +
775 MAX_CONCAT_SRC + " sources at most.");
776 }
777 this.srcs = srcs;
778
779 return this;
780 }
781
782 ConcatDeleteOp setTimestamp(long timestamp) {
783 this.timestamp = timestamp;
784 return this;
785 }
786
787 @Override
788 public void writeFields(DataOutputStream out) throws IOException {
789 FSImageSerialization.writeString(trg, out);
790
791 DeprecatedUTF8 info[] = new DeprecatedUTF8[srcs.length];
792 int idx = 0;
793 for(int i=0; i<srcs.length; i++) {
794 info[idx++] = new DeprecatedUTF8(srcs[i]);
795 }
796 new ArrayWritable(DeprecatedUTF8.class, info).write(out);
797
798 FSImageSerialization.writeLong(timestamp, out);
799
800 // rpc ids
801 writeRpcIds(rpcClientId, rpcCallId, out);
802 }
803
804 @Override
805 void readFields(DataInputStream in, int logVersion)
806 throws IOException {
807 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
808 this.length = in.readInt();
809 if (length < 3) { // trg, srcs.., timestamp
810 throw new IOException("Incorrect data format " +
811 "for ConcatDeleteOp.");
812 }
813 }
814 this.trg = FSImageSerialization.readString(in);
815 int srcSize = 0;
816 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
817 srcSize = in.readInt();
818 } else {
819 srcSize = this.length - 1 - 1; // trg and timestamp
820 }
821 if (srcSize < 0) {
822 throw new IOException("Incorrect data format. "
823 + "ConcatDeleteOp cannot have a negative number of data " +
824 " sources.");
825 } else if (srcSize > MAX_CONCAT_SRC) {
826 throw new IOException("Incorrect data format. "
827 + "ConcatDeleteOp can have at most " + MAX_CONCAT_SRC +
828 " sources, but we tried to have " + (length - 3) + " sources.");
829 }
830 this.srcs = new String [srcSize];
831 for(int i=0; i<srcSize;i++) {
832 srcs[i]= FSImageSerialization.readString(in);
833 }
834
835 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
836 this.timestamp = FSImageSerialization.readLong(in);
837 } else {
838 this.timestamp = readLong(in);
839 }
840 // read RPC ids if necessary
841 readRpcIds(in, logVersion);
842 }
843
844 @Override
845 public String toString() {
846 StringBuilder builder = new StringBuilder();
847 builder.append("ConcatDeleteOp [length=");
848 builder.append(length);
849 builder.append(", trg=");
850 builder.append(trg);
851 builder.append(", srcs=");
852 builder.append(Arrays.toString(srcs));
853 builder.append(", timestamp=");
854 builder.append(timestamp);
855 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
856 builder.append(", opCode=");
857 builder.append(opCode);
858 builder.append(", txid=");
859 builder.append(txid);
860 builder.append("]");
861 return builder.toString();
862 }
863
864 @Override
865 protected void toXml(ContentHandler contentHandler) throws SAXException {
866 XMLUtils.addSaxString(contentHandler, "LENGTH",
867 Integer.valueOf(length).toString());
868 XMLUtils.addSaxString(contentHandler, "TRG", trg);
869 XMLUtils.addSaxString(contentHandler, "TIMESTAMP",
870 Long.valueOf(timestamp).toString());
871 contentHandler.startElement("", "", "SOURCES", new AttributesImpl());
872 for (int i = 0; i < srcs.length; ++i) {
873 XMLUtils.addSaxString(contentHandler,
874 "SOURCE" + (i + 1), srcs[i]);
875 }
876 contentHandler.endElement("", "", "SOURCES");
877 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
878 }
879
880 @Override void fromXml(Stanza st) throws InvalidXmlException {
881 this.length = Integer.valueOf(st.getValue("LENGTH"));
882 this.trg = st.getValue("TRG");
883 this.timestamp = Long.valueOf(st.getValue("TIMESTAMP"));
884 List<Stanza> sources = st.getChildren("SOURCES");
885 int i = 0;
886 while (true) {
887 if (!sources.get(0).hasChildren("SOURCE" + (i + 1)))
888 break;
889 i++;
890 }
891 srcs = new String[i];
892 for (i = 0; i < srcs.length; i++) {
893 srcs[i] = sources.get(0).getValue("SOURCE" + (i + 1));
894 }
895 readRpcIdsFromXml(st);
896 }
897 }
898
899 /** {@literal @AtMostOnce} for {@link ClientProtocol#rename} */
900 static class RenameOldOp extends FSEditLogOp {
901 int length;
902 String src;
903 String dst;
904 long timestamp;
905
906 private RenameOldOp() {
907 super(OP_RENAME_OLD);
908 }
909
910 static RenameOldOp getInstance(OpInstanceCache cache) {
911 return (RenameOldOp)cache.get(OP_RENAME_OLD);
912 }
913
914 RenameOldOp setSource(String src) {
915 this.src = src;
916 return this;
917 }
918
919 RenameOldOp setDestination(String dst) {
920 this.dst = dst;
921 return this;
922 }
923
924 RenameOldOp setTimestamp(long timestamp) {
925 this.timestamp = timestamp;
926 return this;
927 }
928
929 @Override
930 public
931 void writeFields(DataOutputStream out) throws IOException {
932 FSImageSerialization.writeString(src, out);
933 FSImageSerialization.writeString(dst, out);
934 FSImageSerialization.writeLong(timestamp, out);
935 writeRpcIds(rpcClientId, rpcCallId, out);
936 }
937
938 @Override
939 void readFields(DataInputStream in, int logVersion)
940 throws IOException {
941 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
942 this.length = in.readInt();
943 if (this.length != 3) {
944 throw new IOException("Incorrect data format. "
945 + "Old rename operation.");
946 }
947 }
948 this.src = FSImageSerialization.readString(in);
949 this.dst = FSImageSerialization.readString(in);
950 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
951 this.timestamp = FSImageSerialization.readLong(in);
952 } else {
953 this.timestamp = readLong(in);
954 }
955
956 // read RPC ids if necessary
957 readRpcIds(in, logVersion);
958 }
959
960 @Override
961 public String toString() {
962 StringBuilder builder = new StringBuilder();
963 builder.append("RenameOldOp [length=");
964 builder.append(length);
965 builder.append(", src=");
966 builder.append(src);
967 builder.append(", dst=");
968 builder.append(dst);
969 builder.append(", timestamp=");
970 builder.append(timestamp);
971 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
972 builder.append(", opCode=");
973 builder.append(opCode);
974 builder.append(", txid=");
975 builder.append(txid);
976 builder.append("]");
977 return builder.toString();
978 }
979
980 @Override
981 protected void toXml(ContentHandler contentHandler) throws SAXException {
982 XMLUtils.addSaxString(contentHandler, "LENGTH",
983 Integer.valueOf(length).toString());
984 XMLUtils.addSaxString(contentHandler, "SRC", src);
985 XMLUtils.addSaxString(contentHandler, "DST", dst);
986 XMLUtils.addSaxString(contentHandler, "TIMESTAMP",
987 Long.valueOf(timestamp).toString());
988 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
989 }
990
991 @Override
992 void fromXml(Stanza st) throws InvalidXmlException {
993 this.length = Integer.valueOf(st.getValue("LENGTH"));
994 this.src = st.getValue("SRC");
995 this.dst = st.getValue("DST");
996 this.timestamp = Long.valueOf(st.getValue("TIMESTAMP"));
997
998 readRpcIdsFromXml(st);
999 }
1000 }
1001
1002 /** {@literal @AtMostOnce} for {@link ClientProtocol#delete} */
1003 static class DeleteOp extends FSEditLogOp {
1004 int length;
1005 String path;
1006 long timestamp;
1007
1008 private DeleteOp() {
1009 super(OP_DELETE);
1010 }
1011
1012 static DeleteOp getInstance(OpInstanceCache cache) {
1013 return (DeleteOp)cache.get(OP_DELETE);
1014 }
1015
1016 DeleteOp setPath(String path) {
1017 this.path = path;
1018 return this;
1019 }
1020
1021 DeleteOp setTimestamp(long timestamp) {
1022 this.timestamp = timestamp;
1023 return this;
1024 }
1025
1026 @Override
1027 public
1028 void writeFields(DataOutputStream out) throws IOException {
1029 FSImageSerialization.writeString(path, out);
1030 FSImageSerialization.writeLong(timestamp, out);
1031 writeRpcIds(rpcClientId, rpcCallId, out);
1032 }
1033
1034 @Override
1035 void readFields(DataInputStream in, int logVersion)
1036 throws IOException {
1037 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1038 this.length = in.readInt();
1039 if (this.length != 2) {
1040 throw new IOException("Incorrect data format. " + "delete operation.");
1041 }
1042 }
1043 this.path = FSImageSerialization.readString(in);
1044 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1045 this.timestamp = FSImageSerialization.readLong(in);
1046 } else {
1047 this.timestamp = readLong(in);
1048 }
1049 // read RPC ids if necessary
1050 readRpcIds(in, logVersion);
1051 }
1052
1053 @Override
1054 public String toString() {
1055 StringBuilder builder = new StringBuilder();
1056 builder.append("DeleteOp [length=");
1057 builder.append(length);
1058 builder.append(", path=");
1059 builder.append(path);
1060 builder.append(", timestamp=");
1061 builder.append(timestamp);
1062 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
1063 builder.append(", opCode=");
1064 builder.append(opCode);
1065 builder.append(", txid=");
1066 builder.append(txid);
1067 builder.append("]");
1068 return builder.toString();
1069 }
1070
1071 @Override
1072 protected void toXml(ContentHandler contentHandler) throws SAXException {
1073 XMLUtils.addSaxString(contentHandler, "LENGTH",
1074 Integer.valueOf(length).toString());
1075 XMLUtils.addSaxString(contentHandler, "PATH", path);
1076 XMLUtils.addSaxString(contentHandler, "TIMESTAMP",
1077 Long.valueOf(timestamp).toString());
1078 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
1079 }
1080
1081 @Override void fromXml(Stanza st) throws InvalidXmlException {
1082 this.length = Integer.valueOf(st.getValue("LENGTH"));
1083 this.path = st.getValue("PATH");
1084 this.timestamp = Long.valueOf(st.getValue("TIMESTAMP"));
1085
1086 readRpcIdsFromXml(st);
1087 }
1088 }
1089
1090 /** {@literal @Idempotent} for {@link ClientProtocol#mkdirs} */
1091 static class MkdirOp extends FSEditLogOp {
1092 int length;
1093 long inodeId;
1094 String path;
1095 long timestamp;
1096 PermissionStatus permissions;
1097
1098 private MkdirOp() {
1099 super(OP_MKDIR);
1100 }
1101
1102 static MkdirOp getInstance(OpInstanceCache cache) {
1103 return (MkdirOp)cache.get(OP_MKDIR);
1104 }
1105
1106 MkdirOp setInodeId(long inodeId) {
1107 this.inodeId = inodeId;
1108 return this;
1109 }
1110
1111 MkdirOp setPath(String path) {
1112 this.path = path;
1113 return this;
1114 }
1115
1116 MkdirOp setTimestamp(long timestamp) {
1117 this.timestamp = timestamp;
1118 return this;
1119 }
1120
1121 MkdirOp setPermissionStatus(PermissionStatus permissions) {
1122 this.permissions = permissions;
1123 return this;
1124 }
1125
1126 @Override
1127 public
1128 void writeFields(DataOutputStream out) throws IOException {
1129 FSImageSerialization.writeLong(inodeId, out);
1130 FSImageSerialization.writeString(path, out);
1131 FSImageSerialization.writeLong(timestamp, out); // mtime
1132 FSImageSerialization.writeLong(timestamp, out); // atime, unused at this
1133 permissions.write(out);
1134 }
1135
1136 @Override
1137 void readFields(DataInputStream in, int logVersion) throws IOException {
1138 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1139 this.length = in.readInt();
1140 }
1141 if (-17 < logVersion && length != 2 ||
1142 logVersion <= -17 && length != 3
1143 && !LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1144 throw new IOException("Incorrect data format. Mkdir operation.");
1145 }
1146 if (LayoutVersion.supports(Feature.ADD_INODE_ID, logVersion)) {
1147 this.inodeId = FSImageSerialization.readLong(in);
1148 } else {
1149 // This id should be updated when this editLogOp is applied
1150 this.inodeId = INodeId.GRANDFATHER_INODE_ID;
1151 }
1152 this.path = FSImageSerialization.readString(in);
1153 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1154 this.timestamp = FSImageSerialization.readLong(in);
1155 } else {
1156 this.timestamp = readLong(in);
1157 }
1158
1159 // The disk format stores atimes for directories as well.
1160 // However, currently this is not being updated/used because of
1161 // performance reasons.
1162 if (LayoutVersion.supports(Feature.FILE_ACCESS_TIME, logVersion)) {
1163 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1164 FSImageSerialization.readLong(in);
1165 } else {
1166 readLong(in);
1167 }
1168 }
1169
1170 this.permissions = PermissionStatus.read(in);
1171 }
1172
1173 @Override
1174 public String toString() {
1175 StringBuilder builder = new StringBuilder();
1176 builder.append("MkdirOp [length=");
1177 builder.append(length);
1178 builder.append(", inodeId=");
1179 builder.append(inodeId);
1180 builder.append(", path=");
1181 builder.append(path);
1182 builder.append(", timestamp=");
1183 builder.append(timestamp);
1184 builder.append(", permissions=");
1185 builder.append(permissions);
1186 builder.append(", opCode=");
1187 builder.append(opCode);
1188 builder.append(", txid=");
1189 builder.append(txid);
1190 builder.append("]");
1191 return builder.toString();
1192 }
1193
1194 @Override
1195 protected void toXml(ContentHandler contentHandler) throws SAXException {
1196 XMLUtils.addSaxString(contentHandler, "LENGTH",
1197 Integer.valueOf(length).toString());
1198 XMLUtils.addSaxString(contentHandler, "INODEID",
1199 Long.valueOf(inodeId).toString());
1200 XMLUtils.addSaxString(contentHandler, "PATH", path);
1201 XMLUtils.addSaxString(contentHandler, "TIMESTAMP",
1202 Long.valueOf(timestamp).toString());
1203 FSEditLogOp.permissionStatusToXml(contentHandler, permissions);
1204 }
1205
1206 @Override void fromXml(Stanza st) throws InvalidXmlException {
1207 this.length = Integer.valueOf(st.getValue("LENGTH"));
1208 this.inodeId = Long.valueOf(st.getValue("INODEID"));
1209 this.path = st.getValue("PATH");
1210 this.timestamp = Long.valueOf(st.getValue("TIMESTAMP"));
1211 this.permissions =
1212 permissionStatusFromXml(st.getChildren("PERMISSION_STATUS").get(0));
1213 }
1214 }
1215
1216 /**
1217 * The corresponding operations are either {@literal @Idempotent} (
1218 * {@link ClientProtocol#updateBlockForPipeline},
1219 * {@link ClientProtocol#recoverLease}, {@link ClientProtocol#addBlock}) or
1220 * already bound with other editlog op which records rpc ids (
1221 * {@link ClientProtocol#startFile}). Thus no need to record rpc ids here.
1222 */
1223 static class SetGenstampV1Op extends FSEditLogOp {
1224 long genStampV1;
1225
1226 private SetGenstampV1Op() {
1227 super(OP_SET_GENSTAMP_V1);
1228 }
1229
1230 static SetGenstampV1Op getInstance(OpInstanceCache cache) {
1231 return (SetGenstampV1Op)cache.get(OP_SET_GENSTAMP_V1);
1232 }
1233
1234 SetGenstampV1Op setGenerationStamp(long genStamp) {
1235 this.genStampV1 = genStamp;
1236 return this;
1237 }
1238
1239 @Override
1240 public
1241 void writeFields(DataOutputStream out) throws IOException {
1242 FSImageSerialization.writeLong(genStampV1, out);
1243 }
1244
1245 @Override
1246 void readFields(DataInputStream in, int logVersion)
1247 throws IOException {
1248 this.genStampV1 = FSImageSerialization.readLong(in);
1249 }
1250
1251 @Override
1252 public String toString() {
1253 StringBuilder builder = new StringBuilder();
1254 builder.append("SetGenstampOp [GenStamp=");
1255 builder.append(genStampV1);
1256 builder.append(", opCode=");
1257 builder.append(opCode);
1258 builder.append(", txid=");
1259 builder.append(txid);
1260 builder.append("]");
1261 return builder.toString();
1262 }
1263
1264 @Override
1265 protected void toXml(ContentHandler contentHandler) throws SAXException {
1266 XMLUtils.addSaxString(contentHandler, "GENSTAMP",
1267 Long.valueOf(genStampV1).toString());
1268 }
1269
1270 @Override void fromXml(Stanza st) throws InvalidXmlException {
1271 this.genStampV1 = Long.valueOf(st.getValue("GENSTAMP"));
1272 }
1273 }
1274
1275 /** Similar with {@link SetGenstampV1Op} */
1276 static class SetGenstampV2Op extends FSEditLogOp {
1277 long genStampV2;
1278
1279 private SetGenstampV2Op() {
1280 super(OP_SET_GENSTAMP_V2);
1281 }
1282
1283 static SetGenstampV2Op getInstance(OpInstanceCache cache) {
1284 return (SetGenstampV2Op)cache.get(OP_SET_GENSTAMP_V2);
1285 }
1286
1287 SetGenstampV2Op setGenerationStamp(long genStamp) {
1288 this.genStampV2 = genStamp;
1289 return this;
1290 }
1291
1292 @Override
1293 public
1294 void writeFields(DataOutputStream out) throws IOException {
1295 FSImageSerialization.writeLong(genStampV2, out);
1296 }
1297
1298 @Override
1299 void readFields(DataInputStream in, int logVersion)
1300 throws IOException {
1301 this.genStampV2 = FSImageSerialization.readLong(in);
1302 }
1303
1304 @Override
1305 public String toString() {
1306 StringBuilder builder = new StringBuilder();
1307 builder.append("SetGenstampV2Op [GenStampV2=");
1308 builder.append(genStampV2);
1309 builder.append(", opCode=");
1310 builder.append(opCode);
1311 builder.append(", txid=");
1312 builder.append(txid);
1313 builder.append("]");
1314 return builder.toString();
1315 }
1316
1317 @Override
1318 protected void toXml(ContentHandler contentHandler) throws SAXException {
1319 XMLUtils.addSaxString(contentHandler, "GENSTAMPV2",
1320 Long.valueOf(genStampV2).toString());
1321 }
1322
1323 @Override void fromXml(Stanza st) throws InvalidXmlException {
1324 this.genStampV2 = Long.valueOf(st.getValue("GENSTAMPV2"));
1325 }
1326 }
1327
1328 /** {@literal @Idempotent} for {@link ClientProtocol#addBlock} */
1329 static class AllocateBlockIdOp extends FSEditLogOp {
1330 long blockId;
1331
1332 private AllocateBlockIdOp() {
1333 super(OP_ALLOCATE_BLOCK_ID);
1334 }
1335
1336 static AllocateBlockIdOp getInstance(OpInstanceCache cache) {
1337 return (AllocateBlockIdOp)cache.get(OP_ALLOCATE_BLOCK_ID);
1338 }
1339
1340 AllocateBlockIdOp setBlockId(long blockId) {
1341 this.blockId = blockId;
1342 return this;
1343 }
1344
1345 @Override
1346 public
1347 void writeFields(DataOutputStream out) throws IOException {
1348 FSImageSerialization.writeLong(blockId, out);
1349 }
1350
1351 @Override
1352 void readFields(DataInputStream in, int logVersion)
1353 throws IOException {
1354 this.blockId = FSImageSerialization.readLong(in);
1355 }
1356
1357 @Override
1358 public String toString() {
1359 StringBuilder builder = new StringBuilder();
1360 builder.append("AllocateBlockIdOp [blockId=");
1361 builder.append(blockId);
1362 builder.append(", opCode=");
1363 builder.append(opCode);
1364 builder.append(", txid=");
1365 builder.append(txid);
1366 builder.append("]");
1367 return builder.toString();
1368 }
1369
1370 @Override
1371 protected void toXml(ContentHandler contentHandler) throws SAXException {
1372 XMLUtils.addSaxString(contentHandler, "BLOCK_ID",
1373 Long.valueOf(blockId).toString());
1374 }
1375
1376 @Override void fromXml(Stanza st) throws InvalidXmlException {
1377 this.blockId = Long.valueOf(st.getValue("BLOCK_ID"));
1378 }
1379 }
1380
1381 /** {@literal @Idempotent} for {@link ClientProtocol#setPermission} */
1382 static class SetPermissionsOp extends FSEditLogOp {
1383 String src;
1384 FsPermission permissions;
1385
1386 private SetPermissionsOp() {
1387 super(OP_SET_PERMISSIONS);
1388 }
1389
1390 static SetPermissionsOp getInstance(OpInstanceCache cache) {
1391 return (SetPermissionsOp)cache.get(OP_SET_PERMISSIONS);
1392 }
1393
1394 SetPermissionsOp setSource(String src) {
1395 this.src = src;
1396 return this;
1397 }
1398
1399 SetPermissionsOp setPermissions(FsPermission permissions) {
1400 this.permissions = permissions;
1401 return this;
1402 }
1403
1404 @Override
1405 public
1406 void writeFields(DataOutputStream out) throws IOException {
1407 FSImageSerialization.writeString(src, out);
1408 permissions.write(out);
1409 }
1410
1411 @Override
1412 void readFields(DataInputStream in, int logVersion)
1413 throws IOException {
1414 this.src = FSImageSerialization.readString(in);
1415 this.permissions = FsPermission.read(in);
1416 }
1417
1418 @Override
1419 public String toString() {
1420 StringBuilder builder = new StringBuilder();
1421 builder.append("SetPermissionsOp [src=");
1422 builder.append(src);
1423 builder.append(", permissions=");
1424 builder.append(permissions);
1425 builder.append(", opCode=");
1426 builder.append(opCode);
1427 builder.append(", txid=");
1428 builder.append(txid);
1429 builder.append("]");
1430 return builder.toString();
1431 }
1432
1433 @Override
1434 protected void toXml(ContentHandler contentHandler) throws SAXException {
1435 XMLUtils.addSaxString(contentHandler, "SRC", src);
1436 XMLUtils.addSaxString(contentHandler, "MODE",
1437 Short.valueOf(permissions.toShort()).toString());
1438 }
1439
1440 @Override void fromXml(Stanza st) throws InvalidXmlException {
1441 this.src = st.getValue("SRC");
1442 this.permissions = new FsPermission(
1443 Short.valueOf(st.getValue("MODE")));
1444 }
1445 }
1446
1447 /** {@literal @Idempotent} for {@link ClientProtocol#setOwner} */
1448 static class SetOwnerOp extends FSEditLogOp {
1449 String src;
1450 String username;
1451 String groupname;
1452
1453 private SetOwnerOp() {
1454 super(OP_SET_OWNER);
1455 }
1456
1457 static SetOwnerOp getInstance(OpInstanceCache cache) {
1458 return (SetOwnerOp)cache.get(OP_SET_OWNER);
1459 }
1460
1461 SetOwnerOp setSource(String src) {
1462 this.src = src;
1463 return this;
1464 }
1465
1466 SetOwnerOp setUser(String username) {
1467 this.username = username;
1468 return this;
1469 }
1470
1471 SetOwnerOp setGroup(String groupname) {
1472 this.groupname = groupname;
1473 return this;
1474 }
1475
1476 @Override
1477 public
1478 void writeFields(DataOutputStream out) throws IOException {
1479 FSImageSerialization.writeString(src, out);
1480 FSImageSerialization.writeString(username == null ? "" : username, out);
1481 FSImageSerialization.writeString(groupname == null ? "" : groupname, out);
1482 }
1483
1484 @Override
1485 void readFields(DataInputStream in, int logVersion)
1486 throws IOException {
1487 this.src = FSImageSerialization.readString(in);
1488 this.username = FSImageSerialization.readString_EmptyAsNull(in);
1489 this.groupname = FSImageSerialization.readString_EmptyAsNull(in);
1490 }
1491
1492 @Override
1493 public String toString() {
1494 StringBuilder builder = new StringBuilder();
1495 builder.append("SetOwnerOp [src=");
1496 builder.append(src);
1497 builder.append(", username=");
1498 builder.append(username);
1499 builder.append(", groupname=");
1500 builder.append(groupname);
1501 builder.append(", opCode=");
1502 builder.append(opCode);
1503 builder.append(", txid=");
1504 builder.append(txid);
1505 builder.append("]");
1506 return builder.toString();
1507 }
1508
1509 @Override
1510 protected void toXml(ContentHandler contentHandler) throws SAXException {
1511 XMLUtils.addSaxString(contentHandler, "SRC", src);
1512 if (username != null) {
1513 XMLUtils.addSaxString(contentHandler, "USERNAME", username);
1514 }
1515 if (groupname != null) {
1516 XMLUtils.addSaxString(contentHandler, "GROUPNAME", groupname);
1517 }
1518 }
1519
1520 @Override void fromXml(Stanza st) throws InvalidXmlException {
1521 this.src = st.getValue("SRC");
1522 this.username = (st.hasChildren("USERNAME")) ?
1523 st.getValue("USERNAME") : null;
1524 this.groupname = (st.hasChildren("GROUPNAME")) ?
1525 st.getValue("GROUPNAME") : null;
1526 }
1527 }
1528
1529 static class SetNSQuotaOp extends FSEditLogOp {
1530 String src;
1531 long nsQuota;
1532
1533 private SetNSQuotaOp() {
1534 super(OP_SET_NS_QUOTA);
1535 }
1536
1537 static SetNSQuotaOp getInstance(OpInstanceCache cache) {
1538 return (SetNSQuotaOp)cache.get(OP_SET_NS_QUOTA);
1539 }
1540
1541 @Override
1542 public
1543 void writeFields(DataOutputStream out) throws IOException {
1544 throw new IOException("Deprecated");
1545 }
1546
1547 @Override
1548 void readFields(DataInputStream in, int logVersion)
1549 throws IOException {
1550 this.src = FSImageSerialization.readString(in);
1551 this.nsQuota = FSImageSerialization.readLong(in);
1552 }
1553
1554 @Override
1555 public String toString() {
1556 StringBuilder builder = new StringBuilder();
1557 builder.append("SetNSQuotaOp [src=");
1558 builder.append(src);
1559 builder.append(", nsQuota=");
1560 builder.append(nsQuota);
1561 builder.append(", opCode=");
1562 builder.append(opCode);
1563 builder.append(", txid=");
1564 builder.append(txid);
1565 builder.append("]");
1566 return builder.toString();
1567 }
1568
1569 @Override
1570 protected void toXml(ContentHandler contentHandler) throws SAXException {
1571 XMLUtils.addSaxString(contentHandler, "SRC", src);
1572 XMLUtils.addSaxString(contentHandler, "NSQUOTA",
1573 Long.valueOf(nsQuota).toString());
1574 }
1575
1576 @Override void fromXml(Stanza st) throws InvalidXmlException {
1577 this.src = st.getValue("SRC");
1578 this.nsQuota = Long.valueOf(st.getValue("NSQUOTA"));
1579 }
1580 }
1581
1582 static class ClearNSQuotaOp extends FSEditLogOp {
1583 String src;
1584
1585 private ClearNSQuotaOp() {
1586 super(OP_CLEAR_NS_QUOTA);
1587 }
1588
1589 static ClearNSQuotaOp getInstance(OpInstanceCache cache) {
1590 return (ClearNSQuotaOp)cache.get(OP_CLEAR_NS_QUOTA);
1591 }
1592
1593 @Override
1594 public
1595 void writeFields(DataOutputStream out) throws IOException {
1596 throw new IOException("Deprecated");
1597 }
1598
1599 @Override
1600 void readFields(DataInputStream in, int logVersion)
1601 throws IOException {
1602 this.src = FSImageSerialization.readString(in);
1603 }
1604
1605 @Override
1606 public String toString() {
1607 StringBuilder builder = new StringBuilder();
1608 builder.append("ClearNSQuotaOp [src=");
1609 builder.append(src);
1610 builder.append(", opCode=");
1611 builder.append(opCode);
1612 builder.append(", txid=");
1613 builder.append(txid);
1614 builder.append("]");
1615 return builder.toString();
1616 }
1617
1618 @Override
1619 protected void toXml(ContentHandler contentHandler) throws SAXException {
1620 XMLUtils.addSaxString(contentHandler, "SRC", src);
1621 }
1622
1623 @Override void fromXml(Stanza st) throws InvalidXmlException {
1624 this.src = st.getValue("SRC");
1625 }
1626 }
1627
1628 /** {@literal @Idempotent} for {@link ClientProtocol#setQuota} */
1629 static class SetQuotaOp extends FSEditLogOp {
1630 String src;
1631 long nsQuota;
1632 long dsQuota;
1633
1634 private SetQuotaOp() {
1635 super(OP_SET_QUOTA);
1636 }
1637
1638 static SetQuotaOp getInstance(OpInstanceCache cache) {
1639 return (SetQuotaOp)cache.get(OP_SET_QUOTA);
1640 }
1641
1642 SetQuotaOp setSource(String src) {
1643 this.src = src;
1644 return this;
1645 }
1646
1647 SetQuotaOp setNSQuota(long nsQuota) {
1648 this.nsQuota = nsQuota;
1649 return this;
1650 }
1651
1652 SetQuotaOp setDSQuota(long dsQuota) {
1653 this.dsQuota = dsQuota;
1654 return this;
1655 }
1656
1657 @Override
1658 public
1659 void writeFields(DataOutputStream out) throws IOException {
1660 FSImageSerialization.writeString(src, out);
1661 FSImageSerialization.writeLong(nsQuota, out);
1662 FSImageSerialization.writeLong(dsQuota, out);
1663 }
1664
1665 @Override
1666 void readFields(DataInputStream in, int logVersion)
1667 throws IOException {
1668 this.src = FSImageSerialization.readString(in);
1669 this.nsQuota = FSImageSerialization.readLong(in);
1670 this.dsQuota = FSImageSerialization.readLong(in);
1671 }
1672
1673 @Override
1674 public String toString() {
1675 StringBuilder builder = new StringBuilder();
1676 builder.append("SetQuotaOp [src=");
1677 builder.append(src);
1678 builder.append(", nsQuota=");
1679 builder.append(nsQuota);
1680 builder.append(", dsQuota=");
1681 builder.append(dsQuota);
1682 builder.append(", opCode=");
1683 builder.append(opCode);
1684 builder.append(", txid=");
1685 builder.append(txid);
1686 builder.append("]");
1687 return builder.toString();
1688 }
1689
1690 @Override
1691 protected void toXml(ContentHandler contentHandler) throws SAXException {
1692 XMLUtils.addSaxString(contentHandler, "SRC", src);
1693 XMLUtils.addSaxString(contentHandler, "NSQUOTA",
1694 Long.valueOf(nsQuota).toString());
1695 XMLUtils.addSaxString(contentHandler, "DSQUOTA",
1696 Long.valueOf(dsQuota).toString());
1697 }
1698
1699 @Override void fromXml(Stanza st) throws InvalidXmlException {
1700 this.src = st.getValue("SRC");
1701 this.nsQuota = Long.valueOf(st.getValue("NSQUOTA"));
1702 this.dsQuota = Long.valueOf(st.getValue("DSQUOTA"));
1703 }
1704 }
1705
1706 /** {@literal @Idempotent} for {@link ClientProtocol#setTimes} */
1707 static class TimesOp extends FSEditLogOp {
1708 int length;
1709 String path;
1710 long mtime;
1711 long atime;
1712
1713 private TimesOp() {
1714 super(OP_TIMES);
1715 }
1716
1717 static TimesOp getInstance(OpInstanceCache cache) {
1718 return (TimesOp)cache.get(OP_TIMES);
1719 }
1720
1721 TimesOp setPath(String path) {
1722 this.path = path;
1723 return this;
1724 }
1725
1726 TimesOp setModificationTime(long mtime) {
1727 this.mtime = mtime;
1728 return this;
1729 }
1730
1731 TimesOp setAccessTime(long atime) {
1732 this.atime = atime;
1733 return this;
1734 }
1735
1736 @Override
1737 public
1738 void writeFields(DataOutputStream out) throws IOException {
1739 FSImageSerialization.writeString(path, out);
1740 FSImageSerialization.writeLong(mtime, out);
1741 FSImageSerialization.writeLong(atime, out);
1742 }
1743
1744 @Override
1745 void readFields(DataInputStream in, int logVersion)
1746 throws IOException {
1747 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1748 this.length = in.readInt();
1749 if (length != 3) {
1750 throw new IOException("Incorrect data format. " + "times operation.");
1751 }
1752 }
1753 this.path = FSImageSerialization.readString(in);
1754
1755 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1756 this.mtime = FSImageSerialization.readLong(in);
1757 this.atime = FSImageSerialization.readLong(in);
1758 } else {
1759 this.mtime = readLong(in);
1760 this.atime = readLong(in);
1761 }
1762 }
1763
1764 @Override
1765 public String toString() {
1766 StringBuilder builder = new StringBuilder();
1767 builder.append("TimesOp [length=");
1768 builder.append(length);
1769 builder.append(", path=");
1770 builder.append(path);
1771 builder.append(", mtime=");
1772 builder.append(mtime);
1773 builder.append(", atime=");
1774 builder.append(atime);
1775 builder.append(", opCode=");
1776 builder.append(opCode);
1777 builder.append(", txid=");
1778 builder.append(txid);
1779 builder.append("]");
1780 return builder.toString();
1781 }
1782
1783 @Override
1784 protected void toXml(ContentHandler contentHandler) throws SAXException {
1785 XMLUtils.addSaxString(contentHandler, "LENGTH",
1786 Integer.valueOf(length).toString());
1787 XMLUtils.addSaxString(contentHandler, "PATH", path);
1788 XMLUtils.addSaxString(contentHandler, "MTIME",
1789 Long.valueOf(mtime).toString());
1790 XMLUtils.addSaxString(contentHandler, "ATIME",
1791 Long.valueOf(atime).toString());
1792 }
1793
1794 @Override void fromXml(Stanza st) throws InvalidXmlException {
1795 this.length = Integer.valueOf(st.getValue("LENGTH"));
1796 this.path = st.getValue("PATH");
1797 this.mtime = Long.valueOf(st.getValue("MTIME"));
1798 this.atime = Long.valueOf(st.getValue("ATIME"));
1799 }
1800 }
1801
1802 /** {@literal @AtMostOnce} for {@link ClientProtocol#createSymlink} */
1803 static class SymlinkOp extends FSEditLogOp {
1804 int length;
1805 long inodeId;
1806 String path;
1807 String value;
1808 long mtime;
1809 long atime;
1810 PermissionStatus permissionStatus;
1811
1812 private SymlinkOp() {
1813 super(OP_SYMLINK);
1814 }
1815
1816 static SymlinkOp getInstance(OpInstanceCache cache) {
1817 return (SymlinkOp)cache.get(OP_SYMLINK);
1818 }
1819
1820 SymlinkOp setId(long inodeId) {
1821 this.inodeId = inodeId;
1822 return this;
1823 }
1824
1825 SymlinkOp setPath(String path) {
1826 this.path = path;
1827 return this;
1828 }
1829
1830 SymlinkOp setValue(String value) {
1831 this.value = value;
1832 return this;
1833 }
1834
1835 SymlinkOp setModificationTime(long mtime) {
1836 this.mtime = mtime;
1837 return this;
1838 }
1839
1840 SymlinkOp setAccessTime(long atime) {
1841 this.atime = atime;
1842 return this;
1843 }
1844
1845 SymlinkOp setPermissionStatus(PermissionStatus permissionStatus) {
1846 this.permissionStatus = permissionStatus;
1847 return this;
1848 }
1849
1850 @Override
1851 public void writeFields(DataOutputStream out) throws IOException {
1852 FSImageSerialization.writeLong(inodeId, out);
1853 FSImageSerialization.writeString(path, out);
1854 FSImageSerialization.writeString(value, out);
1855 FSImageSerialization.writeLong(mtime, out);
1856 FSImageSerialization.writeLong(atime, out);
1857 permissionStatus.write(out);
1858 writeRpcIds(rpcClientId, rpcCallId, out);
1859 }
1860
1861 @Override
1862 void readFields(DataInputStream in, int logVersion)
1863 throws IOException {
1864 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1865 this.length = in.readInt();
1866 if (this.length != 4) {
1867 throw new IOException("Incorrect data format. "
1868 + "symlink operation.");
1869 }
1870 }
1871 if (LayoutVersion.supports(Feature.ADD_INODE_ID, logVersion)) {
1872 this.inodeId = FSImageSerialization.readLong(in);
1873 } else {
1874 // This id should be updated when the editLogOp is applied
1875 this.inodeId = INodeId.GRANDFATHER_INODE_ID;
1876 }
1877 this.path = FSImageSerialization.readString(in);
1878 this.value = FSImageSerialization.readString(in);
1879
1880 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
1881 this.mtime = FSImageSerialization.readLong(in);
1882 this.atime = FSImageSerialization.readLong(in);
1883 } else {
1884 this.mtime = readLong(in);
1885 this.atime = readLong(in);
1886 }
1887 this.permissionStatus = PermissionStatus.read(in);
1888
1889 // read RPC ids if necessary
1890 readRpcIds(in, logVersion);
1891 }
1892
1893 @Override
1894 public String toString() {
1895 StringBuilder builder = new StringBuilder();
1896 builder.append("SymlinkOp [length=");
1897 builder.append(length);
1898 builder.append(", inodeId=");
1899 builder.append(inodeId);
1900 builder.append(", path=");
1901 builder.append(path);
1902 builder.append(", value=");
1903 builder.append(value);
1904 builder.append(", mtime=");
1905 builder.append(mtime);
1906 builder.append(", atime=");
1907 builder.append(atime);
1908 builder.append(", permissionStatus=");
1909 builder.append(permissionStatus);
1910 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
1911 builder.append(", opCode=");
1912 builder.append(opCode);
1913 builder.append(", txid=");
1914 builder.append(txid);
1915 builder.append("]");
1916 return builder.toString();
1917 }
1918
1919 @Override
1920 protected void toXml(ContentHandler contentHandler) throws SAXException {
1921 XMLUtils.addSaxString(contentHandler, "LENGTH",
1922 Integer.valueOf(length).toString());
1923 XMLUtils.addSaxString(contentHandler, "INODEID",
1924 Long.valueOf(inodeId).toString());
1925 XMLUtils.addSaxString(contentHandler, "PATH", path);
1926 XMLUtils.addSaxString(contentHandler, "VALUE", value);
1927 XMLUtils.addSaxString(contentHandler, "MTIME",
1928 Long.valueOf(mtime).toString());
1929 XMLUtils.addSaxString(contentHandler, "ATIME",
1930 Long.valueOf(atime).toString());
1931 FSEditLogOp.permissionStatusToXml(contentHandler, permissionStatus);
1932 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
1933 }
1934
1935 @Override
1936 void fromXml(Stanza st) throws InvalidXmlException {
1937 this.length = Integer.valueOf(st.getValue("LENGTH"));
1938 this.inodeId = Long.valueOf(st.getValue("INODEID"));
1939 this.path = st.getValue("PATH");
1940 this.value = st.getValue("VALUE");
1941 this.mtime = Long.valueOf(st.getValue("MTIME"));
1942 this.atime = Long.valueOf(st.getValue("ATIME"));
1943 this.permissionStatus =
1944 permissionStatusFromXml(st.getChildren("PERMISSION_STATUS").get(0));
1945
1946 readRpcIdsFromXml(st);
1947 }
1948 }
1949
1950 /** {@literal @AtMostOnce} for {@link ClientProtocol#rename2} */
1951 static class RenameOp extends FSEditLogOp {
1952 int length;
1953 String src;
1954 String dst;
1955 long timestamp;
1956 Rename[] options;
1957
1958 private RenameOp() {
1959 super(OP_RENAME);
1960 }
1961
1962 static RenameOp getInstance(OpInstanceCache cache) {
1963 return (RenameOp)cache.get(OP_RENAME);
1964 }
1965
1966 RenameOp setSource(String src) {
1967 this.src = src;
1968 return this;
1969 }
1970
1971 RenameOp setDestination(String dst) {
1972 this.dst = dst;
1973 return this;
1974 }
1975
1976 RenameOp setTimestamp(long timestamp) {
1977 this.timestamp = timestamp;
1978 return this;
1979 }
1980
1981 RenameOp setOptions(Rename[] options) {
1982 this.options = options;
1983 return this;
1984 }
1985
1986 @Override
1987 public
1988 void writeFields(DataOutputStream out) throws IOException {
1989 FSImageSerialization.writeString(src, out);
1990 FSImageSerialization.writeString(dst, out);
1991 FSImageSerialization.writeLong(timestamp, out);
1992 toBytesWritable(options).write(out);
1993 writeRpcIds(rpcClientId, rpcCallId, out);
1994 }
1995
1996 @Override
1997 void readFields(DataInputStream in, int logVersion)
1998 throws IOException {
1999 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
2000 this.length = in.readInt();
2001 if (this.length != 3) {
2002 throw new IOException("Incorrect data format. " + "Rename operation.");
2003 }
2004 }
2005 this.src = FSImageSerialization.readString(in);
2006 this.dst = FSImageSerialization.readString(in);
2007
2008 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
2009 this.timestamp = FSImageSerialization.readLong(in);
2010 } else {
2011 this.timestamp = readLong(in);
2012 }
2013 this.options = readRenameOptions(in);
2014
2015 // read RPC ids if necessary
2016 readRpcIds(in, logVersion);
2017 }
2018
2019 private static Rename[] readRenameOptions(DataInputStream in) throws IOException {
2020 BytesWritable writable = new BytesWritable();
2021 writable.readFields(in);
2022
2023 byte[] bytes = writable.getBytes();
2024 Rename[] options = new Rename[bytes.length];
2025
2026 for (int i = 0; i < bytes.length; i++) {
2027 options[i] = Rename.valueOf(bytes[i]);
2028 }
2029 return options;
2030 }
2031
2032 static BytesWritable toBytesWritable(Rename... options) {
2033 byte[] bytes = new byte[options.length];
2034 for (int i = 0; i < options.length; i++) {
2035 bytes[i] = options[i].value();
2036 }
2037 return new BytesWritable(bytes);
2038 }
2039
2040 @Override
2041 public String toString() {
2042 StringBuilder builder = new StringBuilder();
2043 builder.append("RenameOp [length=");
2044 builder.append(length);
2045 builder.append(", src=");
2046 builder.append(src);
2047 builder.append(", dst=");
2048 builder.append(dst);
2049 builder.append(", timestamp=");
2050 builder.append(timestamp);
2051 builder.append(", options=");
2052 builder.append(Arrays.toString(options));
2053 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
2054 builder.append(", opCode=");
2055 builder.append(opCode);
2056 builder.append(", txid=");
2057 builder.append(txid);
2058 builder.append("]");
2059 return builder.toString();
2060 }
2061
2062 @Override
2063 protected void toXml(ContentHandler contentHandler) throws SAXException {
2064 XMLUtils.addSaxString(contentHandler, "LENGTH",
2065 Integer.valueOf(length).toString());
2066 XMLUtils.addSaxString(contentHandler, "SRC", src);
2067 XMLUtils.addSaxString(contentHandler, "DST", dst);
2068 XMLUtils.addSaxString(contentHandler, "TIMESTAMP",
2069 Long.valueOf(timestamp).toString());
2070 StringBuilder bld = new StringBuilder();
2071 String prefix = "";
2072 for (Rename r : options) {
2073 bld.append(prefix).append(r.toString());
2074 prefix = "|";
2075 }
2076 XMLUtils.addSaxString(contentHandler, "OPTIONS", bld.toString());
2077 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
2078 }
2079
2080 @Override void fromXml(Stanza st) throws InvalidXmlException {
2081 this.length = Integer.valueOf(st.getValue("LENGTH"));
2082 this.src = st.getValue("SRC");
2083 this.dst = st.getValue("DST");
2084 this.timestamp = Long.valueOf(st.getValue("TIMESTAMP"));
2085 String opts = st.getValue("OPTIONS");
2086 String o[] = opts.split("\\|");
2087 this.options = new Rename[o.length];
2088 for (int i = 0; i < o.length; i++) {
2089 if (o[i].equals(""))
2090 continue;
2091 try {
2092 this.options[i] = Rename.valueOf(o[i]);
2093 } finally {
2094 if (this.options[i] == null) {
2095 System.err.println("error parsing Rename value: \"" + o[i] + "\"");
2096 }
2097 }
2098 }
2099 readRpcIdsFromXml(st);
2100 }
2101 }
2102
2103 /**
2104 * {@literal @Idempotent} for {@link ClientProtocol#recoverLease}. In the
2105 * meanwhile, startFile and appendFile both have their own corresponding
2106 * editlog op.
2107 */
2108 static class ReassignLeaseOp extends FSEditLogOp {
2109 String leaseHolder;
2110 String path;
2111 String newHolder;
2112
2113 private ReassignLeaseOp() {
2114 super(OP_REASSIGN_LEASE);
2115 }
2116
2117 static ReassignLeaseOp getInstance(OpInstanceCache cache) {
2118 return (ReassignLeaseOp)cache.get(OP_REASSIGN_LEASE);
2119 }
2120
2121 ReassignLeaseOp setLeaseHolder(String leaseHolder) {
2122 this.leaseHolder = leaseHolder;
2123 return this;
2124 }
2125
2126 ReassignLeaseOp setPath(String path) {
2127 this.path = path;
2128 return this;
2129 }
2130
2131 ReassignLeaseOp setNewHolder(String newHolder) {
2132 this.newHolder = newHolder;
2133 return this;
2134 }
2135
2136 @Override
2137 public
2138 void writeFields(DataOutputStream out) throws IOException {
2139 FSImageSerialization.writeString(leaseHolder, out);
2140 FSImageSerialization.writeString(path, out);
2141 FSImageSerialization.writeString(newHolder, out);
2142 }
2143
2144 @Override
2145 void readFields(DataInputStream in, int logVersion)
2146 throws IOException {
2147 this.leaseHolder = FSImageSerialization.readString(in);
2148 this.path = FSImageSerialization.readString(in);
2149 this.newHolder = FSImageSerialization.readString(in);
2150 }
2151
2152 @Override
2153 public String toString() {
2154 StringBuilder builder = new StringBuilder();
2155 builder.append("ReassignLeaseOp [leaseHolder=");
2156 builder.append(leaseHolder);
2157 builder.append(", path=");
2158 builder.append(path);
2159 builder.append(", newHolder=");
2160 builder.append(newHolder);
2161 builder.append(", opCode=");
2162 builder.append(opCode);
2163 builder.append(", txid=");
2164 builder.append(txid);
2165 builder.append("]");
2166 return builder.toString();
2167 }
2168
2169 @Override
2170 protected void toXml(ContentHandler contentHandler) throws SAXException {
2171 XMLUtils.addSaxString(contentHandler, "LEASEHOLDER", leaseHolder);
2172 XMLUtils.addSaxString(contentHandler, "PATH", path);
2173 XMLUtils.addSaxString(contentHandler, "NEWHOLDER", newHolder);
2174 }
2175
2176 @Override void fromXml(Stanza st) throws InvalidXmlException {
2177 this.leaseHolder = st.getValue("LEASEHOLDER");
2178 this.path = st.getValue("PATH");
2179 this.newHolder = st.getValue("NEWHOLDER");
2180 }
2181 }
2182
2183 /** {@literal @Idempotent} for {@link ClientProtocol#getDelegationToken} */
2184 static class GetDelegationTokenOp extends FSEditLogOp {
2185 DelegationTokenIdentifier token;
2186 long expiryTime;
2187
2188 private GetDelegationTokenOp() {
2189 super(OP_GET_DELEGATION_TOKEN);
2190 }
2191
2192 static GetDelegationTokenOp getInstance(OpInstanceCache cache) {
2193 return (GetDelegationTokenOp)cache.get(OP_GET_DELEGATION_TOKEN);
2194 }
2195
2196 GetDelegationTokenOp setDelegationTokenIdentifier(
2197 DelegationTokenIdentifier token) {
2198 this.token = token;
2199 return this;
2200 }
2201
2202 GetDelegationTokenOp setExpiryTime(long expiryTime) {
2203 this.expiryTime = expiryTime;
2204 return this;
2205 }
2206
2207 @Override
2208 public
2209 void writeFields(DataOutputStream out) throws IOException {
2210 token.write(out);
2211 FSImageSerialization.writeLong(expiryTime, out);
2212 }
2213
2214 @Override
2215 void readFields(DataInputStream in, int logVersion)
2216 throws IOException {
2217 this.token = new DelegationTokenIdentifier();
2218 this.token.readFields(in);
2219 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
2220 this.expiryTime = FSImageSerialization.readLong(in);
2221 } else {
2222 this.expiryTime = readLong(in);
2223 }
2224 }
2225
2226 @Override
2227 public String toString() {
2228 StringBuilder builder = new StringBuilder();
2229 builder.append("GetDelegationTokenOp [token=");
2230 builder.append(token);
2231 builder.append(", expiryTime=");
2232 builder.append(expiryTime);
2233 builder.append(", opCode=");
2234 builder.append(opCode);
2235 builder.append(", txid=");
2236 builder.append(txid);
2237 builder.append("]");
2238 return builder.toString();
2239 }
2240
2241 @Override
2242 protected void toXml(ContentHandler contentHandler) throws SAXException {
2243 FSEditLogOp.delegationTokenToXml(contentHandler, token);
2244 XMLUtils.addSaxString(contentHandler, "EXPIRY_TIME",
2245 Long.valueOf(expiryTime).toString());
2246 }
2247
2248 @Override void fromXml(Stanza st) throws InvalidXmlException {
2249 this.token = delegationTokenFromXml(st.getChildren(
2250 "DELEGATION_TOKEN_IDENTIFIER").get(0));
2251 this.expiryTime = Long.valueOf(st.getValue("EXPIRY_TIME"));
2252 }
2253 }
2254
2255 /** {@literal @Idempotent} for {@link ClientProtocol#renewDelegationToken} */
2256 static class RenewDelegationTokenOp extends FSEditLogOp {
2257 DelegationTokenIdentifier token;
2258 long expiryTime;
2259
2260 private RenewDelegationTokenOp() {
2261 super(OP_RENEW_DELEGATION_TOKEN);
2262 }
2263
2264 static RenewDelegationTokenOp getInstance(OpInstanceCache cache) {
2265 return (RenewDelegationTokenOp)cache.get(OP_RENEW_DELEGATION_TOKEN);
2266 }
2267
2268 RenewDelegationTokenOp setDelegationTokenIdentifier(
2269 DelegationTokenIdentifier token) {
2270 this.token = token;
2271 return this;
2272 }
2273
2274 RenewDelegationTokenOp setExpiryTime(long expiryTime) {
2275 this.expiryTime = expiryTime;
2276 return this;
2277 }
2278
2279 @Override
2280 public
2281 void writeFields(DataOutputStream out) throws IOException {
2282 token.write(out);
2283 FSImageSerialization.writeLong(expiryTime, out);
2284 }
2285
2286 @Override
2287 void readFields(DataInputStream in, int logVersion)
2288 throws IOException {
2289 this.token = new DelegationTokenIdentifier();
2290 this.token.readFields(in);
2291 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
2292 this.expiryTime = FSImageSerialization.readLong(in);
2293 } else {
2294 this.expiryTime = readLong(in);
2295 }
2296 }
2297
2298 @Override
2299 public String toString() {
2300 StringBuilder builder = new StringBuilder();
2301 builder.append("RenewDelegationTokenOp [token=");
2302 builder.append(token);
2303 builder.append(", expiryTime=");
2304 builder.append(expiryTime);
2305 builder.append(", opCode=");
2306 builder.append(opCode);
2307 builder.append(", txid=");
2308 builder.append(txid);
2309 builder.append("]");
2310 return builder.toString();
2311 }
2312
2313 @Override
2314 protected void toXml(ContentHandler contentHandler) throws SAXException {
2315 FSEditLogOp.delegationTokenToXml(contentHandler, token);
2316 XMLUtils.addSaxString(contentHandler, "EXPIRY_TIME",
2317 Long.valueOf(expiryTime).toString());
2318 }
2319
2320 @Override void fromXml(Stanza st) throws InvalidXmlException {
2321 this.token = delegationTokenFromXml(st.getChildren(
2322 "DELEGATION_TOKEN_IDENTIFIER").get(0));
2323 this.expiryTime = Long.valueOf(st.getValue("EXPIRY_TIME"));
2324 }
2325 }
2326
2327 /** {@literal @Idempotent} for {@link ClientProtocol#cancelDelegationToken} */
2328 static class CancelDelegationTokenOp extends FSEditLogOp {
2329 DelegationTokenIdentifier token;
2330
2331 private CancelDelegationTokenOp() {
2332 super(OP_CANCEL_DELEGATION_TOKEN);
2333 }
2334
2335 static CancelDelegationTokenOp getInstance(OpInstanceCache cache) {
2336 return (CancelDelegationTokenOp)cache.get(OP_CANCEL_DELEGATION_TOKEN);
2337 }
2338
2339 CancelDelegationTokenOp setDelegationTokenIdentifier(
2340 DelegationTokenIdentifier token) {
2341 this.token = token;
2342 return this;
2343 }
2344
2345 @Override
2346 public
2347 void writeFields(DataOutputStream out) throws IOException {
2348 token.write(out);
2349 }
2350
2351 @Override
2352 void readFields(DataInputStream in, int logVersion)
2353 throws IOException {
2354 this.token = new DelegationTokenIdentifier();
2355 this.token.readFields(in);
2356 }
2357
2358 @Override
2359 public String toString() {
2360 StringBuilder builder = new StringBuilder();
2361 builder.append("CancelDelegationTokenOp [token=");
2362 builder.append(token);
2363 builder.append(", opCode=");
2364 builder.append(opCode);
2365 builder.append(", txid=");
2366 builder.append(txid);
2367 builder.append("]");
2368 return builder.toString();
2369 }
2370
2371 @Override
2372 protected void toXml(ContentHandler contentHandler) throws SAXException {
2373 FSEditLogOp.delegationTokenToXml(contentHandler, token);
2374 }
2375
2376 @Override void fromXml(Stanza st) throws InvalidXmlException {
2377 this.token = delegationTokenFromXml(st.getChildren(
2378 "DELEGATION_TOKEN_IDENTIFIER").get(0));
2379 }
2380 }
2381
2382 static class UpdateMasterKeyOp extends FSEditLogOp {
2383 DelegationKey key;
2384
2385 private UpdateMasterKeyOp() {
2386 super(OP_UPDATE_MASTER_KEY);
2387 }
2388
2389 static UpdateMasterKeyOp getInstance(OpInstanceCache cache) {
2390 return (UpdateMasterKeyOp)cache.get(OP_UPDATE_MASTER_KEY);
2391 }
2392
2393 UpdateMasterKeyOp setDelegationKey(DelegationKey key) {
2394 this.key = key;
2395 return this;
2396 }
2397
2398 @Override
2399 public
2400 void writeFields(DataOutputStream out) throws IOException {
2401 key.write(out);
2402 }
2403
2404 @Override
2405 void readFields(DataInputStream in, int logVersion)
2406 throws IOException {
2407 this.key = new DelegationKey();
2408 this.key.readFields(in);
2409 }
2410
2411 @Override
2412 public String toString() {
2413 StringBuilder builder = new StringBuilder();
2414 builder.append("UpdateMasterKeyOp [key=");
2415 builder.append(key);
2416 builder.append(", opCode=");
2417 builder.append(opCode);
2418 builder.append(", txid=");
2419 builder.append(txid);
2420 builder.append("]");
2421 return builder.toString();
2422 }
2423
2424 @Override
2425 protected void toXml(ContentHandler contentHandler) throws SAXException {
2426 FSEditLogOp.delegationKeyToXml(contentHandler, key);
2427 }
2428
2429 @Override void fromXml(Stanza st) throws InvalidXmlException {
2430 this.key = delegationKeyFromXml(st.getChildren(
2431 "DELEGATION_KEY").get(0));
2432 }
2433 }
2434
2435 static class LogSegmentOp extends FSEditLogOp {
2436 private LogSegmentOp(FSEditLogOpCodes code) {
2437 super(code);
2438 assert code == OP_START_LOG_SEGMENT ||
2439 code == OP_END_LOG_SEGMENT : "Bad op: " + code;
2440 }
2441
2442 static LogSegmentOp getInstance(OpInstanceCache cache,
2443 FSEditLogOpCodes code) {
2444 return (LogSegmentOp)cache.get(code);
2445 }
2446
2447 @Override
2448 public void readFields(DataInputStream in, int logVersion)
2449 throws IOException {
2450 // no data stored in these ops yet
2451 }
2452
2453 @Override
2454 public
2455 void writeFields(DataOutputStream out) throws IOException {
2456 // no data stored
2457 }
2458
2459 @Override
2460 public String toString() {
2461 StringBuilder builder = new StringBuilder();
2462 builder.append("LogSegmentOp [opCode=");
2463 builder.append(opCode);
2464 builder.append(", txid=");
2465 builder.append(txid);
2466 builder.append("]");
2467 return builder.toString();
2468 }
2469
2470 @Override
2471 protected void toXml(ContentHandler contentHandler) throws SAXException {
2472 // no data stored
2473 }
2474
2475 @Override void fromXml(Stanza st) throws InvalidXmlException {
2476 // do nothing
2477 }
2478 }
2479
2480 static class InvalidOp extends FSEditLogOp {
2481 private InvalidOp() {
2482 super(OP_INVALID);
2483 }
2484
2485 static InvalidOp getInstance(OpInstanceCache cache) {
2486 return (InvalidOp)cache.get(OP_INVALID);
2487 }
2488
2489 @Override
2490 public
2491 void writeFields(DataOutputStream out) throws IOException {
2492 }
2493
2494 @Override
2495 void readFields(DataInputStream in, int logVersion)
2496 throws IOException {
2497 // nothing to read
2498 }
2499
2500 @Override
2501 public String toString() {
2502 StringBuilder builder = new StringBuilder();
2503 builder.append("InvalidOp [opCode=");
2504 builder.append(opCode);
2505 builder.append(", txid=");
2506 builder.append(txid);
2507 builder.append("]");
2508 return builder.toString();
2509 }
2510 @Override
2511 protected void toXml(ContentHandler contentHandler) throws SAXException {
2512 // no data stored
2513 }
2514
2515 @Override void fromXml(Stanza st) throws InvalidXmlException {
2516 // do nothing
2517 }
2518 }
2519
2520 /**
2521 * Operation corresponding to creating a snapshot.
2522 * {@literal @AtMostOnce} for {@link ClientProtocol#createSnapshot}.
2523 */
2524 static class CreateSnapshotOp extends FSEditLogOp {
2525 String snapshotRoot;
2526 String snapshotName;
2527
2528 public CreateSnapshotOp() {
2529 super(OP_CREATE_SNAPSHOT);
2530 }
2531
2532 static CreateSnapshotOp getInstance(OpInstanceCache cache) {
2533 return (CreateSnapshotOp)cache.get(OP_CREATE_SNAPSHOT);
2534 }
2535
2536 CreateSnapshotOp setSnapshotName(String snapName) {
2537 this.snapshotName = snapName;
2538 return this;
2539 }
2540
2541 public CreateSnapshotOp setSnapshotRoot(String snapRoot) {
2542 snapshotRoot = snapRoot;
2543 return this;
2544 }
2545
2546 @Override
2547 void readFields(DataInputStream in, int logVersion) throws IOException {
2548 snapshotRoot = FSImageSerialization.readString(in);
2549 snapshotName = FSImageSerialization.readString(in);
2550
2551 // read RPC ids if necessary
2552 readRpcIds(in, logVersion);
2553 }
2554
2555 @Override
2556 public void writeFields(DataOutputStream out) throws IOException {
2557 FSImageSerialization.writeString(snapshotRoot, out);
2558 FSImageSerialization.writeString(snapshotName, out);
2559 writeRpcIds(rpcClientId, rpcCallId, out);
2560 }
2561
2562 @Override
2563 protected void toXml(ContentHandler contentHandler) throws SAXException {
2564 XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
2565 XMLUtils.addSaxString(contentHandler, "SNAPSHOTNAME", snapshotName);
2566 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
2567 }
2568
2569 @Override
2570 void fromXml(Stanza st) throws InvalidXmlException {
2571 snapshotRoot = st.getValue("SNAPSHOTROOT");
2572 snapshotName = st.getValue("SNAPSHOTNAME");
2573
2574 readRpcIdsFromXml(st);
2575 }
2576
2577 @Override
2578 public String toString() {
2579 StringBuilder builder = new StringBuilder();
2580 builder.append("CreateSnapshotOp [snapshotRoot=");
2581 builder.append(snapshotRoot);
2582 builder.append(", snapshotName=");
2583 builder.append(snapshotName);
2584 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
2585 builder.append("]");
2586 return builder.toString();
2587 }
2588 }
2589
2590 /**
2591 * Operation corresponding to delete a snapshot.
2592 * {@literal @AtMostOnce} for {@link ClientProtocol#deleteSnapshot}.
2593 */
2594 static class DeleteSnapshotOp extends FSEditLogOp {
2595 String snapshotRoot;
2596 String snapshotName;
2597
2598 DeleteSnapshotOp() {
2599 super(OP_DELETE_SNAPSHOT);
2600 }
2601
2602 static DeleteSnapshotOp getInstance(OpInstanceCache cache) {
2603 return (DeleteSnapshotOp)cache.get(OP_DELETE_SNAPSHOT);
2604 }
2605
2606 DeleteSnapshotOp setSnapshotName(String snapName) {
2607 this.snapshotName = snapName;
2608 return this;
2609 }
2610
2611 DeleteSnapshotOp setSnapshotRoot(String snapRoot) {
2612 snapshotRoot = snapRoot;
2613 return this;
2614 }
2615
2616 @Override
2617 void readFields(DataInputStream in, int logVersion) throws IOException {
2618 snapshotRoot = FSImageSerialization.readString(in);
2619 snapshotName = FSImageSerialization.readString(in);
2620
2621 // read RPC ids if necessary
2622 readRpcIds(in, logVersion);
2623 }
2624
2625 @Override
2626 public void writeFields(DataOutputStream out) throws IOException {
2627 FSImageSerialization.writeString(snapshotRoot, out);
2628 FSImageSerialization.writeString(snapshotName, out);
2629 writeRpcIds(rpcClientId, rpcCallId, out);
2630 }
2631
2632 @Override
2633 protected void toXml(ContentHandler contentHandler) throws SAXException {
2634 XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
2635 XMLUtils.addSaxString(contentHandler, "SNAPSHOTNAME", snapshotName);
2636 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
2637 }
2638
2639 @Override
2640 void fromXml(Stanza st) throws InvalidXmlException {
2641 snapshotRoot = st.getValue("SNAPSHOTROOT");
2642 snapshotName = st.getValue("SNAPSHOTNAME");
2643
2644 readRpcIdsFromXml(st);
2645 }
2646
2647 @Override
2648 public String toString() {
2649 StringBuilder builder = new StringBuilder();
2650 builder.append("DeleteSnapshotOp [snapshotRoot=");
2651 builder.append(snapshotRoot);
2652 builder.append(", snapshotName=");
2653 builder.append(snapshotName);
2654 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
2655 builder.append("]");
2656 return builder.toString();
2657 }
2658 }
2659
2660 /**
2661 * Operation corresponding to rename a snapshot.
2662 * {@literal @AtMostOnce} for {@link ClientProtocol#renameSnapshot}.
2663 */
2664 static class RenameSnapshotOp extends FSEditLogOp {
2665 String snapshotRoot;
2666 String snapshotOldName;
2667 String snapshotNewName;
2668
2669 RenameSnapshotOp() {
2670 super(OP_RENAME_SNAPSHOT);
2671 }
2672
2673 static RenameSnapshotOp getInstance(OpInstanceCache cache) {
2674 return (RenameSnapshotOp) cache.get(OP_RENAME_SNAPSHOT);
2675 }
2676
2677 RenameSnapshotOp setSnapshotOldName(String snapshotOldName) {
2678 this.snapshotOldName = snapshotOldName;
2679 return this;
2680 }
2681
2682 RenameSnapshotOp setSnapshotNewName(String snapshotNewName) {
2683 this.snapshotNewName = snapshotNewName;
2684 return this;
2685 }
2686
2687 RenameSnapshotOp setSnapshotRoot(String snapshotRoot) {
2688 this.snapshotRoot = snapshotRoot;
2689 return this;
2690 }
2691
2692 @Override
2693 void readFields(DataInputStream in, int logVersion) throws IOException {
2694 snapshotRoot = FSImageSerialization.readString(in);
2695 snapshotOldName = FSImageSerialization.readString(in);
2696 snapshotNewName = FSImageSerialization.readString(in);
2697
2698 // read RPC ids if necessary
2699 readRpcIds(in, logVersion);
2700 }
2701
2702 @Override
2703 public void writeFields(DataOutputStream out) throws IOException {
2704 FSImageSerialization.writeString(snapshotRoot, out);
2705 FSImageSerialization.writeString(snapshotOldName, out);
2706 FSImageSerialization.writeString(snapshotNewName, out);
2707
2708 writeRpcIds(rpcClientId, rpcCallId, out);
2709 }
2710
2711 @Override
2712 protected void toXml(ContentHandler contentHandler) throws SAXException {
2713 XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
2714 XMLUtils.addSaxString(contentHandler, "SNAPSHOTOLDNAME", snapshotOldName);
2715 XMLUtils.addSaxString(contentHandler, "SNAPSHOTNEWNAME", snapshotNewName);
2716 appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
2717 }
2718
2719 @Override
2720 void fromXml(Stanza st) throws InvalidXmlException {
2721 snapshotRoot = st.getValue("SNAPSHOTROOT");
2722 snapshotOldName = st.getValue("SNAPSHOTOLDNAME");
2723 snapshotNewName = st.getValue("SNAPSHOTNEWNAME");
2724
2725 readRpcIdsFromXml(st);
2726 }
2727
2728 @Override
2729 public String toString() {
2730 StringBuilder builder = new StringBuilder();
2731 builder.append("RenameSnapshotOp [snapshotRoot=");
2732 builder.append(snapshotRoot);
2733 builder.append(", snapshotOldName=");
2734 builder.append(snapshotOldName);
2735 builder.append(", snapshotNewName=");
2736 builder.append(snapshotNewName);
2737 appendRpcIdsToString(builder, rpcClientId, rpcCallId);
2738 builder.append("]");
2739 return builder.toString();
2740 }
2741 }
2742
2743 /**
2744 * Operation corresponding to allow creating snapshot on a directory
2745 */
2746 static class AllowSnapshotOp extends FSEditLogOp { // @Idempotent
2747 String snapshotRoot;
2748
2749 public AllowSnapshotOp() {
2750 super(OP_ALLOW_SNAPSHOT);
2751 }
2752
2753 public AllowSnapshotOp(String snapRoot) {
2754 super(OP_ALLOW_SNAPSHOT);
2755 snapshotRoot = snapRoot;
2756 }
2757
2758 static AllowSnapshotOp getInstance(OpInstanceCache cache) {
2759 return (AllowSnapshotOp) cache.get(OP_ALLOW_SNAPSHOT);
2760 }
2761
2762 public AllowSnapshotOp setSnapshotRoot(String snapRoot) {
2763 snapshotRoot = snapRoot;
2764 return this;
2765 }
2766
2767 @Override
2768 void readFields(DataInputStream in, int logVersion) throws IOException {
2769 snapshotRoot = FSImageSerialization.readString(in);
2770 }
2771
2772 @Override
2773 public void writeFields(DataOutputStream out) throws IOException {
2774 FSImageSerialization.writeString(snapshotRoot, out);
2775 }
2776
2777 @Override
2778 protected void toXml(ContentHandler contentHandler) throws SAXException {
2779 XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
2780 }
2781
2782 @Override
2783 void fromXml(Stanza st) throws InvalidXmlException {
2784 snapshotRoot = st.getValue("SNAPSHOTROOT");
2785 }
2786
2787 @Override
2788 public String toString() {
2789 StringBuilder builder = new StringBuilder();
2790 builder.append("AllowSnapshotOp [snapshotRoot=");
2791 builder.append(snapshotRoot);
2792 builder.append("]");
2793 return builder.toString();
2794 }
2795 }
2796
2797 /**
2798 * Operation corresponding to disallow creating snapshot on a directory
2799 */
2800 static class DisallowSnapshotOp extends FSEditLogOp { // @Idempotent
2801 String snapshotRoot;
2802
2803 public DisallowSnapshotOp() {
2804 super(OP_DISALLOW_SNAPSHOT);
2805 }
2806
2807 public DisallowSnapshotOp(String snapRoot) {
2808 super(OP_DISALLOW_SNAPSHOT);
2809 snapshotRoot = snapRoot;
2810 }
2811
2812 static DisallowSnapshotOp getInstance(OpInstanceCache cache) {
2813 return (DisallowSnapshotOp) cache.get(OP_DISALLOW_SNAPSHOT);
2814 }
2815
2816 public DisallowSnapshotOp setSnapshotRoot(String snapRoot) {
2817 snapshotRoot = snapRoot;
2818 return this;
2819 }
2820
2821 @Override
2822 void readFields(DataInputStream in, int logVersion) throws IOException {
2823 snapshotRoot = FSImageSerialization.readString(in);
2824 }
2825
2826 @Override
2827 public void writeFields(DataOutputStream out) throws IOException {
2828 FSImageSerialization.writeString(snapshotRoot, out);
2829 }
2830
2831 @Override
2832 protected void toXml(ContentHandler contentHandler) throws SAXException {
2833 XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
2834 }
2835
2836 @Override
2837 void fromXml(Stanza st) throws InvalidXmlException {
2838 snapshotRoot = st.getValue("SNAPSHOTROOT");
2839 }
2840
2841 @Override
2842 public String toString() {
2843 StringBuilder builder = new StringBuilder();
2844 builder.append("DisallowSnapshotOp [snapshotRoot=");
2845 builder.append(snapshotRoot);
2846 builder.append("]");
2847 return builder.toString();
2848 }
2849 }
2850
2851 static private short readShort(DataInputStream in) throws IOException {
2852 return Short.parseShort(FSImageSerialization.readString(in));
2853 }
2854
2855 static private long readLong(DataInputStream in) throws IOException {
2856 return Long.parseLong(FSImageSerialization.readString(in));
2857 }
2858
2859 /**
2860 * A class to read in blocks stored in the old format. The only two
2861 * fields in the block were blockid and length.
2862 */
2863 static class BlockTwo implements Writable {
2864 long blkid;
2865 long len;
2866
2867 static { // register a ctor
2868 WritableFactories.setFactory
2869 (BlockTwo.class,
2870 new WritableFactory() {
2871 @Override
2872 public Writable newInstance() { return new BlockTwo(); }
2873 });
2874 }
2875
2876
2877 BlockTwo() {
2878 blkid = 0;
2879 len = 0;
2880 }
2881 /////////////////////////////////////
2882 // Writable
2883 /////////////////////////////////////
2884 @Override
2885 public void write(DataOutput out) throws IOException {
2886 out.writeLong(blkid);
2887 out.writeLong(len);
2888 }
2889
2890 @Override
2891 public void readFields(DataInput in) throws IOException {
2892 this.blkid = in.readLong();
2893 this.len = in.readLong();
2894 }
2895 }
2896
2897 /**
2898 * Class for writing editlog ops
2899 */
2900 public static class Writer {
2901 private final DataOutputBuffer buf;
2902 private final Checksum checksum;
2903
2904 public Writer(DataOutputBuffer out) {
2905 this.buf = out;
2906 this.checksum = new PureJavaCrc32();
2907 }
2908
2909 /**
2910 * Write an operation to the output stream
2911 *
2912 * @param op The operation to write
2913 * @throws IOException if an error occurs during writing.
2914 */
2915 public void writeOp(FSEditLogOp op) throws IOException {
2916 int start = buf.getLength();
2917 buf.writeByte(op.opCode.getOpCode());
2918 buf.writeLong(op.txid);
2919 op.writeFields(buf);
2920 int end = buf.getLength();
2921 checksum.reset();
2922 checksum.update(buf.getData(), start, end-start);
2923 int sum = (int)checksum.getValue();
2924 buf.writeInt(sum);
2925 }
2926 }
2927
2928 /**
2929 * Class for reading editlog ops from a stream
2930 */
2931 public static class Reader {
2932 private final DataInputStream in;
2933 private final StreamLimiter limiter;
2934 private final int logVersion;
2935 private final Checksum checksum;
2936 private final OpInstanceCache cache;
2937 private int maxOpSize;
2938
2939 /**
2940 * Construct the reader
2941 * @param in The stream to read from.
2942 * @param logVersion The version of the data coming from the stream.
2943 */
2944 @SuppressWarnings("deprecation")
2945 public Reader(DataInputStream in, StreamLimiter limiter,
2946 int logVersion) {
2947 this.logVersion = logVersion;
2948 if (LayoutVersion.supports(Feature.EDITS_CHESKUM, logVersion)) {
2949 this.checksum = new PureJavaCrc32();
2950 } else {
2951 this.checksum = null;
2952 }
2953
2954 if (this.checksum != null) {
2955 this.in = new DataInputStream(
2956 new CheckedInputStream(in, this.checksum));
2957 } else {
2958 this.in = in;
2959 }
2960 this.limiter = limiter;
2961 this.cache = new OpInstanceCache();
2962 this.maxOpSize = DFSConfigKeys.DFS_NAMENODE_MAX_OP_SIZE_DEFAULT;
2963 }
2964
2965 public void setMaxOpSize(int maxOpSize) {
2966 this.maxOpSize = maxOpSize;
2967 }
2968
2969 /**
2970 * Read an operation from the input stream.
2971 *
2972 * Note that the objects returned from this method may be re-used by future
2973 * calls to the same method.
2974 *
2975 * @param skipBrokenEdits If true, attempt to skip over damaged parts of
2976 * the input stream, rather than throwing an IOException
2977 * @return the operation read from the stream, or null at the end of the
2978 * file
2979 * @throws IOException on error. This function should only throw an
2980 * exception when skipBrokenEdits is false.
2981 */
2982 public FSEditLogOp readOp(boolean skipBrokenEdits) throws IOException {
2983 while (true) {
2984 try {
2985 return decodeOp();
2986 } catch (IOException e) {
2987 in.reset();
2988 if (!skipBrokenEdits) {
2989 throw e;
2990 }
2991 } catch (RuntimeException e) {
2992 // FSEditLogOp#decodeOp is not supposed to throw RuntimeException.
2993 // However, we handle it here for recovery mode, just to be more
2994 // robust.
2995 in.reset();
2996 if (!skipBrokenEdits) {
2997 throw e;
2998 }
2999 } catch (Throwable e) {
3000 in.reset();
3001 if (!skipBrokenEdits) {
3002 throw new IOException("got unexpected exception " +
3003 e.getMessage(), e);
3004 }
3005 }
3006 // Move ahead one byte and re-try the decode process.
3007 if (in.skip(1) < 1) {
3008 return null;
3009 }
3010 }
3011 }
3012
3013 private void verifyTerminator() throws IOException {
3014 /** The end of the edit log should contain only 0x00 or 0xff bytes.
3015 * If it contains other bytes, the log itself may be corrupt.
3016 * It is important to check this; if we don't, a stray OP_INVALID byte
3017 * could make us stop reading the edit log halfway through, and we'd never
3018 * know that we had lost data.
3019 */
3020 byte[] buf = new byte[4096];
3021 limiter.clearLimit();
3022 int numRead = -1, idx = 0;
3023 while (true) {
3024 try {
3025 numRead = -1;
3026 idx = 0;
3027 numRead = in.read(buf);
3028 if (numRead == -1) {
3029 return;
3030 }
3031 while (idx < numRead) {
3032 if ((buf[idx] != (byte)0) && (buf[idx] != (byte)-1)) {
3033 throw new IOException("Read extra bytes after " +
3034 "the terminator!");
3035 }
3036 idx++;
3037 }
3038 } finally {
3039 // After reading each group of bytes, we reposition the mark one
3040 // byte before the next group. Similarly, if there is an error, we
3041 // want to reposition the mark one byte before the error
3042 if (numRead != -1) {
3043 in.reset();
3044 IOUtils.skipFully(in, idx);
3045 in.mark(buf.length + 1);
3046 IOUtils.skipFully(in, 1);
3047 }
3048 }
3049 }
3050 }
3051
3052 /**
3053 * Read an opcode from the input stream.
3054 *
3055 * @return the opcode, or null on EOF.
3056 *
3057 * If an exception is thrown, the stream's mark will be set to the first
3058 * problematic byte. This usually means the beginning of the opcode.
3059 */
3060 private FSEditLogOp decodeOp() throws IOException {
3061 limiter.setLimit(maxOpSize);
3062 in.mark(maxOpSize);
3063
3064 if (checksum != null) {
3065 checksum.reset();
3066 }
3067
3068 byte opCodeByte;
3069 try {
3070 opCodeByte = in.readByte();
3071 } catch (EOFException eof) {
3072 // EOF at an opcode boundary is expected.
3073 return null;
3074 }
3075
3076 FSEditLogOpCodes opCode = FSEditLogOpCodes.fromByte(opCodeByte);
3077 if (opCode == OP_INVALID) {
3078 verifyTerminator();
3079 return null;
3080 }
3081
3082 FSEditLogOp op = cache.get(opCode);
3083 if (op == null) {
3084 throw new IOException("Read invalid opcode " + opCode);
3085 }
3086
3087 if (LayoutVersion.supports(Feature.STORED_TXIDS, logVersion)) {
3088 // Read the txid
3089 op.setTransactionId(in.readLong());
3090 } else {
3091 op.setTransactionId(HdfsConstants.INVALID_TXID);
3092 }
3093
3094 op.readFields(in, logVersion);
3095
3096 validateChecksum(in, checksum, op.txid);
3097 return op;
3098 }
3099
3100 /**
3101 * Validate a transaction's checksum
3102 */
3103 private void validateChecksum(DataInputStream in,
3104 Checksum checksum,
3105 long txid)
3106 throws IOException {
3107 if (checksum != null) {
3108 int calculatedChecksum = (int)checksum.getValue();
3109 int readChecksum = in.readInt(); // read in checksum
3110 if (readChecksum != calculatedChecksum) {
3111 throw new ChecksumException(
3112 "Transaction is corrupt. Calculated checksum is " +
3113 calculatedChecksum + " but read checksum " + readChecksum, txid);
3114 }
3115 }
3116 }
3117 }
3118
3119 public void outputToXml(ContentHandler contentHandler) throws SAXException {
3120 contentHandler.startElement("", "", "RECORD", new AttributesImpl());
3121 XMLUtils.addSaxString(contentHandler, "OPCODE", opCode.toString());
3122 contentHandler.startElement("", "", "DATA", new AttributesImpl());
3123 XMLUtils.addSaxString(contentHandler, "TXID", "" + txid);
3124 toXml(contentHandler);
3125 contentHandler.endElement("", "", "DATA");
3126 contentHandler.endElement("", "", "RECORD");
3127 }
3128
3129 protected abstract void toXml(ContentHandler contentHandler)
3130 throws SAXException;
3131
3132 abstract void fromXml(Stanza st) throws InvalidXmlException;
3133
3134 public void decodeXml(Stanza st) throws InvalidXmlException {
3135 this.txid = Long.valueOf(st.getValue("TXID"));
3136 fromXml(st);
3137 }
3138
3139 public static void blockToXml(ContentHandler contentHandler, Block block)
3140 throws SAXException {
3141 contentHandler.startElement("", "", "BLOCK", new AttributesImpl());
3142 XMLUtils.addSaxString(contentHandler, "BLOCK_ID",
3143 Long.valueOf(block.getBlockId()).toString());
3144 XMLUtils.addSaxString(contentHandler, "NUM_BYTES",
3145 Long.valueOf(block.getNumBytes()).toString());
3146 XMLUtils.addSaxString(contentHandler, "GENSTAMP",
3147 Long.valueOf(block.getGenerationStamp()).toString());
3148 contentHandler.endElement("", "", "BLOCK");
3149 }
3150
3151 public static Block blockFromXml(Stanza st)
3152 throws InvalidXmlException {
3153 long blockId = Long.valueOf(st.getValue("BLOCK_ID"));
3154 long numBytes = Long.valueOf(st.getValue("NUM_BYTES"));
3155 long generationStamp = Long.valueOf(st.getValue("GENSTAMP"));
3156 return new Block(blockId, numBytes, generationStamp);
3157 }
3158
3159 public static void delegationTokenToXml(ContentHandler contentHandler,
3160 DelegationTokenIdentifier token) throws SAXException {
3161 contentHandler.startElement("", "", "DELEGATION_TOKEN_IDENTIFIER", new AttributesImpl());
3162 XMLUtils.addSaxString(contentHandler, "KIND", token.getKind().toString());
3163 XMLUtils.addSaxString(contentHandler, "SEQUENCE_NUMBER",
3164 Integer.valueOf(token.getSequenceNumber()).toString());
3165 XMLUtils.addSaxString(contentHandler, "OWNER",
3166 token.getOwner().toString());
3167 XMLUtils.addSaxString(contentHandler, "RENEWER",
3168 token.getRenewer().toString());
3169 XMLUtils.addSaxString(contentHandler, "REALUSER",
3170 token.getRealUser().toString());
3171 XMLUtils.addSaxString(contentHandler, "ISSUE_DATE",
3172 Long.valueOf(token.getIssueDate()).toString());
3173 XMLUtils.addSaxString(contentHandler, "MAX_DATE",
3174 Long.valueOf(token.getMaxDate()).toString());
3175 XMLUtils.addSaxString(contentHandler, "MASTER_KEY_ID",
3176 Integer.valueOf(token.getMasterKeyId()).toString());
3177 contentHandler.endElement("", "", "DELEGATION_TOKEN_IDENTIFIER");
3178 }
3179
3180 public static DelegationTokenIdentifier delegationTokenFromXml(Stanza st)
3181 throws InvalidXmlException {
3182 String kind = st.getValue("KIND");
3183 if (!kind.equals(DelegationTokenIdentifier.
3184 HDFS_DELEGATION_KIND.toString())) {
3185 throw new InvalidXmlException("can't understand " +
3186 "DelegationTokenIdentifier KIND " + kind);
3187 }
3188 int seqNum = Integer.valueOf(st.getValue("SEQUENCE_NUMBER"));
3189 String owner = st.getValue("OWNER");
3190 String renewer = st.getValue("RENEWER");
3191 String realuser = st.getValue("REALUSER");
3192 long issueDate = Long.valueOf(st.getValue("ISSUE_DATE"));
3193 long maxDate = Long.valueOf(st.getValue("MAX_DATE"));
3194 int masterKeyId = Integer.valueOf(st.getValue("MASTER_KEY_ID"));
3195 DelegationTokenIdentifier token =
3196 new DelegationTokenIdentifier(new Text(owner),
3197 new Text(renewer), new Text(realuser));
3198 token.setSequenceNumber(seqNum);
3199 token.setIssueDate(issueDate);
3200 token.setMaxDate(maxDate);
3201 token.setMasterKeyId(masterKeyId);
3202 return token;
3203 }
3204
3205 public static void delegationKeyToXml(ContentHandler contentHandler,
3206 DelegationKey key) throws SAXException {
3207 contentHandler.startElement("", "", "DELEGATION_KEY", new AttributesImpl());
3208 XMLUtils.addSaxString(contentHandler, "KEY_ID",
3209 Integer.valueOf(key.getKeyId()).toString());
3210 XMLUtils.addSaxString(contentHandler, "EXPIRY_DATE",
3211 Long.valueOf(key.getExpiryDate()).toString());
3212 if (key.getEncodedKey() != null) {
3213 XMLUtils.addSaxString(contentHandler, "KEY",
3214 Hex.encodeHexString(key.getEncodedKey()));
3215 }
3216 contentHandler.endElement("", "", "DELEGATION_KEY");
3217 }
3218
3219 public static DelegationKey delegationKeyFromXml(Stanza st)
3220 throws InvalidXmlException {
3221 int keyId = Integer.valueOf(st.getValue("KEY_ID"));
3222 long expiryDate = Long.valueOf(st.getValue("EXPIRY_DATE"));
3223 byte key[] = null;
3224 try {
3225 key = Hex.decodeHex(st.getValue("KEY").toCharArray());
3226 } catch (DecoderException e) {
3227 throw new InvalidXmlException(e.toString());
3228 } catch (InvalidXmlException e) {
3229 }
3230 return new DelegationKey(keyId, expiryDate, key);
3231 }
3232
3233 public static void permissionStatusToXml(ContentHandler contentHandler,
3234 PermissionStatus perm) throws SAXException {
3235 contentHandler.startElement("", "", "PERMISSION_STATUS", new AttributesImpl());
3236 XMLUtils.addSaxString(contentHandler, "USERNAME", perm.getUserName());
3237 XMLUtils.addSaxString(contentHandler, "GROUPNAME", perm.getGroupName());
3238 XMLUtils.addSaxString(contentHandler, "MODE",
3239 Short.valueOf(perm.getPermission().toShort()).toString());
3240 contentHandler.endElement("", "", "PERMISSION_STATUS");
3241 }
3242
3243 public static PermissionStatus permissionStatusFromXml(Stanza st)
3244 throws InvalidXmlException {
3245 String username = st.getValue("USERNAME");
3246 String groupname = st.getValue("GROUPNAME");
3247 short mode = Short.valueOf(st.getValue("MODE"));
3248 return new PermissionStatus(username, groupname, new FsPermission(mode));
3249 }
3250 }