Closed GoogleCodeExporter closed 9 years ago
Original comment by ingen...@gmail.com
on 10 Mar 2010 at 4:36
I looked at the threading access today around the offending queue and, if I
have my
analysis right, the readQ is only accessed from the spy thread. As such a
simple
temporary workaround of building a wrapper around LinkedBlockingQueue with an
embedded Set seems to work for me at present - not ideal, but a massive
improvement
on the performance. I can now add 500,000 items to the set and see that it
takes
41,300ms to add the data and 10,800ms to drain the queues. If you're
interested in
the code I can post (but it's pretty trivial). I also finally get to see
memcached
getting exercised (30-70% processor utilization rather than 0.1%).
Original comment by nickrior...@googlemail.com
on 10 Mar 2010 at 12:05
Nick - can you post your bug fix or integrate it into github?
I believe i'm running into this issue in production.
Original comment by spicysq...@gmail.com
on 9 Apr 2010 at 4:19
Hi spicysquid
The way I solved this was to create a wrapper around the LinkedBlockingQueue
that is
causing the problem. It contains a HashSet containing all the items in the
queue -
the contains() method can then use this efficiently. This works for two
reasons -
1. There is very limited threading going on (only one spy thread + your
application
threads) - and the communications between the threads are quite controlled.
2. Not all methods are used in the LinkedBlockingQueue - and in particular I
don't
have to implement the semantics of drainTo() (thankfully).
It's a monumental bodge, but it works neatly because you can slot it in via the
existing API by creating your own derivative of the ConnectionFactory and
overriding
createReadOperationQueue() to return the custom LinkedBlockingQueue.
Here's the wrapped Queue -
/**
* This is a temporary solution to the performance issues of the contains method being
* inefficient with long queues.
*/
public class CustomLinkedBlockingQueue<T> extends LinkedBlockingQueue<T> {
private Set<T> objectsInQueue = new HashSet<T>();
public CustomLinkedBlockingQueue() {
super();
}
public CustomLinkedBlockingQueue(int capacity) {
super(capacity);
}
public CustomLinkedBlockingQueue(Collection<T> c) {
super(c);
}
@Override
public void put(T t) throws InterruptedException {
super.put(t);
objectsInQueue.add(t);
}
@Override
public boolean offer(T t, long timeout, TimeUnit unit) throws InterruptedException {
boolean b = super.offer(t, timeout, unit);
if (b) {
objectsInQueue.add(t);
}
return b;
}
@Override
public boolean offer(T t) {
boolean b = super.offer(t);
if (b) {
objectsInQueue.add(t);
}
return b;
}
@Override
public T take() throws InterruptedException {
final T o = super.take();
objectsInQueue.remove(o);
return o;
}
@Override
public T poll(long timeout, TimeUnit unit) throws InterruptedException {
final T o = super.poll(timeout, unit);
if (o != null) {
objectsInQueue.remove(o);
}
return o;
}
@Override
public T poll() {
final T o = super.poll();
if (o != null) {
objectsInQueue.remove(o);
}
return o;
}
@Override
public boolean remove(Object o) {
boolean b = super.remove(o);
if (b) {
objectsInQueue.remove(o);
}
return b;
}
@Override
public int drainTo(Collection<? super T> c) {
int count = super.drainTo(c);
if (count > 0) {
objectsInQueue.removeAll(c);
}
return count;
}
@Override
public int drainTo(Collection<? super T> c, int maxElements) {
if (c.size() > 0) {
throw new UnsupportedOperationException("doesn't support this at present");
}
int count = super.drainTo(c, maxElements);
if (count > 0) {
objectsInQueue.removeAll(c);
}
return count;
}
@Override
public T remove() {
final T o = super.remove();
objectsInQueue.remove(o);
return o;
}
@Override
public boolean contains(Object o) {
return objectsInQueue.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return objectsInQueue.containsAll(c);
}
}
then create a new ConnectionFactory by
public class MyConnectionFactory extends DefaultConnectionFactory {
// ... constructors omitted for clarity ...
@Override
public BlockingQueue<Operation> createReadOperationQueue() {
return new CustomLinkedBlockingQueue<Operation>();
}
}
I hope that helps.
- Nick
Original comment by nickrior...@googlemail.com
on 9 Apr 2010 at 11:49
I am using this patch with one small change:
private Set<Operation> objectsInQueue = Collections.newSetFromMap(new
ConcurrentHashMap<Operation, Boolean>());
not sure if its necessary but I wanted to make sure the HashSet was thread-safe.
-Jonathan
Original comment by jonat...@gmail.com
on 15 Oct 2010 at 6:42
I have just begun working on a fix for this issue. Thanks to everyone for their
feedback as well as the test to reproduce this issue. I want to provide some
feedback on some of my findings from playing around with the code and then
later I will post another update when I have completed my fix.
First off I want to note that while this portion of code can definitely be
improved and should perform better, but anyone doing a sets at a very high rate
should still handle timeout issues and check to make sure that their set
operations are succeeding. I say this because even when I deleted the
!readQ.contains(o) and just added the operation to the read queue I was still
able to run into situations where I got large amounts of timeouts from my
operations. This is because no matter how much better we make the code
developers will still be io bound and if you write to the queues quicker than
they can be sent out on the network then operation timeouts will be inevitable.
Original comment by mikewie...@gmail.com
on 24 Aug 2011 at 12:11
I just committed a fix for this. It's in review right now. I'll post a jar with
patch on top of Spy 2.7.1 when it gets through review.
Original comment by mikewie...@gmail.com
on 24 Aug 2011 at 10:33
The fix has made it through review and will be in the Spy 2.8 beta and 2.7.2
releases of Spymemcached.
Original comment by mikewie...@gmail.com
on 5 Sep 2011 at 10:32
Here's the 2.7.2 jar that contains a fix for this issue. It's the first commits
on top of 2.7.1 so this is just 2.7.1 + Bug 125.
Original comment by mikewie...@gmail.com
on 6 Sep 2011 at 10:49
Attachments:
Thanks
Original comment by n...@anamatica.com
on 7 Sep 2011 at 5:28
Related to this: http://code.google.com/p/spymemcached/issues/detail?id=316
Original comment by oooctav...@gmail.com
on 22 Jan 2015 at 12:10
Original issue reported on code.google.com by
nickrior...@googlemail.com
on 9 Mar 2010 at 10:44