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 }