[JAVA-2434] Empty insert causes subsequent queries to hang Created: 27/Jan/17  Updated: 27/Jul/17  Resolved: 22/Feb/17

Status: Closed
Project: Java Driver
Component/s: Write Operations
Affects Version/s: 3.0.0
Fix Version/s: 3.5.0

Type: Bug Priority: Major - P3
Reporter: Stephan Schroevers Assignee: Jeffrey Yemin
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Reproduced against server 3.2.11 and 3.4.1.
JDK 1.8.0_121.
Linux Mint and Amazon Linux.


Issue Links:
Related
related to JAVA-2260 Thread blocked forever when operating... Closed
is related to JAVA-2436 Consider allowing zero-document inserts Closed

 Description   

The following test hangs:

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import java.util.Collections;
import org.testng.annotations.Test;
 
public final class MongoTest {
    @Test
    public void testEmptyAndNonemptyListInsertion() {
        try (MongoClient client = new MongoClient()) {
            /*
             * This issue was found while using Jongo, which relies on this deprecated method. See
             * https://github.com/bguerout/jongo/issues/254
             */
            @SuppressWarnings("deprecation")
            DB db = client.getDB("test");
            DBCollection collection = db.getCollection("foo");
            try {
                collection.insert(Collections.emptyList());
            } catch (final IllegalArgumentException e) {
                /*
                 * This is "java.lang.IllegalArgumentException: state should be: count".
                 * For the purposes of this demo it's important that we proceed.
                 */
                e.printStackTrace();
            }
 
            /* This call hangs! */
            collection.insert(new BasicDBObject());
        }
    }
}

The exception associated with the empty insert is:

java.lang.IllegalArgumentException: state should be: count
        at com.mongodb.assertions.Assertions.isTrueArgument(Assertions.java:99)
        at com.mongodb.internal.connection.IndexMap$RangeBased.<init>(IndexMap.java:106)
        at com.mongodb.internal.connection.IndexMap.create(IndexMap.java:52)
        at com.mongodb.connection.WriteCommandProtocol.execute(WriteCommandProtocol.java:103)
        at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:67)
        at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:37)
        at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:168)
        at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:289)
        at com.mongodb.connection.DefaultServerConnection.insertCommand(DefaultServerConnection.java:118)
        at com.mongodb.operation.InsertOperation.executeCommandProtocol(InsertOperation.java:76)
        at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:139)
        at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:133)
        at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
        at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:413)
        at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:133)
        at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:60)
        at com.mongodb.Mongo.execute(Mongo.java:845)
        at com.mongodb.Mongo$2.execute(Mongo.java:828)
        at com.mongodb.DBCollection.executeWriteOperation(DBCollection.java:342)
        at com.mongodb.DBCollection.insert(DBCollection.java:337)
        at com.mongodb.DBCollection.insert(DBCollection.java:328)
        at com.mongodb.DBCollection.insert(DBCollection.java:298)
        at com.mongodb.DBCollection.insert(DBCollection.java:264)
        at com.mongodb.DBCollection.insert(DBCollection.java:248)
        at com.exampe.MongoTest.testEmptyAndNonemptyListInsertion(MongoTest.java:22)

(I'd argue that an empty insert should just be a NO-OP, but I noticed that MongoCollection#insertMany also throws an IllegalArgumentException on empty input. At the very least the documentation should be clearer on this point. But this is not the primary topic of this ticket.)

The second insertion hangs indefinitely. Associated jstack thread dump:

"pool-1-thread-1" #12 prio=5 os_prio=0 tid=0x00007f96807bb000 nid=0x61a3 waiting on condition [0x00007f96663ac000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x000000076d293b28> (a java.util.concurrent.CountDownLatch$Sync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
        at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
        at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:252)
        at com.mongodb.connection.UsageTrackingInternalConnection.receiveMessage(UsageTrackingInternalConnection.java:96)
        at com.mongodb.connection.DefaultConnectionPool$PooledConnection.receiveMessage(DefaultConnectionPool.java:440)
        at com.mongodb.connection.WriteCommandProtocol.receiveMessage(WriteCommandProtocol.java:262)
        at com.mongodb.connection.WriteCommandProtocol.execute(WriteCommandProtocol.java:104)
        at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:67)
        at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:37)
        at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:168)
        at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:289)
        at com.mongodb.connection.DefaultServerConnection.insertCommand(DefaultServerConnection.java:118)
        at com.mongodb.operation.InsertOperation.executeCommandProtocol(InsertOperation.java:76)
        at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:139)
        at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:133)
        at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
        at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:413)
        at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:133)
        at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:60)
        at com.mongodb.Mongo.execute(Mongo.java:845)
        at com.mongodb.Mongo$2.execute(Mongo.java:828)
        at com.mongodb.DBCollection.executeWriteOperation(DBCollection.java:342)
        at com.mongodb.DBCollection.insert(DBCollection.java:337)
        at com.mongodb.DBCollection.insert(DBCollection.java:328)
        at com.mongodb.DBCollection.insert(DBCollection.java:298)
        at com.mongodb.DBCollection.insert(DBCollection.java:264)
        at com.mongodb.DBCollection.insert(DBCollection.java:201)
        at com.example.MongoTest.testEmptyAndNonemptyListInsertion(MongoTest.java:32)

This issue looks similar to JAVA-2260, but that ticket lacks the content necessary to be sure (for a non-expert like myself).



 Comments   
Comment by Githook User [ 22/Feb/17 ]

Author:

{u'username': u'jyemin', u'name': u'Jeff Yemin', u'email': u'jeff.yemin@10gen.com'}

Message: JAVA-2434: Empty list of writes throws IllegalArgumentException
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/ca0be04dc1beb7dcaf3c67f710eb96a0e9d818de

Comment by Stephan Schroevers [ 27/Jan/17 ]

Alright, I filed JAVA-2436.

Comment by Jeffrey Yemin [ 27/Jan/17 ]

There is some inconsistency between the server, drivers, and the shell in this regard, so feel free to open a ticket. We may end up closing it as Works as Designed, but we should at least track the request separately from this one, as there's a real bug here that we need to fix.

Comment by Stephan Schroevers [ 27/Jan/17 ]

Thanks for the rapid response, jeff.yemin!

Given that this bug occurs only in situations that an application must take care to avoid anyway [..]

Indeed, as it stands one should prevent inserting zero documents. But in cases where the list to be inserted is generated dynamically, this can quite easily happen. Is the MongoDB team's official stance on this topic that one should guard all such invocations, or should/can/may I open a separate ticket with a request to have this limitation lifted?

Comment by Jeffrey Yemin [ 27/Jan/17 ]

Thanks for reporting this. We've identified the root cause and will get a fix in the next patch release.

Given that this bug occurs only in situations that an application must take care to avoid anyway, I'm going to change the priority from Critical to Major.

Generated at Thu Feb 08 08:57:12 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.