@@ -169,25 +169,37 @@ public void setUp() throws Exception {
169169 public void destroy () throws Exception {
170170 // Cleanup our global context object
171171 try {
172- // Builders/cleanupContext can trigger a transactional commit through Hibernate.
172+ // Builders/cleanupContext can trigger transactional commits through Hibernate.
173173 // Older Hibernate releases have a race in ResourceRegistryStandardImpl#releaseResources
174- // where the close() callback removes the just-iterated entry from the registry map,
175- // causing an intermittent ConcurrentModificationException (see HHH-15116).
176- // The DB cleanup work is best-effort here (test data is purged per-class anyway),
177- // so on CME we abort the context to release the JDBC connection and continue
178- // with the remaining (Solr/config) cleanup instead of failing an already-passed test.
179- try {
180- AbstractBuilder .cleanupObjects ();
181- parentCommunity = null ;
182- cleanupContext ();
183- } catch (ConcurrentModificationException cme ) {
184- log .warn ("Ignoring transient Hibernate CME during @After cleanup (HHH-15116); "
185- + "aborting context and continuing." , cme );
186- if (context != null && context .isValid ()) {
187- context .abort ();
174+ // which may raise an intermittent ConcurrentModificationException (HHH-15116).
175+ // Retry cleanup after aborting the context so we don't silently skip DB cleanup.
176+ final int maxCleanupAttempts = 3 ;
177+ boolean cleanupComplete = false ;
178+ for (int cleanupAttempt = 1 ; cleanupAttempt <= maxCleanupAttempts ; cleanupAttempt ++) {
179+ try {
180+ AbstractBuilder .cleanupObjects ();
181+ parentCommunity = null ;
182+ cleanupContext ();
183+ cleanupComplete = true ;
184+ break ;
185+ } catch (ConcurrentModificationException cme ) {
186+ log .warn ("Transient Hibernate CME during @After cleanup (HHH-15116), attempt {}/{}; "
187+ + "aborting context and retrying cleanup." , cleanupAttempt , maxCleanupAttempts , cme );
188+ if (context != null && context .isValid ()) {
189+ context .abort ();
190+ }
191+ context = null ;
192+ parentCommunity = null ;
193+
194+ if (cleanupAttempt < maxCleanupAttempts ) {
195+ context = new Context (Context .Mode .READ_WRITE );
196+ context .turnOffAuthorisationSystem ();
197+ }
188198 }
189- context = null ;
190- parentCommunity = null ;
199+ }
200+
201+ if (!cleanupComplete ) {
202+ throw new IllegalStateException ("Unable to complete @After DB cleanup after retries." );
191203 }
192204
193205 ServiceManager serviceManager = DSpaceServicesFactory .getInstance ().getServiceManager ();
0 commit comments