@@ -41,6 +41,7 @@ public class SimpleObjectPool<T extends PoolObject> implements AutoCloseable {
41
41
private final Condition retryCreationWait ;
42
42
private final AtomicLong objectCreateCount = new AtomicLong (0 );
43
43
private final AtomicInteger currentPoolSize = new AtomicInteger (0 );
44
+ private final AtomicLong timesBorrowed = new AtomicLong (0 );
44
45
45
46
public SimpleObjectPool (SimpleObjectPoolConfig config , PooledObjectFactory <T > factory ) {
46
47
this .config = config ;
@@ -172,7 +173,7 @@ private void evictionRun() {
172
173
173
174
if (!objectsToDestroy .isEmpty ()) {
174
175
log .debug ("Evicted {} idle objects. Current pool size: {}, Idle: {}, Borrowed: {}" ,
175
- objectsToDestroy .size (), currentPoolSize (), idleObjectCount (), borrowedObjectsCount ());
176
+ objectsToDestroy .size (), currentPoolSize (), idleObjectCount (), borrowedObjectsCount ());
176
177
objectsToDestroy .clear ();
177
178
}
178
179
}
@@ -256,7 +257,8 @@ private PooledObject<T> createObject() {
256
257
try {
257
258
pooledObject = new PooledObject <>(factory .createObject (), objectCreateCount .incrementAndGet ());
258
259
} catch (Exception e ) {
259
- throw new PoolObjectException ("Failed to create object" , e );
260
+ log .error ("Failed to create object for the pool: {}" , e .getMessage ());
261
+ throw e ;
260
262
}
261
263
if (config .testOnCreate ()) {
262
264
if (!factory .isObjectValid (pooledObject .object ())) {
@@ -319,9 +321,15 @@ public T borrowObject() throws PoolException {
319
321
pooledObject = createObject ();
320
322
createdObject = true ;
321
323
retriesLeft --;
322
- } catch (PoolObjectException | PoolObjectValidationException e ) {
323
- log .error ("Failed to create objects when borrowing" , e );
324
+ } catch (Exception e ) {
325
+ if (e instanceof PoolObjectValidationException ) {
326
+ log .error ("" , e );
327
+ }
324
328
retriesLeft --;
329
+ if (retriesLeft < 0 ) {
330
+ // we have exhausted retries and throw the actual exception so that the caller can handle it
331
+ throw e ;
332
+ }
325
333
continue ;
326
334
}
327
335
}
@@ -343,11 +351,13 @@ public T borrowObject() throws PoolException {
343
351
continue ;
344
352
}
345
353
354
+
346
355
// Object is valid, prepare for borrowing
347
356
pooledObject .borrow ();
348
357
factory .activateObject (object );
349
358
borrowedObjects .put (pooledObject .id (), pooledObject );
350
359
if (createdObject ) currentPoolSize .incrementAndGet ();
360
+ timesBorrowed .incrementAndGet ();
351
361
notEmpty .signal ();
352
362
log .trace ("Resource borrowed - id: {}, current pool size: {}" ,
353
363
pooledObject .id (), currentPoolSize .get ());
@@ -380,43 +390,43 @@ public void returnObject(T obj, boolean broken) throws PoolObjectException {
380
390
381
391
try {
382
392
lock .lock ();
383
- var pooledEntity = borrowedObjects .get (obj .getEntityId ());
384
- if (pooledEntity == null ) {
393
+ var pooledObject = borrowedObjects .get (obj .getEntityId ());
394
+ if (pooledObject == null ) {
385
395
log .warn ("Attempted returning object that is not in borrowed objects list. id: {}" , obj .getEntityId ());
386
396
return ;
387
397
}
388
398
if (broken ) {
389
- pooledEntity .broken (true );
399
+ pooledObject .broken (true );
390
400
}
391
401
// First check if object is broken
392
- boolean isValid = !pooledEntity .isBroken ();
402
+ boolean isValid = !pooledObject .isBroken ();
393
403
394
404
// Then perform testOnReturn validation if configured and object isn't already invalid
395
405
if (isValid && config .testOnReturn ()) {
396
406
try {
397
407
isValid = factory .isObjectValid (obj );
398
408
} catch (Exception e ) {
399
409
log .error ("Error validating object on return" , e );
410
+ // exception is swallowed since object is already invalid and will be destroyed.
400
411
isValid = false ;
401
412
}
402
413
}
403
414
404
415
if (!isValid ) {
405
- removeAndDestroyBorrowedObjects ( pooledEntity );
406
- log . warn ( "Returned broken or invalid entity with id {} and destroyed it." , pooledEntity . id () );
416
+ log . warn ( "Returned broken or invalid entity with id {} and destroying it." , pooledObject . id () );
417
+ removeAndDestroyBorrowedObjects ( pooledObject );
407
418
} else {
408
419
409
420
factory .passivateObject (obj );
410
- borrowedObjects .remove (pooledEntity .id ());
411
- pooledEntity .markIdle ();
412
- idleObjects .add (pooledEntity );
421
+ borrowedObjects .remove (pooledObject .id ());
422
+ pooledObject .markIdle ();
423
+ idleObjects .add (pooledObject );
413
424
log .trace ("Object returned - id: {}, current pool size: {}" ,
414
- pooledEntity .id (), currentPoolSize .get ());
425
+ pooledObject .id (), currentPoolSize .get ());
415
426
notEmpty .signal ();
416
427
}
417
428
} catch (Exception e ) {
418
- log .error ("Error returning object to pool" , e );
419
- throw new PoolObjectException ("Failed to return object to pool" , e );
429
+ throw new PoolObjectException ("Unable to properly return object back to pool" , e );
420
430
} finally {
421
431
lock .unlock ();
422
432
}
@@ -530,4 +540,43 @@ public long numOfObjectsCreated() {
530
540
public int waitingCount () {
531
541
return lock .getQueueLength ();
532
542
}
543
+
544
+
545
+ /**
546
+ * Returns the total number of times objects have been borrowed from this pool
547
+ * since its creation.
548
+ *
549
+ * @return the total number of times objects have been borrowed
550
+ */
551
+ public long numOfTimesBorrowedFromPool () {
552
+ return timesBorrowed .get ();
553
+ }
554
+
555
+
556
+ /**
557
+ * Returns the number of times a specific object has been borrowed from the pool
558
+ * since its creation.
559
+ * <p>
560
+ * Note that this method will only return statistics for objects that are currently
561
+ * borrowed from the pool. For objects that are idle this will have to iterate and will have a delay.
562
+ * If you need to check, check only for borrowed objects.
563
+ *
564
+ * @param objectId the id of the object to query, may be null
565
+ * @return the number of times the object has been borrowed
566
+ */
567
+ public long numOfTimesBorrowed (Long objectId ) {
568
+ if (objectId == null ) return 0 ;
569
+ var pooledObject = borrowedObjects .get (objectId );
570
+ if (pooledObject == null ) {
571
+ log .warn ("Object with id {} not found in borrowed objects" , objectId );
572
+ pooledObject = idleObjects .stream ()
573
+ .filter (pooledObject1 -> pooledObject1 .id ().equals (objectId ))
574
+ .findAny ().orElse (null );
575
+ }
576
+ if (pooledObject == null ) {
577
+ log .warn ("Object with id {} not found in idle objects" , objectId );
578
+ return 0 ;
579
+ }
580
+ return pooledObject .timesBorrowed ();
581
+ }
533
582
}
0 commit comments