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

Exception when adding an edge results in a non-existing Edge reference in the parent Vertex #1495

Closed
RoarN opened this issue May 24, 2013 · 4 comments
Assignees
Milestone

Comments

@RoarN
Copy link

RoarN commented May 24, 2013

Versions:
orientdb-graphdb-1.3.0
orientdb-grahped-1.3.0 (server)

Problem:
I'm getting invalid (non existing) edge references in some of my vertexes, making the document inconsistent.

Setup:
My real environment is a large OSGi based application server, but I was able to simplify it down to
an application with one main and two threads.

I have one parent document that has two types of vertexes added to it on different intervals.
At one point I get the classic message:

"Cannot ? the record #10:0 because the version is not the latest. Probably you are using an old record or
it has been modified by another user (db=v40 your=v0)"

This is by itself not a problem, the problem however is that the exception causes a parent document being
updated with an edge-reference to a non-existing edge that was never created.

Test:
Parent class X
Child classes A and B, edge classes xa and xb

Create all classes and and instance of class X (parent).
Start two threads, one that adds A Documents and one that adds B documents.
Both uses the same X document as parent document, the parent document is fetched each time

Result:
starting test
TestThread starting: A
TestThread starting: B
adding vertex: B
adding vertex: A
adding vertex: B
adding vertex: A
adding vertex: B
adding vertex: A
adding vertex: B
adding vertex: B
adding vertex: B
adding vertex: A
adding vertex: A
adding vertex: B
Run ERROR:com.orientechnologies.orient.core.exception.OConcurrentModificationException: Cannot ? the record #10:0 because the version is not the latest.
Probably you are ing an old record or it has been modified by another user (db=v11 your=v0)
...
Check out edges for Parent document:
--> xa#13:0{out:#10:0,in:#11:0,label:xa} v1
--> xa#13:1{out:#10:0,in:#11:1,label:xa} v1
--> xa#13:2{out:#10:0,in:#11:2,label:xa} v1
--> xa#13:3{out:#10:0,in:#11:3,label:xa} v2
--> xa#13:4{out:#10:0,in:#11:4,label:xa} v2
--> xb#14:0{out:#10:0,in:#12:0,label:xb} v1
--> xb#14:1{out:#10:0,in:#12:1,label:xb} v1
--> xb#14:2{out:#10:0,in:#12:2,label:xb} v1
--> xb#14:3{out:#10:0,in:#12:3,label:xb} v1
--> xb#14:4{out:#10:0,in:#12:4,label:xb} v1
--> xb#14:5{out:#10:0,in:#12:5,label:xb} v1
--> #14:6 v0
REFERENCE TO AN EDGE THAT DOES NOT EXIST IN THE BASE!
done

OutEdges in the Parent document:
[#13:0, #13:1, #13:2, #13:3, #13:4, #14:0, #14:1, #14:2, #14:3, #14:4, #14:5, #14:6]

'select from E' does not contain #14:6

@RoarN
Copy link
Author

RoarN commented May 24, 2013

package test;

import java.util.List;

import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.db.graph.OGraphDatabase;
import com.orientechnologies.orient.core.db.graph.OGraphDatabasePool;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;

public class TestEdge
{
public static OGraphDatabase getConnection()
{
String url = "remote:localhost/test";
String user = "admin";
String password = "admin";
return OGraphDatabasePool.global().acquire(url, user, password);
}

@SuppressWarnings("unused")
private static void setup(String id)
{
    OGraphDatabase gdb = getConnection();
    try
    {
        if (gdb.getVertexType("X") != null)
        {
            return;
        }

        OClass x = gdb.createVertexType("X");
        x.createProperty("id", OType.STRING).createIndex(INDEX_TYPE.UNIQUE);

        OClass a = gdb.createVertexType("A");
        OClass b = gdb.createVertexType("B");
        OClass e1 = gdb.createEdgeType("xa");
        OClass e2 = gdb.createEdgeType("xb");

        ODocument doc = gdb.createVertex("X");
        doc.field("id",id);
        doc.save();
    }
    catch (OException e)
    {
        System.out.println("setup failed: ");
        e.printStackTrace();
    }
    finally
    {
        gdb.close();
    }
}

private static void check(String id)
{
    OGraphDatabase gdb = getConnection();
    try
    {
        OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>("SELECT FROM X WHERE id = ?");
        List<ODocument> result = gdb.command(query).execute(id);
        ODocument x = result.get(0);
        System.out.println("Check out edges for Parent document:");
        for (OIdentifiable edge : gdb.getOutEdges(x))
        {
            ODocument edoc = gdb.getRecord(edge);
            System.out.println(" --> " + edoc);
            if (edoc.getClassName() == null)
            {
                System.out.println("REFERENCE TO AN EDGE THAT DOES NOT EXIST IN THE BASE!");
                break;
            }
        }
    }
    catch (OException e)
    {
        System.out.println("check failed: ");
        e.printStackTrace();
    }
    finally
    {
        gdb.close();
    }       
}

public static void main(String[] args) throws InterruptedException
{
    OGlobalConfiguration.CACHE_LEVEL1_ENABLED.setValue(false);
    OGlobalConfiguration.CACHE_LEVEL2_ENABLED.setValue(false);
    String testName = "test";

    System.out.println("starting test");
    setup(testName);

    TestThread tt1 = new TestThread("A","xa",testName);
    TestThread tt2 = new TestThread("B","xb",testName);
    Thread t1 = new Thread(tt1);
    Thread t2 = new Thread(tt2);

    t1.start();
    t2.start();

    while(true)
    {
        // one of the threads has terminated, make sure the other stops as well
        if(t1.isAlive() == false || t2.isAlive() == false)
        {
            tt1.shutdown();
            tt2.shutdown();
            break;
        }
    }

    t1.join();
    t2.join();

    check(testName);

    System.out.println("done"); 
}

}

package test;

import java.util.List;
import java.util.Random;

import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.db.graph.OGraphDatabase;
import com.orientechnologies.orient.core.db.graph.OGraphDatabasePool;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;

public class TestThread implements Runnable
{
private String vertexName;
private String edgeName;
private String xId;

private boolean shutdown = false;

public TestThread(String vertexName, String edgeName, String xId)
{
    this.vertexName = vertexName;
    this.edgeName = edgeName;
    this.xId = xId;
}

public OGraphDatabase getConnection()
{
    String url = "remote:localhost/test";
    String user = "admin";
    String password = "admin";
    return OGraphDatabasePool.global().acquire(url, user, password);
}

@Override
public void run()
{
    System.out.println("TestThread starting: " + vertexName);
    Random r = new Random();
    while(shutdown == false)
    {
        OGraphDatabase db = getConnection();
        try
        {
            Thread.sleep(r.nextInt(101));
            System.out.println("adding vertex: " + vertexName);

            ODocument x = fetchX(xId);
            ODocument doc = db.createVertex(vertexName);
            ODocument edge = db.createEdge(x, doc, edgeName);
            edge.field("label",edgeName);
            edge.save();
        }
        catch (OException e)
        {
            System.out.print("Run ERROR:");
            e.printStackTrace();
            System.out.println("\n");
            shutdown = true;
        }
        catch (InterruptedException e)
        {
            shutdown = true;
        }
        finally
        {
            db.close();
        }           
    }
}

private ODocument fetchX(String id)
{
    OGraphDatabase gdb = getConnection();
    try
    {
        OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>("SELECT FROM X WHERE id = ?");
        List<ODocument> result = gdb.command(query).execute(id);
        if (result.size() == 1)
        {
            ODocument doc = result.get(0);
            return doc;
        }
    }
    finally
    {
        gdb.close();
    }
    return null;
}

public void shutdown()
{
    shutdown = true;
}

}

@lvca
Copy link
Member

lvca commented May 24, 2013

Have you tried 1.4.0-SNAPSHOT?

@RoarN
Copy link
Author

RoarN commented May 24, 2013

Did that just now. Downloaded today's source and ran the test, same problem.

@RoarN
Copy link
Author

RoarN commented May 24, 2013

It actually behaves a bit different, now the parent document seems ok, but there is an extra edge in the in the E table and 'select from E' gives an NullPointerException.

@lvca lvca closed this as completed Oct 3, 2014
@lvca lvca self-assigned this Oct 3, 2014
@lvca lvca added this to the 1.6 milestone Oct 3, 2014
@lvca lvca added the bug label Oct 3, 2014
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

2 participants