different tags could be written to the same file
There was a missing synchronization in the code that maps Strings to Integers.
This commit is contained in:
1
pdb-api/.gitignore
vendored
1
pdb-api/.gitignore
vendored
@@ -3,3 +3,4 @@
|
|||||||
/.settings/
|
/.settings/
|
||||||
/.classpath
|
/.classpath
|
||||||
/.project
|
/.project
|
||||||
|
/test-output/
|
||||||
|
|||||||
@@ -121,8 +121,12 @@ public class UniqueStringIntegerPairs {
|
|||||||
public Integer computeIfAbsent(final String first, final Function<String, Integer> mappingFunction) {
|
public Integer computeIfAbsent(final String first, final Function<String, Integer> mappingFunction) {
|
||||||
|
|
||||||
if (!stringToInt.containsKey(first)) {
|
if (!stringToInt.containsKey(first)) {
|
||||||
final Integer second = mappingFunction.apply(first);
|
synchronized (stringToInt) {
|
||||||
put(first, second);
|
if (!stringToInt.containsKey(first)) {
|
||||||
|
final Integer second = mappingFunction.apply(first);
|
||||||
|
put(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringToInt.get(first);
|
return stringToInt.get(first);
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ package org.lucares.pdb.api;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.lucares.utils.file.FileUtils;
|
import org.lucares.utils.file.FileUtils;
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
@@ -49,4 +58,49 @@ public class StringCompressorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class StringInserter implements Callable<List<String>> {
|
||||||
|
|
||||||
|
private final StringCompressor stringCompressor;
|
||||||
|
private final int numEntries;
|
||||||
|
|
||||||
|
public StringInserter(final StringCompressor stringCompressor, final int numEntries) {
|
||||||
|
this.stringCompressor = stringCompressor;
|
||||||
|
this.numEntries = numEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> call() throws Exception {
|
||||||
|
|
||||||
|
final List<String> result = new ArrayList<>();
|
||||||
|
for (int i = 0; i < numEntries; i++) {
|
||||||
|
final String s = UUID.randomUUID().toString();
|
||||||
|
stringCompressor.put(s);
|
||||||
|
result.add(s);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test(invocationCount = 1)
|
||||||
|
public void testPutConcurrently() throws InterruptedException, ExecutionException {
|
||||||
|
final UniqueStringIntegerPairs usip = new UniqueStringIntegerPairs();
|
||||||
|
final StringCompressor stringCompressor = new StringCompressor(usip);
|
||||||
|
|
||||||
|
final ExecutorService pool = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
|
final int numEntries = 1000;
|
||||||
|
final Future<List<String>> future1 = pool.submit(new StringInserter(stringCompressor, numEntries));
|
||||||
|
final Future<List<String>> future2 = pool.submit(new StringInserter(stringCompressor, numEntries));
|
||||||
|
final Future<List<String>> future3 = pool.submit(new StringInserter(stringCompressor, numEntries));
|
||||||
|
|
||||||
|
future1.get();
|
||||||
|
future2.get();
|
||||||
|
future3.get();
|
||||||
|
|
||||||
|
pool.shutdown();
|
||||||
|
pool.awaitTermination(1, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
Assert.assertEquals((int) usip.getHighestInteger(), 3 * numEntries - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user