Jackrabbit 和并发修改

发布于 2024-11-19 23:56:29 字数 4957 浏览 1 评论 0原文

在我们对使用 jackrabbit 的应用程序进行了一些性能测试之后,我们面临着并发修改 jackrabbit 存储库的巨大问题。当我们在多线程模拟中添加节点或编辑节点时,就会出现问题。然后我编写了非常简单的测试,这表明问题不在我们的环境中。

有它:

简单无状态Bean

     @Stateless
        @Local(TestFacadeLocal.class)
        @Remote(TestFacadeRemote.class)
        public class TestFacadeBean implements TestFacadeRemote, TestFacadeLocal {
            public void doAction(int name) throws Exception {
                new TestSynch().doAction(name);
            }
        }

简单类

    public class TestSynch {
        public void doAction(int name) throws Exception {
            Session session = ((Repository) new InitialContext().
                    lookup("java:jcr/local")).login(
                    new SimpleCredentials("username", "pwd".toCharArray()));
            List added = new ArrayList();
            Node folder = session.getRootNode().getNode("test");
            for (int i = 0; i <= 100; i++) {
                Node child = folder.addNode("" + System.currentTimeMillis(), 
                              "nt:folder");
                child.addMixin("mix:versionable");

                added.add(child);
            }
            // saving butch changes
            session.save();

            //checking in all created nodes
            for (Node node : added) {
                session.getWorkspace().getVersionManager().checkin(node.getPath());
            }
        }
    }

和测试类

    public class Test {
        private int c = 0;
        private int countAll = 50;
        private ExecutorService executor = Executors.newFixedThreadPool(5);

        public ExecutorService getExecutor() {
            return executor;
        }

        public static void main(String[] args) {
            Test test = new Test();
            try {
                test.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void start() throws Exception {
            long time = System.currentTimeMillis();
            TestFacadeRemote testBean = (TestFacadeRemote) getContext().
                                        lookup( "test/TestFacadeBean/remote");
            for (int i = 0; i < countAll; i++) {
                getExecutor().execute(new TestInstallerThread(i, testBean));
            }

            getExecutor().shutdown();
            while (!getExecutor().isTerminated()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(c + " shutdown " + 
                               (System.currentTimeMillis() - time));

        }

        class TestInstallerThread implements Runnable {
            private int number = 0;
            TestFacadeRemote testBean;

            public TestInstallerThread(int number, TestFacadeRemote testBean) {
                this.number = number;
                this.testBean = testBean;
            }

            @Override
            public void run() {
                try {
                    System.out.println("Installing data " + number);
                    testBean.doAction(number);
                    System.out.println("STOP" + number);
                } catch (Exception e) {
                    e.printStackTrace();
                    c++;
                }
            }

        }

        public Context getContext() throws NamingException {
            Properties properties = new Properties();
            //init props
            ..............
            return new InitialContext(properties);
        }
    }

如果我用池中的1个线程初始化执行器,则所有操作都完成,没有任何错误。如果我用 5 个线程初始化执行器,有时会出现错误:

在服务器上的客户端上

    java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can't commit because the transaction is in aborted state
        at org.jboss.aspects.tx.TxPolicy.handleEndTransactionException(TxPolicy.java:198)

,一开始就发出警告

    ItemStateReferenceCache [ItemStateReferenceCache.java:176] overwriting cached entry 187554a7-4c41-404b-b6ee-3ce2a9796a70

,然后

    javax.jcr.RepositoryException: org.apache.jackrabbit.core.state.ItemStateException: there's already a property state instance with id 52fb4b2c-3ef4-4fc5-9b79-f20a6b2e9ea3/{http://www.jcp.org/jcr/1.0}created
        at org.apache.jackrabbit.core.PropertyImpl.restoreTransient(PropertyImpl.java:195) ~[jackrabbit-core-2.2.7.jar:2.2.7]
        at org.apache.jackrabbit.core.ItemSaveOperation.restoreTransientItems(ItemSaveOperation.java:879) [jackrabbit-core-2.2.7.jar:2.2.7]

我们尝试同步此方法和其他工作流程,以将多线程调用作为一个线程处理。没有任何帮助。

还有一件事 - 当我们在没有 ejb 层的情况下进行类似的测试时 - 一切都工作正常。 它看起来像是包裹在自己的事务中的容器,然后全部崩溃了。

也许有人遇到过这样的问题。 提前致谢。

After we have done some performance testing for our application which uses jackrabbit we faced with the huge problem with concurrent modification jackrabbit's repository. Problem appears when we add nodes or edit them in multithread emulation. Then I wrote very simple test which shows us that problem is not in our environment.

There is it:

Simple Stateless Bean


     @Stateless
        @Local(TestFacadeLocal.class)
        @Remote(TestFacadeRemote.class)
        public class TestFacadeBean implements TestFacadeRemote, TestFacadeLocal {
            public void doAction(int name) throws Exception {
                new TestSynch().doAction(name);
            }
        }

Simple class


    public class TestSynch {
        public void doAction(int name) throws Exception {
            Session session = ((Repository) new InitialContext().
                    lookup("java:jcr/local")).login(
                    new SimpleCredentials("username", "pwd".toCharArray()));
            List added = new ArrayList();
            Node folder = session.getRootNode().getNode("test");
            for (int i = 0; i <= 100; i++) {
                Node child = folder.addNode("" + System.currentTimeMillis(), 
                              "nt:folder");
                child.addMixin("mix:versionable");

                added.add(child);
            }
            // saving butch changes
            session.save();

            //checking in all created nodes
            for (Node node : added) {
                session.getWorkspace().getVersionManager().checkin(node.getPath());
            }
        }
    }

And Test class


    public class Test {
        private int c = 0;
        private int countAll = 50;
        private ExecutorService executor = Executors.newFixedThreadPool(5);

        public ExecutorService getExecutor() {
            return executor;
        }

        public static void main(String[] args) {
            Test test = new Test();
            try {
                test.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void start() throws Exception {
            long time = System.currentTimeMillis();
            TestFacadeRemote testBean = (TestFacadeRemote) getContext().
                                        lookup( "test/TestFacadeBean/remote");
            for (int i = 0; i < countAll; i++) {
                getExecutor().execute(new TestInstallerThread(i, testBean));
            }

            getExecutor().shutdown();
            while (!getExecutor().isTerminated()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(c + " shutdown " + 
                               (System.currentTimeMillis() - time));

        }

        class TestInstallerThread implements Runnable {
            private int number = 0;
            TestFacadeRemote testBean;

            public TestInstallerThread(int number, TestFacadeRemote testBean) {
                this.number = number;
                this.testBean = testBean;
            }

            @Override
            public void run() {
                try {
                    System.out.println("Installing data " + number);
                    testBean.doAction(number);
                    System.out.println("STOP" + number);
                } catch (Exception e) {
                    e.printStackTrace();
                    c++;
                }
            }

        }

        public Context getContext() throws NamingException {
            Properties properties = new Properties();
            //init props
            ..............
            return new InitialContext(properties);
        }
    }

If I initialized executor with 1 thread in pool all done without any error. If I initialized executor with 5 thread I got sometimes errors:

on client

    java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can't commit because the transaction is in aborted state
        at org.jboss.aspects.tx.TxPolicy.handleEndTransactionException(TxPolicy.java:198)

on server at the beginning warn

    ItemStateReferenceCache [ItemStateReferenceCache.java:176] overwriting cached entry 187554a7-4c41-404b-b6ee-3ce2a9796a70

and then

    javax.jcr.RepositoryException: org.apache.jackrabbit.core.state.ItemStateException: there's already a property state instance with id 52fb4b2c-3ef4-4fc5-9b79-f20a6b2e9ea3/{http://www.jcp.org/jcr/1.0}created
        at org.apache.jackrabbit.core.PropertyImpl.restoreTransient(PropertyImpl.java:195) ~[jackrabbit-core-2.2.7.jar:2.2.7]
        at org.apache.jackrabbit.core.ItemSaveOperation.restoreTransientItems(ItemSaveOperation.java:879) [jackrabbit-core-2.2.7.jar:2.2.7]

We have tried synchronize this method and other workflow for handle multithread calls as one thread. Nothing helps.

And one more thing - when we have done similar test without ejb layer - all worked fine.
It looks like container wrapped in own transaction and then all crashed.

Maybe somebody faced with such a problem.
Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

也只是曾经 2024-11-26 23:56:29

来自 Jackrabbit Wiki

JCR 规范明确指出会话不是线程安全的(JCR 1.0 第 7.5 节和 JCR 2.0 第 4.1.2 节)。因此,Jackrabbit 不支持多个线程同时读取或写入同一会话。每个会话只能从一个线程访问。

...
如果需要并发写入同一个节点,则需要使用多个会话,并使用JCR锁定来确保不发生冲突。

From the Jackrabbit Wiki:

The JCR specification explicitly states that a Session is not thread-safe (JCR 1.0 section 7.5 and JCR 2.0 section 4.1.2). Hence, Jackrabbit does not support multiple threads concurrently reading from or writing to the same session. Each session should only ever be accessed from one thread.

...
If you need to write to the same node concurrently, then you need to use multiple sessions, and use JCR locking to ensure there is no conflict.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文