Orientdb: Cannot update the record because the version is not the latest

Created on 28 Jan 2013  路  47Comments  路  Source: orientechnologies/orientdb

Hi,

This is probably a very old question, but slightly different in my case and haven't found answer in group, so post it again.

Following is my code snippet.

  1. With blueprints
    @Test
    public void testTransaction() {
        OrientGraph graph = new OrientGraph("remote:localhost/tmp", "admin", "admin");

        Vertex a = null;
        try {
            a = graph.addVertex(null);
            graph.stopTransaction(TransactionalGraph.Conclusion.SUCCESS);
        } catch (Exception e) {
            graph.stopTransaction(TransactionalGraph.Conclusion.FAILURE);
            e.printStackTrace();
        }

        try {
            for (int i = 0; i < 100; ++i) {
                graph.addEdge(null, graph.addVertex(null), a, "");
            }
            graph.stopTransaction(TransactionalGraph.Conclusion.SUCCESS);
        } catch (Exception e) {
            graph.stopTransaction(TransactionalGraph.Conclusion.FAILURE);
            e.printStackTrace();
        }

        try {
            Vertex b = graph.addVertex(null);
            graph.addEdge(null, b, a, "");
            graph.stopTransaction(TransactionalGraph.Conclusion.SUCCESS);
        } catch (Exception e) {
            graph.stopTransaction(TransactionalGraph.Conclusion.FAILURE);
            e.printStackTrace();
        } finally {
            graph.shutdown();
        }
    }
  1. Without blueprints
    @Test
    public void testTransactionNative() {
        OGraphDatabase db = new OGraphDatabase("remote:localhost/tmp");
        db.open("admin", "admin");

        ODocument a = null;
        try {
            db.begin(OTransaction.TXTYPE.OPTIMISTIC);

            a = db.createVertex().save();

            db.commit();
        } catch (Exception e) {
            db.rollback();
            e.printStackTrace();
        }

        try {
            db.begin(OTransaction.TXTYPE.OPTIMISTIC);

            for (int i = 0; i < 100; ++i) {
                db.createEdge(db.createVertex().save(), a.save()).save();
            }

            db.commit();
        } catch (Exception e) {
            db.rollback();
            e.printStackTrace();
        }

        try {
            db.begin(OTransaction.TXTYPE.OPTIMISTIC);

            db.createEdge(db.createVertex().save(), a.save()).save();

            db.commit();
        } catch (Exception e) {
            db.rollback();
            e.printStackTrace();
        } finally {
            db.close();
        }
    }

Both versions I will get exception when committing the third transaction like: om.orientechnologies.orient.core.exception.OConcurrentModificationException: Cannot UPDATE the record #7:4 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v2 your=v1)

The problem here is "a" actually, when I create the edge, if I try to "save" it again, then I will get the above exception; while if not, everything is fine.

But in blueprints, "a" will always be saved:

public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) {
        // ...

        // SAVE THE VERTICES TO ASSURE THEY ARE IN TX
        db.save(((OrientVertex) outVertex).getRawElement());
        db.save(((OrientVertex) inVertex).getRawElement());
        edge.save();
        return edge;
    }

I've tried to disable level1 and level2 cache, and disable mvcc, but nothing works.

How can I solve this problem? Or is it not expected to use a vertex/edge created in another transaction?

bug waiting reply

All 47 comments

Fixed in commit 009dd87f29233a36da009279ca26c9cf8ae5c134

Hi Luca,

I am using 2.M1 and I have started getting the above mentioned error. I was not getting this error when I was using version 1.7.7

Please let me know if you are going to fix it ..

Hi Luca,
same here. I've checked and the version number is the latest.

I am getting the same error in orientdb-community-2.1.5.

Please try to fix it as soon as possible because we have planned to use it in production.

Sometimes I got the same error in Studio but I can't reproduce it.

Hi, OrientDB supports optimistic transactions. Look at: http://orientdb.com/docs/last/Concurrency.html#atomic-operations

Closed in 2.1.9.

Hello Guys,

We are using version orientdb-community-2.1.10 and facing the similar issue . Please let us know in which version this bug is fixed or is still existing.

@varuntahin001 why do you think that that is a bug ?

While deleting and adding edge we are having similar issue as the graph is taking previous vertex in cache and it is throwing Cannot update the record because the version is not the latest.
So the version of vertex is not upgrading and it is taking vertex from cache.
We tried clearing the local cache before reading the vertex and retry logic to avoid this and OConcurrentModificationException. But this logic seems inconsistent , it happens sometimes, while not the other times.

We have also tried with global setting OGlobalConfiguration.CACHE_LOCAL_ENABLED.setValue(false);

As above discussions are happening I was curious as this might be issue with the previous versions , as comment states hotfix for this in 2.1.10

@varuntahin001 sorry for asking but did you try to use latest version , a lot of issues were fixed since 2.1.10 ?

Hi @laa
i have similar error in odb 2.2.13 .

Cannot UPDATE the record #17:9 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v763 your=v762)
    DB name="Putin_DB"

when i try some update on a record i got this error !

Hi @saeedtabrizi , why do you think that this error is incorrect ?

@laa this error is correct but i need to remove all async update operation from my app to handle this issue . i think all users confused because there is lack of documentation about CRUD operation (such as our scenario for parallel updating ) in ODB.
i suggest write more documentation about versioning of records in ODB .
Thanks

@saeedtabrizi @laa I think the problem is that orientdb use OCC instead MVCC or a MIX of both.
There are MVCC in transactions but the strategy looks very chaotic because orientdb says:

For this reason, you need to code your applications to be concurrency-proof.
Reference: http://orientdb.com/docs/2.1/Concurrency.html#transactions

I think I speak to lots of developers when I say thats some of a reason why I use a database is because I dont want to care about such issues. MVCC was created to prevent locking. If orientdb throws an excepction and breaks my operation it shows that MVCC is not implemented correctly.

Use of retry, locking or other mechanism is just "plug holes". In my opinion the whole strategy of concurrency should be reviewed and standardized.

Very good paper: http://guide.couchdb.org/draft/consistency.html

I am sort of lost. I thought if a transaction is used, then the record or records are locked and the updates are carried out at the commit point, meaning, once a transaction is committed, then no other updates can happen. But, if a transaction is used and any version of the data is older than what is in the database, a transaction will also fail. Isn't that how MVCC works?

Scott

Well, I am also lost a bit because I always thought that save-retry is how MVCC works.

Do you mean

-attempt update - get error "you have stale data" - refresh local copy - retry update

??

That is what I understood MVCC was too.

Scott

Which part of that document is ODB not following?

Scott

In fact, that doc explains the "recovering from the (stale data) error is easy from an applicatin perspective", which is normal for such a system.

Recovering from this error is easy to accomplish from an application perspective. Just download CouchDB鈥檚 version of the playlist and provide an opportunity to merge the changes or save local modifications into a new playlist.

Like I said. :smile:

attempt update - get error "you have stale data" - refresh local copy - retry update

Scott

@smolinari What's your point?

What's your point?

That ODB works just like Couchdb in terms of concurrency. If an update to a record happens before another, then the later update will fail, because that version is old/ stale. At that point, the newer record must be retrieved and it must be changed and attempted to update again. That is how MVCC works. It doesn't ensure a proper is update is made between to updating clients. It ensures an improper update won't be made (i.e with stale data).

Scott

Yes, that's correct like GIT. But its not up to the developer to solve this conflict.

This issue should be solved by setting the "conflict strategy" to e.g content or auto merge right?

Cannot UPDATE the record #17:9 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v763 your=v762)
    DB name="Putin_DB"

but I don't understand the part

For this reason, you need to code your applications to be concurrency-proof.

when orientdb use MVCC under the hood.

Update: Orientdb use optimistic concurrency when transactions are commited. This is correct and the case where the developer has to handle concurrency errors.

What conflict strategy are you looking for?

Scott

Its off topic but a way where I dont have to care about transactions conficts. Setting a default conflict strategy like in MVCC I only know the retry statement commit retry 100. I can also LOCK every record but this is not elegant and is only supported in Memory only databases therefore useless.
https://github.com/orientechnologies/orientdb/issues/1677 the issue is 3 years old 馃憥

@smolinari Imagine you use orientdb with lots of clients and high-traffic. All clients starts transactions in any kind of size (orientdb recommend small transactions because of concurrency issues) what happens? You will run into lots of concurrency issues which you have to solve with a retry logic but the end is not in sight because you need a magical retry number??? I dont get the picture of that concept and I can't imagine that all other database vendors goes with the same approach.

After some research I came to this. I think this is what orientdb needs.

Transaction priorities

BEGIN PRIORITY <LOW | NORMAL | HIGH>;

When two transactions contend for the same resource, the one with the lower priority loses and is retried. On retry, the transaction inherits the priority of the winner. This means that each retry makes a transaction stronger and more likely to succeed.

https://www.cockroachlabs.com/docs/transactions.html#transaction-priorities
Isolation levels

BEGIN ISOLATION LEVEL <SERIALIZABLE | SNAPSHOT>;

Unlike SNAPSHOT, SERIALIZABLE isolation permits no anomalies. However, due to CockroachDB鈥檚 transaction model, SERIALIZABLE isolation may require more transaction restarts, especially in the presence of high contention between concurrent transactions. Consider using SNAPSHOT isolation for high contention workloads.

__Orientdb use SERIALIZABLE__
https://www.cockroachlabs.com/docs/transactions.html#isolation-levels

As far as I can tell, ODB offers serializable isolation and they want to switch to something more like snapshotting (possibly).

https://github.com/orientechnologies/orientdb/issues/6013

I have no idea how transaction contention priority should work and seems like it isn't needed, with ODBs OCC system. There are no locks in ODB's transaction system.

I also think the ODB docs on the transaction system is a bit misleading.

This sentence is correct:

Optimistic concurrency requires that you _retire the transaction_ in the event of conflicts.

So, this part of the code with the retries is basically incorrect.

     catch( OConcurrentModificationException e ) {
          // SOMEONE HAS UPDATED THE INVOICE VERTEX
          // AT THE SAME TIME, RETRY IT
     }

There can be no retry, because every retry will fail. The data is stale. As the sentence above states "retire the transaction", you'd have to go to the user and let them know their update failed, ask them to refresh the page and try again (in a web app) i.e. the conflict is resolved by the user.

So, if there are scenarios where retries will work and will get the transaction to commit, those scenarios aren't clarified in the docs. From what I am reading, only stale data (version conflicts) would be the reason for transactions or non-transactional updates to fail, which means you must resolve the conflict and that means getting the fresh version, making the changes again and saving.

Scott

2.2.17 also got this error

Failed to update an entity: Cannot UPDATE the record #7:1 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v2 your=v1)

Got the same error in 2.2.19.

com.orientechnologies.orient.core.exception.OConcurrentModificationException: Cannot UPDATE the record #18:25457 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v2 your=v1)

@easy2coderep why do you think this is an error ?

I mean that is typical behaviour if the same record is updated from two different clients

@laa I am quite sure that there is single instance is performing the update operations sequentially. So if there is any such instance where the record which is accessed by first client, is been modified by another client then better to print the stacktrace of first client with warning message.

It would be more meaningful and users may need not be scaring of this exception.

@easy2coderep sorry I do not understand you. You are quite sure that you make only sequential requests? According to your question update from the first client is already happened so we can not print a stack trace from the first client.

@laa : i came across the same issue and found i this thread.
Do you think ODB is good to be used in a system where data contention is frequent and the order the data is also important?

@zeeshan2709 what do you mean? Sorry, I do not understand a question, could you provide an example or make question more clear?

I'm getting this same error in 2.2.25. Using the RETRY clause of CREATE VERTEX doesn't do anything, apparently. I'm not sure why that clause exists if it doesn't work in this case.

Apparently, every time I create a vertex I have to code my application to catch these errors and retry. That's a really dumb burden to place on the developers, and reflects very poorly on the maturity and sophistication of OrientDB.

Hi @subwindow it can not be thrown during creation of vertexes only during an update, are you sure that you do not create any edges along with vertexes for example?

@subwindow could you provide SQL which you use to create records together with retry?

Hi @laa ,I have this same question.
I use HTTP RESTful API to execute sqlbatch, and I get this error

{
    "code": 409,
    "reason": 409,
    "content": "com.orientechnologies.orient.core.exception.OConcurrentModificationException: Cannot UPDATE the record #64:0 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v15 your=v14)\r\n\tDB name=\"xxxxx\""
}

Here is my request

curl -X POST \
  http://192.168.100.16:2480/batch/xxx_database_xxxx \
  -H 'accept-encoding: gzip,deflate' \
  -H 'authorization: Basic  YWRtaW46YWRtaW4=' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: c7d4e5a0-9c15-d7e1-0830-6233b7069e8c' \
  -d '{
    "transaction": true,
    "operations": [
        {
            "type": "script",
            "language": "sql",
            "script": [
                "begin;  UPDATE v_xxxxxx CONTENT {\"name\":\"wewqe\",\"instanceId\":\"59aa0a0c378e4\",\"creator\":\"yonghuA\",\"ctime\":\"2017-09-02 09:31:56\"} UPSERT WHERE instanceId = '\''59aa0a0c378e4'\''; UPDATE v_xxxxxx CONTENT {\"name\":\"\u6743\u9650\u6d4b\u8bd5\",\"instanceId\":\"59aa0a1865632\",\"creator\":\"yonghuA\",\"ctime\":\"2017-09-02 09:32:08\"} UPSERT WHERE instanceId = '\''59aa0a1865632'\''; commit;"
            ]
        }
    ]
}'

The data were desensitized

This problem is difficult to reproduce, and can I use RETRY to solve this problem?

Was also experiencing this it seems because of an embedded doc with the @type flag set:

https://github.com/orientechnologies/orientdb/issues/3779#issuecomment-338430241

I am able to reproduce this reliably

I get the same error on OrientDB 2.2.0

There's no concurrency in my case. Only 1 client performing the update. (through postman)

At first I thought the record got locked for some reason, so to be sure, I recreated the whole DB. So I performed a new test, Insert record then update it. Same thing happened.

It was happening randomly at first, but now, it does happen on every update.

"Cannot UPDATE the record #18:0 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v5 your=v4)\r\n\tDB name=\"mydb\"\r\n\tDB name=\"mydb\""

In which version has this been fixed?

Thanks.

There is nothing to fix. ODB works correctly. Check your setup and what you are doing. You more then likely have some sort of error in your thinking, data or logic.

Scott

I am having a similar error. I am using orientDB-tp3-3.0.2 and gremlin_python to connect to orientdb and run queries.
I open a thread from the python application (only 1 thread), it runs all gremlin queries sequentially.

Right now I am testing with 3 vertices and 2 edges creation. I successfully create the 3 vertices and am able to create the first edge. The second edge creation throws the error :
500: Cannot UPDATE the record #23:8 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v2 your=v1)

I also get a similar error when I try to drop the graph.
I use :
> g.E().drop().iterate() - works fine
> g.V().drop().iterate() - throws error
> g.V().drop().iterate() - works fine after a few tries and after trying some other queries in between

Hi @Tushavi

see this. https://github.com/orientechnologies/orientdb-gremlin/issues/148

It should be solved in the next OrientDB 3.04 release

Hi @maggiolo00 ,
I upgraded the version to 3.04, it works way better now. There are very infrequent instances, when i get the same error, but the gremlin requests are not freezing now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hp1975 picture hp1975  路  27Comments

gerdhub picture gerdhub  路  38Comments

smolinari picture smolinari  路  29Comments

MartinBrugnara picture MartinBrugnara  路  35Comments

saeedtabrizi picture saeedtabrizi  路  24Comments