From a03710f697e2f0fc9b4a5732a085f3781d260818 Mon Sep 17 00:00:00 2001
From: fhanik
Date: Mon, 14 Sep 2009 18:53:27 +0000
Subject: [PATCH] Add in behavior and properties around async logging. Thinking
about it, I think the exact same functionality can be achieved in a much
simpler manner by just using a blocking queue. Will attempt that refactor
next
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@814775 13f79535-47bb-0310-9956-ffa450edef68
---
java/org/apache/juli/AsyncFileHandler.java | 52 ++++++++++++++++++++++++++----
webapps/docs/config/systemprops.xml | 31 ++++++++++++++++++
2 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/java/org/apache/juli/AsyncFileHandler.java b/java/org/apache/juli/AsyncFileHandler.java
index 8c13e1df2..8668b5335 100644
--- a/java/org/apache/juli/AsyncFileHandler.java
+++ b/java/org/apache/juli/AsyncFileHandler.java
@@ -30,7 +30,10 @@ 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 OVERFLOW_DROP_FLUSH = 3;
+
+ public static final int OVERFLOW_DROP_TYPE = Integer.parseInt(System.getProperty("org.apache.juli.AsyncOverflowDropType","1"));
+ public static final int DEFAULT_MAX_RECORDS = Integer.parseInt(System.getProperty("org.apache.juli.AsyncMaxRecordCount","1000"));
public static final int RECORD_BATCH_COUNT = Integer.parseInt(System.getProperty("org.apache.juli.AsyncRecordBatchCount","100"));
protected static ConcurrentLinkedQueue handlers = new ConcurrentLinkedQueue();
@@ -42,7 +45,7 @@ public class AsyncFileHandler extends FileHandler {
}
protected LogQueue queue = new LogQueue();
- protected boolean closed = false;
+ protected volatile boolean closed = false;
public AsyncFileHandler() {
this(null,null,null);
@@ -55,14 +58,18 @@ public class AsyncFileHandler extends FileHandler {
@Override
public void close() {
+ if (closed) return;
closed = true;
// TODO Auto-generated method stub
super.close();
handlers.remove(this);
+ //empty the queue of log entries for this log
+ while (queue.poll()!=null) recordCounter.addAndGet(-1);
}
@Override
protected void open() {
+ if(!closed) return;
closed = false;
// TODO Auto-generated method stub
super.open();
@@ -108,14 +115,22 @@ public class AsyncFileHandler extends FileHandler {
protected static class SignalAtomicLong {
AtomicLong delegate = new AtomicLong(0);
ReentrantLock lock = new ReentrantLock();
- Condition cond = lock.newCondition();
+ Condition sleepUntilPositiveCond = lock.newCondition();
+ Condition sleepUntilEmpty = lock.newCondition();
public long addAndGet(long i) {
long prevValue = delegate.getAndAdd(i);
if (prevValue<=0 && i>0) {
lock.lock();
try {
- cond.signalAll();
+ sleepUntilPositiveCond.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ } else if (prevValue>0 && delegate.get()<=0) {
+ lock.lock();
+ try {
+ sleepUntilEmpty.signalAll();
} finally {
lock.unlock();
}
@@ -128,12 +143,24 @@ public class AsyncFileHandler extends FileHandler {
lock.lock();
try {
if (delegate.get()>0) return;
- cond.await();
+ sleepUntilPositiveCond.await();
} finally {
lock.unlock();
}
}
+ public void sleepUntilEmpty() throws InterruptedException {
+ if (delegate.get()<=0) return;
+ lock.lock();
+ try {
+ if (delegate.get()<=0) return;
+ sleepUntilPositiveCond.await();
+ } finally {
+ lock.unlock();
+ }
+
+ }
+
public long get() {
return delegate.get();
}
@@ -171,7 +198,7 @@ public class AsyncFileHandler extends FileHandler {
protected static class LogQueue {
protected int max = DEFAULT_MAX_RECORDS;
- protected int type = OVERFLOW_DROP_LAST;
+ protected int type = OVERFLOW_DROP_TYPE;
protected ConcurrentLinkedQueue delegate = new ConcurrentLinkedQueue();
public boolean offer(E e) {
@@ -188,6 +215,19 @@ public class AsyncFileHandler extends FileHandler {
return false;
}
}
+ case OVERFLOW_DROP_FLUSH: {
+ try {
+ recordCounter.sleepUntilEmpty();
+ }catch (InterruptedException x) {
+ //no op - simply continue the operation
+ }
+ if (delegate.offer(e)) {
+ recordCounter.addAndGet(1);
+ return true;
+ } else {
+ return false;
+ }
+ }
default:
return false;
}
diff --git a/webapps/docs/config/systemprops.xml b/webapps/docs/config/systemprops.xml
index b024f3978..d32d19e73 100644
--- a/webapps/docs/config/systemprops.xml
+++ b/webapps/docs/config/systemprops.xml
@@ -325,6 +325,37 @@
+
+
+
+
+
+ When the memory limit of records has been reached the system needs to determine what action to take.
+ Currently there are three actions that can be taken:
+
+ int OVERFLOW_DROP_LAST = 1 - the record that caused the overflow will be dropped and not logged
+ int OVERFLOW_DROP_FIRST = 2 - the record that is next in line to be logged will be dropped to make room for the latest record on the queue
+ int OVERFLOW_DROP_FLUSH = 3 - suspend the thread while the queue empties out and flushes the entries to the write buffer
+
+ Default value is 1 (OVERFLOW_DROP_LAST).
+
+
+
+
+ The max number of log records that the async logger will keep in memory. When this limit is reached and a new record is being logged by the
+ JULI framework the system will take an action based on the org.apache.juli.AsyncOverflowDropType setting.
+ The default value is 1000 records
+
+
+
+
+
+
+
+
+
+
+