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}