001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.server.namenode; 019 020import java.util.zip.CheckedInputStream; 021import java.util.zip.Checksum; 022import java.util.EnumMap; 023 024import org.apache.hadoop.fs.ChecksumException; 025import org.apache.hadoop.classification.InterfaceAudience; 026import org.apache.hadoop.classification.InterfaceStability; 027import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 028import org.apache.hadoop.fs.Options.Rename; 029import org.apache.hadoop.fs.permission.FsPermission; 030import org.apache.hadoop.fs.permission.PermissionStatus; 031import org.apache.hadoop.hdfs.protocol.Block; 032import org.apache.hadoop.hdfs.protocol.DatanodeID; 033import org.apache.hadoop.hdfs.protocol.LayoutVersion; 034import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature; 035import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor; 036import org.apache.hadoop.hdfs.server.common.GenerationStamp; 037import org.apache.hadoop.util.PureJavaCrc32; 038 039import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.*; 040import org.apache.hadoop.security.token.delegation.DelegationKey; 041import org.apache.hadoop.io.BytesWritable; 042import org.apache.hadoop.io.DataOutputBuffer; 043import org.apache.hadoop.io.ArrayWritable; 044import org.apache.hadoop.io.Writable; 045import org.apache.hadoop.io.WritableFactories; 046import org.apache.hadoop.io.WritableFactory; 047import org.apache.hadoop.hdfs.DeprecatedUTF8; 048 049import java.io.DataInput; 050import java.io.DataOutput; 051import java.io.DataInputStream; 052import java.io.DataOutputStream; 053import java.io.IOException; 054import java.io.EOFException; 055 056/** 057 * Helper classes for reading the ops from an InputStream. 058 * All ops derive from FSEditLogOp and are only 059 * instantiated from Reader#readOp() 060 */ 061@InterfaceAudience.Private 062@InterfaceStability.Unstable 063public abstract class FSEditLogOp { 064 final FSEditLogOpCodes opCode; 065 long txid; 066 067 068 @SuppressWarnings("deprecation") 069 private static ThreadLocal<EnumMap<FSEditLogOpCodes, FSEditLogOp>> opInstances = 070 new ThreadLocal<EnumMap<FSEditLogOpCodes, FSEditLogOp>>() { 071 @Override 072 protected EnumMap<FSEditLogOpCodes, FSEditLogOp> initialValue() { 073 EnumMap<FSEditLogOpCodes, FSEditLogOp> instances 074 = new EnumMap<FSEditLogOpCodes, FSEditLogOp>(FSEditLogOpCodes.class); 075 instances.put(OP_ADD, new AddOp()); 076 instances.put(OP_CLOSE, new CloseOp()); 077 instances.put(OP_SET_REPLICATION, new SetReplicationOp()); 078 instances.put(OP_CONCAT_DELETE, new ConcatDeleteOp()); 079 instances.put(OP_RENAME_OLD, new RenameOldOp()); 080 instances.put(OP_DELETE, new DeleteOp()); 081 instances.put(OP_MKDIR, new MkdirOp()); 082 instances.put(OP_SET_GENSTAMP, new SetGenstampOp()); 083 instances.put(OP_DATANODE_ADD, new DatanodeAddOp()); 084 instances.put(OP_DATANODE_REMOVE, new DatanodeRemoveOp()); 085 instances.put(OP_SET_PERMISSIONS, new SetPermissionsOp()); 086 instances.put(OP_SET_OWNER, new SetOwnerOp()); 087 instances.put(OP_SET_NS_QUOTA, new SetNSQuotaOp()); 088 instances.put(OP_CLEAR_NS_QUOTA, new ClearNSQuotaOp()); 089 instances.put(OP_SET_QUOTA, new SetQuotaOp()); 090 instances.put(OP_TIMES, new TimesOp()); 091 instances.put(OP_SYMLINK, new SymlinkOp()); 092 instances.put(OP_RENAME, new RenameOp()); 093 instances.put(OP_REASSIGN_LEASE, new ReassignLeaseOp()); 094 instances.put(OP_GET_DELEGATION_TOKEN, new GetDelegationTokenOp()); 095 instances.put(OP_RENEW_DELEGATION_TOKEN, new RenewDelegationTokenOp()); 096 instances.put(OP_CANCEL_DELEGATION_TOKEN, 097 new CancelDelegationTokenOp()); 098 instances.put(OP_UPDATE_MASTER_KEY, new UpdateMasterKeyOp()); 099 instances.put(OP_START_LOG_SEGMENT, 100 new LogSegmentOp(OP_START_LOG_SEGMENT)); 101 instances.put(OP_END_LOG_SEGMENT, 102 new LogSegmentOp(OP_END_LOG_SEGMENT)); 103 return instances; 104 } 105 }; 106 107 /** 108 * Constructor for an EditLog Op. EditLog ops cannot be constructed 109 * directly, but only through Reader#readOp. 110 */ 111 private FSEditLogOp(FSEditLogOpCodes opCode) { 112 this.opCode = opCode; 113 this.txid = 0; 114 } 115 116 public void setTransactionId(long txid) { 117 this.txid = txid; 118 } 119 120 abstract void readFields(DataInputStream in, int logVersion) 121 throws IOException; 122 123 abstract void writeFields(DataOutputStream out) 124 throws IOException; 125 126 @SuppressWarnings("unchecked") 127 static abstract class AddCloseOp extends FSEditLogOp { 128 int length; 129 String path; 130 short replication; 131 long mtime; 132 long atime; 133 long blockSize; 134 Block[] blocks; 135 PermissionStatus permissions; 136 String clientName; 137 String clientMachine; 138 //final DatanodeDescriptor[] dataNodeDescriptors; UNUSED 139 140 private AddCloseOp(FSEditLogOpCodes opCode) { 141 super(opCode); 142 assert(opCode == OP_ADD || opCode == OP_CLOSE); 143 } 144 145 <T extends AddCloseOp> T setPath(String path) { 146 this.path = path; 147 return (T)this; 148 } 149 150 <T extends AddCloseOp> T setReplication(short replication) { 151 this.replication = replication; 152 return (T)this; 153 } 154 155 <T extends AddCloseOp> T setModificationTime(long mtime) { 156 this.mtime = mtime; 157 return (T)this; 158 } 159 160 <T extends AddCloseOp> T setAccessTime(long atime) { 161 this.atime = atime; 162 return (T)this; 163 } 164 165 <T extends AddCloseOp> T setBlockSize(long blockSize) { 166 this.blockSize = blockSize; 167 return (T)this; 168 } 169 170 <T extends AddCloseOp> T setBlocks(Block[] blocks) { 171 this.blocks = blocks; 172 return (T)this; 173 } 174 175 <T extends AddCloseOp> T setPermissionStatus(PermissionStatus permissions) { 176 this.permissions = permissions; 177 return (T)this; 178 } 179 180 <T extends AddCloseOp> T setClientName(String clientName) { 181 this.clientName = clientName; 182 return (T)this; 183 } 184 185 <T extends AddCloseOp> T setClientMachine(String clientMachine) { 186 this.clientMachine = clientMachine; 187 return (T)this; 188 } 189 190 @Override 191 void writeFields(DataOutputStream out) throws IOException { 192 FSImageSerialization.writeString(path, out); 193 FSImageSerialization.writeShort(replication, out); 194 FSImageSerialization.writeLong(mtime, out); 195 FSImageSerialization.writeLong(atime, out); 196 FSImageSerialization.writeLong(blockSize, out); 197 new ArrayWritable(Block.class, blocks).write(out); 198 permissions.write(out); 199 200 if (this.opCode == OP_ADD) { 201 FSImageSerialization.writeString(clientName,out); 202 FSImageSerialization.writeString(clientMachine,out); 203 } 204 } 205 206 @Override 207 void readFields(DataInputStream in, int logVersion) 208 throws IOException { 209 // versions > 0 support per file replication 210 // get name and replication 211 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 212 this.length = in.readInt(); 213 } 214 if (-7 == logVersion && length != 3|| 215 -17 < logVersion && logVersion < -7 && length != 4 || 216 (logVersion <= -17 && length != 5 && !LayoutVersion.supports( 217 Feature.EDITLOG_OP_OPTIMIZATION, logVersion))) { 218 throw new IOException("Incorrect data format." + 219 " logVersion is " + logVersion + 220 " but writables.length is " + 221 length + ". "); 222 } 223 this.path = FSImageSerialization.readString(in); 224 225 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 226 this.replication = FSImageSerialization.readShort(in); 227 this.mtime = FSImageSerialization.readLong(in); 228 } else { 229 this.replication = readShort(in); 230 this.mtime = readLong(in); 231 } 232 233 if (LayoutVersion.supports(Feature.FILE_ACCESS_TIME, logVersion)) { 234 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 235 this.atime = FSImageSerialization.readLong(in); 236 } else { 237 this.atime = readLong(in); 238 } 239 } else { 240 this.atime = 0; 241 } 242 if (logVersion < -7) { 243 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 244 this.blockSize = FSImageSerialization.readLong(in); 245 } else { 246 this.blockSize = readLong(in); 247 } 248 } else { 249 this.blockSize = 0; 250 } 251 252 // get blocks 253 this.blocks = readBlocks(in, logVersion); 254 255 if (logVersion <= -11) { 256 this.permissions = PermissionStatus.read(in); 257 } else { 258 this.permissions = null; 259 } 260 261 // clientname, clientMachine and block locations of last block. 262 if (this.opCode == OP_ADD && logVersion <= -12) { 263 this.clientName = FSImageSerialization.readString(in); 264 this.clientMachine = FSImageSerialization.readString(in); 265 if (-13 <= logVersion) { 266 readDatanodeDescriptorArray(in); 267 } 268 } else { 269 this.clientName = ""; 270 this.clientMachine = ""; 271 } 272 } 273 274 /** This method is defined for compatibility reason. */ 275 private static DatanodeDescriptor[] readDatanodeDescriptorArray(DataInput in) 276 throws IOException { 277 DatanodeDescriptor[] locations = new DatanodeDescriptor[in.readInt()]; 278 for (int i = 0; i < locations.length; i++) { 279 locations[i] = new DatanodeDescriptor(); 280 locations[i].readFieldsFromFSEditLog(in); 281 } 282 return locations; 283 } 284 285 private static Block[] readBlocks( 286 DataInputStream in, 287 int logVersion) throws IOException { 288 int numBlocks = in.readInt(); 289 Block[] blocks = new Block[numBlocks]; 290 for (int i = 0; i < numBlocks; i++) { 291 Block blk = new Block(); 292 if (logVersion <= -14) { 293 blk.readFields(in); 294 } else { 295 BlockTwo oldblk = new BlockTwo(); 296 oldblk.readFields(in); 297 blk.set(oldblk.blkid, oldblk.len, 298 GenerationStamp.GRANDFATHER_GENERATION_STAMP); 299 } 300 blocks[i] = blk; 301 } 302 return blocks; 303 } 304 } 305 306 static class AddOp extends AddCloseOp { 307 private AddOp() { 308 super(OP_ADD); 309 } 310 311 static AddOp getInstance() { 312 return (AddOp)opInstances.get().get(OP_ADD); 313 } 314 } 315 316 static class CloseOp extends AddCloseOp { 317 private CloseOp() { 318 super(OP_CLOSE); 319 } 320 321 static CloseOp getInstance() { 322 return (CloseOp)opInstances.get().get(OP_CLOSE); 323 } 324 } 325 326 static class SetReplicationOp extends FSEditLogOp { 327 String path; 328 short replication; 329 330 private SetReplicationOp() { 331 super(OP_SET_REPLICATION); 332 } 333 334 static SetReplicationOp getInstance() { 335 return (SetReplicationOp)opInstances.get() 336 .get(OP_SET_REPLICATION); 337 } 338 339 SetReplicationOp setPath(String path) { 340 this.path = path; 341 return this; 342 } 343 344 SetReplicationOp setReplication(short replication) { 345 this.replication = replication; 346 return this; 347 } 348 349 @Override 350 void writeFields(DataOutputStream out) throws IOException { 351 FSImageSerialization.writeString(path, out); 352 FSImageSerialization.writeShort(replication, out); 353 } 354 355 @Override 356 void readFields(DataInputStream in, int logVersion) 357 throws IOException { 358 this.path = FSImageSerialization.readString(in); 359 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 360 this.replication = FSImageSerialization.readShort(in); 361 } else { 362 this.replication = readShort(in); 363 } 364 } 365 } 366 367 static class ConcatDeleteOp extends FSEditLogOp { 368 int length; 369 String trg; 370 String[] srcs; 371 long timestamp; 372 373 private ConcatDeleteOp() { 374 super(OP_CONCAT_DELETE); 375 } 376 377 static ConcatDeleteOp getInstance() { 378 return (ConcatDeleteOp)opInstances.get() 379 .get(OP_CONCAT_DELETE); 380 } 381 382 ConcatDeleteOp setTarget(String trg) { 383 this.trg = trg; 384 return this; 385 } 386 387 ConcatDeleteOp setSources(String[] srcs) { 388 this.srcs = srcs; 389 return this; 390 } 391 392 ConcatDeleteOp setTimestamp(long timestamp) { 393 this.timestamp = timestamp; 394 return this; 395 } 396 397 @Override 398 void writeFields(DataOutputStream out) throws IOException { 399 FSImageSerialization.writeString(trg, out); 400 401 DeprecatedUTF8 info[] = new DeprecatedUTF8[srcs.length]; 402 int idx = 0; 403 for(int i=0; i<srcs.length; i++) { 404 info[idx++] = new DeprecatedUTF8(srcs[i]); 405 } 406 new ArrayWritable(DeprecatedUTF8.class, info).write(out); 407 408 FSImageSerialization.writeLong(timestamp, out); 409 } 410 411 @Override 412 void readFields(DataInputStream in, int logVersion) 413 throws IOException { 414 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 415 this.length = in.readInt(); 416 if (length < 3) { // trg, srcs.., timestamp 417 throw new IOException("Incorrect data format. " 418 + "Concat delete operation."); 419 } 420 } 421 this.trg = FSImageSerialization.readString(in); 422 int srcSize = 0; 423 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 424 srcSize = in.readInt(); 425 } else { 426 srcSize = this.length - 1 - 1; // trg and timestamp 427 } 428 this.srcs = new String [srcSize]; 429 for(int i=0; i<srcSize;i++) { 430 srcs[i]= FSImageSerialization.readString(in); 431 } 432 433 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 434 this.timestamp = FSImageSerialization.readLong(in); 435 } else { 436 this.timestamp = readLong(in); 437 } 438 } 439 } 440 441 static class RenameOldOp extends FSEditLogOp { 442 int length; 443 String src; 444 String dst; 445 long timestamp; 446 447 private RenameOldOp() { 448 super(OP_RENAME_OLD); 449 } 450 451 static RenameOldOp getInstance() { 452 return (RenameOldOp)opInstances.get() 453 .get(OP_RENAME_OLD); 454 } 455 456 RenameOldOp setSource(String src) { 457 this.src = src; 458 return this; 459 } 460 461 RenameOldOp setDestination(String dst) { 462 this.dst = dst; 463 return this; 464 } 465 466 RenameOldOp setTimestamp(long timestamp) { 467 this.timestamp = timestamp; 468 return this; 469 } 470 471 @Override 472 void writeFields(DataOutputStream out) throws IOException { 473 FSImageSerialization.writeString(src, out); 474 FSImageSerialization.writeString(dst, out); 475 FSImageSerialization.writeLong(timestamp, out); 476 } 477 478 @Override 479 void readFields(DataInputStream in, int logVersion) 480 throws IOException { 481 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 482 this.length = in.readInt(); 483 if (this.length != 3) { 484 throw new IOException("Incorrect data format. " 485 + "Old rename operation."); 486 } 487 } 488 this.src = FSImageSerialization.readString(in); 489 this.dst = FSImageSerialization.readString(in); 490 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 491 this.timestamp = FSImageSerialization.readLong(in); 492 } else { 493 this.timestamp = readLong(in); 494 } 495 } 496 } 497 498 static class DeleteOp extends FSEditLogOp { 499 int length; 500 String path; 501 long timestamp; 502 503 private DeleteOp() { 504 super(OP_DELETE); 505 } 506 507 static DeleteOp getInstance() { 508 return (DeleteOp)opInstances.get() 509 .get(OP_DELETE); 510 } 511 512 DeleteOp setPath(String path) { 513 this.path = path; 514 return this; 515 } 516 517 DeleteOp setTimestamp(long timestamp) { 518 this.timestamp = timestamp; 519 return this; 520 } 521 522 @Override 523 void writeFields(DataOutputStream out) throws IOException { 524 FSImageSerialization.writeString(path, out); 525 FSImageSerialization.writeLong(timestamp, out); 526 } 527 528 @Override 529 void readFields(DataInputStream in, int logVersion) 530 throws IOException { 531 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 532 this.length = in.readInt(); 533 if (this.length != 2) { 534 throw new IOException("Incorrect data format. " + "delete operation."); 535 } 536 } 537 this.path = FSImageSerialization.readString(in); 538 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 539 this.timestamp = FSImageSerialization.readLong(in); 540 } else { 541 this.timestamp = readLong(in); 542 } 543 } 544 } 545 546 static class MkdirOp extends FSEditLogOp { 547 int length; 548 String path; 549 long timestamp; 550 PermissionStatus permissions; 551 552 private MkdirOp() { 553 super(OP_MKDIR); 554 } 555 556 static MkdirOp getInstance() { 557 return (MkdirOp)opInstances.get() 558 .get(OP_MKDIR); 559 } 560 561 MkdirOp setPath(String path) { 562 this.path = path; 563 return this; 564 } 565 566 MkdirOp setTimestamp(long timestamp) { 567 this.timestamp = timestamp; 568 return this; 569 } 570 571 MkdirOp setPermissionStatus(PermissionStatus permissions) { 572 this.permissions = permissions; 573 return this; 574 } 575 576 @Override 577 void writeFields(DataOutputStream out) throws IOException { 578 FSImageSerialization.writeString(path, out); 579 FSImageSerialization.writeLong(timestamp, out); // mtime 580 FSImageSerialization.writeLong(timestamp, out); // atime, unused at this 581 permissions.write(out); 582 } 583 584 @Override 585 void readFields(DataInputStream in, int logVersion) 586 throws IOException { 587 588 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 589 this.length = in.readInt(); 590 } 591 if (-17 < logVersion && length != 2 || 592 logVersion <= -17 && length != 3 593 && !LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 594 throw new IOException("Incorrect data format. " 595 + "Mkdir operation."); 596 } 597 this.path = FSImageSerialization.readString(in); 598 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 599 this.timestamp = FSImageSerialization.readLong(in); 600 } else { 601 this.timestamp = readLong(in); 602 } 603 604 // The disk format stores atimes for directories as well. 605 // However, currently this is not being updated/used because of 606 // performance reasons. 607 if (LayoutVersion.supports(Feature.FILE_ACCESS_TIME, logVersion)) { 608 /* unused this.atime = */ 609 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 610 FSImageSerialization.readLong(in); 611 } else { 612 readLong(in); 613 } 614 } 615 616 if (logVersion <= -11) { 617 this.permissions = PermissionStatus.read(in); 618 } else { 619 this.permissions = null; 620 } 621 } 622 } 623 624 static class SetGenstampOp extends FSEditLogOp { 625 long genStamp; 626 627 private SetGenstampOp() { 628 super(OP_SET_GENSTAMP); 629 } 630 631 static SetGenstampOp getInstance() { 632 return (SetGenstampOp)opInstances.get() 633 .get(OP_SET_GENSTAMP); 634 } 635 636 SetGenstampOp setGenerationStamp(long genStamp) { 637 this.genStamp = genStamp; 638 return this; 639 } 640 641 @Override 642 void writeFields(DataOutputStream out) throws IOException { 643 FSImageSerialization.writeLong(genStamp, out); 644 } 645 646 @Override 647 void readFields(DataInputStream in, int logVersion) 648 throws IOException { 649 this.genStamp = FSImageSerialization.readLong(in); 650 } 651 } 652 653 @SuppressWarnings("deprecation") 654 static class DatanodeAddOp extends FSEditLogOp { 655 private DatanodeAddOp() { 656 super(OP_DATANODE_ADD); 657 } 658 659 static DatanodeAddOp getInstance() { 660 return (DatanodeAddOp)opInstances.get() 661 .get(OP_DATANODE_ADD); 662 } 663 664 @Override 665 void writeFields(DataOutputStream out) throws IOException { 666 throw new IOException("Deprecated, should not write"); 667 } 668 669 @Override 670 void readFields(DataInputStream in, int logVersion) 671 throws IOException { 672 //Datanodes are not persistent any more. 673 FSImageSerialization.DatanodeImage.skipOne(in); 674 } 675 } 676 677 @SuppressWarnings("deprecation") 678 static class DatanodeRemoveOp extends FSEditLogOp { 679 private DatanodeRemoveOp() { 680 super(OP_DATANODE_REMOVE); 681 } 682 683 static DatanodeRemoveOp getInstance() { 684 return (DatanodeRemoveOp)opInstances.get() 685 .get(OP_DATANODE_REMOVE); 686 } 687 688 @Override 689 void writeFields(DataOutputStream out) throws IOException { 690 throw new IOException("Deprecated, should not write"); 691 } 692 693 @Override 694 void readFields(DataInputStream in, int logVersion) 695 throws IOException { 696 DatanodeID nodeID = new DatanodeID(); 697 nodeID.readFields(in); 698 //Datanodes are not persistent any more. 699 } 700 } 701 702 static class SetPermissionsOp extends FSEditLogOp { 703 String src; 704 FsPermission permissions; 705 706 private SetPermissionsOp() { 707 super(OP_SET_PERMISSIONS); 708 } 709 710 static SetPermissionsOp getInstance() { 711 return (SetPermissionsOp)opInstances.get() 712 .get(OP_SET_PERMISSIONS); 713 } 714 715 SetPermissionsOp setSource(String src) { 716 this.src = src; 717 return this; 718 } 719 720 SetPermissionsOp setPermissions(FsPermission permissions) { 721 this.permissions = permissions; 722 return this; 723 } 724 725 @Override 726 void writeFields(DataOutputStream out) throws IOException { 727 FSImageSerialization.writeString(src, out); 728 permissions.write(out); 729 } 730 731 @Override 732 void readFields(DataInputStream in, int logVersion) 733 throws IOException { 734 this.src = FSImageSerialization.readString(in); 735 this.permissions = FsPermission.read(in); 736 } 737 } 738 739 static class SetOwnerOp extends FSEditLogOp { 740 String src; 741 String username; 742 String groupname; 743 744 private SetOwnerOp() { 745 super(OP_SET_OWNER); 746 } 747 748 static SetOwnerOp getInstance() { 749 return (SetOwnerOp)opInstances.get() 750 .get(OP_SET_OWNER); 751 } 752 753 SetOwnerOp setSource(String src) { 754 this.src = src; 755 return this; 756 } 757 758 SetOwnerOp setUser(String username) { 759 this.username = username; 760 return this; 761 } 762 763 SetOwnerOp setGroup(String groupname) { 764 this.groupname = groupname; 765 return this; 766 } 767 768 @Override 769 void writeFields(DataOutputStream out) throws IOException { 770 FSImageSerialization.writeString(src, out); 771 FSImageSerialization.writeString(username == null ? "" : username, out); 772 FSImageSerialization.writeString(groupname == null ? "" : groupname, out); 773 } 774 775 @Override 776 void readFields(DataInputStream in, int logVersion) 777 throws IOException { 778 this.src = FSImageSerialization.readString(in); 779 this.username = FSImageSerialization.readString_EmptyAsNull(in); 780 this.groupname = FSImageSerialization.readString_EmptyAsNull(in); 781 } 782 } 783 784 static class SetNSQuotaOp extends FSEditLogOp { 785 String src; 786 long nsQuota; 787 788 private SetNSQuotaOp() { 789 super(OP_SET_NS_QUOTA); 790 } 791 792 static SetNSQuotaOp getInstance() { 793 return (SetNSQuotaOp)opInstances.get() 794 .get(OP_SET_NS_QUOTA); 795 } 796 797 @Override 798 void writeFields(DataOutputStream out) throws IOException { 799 throw new IOException("Deprecated"); 800 } 801 802 @Override 803 void readFields(DataInputStream in, int logVersion) 804 throws IOException { 805 this.src = FSImageSerialization.readString(in); 806 this.nsQuota = FSImageSerialization.readLong(in); 807 } 808 } 809 810 static class ClearNSQuotaOp extends FSEditLogOp { 811 String src; 812 813 private ClearNSQuotaOp() { 814 super(OP_CLEAR_NS_QUOTA); 815 } 816 817 static ClearNSQuotaOp getInstance() { 818 return (ClearNSQuotaOp)opInstances.get() 819 .get(OP_CLEAR_NS_QUOTA); 820 } 821 822 @Override 823 void writeFields(DataOutputStream out) throws IOException { 824 throw new IOException("Deprecated"); 825 } 826 827 @Override 828 void readFields(DataInputStream in, int logVersion) 829 throws IOException { 830 this.src = FSImageSerialization.readString(in); 831 } 832 } 833 834 static class SetQuotaOp extends FSEditLogOp { 835 String src; 836 long nsQuota; 837 long dsQuota; 838 839 private SetQuotaOp() { 840 super(OP_SET_QUOTA); 841 } 842 843 static SetQuotaOp getInstance() { 844 return (SetQuotaOp)opInstances.get() 845 .get(OP_SET_QUOTA); 846 } 847 848 SetQuotaOp setSource(String src) { 849 this.src = src; 850 return this; 851 } 852 853 SetQuotaOp setNSQuota(long nsQuota) { 854 this.nsQuota = nsQuota; 855 return this; 856 } 857 858 SetQuotaOp setDSQuota(long dsQuota) { 859 this.dsQuota = dsQuota; 860 return this; 861 } 862 863 @Override 864 void writeFields(DataOutputStream out) throws IOException { 865 FSImageSerialization.writeString(src, out); 866 FSImageSerialization.writeLong(nsQuota, out); 867 FSImageSerialization.writeLong(dsQuota, out); 868 } 869 870 @Override 871 void readFields(DataInputStream in, int logVersion) 872 throws IOException { 873 this.src = FSImageSerialization.readString(in); 874 this.nsQuota = FSImageSerialization.readLong(in); 875 this.dsQuota = FSImageSerialization.readLong(in); 876 } 877 } 878 879 static class TimesOp extends FSEditLogOp { 880 int length; 881 String path; 882 long mtime; 883 long atime; 884 885 private TimesOp() { 886 super(OP_TIMES); 887 } 888 889 static TimesOp getInstance() { 890 return (TimesOp)opInstances.get() 891 .get(OP_TIMES); 892 } 893 894 TimesOp setPath(String path) { 895 this.path = path; 896 return this; 897 } 898 899 TimesOp setModificationTime(long mtime) { 900 this.mtime = mtime; 901 return this; 902 } 903 904 TimesOp setAccessTime(long atime) { 905 this.atime = atime; 906 return this; 907 } 908 909 @Override 910 void writeFields(DataOutputStream out) throws IOException { 911 FSImageSerialization.writeString(path, out); 912 FSImageSerialization.writeLong(mtime, out); 913 FSImageSerialization.writeLong(atime, out); 914 } 915 916 @Override 917 void readFields(DataInputStream in, int logVersion) 918 throws IOException { 919 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 920 this.length = in.readInt(); 921 if (length != 3) { 922 throw new IOException("Incorrect data format. " + "times operation."); 923 } 924 } 925 this.path = FSImageSerialization.readString(in); 926 927 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 928 this.mtime = FSImageSerialization.readLong(in); 929 this.atime = FSImageSerialization.readLong(in); 930 } else { 931 this.mtime = readLong(in); 932 this.atime = readLong(in); 933 } 934 } 935 } 936 937 static class SymlinkOp extends FSEditLogOp { 938 int length; 939 String path; 940 String value; 941 long mtime; 942 long atime; 943 PermissionStatus permissionStatus; 944 945 private SymlinkOp() { 946 super(OP_SYMLINK); 947 } 948 949 static SymlinkOp getInstance() { 950 return (SymlinkOp)opInstances.get() 951 .get(OP_SYMLINK); 952 } 953 954 SymlinkOp setPath(String path) { 955 this.path = path; 956 return this; 957 } 958 959 SymlinkOp setValue(String value) { 960 this.value = value; 961 return this; 962 } 963 964 SymlinkOp setModificationTime(long mtime) { 965 this.mtime = mtime; 966 return this; 967 } 968 969 SymlinkOp setAccessTime(long atime) { 970 this.atime = atime; 971 return this; 972 } 973 974 SymlinkOp setPermissionStatus(PermissionStatus permissionStatus) { 975 this.permissionStatus = permissionStatus; 976 return this; 977 } 978 979 @Override 980 void writeFields(DataOutputStream out) throws IOException { 981 FSImageSerialization.writeString(path, out); 982 FSImageSerialization.writeString(value, out); 983 FSImageSerialization.writeLong(mtime, out); 984 FSImageSerialization.writeLong(atime, out); 985 permissionStatus.write(out); 986 } 987 988 @Override 989 void readFields(DataInputStream in, int logVersion) 990 throws IOException { 991 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 992 this.length = in.readInt(); 993 if (this.length != 4) { 994 throw new IOException("Incorrect data format. " 995 + "symlink operation."); 996 } 997 } 998 this.path = FSImageSerialization.readString(in); 999 this.value = FSImageSerialization.readString(in); 1000 1001 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 1002 this.mtime = FSImageSerialization.readLong(in); 1003 this.atime = FSImageSerialization.readLong(in); 1004 } else { 1005 this.mtime = readLong(in); 1006 this.atime = readLong(in); 1007 } 1008 this.permissionStatus = PermissionStatus.read(in); 1009 } 1010 } 1011 1012 static class RenameOp extends FSEditLogOp { 1013 int length; 1014 String src; 1015 String dst; 1016 long timestamp; 1017 Rename[] options; 1018 1019 private RenameOp() { 1020 super(OP_RENAME); 1021 } 1022 1023 static RenameOp getInstance() { 1024 return (RenameOp)opInstances.get() 1025 .get(OP_RENAME); 1026 } 1027 1028 RenameOp setSource(String src) { 1029 this.src = src; 1030 return this; 1031 } 1032 1033 RenameOp setDestination(String dst) { 1034 this.dst = dst; 1035 return this; 1036 } 1037 1038 RenameOp setTimestamp(long timestamp) { 1039 this.timestamp = timestamp; 1040 return this; 1041 } 1042 1043 RenameOp setOptions(Rename[] options) { 1044 this.options = options; 1045 return this; 1046 } 1047 1048 @Override 1049 void writeFields(DataOutputStream out) throws IOException { 1050 FSImageSerialization.writeString(src, out); 1051 FSImageSerialization.writeString(dst, out); 1052 FSImageSerialization.writeLong(timestamp, out); 1053 toBytesWritable(options).write(out); 1054 } 1055 1056 @Override 1057 void readFields(DataInputStream in, int logVersion) 1058 throws IOException { 1059 if (!LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 1060 this.length = in.readInt(); 1061 if (this.length != 3) { 1062 throw new IOException("Incorrect data format. " + "Rename operation."); 1063 } 1064 } 1065 this.src = FSImageSerialization.readString(in); 1066 this.dst = FSImageSerialization.readString(in); 1067 1068 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 1069 this.timestamp = FSImageSerialization.readLong(in); 1070 } else { 1071 this.timestamp = readLong(in); 1072 } 1073 this.options = readRenameOptions(in); 1074 } 1075 1076 private static Rename[] readRenameOptions(DataInputStream in) throws IOException { 1077 BytesWritable writable = new BytesWritable(); 1078 writable.readFields(in); 1079 1080 byte[] bytes = writable.getBytes(); 1081 Rename[] options = new Rename[bytes.length]; 1082 1083 for (int i = 0; i < bytes.length; i++) { 1084 options[i] = Rename.valueOf(bytes[i]); 1085 } 1086 return options; 1087 } 1088 1089 static BytesWritable toBytesWritable(Rename... options) { 1090 byte[] bytes = new byte[options.length]; 1091 for (int i = 0; i < options.length; i++) { 1092 bytes[i] = options[i].value(); 1093 } 1094 return new BytesWritable(bytes); 1095 } 1096 } 1097 1098 static class ReassignLeaseOp extends FSEditLogOp { 1099 String leaseHolder; 1100 String path; 1101 String newHolder; 1102 1103 private ReassignLeaseOp() { 1104 super(OP_REASSIGN_LEASE); 1105 } 1106 1107 static ReassignLeaseOp getInstance() { 1108 return (ReassignLeaseOp)opInstances.get() 1109 .get(OP_REASSIGN_LEASE); 1110 } 1111 1112 ReassignLeaseOp setLeaseHolder(String leaseHolder) { 1113 this.leaseHolder = leaseHolder; 1114 return this; 1115 } 1116 1117 ReassignLeaseOp setPath(String path) { 1118 this.path = path; 1119 return this; 1120 } 1121 1122 ReassignLeaseOp setNewHolder(String newHolder) { 1123 this.newHolder = newHolder; 1124 return this; 1125 } 1126 1127 @Override 1128 void writeFields(DataOutputStream out) throws IOException { 1129 FSImageSerialization.writeString(leaseHolder, out); 1130 FSImageSerialization.writeString(path, out); 1131 FSImageSerialization.writeString(newHolder, out); 1132 } 1133 1134 @Override 1135 void readFields(DataInputStream in, int logVersion) 1136 throws IOException { 1137 this.leaseHolder = FSImageSerialization.readString(in); 1138 this.path = FSImageSerialization.readString(in); 1139 this.newHolder = FSImageSerialization.readString(in); 1140 } 1141 } 1142 1143 static class GetDelegationTokenOp extends FSEditLogOp { 1144 DelegationTokenIdentifier token; 1145 long expiryTime; 1146 1147 private GetDelegationTokenOp() { 1148 super(OP_GET_DELEGATION_TOKEN); 1149 } 1150 1151 static GetDelegationTokenOp getInstance() { 1152 return (GetDelegationTokenOp)opInstances.get() 1153 .get(OP_GET_DELEGATION_TOKEN); 1154 } 1155 1156 GetDelegationTokenOp setDelegationTokenIdentifier( 1157 DelegationTokenIdentifier token) { 1158 this.token = token; 1159 return this; 1160 } 1161 1162 GetDelegationTokenOp setExpiryTime(long expiryTime) { 1163 this.expiryTime = expiryTime; 1164 return this; 1165 } 1166 1167 @Override 1168 void writeFields(DataOutputStream out) throws IOException { 1169 token.write(out); 1170 FSImageSerialization.writeLong(expiryTime, out); 1171 } 1172 1173 @Override 1174 void readFields(DataInputStream in, int logVersion) 1175 throws IOException { 1176 this.token = new DelegationTokenIdentifier(); 1177 this.token.readFields(in); 1178 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 1179 this.expiryTime = FSImageSerialization.readLong(in); 1180 } else { 1181 this.expiryTime = readLong(in); 1182 } 1183 } 1184 } 1185 1186 static class RenewDelegationTokenOp extends FSEditLogOp { 1187 DelegationTokenIdentifier token; 1188 long expiryTime; 1189 1190 private RenewDelegationTokenOp() { 1191 super(OP_RENEW_DELEGATION_TOKEN); 1192 } 1193 1194 static RenewDelegationTokenOp getInstance() { 1195 return (RenewDelegationTokenOp)opInstances.get() 1196 .get(OP_RENEW_DELEGATION_TOKEN); 1197 } 1198 1199 RenewDelegationTokenOp setDelegationTokenIdentifier( 1200 DelegationTokenIdentifier token) { 1201 this.token = token; 1202 return this; 1203 } 1204 1205 RenewDelegationTokenOp setExpiryTime(long expiryTime) { 1206 this.expiryTime = expiryTime; 1207 return this; 1208 } 1209 1210 @Override 1211 void writeFields(DataOutputStream out) throws IOException { 1212 token.write(out); 1213 FSImageSerialization.writeLong(expiryTime, out); 1214 } 1215 1216 @Override 1217 void readFields(DataInputStream in, int logVersion) 1218 throws IOException { 1219 this.token = new DelegationTokenIdentifier(); 1220 this.token.readFields(in); 1221 if (LayoutVersion.supports(Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) { 1222 this.expiryTime = FSImageSerialization.readLong(in); 1223 } else { 1224 this.expiryTime = readLong(in); 1225 } 1226 } 1227 } 1228 1229 static class CancelDelegationTokenOp extends FSEditLogOp { 1230 DelegationTokenIdentifier token; 1231 1232 private CancelDelegationTokenOp() { 1233 super(OP_CANCEL_DELEGATION_TOKEN); 1234 } 1235 1236 static CancelDelegationTokenOp getInstance() { 1237 return (CancelDelegationTokenOp)opInstances.get() 1238 .get(OP_CANCEL_DELEGATION_TOKEN); 1239 } 1240 1241 CancelDelegationTokenOp setDelegationTokenIdentifier( 1242 DelegationTokenIdentifier token) { 1243 this.token = token; 1244 return this; 1245 } 1246 1247 @Override 1248 void writeFields(DataOutputStream out) throws IOException { 1249 token.write(out); 1250 } 1251 1252 @Override 1253 void readFields(DataInputStream in, int logVersion) 1254 throws IOException { 1255 this.token = new DelegationTokenIdentifier(); 1256 this.token.readFields(in); 1257 } 1258 } 1259 1260 static class UpdateMasterKeyOp extends FSEditLogOp { 1261 DelegationKey key; 1262 1263 private UpdateMasterKeyOp() { 1264 super(OP_UPDATE_MASTER_KEY); 1265 } 1266 1267 static UpdateMasterKeyOp getInstance() { 1268 return (UpdateMasterKeyOp)opInstances.get() 1269 .get(OP_UPDATE_MASTER_KEY); 1270 } 1271 1272 UpdateMasterKeyOp setDelegationKey(DelegationKey key) { 1273 this.key = key; 1274 return this; 1275 } 1276 1277 @Override 1278 void writeFields(DataOutputStream out) throws IOException { 1279 key.write(out); 1280 } 1281 1282 @Override 1283 void readFields(DataInputStream in, int logVersion) 1284 throws IOException { 1285 this.key = new DelegationKey(); 1286 this.key.readFields(in); 1287 } 1288 } 1289 1290 static class LogSegmentOp extends FSEditLogOp { 1291 private LogSegmentOp(FSEditLogOpCodes code) { 1292 super(code); 1293 assert code == OP_START_LOG_SEGMENT || 1294 code == OP_END_LOG_SEGMENT : "Bad op: " + code; 1295 } 1296 1297 static LogSegmentOp getInstance(FSEditLogOpCodes code) { 1298 return (LogSegmentOp)opInstances.get().get(code); 1299 } 1300 1301 public void readFields(DataInputStream in, int logVersion) 1302 throws IOException { 1303 // no data stored in these ops yet 1304 } 1305 1306 @Override 1307 void writeFields(DataOutputStream out) throws IOException { 1308 // no data stored 1309 } 1310 } 1311 1312 static class InvalidOp extends FSEditLogOp { 1313 private InvalidOp() { 1314 super(OP_INVALID); 1315 } 1316 1317 static InvalidOp getInstance() { 1318 return (InvalidOp)opInstances.get().get(OP_INVALID); 1319 } 1320 1321 @Override 1322 void writeFields(DataOutputStream out) throws IOException { 1323 } 1324 1325 @Override 1326 void readFields(DataInputStream in, int logVersion) 1327 throws IOException { 1328 // nothing to read 1329 } 1330 } 1331 1332 static private short readShort(DataInputStream in) throws IOException { 1333 return Short.parseShort(FSImageSerialization.readString(in)); 1334 } 1335 1336 static private long readLong(DataInputStream in) throws IOException { 1337 return Long.parseLong(FSImageSerialization.readString(in)); 1338 } 1339 1340 /** 1341 * A class to read in blocks stored in the old format. The only two 1342 * fields in the block were blockid and length. 1343 */ 1344 static class BlockTwo implements Writable { 1345 long blkid; 1346 long len; 1347 1348 static { // register a ctor 1349 WritableFactories.setFactory 1350 (BlockTwo.class, 1351 new WritableFactory() { 1352 public Writable newInstance() { return new BlockTwo(); } 1353 }); 1354 } 1355 1356 1357 BlockTwo() { 1358 blkid = 0; 1359 len = 0; 1360 } 1361 ///////////////////////////////////// 1362 // Writable 1363 ///////////////////////////////////// 1364 public void write(DataOutput out) throws IOException { 1365 out.writeLong(blkid); 1366 out.writeLong(len); 1367 } 1368 1369 public void readFields(DataInput in) throws IOException { 1370 this.blkid = in.readLong(); 1371 this.len = in.readLong(); 1372 } 1373 } 1374 1375 /** 1376 * Class for writing editlog ops 1377 */ 1378 public static class Writer { 1379 private final DataOutputBuffer buf; 1380 private final Checksum checksum; 1381 1382 public Writer(DataOutputBuffer out) { 1383 this.buf = out; 1384 this.checksum = new PureJavaCrc32(); 1385 } 1386 1387 /** 1388 * Write an operation to the output stream 1389 * 1390 * @param op The operation to write 1391 * @throws IOException if an error occurs during writing. 1392 */ 1393 public void writeOp(FSEditLogOp op) throws IOException { 1394 int start = buf.getLength(); 1395 buf.writeByte(op.opCode.getOpCode()); 1396 buf.writeLong(op.txid); 1397 op.writeFields(buf); 1398 int end = buf.getLength(); 1399 checksum.reset(); 1400 checksum.update(buf.getData(), start, end-start); 1401 int sum = (int)checksum.getValue(); 1402 buf.writeInt(sum); 1403 } 1404 } 1405 1406 /** 1407 * Class for reading editlog ops from a stream 1408 */ 1409 public static class Reader { 1410 private final DataInputStream in; 1411 private final int logVersion; 1412 private final Checksum checksum; 1413 1414 /** 1415 * Construct the reader 1416 * @param in The stream to read from. 1417 * @param logVersion The version of the data coming from the stream. 1418 */ 1419 @SuppressWarnings("deprecation") 1420 public Reader(DataInputStream in, int logVersion) { 1421 this.logVersion = logVersion; 1422 if (LayoutVersion.supports(Feature.EDITS_CHESKUM, logVersion)) { 1423 this.checksum = new PureJavaCrc32(); 1424 } else { 1425 this.checksum = null; 1426 } 1427 1428 if (this.checksum != null) { 1429 this.in = new DataInputStream( 1430 new CheckedInputStream(in, this.checksum)); 1431 } else { 1432 this.in = in; 1433 } 1434 } 1435 1436 /** 1437 * Read an operation from the input stream. 1438 * 1439 * Note that the objects returned from this method may be re-used by future 1440 * calls to the same method. 1441 * 1442 * @return the operation read from the stream, or null at the end of the file 1443 * @throws IOException on error. 1444 */ 1445 public FSEditLogOp readOp() throws IOException { 1446 if (checksum != null) { 1447 checksum.reset(); 1448 } 1449 1450 in.mark(1); 1451 1452 byte opCodeByte; 1453 try { 1454 opCodeByte = in.readByte(); 1455 } catch (EOFException eof) { 1456 // EOF at an opcode boundary is expected. 1457 return null; 1458 } 1459 1460 FSEditLogOpCodes opCode = FSEditLogOpCodes.fromByte(opCodeByte); 1461 if (opCode == OP_INVALID) { 1462 in.reset(); // reset back to end of file if somebody reads it again 1463 return null; 1464 } 1465 1466 FSEditLogOp op = opInstances.get().get(opCode); 1467 if (op == null) { 1468 throw new IOException("Read invalid opcode " + opCode); 1469 } 1470 1471 if (LayoutVersion.supports(Feature.STORED_TXIDS, logVersion)) { 1472 // Read the txid 1473 op.setTransactionId(in.readLong()); 1474 } 1475 1476 op.readFields(in, logVersion); 1477 1478 validateChecksum(in, checksum, op.txid); 1479 return op; 1480 } 1481 1482 /** 1483 * Validate a transaction's checksum 1484 */ 1485 private void validateChecksum(DataInputStream in, 1486 Checksum checksum, 1487 long txid) 1488 throws IOException { 1489 if (checksum != null) { 1490 int calculatedChecksum = (int)checksum.getValue(); 1491 int readChecksum = in.readInt(); // read in checksum 1492 if (readChecksum != calculatedChecksum) { 1493 throw new ChecksumException( 1494 "Transaction is corrupt. Calculated checksum is " + 1495 calculatedChecksum + " but read checksum " + readChecksum, txid); 1496 } 1497 } 1498 } 1499 } 1500}