On 29/10/2008, [EMAIL PROTECTED] <[EMAIL PROTECTED]> 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: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]