IQueueRORA as interface, add an implementation using a Lock.

+ Use in AbstractLogNodeDispatcher.
This commit is contained in:
asofold 2017-04-10 14:29:37 +02:00
parent 73a62a1e13
commit 2de5f2fd3a
4 changed files with 179 additions and 62 deletions

View File

@ -17,6 +17,7 @@ package fr.neatmonster.nocheatplus.logging.details;
import java.util.List;
import java.util.logging.Level;
import fr.neatmonster.nocheatplus.utilities.ds.corw.IQueueRORA;
import fr.neatmonster.nocheatplus.utilities.ds.corw.QueueRORA;
/**
@ -32,8 +33,8 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
/**
* This queue has to be processed in a task within the primary thread with calling runLogsPrimary.
*/
protected final QueueRORA<LogRecord<?>> queuePrimary = new QueueRORA<LogRecord<?>>();
protected final QueueRORA<LogRecord<?>> queueAsynchronous = new QueueRORA<LogRecord<?>>();
protected final IQueueRORA<LogRecord<?>> queuePrimary = new QueueRORA<LogRecord<?>>();
protected final IQueueRORA<LogRecord<?>> queueAsynchronous = new QueueRORA<LogRecord<?>>();
/** Once a queue reaches this size, it will be reduced (loss of content). */
protected int maxQueueSize = 5000;
@ -111,7 +112,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
return runLogs(queueAsynchronous);
}
private boolean runLogs(final QueueRORA<LogRecord<?>> queue) {
private boolean runLogs(final IQueueRORA<LogRecord<?>> queue) {
// TODO: Consider allowYield + msYield, calling yield after 5 ms if async.
final List<LogRecord<?>> records = queue.removeAll();
if (records.isEmpty()) {
@ -206,7 +207,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
* Hard reduce the queue (heavy locking!).
* @param queue
*/
private void reduceQueue(final QueueRORA<LogRecord<?>> queue) {
private void reduceQueue(final IQueueRORA<LogRecord<?>> queue) {
// TODO: Different dropping strategies (drop first, last, alternate).
final int dropped;
synchronized (queue) {

View File

@ -0,0 +1,48 @@
package fr.neatmonster.nocheatplus.utilities.ds.corw;
import java.util.List;
/**
* Thread-safe queue - a replace-on-read-all queue-thing, supposedly exchanging
* the internally stored list by a new empty one under lock, for a very small
* locking time, so it is not really a typical copy-on-read. All methods use
* locking, implementation-specific.
*
* @author asofold
*
*/
public interface IQueueRORA<E> {
/**
* Add to list.
*
* @param element
* @return Size of queue after adding.
*/
public int add(final E element);
/**
*
* @return An ordinary List containing all elements. This should be the
* previously internally stored list, to keep locking time minimal.
*/
public List<E> removeAll();
/**
* Remove oldest entries until maxSize is reached.
*
* @param maxSize
* @return
*/
public int reduce(final int maxSize);
public void clear();
public boolean isEmpty();
public int size();
}

View File

@ -19,23 +19,18 @@ import java.util.List;
/**
* A replace-on-read-all queue-thing, exchanging the internal list under lock by
* a new empty one, for a small locking time, so it is not really a typical
* copy-on-read. All methods use locking, the QueueRORA instance is used for
* locking.
* IQueueRORA implementation using the synchronized keyword for locking, with a
* LinkedList inside.
*
* @author dev1mc
* @author asofold
*
* @param <E>
*/
public class QueueRORA<E> {
public class QueueRORA<E> implements IQueueRORA<E> {
private LinkedList<E> elements = new LinkedList<E>();
/**
* Add to list (synchronized).
* @param element
* @return Size of queue after adding.
*/
@Override
public int add(final E element) {
final int size;
synchronized (this) {
@ -45,10 +40,7 @@ public class QueueRORA<E> {
return size;
}
/**
*
* @return An ordinary (linked) List containing all elements.
*/
@Override
public List<E> removeAll() {
final List<E> result;
synchronized (this) {
@ -58,11 +50,7 @@ public class QueueRORA<E> {
return result;
}
/**
* Remove oldest entries until maxSize is reached.
* @param maxSize
* @return
*/
@Override
public int reduce(final int maxSize) {
int dropped = 0;
synchronized (this) {
@ -78,14 +66,12 @@ public class QueueRORA<E> {
return dropped;
}
@Override
public void clear() {
removeAll();
}
/**
*
* @return
*/
@Override
public boolean isEmpty() {
final boolean isEmpty;
synchronized (this) {
@ -94,10 +80,7 @@ public class QueueRORA<E> {
return isEmpty;
}
/**
*
* @return
*/
@Override
public int size() {
final int size;
synchronized (this) {

View File

@ -0,0 +1,85 @@
package fr.neatmonster.nocheatplus.utilities.ds.corw;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* IQueueRORA implementation using an external Lock or a ReentrantLock for
* locking, with a LinkedList inside.
*
* @author asofold
*
* @param <E>
*/
public class QueueRORAWithLock<E> implements IQueueRORA<E> {
private final Lock lock;
private LinkedList<E> elements = new LinkedList<E>();
public QueueRORAWithLock() {
this(new ReentrantLock());
}
public QueueRORAWithLock(Lock lock) {
this.lock = lock;
}
@Override
public int add(final E element) {
lock.lock();
elements.add(element);
final int size = elements.size();
lock.unlock();
return size;
}
@Override
public List<E> removeAll() {
lock.lock();
final List<E> result = elements;
elements = new LinkedList<E>();
lock.unlock();
return result;
}
@Override
public int reduce(final int maxSize) {
int dropped = 0;
lock.lock();
final int size = elements.size();
if (size <= maxSize) {
return dropped;
}
while (dropped < size - maxSize) {
elements.removeFirst();
dropped ++;
}
lock.unlock();
return dropped;
}
@Override
public void clear() {
removeAll();
}
@Override
public boolean isEmpty() {
lock.lock();
final boolean isEmpty = elements.isEmpty();
lock.unlock();
return isEmpty;
}
@Override
public int size() {
// TODO: Could maintain an int, simply.
lock.lock();
final int size = elements.size();
lock.unlock();
return size;
}
}