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