How does "update" n1ql works internally when it comes to concurrency?

n1ql

#1

Hello,

I think I’ve asked a similar question before, but I think I actually have a use case.

I’m calling two apis concurrently from javascript.

The two apis use the same document almost at the same time as the two apis gets called almost exactly the same time in many cases.

When I use “upsert” method, I get concurrency issue 90% of the time. However, when I use “update mybucket use keys…” n1ql query, it always works.

As far as I know, n1ql uses “cas” internally. I expected to get an exception from n1ql query, but it looks like it works 100% of the time so far.

Can I depend on n1ql when it comes to concurrency? How does n1ql handle concurrency? Does it automatically lock the document then wait if the target document is locked and then update?


#2

N1QL uses optimistic concurrency, and does not do pessimistic locking. The N1QL concurrency is safe.

UPDATE steps: (1) retrieve document; (2) modify it; (3) save it using CAS.

UPSERT steps: (1) set key-value pair.

Not sure why you are getting concurrency errors with UPSERT.


#3

Hi @geraldss

sorry for the confusion.

For “upsert”, I meant upsert method in a bucket object. I did not mean “upsert” n1ql.

I’ve also tried upsert n1ql last night. This is how I tested (pseudo code)

Say we have a document

{
    "fieldA": "valueA",
    "fieldB": "valueB"
}

My n1ql query for both apis. Both of them use the same key.

function persist(myObject) {
    run query "upsert into mybucket (key, values) values ("mykey", both fieldA and fieldB here)";
} 

In my node script, I call the two apis in async. Sometimes API A gets called first, sometimes API B gets called first.

When I use “upsert” n1ql query, one of the api gets ignored (overwritten?) without exception.

When I use update query, everything works just fine.

for API A,

"update mybucket use keys 'mykey' set fieldA=valueA";

for API B,
"update mybucket use keys 'mykey' set fieldB=valueB";

I first thought that my code has an issue when I used “upsert” query because I did not get any exceptions, but then that does not explain why “update” query works.


#4

UPDATE with USE KEYS updates retrieves and single document using the method @geraldss wrote above.
You’ll get an exception, iff they step over each other step 1 and 3 for the same document.


#5

Hi @keshav_m

I don’t think I’m following.

So far, I haven’t received any exceptions with updates.

Are you saying that there is a way to raise an exception intentionally for testing?


#6

N1QL will detect any conflict and raise the exception itself automatically.


#7

I’m not still following your posts. I’m getting unexpected update result with bucket->upsert. By “unexpected”, I’m not getting any exceptions when it should have raised an exception. I’m aware that n1ql or just upsert from bucket object raise an exception, but I’m not getting them. I think you just repeated yourself what geraldss wrote. That is why I thought there was something I missed.


#8

Are these steps done in parallel on multiple documents? If UPDATE has 100 documents to modify - are they handled one at a time or in bulk?

“UPDATE steps: (1) retrieve document; (2) modify it; (3) save it using CAS.”


#9

By default, the retrieval (get) and updates (sets) are done by parallel threads in bulk.
The in-memory modification (step 2) is done serially.
You can parallelize this step 2 by setting the max-parallelism (per query) or by setting max_parallelism(per node) higher.