Details
-
Bug
-
Resolution: Done
-
Major - P3
-
None
-
3.2.0
-
None
-
Ubuntu, connecting to single instance of Mongo DB 3.0.6 on localhost
Description
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; |
}
|
}
|