Сервер Couchbase, допускающий одновременную мутацию документов, даже с установленным CAS? - PullRequest
2 голосов
/ 30 января 2020

У меня есть объект SomeObject, который представляет объект, сохраненный как документ в Couchbase. У SomeObject есть переменная cas для хранения значения CAS.

У меня есть такой код:

/* Get two identical objects from Couchbase, they'll have identical CAS value */
SomeObject someObjectA = getSomeObjectFromCouchbase(sameId);
SomeObject someObjectB = getSomeObjectFromCouchbase(sameId);

/* Make arbitrary modifications to the objects */
someObjectA.getListInObject().add(arbitraryValue1);
someObjectB.getListInObject().add(arbitraryValue2);

/* Convert SomeObject objects to JsonDocument objects, ensuring the CAS value is set */
JsonDocument jsonDocA = JsonDocument.create(someObjectA.getId(), JsonObject.fromJson(mapper.writeValueAsString(someObjectA)), someObjectA.getCas());
JsonDocument jsonDocB = JsonDocument.create(someObjectB.getId(), JsonObject.fromJson(mapper.writeValueAsString(someObjectB)), someObjectB.getCas());

/* Perform upserts on both JsonDocument objects; expectation is the second one should fail with CASMismatchException because the CAS value should have changed after the first upsert */
couchbaseDao.getDatasource().getBucket().upsert(jsonDocA, writeTimeout, TimeUnit.MILLISECONDS);
couchbaseDao.getDatasource().getBucket().upsert(jsonDocB, writeTimeout, TimeUnit.MILLISECONDS);

Несмотря на мои ожидания, что второе обновление должно завершиться с CASMismatchException, который я пытаюсь поймать с помощью оборачивая код в блок try / catch, этого не происходит. Оба upserts успешны, и сервер действительно изменяет значение CAS после обоих upserts. Это как если бы он даже не проверял значение CAS при загрузке, просто слепо принимал что-то и затем обновлял значение CAS.

Конечный результат состоит в том, что список в документе Couchbase содержит толькоопроизвольное значение произвольного, а отсутствует произвольное произвольное значение1 в то время как я ожидал, что он будет иметь произвольное значение1, а не произвольное значение2 (так как второй переход должен был вызвать CASMismatchException). Я что-то не так делаю, или что-то не так с сервером, что он неправильно работает с CAS?

1 Ответ

4 голосов
/ 30 января 2020

CAS просто используется в методе replace :

    JsonDocument doc = userRepository.getCouchbaseOperations().getCouchbaseBucket().get("1");
    JsonDocument doc2 = userRepository.getCouchbaseOperations().getCouchbaseBucket().get("1");
    doc.content().put("username", "Michael");

    userRepository.getCouchbaseOperations().getCouchbaseBucket().replace(doc);

    doc2.content().put("username", "denis");
    userRepository.getCouchbaseOperations().getCouchbaseBucket().replace(doc2);

    User userResult2 = userRepository.findById("1").get();
    System.out.println(userResult2.getUsername());

Если вы попытаетесь выполнить приведенный выше код, вы получите следующее исключение:

aused by: com.couchbase.client.java.error.CASMismatchException: null
at com.couchbase.client.java.bucket.api.Mutate$3$1.call(Mutate.java:333) ~[java-client-2.7.11.jar:na]
at com.couchbase.client.java.bucket.api.Mutate$3$1.call(Mutate.java:308) ~[java-client-2.7.11.jar:na]
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:69) ~[rxjava-1.3.8.jar:1.3.8]
at rx.observers.Subscribers$5.onNext(Subscribers.java:235) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onNext(OnSubscribeDoOnEach.java:101) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.producers.SingleProducer.request(SingleProducer.java:65) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.producers.ProducerArbiter.setProducer(ProducerArbiter.java:126) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeTimeoutTimedWithFallback$TimeoutMainSubscriber.setProducer(OnSubscribeTimeoutTimedWithFallback.java:155) ~[rxjava-1.3.8.jar:1.3.8]
at rx.Subscriber.setProducer(Subscriber.java:205) ~[rxjava-1.3.8.jar:1.3.8]
at rx.internal.operators.OnSubscribeMap$MapSubscriber.setProducer(OnSubscribeMap.java:102) ~[rxjava-1.3.8.jar:1.3.8]
at rx.Subscriber.setProducer(Subscriber.java:205) ~[rxjava-1.3.8.jar:1.3.8]
at rx.Subscriber.setProducer(Subscriber.java:205) ~[rxjava-1.3.8.jar:1.3.8]
at rx.subjects.AsyncSubject.onCompleted(AsyncSubject.java:103) ~[rxjava-1.3.8.jar:1.3.8]
at com.couchbase.client.core.endpoint.AbstractGenericHandler.completeResponse(AbstractGenericHandler.java:508) ~[core-io-1.7.11.jar:na]
at com.couchbase.client.core.endpoint.AbstractGenericHandler.access$000(AbstractGenericHandler.java:86) ~[core-io-1.7.11.jar:na]
at com.couchbase.client.core.endpoint.AbstractGenericHandler$1.call(AbstractGenericHandler.java:526) ~[core-io-1.7.11.jar:na]
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) ~[rxjava-1.3.8.jar:1.3.8]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:835) ~[na:na]
Caused by: rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value: com.couchbase.client.core.message.kv.ReplaceResponse.class
...