簡體   English   中英

Java中的OrientDB並發圖操作

[英]OrientDB concurrent graph operations in Java

我試圖在多線程環境(Java 8)中使用orientdb(v2.1.2),我在多個線程中更新頂點。 我知道orientdb正在使用MVCC,因此這些操作可能會失敗並且必須再次執行。

我寫了一個小單元測試,試圖通過等待我fork的線程中的循環障礙來激發這種情況。 不幸的是,測試失敗了一個模糊的異常,我不明白:

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)

該測試使用的是簡單的內存數據庫。 我不明白為什么orientdb正在檢查一些集群操作:

Cluster with id 11 already belongs to class testedge

不知何故,只有當我嘗試使用相同的標簽創建兩個邊時才會出現此問題。

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;
}

總的來說,我非常感謝一個演示如何在嵌入式多線程Java環境中使用orientdb時處理MVCC沖突的示例。


更新:

我注意到當我通過tx.getVertex(vertex.getId())(而不是通過.reload())重新加載我的線程中的頂點時,問題不再發生。 當我將頂點對象引用傳遞給我的線程並在那里使用它時,我得到各種錯誤。 我假設OrientVertex類不是線程安全的。

  1. 你是對的, 所有圖形元素都不是線程安全的。
  2. 創建邊緣時會出現異常的原因,在圖形數據庫下面創建文檔,其類等於邊的標簽。 如果缺少類,則會自動提交事務,並在模式中創建新類。 當您同時添加邊緣時,每個類都映射到數據庫中的集群(它就像一個表),同時創建相同的類,並因此創建相同的集群。 因此,一個線程贏得其他失敗,除了已經創建了具有給定名稱的群集。 實際上我建議你在運行時添加邊之前創建所有類,即邊緣標簽。

還有一個建議。 您應該將OrientGraph實例視為與服務器的連接。 最佳用法如下:

  1. OrientGraphFactory中的設置池
  2. 在交易之前獲取圖表實例。
  3. 執行交易。
  4. 調用.shutdown() ,不要創建長生活圖實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM