This is an automated email from the ASF dual-hosted git repository.
ctubbsii pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo-classloaders.git
The following commit(s) were added to refs/heads/main by this push:
new a83e25a tests concurrent deletes of files in resources dir (#65)
a83e25a is described below
commit a83e25a3c15c9a39fea2e10c8216c2f2a6b99225
Author: Keith Turner <[email protected]>
AuthorDate: Thu Feb 5 14:51:38 2026 -0500
tests concurrent deletes of files in resources dir (#65)
---
.../LocalCachingContextClassLoaderFactoryTest.java | 86 +++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)
diff --git
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
index 1c6515a..7d68d3b 100644
---
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
+++
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
@@ -29,6 +29,7 @@ import static
org.apache.accumulo.classloader.lcc.TestUtils.updateContextDefinit
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -47,6 +48,10 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
@@ -57,6 +62,7 @@ import org.apache.accumulo.classloader.lcc.util.LocalStore;
import org.apache.accumulo.core.conf.ConfigurationCopy;
import
org.apache.accumulo.core.spi.common.ContextClassLoaderFactory.ContextClassLoaderException;
import org.apache.accumulo.core.util.ConfigurationImpl;
+import org.apache.accumulo.core.util.Timer;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.eclipse.jetty.server.Server;
@@ -64,7 +70,10 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDir;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
@@ -73,6 +82,8 @@ public class LocalCachingContextClassLoaderFactoryTest {
protected static final int MONITOR_INTERVAL_SECS = 5;
// MD5 sum for "bad"
private static final String BAD_MD5 = "bae60998ffe4923b131e3d6e4c19993e";
+ private static final Logger log =
+ LoggerFactory.getLogger(LocalCachingContextClassLoaderFactoryTest.class);
private static MiniDFSCluster hdfs;
private static FileSystem fs;
private static Server jetty;
@@ -92,7 +103,7 @@ public class LocalCachingContextClassLoaderFactoryTest {
private LocalCachingContextClassLoaderFactory FACTORY;
private Path baseCacheDir;
- @TempDir
+ @TempDir(cleanup = CleanupMode.ON_SUCCESS)
private Path tempDir;
@BeforeAll
@@ -826,4 +837,77 @@ public class LocalCachingContextClassLoaderFactoryTest {
// ensure it works now
FACTORY.getClassLoader(updatedDefUrl2.toString());
}
+
+ @Test
+ public void testConcurrentDeletes() throws Exception {
+
+ var executor = Executors.newCachedThreadPool();
+
+ AtomicBoolean stop = new AtomicBoolean(false);
+
+ // create a background task that continually concurrently deletes files in
the resources dir
+ var deleteFuture = executor.submit(() -> {
+ while (!stop.get()) {
+ var resourcesDir =
tempDir.resolve("base").resolve("resources").toFile();
+ assertTrue(resourcesDir.exists() && resourcesDir.isDirectory());
+ var files = resourcesDir.listFiles();
+ for (var file : files) {
+ assertTrue(file.delete());
+ }
+ Thread.sleep(100);
+ }
+ return null;
+ });
+
+ var def = ContextDefinition.create(100, "SHA-512", jarAOrigLocation,
jarBOrigLocation,
+ jarCOrigLocation, jarDOrigLocation);
+
+ List<Future<?>> futures = new ArrayList<>();
+
+ // create 10 threads that are continually creating new classloaders, the
deletes should cause
+ // hard link creations to fail sometimes
+ for (int i = 0; i < 10; i++) {
+ int threadNum = i;
+ var future = executor.submit(() -> {
+ Timer timer = Timer.startNew();
+ int j = 0;
+ ClassLoader lastCl = null;
+ while (!timer.hasElapsed(10, TimeUnit.SECONDS)) {
+ var contextFile = tempDir.resolve("context-cd-" + threadNum + "_" +
j + ".json");
+ Files.writeString(contextFile, def.toJson());
+ var contextUrl = contextFile.toUri().toURL().toExternalForm();
+
+ final ClassLoader cl = FACTORY.getClassLoader(contextUrl);
+ // This test is assuming that each call above creates a new
classloader which in turn
+ // creates new hard links. This is checking that assumption in case
the impl changes and
+ // this test needs to be reevaluated.
+ assertNotSame(cl, lastCl);
+ lastCl = cl;
+ testClassLoads(cl, classA);
+ testClassLoads(cl, classB);
+ testClassLoads(cl, classC);
+ testClassLoads(cl, classD);
+ j++;
+ }
+
+ return null;
+ });
+ futures.add(future);
+ }
+
+ for (var future : futures) {
+ future.get();
+ }
+
+ stop.set(true);
+ // ensure the delete task had no errors
+ deleteFuture.get();
+ executor.shutdown();
+
+ var workingDir = tempDir.resolve("base").resolve("working").toFile();
+ var filesList = workingDir.listFiles();
+ var workingDirs = filesList == null ? 0 : filesList.length;
+ // check that many hard link directories were created
+ assertTrue(workingDirs > 50, () -> "workingDirs:" + workingDirs);
+ }
}