Concurrent update to the same document can get lost


#1

Hello,
I am using Couchbase Community 4.5.1 server with Java client in version 2.4.7. I try to concurrently update value for N different properties in one document. All requests succeed. At the end I get the whole document and observe that some updates were lost. Problem is easy to reproduce when more than one instance of my service is working. The service uses Java SDK and operate on Couchbase cluster. Below unit test simulates this situation even with single Couchbase node (an average of 25% of the update is lost):

@Test
public void shouldUpdateManyPartsOfDocumentInParallel() throws InterruptedException
{
//configuration
final int propertiesToCreate = 200;
final int propertiesPerThread = 10;

    //given
    final JsonObject data = JsonObject.create().put("initialKey", "initialValue");
    final String docuId = "testDocument";

    final List<String> keys = IntStream.rangeClosed(1, propertiesToCreate).boxed() //
            .map(i -> "testKey_" + i) //
            .collect(Collectors.toList());

    // each thread simulate separated instance of service and will try to create 10 new properties in document
    final List updates = IntStream.range(0, propertiesToCreate / propertiesPerThread).boxed() //
            .map(i -> (Callable) () ->
            {
                CouchbaseCluster cluster = CouchbaseCluster.create();
                Bucket bucket = cluster.openBucket("default");

                final int startIndex = i * propertiesPerThread;
                keys.subList(startIndex, startIndex + propertiesPerThread)
                        .forEach(path ->
                        { //
                            try
                            {
                                final String value = path.replace("Key", "Value");
                                bucket.mutateIn(docuId) //
                                        .upsert(path, value, SubdocOptionsBuilder.builder().createParents(true)) //
                                        .execute();
                            }
                            catch (final Exception e)
                            {
                                System.out.println(path + ": " + e.toString());
                            }
                        });
                return "";
            }).collect(Collectors.toList());

    final ExecutorService executorService = Executors.newWorkStealingPool(updates.size());

    //CREATING DOCUMENT
    //when
    final JsonDocument document = JsonDocument.create(docuId, data);
    try {
        bucket.upsert(document);
    } catch (final Exception e) {
        System.out.println("Error during creating document" + e.getMessage());
        throw e;
    }

    //UPDATING DOCUMENT
    executorService.invokeAll(updates)
            .stream()
            .map(future -> {
                try {
                    return future;
                }
                catch (Exception e) {
                    throw new IllegalStateException(e);
                }
            })
            .forEach(System.out::println);

    // CHECK RESULT OF OPERATIONS
    final Map<String, Object> receivedDocument = bucket.get(docuId).content().toMap();

    int errors = 0;
    final ArrayList<Object> failedUpdates = new ArrayList<>();
    for(String key: keys) {
        if(!receivedDocument.containsKey(key)) {
            errors++;
            failedUpdates.add(key);
        }
    }

    System.out.println(String.format("Number of errors: %d. Failed to create following properties: %s", errors, failedUpdates.toString()));
}

#2

@sebarys, you’ve hit a known issue with the 4.5.1 release: MB-21597. See the release notes for guidance: Release Notes for Couchbase Server 4.5.


#3

Thank you for response @jkurtz. There is any place where can I check if this issue will be solved also in the next community editions?


#4

There is any place where can I receive some information about this?