:-) I agree. Will do. Remko Sent from my iPhone
> On 2015/01/12, at 21:53, Gary Gregory <[email protected]> wrote: > > The funky bit computations should be better documented IMO. "it works" is > funny but does _not_ inspire confidence. > > Gary > > ---------- Forwarded message ---------- > From: <[email protected]> > Date: Mon, Jan 12, 2015 at 3:53 AM > Subject: [06/18] logging-log4j2 git commit: initial version > To: [email protected] > > > initial version > > Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo > Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/258fede7 > Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/258fede7 > Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/258fede7 > > Branch: refs/heads/LOG4J2-930 > Commit: 258fede78aa9bbbbe5042c9af3152e59b7241834 > Parents: 84bd3f9 > Author: rpopma <[email protected]> > Authored: Mon Jan 12 17:31:05 2015 +0900 > Committer: rpopma <[email protected]> > Committed: Mon Jan 12 17:31:05 2015 +0900 > > ---------------------------------------------------------------------- > .../log4j/core/pattern/FastTimeFormatter.java | 209 +++++++++++++++++++ > 1 file changed, 209 insertions(+) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/258fede7/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FastTimeFormatter.java > ---------------------------------------------------------------------- > diff --git > a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FastTimeFormatter.java > > b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FastTimeFormatter.java > new file mode 100644 > index 0000000..3cc2081 > --- /dev/null > +++ > b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FastTimeFormatter.java > @@ -0,0 +1,209 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache license, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the license for the specific language governing permissions and > + * limitations under the license. > + */ > + > +package org.apache.logging.log4j.core.pattern; > + > +import java.nio.charset.Charset; > +import java.text.SimpleDateFormat; > +import java.util.Calendar; > +import java.util.Date; > +import java.util.concurrent.atomic.AtomicReference; > + > +import org.apache.logging.log4j.core.util.Assert; > + > +/** > + * TODO doc > + */ > +public class FastTimeFormatter implements DatePatternConverter.Formatter { > + > + // cached value is non-volatile on purpose > + private DatePart cached; > + private final AtomicReference<DatePart> safe = new > AtomicReference<DatePart>(); > + private final String pattern; > + private final Charset charset; > + > + private static class DatePart { > + final long midnightToday; > + final long midnightTomorrow; > + final String dateTodayString; > + final byte[] dateTodayBytes; > + > + public DatePart(final String pattern, final Charset charset) { > + final Calendar cal = midnightToday(); > + final Date today = cal.getTime(); > + midnightToday = cal.getTimeInMillis(); > + > + cal.add(Calendar.DATE, 1); > + midnightTomorrow = cal.getTimeInMillis(); > + > + final String datePart = extractDatePart(pattern); > + if (datePart != null) { > + dateTodayString = new > SimpleDateFormat(datePart).format(today); > + dateTodayBytes = dateTodayString.getBytes(charset); > + } else { > + dateTodayString = null; > + dateTodayBytes = null; > + } > + } > + > + /** > + * Returns the date part of a date+time format string, or {@code > null} if the specified string does not contain > + * a date part. > + */ > + private static String extractDatePart(final String pattern) { > + final int offset = > pattern.indexOf(DatePatternConverter.ABSOLUTE_TIME_PATTERN); > + if (offset <= 0) { > + return null; > + } > + return pattern.substring(0, offset); > + } > + > + private static Calendar midnightToday() { > + final Calendar cal = Calendar.getInstance(); > + cal.set(Calendar.HOUR_OF_DAY, 0); > + cal.set(Calendar.MINUTE, 0); > + cal.set(Calendar.SECOND, 0); > + cal.set(Calendar.MILLISECOND, 0); > + return cal; > + } > + > + public long millisSinceMidnight(final long now) { > + return now - midnightToday; > + } > + } > + > + public FastTimeFormatter(final String pattern, final Charset charset) { > + this.pattern = Assert.requireNonNull(pattern, "pattern is null"); > + this.charset = Assert.requireNonNull(charset, "charset is null"); > + cached = new DatePart(pattern, charset); > + safe.set(cached); > + } > + > + private DatePart datePart(final long now) { > + DatePart result = cached; // postpone reading from volatile field > + if (now >= result.midnightTomorrow) { > + result = safe.get(); > + if (now >= result.midnightTomorrow) { > + result = new DatePart(pattern, charset); > + cached = result; > + safe.set(result); // store barrier; ensures cached field > update is also visible to other threads > + } > + } > + return result; > + } > + > + /* > + * (non-Javadoc) > + * > + * @see > org.apache.logging.log4j.core.pattern.DatePatternConverter.Formatter#format(long, > + * org.apache.logging.log4j.core.pattern.BinaryBuffer, > java.nio.charset.Charset) > + */ > + public void format(final long time, final BinaryBuffer buffer, final > Charset charset) { > + format(time, buffer); > + } > + > + /* > + * (non-Javadoc) > + * > + * @see > org.apache.logging.log4j.core.pattern.DatePatternConverter.Formatter#format(java.util.Date, > + * org.apache.logging.log4j.core.pattern.Buffer) > + */ > + @Override > + public void format(Date time, Buffer buffer) { > + format(time.getTime(), buffer); > + } > + > + /* > + * (non-Javadoc) > + * > + * @see > org.apache.logging.log4j.core.pattern.DatePatternConverter.Formatter#format(long, > + * org.apache.logging.log4j.core.pattern.Buffer) > + */ > + @Override > + public void format(long time, Buffer buffer) { > + // Calculate values by getting the ms values first and do then > + // shave off the hour minute and second values with multiplications > + // and bit shifts instead of simple but expensive divisions. > + > + // Get daytime in ms which does fit into an int > + // int ms = (int) (time % 86400000); > + DatePart stamp = datePart(time); > + int ms = (int) stamp.millisSinceMidnight(time); > + > + if (stamp.dateTodayBytes != null) { > + buffer.append(stamp.dateTodayBytes); > + } > + > + // well ... it works > + final int hour = (int) (((ms >> 7) * 9773437L) >> 38); // hours = ms > / 3600000; > + ms -= 3600000 * hour; > + > + final int minute = (int) (((ms >> 5) * 2290650L) >> 32); // minutes > = ms / 60000; > + ms -= 60000 * minute; > + > + final int second = ((ms >> 3) * 67109) >> 23; // seconds = ms / 1000; > + ms -= 1000 * second; > + > + // Hour > + // 13/128 is nearly the same as /10 for values up to 65 > + int temp = (hour * 13) >> 7; > + buffer.append((byte) (temp + '0')); > + > + // Do subtract to get remainder instead of doing % 10 > + buffer.append((byte) (hour - 10 * temp + '0')); > + buffer.append((byte) ':'); > + > + // Minute > + // 13/128 is nearly the same as /10 for values up to 65 > + temp = (minute * 13) >> 7; > + buffer.append((byte) (temp + '0')); > + > + // Do subtract to get remainder instead of doing % 10 > + buffer.append((byte) (minute - 10 * temp + '0')); > + buffer.append((byte) ':'); > + > + // Second > + // 13/128 is nearly the same as /10 for values up to 65 > + temp = (second * 13) >> 7; > + buffer.append((byte) (temp + '0')); > + buffer.append((byte) (second - 10 * temp + '0')); > + buffer.append((byte) ','); > + > + // Millisecond > + // 41/4096 is nearly the same as /100 > + temp = (ms * 41) >> 12; > + buffer.append((byte) (temp + '0')); > + > + ms -= 100 * temp; > + temp = (ms * 205) >> 11; // 205/2048 is nearly the same as /10 > + buffer.append((byte) (temp + '0')); > + > + ms -= 10 * temp; > + buffer.append((byte) (ms + '0')); > + } > + > + /* > + * (non-Javadoc) > + * > + * @see > org.apache.logging.log4j.core.pattern.DatePatternConverter.Formatter#toPattern() > + */ > + @Override > + public String toPattern() { > + return pattern; > + } > + > +} > > > > > -- > E-Mail: [email protected] | [email protected] > Java Persistence with Hibernate, Second Edition > JUnit in Action, Second Edition > Spring Batch in Action > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory
