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