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 static 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 static 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=" + iNodeType + ", path=" + path 251 + ", ctime=" + ctime + ", replication=" + replication 252 + ", ownerName=" + ownerName + ", groupName=" + groupName 253 + ", perms=" + perms + ", "); 254 255 if (symlinkTarget != null) { 256 content.append("symlinkTarget=" + symlinkTarget + ", "); 257 } 258 259 content.append("overwrite=" + overwrite + ", defaultBlockSize=" 260 + defaultBlockSize + "]"); 261 return content.toString(); 262 } 263 264 } 265 266 /** 267 * Sent when there is an update to directory or file (none of the metadata 268 * tracked here applies to symlinks) that is not associated with another 269 * inotify event. The tracked metadata includes atime/mtime, replication, 270 * owner/group, permissions, ACLs, and XAttributes. Fields not relevant to the 271 * metadataType of the MetadataUpdateEvent will be null or will have their default 272 * values. 273 */ 274 @InterfaceAudience.Public 275 public static class MetadataUpdateEvent extends Event { 276 277 public static enum MetadataType { 278 TIMES, REPLICATION, OWNER, PERMS, ACLS, XATTRS; 279 } 280 281 private String path; 282 private MetadataType metadataType; 283 private long mtime; 284 private long atime; 285 private int replication; 286 private String ownerName; 287 private String groupName; 288 private FsPermission perms; 289 private List<AclEntry> acls; 290 private List<XAttr> xAttrs; 291 private boolean xAttrsRemoved; 292 293 public static class Builder { 294 private String path; 295 private MetadataType metadataType; 296 private long mtime; 297 private long atime; 298 private int replication; 299 private String ownerName; 300 private String groupName; 301 private FsPermission perms; 302 private List<AclEntry> acls; 303 private List<XAttr> xAttrs; 304 private boolean xAttrsRemoved; 305 306 public Builder path(String path) { 307 this.path = path; 308 return this; 309 } 310 311 public Builder metadataType(MetadataType type) { 312 this.metadataType = type; 313 return this; 314 } 315 316 public Builder mtime(long mtime) { 317 this.mtime = mtime; 318 return this; 319 } 320 321 public Builder atime(long atime) { 322 this.atime = atime; 323 return this; 324 } 325 326 public Builder replication(int replication) { 327 this.replication = replication; 328 return this; 329 } 330 331 public Builder ownerName(String ownerName) { 332 this.ownerName = ownerName; 333 return this; 334 } 335 336 public Builder groupName(String groupName) { 337 this.groupName = groupName; 338 return this; 339 } 340 341 public Builder perms(FsPermission perms) { 342 this.perms = perms; 343 return this; 344 } 345 346 public Builder acls(List<AclEntry> acls) { 347 this.acls = acls; 348 return this; 349 } 350 351 public Builder xAttrs(List<XAttr> xAttrs) { 352 this.xAttrs = xAttrs; 353 return this; 354 } 355 356 public Builder xAttrsRemoved(boolean xAttrsRemoved) { 357 this.xAttrsRemoved = xAttrsRemoved; 358 return this; 359 } 360 361 public MetadataUpdateEvent build() { 362 return new MetadataUpdateEvent(this); 363 } 364 } 365 366 private MetadataUpdateEvent(Builder b) { 367 super(EventType.METADATA); 368 this.path = b.path; 369 this.metadataType = b.metadataType; 370 this.mtime = b.mtime; 371 this.atime = b.atime; 372 this.replication = b.replication; 373 this.ownerName = b.ownerName; 374 this.groupName = b.groupName; 375 this.perms = b.perms; 376 this.acls = b.acls; 377 this.xAttrs = b.xAttrs; 378 this.xAttrsRemoved = b.xAttrsRemoved; 379 } 380 381 public String getPath() { 382 return path; 383 } 384 385 public MetadataType getMetadataType() { 386 return metadataType; 387 } 388 389 public long getMtime() { 390 return mtime; 391 } 392 393 public long getAtime() { 394 return atime; 395 } 396 397 public int getReplication() { 398 return replication; 399 } 400 401 public String getOwnerName() { 402 return ownerName; 403 } 404 405 public String getGroupName() { 406 return groupName; 407 } 408 409 public FsPermission getPerms() { 410 return perms; 411 } 412 413 /** 414 * The full set of ACLs currently associated with this file or directory. 415 * May be null if all ACLs were removed. 416 */ 417 public List<AclEntry> getAcls() { 418 return acls; 419 } 420 421 public List<XAttr> getxAttrs() { 422 return xAttrs; 423 } 424 425 /** 426 * Whether the xAttrs returned by getxAttrs() were removed (as opposed to 427 * added). 428 */ 429 public boolean isxAttrsRemoved() { 430 return xAttrsRemoved; 431 } 432 433 @Override 434 @InterfaceStability.Unstable 435 public String toString() { 436 StringBuilder content = new StringBuilder(); 437 content.append("MetadataUpdateEvent [path=" + path + ", metadataType=" 438 + metadataType); 439 switch (metadataType) { 440 case TIMES: 441 content.append(", mtime=" + mtime + ", atime=" + atime); 442 break; 443 case REPLICATION: 444 content.append(", replication=" + replication); 445 break; 446 case OWNER: 447 content.append(", ownerName=" + ownerName 448 + ", groupName=" + groupName); 449 break; 450 case PERMS: 451 content.append(", perms=" + perms); 452 break; 453 case ACLS: 454 content.append(", acls=" + acls); 455 break; 456 case XATTRS: 457 content.append(", xAttrs=" + xAttrs + ", xAttrsRemoved=" 458 + xAttrsRemoved); 459 break; 460 default: 461 break; 462 } 463 content.append(']'); 464 return content.toString(); 465 } 466 } 467 468 /** 469 * Sent when a file, directory, or symlink is renamed. 470 */ 471 @InterfaceAudience.Public 472 public static class RenameEvent extends Event { 473 private String srcPath; 474 private String dstPath; 475 private long timestamp; 476 477 public static class Builder { 478 private String srcPath; 479 private String dstPath; 480 private long timestamp; 481 482 public Builder srcPath(String srcPath) { 483 this.srcPath = srcPath; 484 return this; 485 } 486 487 public Builder dstPath(String dstPath) { 488 this.dstPath = dstPath; 489 return this; 490 } 491 492 public Builder timestamp(long timestamp) { 493 this.timestamp = timestamp; 494 return this; 495 } 496 497 public RenameEvent build() { 498 return new RenameEvent(this); 499 } 500 } 501 502 private RenameEvent(Builder builder) { 503 super(EventType.RENAME); 504 this.srcPath = builder.srcPath; 505 this.dstPath = builder.dstPath; 506 this.timestamp = builder.timestamp; 507 } 508 509 public String getSrcPath() { 510 return srcPath; 511 } 512 513 public String getDstPath() { 514 return dstPath; 515 } 516 517 /** 518 * The time when this event occurred, in milliseconds since the epoch. 519 */ 520 public long getTimestamp() { 521 return timestamp; 522 } 523 524 @Override 525 @InterfaceStability.Unstable 526 public String toString() { 527 return "RenameEvent [srcPath=" + srcPath + ", dstPath=" + dstPath 528 + ", timestamp=" + timestamp + "]"; 529 } 530 531 } 532 533 /** 534 * Sent when an existing file is opened for append. 535 */ 536 @InterfaceAudience.Public 537 public static class AppendEvent extends Event { 538 private String path; 539 private boolean newBlock; 540 541 public static class Builder { 542 private String path; 543 private boolean newBlock; 544 545 public Builder path(String path) { 546 this.path = path; 547 return this; 548 } 549 550 public Builder newBlock(boolean newBlock) { 551 this.newBlock = newBlock; 552 return this; 553 } 554 555 public AppendEvent build() { 556 return new AppendEvent(this); 557 } 558 } 559 560 private AppendEvent(Builder b) { 561 super(EventType.APPEND); 562 this.path = b.path; 563 this.newBlock = b.newBlock; 564 } 565 566 public String getPath() { 567 return path; 568 } 569 570 public boolean toNewBlock() { 571 return newBlock; 572 } 573 574 @Override 575 @InterfaceStability.Unstable 576 public String toString() { 577 return "AppendEvent [path=" + path + ", newBlock=" + newBlock + "]"; 578 } 579 580 } 581 582 /** 583 * Sent when a file, directory, or symlink is deleted. 584 */ 585 @InterfaceAudience.Public 586 public static class UnlinkEvent extends Event { 587 private String path; 588 private long timestamp; 589 590 public static class Builder { 591 private String path; 592 private long timestamp; 593 594 public Builder path(String path) { 595 this.path = path; 596 return this; 597 } 598 599 public Builder timestamp(long timestamp) { 600 this.timestamp = timestamp; 601 return this; 602 } 603 604 public UnlinkEvent build() { 605 return new UnlinkEvent(this); 606 } 607 } 608 609 private UnlinkEvent(Builder builder) { 610 super(EventType.UNLINK); 611 this.path = builder.path; 612 this.timestamp = builder.timestamp; 613 } 614 615 public String getPath() { 616 return path; 617 } 618 619 /** 620 * The time when this event occurred, in milliseconds since the epoch. 621 */ 622 public long getTimestamp() { 623 return timestamp; 624 } 625 626 @Override 627 @InterfaceStability.Unstable 628 public String toString() { 629 return "UnlinkEvent [path=" + path + ", timestamp=" + timestamp + "]"; 630 } 631 } 632 633 /** 634 * Sent when a file is truncated. 635 */ 636 @InterfaceAudience.Public 637 public static class TruncateEvent extends Event { 638 private String path; 639 private long fileSize; 640 private long timestamp; 641 642 643 public TruncateEvent(String path, long fileSize, long timestamp) { 644 super(EventType.TRUNCATE); 645 this.path = path; 646 this.fileSize = fileSize; 647 this.timestamp = timestamp; 648 } 649 650 public String getPath() { 651 return path; 652 } 653 654 /** 655 * The size of the truncated file in bytes. 656 */ 657 public long getFileSize() { 658 return fileSize; 659 } 660 661 /** 662 * The time when this event occurred, in milliseconds since the epoch. 663 */ 664 public long getTimestamp() { 665 return timestamp; 666 } 667 668 @Override 669 @InterfaceStability.Unstable 670 public String toString() { 671 return "TruncateEvent [path=" + path + ", fileSize=" + fileSize 672 + ", timestamp=" + timestamp + "]"; 673 } 674 } 675}