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}