-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
None
-
Affects Version/s: 3.2.0
-
Component/s: Connection Management
-
None
-
Environment:Ubuntu, connecting to single instance of Mongo DB 3.0.6 on localhost
We recently upgraded from a older version of the MongoDB driver to 3.2 and are see multiple exceptions being thrown.
Our application runs OK for a day or so but then we're seeing this exception being thrown frequently...
Error message com.mongodb.MongoInterruptedException: Interrupted acquiring a permit to retrieve an item from the pool Sample stack trace …ngodb.internal.connection.ConcurrentPool.acquirePermit (ConcurrentPool.java:186) com.mongodb.internal.connection.ConcurrentPool.get (ConcurrentPool.java:126) …b.connection.DefaultConnectionPool.getPooledConnection (DefaultConnectionPool.java:250) com.mongodb.connection.DefaultConnectionPool.get (DefaultConnectionPool.java:91) com.mongodb.connection.DefaultConnectionPool.get (DefaultConnectionPool.java:80) com.mongodb.connection.DefaultConnectionPool.get com.mongodb.connection.DefaultServer.getConnection (DefaultServer.java:72) …erBinding$ClusterBindingConnectionSource.getConnection (ClusterBinding.java:86) …mongodb.operation.OperationHelper.withConnectionSource (OperationHelper.java:228) com.mongodb.operation.OperationHelper.withConnection (OperationHelper.java:221) com.mongodb.operation.MixedBulkWriteOperation.execute (MixedBulkWriteOperation.java:168) com.mongodb.operation.MixedBulkWriteOperation.execute (MixedBulkWriteOperation.java:74) com.mongodb.Mongo.execute (Mongo.java:782) com.mongodb.Mongo$2.execute (Mongo.java:765) ….mongodb.MongoCollectionImpl.executeSingleWriteRequest (MongoCollectionImpl.java:515) com.mongodb.MongoCollectionImpl.replaceOne (MongoCollectionImpl.java:344) com.mapov.availability.AvailabilityCache.cacheResponse (AvailabilityCache.java:62) com.mapov.availability.AvailabilityCache.cacheResponse (AvailabilityCache.java:45) ….availability.AvailabilityRequestHandler.cacheResponse (AvailabilityRequestHandler.java:146) …apov.availability.AvailabilityRequestHandler.sendError (AvailabilityRequestHandler.java:204) com.mapov.availability.agoda.AgodaAvailability.run (AgodaAvailability.java:93) java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617) java.lang.Thread.run (Thread.java:745) caused by java.lang.InterruptedException …locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1326) java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:409) …ngodb.internal.connection.ConcurrentPool.acquirePermit (ConcurrentPool.java:180) com.mongodb.internal.connection.ConcurrentPool.get (ConcurrentPool.java:126) …b.connection.DefaultConnectionPool.getPooledConnection (DefaultConnectionPool.java:250) com.mongodb.connection.DefaultConnectionPool.get (DefaultConnectionPool.java:91) com.mongodb.connection.DefaultConnectionPool.get (DefaultConnectionPool.java:80) com.mongodb.connection.DefaultServer.getConnection (DefaultServer.java:72) …erBinding$ClusterBindingConnectionSource.getConnection (ClusterBinding.java:86) …mongodb.operation.OperationHelper.withConnectionSource (OperationHelper.java:228) com.mongodb.operation.OperationHelper.withConnection (OperationHelper.java:221) com.mongodb.operation.MixedBulkWriteOperation.execute (MixedBulkWriteOperation.java:168) com.mongodb.operation.MixedBulkWriteOperation.execute (MixedBulkWriteOperation.java:74) com.mongodb.Mongo.execute (Mongo.java:782) com.mongodb.Mongo$2.execute (Mongo.java:765) ….mongodb.MongoCollectionImpl.executeSingleWriteRequest (MongoCollectionImpl.java:515) com.mongodb.MongoCollectionImpl.replaceOne (MongoCollectionImpl.java:344) com.mapov.availability.AvailabilityCache.cacheResponse (AvailabilityCache.java:62) com.mapov.availability.AvailabilityCache.cacheResponse (AvailabilityCache.java:45) ….availability.AvailabilityRequestHandler.cacheResponse (AvailabilityRequestHandler.java:146) …apov.availability.AvailabilityRequestHandler.sendError (AvailabilityRequestHandler.java:204) com.mapov.availability.agoda.AgodaAvailability.run (AgodaAvailability.java:93) java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617) java.lang.Thread.run (Thread.java:745)
We have a single MongoClient instance:
package com.mapov.availability; import com.mongodb.MongoClient; import com.mongodb.client.MongoDatabase; /** * * @author Justin */ public class MongoConnection { private static MongoClient mongoClient = null; private MongoConnection() { // Private constructor } public static MongoDatabase getMapovDB() { if( mongoClient == null) { mongoClient = new MongoClient(); } return mongoClient.getDatabase("mapov"); } }
This is the cache code, called from multiple threads:
package com.mapov.availability; import com.mapov.util.Util; import com.mongodb.BasicDBObject; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; import com.mongodb.client.model.UpdateOptions; import java.util.logging.Logger; import org.bson.Document; import org.bson.conversions.Bson; import org.joda.time.DateTime; import static com.mongodb.client.model.Filters.*; import static com.mongodb.client.model.Sorts.*; /** * * @author Justin */ public class AvailabilityCache { private static final Logger logger = Logger.getLogger(AvailabilityCache.class.getName()); private static final int cacheExpirySeconds = 3600; // Default cache time is 1 hour private final MongoCollection<Document> cacheCollection; public AvailabilityCache() { MongoDatabase mapovDB = MongoConnection.getMapovDB(); this.cacheCollection = mapovDB.getCollection("availability"); } private BasicDBObject buildKey(AvailabilityRequest request, AvailabilityResponse response) { BasicDBObject key = new BasicDBObject("startDate", request.startDate); key.append("endDate", request.endDate); key.append("locale", request.locale); key.append("rooms", Util.implode(request.rooms, ",")); key.append("children", Util.implode(request.children, ",")); key.append("cpID", response.cpID); key.append("providerPropertyID", response.providerPropertyID); key.append("currency", request.currencyCode); return key; } public void cacheResponse(AvailabilityRequest request, AvailabilityResponse response) { cacheResponse(request, response, cacheExpirySeconds); } public void cacheResponse(AvailabilityRequest request, AvailabilityResponse response, int cacheExpirySeconds) { BasicDBObject key = buildKey(request, response); Document doc = new Document(); doc.append("_id", key); doc.append("rate", (int)response.rate*100); doc.append("deepLink", response.deepLink); doc.append("availableRooms", response.availableRooms); doc.append("error", response.error); doc.append("errorMsg", response.errorMsg); DateTime expiry = DateTime.now().plusSeconds(cacheExpirySeconds); doc.append("expireAt", expiry.toDate()); UpdateOptions uo = new UpdateOptions(); uo.upsert(true); cacheCollection.replaceOne(Filters.eq("_id", key),doc, uo);//Upserts } public boolean checkCache(AvailabilityRequest request, AvailabilityResponse response) { boolean found = false; BasicDBObject key = buildKey(request, response); Bson query = eq("_id", key); Bson orderBy = descending("expireAt"); Document result = (Document)cacheCollection.find(query).sort(orderBy).first(); if( result!=null) { response.rate = (Integer)result.get("rate")/100; response.deepLink = (String)result.get("deepLink"); response.error = (Integer)result.get("error"); response.errorMsg = (String)result.get("errorMsg"); if( result.containsKey("availableRooms")) { response.availableRooms = (Integer)result.get("availableRooms"); } found = true; //logger.log(Level.INFO, "Cache match: {0}", response); } return found; } }