ARTEMIS-1622 Reduce memory footprint of QueueImpl

LinkedListImpl is turned into an optionally intrusive linked list by allowing message references to extend Node.
This commit is contained in:
Francesco Nigro 2018-01-18 15:45:20 +01:00 committed by Michael Pearce
parent 71a49c4614
commit 3f646474c2
3 changed files with 34 additions and 12 deletions

View File

@ -18,6 +18,7 @@ package org.apache.activemq.artemis.utils.collections;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Objects;
/** /**
* A linked list implementation which allows multiple iterators to exist at the same time on the queue, and which see any * A linked list implementation which allows multiple iterators to exist at the same time on the queue, and which see any
@ -48,7 +49,7 @@ public class LinkedListImpl<E> implements LinkedList<E> {
@Override @Override
public void addHead(E e) { public void addHead(E e) {
Node<E> node = new Node<>(e); Node<E> node = Node.with(e);
node.next = head.next; node.next = head.next;
@ -71,7 +72,7 @@ public class LinkedListImpl<E> implements LinkedList<E> {
if (size == 0) { if (size == 0) {
addHead(e); addHead(e);
} else { } else {
Node<E> node = new Node<>(e); Node<E> node = Node.with(e);
node.prev = tail; node.prev = tail;
@ -217,23 +218,43 @@ public class LinkedListImpl<E> implements LinkedList<E> {
throw new IllegalStateException("Cannot find iter to remove"); throw new IllegalStateException("Cannot find iter to remove");
} }
private static final class Node<E> { public static class Node<T> {
Node<E> next; private Node<T> next;
Node<E> prev; private Node<T> prev;
final E val; private final T val;
int iterCount; private int iterCount;
Node(E e) { @SuppressWarnings("unchecked")
protected Node() {
val = (T)this;
}
//only the head is allowed to hold a null
private Node(T e) {
val = e; val = e;
} }
@Override @Override
public String toString() { public String toString() {
return "Node, value = " + val; return val == this ? "Intrusive Node" : "Node, value = " + val;
}
private static <T> Node<T> with(final T o) {
Objects.requireNonNull(o, "Only HEAD nodes are allowed to hold null values");
if (o instanceof Node) {
final Node node = (Node) o;
//only a node that not belong already to a list is allowed to be reused
if (node.prev == null && node.next == null) {
//reset the iterCount
node.iterCount = 0;
return node;
}
}
return new Node(o);
} }
} }

View File

@ -20,16 +20,16 @@ import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagedMessage;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.impl.AckReason; import org.apache.activemq.artemis.core.server.impl.AckReason;
import org.apache.activemq.artemis.core.transaction.Transaction; import org.apache.activemq.artemis.core.transaction.Transaction;
import org.apache.activemq.artemis.utils.collections.LinkedListImpl;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
public class PagedReferenceImpl implements PagedReference { public class PagedReferenceImpl extends LinkedListImpl.Node<PagedReferenceImpl> implements PagedReference {
private static final Logger logger = Logger.getLogger(PagedReferenceImpl.class); private static final Logger logger = Logger.getLogger(PagedReferenceImpl.class);

View File

@ -22,11 +22,12 @@ import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.transaction.Transaction; import org.apache.activemq.artemis.core.transaction.Transaction;
import org.apache.activemq.artemis.utils.collections.LinkedListImpl;
/** /**
* Implementation of a MessageReference * Implementation of a MessageReference
*/ */
public class MessageReferenceImpl implements MessageReference { public class MessageReferenceImpl extends LinkedListImpl.Node<MessageReferenceImpl> implements MessageReference {
private final AtomicInteger deliveryCount = new AtomicInteger(); private final AtomicInteger deliveryCount = new AtomicInteger();