orientechnologies / orientdb

OrientDB is the most versatile DBMS supporting Graph, Document, Reactive, Full-Text and Geospatial models in one Multi-Model product. OrientDB can run distributed (Multi-Master), supports SQL, ACID Transactions, Full-Text indexing and Reactive Queries.
https://orientdb.dev
Apache License 2.0
4.73k stars 871 forks source link

OSBTreeRidBag.add - Nullpointer exception #3592

Closed ginojohn closed 9 years ago

ginojohn commented 9 years ago

The following null pointer exception is thrown. Attached a sample program to re-produce the issue. OrientDB version 2.0.2. This Exception happens only when CONFLICT STRATEGY is set to auto merge.

com.orientechnologies.orient.core.exception.OStorageException: Error during transaction commit. at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.commit(OAbstractPaginatedStorage.java:931) at com.orientechnologies.orient.core.tx.OTransactionOptimistic.doCommit(OTransactionOptimistic.java:483) at com.orientechnologies.orient.core.tx.OTransactionOptimistic.commit(OTransactionOptimistic.java:147) at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2373) at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2343) at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.commit(ONetworkProtocolBinary.java:1087) at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.executeRequest(ONetworkProtocolBinary.java:389) at com.orientechnologies.orient.server.network.protocol.binary.OBinaryNetworkProtocolAbstract.execute(OBinaryNetworkProtocolAbstract.java:216) at com.orientechnologies.common.thread.OSoftThread.run(OSoftThread.java:65) Caused by: java.lang.NullPointerException at com.orientechnologies.orient.core.db.record.ridbag.sbtree.OSBTreeRidBag.add(OSBTreeRidBag.java:618) at com.orientechnologies.orient.core.db.record.ridbag.ORidBag.add(ORidBag.java:134) at com.orientechnologies.orient.core.db.record.ridbag.ORidBag.add(ORidBag.java:80) at com.orientechnologies.common.collection.OMultiValue.add(OMultiValue.java:400) at com.orientechnologies.orient.core.record.impl.ODocument.merge(ODocument.java:1222) at com.orientechnologies.orient.core.record.impl.ODocument.merge(ODocument.java:1183) at com.orientechnologies.orient.core.conflict.OAutoMergeRecordConflictStrategy.onUpdate(OAutoMergeRecordConflictStrategy.java:43) at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.checkAndIncrementVersion(OAbstractPaginatedStorage.java:2020) at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.doUpdateRecord(OAbstractPaginatedStorage.java:1651) at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.commitEntry(OAbstractPaginatedStorage.java:2105) at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.commit(OAbstractPaginatedStorage.java:913) ... 8 more


import com.orientechnologies.orient.client.remote.OServerAdmin;
import com.orientechnologies.orient.core.exception.OConcurrentModificationException;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Parameter;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;
import com.tinkerpop.blueprints.impls.orient.OrientEdgeType;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.tinkerpop.blueprints.impls.orient.OrientGraphFactory;
import com.tinkerpop.blueprints.impls.orient.OrientGraphNoTx;

public final class DatabaseDuplicateEdgeTest {

    private String dbName;
    private OrientGraphFactory graphReadFactory;

    public DatabaseDuplicateEdgeTest(String dbName) {
        this.dbName = dbName;
        checkAndCreateDatabase(dbName);
    }

    public void runTest() {

        OrientBaseGraph graph = getGraphFactory().getTx();

        Vertex vertex = graph.addVertex("class:Host");
        vertex.setProperty("prop1", "v1-1");
        vertex.setProperty("prop2", "v2-1");
        vertex.setProperty("prop3", "v3-1");

        Vertex vertex1 = graph.addVertex("class:Host");
        vertex1.setProperty("prop1", "v1-2");
        vertex1.setProperty("prop2", "v2-1");
        vertex1.setProperty("prop3", "v3-1");

        Vertex vertex2 = graph.addVertex("class:Host");
        vertex2.setProperty("prop1", "v1-3");
        vertex2.setProperty("prop2", "v2-1");
        vertex2.setProperty("prop3", "v3-1");

        graph.commit();
        graph.shutdown();

        Thread th1 = startThread("v1-1", "v1-2", "c1");
        Thread th11 = startThread("v1-1", "v1-2", "c1");
        Thread th2 = startThread("v1-2", "v1-3", "c2");
        Thread th3 = startThread("v1-3", "v1-2", "c2");
        try {
            th1.join();
            th2.join();
            th3.join();
            th11.join();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private Thread startThread(String key1, String key2, String edgeKey) {

        Thread th = new Thread() {
            @Override
            public void run() {
                OrientGraph graph = getGraphFactory().getTx();
                for (int j=0; j < 10; j++) {
                    boolean retry = true;
                    while (retry) {
                        try {
                            Vertex vtxx1 = findVertex(graph, key1);
                            Iterable<Edge> edges = vtxx1.getEdges(Direction.BOTH, "label", "Connection");
                            //LOGGER.debug("### Removing link edges for {}", nodeAndEdge.getClassName());
                            for (Edge edge : edges) {
                                graph.removeEdge(edge);
                                graph.commit();
                            }
                            retry = false;
                        } catch (OConcurrentModificationException ex) {
                            retry = true;
                        } catch (Exception ex) {
                            retry = false;
                            ex.printStackTrace();
                        }
                    }
                    //graph.shutdown();

                    //graph = getGraphFactory().getTx();

                    Vertex vtxx1 = findVertex(graph, key1);
                    Vertex vtxx2 = findVertex(graph, key2);

                    for (int i = 1; i <= 25; i ++) {
                        retry = true;
                        while (retry) {
                            try {
                                String edgeName = edgeKey + "-key-" + i;
                                Edge edge1 = findEdge(graph,"Connection.linkKey", edgeName);
                                if (edge1 == null) {
                                    edge1 = vtxx1.addEdge("Connection", vtxx2);
                                    edge1.setProperty("linkKey", edgeName);
                                }
                                edge1.setProperty("status", "up");
                                graph.commit();
                                retry = false;
                            } catch (OConcurrentModificationException ex) {
                                vtxx1 = findVertex(graph, key1);
                                vtxx2 = findVertex(graph, key2);
                                //log("Concurrent modification exception retrying.....");
                            } catch (Exception ex) {
                                retry = false;
                                log("Exception - " + ex.getMessage());
                            }
                        }
                    }
                    //graph.shutdown();
                }
                graph.shutdown();
            }

        };
        th.start();
        return th;
    }

    public Edge findEdge(OrientGraph graph, String property, Object value) {
        Iterable<Edge> edges = graph.getEdges(property, value);
        for (Edge edge : edges) {
            return edge;
        }
        return null;
    }

    private Vertex findVertex(OrientGraph graph, String key) {
        Iterable<Vertex> vtxs = graph.command(new OCommandSQL("select from Host where prop1='" + key + "'")).execute();
        for (Vertex vertex : vtxs) {
            return vertex;
        }
        return null;
    }

    /**
     * @return
     */
    public String getDBURL() {
        return "remote:" + "localhost" + "/" + dbName;
    }

    private OrientGraphFactory getGraphFactory() {
        if (graphReadFactory == null) {
            log("Datastore pool created with size : 10, db location: " + getDBURL());
            graphReadFactory = new OrientGraphFactory(getDBURL()).setupPool(1, 10);
        }
        return graphReadFactory;
    }

    /**
     *
     */
    public void checkAndCreateDatabase(String dbName) {
        try {
            OServerAdmin serverAdmin = new OServerAdmin(getDBURL()).connect("root", "C63447B06BE9A894BFB16031C23796421202D3FE136EC5D617578B025F405343");
            if (!serverAdmin.existsDatabase("plocal")) {
                log("Database does not exists. New database is created");
                serverAdmin.createDatabase(dbName,"graph", "plocal");
                OrientBaseGraph orientGraph = new OrientGraphNoTx(getDBURL());
                log("Set database CONFLICTSTRATEGY to automerge");
                orientGraph.command(new OCommandSQL("ALTER database CONFLICTSTRATEGY automerge")).execute();
                orientGraph.shutdown();
                serverAdmin.close();
                createDbSchema();
            } else {
                log ("Database already exists.");
            }
        } catch (Exception ex) {
            log("Failed to create database", ex);
        }
    }

    private void createDbSchema() {
        OrientBaseGraph orientGraph = new OrientGraphNoTx(getDBURL());
        createVertexType(orientGraph, "Host");
        createLinkIndex(orientGraph, "Connection");
        orientGraph.shutdown();
    }

    private void createLinkIndex(OrientBaseGraph orientGraph, String linkName) {
        OrientEdgeType edge = orientGraph.createEdgeType(linkName);
        edge.createProperty("linkKey", OType.STRING);
        orientGraph.createKeyIndex("linkKey", Edge.class, new Parameter<>("class", linkName), new Parameter<>("type", "UNIQUE"));

    }

    private void createVertexType(OrientBaseGraph orientGraph, String className) {
        OClass clazz = orientGraph.getVertexType(className);
        if (clazz == null) {
            log("Creating vertex type - " + className);
            orientGraph.createVertexType(className);
        }
    }

    private void log(String message) {
        System.out.println(message);
    }

    private void log(String message, Throwable th) {
        System.out.println(th.getMessage());
        th.printStackTrace();
    }

    public static void main(String args[]) {
        DatabaseDuplicateEdgeTest test = new DatabaseDuplicateEdgeTest("duplicateedge");
        test.runTest();
        Runtime.getRuntime().halt(0);
    }

}
andrii0lomakin commented 9 years ago

Hi Gino, It is the same issue which we are working at, you just duplicated it.