提交 c937b4b4 authored 作者: Thomas Mueller's avatar Thomas Mueller

Prepare release

上级 e8c85730
...@@ -17,6 +17,10 @@ Change Log ...@@ -17,6 +17,10 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>-
</li></ul>
<h2>Version 1.4.180 Beta (2014-07-13)</h2>
<ul><li>MVStore: the store is now auto-compacted automatically up to some point, <ul><li>MVStore: the store is now auto-compacted automatically up to some point,
to avoid very large file sizes. This area is still work in progress. to avoid very large file sizes. This area is still work in progress.
</li><li>Sequences of temporary tables (auto-increment or identity columns) </li><li>Sequences of temporary tables (auto-increment or identity columns)
...@@ -27,11 +31,11 @@ Change Log ...@@ -27,11 +31,11 @@ Change Log
</li><li>The LIRS cache now re-sizes the internal hash map if needed. </li><li>The LIRS cache now re-sizes the internal hash map if needed.
</li><li>Optionally persist session history in the H2 console. (patch from Martin Grajcar) </li><li>Optionally persist session history in the H2 console. (patch from Martin Grajcar)
</li><li>Add client-info property to get the number of servers currently in the cluster </li><li>Add client-info property to get the number of servers currently in the cluster
and which servers that are available. (patch from Nikolaj Fogh) and which servers that are available. (patch from Nikolaj Fogh)
</li><li>Fix bug in changing encrypted DB password that kept the file handle </li><li>Fix bug in changing encrypted DB password that kept the file handle
open when the wrong password was supplied. (test case from Jens Hohmuth). open when the wrong password was supplied. (test case from Jens Hohmuth).
</li><li>Issue 567: h2 hangs for a long time then (sometimes) recovers. </li><li>Issue 567: H2 hangs for a long time then (sometimes) recovers.
Introduce a queue when doing table locking to prevent session starvation. Introduce a queue when doing table locking to prevent session starvation.
</li></ul> </li></ul>
<h2>Version 1.4.179 Beta (2014-06-23)</h2> <h2>Version 1.4.179 Beta (2014-06-23)</h2>
......
...@@ -16,7 +16,7 @@ public class Constants { ...@@ -16,7 +16,7 @@ public class Constants {
/** /**
* The build date is updated for each public release. * The build date is updated for each public release.
*/ */
public static final String BUILD_DATE = "2014-06-23"; public static final String BUILD_DATE = "2014-07-13";
/** /**
* The build date of the last stable release. * The build date of the last stable release.
...@@ -26,7 +26,7 @@ public class Constants { ...@@ -26,7 +26,7 @@ public class Constants {
/** /**
* The build id is incremented for each public release. * The build id is incremented for each public release.
*/ */
public static final int BUILD_ID = 179; public static final int BUILD_ID = 180;
/** /**
* The build id of the last stable release. * The build id of the last stable release.
......
...@@ -186,7 +186,7 @@ public class Chunk { ...@@ -186,7 +186,7 @@ public class Chunk {
/** /**
* Calculate the fill rate in %. 0 means empty, 100 means full. * Calculate the fill rate in %. 0 means empty, 100 means full.
* *
* @return the fill rate * @return the fill rate
*/ */
public int getFillRate() { public int getFillRate() {
......
...@@ -9,24 +9,40 @@ import java.util.Iterator; ...@@ -9,24 +9,40 @@ import java.util.Iterator;
/** /**
* A very simple linked list that supports concurrent access. * A very simple linked list that supports concurrent access.
* Internally, it uses immutable objects. * Internally, it uses immutable objects.
* It uses recursion and is not meant for long lists. * It uses recursion and is not meant for long lists.
* *
* @param <K> the key type * @param <K> the key type
*/ */
public class ConcurrentLinkedList<K> { public class ConcurrentLinkedList<K> {
/**
* The sentinel entry.
*/
static final Entry<?> NULL = new Entry<Object>(null, null); static final Entry<?> NULL = new Entry<Object>(null, null);
/**
* The head entry.
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
volatile Entry<K> head = (Entry<K>) NULL; volatile Entry<K> head = (Entry<K>) NULL;
/**
* Get the first element, or null if none.
*
* @return the first element
*/
public K peekFirst() { public K peekFirst() {
Entry<K> x = head; Entry<K> x = head;
return x.obj; return x.obj;
} }
/**
* Get the last element, or null if none.
*
* @return the last element
*/
public K peekLast() { public K peekLast() {
Entry<K> x = head; Entry<K> x = head;
while (x != NULL && x.next != NULL) { while (x != NULL && x.next != NULL) {
...@@ -35,10 +51,21 @@ public class ConcurrentLinkedList<K> { ...@@ -35,10 +51,21 @@ public class ConcurrentLinkedList<K> {
return x.obj; return x.obj;
} }
/**
* Add an element at the end.
*
* @param obj the element
*/
public synchronized void add(K obj) { public synchronized void add(K obj) {
head = Entry.append(head, obj); head = Entry.append(head, obj);
} }
/**
* Remove the first element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public synchronized boolean removeFirst(K obj) { public synchronized boolean removeFirst(K obj) {
if (head.obj != obj) { if (head.obj != obj) {
return false; return false;
...@@ -47,6 +74,12 @@ public class ConcurrentLinkedList<K> { ...@@ -47,6 +74,12 @@ public class ConcurrentLinkedList<K> {
return true; return true;
} }
/**
* Remove the last element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public synchronized boolean removeLast(K obj) { public synchronized boolean removeLast(K obj) {
if (peekLast() != obj) { if (peekLast() != obj) {
return false; return false;
...@@ -55,6 +88,11 @@ public class ConcurrentLinkedList<K> { ...@@ -55,6 +88,11 @@ public class ConcurrentLinkedList<K> {
return true; return true;
} }
/**
* Get an iterator over all entries.
*
* @return the iterator
*/
public Iterator<K> iterator() { public Iterator<K> iterator() {
return new Iterator<K>() { return new Iterator<K>() {
...@@ -86,7 +124,7 @@ public class ConcurrentLinkedList<K> { ...@@ -86,7 +124,7 @@ public class ConcurrentLinkedList<K> {
private static class Entry<K> { private static class Entry<K> {
final K obj; final K obj;
Entry<K> next; Entry<K> next;
Entry(K obj, Entry<K> next) { Entry(K obj, Entry<K> next) {
this.obj = obj; this.obj = obj;
this.next = next; this.next = next;
...@@ -99,7 +137,7 @@ public class ConcurrentLinkedList<K> { ...@@ -99,7 +137,7 @@ public class ConcurrentLinkedList<K> {
} }
return new Entry<K>(list.obj, append(list.next, obj)); return new Entry<K>(list.obj, append(list.next, obj));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <K> Entry<K> removeLast(Entry<K> list) { static <K> Entry<K> removeLast(Entry<K> list) {
if (list == NULL || list.next == NULL) { if (list == NULL || list.next == NULL) {
......
...@@ -52,8 +52,8 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -52,8 +52,8 @@ public class MVMap<K, V> extends AbstractMap<K, V>
private long createVersion; private long createVersion;
private final DataType keyType; private final DataType keyType;
private final DataType valueType; private final DataType valueType;
private ConcurrentLinkedList<Page> oldRoots = private ConcurrentLinkedList<Page> oldRoots =
new ConcurrentLinkedList<Page>(); new ConcurrentLinkedList<Page>();
private boolean closed; private boolean closed;
...@@ -1169,7 +1169,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1169,7 +1169,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
if (last == null || version < last.getVersion()) { if (last == null || version < last.getVersion()) {
// smaller than all in-memory versions // smaller than all in-memory versions
return store.openMapVersion(version, id, this); return store.openMapVersion(version, id, this);
} }
Iterator<Page> it = oldRoots.iterator(); Iterator<Page> it = oldRoots.iterator();
while (it.hasNext()) { while (it.hasNext()) {
Page p = it.next(); Page p = it.next();
...@@ -1251,6 +1251,11 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1251,6 +1251,11 @@ public class MVMap<K, V> extends AbstractMap<K, V>
this.writeVersion = writeVersion; this.writeVersion = writeVersion;
} }
/**
* Copy a map. All pages are copied.
*
* @param sourceMap the source map
*/
void copyFrom(MVMap<K, V> sourceMap) { void copyFrom(MVMap<K, V> sourceMap) {
; // TODO work in progress ; // TODO work in progress
root = copy(sourceMap.root, null); root = copy(sourceMap.root, null);
......
...@@ -237,7 +237,7 @@ public class MVStore { ...@@ -237,7 +237,7 @@ public class MVStore {
* The delay in milliseconds to automatically commit and write changes. * The delay in milliseconds to automatically commit and write changes.
*/ */
private int autoCommitDelay; private int autoCommitDelay;
private int autoCompactFillRate = 10; private int autoCompactFillRate = 10;
private int autoCompactSize = 2 * 1024 * 1024; private int autoCompactSize = 2 * 1024 * 1024;
......
...@@ -164,6 +164,14 @@ public class Page { ...@@ -164,6 +164,14 @@ public class Page {
return p; return p;
} }
/**
* Create a copy of a page.
*
* @param map the map
* @param version the version
* @param source the source page
* @return the page
*/
public static Page create(MVMap<?, ?> map, long version, Page source) { public static Page create(MVMap<?, ?> map, long version, Page source) {
Page p = new Page(map, version); Page p = new Page(map, version);
// the position is 0 // the position is 0
......
...@@ -52,8 +52,10 @@ public class MVTable extends TableBase { ...@@ -52,8 +52,10 @@ public class MVTable extends TableBase {
private long lastModificationId; private long lastModificationId;
private volatile Session lockExclusiveSession; private volatile Session lockExclusiveSession;
private final HashSet<Session> lockSharedSessions = New.hashSet(); private final HashSet<Session> lockSharedSessions = New.hashSet();
/** /**
* FIFO queue to prevent starvation, since Java's synchronized locking is biased. * The queue of sessions waiting to lock the table. It is a FIFO queue to
* prevent starvation, since Java's synchronized locking is biased.
*/ */
private final ArrayDeque<Session> waitingSessions = new ArrayDeque<Session>(); private final ArrayDeque<Session> waitingSessions = new ArrayDeque<Session>();
private final Trace traceLock; private final Trace traceLock;
...@@ -96,7 +98,8 @@ public class MVTable extends TableBase { ...@@ -96,7 +98,8 @@ public class MVTable extends TableBase {
} }
@Override @Override
public void lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc) { public void lock(Session session, boolean exclusive,
boolean forceLockEvenInMvcc) {
int lockMode = database.getLockMode(); int lockMode = database.getLockMode();
if (lockMode == Constants.LOCK_MODE_OFF) { if (lockMode == Constants.LOCK_MODE_OFF) {
return; return;
...@@ -187,7 +190,7 @@ public class MVTable extends TableBase { ...@@ -187,7 +190,7 @@ public class MVTable extends TableBase {
} }
} }
} }
private boolean doLock2(Session session, int lockMode, boolean exclusive) { private boolean doLock2(Session session, int lockMode, boolean exclusive) {
if (exclusive) { if (exclusive) {
if (lockExclusiveSession == null) { if (lockExclusiveSession == null) {
...@@ -196,7 +199,8 @@ public class MVTable extends TableBase { ...@@ -196,7 +199,8 @@ public class MVTable extends TableBase {
session.addLock(this); session.addLock(this);
lockExclusiveSession = session; lockExclusiveSession = session;
return true; return true;
} else if (lockSharedSessions.size() == 1 && lockSharedSessions.contains(session)) { } else if (lockSharedSessions.size() == 1 &&
lockSharedSessions.contains(session)) {
traceLock(session, exclusive, "add (upgraded) for "); traceLock(session, exclusive, "add (upgraded) for ");
lockExclusiveSession = session; lockExclusiveSession = session;
return true; return true;
......
...@@ -55,8 +55,10 @@ public class RegularTable extends TableBase { ...@@ -55,8 +55,10 @@ public class RegularTable extends TableBase {
private long rowCount; private long rowCount;
private volatile Session lockExclusiveSession; private volatile Session lockExclusiveSession;
private HashSet<Session> lockSharedSessions = New.hashSet(); private HashSet<Session> lockSharedSessions = New.hashSet();
/** /**
* FIFO queue to prevent starvation, since Java's synchronized locking is biased. * The queue of sessions waiting to lock the table. It is a FIFO queue to
* prevent starvation, since Java's synchronized locking is biased.
*/ */
private final ArrayDeque<Session> waitingSessions = new ArrayDeque<Session>(); private final ArrayDeque<Session> waitingSessions = new ArrayDeque<Session>();
private final Trace traceLock; private final Trace traceLock;
...@@ -437,7 +439,8 @@ public class RegularTable extends TableBase { ...@@ -437,7 +439,8 @@ public class RegularTable extends TableBase {
} }
@Override @Override
public void lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc) { public void lock(Session session, boolean exclusive,
boolean forceLockEvenInMvcc) {
int lockMode = database.getLockMode(); int lockMode = database.getLockMode();
if (lockMode == Constants.LOCK_MODE_OFF) { if (lockMode == Constants.LOCK_MODE_OFF) {
return; return;
...@@ -532,7 +535,8 @@ public class RegularTable extends TableBase { ...@@ -532,7 +535,8 @@ public class RegularTable extends TableBase {
session.addLock(this); session.addLock(this);
lockExclusiveSession = session; lockExclusiveSession = session;
return true; return true;
} else if (lockSharedSessions.size() == 1 && lockSharedSessions.contains(session)) { } else if (lockSharedSessions.size() == 1 &&
lockSharedSessions.contains(session)) {
traceLock(session, exclusive, "add (upgraded) for "); traceLock(session, exclusive, "add (upgraded) for ");
lockExclusiveSession = session; lockExclusiveSession = session;
return true; return true;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
CREATE TABLE VERSION(ID INT PRIMARY KEY, VERSION VARCHAR, CREATED VARCHAR); CREATE TABLE VERSION(ID INT PRIMARY KEY, VERSION VARCHAR, CREATED VARCHAR);
INSERT INTO VERSION VALUES INSERT INTO VERSION VALUES
(130, '1.4.180', '2014-07-13'),
(129, '1.4.179', '2014-06-23'), (129, '1.4.179', '2014-06-23'),
(128, '1.4.178', '2014-05-02'), (128, '1.4.178', '2014-05-02'),
(127, '1.4.177', '2014-04-12'), (127, '1.4.177', '2014-04-12'),
......
...@@ -252,7 +252,7 @@ public class TestCluster extends TestBase { ...@@ -252,7 +252,7 @@ public class TestCluster extends TestBase {
n1.stop(); n1.stop();
deleteFiles(); deleteFiles();
} }
private void testClientInfo() throws SQLException { private void testClientInfo() throws SQLException {
if (config.memory || config.networked || config.cipher != null) { if (config.memory || config.networked || config.cipher != null) {
return; return;
...@@ -294,7 +294,7 @@ public class TestCluster extends TestBase { ...@@ -294,7 +294,7 @@ public class TestCluster extends TestBase {
conn = getConnection(urlCluster, user, password); conn = getConnection(urlCluster, user, password);
p = conn.getClientInfo(); p = conn.getClientInfo();
assertEquals("1", p.getProperty("numServers")); assertEquals("1", p.getProperty("numServers"));
assertEquals("127.0.0.1:" + port1, p.getProperty("server0")); assertEquals("127.0.0.1:" + port1, p.getProperty("server0"));
assertEquals("1", conn.getClientInfo("numServers")); assertEquals("1", conn.getClientInfo("numServers"));
...@@ -304,7 +304,7 @@ public class TestCluster extends TestBase { ...@@ -304,7 +304,7 @@ public class TestCluster extends TestBase {
n1.stop(); n1.stop();
deleteFiles(); deleteFiles();
} }
private void testCreateClusterAtRuntime() throws SQLException { private void testCreateClusterAtRuntime() throws SQLException {
if (config.memory || config.networked || config.cipher != null) { if (config.memory || config.networked || config.cipher != null) {
return; return;
......
...@@ -21,7 +21,7 @@ public class TestConcurrentLinkedList extends TestBase { ...@@ -21,7 +21,7 @@ public class TestConcurrentLinkedList extends TestBase {
/** /**
* Run just this test. * Run just this test.
* *
* @param a ignored * @param a ignored
*/ */
public static void main(String... a) throws Exception { public static void main(String... a) throws Exception {
...@@ -35,7 +35,7 @@ public class TestConcurrentLinkedList extends TestBase { ...@@ -35,7 +35,7 @@ public class TestConcurrentLinkedList extends TestBase {
testRandomized(); testRandomized();
testConcurrent(); testConcurrent();
} }
private void testPerformance() { private void testPerformance() {
testPerformance(true); testPerformance(true);
testPerformance(false); testPerformance(false);
...@@ -44,7 +44,7 @@ public class TestConcurrentLinkedList extends TestBase { ...@@ -44,7 +44,7 @@ public class TestConcurrentLinkedList extends TestBase {
testPerformance(true); testPerformance(true);
testPerformance(false); testPerformance(false);
} }
private void testPerformance(final boolean stock) { private void testPerformance(final boolean stock) {
System.out.print(stock ? "stock " : "custom "); System.out.print(stock ? "stock " : "custom ");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
...@@ -191,7 +191,7 @@ public class TestConcurrentLinkedList extends TestBase { ...@@ -191,7 +191,7 @@ public class TestConcurrentLinkedList extends TestBase {
} }
} }
} }
private static <T> String toString(Iterator<T> it) { private static <T> String toString(Iterator<T> it) {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
while (it.hasNext()) { while (it.hasNext()) {
......
...@@ -32,7 +32,8 @@ public class TestMVStoreTool extends TestBase { ...@@ -32,7 +32,8 @@ public class TestMVStoreTool extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
testCompress(); ; // TODO work in progress
// testCompress();
} }
private void testCompress() { private void testCompress() {
...@@ -51,7 +52,6 @@ public class TestMVStoreTool extends TestBase { ...@@ -51,7 +52,6 @@ public class TestMVStoreTool extends TestBase {
} }
} }
s.close(); s.close();
; // TODO testing
// MVStoreTool.dump(fileName); // MVStoreTool.dump(fileName);
// MVStoreTool.dump(fileName + ".new"); // MVStoreTool.dump(fileName + ".new");
MVStoreTool.compress(fileName, fileName + ".new"); MVStoreTool.compress(fileName, fileName + ".new");
......
...@@ -760,4 +760,4 @@ inaccuracies detector logos launcher rewrite monitors equivalents trademarks ...@@ -760,4 +760,4 @@ inaccuracies detector logos launcher rewrite monitors equivalents trademarks
reinstated uninteresting dead defendant doctrines beat factual fair suspended reinstated uninteresting dead defendant doctrines beat factual fair suspended
exploit noise ongoing disclaimers shrinks remedy party desirable timely construe exploit noise ongoing disclaimers shrinks remedy party desirable timely construe
deque synchronizers affero kevent nikolaj hohmuth grajcar jens fogh hostnames deque synchronizers affero kevent nikolaj hohmuth grajcar jens fogh hostnames
operate resized operate resized jni yjp ownable starvation reaper biased introduce epoll hangs
...@@ -11,24 +11,46 @@ import org.h2.mvstore.DataUtils; ...@@ -11,24 +11,46 @@ import org.h2.mvstore.DataUtils;
/** /**
* A very simple linked list that supports concurrent access. * A very simple linked list that supports concurrent access.
* *
* @param <K> the key type * @param <K> the key type
*/ */
public class ConcurrentLinkedListWithTail<K> { public class ConcurrentLinkedListWithTail<K> {
/**
* The first entry (if any).
*/
volatile Entry<K> head; volatile Entry<K> head;
/**
* The last entry (if any).
*/
private volatile Entry<K> tail; private volatile Entry<K> tail;
/**
* Get the first element, or null if none.
*
* @return the first element
*/
public K peekFirst() { public K peekFirst() {
Entry<K> x = head; Entry<K> x = head;
return x == null ? null : x.obj; return x == null ? null : x.obj;
} }
/**
* Get the last element, or null if none.
*
* @return the last element
*/
public K peekLast() { public K peekLast() {
Entry<K> x = tail; Entry<K> x = tail;
return x == null ? null : x.obj; return x == null ? null : x.obj;
} }
/**
* Add an element at the end.
*
* @param obj the element
*/
public void add(K obj) { public void add(K obj) {
Entry<K> x = new Entry<K>(obj); Entry<K> x = new Entry<K>(obj);
Entry<K> t = tail; Entry<K> t = tail;
...@@ -40,7 +62,13 @@ public class ConcurrentLinkedListWithTail<K> { ...@@ -40,7 +62,13 @@ public class ConcurrentLinkedListWithTail<K> {
head = x; head = x;
} }
} }
/**
* Remove the first element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeFirst(K obj) { public boolean removeFirst(K obj) {
Entry<K> x = head; Entry<K> x = head;
if (x == null || x.obj != obj) { if (x == null || x.obj != obj) {
...@@ -53,6 +81,12 @@ public class ConcurrentLinkedListWithTail<K> { ...@@ -53,6 +81,12 @@ public class ConcurrentLinkedListWithTail<K> {
return true; return true;
} }
/**
* Remove the last element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeLast(K obj) { public boolean removeLast(K obj) {
Entry<K> x = head; Entry<K> x = head;
if (x == null) { if (x == null) {
...@@ -76,6 +110,11 @@ public class ConcurrentLinkedListWithTail<K> { ...@@ -76,6 +110,11 @@ public class ConcurrentLinkedListWithTail<K> {
return true; return true;
} }
/**
* Get an iterator over all entries.
*
* @return the iterator
*/
public Iterator<K> iterator() { public Iterator<K> iterator() {
return new Iterator<K>() { return new Iterator<K>() {
...@@ -107,7 +146,7 @@ public class ConcurrentLinkedListWithTail<K> { ...@@ -107,7 +146,7 @@ public class ConcurrentLinkedListWithTail<K> {
private static class Entry<K> { private static class Entry<K> {
final K obj; final K obj;
Entry<K> next; Entry<K> next;
Entry(K obj) { Entry(K obj) {
this.obj = obj; this.obj = obj;
} }
......
...@@ -11,28 +11,54 @@ import org.h2.mvstore.DataUtils; ...@@ -11,28 +11,54 @@ import org.h2.mvstore.DataUtils;
/** /**
* A ring buffer that supports concurrent access. * A ring buffer that supports concurrent access.
* *
* @param <K> the key type * @param <K> the key type
*/ */
public class ConcurrentRing<K> { public class ConcurrentRing<K> {
/**
* The ring buffer.
*/
K[] buffer; K[] buffer;
/**
* The read position.
*/
volatile int readPos; volatile int readPos;
/**
* The write position.
*/
volatile int writePos; volatile int writePos;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public ConcurrentRing() { public ConcurrentRing() {
buffer = (K[]) new Object[4]; buffer = (K[]) new Object[4];
} }
/**
* Get the first element, or null if none.
*
* @return the first element
*/
public K peekFirst() { public K peekFirst() {
return buffer[getIndex(readPos)]; return buffer[getIndex(readPos)];
} }
/**
* Get the last element, or null if none.
*
* @return the last element
*/
public K peekLast() { public K peekLast() {
return buffer[getIndex(writePos - 1)]; return buffer[getIndex(writePos - 1)];
} }
/**
* Add an element at the end.
*
* @param obj the element
*/
public void add(K obj) { public void add(K obj) {
buffer[getIndex(writePos)] = obj; buffer[getIndex(writePos)] = obj;
writePos++; writePos++;
...@@ -48,7 +74,13 @@ public class ConcurrentRing<K> { ...@@ -48,7 +74,13 @@ public class ConcurrentRing<K> {
buffer = b2; buffer = b2;
} }
} }
/**
* Remove the first element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeFirst(K obj) { public boolean removeFirst(K obj) {
int p = readPos; int p = readPos;
int idx = getIndex(p); int idx = getIndex(p);
...@@ -60,6 +92,12 @@ public class ConcurrentRing<K> { ...@@ -60,6 +92,12 @@ public class ConcurrentRing<K> {
return true; return true;
} }
/**
* Remove the last element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeLast(K obj) { public boolean removeLast(K obj) {
int p = writePos; int p = writePos;
int idx = getIndex(p - 1); int idx = getIndex(p - 1);
...@@ -70,11 +108,22 @@ public class ConcurrentRing<K> { ...@@ -70,11 +108,22 @@ public class ConcurrentRing<K> {
writePos = p - 1; writePos = p - 1;
return true; return true;
} }
/**
* Get the index in the array of the given position.
*
* @param pos the position
* @return the index
*/
int getIndex(int pos) { int getIndex(int pos) {
return pos & (buffer.length - 1); return pos & (buffer.length - 1);
} }
/**
* Get an iterator over all entries.
*
* @return the iterator
*/
public Iterator<K> iterator() { public Iterator<K> iterator() {
return new Iterator<K>() { return new Iterator<K>() {
...@@ -102,5 +151,5 @@ public class ConcurrentRing<K> { ...@@ -102,5 +151,5 @@ public class ConcurrentRing<K> {
}; };
} }
} }
...@@ -21,28 +21,28 @@ import java.util.regex.Pattern; ...@@ -21,28 +21,28 @@ import java.util.regex.Pattern;
* A tool that removes uninteresting lines from stack traces. * A tool that removes uninteresting lines from stack traces.
*/ */
public class ThreadDumpCleaner { public class ThreadDumpCleaner {
private static final String[] PATTERN = { private static final String[] PATTERN = {
"\\$\\$YJP\\$\\$", "\\$\\$YJP\\$\\$",
"\"(Attach|Service|VM|GC|DestroyJavaVM|Signal|AWT|AppKit|C2 |" + "\"(Attach|Service|VM|GC|DestroyJavaVM|Signal|AWT|AppKit|C2 |" +
"process reaper|YJPAgent-).*?\"(?s).*?\n\n", "process reaper|YJPAgent-).*?\"(?s).*?\n\n",
" Locked ownable synchronizers:(?s).*?\n\n", " Locked ownable synchronizers:(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State: (TIMED_)?WAITING(?s).*?\n\n", "\".*?\".*?\n java.lang.Thread.State: (TIMED_)?WAITING(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State:.*\n\t" + "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
"at sun.nio.ch.KQueueArrayWrapper.kevent0(?s).*?\n\n", "at sun.nio.ch.KQueueArrayWrapper.kevent0(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State:.*\n\t" + "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
"at java.io.FileInputStream.readBytes(?s).*?\n\n", "at java.io.FileInputStream.readBytes(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State:.*\n\t" + "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
"at sun.nio.ch.ServerSocketChannelImpl.accept(?s).*?\n\n", "at sun.nio.ch.ServerSocketChannelImpl.accept(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State:.*\n\t" + "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
"at sun.nio.ch.EPollArrayWrapper.epollWait(?s).*?\n\n", "at sun.nio.ch.EPollArrayWrapper.epollWait(?s).*?\n\n",
"\".*?\".*?\n java.lang.Thread.State:.*\n\t" + "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
"at java.lang.Object.wait(?s).*?\n\n", "at java.lang.Object.wait(?s).*?\n\n",
"JNI global references:.*\n\n", "JNI global references:.*\n\n",
}; };
private ArrayList<Pattern> patterns = new ArrayList<Pattern>(); private ArrayList<Pattern> patterns = new ArrayList<Pattern>();
{ {
for (String s : PATTERN) { for (String s : PATTERN) {
patterns.add(Pattern.compile(s)); patterns.add(Pattern.compile(s));
...@@ -76,10 +76,10 @@ public class ThreadDumpCleaner { ...@@ -76,10 +76,10 @@ public class ThreadDumpCleaner {
r = new InputStreamReader(System.in); r = new InputStreamReader(System.in);
} }
new ThreadDumpCleaner().run( new ThreadDumpCleaner().run(
new LineNumberReader(new BufferedReader(r)), new LineNumberReader(new BufferedReader(r)),
writer); writer);
} }
private void run(LineNumberReader reader, PrintWriter writer) throws IOException { private void run(LineNumberReader reader, PrintWriter writer) throws IOException {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
while (true) { while (true) {
...@@ -94,13 +94,13 @@ public class ThreadDumpCleaner { ...@@ -94,13 +94,13 @@ public class ThreadDumpCleaner {
} }
} }
writer.println(filter(buff.toString())); writer.println(filter(buff.toString()));
} }
private String filter(String s) { private String filter(String s) {
for (Pattern p : patterns) { for (Pattern p : patterns) {
s = p.matcher(s).replaceAll(""); s = p.matcher(s).replaceAll("");
} }
return s; return s;
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论