View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.time;
18  
19  import org.apache.logging.log4j.core.util.Clock;
20  import org.apache.logging.log4j.util.PerformanceSensitive;
21  
22  import java.io.Serializable;
23  
24  /**
25   * An instantaneous point on the time line, used for high-precision log event timestamps.
26   * Modeled on <a href="https://docs.oracle.com/javase/9/docs/api/?java/time/class-use/Instant.html">java.time.Instant</a>,
27   * except that this version is mutable to prevent allocating temporary objects that need to be garbage-collected later.
28   * <p>
29   * Instances of this class are <em>not</em> thread-safe and should not be shared between threads.
30   * </p>
31   *
32   * @since 2.11
33   */
34  @PerformanceSensitive("allocation")
35  public class MutableInstant implements Instant, Serializable {
36  
37      private static final int MILLIS_PER_SECOND = 1000;
38      private static final int NANOS_PER_MILLI = 1000_000;
39      private static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI;
40  
41      private long epochSecond;
42      private int nanoOfSecond;
43  
44      @Override
45      public long getEpochSecond() {
46          return epochSecond;
47      }
48  
49      @Override
50      public int getNanoOfSecond() {
51          return nanoOfSecond;
52      }
53  
54      @Override
55      public long getEpochMillisecond() {
56          final int millis = nanoOfSecond / NANOS_PER_MILLI;
57          final long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis;
58          return epochMillisecond;
59      }
60  
61      @Override
62      public int getNanoOfMillisecond() {
63          final int millis = nanoOfSecond / NANOS_PER_MILLI;
64          final int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
65          return nanoOfMillisecond;
66      }
67  
68      public void initFrom(final Instant other) {
69          this.epochSecond = other.getEpochSecond();
70          this.nanoOfSecond = other.getNanoOfSecond();
71      }
72  
73      /**
74       * Updates the fields of this {@code MutableInstant} from the specified epoch millis.
75       * @param epochMilli the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z
76       * @param nanoOfMillisecond the number of nanoseconds, later along the time-line, from the start of the millisecond
77       */
78      public void initFromEpochMilli(final long epochMilli, final int nanoOfMillisecond) {
79          validateNanoOfMillisecond(nanoOfMillisecond);
80          this.epochSecond = epochMilli / MILLIS_PER_SECOND;
81          this.nanoOfSecond = (int) (epochMilli - (epochSecond * MILLIS_PER_SECOND)) * NANOS_PER_MILLI + nanoOfMillisecond;
82      }
83  
84      private void validateNanoOfMillisecond(final int nanoOfMillisecond) {
85          if (nanoOfMillisecond < 0 || nanoOfMillisecond >= NANOS_PER_MILLI) {
86              throw new IllegalArgumentException("Invalid nanoOfMillisecond " + nanoOfMillisecond);
87          }
88      }
89  
90      public void initFrom(final Clock clock) {
91          if (clock instanceof PreciseClock) {
92              ((PreciseClock) clock).init(this);
93          } else {
94              initFromEpochMilli(clock.currentTimeMillis(), 0);
95          }
96      }
97  
98      /**
99       * Updates the fields of this {@code MutableInstant} from the specified instant components.
100      * @param epochSecond the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
101      * @param nano the number of nanoseconds, later along the time-line, from the start of the second
102      */
103     public void initFromEpochSecond(final long epochSecond, final int nano) {
104         validateNanoOfSecond(nano);
105         this.epochSecond = epochSecond;
106         this.nanoOfSecond = nano;
107     }
108 
109     private void validateNanoOfSecond(final int nano) {
110         if (nano < 0 || nano >= NANOS_PER_SECOND) {
111             throw new IllegalArgumentException("Invalid nanoOfSecond " + nano);
112         }
113     }
114 
115     /**
116      * Updates the elements of the specified {@code long[]} result array from the specified instant components.
117      * @param epochSecond (input) the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
118      * @param nano (input) the number of nanoseconds, later along the time-line, from the start of the second
119      * @param result (output) a two-element array to store the result: the first element is the number of milliseconds
120      *               from the Java epoch of 1970-01-01T00:00:00Z,
121      *               the second element is the number of nanoseconds, later along the time-line, from the start of the millisecond
122      */
123     public static void instantToMillisAndNanos(final long epochSecond, final int nano, final long[] result) {
124         final int millis = nano / NANOS_PER_MILLI;
125         result[0] = epochSecond * MILLIS_PER_SECOND + millis;
126         result[1] = nano - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
127     }
128 
129     @Override
130     public boolean equals(final Object object) {
131         if (object == this) {
132             return true;
133         }
134         if (!(object instanceof MutableInstant)) {
135             return false;
136         }
137         final MutableInstant other = (MutableInstant) object;
138         return epochSecond == other.epochSecond && nanoOfSecond == other.nanoOfSecond;
139     }
140 
141     @Override
142     public int hashCode() {
143         int result = 17;
144         result = 31 * result + (int) (epochSecond ^ (epochSecond >>> 32));
145         result = 31 * result + nanoOfSecond;
146         return result;
147     }
148 
149     @Override
150     public String toString() {
151         final StringBuilder sb = new StringBuilder(64);
152         formatTo(sb);
153         return sb.toString();
154     }
155 
156     @Override
157     public void formatTo(final StringBuilder buffer) {
158         buffer.append("MutableInstant[epochSecond=").append(epochSecond).append(", nano=").append(nanoOfSecond).append("]");
159     }
160 }