tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sebb <seb...@gmail.com>
Subject Re: svn commit: r709018 - in /tomcat/trunk/java/org/apache/juli: AsyncFileHandler.java FileHandler.java
Date Mon, 03 Nov 2008 10:08:27 GMT
On 29/10/2008, fhanik@apache.org <fhanik@apache.org> wrote:
> Author: fhanik
>  Date: Wed Oct 29 14:41:09 2008
>  New Revision: 709018
>
>  URL: http://svn.apache.org/viewvc?rev=709018&view=rev
>  Log:
>  Add asynchronous log handling, feature not yet complete. Need to figure out when to
stop the logger thread (possible when there are no loggers) and also make sure the thread
sleep/wakeup is bullet proof
>
>
>  Added:
>     tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java
>  Modified:
>     tomcat/trunk/java/org/apache/juli/FileHandler.java
>
>  Added: tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java
>  URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java?rev=709018&view=auto
>  ==============================================================================
>  --- tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java (added)
>  +++ tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java Wed Oct 29 14:41:09 2008
>  @@ -0,0 +1,217 @@
>  +/*
>  + * 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.juli;
>  +
>  +import java.util.concurrent.ConcurrentLinkedQueue;
>  +import java.util.concurrent.atomic.AtomicLong;
>  +import java.util.concurrent.locks.Condition;
>  +import java.util.concurrent.locks.ReentrantLock;
>  +import java.util.logging.LogRecord;
>  +/**
>  + *
>  + * @author Filip Hanik
>  + *
>  + */
>  +public class AsyncFileHandler extends FileHandler {
>  +
>  +    public static final int OVERFLOW_DROP_LAST = 1;
>  +    public static final int OVERFLOW_DROP_FIRST = 2;
>  +    public static final int DEFAULT_MAX_RECORDS = 1000;
>  +    public static final int RECORD_BATCH_COUNT = Integer.parseInt(System.getProperty("org.apache.juli.AsyncRecordBatchCount","100"));
>  +
>  +    protected static ConcurrentLinkedQueue<FileHandler> handlers = new ConcurrentLinkedQueue<FileHandler>();
>  +    protected static SignalAtomicLong recordCounter = new SignalAtomicLong();
>  +    protected static LoggerThread logger = new LoggerThread();
>  +

It would be safer to make the above final, if possible. If not
possible, then there are probably thread-safety issues.

>  +    static {
>  +        logger.start();
>  +    }
>  +
>  +    protected LogQueue<LogRecord> queue = new LogQueue<LogRecord>();

Ditto.

>  +    protected boolean closed = false;

Probably needs to be volatile - else all accesses need to be sych.

>  +
>  +    public AsyncFileHandler() {
>  +        this(null,null,null);
>  +    }
>  +
>  +    public AsyncFileHandler(String directory, String prefix, String suffix) {
>  +        super(directory, prefix, suffix);
>  +        open();
>  +    }
>  +
>  +    @Override
>  +    public void close() {
>  +        closed = true;
>  +        // TODO Auto-generated method stub
>  +        super.close();
>  +        handlers.remove(this);
>  +    }
>  +
>  +    @Override
>  +    protected void open() {
>  +        closed = false;
>  +        // TODO Auto-generated method stub
>  +        super.open();
>  +        handlers.add(this);
>  +    }
>  +
>  +
>  +    @Override
>  +    public void publish(LogRecord record) {
>  +        if (!isLoggable(record)) {
>  +            return;
>  +        }
>  +        this.queue.offer(record);
>  +    }
>  +
>  +    protected void publishInternal(LogRecord record) {
>  +        recordCounter.addAndGet(-1);
>  +        super.publish(record);
>  +    }
>  +
>  +    @Override
>  +    protected void finalize() throws Throwable {
>  +        // TODO Auto-generated method stub
>  +        super.finalize();
>  +    }
>  +
>  +    public int getMaxRecords() {
>  +        return this.queue.max;
>  +    }
>  +
>  +    public void setMaxRecords(int maxRecords) {
>  +        this.queue.max = maxRecords;
>  +    }
>  +
>  +    public int getOverflowAction() {
>  +        return this.queue.type;
>  +    }
>  +
>  +    public void setOverflowAction(int type) {
>  +        this.queue.type = type;
>  +    }
>  +
>  +    protected static class SignalAtomicLong {
>  +        AtomicLong delegate = new AtomicLong(0);
>  +        ReentrantLock lock = new ReentrantLock();
>  +        Condition cond = lock.newCondition();
>  +
>  +        public long addAndGet(long i) {
>  +            long prevValue = delegate.getAndAdd(i);
>  +            if (prevValue<=0 && i>0) {
>  +                lock.lock();
>  +                try {
>  +                    cond.signalAll();
>  +                } finally {
>  +                    lock.unlock();
>  +                }
>  +            }
>  +            return delegate.get();
>  +        }
>  +
>  +        public void sleepUntilPositive() throws InterruptedException {
>  +            if (delegate.get()>0) return;
>  +            lock.lock();
>  +            try {
>  +                if (delegate.get()>0) return;
>  +                cond.await();
>  +            } finally {
>  +                lock.unlock();
>  +            }
>  +        }
>  +
>  +        public long get() {
>  +            return delegate.get();
>  +        }
>  +
>  +    }
>  +
>  +    protected static class LoggerThread extends Thread {
>  +        protected boolean run = true;

Needs to be volatile, as it is used by at least 2 threads.

>  +        public LoggerThread() {
>  +            this.setDaemon(true);
>  +            this.setName("AsyncFileHandlerWriter-"+System.identityHashCode(this));
>  +        }
>  +
>  +        public void run() {
>  +            while (run) {
>  +                try {
>  +                    AsyncFileHandler.recordCounter.sleepUntilPositive();
>  +                } catch (InterruptedException x) {
>  +                    this.interrupted();
>  +                    continue;
>  +                }
>  +                AsyncFileHandler[] handlers = AsyncFileHandler.handlers.toArray(new
AsyncFileHandler[0]);
>  +                for (int i=0; run && i<handlers.length; i++) {
>  +                    int counter = 0;
>  +                    while (run && (counter++)<RECORD_BATCH_COUNT) {
>  +                        if (handlers[i].closed) break;
>  +                        LogRecord record = handlers[i].queue.poll();
>  +                        if (record==null) break;
>  +                        handlers[i].publishInternal(record);
>  +                    }//while
>  +                }//for
>  +            }//while
>  +        }
>  +    }
>  +
>  +    protected static class LogQueue<E> {
>  +        protected int max = DEFAULT_MAX_RECORDS;
>  +        protected int type = OVERFLOW_DROP_LAST;
>  +        protected ConcurrentLinkedQueue<E> delegate = new ConcurrentLinkedQueue<E>();

Can these be final?

>  +
>  +        public boolean offer(E e) {
>  +            if (delegate.size()>=max) {
>  +                switch (type) {
>  +                    case OVERFLOW_DROP_LAST:
>  +                        return false;
>  +                    case OVERFLOW_DROP_FIRST: {
>  +                        this.poll();
>  +                        if (delegate.offer(e)) {
>  +                            recordCounter.addAndGet(1);
>  +                            return true;
>  +                        } else {
>  +                            return false;
>  +                        }
>  +                    }
>  +                    default:
>  +                        return false;
>  +                }
>  +            } else {
>  +                if (delegate.offer(e)) {
>  +                    recordCounter.addAndGet(1);
>  +                    return true;
>  +                } else {
>  +                    return false;
>  +                }
>  +
>  +            }
>  +        }
>  +
>  +        public E peek() {
>  +            return delegate.peek();
>  +        }
>  +
>  +        public E poll() {
>  +            // TODO Auto-generated method stub
>  +            return delegate.poll();
>  +        }
>  +
>  +    }
>  +
>  +
>  +}
>
>  Modified: tomcat/trunk/java/org/apache/juli/FileHandler.java
>  URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/juli/FileHandler.java?rev=709018&r1=709017&r2=709018&view=diff
>  ==============================================================================
>  --- tomcat/trunk/java/org/apache/juli/FileHandler.java (original)
>  +++ tomcat/trunk/java/org/apache/juli/FileHandler.java Wed Oct 29 14:41:09 2008
>  @@ -56,7 +56,7 @@
>          this.prefix = prefix;
>          this.suffix = suffix;
>          configure();
>  -        open();
>  +        openWriter();
>      }
>
>
>  @@ -117,9 +117,9 @@
>          if (!date.equals(tsDate)) {
>              synchronized (this) {
>                  if (!date.equals(tsDate)) {
>  -                    close();
>  +                    closeWriter();
>                      date = tsDate;
>  -                    open();
>  +                    openWriter();
>                  }
>              }
>          }
>  @@ -154,6 +154,10 @@
>       * Close the currently open log file (if any).
>       */
>      public void close() {
>  +        closeWriter();
>  +    }
>  +
>  +    protected void closeWriter() {
>
>          try {
>              if (writer == null)
>  @@ -193,7 +197,7 @@
>          String tsString = ts.toString().substring(0, 19);
>          date = tsString.substring(0, 10);
>
>  -        String className = FileHandler.class.getName();
>  +        String className = this.getClass().getName(); //allow classes to override
>
>          ClassLoader cl = Thread.currentThread().getContextClassLoader();
>
>  @@ -250,7 +254,11 @@
>      /**
>       * Open the new log file for the date specified by <code>date</code>.
>       */
>  -    private void open() {
>  +    protected void open() {
>  +        openWriter();
>  +    }
>  +
>  +    protected void openWriter() {
>
>          // Create the directory if necessary
>          File dir = new File(directory);
>
>
>
>  ---------------------------------------------------------------------
>  To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
>  For additional commands, e-mail: dev-help@tomcat.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message