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