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