[logback-dev] svn commit: r1790 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic/pattern main/java/ch/qos/logback/classic/spi test/java/ch/qos/logback/classic/pattern test/java/ch/qos/logback/classic/pattern/lru
noreply.ceki at qos.ch
noreply.ceki at qos.ch
Tue Sep 2 18:34:48 CEST 2008
Author: ceki
Date: Tue Sep 2 18:34:48 2008
New Revision: 1790
Added:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/Event.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_Entry.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableInformation.java
Log:
LBGENERAL-23
Extracting package information is a time consuming process.
Improve performance by keeping previously found results in a cache.
Added an LRUCache with accompanying test cases for this purpose.
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,156 @@
+package ch.qos.logback.classic.pattern;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class LRUCache<K, V> {
+
+ Map<K, Entry> map = new HashMap<K, Entry>();
+ Entry head;
+ Entry tail;
+
+ int limit;
+
+ LRUCache(int limit) {
+ if(limit < 1) {
+ throw new IllegalArgumentException("limit cannnot be smaller than 1");
+ }
+
+ this.limit = limit;
+
+ head = new Entry(null, null);
+ tail = head;
+ }
+
+ public void put(K key, V value) {
+ Entry entry = map.get(key);
+ if (entry == null) {
+ entry = new Entry(key, value);
+ map.put(key, entry);
+ }
+ moveToTail(entry);
+ while(map.size() > limit) {
+ removeHead();
+ }
+ }
+
+ public V get(K key) {
+ Entry existing = map.get(key);
+ if (existing == null) {
+ return null;
+ } else {
+ moveToTail(existing);
+ return existing.value;
+ }
+ }
+
+ private void removeHead() {
+ //System.out.println("RemoveHead called");
+ map.remove(head.key);
+ head = head.next;
+ head.prev = null;
+ }
+
+ private void moveToTail(Entry e) {
+ rearrangePreexistingLinks(e);
+ rearrangeTailLinks(e);
+ }
+
+ private void rearrangePreexistingLinks(Entry e) {
+ if (e.prev != null) {
+ e.prev.next = e.next;
+ }
+ if (e.next != null) {
+ e.next.prev = e.prev;
+ }
+ if(head == e) {
+ head = e.next;
+ }
+ }
+
+ private void rearrangeTailLinks(Entry e) {
+ if(head == tail) {
+ head = e;
+ }
+ Entry preTail = tail.prev;
+ if(preTail != null) {
+ preTail.next = e;
+ }
+ e.prev = preTail;
+ e.next = tail;
+ tail.prev = e;
+ }
+
+
+ public void dump() {
+ Entry e = head;
+ System.out.print("N:");
+ while (e != null) {
+ //System.out.print(e+"->");
+ System.out.print(e.key+", ");
+ e = e.next;
+ }
+ System.out.println();
+ }
+
+ List<K> keyList() {
+ List<K> result = new LinkedList<K>();
+ Entry e = head;
+ while (e != tail) {
+ result.add(e.key);
+ e = e.next;
+ }
+ return result;
+ }
+
+ // ================================================================
+ private class Entry {
+ Entry next;
+ Entry prev;
+ K key;
+ V value;
+
+ Entry(K k, V v) {
+ this.key = k;
+ this.value = v;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Entry other = (Entry) obj;
+ if (key == null) {
+ if (other.key != null)
+ return false;
+ } else if (!key.equals(other.key))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + key + ", " + value + ")";
+ }
+ }
+
+}
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,13 @@
+package ch.qos.logback.classic.pattern;
+
+public class PackageInfo {
+
+
+ String jarName;
+ String version;
+
+ PackageInfo(String jarName, String version) {
+ this.jarName = jarName;
+ this.version = version;
+ }
+}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java Tue Sep 2 18:34:48 2008
@@ -1,33 +1,128 @@
/**
- * LOGBack: the reliable, fast and flexible logging library for Java.
- *
- * Copyright (C) 1999-2006, QOS.ch
- *
- * This library is free software, you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
*/
package ch.qos.logback.classic.pattern;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
import org.slf4j.Marker;
+/**
+ *
+ * @author James Strachan
+ * @author Ceki Gulcu
+ */
public class Util {
+ static Map<String, PackageInfo> cache = new HashMap<String, PackageInfo>();
+
static public boolean match(Marker marker, Marker[] markerArray) {
- if(markerArray == null) {
+ if (markerArray == null) {
throw new IllegalArgumentException("markerArray should not be null");
}
-
- //System.out.println("event marker="+marker);
-
+
+ // System.out.println("event marker="+marker);
+
final int size = markerArray.length;
- for(int i = 0; i < size; i++) {
- //System.out.println("other:"+markerArray[i]);
-
- if(marker.contains(markerArray[i])) {
+ for (int i = 0; i < size; i++) {
+ // System.out.println("other:"+markerArray[i]);
+
+ if (marker.contains(markerArray[i])) {
return true;
}
}
return false;
}
+
+ static String getVersion(String className) {
+ String packageName = getPackageName(className);
+ Package aPackage = Package.getPackage(packageName);
+ if (aPackage != null) {
+ String v = aPackage.getImplementationVersion();
+ if (v == null) {
+ return "na";
+ } else {
+ return v;
+ }
+ }
+ return "na";
+ }
+
+ static public PackageInfo getPackageInfo(String className) {
+ PackageInfo pi = cache.get(className);
+ if(pi != null) {
+ return pi;
+ }
+ String version = getVersion(className);
+ String jarname = getJarNameOfClass(className);
+ pi = new PackageInfo(jarname, version);
+ //cache.put(className, pi);
+ return pi;
+ }
+
+ static String getPackageName(String className) {
+ int j = className.lastIndexOf('.');
+ return className.substring(0, j);
+ }
+
+ /**
+ * Uses the context class path or the current global class loader to deduce
+ * the file that the given class name comes from
+ */
+ static String getJarNameOfClass(String className) {
+ try {
+ Class type = findClass(className);
+ if (type != null) {
+ URL resource = type.getClassLoader().getResource(
+ type.getName().replace('.', '/') + ".class");
+ // "jar:file:/C:/java/../repo/groupId/artifact/1.3/artifact-1.3.jar!/com/some/package/Some.class
+ if (resource != null) {
+ String text = resource.toString();
+ int idx = text.lastIndexOf('!');
+ if (idx > 0) {
+ text = text.substring(0, idx);
+ // now lets remove all but the file name
+ idx = text.lastIndexOf('/');
+ if (idx > 0) {
+ text = text.substring(idx + 1);
+ }
+ idx = text.lastIndexOf('\\');
+ if (idx > 0) {
+ text = text.substring(idx + 1);
+ }
+ return text;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ return "na";
+ }
+
+ static private Class findClass(String className) {
+ try {
+ return Thread.currentThread().getContextClassLoader()
+ .loadClass(className);
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e1) {
+ try {
+ return Util.class.getClassLoader().loadClass(className);
+ } catch (ClassNotFoundException e2) {
+ return null;
+ }
+ }
+ }
+ }
+
}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableInformation.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableInformation.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableInformation.java Tue Sep 2 18:34:48 2008
@@ -29,7 +29,7 @@
}
/**
- * The string representation of the exceptopn (throwable) that this object
+ * The string representation of the throwable that this object
* represents.
*/
public String[] getThrowableStrRep() {
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,71 @@
+package ch.qos.logback.classic.pattern;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import ch.qos.logback.classic.pattern.lru.Event;
+import ch.qos.logback.classic.pattern.lru.T_LRUCache;
+
+public class LRUCacheTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+
+ }
+
+ @Test
+ public void smoke() {
+ LRUCache<String, String> cache = new LRUCache<String, String>(2);
+ cache.put("a", "a");
+ cache.put("b", "b");
+ cache.put("c", "c");
+ List<String> witness = new LinkedList<String>();
+ witness.add("b");
+ witness.add("c");
+ assertEquals(witness, cache.keyList());
+ }
+
+ @Test
+ public void typicalScenarioTest() {
+ int simulationLen = 1000 * 20;
+ int cacheSize = 500;
+ int worldSize = 10000;
+ doScenario(simulationLen, cacheSize, worldSize);
+ }
+
+ @Test
+ public void scenarioCoverageTest() {
+ int simulationLen = 1000 * 20;
+ int[] cacheSizes = new int[] {1,5,10,100,1000,5000,10000};
+ int[] worldSizes = new int[] {1,10,100,1000,20000};
+ for (int i = 0; i < cacheSizes.length; i++) {
+ for (int j = 0; j < worldSizes.length; j++) {
+ System.out.println("cacheSize="+cacheSizes[i]+", worldSize="+worldSizes[j]);
+ doScenario(simulationLen, cacheSizes[i], worldSizes[j]);
+ }
+ }
+ }
+
+ void doScenario(int simulationLen, int chacheSize, int worldSize) {
+ int cacheSize = 500;
+ int get2PutRatio = 10;
+
+ Simulator simulator = new Simulator(worldSize, get2PutRatio);
+ List<Event> scenario = simulator.generateScenario(simulationLen);
+ LRUCache<String, String> lruCache = new LRUCache<String, String>(cacheSize);
+ T_LRUCache<String> tlruCache = new T_LRUCache<String>(cacheSize);
+ simulator.simulate(scenario, lruCache, tlruCache);
+ assertEquals(tlruCache.ketList(), lruCache.keyList());
+ }
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,70 @@
+package ch.qos.logback.classic.pattern;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import ch.qos.logback.classic.pattern.lru.Event;
+import ch.qos.logback.classic.pattern.lru.T_LRUCache;
+
+public class Simulator {
+
+
+ Random random;
+
+ int worldSize;
+ int get2PutRatio;
+
+ public Simulator(int worldSize, int get2PutRatio) {
+ this.worldSize = worldSize;
+ this.get2PutRatio = get2PutRatio;
+ long seed = System.nanoTime();
+ System.out.println("seed is "+seed);
+ random = new Random(seed);
+ }
+
+ public List<Event> generateScenario(int len) {
+ List<Event> scenario = new ArrayList<Event>();
+
+ for(int i = 0; i < len; i++) {
+
+ int r = random.nextInt(get2PutRatio);
+ boolean put = false;
+ if(r == 0) {
+ put = true;
+ }
+ r = random.nextInt(worldSize);
+ Event<String> e = new Event<String>(put, String.valueOf(r));
+ scenario.add(e);
+ }
+ return scenario;
+ }
+
+ public void simulate(List<Event> scenario, LRUCache<String, String> lruCache, T_LRUCache<String> tlruCache) {
+ for(Event<String> e: scenario) {
+ if(e.put) {
+ lruCache.put(e.k, e.k);
+ tlruCache.put(e.k);
+ } else {
+ String r0 = lruCache.get(e.k);
+ String r1 = tlruCache.get(e.k);
+ if(r0 != null) {
+ assertEquals(r0, e.k);
+ }
+ assertEquals(r0, r1);
+ }
+ }
+ }
+
+// void compareAndDumpIfDifferent(LRUCache<String, String> lruCache, T_LRUCache<String> tlruCache) {
+// lruCache.dump();
+// tlruCache.dump();
+// if(!lruCache.keyList().equals(tlruCache.ketList())) {
+// lruCache.dump();
+// tlruCache.dump();
+// throw new AssertionFailedError("s");
+// }
+// }
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,84 @@
+package ch.qos.logback.classic.pattern;
+
+import java.util.Random;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.icegreen.greenmail.util.GreenMail;
+import com.icegreen.greenmail.util.ServerSetup;
+
+public class UtilTest {
+
+ int diff = 1024 + new Random().nextInt(10000);
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void withGreenMail() {
+ try {
+ ServerSetup serverSetup = new ServerSetup(-1, "localhost",
+ ServerSetup.PROTOCOL_SMTP);
+ GreenMail greenMail = new GreenMail((ServerSetup) null);
+ // greenMail.start();
+ } catch (Throwable e) {
+ // e.printStackTrace();
+ StackTraceElement[] stea = e.getStackTrace();
+ for (StackTraceElement ste : stea) {
+ String className = ste.getClassName();
+ PackageInfo pi = Util.getPackageInfo(className);
+ System.out.println(" at " + className + "." + ste.getMethodName()
+ + "(" + ste.getFileName() + ":" + ste.getLineNumber() + ") ["
+ + pi.jarName + ":" + pi.version + "]");
+ }
+ }
+ }
+
+ public void doPerf(boolean versionExtraction) {
+ try {
+ ServerSetup serverSetup = new ServerSetup(-1, "localhost",
+ ServerSetup.PROTOCOL_SMTP);
+ GreenMail greenMail = new GreenMail((ServerSetup) null);
+ // greenMail.start();
+ } catch (Throwable e) {
+ StackTraceElement[] stea = e.getStackTrace();
+ if (versionExtraction) {
+ for (StackTraceElement ste : stea) {
+ String className = ste.getClassName();
+ PackageInfo pi = Util.getPackageInfo(className);
+ }
+ }
+ }
+ }
+
+ double loop(int len, boolean ve) {
+ long start = System.nanoTime();
+ for (int i = 0; i < len; i++) {
+ doPerf(ve);
+ }
+ return (1.0*System.nanoTime() - start)/len/1000;
+ }
+
+ @Test
+ @Ignore
+ public void perfTest() {
+ int len = 1000;
+ loop(len, false);
+ double d0 = loop(len, false);
+
+ System.out.println("false " + d0);
+
+ loop(len, true);
+ double d1 = loop(len, true);
+
+ System.out.println("false " + d1);
+ }
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/Event.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/Event.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,20 @@
+package ch.qos.logback.classic.pattern.lru;
+
+public class Event<K> {
+
+ final public boolean put;
+ final public K k;
+
+ public Event(boolean put, K k) {
+ this.put = put;
+ this.k = k;
+ }
+
+ public String toString() {
+ if(put) {
+ return "Event: put, "+k;
+ } else {
+ return "Event: get, "+k;
+ }
+ }
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_Entry.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_Entry.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,32 @@
+package ch.qos.logback.classic.pattern.lru;
+
+public class T_Entry<K> implements Comparable {
+
+ K k;
+ long sequenceNumber;
+
+ T_Entry(K k, long sn) {
+ this.k = k;
+ this.sequenceNumber = sn;
+ }
+
+ public int compareTo(Object o) {
+ if(!(o instanceof T_Entry)) {
+ throw new IllegalArgumentException("arguments must be of type "+T_Entry.class);
+ }
+
+ T_Entry other = (T_Entry) o;
+ if(sequenceNumber > other.sequenceNumber) {
+ return 1;
+ }
+ if(sequenceNumber == other.sequenceNumber) {
+ return 0;
+ }
+ return -1;
+ }
+ @Override
+ public String toString() {
+ return "("+k+","+sequenceNumber+")";
+ //return "("+k+")";
+ }
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java Tue Sep 2 18:34:48 2008
@@ -0,0 +1,88 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.pattern.lru;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This is an alternative (slower) implementation of LRUCache for testing
+ * purposes.
+ *
+ * @author Ceki Gulcu
+ */
+public class T_LRUCache<K> {
+
+ int sequenceNumber;
+ final int cacheSize;
+ List<T_Entry<K>> cacheList = new LinkedList<T_Entry<K>>();
+
+ public T_LRUCache(int size) {
+ this.cacheSize = size;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void put(K k) {
+ sequenceNumber++;
+ T_Entry<K> te = getEntry(k);
+ if (te != null) {
+ te.sequenceNumber = sequenceNumber;
+ } else {
+ te = new T_Entry<K>(k, sequenceNumber);
+ cacheList.add(te);
+ }
+ Collections.sort(cacheList);
+ while(cacheList.size() > cacheSize) {
+ cacheList.remove(0);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public K get(K k) {
+ T_Entry<K> te = getEntry(k);
+ if (te == null) {
+ return null;
+ } else {
+ te.sequenceNumber = ++sequenceNumber;
+ Collections.sort(cacheList);
+ return te.k;
+ }
+ }
+
+ public List<K> ketList() {
+ List<K> keyList = new ArrayList<K>();
+ for (T_Entry<K> e : cacheList) {
+ keyList.add(e.k);
+ }
+ return keyList;
+ }
+
+ private T_Entry<K> getEntry(K k) {
+ for (int i = 0; i < cacheList.size(); i++) {
+ T_Entry<K> te = cacheList.get(i);
+ if (te.k.equals(k)) {
+ return te;
+ }
+ }
+ return null;
+ }
+
+ public void dump() {
+ System.out.print("T:");
+ for (T_Entry<K> te : cacheList) {
+ //System.out.print(te.toString()+"->");
+ System.out.print(te.k+", ");
+ }
+ System.out.println();
+ }
+
+}
More information about the logback-dev
mailing list