Change CAS value


#1

I want to change document’s CAS without modifying document.
How can I do this?
Is using touch with expiry=0 is good idea , If my document has no expiry?


#2

You could perform a touch with expiry 0; although that still counts as a document modification (as the CAS is changing) and hence will trigger a write to disk and replication to replicas.

What exactly is your reason for wanting to modify the CAS (and nothing else)?


#3

I want to modify two document , in two phase commit, I also need to limit length of an array in a documents
For instance, assume we have User and Blog documents, we have an array in user document contains ids of blogs , each user can have up to 10 blogs

As blog id must be unique and each user can only have 10 blog at must
When a user want to create a blog , if I check length of user’s blog in user document , then insert blog document then add data of blog to user document, it is possible that a user have more than 10 blog , even if I check cas when I add blog id to user document

I want to insert blog document first to ensure that id is available and not taken before

I don’t want have more than 10 blog document per user

So I want do the following

  • check length of array in user document
  • touch user document with cas of previous step, if failed skip
  • if succeeded, insert blog document
  • update array in user document

So I think it is impossible to have more than 10 blog

  • is it good approach?
  • do you have alternative solution?
  • how can I get length of an array in lookup in? I don’t want fetch whole array

#4

Hey @socketman2016,

How about this approach:

  • Get the User document (it’s CAS is say 42)
  • If user.blogs.length < 10:
  • Create the blog document
  • Subdoc insert the new blog’s id into the user.blogs array, using CAS 42
  • If this fails with CASMismatchException, repeat the logic: get the user document again, check users.blog.length again, if < 10 then try inserting the new blog’s id again, with the updated CAS. This can all be repeated until some timeout.
  • If at any point users.blog.length >= 10, delete the blog document.

The downside is the blog could briefly (sub-second) exist when perhaps it’s not allowed to. Whether this is a problem depends on your application.

I don’t think your suggested solution would work any better than this. Someone could modify the User doc between you touching it, and you updating the array (when you discover that modification with a CAS failure), meaning that the same problem of a blog document temporarily existing when it shouldn’t still exists.


#5

Actually, I think you may have another option, if you really can’t have the blog document existing briefly when it’s not supposed to: write-locks.

Use the getAndLock call to lock the User doc. If any other client tries to getAndLock the same User, it will fail. Now you can safely check the user.blogs array, and create the blog if < 10. Updating the user.blogs array will also unlock the doc.


#6

I don’t think your suggested solution would work any better than this. Someone could modify the User doc between you touching it, and you updating the array (when you discover that modification with a CAS failure), meaning that the same problem of a blog document temporarily existing when it shouldn’t still exists.

No , there is no issue , My approach did not check CAS when updating array

  1. Check length of array in user document and get CAS (say 42)2
  2. touch user document with cas 42 , if failed skip
  3. if succeeded, insert blog document
  4. update array in user document without cas check

In last step , I dont check CAS because no need , Step 2 works like lock for me , if step 2 is failed I can retry again, if CAS changed by creating a blog on other process , so array length is changed , if user doc just modified we can repeat logic

As getAndLock has a timeout , it is safe to use it?

I dont know : how can I get length of an array in lookup in? I don’t want fetch whole array

Thank you @graham.pople


#7

I’m just not sure how step 2 acts like a lock… what prevents another app getting the user doc and inserting a blog document after step 2? You’d end up with 11 docs in user.blogs then, no?

The timeout on getAndLock makes it more safe - without it, an app could lock a doc, then crash and the doc would be locked forever.

I don’t think you can get just the length of the array. But since the array only contains IDs, the bandwidth cost of fetching that data is negligible anyway.


#8

what prevents another app getting the user doc and inserting a blog document after step 2? You’d end up with 11 docs in user.blogs then, no?

Every time that I add id to array , I do the touch and , If I pass step 2 it means that , As I pass step 1 too (array length is less than 10), it is not possible that other processes changed the array length
I think step 2 can guarantee that step 1 is valid when I want to insert blog document , because 1 process can pass step 2


#9

If you are using CB Server 5 or newer there’s a getCount() method you can use to get the number of elements in an array or dictionary path.


#10

@drigby Thanks a lot


#11

Yes, but can’t you have app A do steps 1 then 2. Then App B comes in and does steps 1, 2, 3, 4. Then App A does steps 3 and 4. And you’d end up with 11 blogs. I think the problem here is that you see step 2 (touching the doc) as blocking other apps from reading and writing that doc, and I’m not getting how that works? So, I think you need getAndLock instead for this. It’s entirely possible I’m just missing something :slight_smile:


#12

@graham.pople Thank you very much, YOU SAVE ME , your are right, I make mistake