jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stephan lohwasser <stephan.lohwas...@systemone.at>
Subject Re: threading problems
Date Thu, 15 Dec 2005 17:04:06 GMT
hi again,
i wrote a test which (i hope) explains the problem (though i now get a 
different error message :) ):

i'm creating two threads each having a session and they read and write 
randomly into the repositiory:

package at.systemone.wiki.threadthreat;

import junit.framework.TestCase;
import org.apache.jackrabbit.core.jndi.RegistryHelper;
import org.apache.log4j.Logger;

import javax.jcr.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.File;
import java.util.Hashtable;
import java.util.Random;

/**
 *
 */
public class JCRThreadTest extends TestCase {

    protected Logger log;
    Repository r;

    public void setUp() throws Exception {
        super.setUp();
        r = createRepository();
    }

    public void testTwoThreads() throws NamingException, 
RepositoryException, InterruptedException {
        // create two distinct sessions
        Session s1 = createSession();
        Session s2 = createSession();

        // create two threads
        MyThread t1;
        MyThread t2;
        t1 = new MyThread(s1);
        t2 = new MyThread(s2);
        Thread th1 = new Thread(t1);
        Thread th2 = new Thread(t2);

        // let them roll
        th1.start();
        th2.start();

        // end
        th1.join();
        th2.join();
    }

    private Repository createRepository() throws NamingException, 
RepositoryException {
        deleteFolderStructure("repo");
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
"org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
        env.put(Context.PROVIDER_URL, "localhost");
        InitialContext ctx = new InitialContext(env);
        RegistryHelper.registerRepository(ctx, "repo", new 
File("repo/repository.xml").toString(), "repo", true);
        return (Repository) ctx.lookup("repo");
    }

    private Session createSession() throws RepositoryException, 
LoginException {
        SimpleCredentials cred = new SimpleCredentials("userid" + 
Math.random(), "".toCharArray());
        return r.login(cred, null);
    }

    private void deleteFolderStructure(String repHomeDir) {
        // called to errase the foldes which have been created during 
the test
        // setup
        deleteDirectory(new File(repHomeDir + "/meta"));
        deleteDirectory(new File(repHomeDir + "/versions"));
        deleteDirectory(new File(repHomeDir + "/nodetypes"));
        deleteDirectory(new File(repHomeDir + "/namespaces"));
        deleteDirectory(new File(repHomeDir + "/workspaces"));
    }

    private static boolean deleteDirectory(File path) {
        if (path.exists()) {
            File[] files = path.listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        return (path.delete());
    }

    // simple thread containing just the session and randomly 
reading/writing nodes
    class MyThread implements Runnable {
        private Session s;
        private Random r;

        public MyThread(Session s) {
            this.s = s;
            r = new Random();
        }

        public void run() {
            try {
                int i = r.nextInt();
                int counter = 0;
                String nodeName = "node" + i;
                while (counter++ < 100) {
                    try {
                        s.getRootNode().getNode(nodeName);
                    } catch (PathNotFoundException e) {
                        Node rootNode = s.getRootNode();
                        rootNode.addNode(nodeName);
                        s.save();
                    }
                    Thread.sleep((int) (Math.random() * 1000));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


this is what happens:

javax.jcr.InvalidItemStateException: 
cafebabe-cafe-babe-cafe-babecafebabe has been modified externally
    at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:1371)
    at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:765)
    at 
at.systemone.wiki.threadthreat.JCRThreadTest$MyThread.run(JCRThreadTest.java:110)
    at java.lang.Thread.run(Thread.java:595)

do you knwo what i do wrong?

cheers
stephan




Stefan Guggisberg schrieb:

>i quickly checked the implementation and i am pretty sure that
>you are sharing a session among multiple threads. the thread
>that does the import is most probably using the same session
>as the other thread that performs the write operations.
>
>cheers
>stefan
>
>On 12/15/05, Stefan Guggisberg <stefan.guggisberg@gmail.com> wrote:
>  
>
>>hi stephan
>>
>>On 12/15/05, stephan lohwasser <stephan.lohwasser@systemone.at> wrote:
>>    
>>
>>>hi,
>>>i have a problem concerning threads and synchronisation and i have not
>>>the faintest idea how to solve it:
>>>
>>>we're writing a wiki-weblog application based on jackrabbit. now when i
>>>run a thread importing data from wikipedia with one session while a
>>>normal user is logged into the system via another session, a
>>>'javax.jcr.RepositoryException: Unable to start edit operation: Already
>>>in edit mode: Already in edit mode' is thrown when the user tries to
>>>write or read data out of the repository.
>>>i guess it is a problem of multiple threads working on the same data,
>>>but i'm not sure.
>>>
>>>is there any synchronisation of sessions working on the repository, or
>>>do i have to take care of it by myself?
>>>do you have any hints for me?
>>>      
>>>
>>jackrabbit should be thread-safe although i can't guarantee that
>>there aren't still some hidden issues. as long as you don't share
>>Session objects among multiple threads there shouldn't be any
>>unexpected issues. if n threads modify the *same* item concurrently
>>only one thread will succeed and the others will get InvalidItemStateExceptions
>>informing them that their modifications have become stale.
>>this is by design. to prevent this you have to lock the node you're
>>working on.
>>
>>your problem though seems to be caused by another issue.
>>please provide a full thread dump and ideally some simple
>>code to reproduce the problem.
>>
>>cheers
>>stefan
>>
>>    
>>
>>>thanks a lot.
>>>stephan.
>>>
>>>
>>>
>>>      
>>>
>
>  
>


Mime
View raw message