roc230 / spymemcached

Automatically exported from code.google.com/p/spymemcached
0 stars 0 forks source link

memory leak on long network outages #267

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What version of the product are you using? On what operating system?
Memcache 2.8.4 on Linux

Hello,

there is a memory leak on long network outages.

In class src/main/java/net/spy/memcached/MemcachedConnection.java method 
handleInputQueue we added this code to prevent the memory leak:

Operation cwop = qa.getCurrentWriteOp();
if (cwop != null && cwop.isTimedOut()) {
qa.removeCurrentWriteOp();
getLogger().debug("Removed already timed out head from write-queue");           

  // Handle any requests that have been made against the client.
  private void handleInputQueue() {
    if (!addedQueue.isEmpty()) {
      getLogger().debug("Handling queue");
      // If there's stuff in the added queue. Try to process it.
      Collection<MemcachedNode> toAdd = new HashSet<MemcachedNode>();
      // Transfer the queue into a hashset. There are very likely more
      // additions than there are nodes.
      Collection<MemcachedNode> todo = new HashSet<MemcachedNode>();
      MemcachedNode qaNode = null;
      while ((qaNode = addedQueue.poll()) != null) {
        todo.add(qaNode);
      }

      // Now process the queue.
      for (MemcachedNode qa : todo) {
        boolean readyForIO = false;
        if (qa.isActive()) {
          if (qa.getCurrentWriteOp() != null) {
            readyForIO = true;
            getLogger().debug("Handling queued write %s", qa);
          }
        } else {
          toAdd.add(qa);
        }
        qa.copyInputQueue();
        if (readyForIO) {
            try {
                if (qa.getWbuf().hasRemaining()) {
                    handleWrites(qa.getSk(), qa);
                }
            } catch (IOException e) {
                getLogger().warn("Exception handling write", e);
                lostConnection(qa);
            }
        }
        else {
            Operation cwop = qa.getCurrentWriteOp();
            if (cwop != null && cwop.isTimedOut()) {
                qa.removeCurrentWriteOp();
                getLogger().debug("Removed already timed out head from write-queue");
            }
        }
        qa.fixupOps();
      }
      addedQueue.addAll(toAdd);
    }
  }

Can you commit the code changes to svn?

Best regards 

Original issue reported on code.google.com by sergej.w...@gmail.com on 29 Jan 2013 at 3:13

GoogleCodeExporter commented 9 years ago

Original comment by ingen...@gmail.com on 4 Mar 2013 at 8:43

GoogleCodeExporter commented 9 years ago
Memory leak cause is unbounded operation queues.
Just do:

ConnectionFactoryBuilder builder = new ConnectionFactoryBuilder()
  .setOpQueueFactory(new ConfigurableOperationQueueFactory(MAX_QUEUE_SIZE)
  .setReadOpQueueFactory(new ConfigurableOperationQueueFactory(...)
  .setWriteOpQueueFactory(new ConfigurableOperationQueueFactory(...)

public class ConfigurableOperationQueueFactory implements OperationQueueFactory 
{
  private int capacity;

  public ConfigurableOperationQueueFactory(int cap) {
    this.capacity = cap;
  }

  @Override
  public BlockingQueue<Operation> create() {
    if (capacity > 0) {
      return new ArrayBlockingQueue<>(capacity);
    } else {
      return new LinkedBlockingQueue<>();
    }
  }
}

Original comment by Panov.A...@gmail.com on 28 May 2015 at 9:50