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 019package org.apache.hadoop.hdfs.inotify; 020 021import org.apache.hadoop.classification.InterfaceAudience; 022import org.apache.hadoop.classification.InterfaceStability; 023import org.apache.hadoop.fs.XAttr; 024import org.apache.hadoop.fs.permission.AclEntry; 025import org.apache.hadoop.fs.permission.FsPermission; 026 027import java.util.List; 028 029/** 030 * Events sent by the inotify system. Note that no events are necessarily sent 031 * when a file is opened for read (although a MetadataUpdateEvent will be sent 032 * if the atime is updated). 033 */ 034@InterfaceAudience.Public 035@InterfaceStability.Unstable 036public abstract class Event { 037 public enum EventType { 038 CREATE, CLOSE, APPEND, RENAME, METADATA, UNLINK, TRUNCATE 039 } 040 041 private EventType eventType; 042 043 public EventType getEventType() { 044 return eventType; 045 } 046 047 public Event(EventType eventType) { 048 this.eventType = eventType; 049 } 050 051 /** 052 * Sent when a file is closed after append or create. 053 */ 054 @InterfaceAudience.Public 055 public static class CloseEvent extends Event { 056 private String path; 057 private long fileSize; 058 private long timestamp; 059 060 public CloseEvent(String path, long fileSize, long timestamp) { 061 super(EventType.CLOSE); 062 this.path = path; 063 this.fileSize = fileSize; 064 this.timestamp = timestamp; 065 } 066 067 public String getPath() { 068 return path; 069 } 070 071 /** 072 * The size of the closed file in bytes. May be -1 if the size is not 073 * available (e.g. in the case of a close generated by a concat operation). 074 */ 075 public long getFileSize() { 076 return fileSize; 077 } 078 079 /** 080 * The time when this event occurred, in milliseconds since the epoch. 081 */ 082 public long getTimestamp() { 083 return timestamp; 084 } 085 086 @Override 087 @InterfaceStability.Unstable 088 public String toString() { 089 return "CloseEvent [path=" + path + ", fileSize=" + fileSize 090 + ", timestamp=" + timestamp + "]"; 091 } 092 093 } 094 095 /** 096 * Sent when a new file is created (including overwrite). 097 */ 098 @InterfaceAudience.Public 099 public static class CreateEvent extends Event { 100 101 public enum INodeType { 102 FILE, DIRECTORY, SYMLINK 103 } 104 105 private INodeType iNodeType; 106 private String path; 107 private long ctime; 108 private int replication; 109 private String ownerName; 110 private String groupName; 111 private FsPermission perms; 112 private String symlinkTarget; 113 private boolean overwrite; 114 private long defaultBlockSize; 115 116 public static class Builder { 117 private INodeType iNodeType; 118 private String path; 119 private long ctime; 120 private int replication; 121 private String ownerName; 122 private String groupName; 123 private FsPermission perms; 124 private String symlinkTarget; 125 private boolean overwrite; 126 private long defaultBlockSize = 0; 127 128 public Builder iNodeType(INodeType type) { 129 this.iNodeType = type; 130 return this; 131 } 132 133 public Builder path(String path) { 134 this.path = path; 135 return this; 136 } 137 138 public Builder ctime(long ctime) { 139 this.ctime = ctime; 140 return this; 141 } 142 143 public Builder replication(int replication) { 144 this.replication = replication; 145 return this; 146 } 147 148 public Builder ownerName(String ownerName) { 149 this.ownerName = ownerName; 150 return this; 151 } 152 153 public Builder groupName(String groupName) { 154 this.groupName = groupName; 155 return this; 156 } 157 158 public Builder perms(FsPermission perms) { 159 this.perms = perms; 160 return this; 161 } 162 163 public Builder symlinkTarget(String symlinkTarget) { 164 this.symlinkTarget = symlinkTarget; 165 return this; 166 } 167 168 public Builder overwrite(boolean overwrite) { 169 this.overwrite = overwrite; 170 return this; 171 } 172 173 public Builder defaultBlockSize(long defaultBlockSize) { 174 this.defaultBlockSize = defaultBlockSize; 175 return this; 176 } 177 178 public CreateEvent build() { 179 return new CreateEvent(this); 180 } 181 } 182 183 private CreateEvent(Builder b) { 184 super(EventType.CREATE); 185 this.iNodeType = b.iNodeType; 186 this.path = b.path; 187 this.ctime = b.ctime; 188 this.replication = b.replication; 189 this.ownerName = b.ownerName; 190 this.groupName = b.groupName; 191 this.perms = b.perms; 192 this.symlinkTarget = b.symlinkTarget; 193 this.overwrite = b.overwrite; 194 this.defaultBlockSize = b.defaultBlockSize; 195 } 196 197 public INodeType getiNodeType() { 198 return iNodeType; 199 } 200 201 public String getPath() { 202 return path; 203 } 204 205 /** 206 * Creation time of the file, directory, or symlink. 207 */ 208 public long getCtime() { 209 return ctime; 210 } 211 212 /** 213 * Replication is zero if the CreateEvent iNodeType is directory or symlink. 214 */ 215 public int getReplication() { 216 return replication; 217 } 218 219 public String getOwnerName() { 220 return ownerName; 221 } 222 223 public String getGroupName() { 224 return groupName; 225 } 226 227 public FsPermission getPerms() { 228 return perms; 229 } 230 231 /** 232 * Symlink target is null if the CreateEvent iNodeType is not symlink. 233 */ 234 public String getSymlinkTarget() { 235 return symlinkTarget; 236 } 237 238 public boolean getOverwrite() { 239 return overwrite; 240 } 241 242 public long getDefaultBlockSize() { 243 return defaultBlockSize; 244 } 245 246 @Override 247 @InterfaceStability.Unstable 248 public String toString() { 249 StringBuilder content = new StringBuilder(); 250 content.append("CreateEvent [INodeType=").append(iNodeType) 251 .append(", path=").append(path) 252 .append(", ctime=").append(ctime) 253 .append(", replication=").append(replication) 254 .append(", ownerName=").append(ownerName) 255 .append(", groupName=").append(groupName) 256 .append(", perms=").append(perms).append(", "); 257 258 if (symlinkTarget != null) { 259 content.append("symlinkTarget=").append(symlinkTarget).append(", "); 260 } 261 262 content.append("overwrite=").append(overwrite) 263 .append(", defaultBlockSize=").append(defaultBlockSize) 264 .append("]"); 265 return content.toString(); 266 } 267 268 } 269 270 /** 271 * Sent when there is an update to directory or file (none of the metadata 272 * tracked here applies to symlinks) that is not associated with another 273 * inotify event. The tracked metadata includes atime/mtime, replication, 274 * owner/group, permissions, ACLs, and XAttributes. Fields not relevant to the 275 * metadataType of the MetadataUpdateEvent will be null or will have their default 276 * values. 277 */ 278 @InterfaceAudience.Public 279 public static class MetadataUpdateEvent extends Event { 280 281 public enum MetadataType { 282 TIMES, REPLICATION, OWNER, PERMS, ACLS, XATTRS 283 } 284 285 private String path; 286 private MetadataType metadataType; 287 private long mtime; 288 private long atime; 289 private int replication; 290 private String ownerName; 291 private String groupName; 292 private FsPermission perms; 293 private List<AclEntry> acls; 294 private List<XAttr> xAttrs; 295 private boolean xAttrsRemoved; 296 297 public static class Builder { 298 private String path; 299 private MetadataType metadataType; 300 private long mtime; 301 private long atime; 302 private int replication; 303 private String ownerName; 304 private String groupName; 305 private FsPermission perms; 306 private List<AclEntry> acls; 307 private List<XAttr> xAttrs; 308 private boolean xAttrsRemoved; 309 310 public Builder path(String path) { 311 this.path = path; 312 return this; 313 } 314 315 public Builder metadataType(MetadataType type) { 316 this.metadataType = type; 317 return this; 318 } 319 320 public Builder mtime(long mtime) { 321 this.mtime = mtime; 322 return this; 323 } 324 325 public Builder atime(long atime) { 326 this.atime = atime; 327 return this; 328 } 329 330 public Builder replication(int replication) { 331 this.replication = replication; 332 return this; 333 } 334 335 public Builder ownerName(String ownerName) { 336 this.ownerName = ownerName; 337 return this; 338 } 339 340 public Builder groupName(String groupName) { 341 this.groupName = groupName; 342 return this; 343 } 344 345 public Builder perms(FsPermission perms) { 346 this.perms = perms; 347 return this; 348 } 349 350 public Builder acls(List<AclEntry> acls) { 351 this.acls = acls; 352 return this; 353 } 354 355 public Builder xAttrs(List<XAttr> xAttrs) { 356 this.xAttrs = xAttrs; 357 return this; 358 } 359 360 public Builder xAttrsRemoved(boolean xAttrsRemoved) { 361 this.xAttrsRemoved = xAttrsRemoved; 362 return this; 363 } 364 365 public MetadataUpdateEvent build() { 366 return new MetadataUpdateEvent(this); 367 } 368 } 369 370 private MetadataUpdateEvent(Builder b) { 371 super(EventType.METADATA); 372 this.path = b.path; 373 this.metadataType = b.metadataType; 374 this.mtime = b.mtime; 375 this.atime = b.atime; 376 this.replication = b.replication; 377 this.ownerName = b.ownerName; 378 this.groupName = b.groupName; 379 this.perms = b.perms; 380 this.acls = b.acls; 381 this.xAttrs = b.xAttrs; 382 this.xAttrsRemoved = b.xAttrsRemoved; 383 } 384 385 public String getPath() { 386 return path; 387 } 388 389 public MetadataType getMetadataType() { 390 return metadataType; 391 } 392 393 public long getMtime() { 394 return mtime; 395 } 396 397 public long getAtime() { 398 return atime; 399 } 400 401 public int getReplication() { 402 return replication; 403 } 404 405 public String getOwnerName() { 406 return ownerName; 407 } 408 409 public String getGroupName() { 410 return groupName; 411 } 412 413 public FsPermission getPerms() { 414 return perms; 415 } 416 417 /** 418 * The full set of ACLs currently associated with this file or directory. 419 * May be null if all ACLs were removed. 420 */ 421 public List<AclEntry> getAcls() { 422 return acls; 423 } 424 425 public List<XAttr> getxAttrs() { 426 return xAttrs; 427 } 428 429 /** 430 * Whether the xAttrs returned by getxAttrs() were removed (as opposed to 431 * added). 432 */ 433 public boolean isxAttrsRemoved() { 434 return xAttrsRemoved; 435 } 436 437 @Override 438 @InterfaceStability.Unstable 439 public String toString() { 440 StringBuilder content = new StringBuilder(); 441 content.append("MetadataUpdateEvent [path=").append(path) 442 .append(", metadataType=").append(metadataType); 443 switch (metadataType) { 444 case TIMES: 445 content.append(", mtime=").append(mtime) 446 .append(", atime=").append(atime); 447 break; 448 case REPLICATION: 449 content.append(", replication=").append(replication); 450 break; 451 case OWNER: 452 content.append(", ownerName=").append(ownerName) 453 .append(", groupName=").append(groupName); 454 break; 455 case PERMS: 456 content.append(", perms=").append(perms); 457 break; 458 case ACLS: 459 content.append(", acls=").append(acls); 460 break; 461 case XATTRS: 462 content.append(", xAttrs=").append(xAttrs) 463 .append(", xAttrsRemoved=").append(xAttrsRemoved); 464 break; 465 default: 466 break; 467 } 468 content.append(']'); 469 return content.toString(); 470 } 471 } 472 473 /** 474 * Sent when a file, directory, or symlink is renamed. 475 */ 476 @InterfaceAudience.Public 477 public static class RenameEvent extends Event { 478 private String srcPath; 479 private String dstPath; 480 private long timestamp; 481 482 public static class Builder { 483 private String srcPath; 484 private String dstPath; 485 private long timestamp; 486 487 public Builder srcPath(String srcPath) { 488 this.srcPath = srcPath; 489 return this; 490 } 491 492 public Builder dstPath(String dstPath) { 493 this.dstPath = dstPath; 494 return this; 495 } 496 497 public Builder timestamp(long timestamp) { 498 this.timestamp = timestamp; 499 return this; 500 } 501 502 public RenameEvent build() { 503 return new RenameEvent(this); 504 } 505 } 506 507 private RenameEvent(Builder builder) { 508 super(EventType.RENAME); 509 this.srcPath = builder.srcPath; 510 this.dstPath = builder.dstPath; 511 this.timestamp = builder.timestamp; 512 } 513 514 public String getSrcPath() { 515 return srcPath; 516 } 517 518 public String getDstPath() { 519 return dstPath; 520 } 521 522 /** 523 * The time when this event occurred, in milliseconds since the epoch. 524 */ 525 public long getTimestamp() { 526 return timestamp; 527 } 528 529 @Override 530 @InterfaceStability.Unstable 531 public String toString() { 532 return "RenameEvent [srcPath=" + srcPath + ", dstPath=" + dstPath 533 + ", timestamp=" + timestamp + "]"; 534 } 535 536 } 537 538 /** 539 * Sent when an existing file is opened for append. 540 */ 541 @InterfaceAudience.Public 542 public static class AppendEvent extends Event { 543 private String path; 544 private boolean newBlock; 545 546 public static class Builder { 547 private String path; 548 private boolean newBlock; 549 550 public Builder path(String path) { 551 this.path = path; 552 return this; 553 } 554 555 public Builder newBlock(boolean newBlock) { 556 this.newBlock = newBlock; 557 return this; 558 } 559 560 public AppendEvent build() { 561 return new AppendEvent(this); 562 } 563 } 564 565 private AppendEvent(Builder b) { 566 super(EventType.APPEND); 567 this.path = b.path; 568 this.newBlock = b.newBlock; 569 } 570 571 public String getPath() { 572 return path; 573 } 574 575 public boolean toNewBlock() { 576 return newBlock; 577 } 578 579 @Override 580 @InterfaceStability.Unstable 581 public String toString() { 582 return "AppendEvent [path=" + path + ", newBlock=" + newBlock + "]"; 583 } 584 585 } 586 587 /** 588 * Sent when a file, directory, or symlink is deleted. 589 */ 590 @InterfaceAudience.Public 591 public static class UnlinkEvent extends Event { 592 private String path; 593 private long timestamp; 594 595 public static class Builder { 596 private String path; 597 private long timestamp; 598 599 public Builder path(String path) { 600 this.path = path; 601 return this; 602 } 603 604 public Builder timestamp(long timestamp) { 605 this.timestamp = timestamp; 606 return this; 607 } 608 609 public UnlinkEvent build() { 610 return new UnlinkEvent(this); 611 } 612 } 613 614 private UnlinkEvent(Builder builder) { 615 super(EventType.UNLINK); 616 this.path = builder.path; 617 this.timestamp = builder.timestamp; 618 } 619 620 public String getPath() { 621 return path; 622 } 623 624 /** 625 * The time when this event occurred, in milliseconds since the epoch. 626 */ 627 public long getTimestamp() { 628 return timestamp; 629 } 630 631 @Override 632 @InterfaceStability.Unstable 633 public String toString() { 634 return "UnlinkEvent [path=" + path + ", timestamp=" + timestamp + "]"; 635 } 636 } 637 638 /** 639 * Sent when a file is truncated. 640 */ 641 @InterfaceAudience.Public 642 public static class TruncateEvent extends Event { 643 private String path; 644 private long fileSize; 645 private long timestamp; 646 647 648 public TruncateEvent(String path, long fileSize, long timestamp) { 649 super(EventType.TRUNCATE); 650 this.path = path; 651 this.fileSize = fileSize; 652 this.timestamp = timestamp; 653 } 654 655 public String getPath() { 656 return path; 657 } 658 659 /** 660 * The size of the truncated file in bytes. 661 */ 662 public long getFileSize() { 663 return fileSize; 664 } 665 666 /** 667 * The time when this event occurred, in milliseconds since the epoch. 668 */ 669 public long getTimestamp() { 670 return timestamp; 671 } 672 673 @Override 674 @InterfaceStability.Unstable 675 public String toString() { 676 return "TruncateEvent [path=" + path + ", fileSize=" + fileSize 677 + ", timestamp=" + timestamp + "]"; 678 } 679 } 680}