Jackrabbit 和并发修改
在我们对使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
来自 Jackrabbit Wiki:
From the Jackrabbit Wiki: