History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: CACHE-39
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Chris Miller
Reporter: Joseph Mocker
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
OSCache

LRUCache has multi-threading issues

Created: 29/May/03 03:54 PM   Updated: 14/May/06 08:50 AM
Component/s: Base Classes
Affects Version/s: 1.7.5
Fix Version/s: 2.0 beta 1

File Attachments: 1. Java Source File OSGeneralTest.java (1 kb)

Environment:
Solaris 2.9
JDK 1.3.1_07
SunBlade 2000 (dual processor machine)
Issue Links:
Duplicate
 
This issue is duplicated by:
CACHE-44 Multi threading issues with LRU Cache Major Closed
Related
This issue relates to:
CACHE-246 java.util.NoSuchElementException duri... Major Closed
 


 Description  « Hide
I've been evaluating OSCache for use on a project, and have run
across some thread safety issues, that apparently cause
memory "leaks". Attached is a very simple example that illustrates
the problem. It creates multiple threads which each use a single
GeneralCacheAdministrator object to retrieve a cache value.

When run with -verbose:gc, you will notice that memory usage
increases unbounded. The only case where this does not occur is
when the program is run with only a single thread.

This can be reproduced with the latest available version, 1.7.5.
I have been testing this on a Solaris 9, multi-processor machine.

---- Test Case ----

import com.opensymphony.module.oscache.general.*;
import com.opensymphony.module.oscache.base.*;
import com.opensymphony.module.oscache.*;

public class OSGeneralTest implements Runnable {

static GeneralCacheAdministrator admin = null;

static {
        try {
            admin = GeneralCacheAdministrator.getInstance();
        }
        catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

public void run() {
        for (;;) {
            doit();
        }
    }

public void doit() {
        
String myKey = "myKey";
        String myValue;
        int myRefreshPeriod = 60 /*seconds*/ * 1000 /*millis*/;
        
try {
            // Get from the cache
            myValue = (String) admin.getFromCache(myKey, myRefreshPeriod);
        }
        catch (NeedsRefreshException nre) {
            try {
                // Get the value (probably by calling an EJB)
                myValue = "This is the content retrieved.";
                // Store in the cache
                admin.putInCache(myKey, myValue);
                System.err.println("Put in cache");
            }
            catch (Exception ex) {
                // We have the current content if we want fail-over.
                myValue = (String) nre.getCacheContent();
            }
        }
    }

public static void main(String[] args) {
        if (args.length <= 0) {
            System.err.println("usage: java OSGeneralTest <threads>");
            System.exit(1);
        }

for (int idx = 0; idx < Integer.parseInt(args[0]); idx++) {
            OSGeneralTest runner = new OSGeneralTest();
            Thread thread = new Thread(runner);
            thread.start();
        }
    }
}




 All   Comments   Change History      Sort Order:
Joseph Mocker - [29/May/03 03:56 PM ]
Test Case.

Joseph Mocker - [29/May/03 03:58 PM ]
Jean-Philippe's comments on how to fix, which apparently fixes
the issue I have seen:


Granted, I ran a slightly modified version of your testcase in OptimizeIt and ended up with 50 000 cache entries after 2 mins even if my cache size was set to 100.

The problem seems to be in LRUCache.getItem. You should at least have a synchronized bloc like the following. With concurrency, the LinkedList entries falsely keep references (next, previous) on previously removed items.

synchronized (list)
        {
                list.remove(key);
                list.add(key);
        }

There is also a problem with the LRUCache.removeItem where 2 threads could enter this function, one would leave the function and setting the "removeInProgress = false" while the other would still be removing the item. To fix this, this function should be declared synchronized so that only one remove at the time would be tolerated.

Chris Miller - [01/Jun/03 03:46 PM ]
This has been fixed in the sandbox version of oscache.