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