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:
@@ -121,8 +121,12 @@ public class UniqueStringIntegerPairs {
|
||||
public Integer computeIfAbsent(final String first, final Function<String, Integer> mappingFunction) {
|
||||
|
||||
if (!stringToInt.containsKey(first)) {
|
||||
final Integer second = mappingFunction.apply(first);
|
||||
put(first, second);
|
||||
synchronized (stringToInt) {
|
||||
if (!stringToInt.containsKey(first)) {
|
||||
final Integer second = mappingFunction.apply(first);
|
||||
put(first, second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringToInt.get(first);
|
||||
|
||||
@@ -3,6 +3,15 @@ package org.lucares.pdb.api;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
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.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