You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2020/07/16 15:43:09 UTC
[lucene-solr] 01/01: SOLR-14613: Initial POC based on Ilan's
proposal.
This is an automated email from the ASF dual-hosted git repository.
ab pushed a commit to branch jira/solr-14613
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
commit 5f6887de5d5977cb8629ff28147b485291b12a05
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Thu Jul 16 17:42:27 2020 +0200
SOLR-14613: Initial POC based on Ilan's proposal.
---
.../api/collections/assign/AddReplicaDecision.java | 34 +++++
.../api/collections/assign/AddReplicaRequest.java | 72 ++++++++++
.../api/collections/assign/AssignDecision.java | 26 ++++
.../api/collections/assign/AssignDecisions.java | 41 ++++++
.../api/collections/assign/AssignRequest.java | 27 ++++
.../cloud/api/collections/assign/Assigner.java | 30 ++++
.../collections/assign/AssignerClusterState.java | 44 ++++++
.../assign/AssignerCollectionState.java | 34 +++++
.../api/collections/assign/AssignerException.java | 18 +++
.../api/collections/assign/AssignerNodeState.java | 34 +++++
.../api/collections/assign/AssignerReplica.java | 86 +++++++++++
.../api/collections/assign/AssignerShardState.java | 31 ++++
.../api/collections/assign/BaseAssignDecision.java | 18 +++
.../api/collections/assign/BaseAssignRequest.java | 45 ++++++
.../collections/assign/DeleteReplicaDecision.java | 26 ++++
.../collections/assign/DeleteReplicaRequest.java | 33 +++++
.../collections/assign/MoveReplicaDecision.java | 36 +++++
.../api/collections/assign/MoveReplicaRequest.java | 28 ++++
.../cloud/api/collections/assign/NoopDecision.java | 21 +++
.../assign/policy8x/AssignerCloudManager.java | 81 +++++++++++
.../policy8x/AssignerClusterStateProvider.java | 102 +++++++++++++
.../policy8x/AssignerDistribStateManager.java | 99 +++++++++++++
.../assign/policy8x/AssignerNodeStateProvider.java | 56 ++++++++
.../assign/policy8x/Policy8xAssigner.java | 61 ++++++++
.../SolrCloudManagerAssignerClusterState.java | 159 +++++++++++++++++++++
.../collections/assign/policy8x/TestPolicy8x.java | 44 ++++++
26 files changed, 1286 insertions(+)
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaDecision.java
new file mode 100644
index 0000000..a5e29e2
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaDecision.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public class AddReplicaDecision extends BaseAssignDecision {
+ private final String targetNode;
+
+ public AddReplicaDecision(AssignRequest request, String targetNode) {
+ super(request);
+ this.targetNode = targetNode;
+ }
+
+ public String getTargetNode() {
+ return targetNode;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaRequest.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaRequest.java
new file mode 100644
index 0000000..c4d9b38
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AddReplicaRequest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.solr.common.cloud.Replica;
+
+/**
+ *
+ */
+public class AddReplicaRequest extends BaseAssignRequest {
+ private final Replica.Type type;
+ private final Map<String, Object> params = new HashMap<>();
+ private final String targetNode;
+ private final String coreName;
+ private final Set<String> nodeSet;
+
+ public AddReplicaRequest(String collection, String shard, Replica.Type type, Map<String, Object> params,
+ String targetNode, String coreName, Set<String> nodeSet) {
+ super(collection, shard);
+ this.type = type;
+ if (params != null) {
+ this.params.putAll(params);
+ }
+ this.targetNode = targetNode;
+ this.coreName = coreName;
+ this.nodeSet = nodeSet;
+ Objects.requireNonNull(this.type, "'type' must not be null");
+ Objects.requireNonNull(this.coreName, "'coreName' must not be null");
+ }
+
+ public Replica.Type getType() {
+ return type;
+ }
+
+ public Map<String, Object> getParams() {
+ return params;
+ }
+
+ // impls may request a specific target node
+ public String getTargetNode() {
+ return targetNode;
+ }
+
+ public String getCoreName() {
+ return coreName;
+ }
+
+ // subset of live nodes to consider as valid targets, or null
+ public Set<String> getNodeSet() {
+ return nodeSet;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecision.java
new file mode 100644
index 0000000..9e0cfaa
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecision.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public interface AssignDecision {
+
+ AssignRequest getAssignRequest();
+
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecisions.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecisions.java
new file mode 100644
index 0000000..9626a55
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignDecisions.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Collection;
+
+/**
+ *
+ */
+public class AssignDecisions {
+
+ private final AssignerClusterState outputClusterState;
+ private final Collection<AssignDecision> decisions;
+
+ public AssignDecisions(AssignerClusterState outputClusterState, Collection<AssignDecision> decisions) {
+ this.outputClusterState = outputClusterState;
+ this.decisions = decisions;
+ }
+
+ AssignerClusterState getOutputClusterState() {
+ return outputClusterState;
+ }
+
+ Collection<AssignDecision> getAssignmentDecisions() {
+ return decisions;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignRequest.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignRequest.java
new file mode 100644
index 0000000..3d7ab0f
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignRequest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public interface AssignRequest {
+
+ String getCollection();
+
+ String getShard();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/Assigner.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/Assigner.java
new file mode 100644
index 0000000..3388500
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/Assigner.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.List;
+
+/**
+ * Interface implemented by assign strategies.
+ */
+public interface Assigner {
+
+ AssignDecisions computeAssignments(AssignerClusterState initialState,
+ List<AssignRequest> requests) throws InterruptedException, AssignerException;
+
+}
\ No newline at end of file
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerClusterState.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerClusterState.java
new file mode 100644
index 0000000..5deaa01
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerClusterState.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Initial cluster state for assigner.
+ */
+public interface AssignerClusterState {
+ Set<String> getNodes();
+ Set<String> getLiveNodes();
+ Collection<String> getCollections();
+
+ default AssignerNodeState getNodeState(String nodeName) {
+ return getNodeState(nodeName, Collections.emptySet(), Collections.emptySet());
+ }
+
+ AssignerNodeState getNodeState(String nodeName, Collection<String> nodeKeys, Collection<String> replicaKeys);
+
+ AssignerCollectionState getCollectionState(String collectionName, Collection<String> replicaKeys);
+
+ // other cluster properties
+ Map<String, Object> getProperties();
+
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerCollectionState.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerCollectionState.java
new file mode 100644
index 0000000..f848345
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerCollectionState.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *
+ */
+public interface AssignerCollectionState {
+
+ String getCollection();
+ Collection<String> getShards();
+ AssignerShardState getShardState(String shardName);
+
+ // other collection properties (router, policy settings, etc)
+ Map<String, Object> getProperties();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerException.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerException.java
new file mode 100644
index 0000000..d64ca34
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerException.java
@@ -0,0 +1,18 @@
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public class AssignerException extends Exception {
+ public AssignerException(String message) {
+ super(message);
+ }
+
+ public AssignerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AssignerException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerNodeState.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerNodeState.java
new file mode 100644
index 0000000..e6bffe1
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerNodeState.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public interface AssignerNodeState {
+ Collection<AssignerReplica> getReplicas();
+
+ long getTotalDiskGB();
+
+ long getFreeDiskGB();
+
+ Map<String, Object> getProperties();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerReplica.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerReplica.java
new file mode 100644
index 0000000..192ae0e
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerReplica.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.common.cloud.Replica;
+
+/**
+ * Represents basic information about a replica.
+ */
+public class AssignerReplica {
+ private final String name;
+ private final String node;
+ private final String collection;
+ private final String shard;
+ private final String core;
+ private final Replica.Type type;
+ private final Replica.State state;
+ private final Map<String, Object> properties = new HashMap<>();
+
+ public AssignerReplica(String name, String node,
+ String collection, String shard, String core,
+ Replica.Type type, Replica.State state,
+ Map<String, Object> properties) {
+ this.name = name;
+ this.node = node;
+ this.collection = collection;
+ this.shard = shard;
+ this.core = core;
+ this.type = type;
+ this.state = state;
+ if (properties != null) {
+ this.properties.putAll(properties);
+ }
+ }
+
+ // so-called coreNode name
+ public String getName() {
+ return name;
+ }
+
+ public String getNode() {
+ return node;
+ }
+
+ public String getCollection() {
+ return collection;
+ }
+
+ public String getShard() {
+ return shard;
+ }
+
+ // SolrCore name
+ public String getCore() {
+ return core;
+ }
+
+ public Replica.Type getType() {
+ return type;
+ }
+
+ public Replica.State getState() {
+ return state;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerShardState.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerShardState.java
new file mode 100644
index 0000000..93c83b0
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/AssignerShardState.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *
+ */
+public interface AssignerShardState {
+ String getName();
+
+ Collection<AssignerReplica> getReplicas();
+
+ Map<String, Object> getProperties();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignDecision.java
new file mode 100644
index 0000000..c045997
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignDecision.java
@@ -0,0 +1,18 @@
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public abstract class BaseAssignDecision implements AssignDecision {
+
+ protected final AssignRequest request;
+
+ protected BaseAssignDecision(AssignRequest request) {
+ this.request = request;
+ }
+
+ @Override
+ public AssignRequest getAssignRequest() {
+ return request;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignRequest.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignRequest.java
new file mode 100644
index 0000000..dda8d65
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/BaseAssignRequest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import java.util.Objects;
+
+/**
+ *
+ */
+public abstract class BaseAssignRequest implements AssignRequest {
+
+ protected final String collection;
+ protected final String shard;
+
+ protected BaseAssignRequest(String collection, String shard) {
+ this.collection = collection;
+ this.shard = shard;
+ Objects.requireNonNull(this.collection, "'collection' must not be null");
+ Objects.requireNonNull(this.shard, "'shard' must not be null");
+ }
+
+ @Override
+ public String getCollection() {
+ return collection;
+ }
+
+ @Override
+ public String getShard() {
+ return shard;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaDecision.java
new file mode 100644
index 0000000..1fae136
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaDecision.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public class DeleteReplicaDecision extends BaseAssignDecision {
+ public DeleteReplicaDecision(AssignRequest request) {
+ super(request);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaRequest.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaRequest.java
new file mode 100644
index 0000000..3c75926
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/DeleteReplicaRequest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public class DeleteReplicaRequest extends BaseAssignRequest {
+ private final String replicaName;
+
+ public DeleteReplicaRequest(String collection, String shard, String replicaName) {
+ super(collection, shard);
+ this.replicaName = replicaName;
+ }
+
+ public String getReplicaName() {
+ return replicaName;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaDecision.java
new file mode 100644
index 0000000..db3ee80
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaDecision.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+import org.apache.solr.common.cloud.Replica;
+
+/**
+ *
+ */
+public interface MoveReplicaDecision extends AssignDecision {
+ String getSourceNodeName();
+
+ String getTargetNodeName();
+
+ String getCollectionName();
+
+ String getSliceName();
+
+ String getReplicaName();
+
+ Replica.Type getReplicaType();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaRequest.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaRequest.java
new file mode 100644
index 0000000..32df4bc
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/MoveReplicaRequest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public interface MoveReplicaRequest extends AssignRequest {
+ String getSourceNode();
+
+ String getReplicaName();
+
+ String getTargetNode();
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/NoopDecision.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/NoopDecision.java
new file mode 100644
index 0000000..4fe90e1
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/NoopDecision.java
@@ -0,0 +1,21 @@
+package org.apache.solr.cloud.api.collections.assign;
+
+/**
+ *
+ */
+public class NoopDecision extends BaseAssignDecision {
+ private final String reason;
+
+ public NoopDecision(String reason, AssignRequest request) {
+ super(request);
+ this.reason = reason;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public static NoopDecision of(String reason, AssignRequest request) {
+ return new NoopDecision(reason, request);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerCloudManager.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerCloudManager.java
new file mode 100644
index 0000000..8476ff2
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerCloudManager.java
@@ -0,0 +1,81 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrResponse;
+import org.apache.solr.client.solrj.cloud.DistribStateManager;
+import org.apache.solr.client.solrj.cloud.DistributedQueueFactory;
+import org.apache.solr.client.solrj.cloud.NodeStateProvider;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.client.solrj.impl.ClusterStateProvider;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.common.util.ObjectCache;
+import org.apache.solr.common.util.TimeSource;
+
+/**
+ *
+ */
+public class AssignerCloudManager implements SolrCloudManager {
+ private final ObjectCache objectCache = new ObjectCache();
+ private final TimeSource timeSource;
+ private final AssignerClusterState assignerClusterState;
+ private final AssignerClusterStateProvider clusterStateProvider;
+ private final AssignerNodeStateProvider nodeStateProvider;
+ private final AssignerDistribStateManager distribStateManager;
+
+ public AssignerCloudManager(AssignerClusterState assignerClusterState,
+ TimeSource timeSource) {
+ this.assignerClusterState = assignerClusterState;
+ this.timeSource = timeSource;
+ clusterStateProvider = new AssignerClusterStateProvider(assignerClusterState);
+ nodeStateProvider = new AssignerNodeStateProvider(assignerClusterState);
+ distribStateManager = new AssignerDistribStateManager(assignerClusterState);
+ }
+
+ @Override
+ public ClusterStateProvider getClusterStateProvider() {
+ return clusterStateProvider;
+ }
+
+ @Override
+ public NodeStateProvider getNodeStateProvider() {
+ return nodeStateProvider;
+ }
+
+ @Override
+ public DistribStateManager getDistribStateManager() {
+ return distribStateManager;
+ }
+
+ @Override
+ public DistributedQueueFactory getDistributedQueueFactory() {
+ throw new UnsupportedOperationException("getDistributedQueueFactory");
+ }
+
+ @Override
+ public ObjectCache getObjectCache() {
+ return objectCache;
+ }
+
+ @Override
+ public TimeSource getTimeSource() {
+ return timeSource;
+ }
+
+ @Override
+ public SolrResponse request(SolrRequest req) throws IOException {
+ throw new UnsupportedOperationException("request");
+ }
+
+ @Override
+ public byte[] httpRequest(String url, SolrRequest.METHOD method, Map<String, String> headers, String payload, int timeout, boolean followRedirects) throws IOException {
+ throw new UnsupportedOperationException("httpRequest");
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerClusterStateProvider.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerClusterStateProvider.java
new file mode 100644
index 0000000..fdb7278
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerClusterStateProvider.java
@@ -0,0 +1,102 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.client.solrj.impl.ClusterStateProvider;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.cloud.api.collections.assign.AssignerCollectionState;
+import org.apache.solr.cloud.api.collections.assign.AssignerShardState;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.DocRouter;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+
+/**
+ *
+ */
+public class AssignerClusterStateProvider implements ClusterStateProvider {
+
+ private final AssignerClusterState state;
+ private final ClusterState clusterState;
+
+ public AssignerClusterStateProvider(AssignerClusterState state) {
+ this.state = state;
+ // build ClusterState
+ Map<String, DocCollection> collections = new HashMap<>();
+ state.getCollections().forEach(coll -> {
+ AssignerCollectionState collState = state.getCollectionState(coll, Collections.emptySet());
+ Map<String, Slice> slices = new HashMap<>();
+ collState.getShards().forEach(shard -> {
+ AssignerShardState shardState = collState.getShardState(shard);
+ Map<String, Replica> replicas = new HashMap<>();
+ shardState.getReplicas().forEach(ar -> {
+ Replica r = new Replica(ar.getName(), ar.getNode(), ar.getCollection(), ar.getShard(),
+ ar.getCore(), ar.getState(), ar.getType(), ar.getProperties());
+ replicas.put(r.getName(), r);
+ });
+ Slice slice = new Slice(shard, replicas, shardState.getProperties(), coll);
+ slices.put(slice.getName(), slice);
+ });
+ Map<String, Object> routerProp = (Map<String, Object>) collState.getProperties().getOrDefault(DocCollection.DOC_ROUTER, Collections.singletonMap("name", DocRouter.DEFAULT_NAME));
+ DocRouter router = DocRouter.getDocRouter((String)routerProp.getOrDefault("name", DocRouter.DEFAULT_NAME));
+ DocCollection docCollection = new DocCollection(coll, slices, collState.getProperties(), router, -1);
+ collections.put(docCollection.getName(), docCollection);
+ });
+ clusterState = new ClusterState(state.getLiveNodes(), collections);
+ }
+
+ @Override
+ public ClusterState.CollectionRef getState(String collection) {
+ return null;
+ }
+
+ @Override
+ public Set<String> getLiveNodes() {
+ return state.getLiveNodes();
+ }
+
+ @Override
+ public List<String> resolveAlias(String alias) {
+ throw new UnsupportedOperationException("resolveAlias");
+ }
+
+ @Override
+ public Map<String, String> getAliasProperties(String alias) {
+ throw new UnsupportedOperationException("getAliasProperties");
+ }
+
+ @Override
+ public ClusterState getClusterState() throws IOException {
+ return clusterState;
+ }
+
+ @Override
+ public Map<String, Object> getClusterProperties() {
+ return state.getProperties();
+ }
+
+ @Override
+ public String getPolicyNameByCollection(String coll) {
+ DocCollection docCollection = clusterState.getCollectionOrNull(coll);
+ if (docCollection == null) {
+ return null;
+ }
+ return docCollection.getPolicyName();
+ }
+
+ @Override
+ public void connect() {
+
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerDistribStateManager.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerDistribStateManager.java
new file mode 100644
index 0000000..c8115cf
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerDistribStateManager.java
@@ -0,0 +1,99 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.solr.client.solrj.cloud.DistribStateManager;
+import org.apache.solr.client.solrj.cloud.autoscaling.AlreadyExistsException;
+import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
+import org.apache.solr.client.solrj.cloud.autoscaling.BadVersionException;
+import org.apache.solr.client.solrj.cloud.autoscaling.NotEmptyException;
+import org.apache.solr.client.solrj.cloud.autoscaling.VersionedData;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Op;
+import org.apache.zookeeper.OpResult;
+import org.apache.zookeeper.Watcher;
+
+/**
+ *
+ */
+public class AssignerDistribStateManager implements DistribStateManager {
+
+ private final AutoScalingConfig autoScalingConfig;
+
+ public AssignerDistribStateManager(AssignerClusterState assignerClusterState) {
+ String autoscalingJson = (String) assignerClusterState.getProperties().get(ZkStateReader.SOLR_AUTOSCALING_CONF_PATH);
+ if (autoscalingJson != null) {
+ autoScalingConfig = new AutoScalingConfig(autoscalingJson.getBytes(StandardCharsets.UTF_8));
+ } else {
+ autoScalingConfig = new AutoScalingConfig(Collections.emptyMap());
+ }
+ }
+
+ @Override
+ public boolean hasData(String path) throws IOException, KeeperException, InterruptedException {
+ return false;
+ }
+
+ @Override
+ public List<String> listData(String path) throws NoSuchElementException, IOException, KeeperException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public List<String> listData(String path, Watcher watcher) throws NoSuchElementException, IOException, KeeperException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public VersionedData getData(String path, Watcher watcher) throws NoSuchElementException, IOException, KeeperException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public void makePath(String path) throws AlreadyExistsException, IOException, KeeperException, InterruptedException {
+
+ }
+
+ @Override
+ public void makePath(String path, byte[] data, CreateMode createMode, boolean failOnExists) throws AlreadyExistsException, IOException, KeeperException, InterruptedException {
+
+ }
+
+ @Override
+ public String createData(String path, byte[] data, CreateMode mode) throws AlreadyExistsException, IOException, KeeperException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public void removeData(String path, int version) throws NoSuchElementException, IOException, NotEmptyException, KeeperException, InterruptedException, BadVersionException {
+
+ }
+
+ @Override
+ public void setData(String path, byte[] data, int version) throws BadVersionException, NoSuchElementException, IOException, KeeperException, InterruptedException {
+
+ }
+
+ @Override
+ public List<OpResult> multi(Iterable<Op> ops) throws BadVersionException, NoSuchElementException, AlreadyExistsException, IOException, KeeperException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public AutoScalingConfig getAutoScalingConfig(Watcher watcher) throws InterruptedException, IOException {
+ return autoScalingConfig;
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerNodeStateProvider.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerNodeStateProvider.java
new file mode 100644
index 0000000..8502a15
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/AssignerNodeStateProvider.java
@@ -0,0 +1,56 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.solr.client.solrj.cloud.NodeStateProvider;
+import org.apache.solr.client.solrj.cloud.autoscaling.Variable;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.cloud.api.collections.assign.AssignerNodeState;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.util.Utils;
+
+/**
+ *
+ */
+public class AssignerNodeStateProvider implements NodeStateProvider {
+
+ private final AssignerClusterState state;
+
+ public AssignerNodeStateProvider(AssignerClusterState state) {
+ this.state = state;
+ }
+
+ @Override
+ public Map<String, Object> getNodeValues(String node, Collection<String> tags) {
+ AssignerNodeState nodeState = state.getNodeState(node, tags, Collections.emptyList());
+ Map<String, Object> values = new HashMap<>();
+ values.putAll(nodeState.getProperties());
+ values.put(Variable.Type.FREEDISK.tagName, nodeState.getFreeDiskGB());
+ values.put(Variable.Type.TOTALDISK.tagName, nodeState.getTotalDiskGB());
+ return values;
+ }
+
+ @Override
+ public Map<String, Map<String, List<Replica>>> getReplicaInfo(String node, Collection<String> keys) {
+ AssignerNodeState nodeState = state.getNodeState(node, Collections.emptyList(), keys);
+ Map<String, Map<String, List<Replica>>> replicas = new HashMap<>();
+ nodeState.getReplicas().forEach(ar -> {
+ Map<String, List<Replica>> perColl = replicas.computeIfAbsent(ar.getCollection(), Utils.NEW_HASHMAP_FUN);
+ List<Replica> perShard = perColl.computeIfAbsent(ar.getShard(), Utils.NEW_ARRAYLIST_FUN);
+ Replica r = new Replica(ar.getName(), ar.getNode(), ar.getCollection(), ar.getShard(),
+ ar.getCore(), ar.getState(), ar.getType(), ar.getProperties());
+ perShard.add(r);
+ });
+ return replicas;
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/Policy8xAssigner.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/Policy8xAssigner.java
new file mode 100644
index 0000000..14e9b7a
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/Policy8xAssigner.java
@@ -0,0 +1,61 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
+import org.apache.solr.client.solrj.cloud.autoscaling.PolicyHelper;
+import org.apache.solr.cloud.api.collections.assign.AddReplicaDecision;
+import org.apache.solr.cloud.api.collections.assign.AddReplicaRequest;
+import org.apache.solr.cloud.api.collections.assign.Assigner;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.cloud.api.collections.assign.AssignerException;
+import org.apache.solr.cloud.api.collections.assign.AssignDecision;
+import org.apache.solr.cloud.api.collections.assign.AssignDecisions;
+import org.apache.solr.cloud.api.collections.assign.AssignRequest;
+import org.apache.solr.cloud.api.collections.assign.NoopDecision;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.ReplicaPosition;
+import org.apache.solr.common.util.TimeSource;
+
+/**
+ *
+ */
+public class Policy8xAssigner implements Assigner {
+
+ private TimeSource timeSource = TimeSource.NANO_TIME;
+
+ @Override
+ public AssignDecisions computeAssignments(AssignerClusterState initialState,
+ List<AssignRequest> requests) throws InterruptedException, AssignerException {
+ AssignerCloudManager cloudManager = new AssignerCloudManager(initialState, timeSource);
+ try {
+ AutoScalingConfig autoScalingConfig = cloudManager.getDistribStateManager().getAutoScalingConfig();
+ List<AssignDecision> decisions = new ArrayList<>();
+ // XXX this handles only Add requests
+ for (AssignRequest req : requests) {
+ if (req instanceof AddReplicaRequest) {
+ AddReplicaRequest areq = (AddReplicaRequest) req;
+ int nrtReplicas = areq.getType() == Replica.Type.NRT ? 1 : 0;
+ int tlogReplicas = areq.getType() == Replica.Type.TLOG ? 1 : 0;
+ int pullReplicas = areq.getType() == Replica.Type.PULL ? 1 : 0;
+ List<ReplicaPosition> positions = PolicyHelper.getReplicaLocations(areq.getCollection(), autoScalingConfig,
+ cloudManager, null, Collections.singletonList(areq.getShard()),
+ nrtReplicas, tlogReplicas, pullReplicas, areq.getNodeSet() != null ? new ArrayList(areq.getNodeSet()) : null);
+ positions.forEach(pos -> {
+ decisions.add(new AddReplicaDecision(req, pos.node));
+ });
+ } else {
+ decisions.add(NoopDecision.of("unsupported", req));
+ }
+ }
+ // XXX we should return the new state here
+ return new AssignDecisions(initialState, decisions);
+ } catch (IOException e) {
+ throw new AssignerException(e);
+ }
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/SolrCloudManagerAssignerClusterState.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/SolrCloudManagerAssignerClusterState.java
new file mode 100644
index 0000000..e798602
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/assign/policy8x/SolrCloudManagerAssignerClusterState.java
@@ -0,0 +1,159 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.solr.client.solrj.cloud.NodeStateProvider;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
+import org.apache.solr.cloud.api.collections.assign.AssignerClusterState;
+import org.apache.solr.cloud.api.collections.assign.AssignerCollectionState;
+import org.apache.solr.cloud.api.collections.assign.AssignerNodeState;
+import org.apache.solr.cloud.api.collections.assign.AssignerReplica;
+import org.apache.solr.cloud.api.collections.assign.AssignerShardState;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.util.Utils;
+
+/**
+ *
+ */
+public class SolrCloudManagerAssignerClusterState implements AssignerClusterState {
+ private final Map<String, Object> properties = new HashMap<>();
+ private final SolrCloudManager cloudManager;
+
+ public SolrCloudManagerAssignerClusterState(SolrCloudManager cloudManager) throws Exception {
+ this.cloudManager = cloudManager;
+ AutoScalingConfig autoScalingConfig = cloudManager.getDistribStateManager().getAutoScalingConfig();
+ properties.put(ZkStateReader.SOLR_AUTOSCALING_CONF_PATH, Utils.toJSONString(autoScalingConfig));
+ }
+
+ @Override
+ public Set<String> getNodes() {
+ return cloudManager.getClusterStateProvider().getLiveNodes();
+ }
+
+ @Override
+ public Set<String> getLiveNodes() {
+ return cloudManager.getClusterStateProvider().getLiveNodes();
+ }
+
+ @Override
+ public Collection<String> getCollections() {
+ try {
+ return cloudManager.getClusterStateProvider().getClusterState().getCollectionStates().keySet();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public AssignerNodeState getNodeState(String nodeName, Collection<String> nodeKeys, Collection<String> replicaKeys) {
+ final NodeStateProvider nodeStateProvider = cloudManager.getNodeStateProvider();
+ return new AssignerNodeState() {
+ @Override
+ public Collection<AssignerReplica> getReplicas() {
+ Map<String, Map<String, List<Replica>>> replicaInfos = nodeStateProvider.getReplicaInfo(nodeName, replicaKeys);
+ List<AssignerReplica> replicas = new ArrayList<>();
+ replicaInfos.forEach((coll, shards) -> {
+ shards.forEach((shard, infos) -> {
+ infos.forEach(info -> {
+ AssignerReplica ar = new AssignerReplica(info.getName(), info.getNodeName(), info.getCollection(),
+ info.getShard(), info.getCoreName(), info.getType(), info.getState(),
+ info.getProperties());
+ replicas.add(ar);
+ });
+ });
+ });
+ return replicas;
+ }
+
+ @Override
+ public long getTotalDiskGB() {
+ return -1;
+ }
+
+ @Override
+ public long getFreeDiskGB() {
+ return -1;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return nodeStateProvider.getNodeValues(nodeName, nodeKeys);
+ }
+ };
+ }
+
+ @Override
+ public AssignerCollectionState getCollectionState(String collectionName, Collection<String> replicaKeys) {
+ ClusterState.CollectionRef collRef = cloudManager.getClusterStateProvider().getState(collectionName);
+ if (collRef == null) {
+ return null;
+ }
+ final DocCollection coll = collRef.get();
+ return new AssignerCollectionState() {
+ @Override
+ public String getCollection() {
+ return collectionName;
+ }
+
+ @Override
+ public Collection<String> getShards() {
+ return coll.getSlicesMap().keySet();
+ }
+
+ @Override
+ public AssignerShardState getShardState(String shardName) {
+ Slice slice = coll.getSlice(shardName);
+ if (slice == null) {
+ return null;
+ }
+ return new AssignerShardState() {
+ @Override
+ public String getName() {
+ return slice.getName();
+ }
+
+ @Override
+ public Collection<AssignerReplica> getReplicas() {
+ return slice.getReplicas().stream()
+ .map(r -> new AssignerReplica(
+ r.getName(),
+ r.getNodeName(),
+ r.getCollection(),
+ r.getShard(),
+ r.getCoreName(),
+ r.getType(),
+ r.getState(),
+ r.getProperties())).collect(Collectors.toList());
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return slice.getProperties();
+ }
+ };
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return coll.getProperties();
+ }
+ };
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/assign/policy8x/TestPolicy8x.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/assign/policy8x/TestPolicy8x.java
new file mode 100644
index 0000000..3368dfb
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/assign/policy8x/TestPolicy8x.java
@@ -0,0 +1,44 @@
+package org.apache.solr.cloud.api.collections.assign.policy8x;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.cloud.api.collections.assign.AddReplicaRequest;
+import org.apache.solr.cloud.api.collections.assign.AssignDecisions;
+import org.apache.solr.cloud.api.collections.assign.AssignRequest;
+import org.apache.solr.cloud.autoscaling.sim.SimCloudManager;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.util.TimeSource;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class TestPolicy8x extends SolrTestCaseJ4 {
+
+ SolrCloudManager cloudManager;
+
+ @Before
+ public void initCluster() throws Exception {
+ cloudManager = SimCloudManager.createCluster(100, TimeSource.get("simTime:50"));
+ }
+
+ @After
+ public void shutdownCluster() throws Exception {
+ if (cloudManager != null) {
+ cloudManager.close();
+ }
+ }
+
+ @Test
+ public void testBasics() throws Exception {
+ SolrCloudManagerAssignerClusterState initialState = new SolrCloudManagerAssignerClusterState(cloudManager);
+ Policy8xAssigner assigner = new Policy8xAssigner();
+ List<AssignRequest> requests = Collections.singletonList(new AddReplicaRequest("foo", "bar", Replica.Type.NRT, null, null, "c1", null));
+ AssignDecisions decisions = assigner.computeAssignments(initialState, requests);
+ }
+}