Using server side generated ids with compare exchange

82 views
Skip to first unread message

Connor Aaron Roberts

unread,
Dec 16, 2020, 2:51:06 AM12/16/20
to RavenDB - 2nd generation document database
Hello, how can I use server side generated ids with compare exchange? In the example below, after StoreAsync(), account.Id is equal to "accounts|" (because it is server side generated). When it should be equal to "accounts/1".

Example:
Capture.PNG

Grisha Kotler

unread,
Dec 16, 2020, 3:06:16 AM12/16/20
to rav...@googlegroups.com
Regarding the document id, it will be generated after SaveChanges (since the id is generated on the server).
var account = new Account();
await session.StoreAsync(account);

This will generate the id after StoreAsync.

Grisha Kotler
Team Leader   /   Hibernating Rhinos LTD
Skype:  grisha.kotler
Support:  sup...@ravendb.net
  


--
You received this message because you are subscribed to the Google Groups "RavenDB - 2nd generation document database" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ravendb/c478f3a0-3821-45a6-a56a-86f56517bae8n%40googlegroups.com.
Message has been deleted

Connor Aaron Roberts

unread,
Dec 16, 2020, 4:57:06 PM12/16/20
to RavenDB - 2nd generation document database

I dont want to increment the Identity Id if the compare exchange value already exists... so I cant call save changes.
On Wednesday, December 16, 2020 at 4:28:54 PM UTC-5 Connor Aaron Roberts wrote:
I know that, is there any way I can do what I'm trying to do?

Connor Aaron Roberts

unread,
Dec 16, 2020, 4:57:37 PM12/16/20
to RavenDB - 2nd generation document database

and I want to use server side generated ids.

Oren Eini (Ayende Rahien)

unread,
Dec 17, 2020, 3:03:37 AM12/17/20
to ravendb
You cannot mix those together, I'm afraid. You need to know what the ids of the items would be before submitting the transaction to the cluster.
There is a feature request to allow scripts as part of cluster wide transactions, but that isn't a high priority at the moment.

Can you take a step back and explain what is the use case that you are trying to implement?



--
Oren Eini
CEO   /   Hibernating Rhinos LTD
Skype:  ayenderahien
Support:  sup...@ravendb.net
  

Connor Aaron Roberts

unread,
Dec 17, 2020, 11:56:08 AM12/17/20
to RavenDB - 2nd generation document database
I want to have a collection with the document ID's as a incrementing integer (Identity). Each document in this collection has a username, and I want this username to be unique.

Typically you would use a compare exchange to ensure the username is unique, but in this case I can't, because Identity ID's are server side generated. Therefore I can't set the compare exchanges value to the document ID.

In any other scenario, I would just use ravendb hilo document IDs. I cant do that in this scenario because Im trying to recreate a database for a video game that was originally using MySQL. If I could do it this way it would be a lot easier for me.

Oren Eini (Ayende Rahien)

unread,
Dec 18, 2020, 5:58:38 AM12/18/20
to ravendb
Why do you need to use an identity? That is the key problem, because it won't compose well with compare exchange. 
Also, note that you can do that in two calls. First to reserver the username, then to set it to the generate id.

Grisha Kotler

unread,
Dec 18, 2020, 8:53:43 AM12/18/20
to rav...@googlegroups.com
You can generate the server-side identity before trying to generate the compare exchange
long value = store.Maintenance.Send(new NextIdentityForOperation("users"));
var docId = $"users/{value}";


Grisha Kotler
Team Leader   /   Hibernating Rhinos LTD
Skype:  grisha.kotler
Support:  sup...@ravendb.net
  

Connor Aaron Roberts

unread,
Dec 18, 2020, 8:58:26 AM12/18/20
to rav...@googlegroups.com
I dont want to increnent the identity if the username already exists.

Oren Eini (Ayende Rahien)

unread,
Dec 18, 2020, 10:57:44 AM12/18/20
to ravendb
Is the id meaningful to your system?

Connor Aaron Roberts

unread,
Dec 18, 2020, 10:58:34 AM12/18/20
to rav...@googlegroups.com
Yes, I must use the id as identity.

Oren Eini (Ayende Rahien)

unread,
Dec 18, 2020, 11:40:06 AM12/18/20
to ravendb

Connor Aaron Roberts

unread,
Dec 18, 2020, 11:56:27 AM12/18/20
to rav...@googlegroups.com
Because of poor design. It's not something I can change.

Connor Aaron Roberts

unread,
Dec 18, 2020, 6:06:40 PM12/18/20
to RavenDB - 2nd generation document database

Regardless, this is very easy to implement in sql server. I think ravendb should support this.

Oren Eini (Ayende Rahien)

unread,
Dec 20, 2020, 9:24:37 AM12/20/20
to ravendb
The key issue here is that on SQL Server this is easy. It is easy there because you only have to deal with a single node.
If you wanted to do something like that with RavenDB, using a patch script to manage that is easy enough.
Our patch API allows to do something like:

 var id = put("test/", {Name: "Ayende"});
put("names/Ayende", { Data: "foo", Id: id }, ""); // <-- optimistic concurrency

However, RavenDB is a multi master setup. Which means that you have to account for concurrent independent operations.

That is why we have the ability to compare exchange and cluster wide transactions, after all. 
What you can do is something like this:

Two compare exchanges, one that you'll increment to get the id and the other to reverse the value. Something like this:

var identity = session.Advanced.ClusterTransaction.GetCompareExchangeValue<long>("Identity");
if (identity == null)
{
    identity = session.Advanced.ClusterTransaction.CreateCompareExchangeValue("Identity", 0L);
}

identity.Value++;
session.Advanced.ClusterTransaction.CreateCompareExchangeValue("users/ayende", identity.Value);
session.SaveChanges();

Connor Aaron Roberts

unread,
Dec 20, 2020, 10:41:52 AM12/20/20
to RavenDB - 2nd generation document database
Oh, its working. This is very nice. Is there anything I should be concerned about or aware of?

Oren Eini (Ayende Rahien)

unread,
Dec 21, 2020, 10:34:42 AM12/21/20
to ravendb
You need to be aware of failure modes. If you reserved the name, and then you failed, you might need to handle that.
But not beyond this

Reply all
Reply to author
Forward
0 new messages