Should this be ported to the 1.6 branch?

Gary


On Sat, Dec 29, 2012 at 1:23 PM, <pste...@apache.org> wrote:

> Author: psteitz
> Date: Sat Dec 29 18:23:33 2012
> New Revision: 1426799
>
> URL: http://svn.apache.org/viewvc?rev=1426799&view=rev
> Log:
> Fixed threadsafety problem in GOP, GKOP invalidateObject. JIRA: POOL-231.
>
> Modified:
>
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
>
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
>
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
>
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
>
> Modified:
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java?rev=1426799&r1=1426798&r2=1426799&view=diff
>
> ==============================================================================
> ---
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> (original)
> +++
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> Sat Dec 29 18:23:33 2012
> @@ -551,7 +551,11 @@ public class GenericKeyedObjectPool<K,T>
>              throw new IllegalStateException(
>                      "Object not currently part of this pool");
>          }
> -        destroy(key, p, true);
> +        synchronized (p) {
> +            if (p.getState() != PooledObjectState.INVALID) {
> +                destroy(key, p, true);
> +            }
> +        }
>      }
>
>
>
> Modified:
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java?rev=1426799&r1=1426798&r2=1426799&view=diff
>
> ==============================================================================
> ---
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> (original)
> +++
> commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> Sat Dec 29 18:23:33 2012
> @@ -581,10 +581,14 @@ public class GenericObjectPool<T> extend
>                  return;
>              } else {
>                  throw new IllegalStateException(
> -                        "Returned object not currently part of this
> pool");
> +                        "Invalidated object not currently part of this
> pool");
>              }
>          }
> -        destroy(p);
> +        synchronized (p) {
> +            if (p.getState() != PooledObjectState.INVALID) {
> +                destroy(p);
> +            }
> +        }
>      }
>
>      /**
>
> Modified:
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java?rev=1426799&r1=1426798&r2=1426799&view=diff
>
> ==============================================================================
> ---
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> (original)
> +++
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> Sat Dec 29 18:23:33 2012
> @@ -1433,6 +1433,88 @@ public class TestGenericKeyedObjectPool
>          // Check thread was interrupted
>          assertTrue(wtt._thrown instanceof InterruptedException);
>      }
> +
> +    /**
> +     * POOL-231 - verify that concurrent invalidates of the same object
> do not
> +     * corrupt pool destroyCount.
> +     */
> +    @Test
> +    public void testConcurrentInvalidate() throws Exception {
> +        // Get allObjects and idleObjects loaded with some instances
> +        final int nObjects = 1000;
> +        final String key = "one";
> +        pool.setMaxTotal(nObjects);
> +        pool.setMaxTotalPerKey(nObjects);
> +        pool.setMaxIdlePerKey(nObjects);
> +        final String [] obj = new String[nObjects];
> +        for (int i = 0; i < nObjects; i++) {
> +            obj[i] = pool.borrowObject(key);
> +        }
> +        for (int i = 0; i < nObjects; i++) {
> +            if (i % 2 == 0) {
> +                pool.returnObject(key, obj[i]);
> +            }
> +        }
> +        final int nThreads = 20;
> +        final int nIterations = 60;
> +        final InvalidateThread[] threads = new InvalidateThread[nThreads];
> +        // Randomly generated list of distinct invalidation targets
> +        final ArrayList<Integer> targets = new ArrayList<Integer>();
> +        final Random random = new Random();
> +        for (int j = 0; j < nIterations; j++) {
> +            // Get a random invalidation target
> +            Integer targ = new Integer(random.nextInt(nObjects));
> +            while (targets.contains(targ)) {
> +                targ = new Integer(random.nextInt(nObjects));
> +            }
> +            targets.add(targ);
> +            // Launch nThreads threads all trying to invalidate the target
> +            for (int i = 0; i < nThreads; i++) {
> +                threads[i] = new InvalidateThread(pool,key, obj[targ]);
> +            }
> +            for (int i = 0; i < nThreads; i++) {
> +                new Thread(threads[i]).start();
> +            }
> +            boolean done = false;
> +            while (!done) {
> +                done = true;
> +                for (int i = 0; i < nThreads; i++) {
> +                    done = done && threads[i].complete();
> +                }
> +                Thread.sleep(100);
> +            }
> +        }
> +        Assert.assertEquals(nIterations, pool.getDestroyedCount());
> +    }
> +
> +    /**
> +     * Attempts to invalidate an object, swallowing IllegalStateException.
> +     */
> +    static class InvalidateThread implements Runnable {
> +        private final String obj;
> +        private final KeyedObjectPool<String, String> pool;
> +        private final String key;
> +        private boolean done = false;
> +        public InvalidateThread(KeyedObjectPool<String, String> pool,
> String key, String obj) {
> +            this.obj = obj;
> +            this.pool = pool;
> +            this.key = key;
> +        }
> +        public void run() {
> +            try {
> +                pool.invalidateObject(key, obj);
> +            } catch (IllegalStateException ex) {
> +                // Ignore
> +            } catch (Exception ex) {
> +                Assert.fail("Unexpected exception " + ex.toString());
> +            } finally {
> +                done = true;
> +            }
> +        }
> +        public boolean complete() {
> +            return done;
> +        }
> +    }
>
>      /*
>       * Very simple test thread that just tries to borrow an object from
>
> Modified:
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java?rev=1426799&r1=1426798&r2=1426799&view=diff
>
> ==============================================================================
> ---
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> (original)
> +++
> commons/proper/pool/trunk/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> Sat Dec 29 18:23:33 2012
> @@ -1100,6 +1100,84 @@ public class TestGenericObjectPool exten
>          assertEquals("Total count different than expected.", 0,
> pool.getNumActive());
>          pool.close();
>      }
> +
> +    /**
> +     * POOL-231 - verify that concurrent invalidates of the same object
> do not
> +     * corrupt pool destroyCount.
> +     */
> +    @Test
> +    public void testConcurrentInvalidate() throws Exception {
> +        // Get allObjects and idleObjects loaded with some instances
> +        final int nObjects = 1000;
> +        pool.setMaxTotal(nObjects);
> +        pool.setMaxIdle(nObjects);
> +        final Object[] obj = new Object[nObjects];
> +        for (int i = 0; i < nObjects; i++) {
> +            obj[i] = pool.borrowObject();
> +        }
> +        for (int i = 0; i < nObjects; i++) {
> +            if (i % 2 == 0) {
> +                pool.returnObject(obj[i]);
> +            }
> +        }
> +        final int nThreads = 20;
> +        final int nIterations = 60;
> +        final InvalidateThread[] threads = new InvalidateThread[nThreads];
> +        // Randomly generated list of distinct invalidation targets
> +        final ArrayList<Integer> targets = new ArrayList<Integer>();
> +        final Random random = new Random();
> +        for (int j = 0; j < nIterations; j++) {
> +            // Get a random invalidation target
> +            Integer targ = new Integer(random.nextInt(nObjects));
> +            while (targets.contains(targ)) {
> +                targ = new Integer(random.nextInt(nObjects));
> +            }
> +            targets.add(targ);
> +            // Launch nThreads threads all trying to invalidate the target
> +            for (int i = 0; i < nThreads; i++) {
> +                threads[i] = new InvalidateThread(pool, obj[targ]);
> +            }
> +            for (int i = 0; i < nThreads; i++) {
> +                new Thread(threads[i]).start();
> +            }
> +            boolean done = false;
> +            while (!done) {
> +                done = true;
> +                for (int i = 0; i < nThreads; i++) {
> +                    done = done && threads[i].complete();
> +                }
> +                Thread.sleep(100);
> +            }
> +        }
> +        Assert.assertEquals(nIterations, pool.getDestroyedCount());
> +    }
> +
> +    /**
> +     * Attempts to invalidate an object, swallowing IllegalStateException.
> +     */
> +    static class InvalidateThread implements Runnable {
> +        private final Object obj;
> +        private final ObjectPool<Object> pool;
> +        private boolean done = false;
> +        public InvalidateThread(ObjectPool<Object> pool, Object obj) {
> +            this.obj = obj;
> +            this.pool = pool;
> +        }
> +        public void run() {
> +            try {
> +                pool.invalidateObject(obj);
> +            } catch (IllegalStateException ex) {
> +                // Ignore
> +            } catch (Exception ex) {
> +                Assert.fail("Unexpected exception " + ex.toString());
> +            } finally {
> +                done = true;
> +            }
> +        }
> +        public boolean complete() {
> +            return done;
> +        }
> +    }
>
>      @Test(timeout=60000)
>      public void testMinIdle() throws Exception {
>
>
>


-- 
E-Mail: garydgreg...@gmail.com | ggreg...@apache.org
JUnit in Action, 2nd Ed: <http://goog_1249600977>http://bit.ly/ECvg0
Spring Batch in Action: <http://s.apache.org/HOq>http://bit.ly/bqpbCK
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory

Reply via email to