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