简体   繁体   English

Java中的OrientDB并发图操作

[英]OrientDB concurrent graph operations in Java

I'm trying to use orientdb (v2.1.2) in an multithreaded environment (Java 8) where i update a vertex from within multiple threads. 我试图在多线程环境(Java 8)中使用orientdb(v2.1.2),我在多个线程中更新顶点。 I'm aware that orientdb is using MVCC and thus those operations may fail and have to be executed again. 我知道orientdb正在使用MVCC,因此这些操作可能会失败并且必须再次执行。

I wrote a small unit test that tries to provoke such situations by waiting on a cyclic barrier within the threads i fork. 我写了一个小单元测试,试图通过等待我fork的线程中的循环障碍来激发这种情况。 Unfortunately the test fails with an obscure Exception which i don't understand: 不幸的是,测试失败了一个模糊的异常,我不明白:

Sep 21, 2015 3:00:24 PM com.orientechnologies.common.log.OLogManager log
INFO: OrientDB auto-config DISKCACHE=10,427MB (heap=3,566MB os=16,042MB disk=31,720MB)
Thread [0] running 
Thread [1] running 
Sep 21, 2015 3:00:24 PM com.orientechnologies.common.log.OLogManager log
WARNING: {db=tinkerpop} Requested command 'create edge type 'testedge_1442840424480' as subclass of 'E'' must be executed outside active transaction: the transaction will be committed and reopen right after it. To avoid this behavior execute it outside a transaction
Sep 21, 2015 3:00:24 PM com.orientechnologies.common.log.OLogManager log
WARNING: {db=tinkerpop} Requested command 'create edge type 'testedge_1442840424480' as subclass of 'E'' must be executed outside active transaction: the transaction will be committed and reopen right after it. To avoid this behavior execute it outside a transaction
Exception in thread "Thread-4" com.orientechnologies.orient.core.exception.OSchemaException: Cluster with id 11 already belongs to class testedge_1442840424480
    at com.orientechnologies.orient.core.metadata.schema.OSchemaShared.checkClustersAreAbsent(OSchemaShared.java:1264)
    at com.orientechnologies.orient.core.metadata.schema.OSchemaShared.doCreateClass(OSchemaShared.java:983)
    at com.orientechnologies.orient.core.metadata.schema.OSchemaShared.createClass(OSchemaShared.java:415)
    at com.orientechnologies.orient.core.metadata.schema.OSchemaShared.createClass(OSchemaShared.java:400)
    at com.orientechnologies.orient.core.metadata.schema.OSchemaProxy.createClass(OSchemaProxy.java:100)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph$6.call(OrientBaseGraph.java:1387)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph$6.call(OrientBaseGraph.java:1384)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph.executeOutsideTx(OrientBaseGraph.java:1739)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph.createEdgeType(OrientBaseGraph.java:1384)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph.createEdgeType(OrientBaseGraph.java:1368)
    at com.tinkerpop.blueprints.impls.orient.OrientBaseGraph.createEdgeType(OrientBaseGraph.java:1353)
    at com.tinkerpop.blueprints.impls.orient.OrientVertex.addEdge(OrientVertex.java:928)
    at com.tinkerpop.blueprints.impls.orient.OrientVertex.addEdge(OrientVertex.java:832)
    at com.gentics.test.orientdb.OrientDBTinkerpopMultithreadingTest.lambda$0(OrientDBTinkerpopMultithreadingTest.java:31)
    at com.gentics.test.orientdb.OrientDBTinkerpopMultithreadingTest$$Lambda$1/1446001495.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)

The test is using a simple in-memory database. 该测试使用的是简单的内存数据库。 I don't get why orientdb is checking some cluster actions: 我不明白为什么orientdb正在检查一些集群操作:

Cluster with id 11 already belongs to class testedge

Somehow this issue only appears when i try to create two edges with the same label. 不知何故,只有当我尝试使用相同的标签创建两个边时才会出现此问题。

private OrientGraphFactory factory = new OrientGraphFactory("memory:tinkerpop").setupPool(5, 20);

@Test
public void testConcurrentGraphModifications() throws InterruptedException {
    OrientGraph graph = factory.getTx();
    Vertex v = graph.addVertex(null);
    graph.commit();
    CyclicBarrier barrier = new CyclicBarrier(2);

    List<Thread> threads = new ArrayList<>();

    // Spawn two threads
    for (int i = 0; i < 2; i++) {
        final int threadNo = i;
        threads.add(run(() -> {
            System.out.println("Running thread [" + threadNo + "]");
            // Start a new transaction and modify vertex v
            OrientGraph tx = factory.getTx();
            Vertex v2 = tx.addVertex(null);
            v.addEdge("testedge", v2);
            try {
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            tx.commit();
        }));
    }

    // Wait for all spawned threads
    for (Thread thread : threads) {
        thread.join();
    }
}

protected Thread run(Runnable runnable) {
    Thread thread = new Thread(runnable);
    thread.start();
    return thread;
}

In general i would be very thankful for a example that demonstrates how to deal with MVCC conflicts when using orientdb in an embedded multithreaded java environment. 总的来说,我非常感谢一个演示如何在嵌入式多线程Java环境中使用orientdb时处理MVCC冲突的示例。


Update: 更新:

I noticed that the problem no longer occures when i reload the vertex within my thread via tx.getVertex(vertex.getId()) (not via .reload()). 我注意到当我通过tx.getVertex(vertex.getId())(而不是通过.reload())重新加载我的线程中的顶点时,问题不再发生。 I get various errors when i just pass the vertex object reference to my thread and use it there. 当我将顶点对象引用传递给我的线程并在那里使用它时,我得到各种错误。 I assume the OrientVertex class is not threadsafe. 我假设OrientVertex类不是线程安全的。

  1. You are right all graph elements are not thread safe. 你是对的, 所有图形元素都不是线程安全的。
  2. Reason of your exception is following when you create edge, you underneath of graph database create document with class which equals to label of the edge. 创建边缘时会出现异常的原因,在图形数据库下面创建文档,其类等于边的标签。 If class is absent transaction is committed automatically and new class inside of schema is created. 如果缺少类,则会自动提交事务,并在模式中创建新类。 Each class is mapped to cluster in database (it is like a table) when you add edges concurrently you at the same time create the same class and as result the same cluster is created. 当您同时添加边缘时,每个类都映射到数据库中的集群(它就像一个表),同时创建相同的类,并因此创建相同的集群。 So one thread wins other fails with exception that cluster with given name already created. 因此,一个线程赢得其他失败,除了已经创建了具有给定名称的群集。 Actually I suggest you to create all classes aka labels of edges if possible before you will add edges at runtime. 实际上我建议你在运行时添加边之前创建所有类,即边缘标签。

One more suggestion. 还有一个建议。 You should think about OrientGraph instance as if it is connection to the server. 您应该将OrientGraph实例视为与服务器的连接。 The best usage is following: 最佳用法如下:

  1. Setup pool in OrientGraphFactory OrientGraphFactory中的设置池
  2. Acquire graph instance before transaction. 在交易之前获取图表实例。
  3. Execute transaction. 执行交易。
  4. Call .shutdown() , do not create long living graph instances. 调用.shutdown() ,不要创建长生活图实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM