Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken transaction when traversing an edge #5468

Closed
johansjob opened this issue Dec 15, 2015 · 5 comments
Closed

Broken transaction when traversing an edge #5468

johansjob opened this issue Dec 15, 2015 · 5 comments
Assignees

Comments

@johansjob
Copy link

Consider the following test. The test fails at the assert. If I remove the marked code in the doSelects function, the test passes like it should.
It doesn't matter what edge I select, the transaction fails to rollback the saved class.
I am using an embedded db, version 2.1.6.

@Test
public void testRollback() {
    String name = UUID.randomUUID().toString();
    MyClass myClass = new MyClass();
    myClass.setName(name);

     try {
        db.begin();
        doSelects(myClass);
        db.commit();
    } catch (Exception e) {
        db.rollback();
    }

    List<ODocument> oDocs = db.getUnderlying().command(
        new OSQLSynchQuery("SELECT FROM MyClass WHERE name = '" + name + "'")
    ).execute();

    Assert.assertTrue(oDocs.isEmpty());
}

private void doSelects(MyClass myClass) throws Exception {
    // Remove from here
    String q = "SELECT FROM (SELECT out('RandomEdge') FROM #21:0)";
    db.command(new OSQLSynchQuery(q)).execute();
    // Remove to here

    MyClass savedClass = db.save(myClass);
    throw new Exception();
}
@tglman
Copy link
Member

tglman commented Dec 15, 2015

@johansjob
I tried to run this test with a basic graph and i could not reproduce the problem, can you provide a full test case with the MyClass definition and an insert of Edges? I feel like the problem depends also in the structure of class in the database.

@johansjob
Copy link
Author

Alright, I have changed the test a bit. I've included the way we start our embedded db and I'm now only using the document API. All you have to do is:

  1. Create a plain new db called mydb
  2. Fix the ORIENT_PATH and DB_URL
  3. Make sure the new db contains a vertex with id Stored procedure [moved] #4:0
  4. Run the test.
    Like before, the last assert in testRollback fails if the marked code in doSelects() is running. It passes if I make that code a comment.

It fails on both my own machine as well as my collegue's. Will this be enough?

import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.OPartitionedDatabasePoolFactory;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import com.orientechnologies.orient.server.OServer;
import com.orientechnologies.orient.server.OServerMain;
import java.io.File;
import java.util.List;
import java.util.UUID;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class OrientTest {

    public ODatabaseDocumentTx db;

    private static boolean initServer = false;
    private static OServer server = null;

    private static OPartitionedDatabasePoolFactory poolFactory = null;

    private static final String ORIENT_PATH = "C:/orientdb-community/";
    private static final String DB_URL = "plocal:C:/orientdb-community/databases/mydb";
    private static final String DB_USR = "admin";
    private static final String DB_PASS = "admin";

    @Before
    public void before() {
        startDbServer();
        db = getDocumentDB();        
    }

    private static synchronized void startDbServer() {
        if (initServer || server != null) {
            return;
        }
        try {
            server = OServerMain.create();
            server.startup(getDefaultDbConfig());
            server.activate();
            poolFactory = server.getDatabasePoolFactory();
        } catch (Exception ex) {
            if (server != null) {
                server.shutdown();
            }
            ex.printStackTrace();
        }
        initServer = true;
    }

    private ODatabaseDocumentTx getDocumentDB() {
        ODatabaseRecordThreadLocal threadLocal = ODatabaseRecordThreadLocal.INSTANCE;
        ODatabaseDocumentTx db;
        if (!threadLocal.isDefined()) {
            db = poolFactory.get(DB_URL, DB_USR, DB_PASS).acquire();
            db.setDatabaseOwner(db);

        } else {
            ODatabaseDocumentInternal db1 = threadLocal.get();
            db = (ODatabaseDocumentTx) db1;
        }
        return db;
    }

    @After
    public void after() {
        db.close();
        poolFactory.close();
        server.shutdown();        
    }

    @Test
    public void testRollback() {
        String name = UUID.randomUUID().toString();

        ODocument doc = new ODocument();
        doc.setClassName("MyClass");
        doc.field("name", name);

         try {
            db.begin();
            doSelects(doc);
            db.commit();
        } catch (Exception e) {
            db.rollback();
        }

        List<ODocument> oDocs = db.command(
            new OSQLSynchQuery("SELECT FROM MyClass WHERE name = '" + name + "'")
        ).execute();

        Assert.assertTrue(oDocs.isEmpty());
    }

    private void doSelects(ODocument doc) throws Exception {
        // Remove from here
        String q = "SELECT FROM (SELECT out('MyRandomEdge') FROM #4:0)";
        db.command(new OSQLSynchQuery(q)).execute();
        // Remove to here

        ODocument savedDoc = db.save(doc);
        System.out.println(savedDoc.getIdentity().toString());
        System.out.println(savedDoc.field("name").toString());
        throw new Exception();
    }


    private static String getDefaultDbConfig() {
        return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
                + "<orient-server>"
                + "<network>"
                + "<protocols>"
                + "<protocol name=\"binary\" implementation=\"com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary\"/>"
                + "<protocol name=\"http\" implementation=\"com.orientechnologies.orient.server.network.protocol.http.ONetworkProtocolHttpDb\"/>"
                + "</protocols>"
                + "<listeners>"
                + "<listener ip-address=\"127.0.0.1\" port-range=\"2424-2430\" protocol=\"binary\"/>"
                + "<listener ip-address=\"127.0.0.1\" port-range=\"2480-2490\" protocol=\"http\">"
                + "<commands>"
                + "<command implementation=\"com.orientechnologies.orient.server.network.protocol.http.command.get.OServerCommandGetStaticContent\" pattern=\"GET|www GET|studio/ GET| GET|*.htm GET|*.html GET|*.xml GET|*.jpeg GET|*.jpg GET|*.png GET|*.gif GET|*.js GET|*.css GET|*.swf GET|*.ico GET|*.txt GET|*.otf GET|*.pjs GET|*.svg GET|*.json GET|*.woff GET|*.ttf GET|*.svgz\" stateful=\"false\">"
                + "<parameters>"
                + "<entry value=\"Cache-Control: no-cache, no-store, max-age=0, must-revalidate\\r\\nPragma: no-cache\" name=\"http.cache:*.htm *.html\"/>"
                + "<entry value=\"Cache-Control: max-age=120\" name=\"http.cache:default\"/>"
                + "</parameters>"
                + "</command>"
                + "<command implementation=\"com.orientechnologies.orient.graph.server.command.OServerCommandGetGephi\" pattern=\"GET|gephi/*\" stateful=\"false\"/>"
                + "</commands>"
                + "<parameters>"
                + "<parameter value=\"utf-8\" name=\"network.http.charset\"/>"
                + "</parameters>"
                + "</listener>"
                + "</listeners>"
                + "</network>"
                + "<users>"
                + "<user name=\"root\" password=\"somepassword\" resources=\"*\"/>"
                + "<user resources=\"connect,server.listDatabases\" password=\"somepassword2\" name=\"guest\"/>"
                + "</users>"
                + "<properties>"
                + "<entry name=\"server.database.path\" value=\"" + ORIENT_PATH + "databases" + "\"/>"
                + "<entry name=\"orientdb.www.path\" value=\"" + ORIENT_PATH + "www" + "\"/>"
                //path to the general config file (where we control the thread pool, backups etc.)
                //Not sure we need this... 
                + "<entry name=\"orientdb.config.file\" value=\"" + ORIENT_PATH + "config" + File.separator + "orientdb-server-config.xml\"/>"
                + "<entry name=\"server.cache.staticResources\" value=\"false\"/>"
                + "<entry name=\"log.console.level\" value=\"info\"/>"
                + "<entry name=\"log.file.level\" value=\"fine\"/>"
                //The following is required to eliminate an error or warning "Error on resolving property: ORIENTDB_HOME"
                + "<entry name=\"plugin.dynamic\" value=\"false\"/>"
                + "</properties>" + "</orient-server>";
    }

}

@tglman
Copy link
Member

tglman commented Dec 17, 2015

Hi @johansjob

I run your test case against 2.1.6 at was failing, but on 2.1.8 is working, so is already fixed in the last hotfix, just released today.

can you check it ?

@johansjob
Copy link
Author

Works with 2.1.8! :)

@luigidellaquila
Copy link
Member

Perfect, thanks

Closing

Luigi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants