Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,33 @@
import org.elasticsearch.plugins.PluginInfo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class PluginsInfo implements Streamable, ToXContent {
static final class Fields {
static final XContentBuilderString PLUGINS = new XContentBuilderString("plugins");
}

private List<PluginInfo> infos;
private Set<PluginInfo> infos;

public PluginsInfo() {
infos = new ArrayList<>();
}

public PluginsInfo(int size) {
infos = new ArrayList<>(size);
}

/**
* @return an ordered list based on plugins name
*/
public List<PluginInfo> getInfos() {
Collections.sort(infos, new Comparator<PluginInfo>() {
infos = new TreeSet<>(new Comparator<PluginInfo>() {
@Override
public int compare(final PluginInfo o1, final PluginInfo o2) {
return o1.getName().compareTo(o2.getName());
}
});
}

return infos;
/**
* @return an ordered list based on plugins name
*/
public List<PluginInfo> getInfos() {
return Arrays.asList(infos.toArray(new PluginInfo[infos.size()]));
}

public void add(PluginInfo info) {
Expand All @@ -75,6 +70,7 @@ public static PluginsInfo readPluginsInfo(StreamInput in) throws IOException {
@Override
public void readFrom(StreamInput in) throws IOException {
int plugins_size = in.readInt();
infos.clear();
for (int i = 0; i < plugins_size; i++) {
infos.add(PluginInfo.readFromStream(in));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.elasticsearch.common.util.CollectionUtils.eagerTransform;
import static org.hamcrest.Matchers.contains;
Expand Down Expand Up @@ -273,7 +277,7 @@ public void testReadFromPropertiesSitePluginWithoutSite() throws Exception {
}

public void testPluginListSorted() {
PluginsInfo pluginsInfo = new PluginsInfo(5);
PluginsInfo pluginsInfo = new PluginsInfo();
pluginsInfo.add(new PluginInfo("c", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.add(new PluginInfo("b", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.add(new PluginInfo("e", "foo", true, "dummy", true, "dummyclass", true));
Expand All @@ -289,4 +293,42 @@ public String apply(PluginInfo input) {
});
assertThat(names, contains("a", "b", "c", "d", "e"));
}

public void testConcurrentModificationsAreAvoided() throws InterruptedException {
final PluginsInfo pluginsInfo = new PluginsInfo();
int numberOfPlugins = randomIntBetween(128, 256);
for (int i = 0; i < numberOfPlugins; i++) {
pluginsInfo.add(new PluginInfo("name", "description", false, "version", true, "classname", true));
}

int randomNumberOfThreads = randomIntBetween(2, 8);
final int numberOfAttempts = randomIntBetween(2048, 4096);
final CountDownLatch latch = new CountDownLatch(1 + randomNumberOfThreads);
List<Thread> threads = new ArrayList<>(randomNumberOfThreads);
final AtomicBoolean cme = new AtomicBoolean();
for (int i = 0; i < randomNumberOfThreads; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
latch.countDown();
for (int j = 0; j < numberOfAttempts; j++) {
try {
pluginsInfo.getInfos();
} catch (ConcurrentModificationException e) {
cme.set(true);
}
}
}
});
threads.add(thread);
thread.start();
}

latch.countDown();
for (Thread thread : threads) {
thread.join();
}

assertFalse(cme.get());
}
}