Replace List with Map in PersistentTasksInProgress

Store currently running persistent tasks in a map instead of a list.

Original commit: elastic/x-pack-elasticsearch@f383b0bbed
This commit is contained in:
Igor Motov 2017-02-03 15:20:44 -05:00
parent aa86d57487
commit a0b37a2510
11 changed files with 152 additions and 134 deletions

View File

@ -269,7 +269,7 @@ public class GetDatafeedsStatsAction extends Action<GetDatafeedsStatsAction.Requ
if (tasksInProgress != null) { if (tasksInProgress != null) {
Predicate<PersistentTaskInProgress<?>> predicate = ALL.equals(request.getDatafeedId()) ? p -> true : Predicate<PersistentTaskInProgress<?>> predicate = ALL.equals(request.getDatafeedId()) ? p -> true :
p -> request.getDatafeedId().equals(((StartDatafeedAction.Request) p.getRequest()).getDatafeedId()); p -> request.getDatafeedId().equals(((StartDatafeedAction.Request) p.getRequest()).getDatafeedId());
for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.findEntries(StartDatafeedAction.NAME, predicate)) { for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.findTasks(StartDatafeedAction.NAME, predicate)) {
StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) taskInProgress.getRequest(); StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) taskInProgress.getRequest();
states.put(storedRequest.getDatafeedId(), DatafeedState.STARTED); states.put(storedRequest.getDatafeedId(), DatafeedState.STARTED);
} }

View File

@ -251,7 +251,7 @@ public class StartDatafeedAction
Request storedRequest = (Request) taskInProgress.getRequest(); Request storedRequest = (Request) taskInProgress.getRequest();
return storedRequest.getDatafeedId().equals(request.getDatafeedId()); return storedRequest.getDatafeedId().equals(request.getDatafeedId());
}; };
if (persistentTasksInProgress.entriesExist(NAME, predicate)) { if (persistentTasksInProgress.tasksExist(NAME, predicate)) {
throw new ElasticsearchStatusException("datafeed already started, expected datafeed state [{}], but got [{}]", throw new ElasticsearchStatusException("datafeed already started, expected datafeed state [{}], but got [{}]",
RestStatus.CONFLICT, DatafeedState.STOPPED, DatafeedState.STARTED); RestStatus.CONFLICT, DatafeedState.STOPPED, DatafeedState.STARTED);
} }

View File

@ -148,7 +148,7 @@ public class StopDatafeedAction
PersistentTasksInProgress tasksInProgress = state.custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress tasksInProgress = state.custom(PersistentTasksInProgress.TYPE);
if (tasksInProgress != null) { if (tasksInProgress != null) {
for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.findEntries(StartDatafeedAction.NAME, p -> true)) { for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.findTasks(StartDatafeedAction.NAME, p -> true)) {
StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) taskInProgress.getRequest(); StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) taskInProgress.getRequest();
if (storedRequest.getDatafeedId().equals(datafeedId)) { if (storedRequest.getDatafeedId().equals(datafeedId)) {
RemovePersistentTaskAction.Request cancelTasksRequest = new RemovePersistentTaskAction.Request(); RemovePersistentTaskAction.Request cancelTasksRequest = new RemovePersistentTaskAction.Request();

View File

@ -327,7 +327,7 @@ public class MlMetadata implements MetaData.Custom {
StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) t.getRequest(); StartDatafeedAction.Request storedRequest = (StartDatafeedAction.Request) t.getRequest();
return storedRequest.getDatafeedId().equals(datafeedId); return storedRequest.getDatafeedId().equals(datafeedId);
}; };
if (persistentTasksInProgress.entriesExist(StartDatafeedAction.NAME, predicate)) { if (persistentTasksInProgress.tasksExist(StartDatafeedAction.NAME, predicate)) {
String msg = Messages.getMessage(Messages.DATAFEED_CANNOT_DELETE_IN_CURRENT_STATE, datafeedId, String msg = Messages.getMessage(Messages.DATAFEED_CANNOT_DELETE_IN_CURRENT_STATE, datafeedId,
DatafeedState.STARTED); DatafeedState.STARTED);
throw ExceptionsHelper.conflictStatusException(msg); throw ExceptionsHelper.conflictStatusException(msg);

View File

@ -69,7 +69,7 @@ public class PersistentActionCoordinator extends AbstractComponent implements Cl
String localNodeId = event.state().getNodes().getLocalNodeId(); String localNodeId = event.state().getNodes().getLocalNodeId();
Set<PersistentTaskId> notVisitedTasks = new HashSet<>(runningTasks.keySet()); Set<PersistentTaskId> notVisitedTasks = new HashSet<>(runningTasks.keySet());
if (tasks != null) { if (tasks != null) {
for (PersistentTaskInProgress<?> taskInProgress : tasks.entries()) { for (PersistentTaskInProgress<?> taskInProgress : tasks.tasks()) {
if (localNodeId.equals(taskInProgress.getExecutorNode())) { if (localNodeId.equals(taskInProgress.getExecutorNode())) {
PersistentTaskId persistentTaskId = new PersistentTaskId(taskInProgress.getId(), taskInProgress.getAllocationId()); PersistentTaskId persistentTaskId = new PersistentTaskId(taskInProgress.getId(), taskInProgress.getAllocationId());
RunningPersistentTask persistentTask = runningTasks.get(persistentTaskId); RunningPersistentTask persistentTask = runningTasks.get(persistentTaskId);

View File

@ -16,11 +16,12 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.xpack.persistent.PersistentTasksInProgress.PersistentTaskInProgress;
import org.elasticsearch.transport.TransportResponse.Empty; import org.elasticsearch.transport.TransportResponse.Empty;
import org.elasticsearch.xpack.persistent.PersistentTasksInProgress.PersistentTaskInProgress;
import java.util.ArrayList; import java.util.Collections;
import java.util.List; import java.util.HashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -55,17 +56,13 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
public ClusterState execute(ClusterState currentState) throws Exception { public ClusterState execute(ClusterState currentState) throws Exception {
final String executorNodeId = executorNode(action, currentState, request); final String executorNodeId = executorNode(action, currentState, request);
PersistentTasksInProgress tasksInProgress = currentState.custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress tasksInProgress = currentState.custom(PersistentTasksInProgress.TYPE);
final List<PersistentTaskInProgress<?>> currentTasks = new ArrayList<>(); long nextId;
final long nextId;
if (tasksInProgress != null) { if (tasksInProgress != null) {
nextId = tasksInProgress.getCurrentId() + 1; nextId = tasksInProgress.getCurrentId() + 1;
currentTasks.addAll(tasksInProgress.entries());
} else { } else {
nextId = 1; nextId = 1;
} }
currentTasks.add(new PersistentTaskInProgress<>(nextId, action, request, executorNodeId)); return createPersistentTask(currentState, new PersistentTaskInProgress<>(nextId, action, request, executorNodeId));
ClusterState.Builder builder = ClusterState.builder(currentState);
return builder.putCustom(PersistentTasksInProgress.TYPE, new PersistentTasksInProgress(nextId, currentTasks)).build();
} }
@Override @Override
@ -104,23 +101,18 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
// Nothing to do, the task was already deleted // Nothing to do, the task was already deleted
return currentState; return currentState;
} }
if (failure != null) {
boolean found = false; // If the task failed - we need to restart it on another node, otherwise we just remove it
final List<PersistentTaskInProgress<?>> currentTasks = new ArrayList<>(); PersistentTaskInProgress<?> taskInProgress = tasksInProgress.getTask(id);
for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.entries()) { if (taskInProgress != null) {
if (taskInProgress.getId() == id) { String executorNode = executorNode(taskInProgress.getAction(), currentState, taskInProgress.getRequest());
assert found == false; return updatePersistentTask(currentState, new PersistentTaskInProgress<>(taskInProgress, executorNode));
found = true;
if (failure != null) {
// If the task failed - we need to restart it on another node, otherwise we just remove it
String executorNode = executorNode(taskInProgress.getAction(), currentState, taskInProgress.getRequest());
currentTasks.add(new PersistentTaskInProgress<>(taskInProgress, executorNode));
}
} else {
currentTasks.add(taskInProgress);
} }
return currentState;
} else {
return removePersistentTask(currentState, id);
} }
return rebuildClusterStateIfNeeded(found, currentState, currentTasks);
} }
@Override @Override
@ -151,19 +143,11 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
// Nothing to do, the task no longer exists // Nothing to do, the task no longer exists
return currentState; return currentState;
} }
PersistentTaskInProgress<?> task = tasksInProgress.getTask(id);
boolean found = false; if (task != null) {
final List<PersistentTaskInProgress<?>> currentTasks = new ArrayList<>(); return updatePersistentTask(currentState, new PersistentTaskInProgress<>(task, status));
for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.entries()) {
if (taskInProgress.getId() == id) {
assert found == false;
found = true;
currentTasks.add(new PersistentTaskInProgress<>(taskInProgress, status));
} else {
currentTasks.add(taskInProgress);
}
} }
return rebuildClusterStateIfNeeded(found, currentState, currentTasks); return currentState;
} }
@Override @Override
@ -178,14 +162,40 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
}); });
} }
private ClusterState rebuildClusterStateIfNeeded(boolean rebuild, ClusterState oldState, private ClusterState updatePersistentTask(ClusterState oldState, PersistentTaskInProgress<?> newTask) {
List<PersistentTaskInProgress<?>> currentTasks) { PersistentTasksInProgress oldTasks = oldState.custom(PersistentTasksInProgress.TYPE);
if (rebuild) { Map<Long, PersistentTaskInProgress<?>> taskMap = new HashMap<>();
taskMap.putAll(oldTasks.taskMap());
taskMap.put(newTask.getId(), newTask);
ClusterState.Builder builder = ClusterState.builder(oldState);
PersistentTasksInProgress newTasks = new PersistentTasksInProgress(oldTasks.getCurrentId(), Collections.unmodifiableMap(taskMap));
return builder.putCustom(PersistentTasksInProgress.TYPE, newTasks).build();
}
private ClusterState createPersistentTask(ClusterState oldState, PersistentTaskInProgress<?> newTask) {
PersistentTasksInProgress oldTasks = oldState.custom(PersistentTasksInProgress.TYPE);
Map<Long, PersistentTaskInProgress<?>> taskMap = new HashMap<>();
if (oldTasks != null) {
taskMap.putAll(oldTasks.taskMap());
}
taskMap.put(newTask.getId(), newTask);
ClusterState.Builder builder = ClusterState.builder(oldState);
PersistentTasksInProgress newTasks = new PersistentTasksInProgress(newTask.getId(), Collections.unmodifiableMap(taskMap));
return builder.putCustom(PersistentTasksInProgress.TYPE, newTasks).build();
}
private ClusterState removePersistentTask(ClusterState oldState, long taskId) {
PersistentTasksInProgress oldTasks = oldState.custom(PersistentTasksInProgress.TYPE);
if (oldTasks != null) {
Map<Long, PersistentTaskInProgress<?>> taskMap = new HashMap<>();
ClusterState.Builder builder = ClusterState.builder(oldState); ClusterState.Builder builder = ClusterState.builder(oldState);
PersistentTasksInProgress oldTasks = oldState.custom(PersistentTasksInProgress.TYPE); taskMap.putAll(oldTasks.taskMap());
PersistentTasksInProgress tasks = new PersistentTasksInProgress(oldTasks.getCurrentId(), currentTasks); taskMap.remove(taskId);
return builder.putCustom(PersistentTasksInProgress.TYPE, tasks).build(); PersistentTasksInProgress newTasks =
new PersistentTasksInProgress(oldTasks.getCurrentId(), Collections.unmodifiableMap(taskMap));
return builder.putCustom(PersistentTasksInProgress.TYPE, newTasks).build();
} else { } else {
// no tasks - nothing to do
return oldState; return oldState;
} }
} }
@ -213,7 +223,7 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
// We need to check if removed nodes were running any of the tasks and reassign them // We need to check if removed nodes were running any of the tasks and reassign them
boolean reassignmentRequired = false; boolean reassignmentRequired = false;
Set<String> removedNodes = event.nodesDelta().removedNodes().stream().map(DiscoveryNode::getId).collect(Collectors.toSet()); Set<String> removedNodes = event.nodesDelta().removedNodes().stream().map(DiscoveryNode::getId).collect(Collectors.toSet());
for (PersistentTaskInProgress<?> taskInProgress : tasks.entries()) { for (PersistentTaskInProgress<?> taskInProgress : tasks.tasks()) {
if (taskInProgress.getExecutorNode() == null) { if (taskInProgress.getExecutorNode() == null) {
// there is an unassigned task - we need to try assigning it // there is an unassigned task - we need to try assigning it
reassignmentRequired = true; reassignmentRequired = true;
@ -244,22 +254,12 @@ public class PersistentTaskClusterService extends AbstractComponent implements C
DiscoveryNodes nodes = currentState.nodes(); DiscoveryNodes nodes = currentState.nodes();
if (tasks != null) { if (tasks != null) {
// We need to check if removed nodes were running any of the tasks and reassign them // We need to check if removed nodes were running any of the tasks and reassign them
for (PersistentTaskInProgress<?> task : tasks.entries()) { for (PersistentTaskInProgress<?> task : tasks.tasks()) {
if (task.getExecutorNode() == null || nodes.nodeExists(task.getExecutorNode()) == false) { if (task.getExecutorNode() == null || nodes.nodeExists(task.getExecutorNode()) == false) {
// there is an unassigned task - we need to try assigning it // there is an unassigned task - we need to try assigning it
String executorNode = executorNode(task.getAction(), currentState, task.getRequest()); String executorNode = executorNode(task.getAction(), currentState, task.getRequest());
if (Objects.equals(executorNode, task.getExecutorNode()) == false) { if (Objects.equals(executorNode, task.getExecutorNode()) == false) {
PersistentTasksInProgress tasksInProgress = newClusterState.custom(PersistentTasksInProgress.TYPE); newClusterState = updatePersistentTask(newClusterState, new PersistentTaskInProgress<>(task, executorNode));
final List<PersistentTaskInProgress<?>> currentTasks = new ArrayList<>();
for (PersistentTaskInProgress<?> taskInProgress : tasksInProgress.entries()) {
if (task.getId() == taskInProgress.getId()) {
currentTasks.add(new PersistentTaskInProgress<>(task, executorNode));
} else {
currentTasks.add(taskInProgress);
}
}
newClusterState = ClusterState.builder(newClusterState).putCustom(PersistentTasksInProgress.TYPE,
new PersistentTasksInProgress(tasksInProgress.getCurrentId(), currentTasks)).build();
} }
} }
} }

View File

@ -20,7 +20,7 @@ import org.elasticsearch.tasks.Task.Status;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -31,29 +31,37 @@ import java.util.stream.Collectors;
public final class PersistentTasksInProgress extends AbstractNamedDiffable<ClusterState.Custom> implements ClusterState.Custom { public final class PersistentTasksInProgress extends AbstractNamedDiffable<ClusterState.Custom> implements ClusterState.Custom {
public static final String TYPE = "persistent_tasks"; public static final String TYPE = "persistent_tasks";
// TODO: Implement custom Diff for entries // TODO: Implement custom Diff for tasks
private final List<PersistentTaskInProgress<?>> entries; private final Map<Long, PersistentTaskInProgress<?>> tasks;
private final long currentId; private final long currentId;
public PersistentTasksInProgress(long currentId, List<PersistentTaskInProgress<?>> entries) { public PersistentTasksInProgress(long currentId, Map<Long, PersistentTaskInProgress<?>> tasks) {
this.currentId = currentId; this.currentId = currentId;
this.entries = entries; this.tasks = tasks;
} }
public List<PersistentTaskInProgress<?>> entries() { public Collection<PersistentTaskInProgress<?>> tasks() {
return this.entries; return this.tasks.values();
} }
public Collection<PersistentTaskInProgress<?>> findEntries(String actionName, Predicate<PersistentTaskInProgress<?>> predicate) { public Map<Long, PersistentTaskInProgress<?>> taskMap() {
return this.entries().stream() return this.tasks;
}
public PersistentTaskInProgress<?> getTask(long id) {
return this.tasks.get(id);
}
public Collection<PersistentTaskInProgress<?>> findTasks(String actionName, Predicate<PersistentTaskInProgress<?>> predicate) {
return this.tasks().stream()
.filter(p -> actionName.equals(p.getAction())) .filter(p -> actionName.equals(p.getAction()))
.filter(predicate) .filter(predicate)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public boolean entriesExist(String actionName, Predicate<PersistentTaskInProgress<?>> predicate) { public boolean tasksExist(String actionName, Predicate<PersistentTaskInProgress<?>> predicate) {
return this.entries().stream() return this.tasks().stream()
.filter(p -> actionName.equals(p.getAction())) .filter(p -> actionName.equals(p.getAction()))
.anyMatch(predicate); .anyMatch(predicate);
} }
@ -64,16 +72,16 @@ public final class PersistentTasksInProgress extends AbstractNamedDiffable<Clust
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
PersistentTasksInProgress that = (PersistentTasksInProgress) o; PersistentTasksInProgress that = (PersistentTasksInProgress) o;
return currentId == that.currentId && return currentId == that.currentId &&
Objects.equals(entries, that.entries); Objects.equals(tasks, that.tasks);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(entries, currentId); return Objects.hash(tasks, currentId);
} }
public long getNumberOfTasksOnNode(String nodeId, String action) { public long getNumberOfTasksOnNode(String nodeId, String action) {
return entries.stream().filter(task -> action.equals(task.action) && nodeId.equals(task.executorNode)).count(); return tasks.values().stream().filter(task -> action.equals(task.action) && nodeId.equals(task.executorNode)).count();
} }
@Override @Override
@ -84,7 +92,7 @@ public final class PersistentTasksInProgress extends AbstractNamedDiffable<Clust
/** /**
* A record that represents a single running persistent task * A record that represents a single running persistent task
*/ */
public static class PersistentTaskInProgress<Request extends PersistentActionRequest> implements Writeable { public static class PersistentTaskInProgress<Request extends PersistentActionRequest> implements Writeable, ToXContent {
private final long id; private final long id;
private final long allocationId; private final long allocationId;
private final String action; private final String action;
@ -183,6 +191,28 @@ public final class PersistentTasksInProgress extends AbstractNamedDiffable<Clust
public Status getStatus() { public Status getStatus() {
return status; return status;
} }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
{
builder.field("uuid", id);
builder.field("action", action);
builder.field("request");
request.toXContent(builder, params);
if (status != null) {
builder.field("status", status, params);
}
builder.field("executor_node", executorNode);
}
builder.endObject();
return builder;
}
@Override
public boolean isFragment() {
return false;
}
} }
@Override @Override
@ -192,13 +222,15 @@ public final class PersistentTasksInProgress extends AbstractNamedDiffable<Clust
public PersistentTasksInProgress(StreamInput in) throws IOException { public PersistentTasksInProgress(StreamInput in) throws IOException {
currentId = in.readLong(); currentId = in.readLong();
entries = in.readList(PersistentTaskInProgress::new); tasks = in.readMap(StreamInput::readLong, PersistentTaskInProgress::new);
} }
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeLong(currentId); out.writeLong(currentId);
out.writeList(entries); out.writeMap(tasks, StreamOutput::writeLong, (stream, value) -> {
value.writeTo(stream);
});
} }
public static NamedDiff<ClusterState.Custom> readDiffFrom(StreamInput in) throws IOException { public static NamedDiff<ClusterState.Custom> readDiffFrom(StreamInput in) throws IOException {
@ -214,25 +246,11 @@ public final class PersistentTasksInProgress extends AbstractNamedDiffable<Clust
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.field("current_id", currentId); builder.field("current_id", currentId);
builder.startArray("running_tasks"); builder.startArray("running_tasks");
for (PersistentTaskInProgress<?> entry : entries) { for (PersistentTaskInProgress<?> entry : tasks.values()) {
toXContent(entry, builder, params); entry.toXContent(builder, params);
} }
builder.endArray(); builder.endArray();
return builder; return builder;
} }
public void toXContent(PersistentTaskInProgress<?> entry, XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.startObject();
{
builder.field("uuid", entry.id);
builder.field("action", entry.action);
builder.field("request");
entry.request.toXContent(builder, params);
if (entry.status != null) {
builder.field("status", entry.status, params);
}
builder.field("executor_node", entry.executorNode);
}
builder.endObject();
}
} }

View File

@ -196,7 +196,7 @@ public class MlMetadataTests extends AbstractSerializingTestCase<MlMetadata> {
assertThat(result.getDatafeeds().get("datafeed1"), sameInstance(datafeedConfig1)); assertThat(result.getDatafeeds().get("datafeed1"), sameInstance(datafeedConfig1));
builder = new MlMetadata.Builder(result); builder = new MlMetadata.Builder(result);
builder.removeDatafeed("datafeed1", new PersistentTasksInProgress(0, Collections.emptyList())); builder.removeDatafeed("datafeed1", new PersistentTasksInProgress(0, Collections.emptyMap()));
result = builder.build(); result = builder.build();
assertThat(result.getJobs().get("foo"), sameInstance(job1)); assertThat(result.getJobs().get("foo"), sameInstance(job1));
assertThat(result.getAllocations().get("foo").getState(), equalTo(JobState.CLOSED)); assertThat(result.getAllocations().get("foo").getState(), equalTo(JobState.CLOSED));
@ -262,7 +262,8 @@ public class MlMetadataTests extends AbstractSerializingTestCase<MlMetadata> {
StartDatafeedAction.Request request = new StartDatafeedAction.Request("datafeed1", 0L); StartDatafeedAction.Request request = new StartDatafeedAction.Request("datafeed1", 0L);
PersistentTasksInProgress.PersistentTaskInProgress<StartDatafeedAction.Request> taskInProgress = PersistentTasksInProgress.PersistentTaskInProgress<StartDatafeedAction.Request> taskInProgress =
new PersistentTasksInProgress.PersistentTaskInProgress<>(0, StartDatafeedAction.NAME, request, null); new PersistentTasksInProgress.PersistentTaskInProgress<>(0, StartDatafeedAction.NAME, request, null);
PersistentTasksInProgress tasksInProgress = new PersistentTasksInProgress(1, Collections.singletonList(taskInProgress)); PersistentTasksInProgress tasksInProgress =
new PersistentTasksInProgress(1, Collections.singletonMap(taskInProgress.getId(), taskInProgress));
MlMetadata.Builder builder2 = new MlMetadata.Builder(result); MlMetadata.Builder builder2 = new MlMetadata.Builder(result);
ElasticsearchStatusException e = expectThrows(ElasticsearchStatusException.class, ElasticsearchStatusException e = expectThrows(ElasticsearchStatusException.class,

View File

@ -27,7 +27,9 @@ import org.elasticsearch.transport.TransportResponse.Empty;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -71,17 +73,17 @@ public class PersistentActionCoordinatorTests extends ESTestCase {
ClusterState state = ClusterState.builder(clusterService.state()).nodes(createTestNodes(nonLocalNodesCount, Settings.EMPTY)) ClusterState state = ClusterState.builder(clusterService.state()).nodes(createTestNodes(nonLocalNodesCount, Settings.EMPTY))
.build(); .build();
List<PersistentTaskInProgress<?>> tasks = new ArrayList<>(); Map<Long, PersistentTaskInProgress<?>> tasks = new HashMap<>();
long taskId = randomLong(); long taskId = randomLong();
boolean added = false; boolean added = false;
if (nonLocalNodesCount > 0) { if (nonLocalNodesCount > 0) {
for (int i = 0; i < randomInt(5); i++) { for (int i = 0; i < randomInt(5); i++) {
tasks.add(new PersistentTaskInProgress<>(taskId, "test_action", new TestRequest("other_" + i), tasks.put(taskId, new PersistentTaskInProgress<>(taskId, "test_action", new TestRequest("other_" + i),
"other_node_" + randomInt(nonLocalNodesCount))); "other_node_" + randomInt(nonLocalNodesCount)));
taskId++; taskId++;
if (added == false && randomBoolean()) { if (added == false && randomBoolean()) {
added = true; added = true;
tasks.add(new PersistentTaskInProgress<>(taskId, "test", new TestRequest("this_param"), "this_node")); tasks.put(taskId, new PersistentTaskInProgress<>(taskId, "test", new TestRequest("this_param"), "this_node"));
taskId++; taskId++;
} }
} }
@ -288,38 +290,33 @@ public class PersistentActionCoordinatorTests extends ESTestCase {
private <Request extends PersistentActionRequest> ClusterState addTask(ClusterState state, String action, Request request, private <Request extends PersistentActionRequest> ClusterState addTask(ClusterState state, String action, Request request,
String node) { String node) {
PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE);
List<PersistentTaskInProgress<?>> tasks = prevTasks == null ? new ArrayList<>() : new ArrayList<>(prevTasks.entries()); Map<Long, PersistentTaskInProgress<?>> tasks = prevTasks == null ? new HashMap<>() : new HashMap<>(prevTasks.taskMap());
tasks.add(new PersistentTaskInProgress<>(prevTasks == null ? 0 : prevTasks.getCurrentId(), action, request, node)); long id = prevTasks == null ? 0 : prevTasks.getCurrentId();
tasks.put(id, new PersistentTaskInProgress<>(id, action, request, node));
return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE, return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE,
new PersistentTasksInProgress(prevTasks == null ? 1 : prevTasks.getCurrentId() + 1, tasks)).build(); new PersistentTasksInProgress(prevTasks == null ? 1 : prevTasks.getCurrentId() + 1, tasks)).build();
} }
private ClusterState reallocateTask(ClusterState state, long taskId, String node) { private ClusterState reallocateTask(ClusterState state, long taskId, String node) {
PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE);
List<PersistentTaskInProgress<?>> tasks = prevTasks == null ? new ArrayList<>() : new ArrayList<>(prevTasks.entries()); assertNotNull(prevTasks);
for (int i = 0; i < tasks.size(); i++) { Map<Long, PersistentTaskInProgress<?>> tasks = new HashMap<>(prevTasks.taskMap());
if (tasks.get(i).getId() == taskId) { PersistentTaskInProgress<?> prevTask = tasks.get(taskId);
tasks.set(i, new PersistentTaskInProgress<>(tasks.get(i), node)); assertNotNull(prevTask);
return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE, tasks.put(prevTask.getId(), new PersistentTaskInProgress<>(prevTask, node));
new PersistentTasksInProgress(prevTasks == null ? 1 : prevTasks.getCurrentId() + 1, tasks)).build(); return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE,
} new PersistentTasksInProgress(prevTasks.getCurrentId(), tasks)).build();
}
fail("didn't find task with id " + taskId);
return null;
} }
private ClusterState removeTask(ClusterState state, long taskId) { private ClusterState removeTask(ClusterState state, long taskId) {
PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress prevTasks = state.custom(PersistentTasksInProgress.TYPE);
List<PersistentTaskInProgress<?>> tasks = prevTasks == null ? new ArrayList<>() : new ArrayList<>(prevTasks.entries()); assertNotNull(prevTasks);
for (int i = 0; i < tasks.size(); i++) { Map<Long, PersistentTaskInProgress<?>> tasks = new HashMap<>(prevTasks.taskMap());
if (tasks.get(i).getId() == taskId) { PersistentTaskInProgress<?> prevTask = tasks.get(taskId);
tasks.remove(i); assertNotNull(prevTask);
return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE, tasks.remove(prevTask.getId());
new PersistentTasksInProgress(prevTasks == null ? 1 : prevTasks.getCurrentId() + 1, tasks)).build(); return ClusterState.builder(state).putCustom(PersistentTasksInProgress.TYPE,
} new PersistentTasksInProgress(prevTasks.getCurrentId(), tasks)).build();
}
fail("didn't find task with id " + taskId);
return null;
} }
private class Execution { private class Execution {

View File

@ -11,6 +11,7 @@ import org.elasticsearch.tasks.TaskInfo;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestPersistentAction; import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestPersistentAction;
import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestTasksRequestBuilder; import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestTasksRequestBuilder;
import org.junit.After;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -52,6 +53,11 @@ public class PersistentActionIT extends ESIntegTestCase {
.build(); .build();
} }
@After
public void cleanup() throws Exception {
assertNoRunningTasks();
}
public void testPersistentActionRestart() throws Exception { public void testPersistentActionRestart() throws Exception {
long taskId = TestPersistentAction.INSTANCE.newRequestBuilder(client()).testParam("Blah").get().getTaskId(); long taskId = TestPersistentAction.INSTANCE.newRequestBuilder(client()).testParam("Blah").get().getTaskId();
assertBusy(() -> { assertBusy(() -> {
@ -119,8 +125,6 @@ public class PersistentActionIT extends ESIntegTestCase {
.get().getTasks().size(), equalTo(1)); .get().getTasks().size(), equalTo(1));
} }
assertNoRunningTasks();
} }
public void testPersistentActionWithNoAvailableNode() throws Exception { public void testPersistentActionWithNoAvailableNode() throws Exception {
@ -165,8 +169,8 @@ public class PersistentActionIT extends ESIntegTestCase {
.get().getTasks().get(0); .get().getTasks().get(0);
PersistentTasksInProgress tasksInProgress = internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress tasksInProgress = internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE);
assertThat(tasksInProgress.entries().size(), equalTo(1)); assertThat(tasksInProgress.tasks().size(), equalTo(1));
assertThat(tasksInProgress.entries().get(0).getStatus(), nullValue()); assertThat(tasksInProgress.tasks().iterator().next().getStatus(), nullValue());
int numberOfUpdates = randomIntBetween(1, 10); int numberOfUpdates = randomIntBetween(1, 10);
for (int i = 0; i < numberOfUpdates; i++) { for (int i = 0; i < numberOfUpdates; i++) {
@ -178,9 +182,9 @@ public class PersistentActionIT extends ESIntegTestCase {
int finalI = i; int finalI = i;
assertBusy(() -> { assertBusy(() -> {
PersistentTasksInProgress tasks = internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE); PersistentTasksInProgress tasks = internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE);
assertThat(tasks.entries().size(), equalTo(1)); assertThat(tasks.tasks().size(), equalTo(1));
assertThat(tasks.entries().get(0).getStatus(), notNullValue()); assertThat(tasks.tasks().iterator().next().getStatus(), notNullValue());
assertThat(tasks.entries().get(0).getStatus().toString(), equalTo("{\"phase\":\"phase " + (finalI + 1) + "\"}")); assertThat(tasks.tasks().iterator().next().getStatus().toString(), equalTo("{\"phase\":\"phase " + (finalI + 1) + "\"}"));
}); });
} }
@ -189,8 +193,6 @@ public class PersistentActionIT extends ESIntegTestCase {
// Complete the running task and make sure it finishes properly // Complete the running task and make sure it finishes properly
assertThat(new TestTasksRequestBuilder(client()).setOperation("finish").setTaskId(firstRunningTask.getTaskId()) assertThat(new TestTasksRequestBuilder(client()).setOperation("finish").setTaskId(firstRunningTask.getTaskId())
.get().getTasks().size(), equalTo(1)); .get().getTasks().size(), equalTo(1));
assertNoRunningTasks();
} }
private void assertNoRunningTasks() throws Exception { private void assertNoRunningTasks() throws Exception {
@ -203,7 +205,7 @@ public class PersistentActionIT extends ESIntegTestCase {
// Make sure the task is removed from the cluster state // Make sure the task is removed from the cluster state
assertThat(((PersistentTasksInProgress) internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE)) assertThat(((PersistentTasksInProgress) internalCluster().clusterService().state().custom(PersistentTasksInProgress.TYPE))
.entries(), empty()); .tasks(), empty());
}); });
} }

View File

@ -14,16 +14,16 @@ import org.elasticsearch.xpack.persistent.PersistentTasksInProgress.PersistentTa
import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.Status; import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.Status;
import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestPersistentAction; import org.elasticsearch.xpack.persistent.TestPersistentActionPlugin.TestPersistentAction;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.HashMap;
import java.util.Map;
public class PersistentTasksInProgressTests extends AbstractWireSerializingTestCase<PersistentTasksInProgress> { public class PersistentTasksInProgressTests extends AbstractWireSerializingTestCase<PersistentTasksInProgress> {
@Override @Override
protected PersistentTasksInProgress createTestInstance() { protected PersistentTasksInProgress createTestInstance() {
int numberOfTasks = randomInt(10); int numberOfTasks = randomInt(10);
List<PersistentTaskInProgress<?>> entries = new ArrayList<>(); Map<Long, PersistentTaskInProgress<?>> entries = new HashMap<>();
for (int i = 0; i < numberOfTasks; i++) { for (int i = 0; i < numberOfTasks; i++) {
PersistentTaskInProgress<?> taskInProgress = new PersistentTaskInProgress<>( PersistentTaskInProgress<?> taskInProgress = new PersistentTaskInProgress<>(
randomLong(), randomAsciiOfLength(10), new TestPersistentActionPlugin.TestRequest(randomAsciiOfLength(10)), randomLong(), randomAsciiOfLength(10), new TestPersistentActionPlugin.TestRequest(randomAsciiOfLength(10)),
@ -32,7 +32,7 @@ public class PersistentTasksInProgressTests extends AbstractWireSerializingTestC
// From time to time update status // From time to time update status
taskInProgress = new PersistentTaskInProgress<>(taskInProgress, new Status(randomAsciiOfLength(10))); taskInProgress = new PersistentTaskInProgress<>(taskInProgress, new Status(randomAsciiOfLength(10)));
} }
entries.add(taskInProgress); entries.put(taskInProgress.getId(), taskInProgress);
} }
return new PersistentTasksInProgress(randomLong(), entries); return new PersistentTasksInProgress(randomLong(), entries);
} }