PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateSnapshotCmd.java

https://github.com/apache/solr
Java | 229 lines | 176 code | 24 blank | 29 comment | 24 complexity | ecdc20fac75e8e1aae1c62faaca2cdc4 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.solr.cloud.api.collections;
  18. import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
  19. import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
  20. import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
  21. import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
  22. import static org.apache.solr.common.params.CommonParams.NAME;
  23. import java.lang.invoke.MethodHandles;
  24. import java.util.ArrayList;
  25. import java.util.Date;
  26. import java.util.HashMap;
  27. import java.util.HashSet;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.Set;
  31. import org.apache.solr.cloud.api.collections.CollectionHandlingUtils.ShardRequestTracker;
  32. import org.apache.solr.common.SolrException;
  33. import org.apache.solr.common.SolrException.ErrorCode;
  34. import org.apache.solr.common.cloud.ClusterState;
  35. import org.apache.solr.common.cloud.DocCollection;
  36. import org.apache.solr.common.cloud.Replica;
  37. import org.apache.solr.common.cloud.Replica.State;
  38. import org.apache.solr.common.cloud.Slice;
  39. import org.apache.solr.common.cloud.SolrZkClient;
  40. import org.apache.solr.common.cloud.ZkNodeProps;
  41. import org.apache.solr.common.params.CoreAdminParams;
  42. import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
  43. import org.apache.solr.common.params.ModifiableSolrParams;
  44. import org.apache.solr.common.util.NamedList;
  45. import org.apache.solr.core.snapshots.CollectionSnapshotMetaData;
  46. import org.apache.solr.core.snapshots.CollectionSnapshotMetaData.CoreSnapshotMetaData;
  47. import org.apache.solr.core.snapshots.CollectionSnapshotMetaData.SnapshotStatus;
  48. import org.apache.solr.core.snapshots.SolrSnapshotManager;
  49. import org.apache.solr.handler.component.ShardHandler;
  50. import org.slf4j.Logger;
  51. import org.slf4j.LoggerFactory;
  52. /** This class implements the functionality of creating a collection level snapshot. */
  53. public class CreateSnapshotCmd implements CollApiCmds.CollectionApiCommand {
  54. private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  55. private final CollectionCommandContext ccc;
  56. public CreateSnapshotCmd(CollectionCommandContext ccc) {
  57. this.ccc = ccc;
  58. }
  59. @Override
  60. public void call(ClusterState state, ZkNodeProps message, NamedList<Object> results)
  61. throws Exception {
  62. String extCollectionName = message.getStr(COLLECTION_PROP);
  63. boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
  64. String collectionName;
  65. if (followAliases) {
  66. collectionName = ccc.getZkStateReader().getAliases().resolveSimpleAlias(extCollectionName);
  67. } else {
  68. collectionName = extCollectionName;
  69. }
  70. String commitName = message.getStr(CoreAdminParams.COMMIT_NAME);
  71. String asyncId = message.getStr(ASYNC);
  72. SolrZkClient zkClient = ccc.getZkStateReader().getZkClient();
  73. Date creationDate = new Date();
  74. if (SolrSnapshotManager.snapshotExists(zkClient, collectionName, commitName)) {
  75. throw new SolrException(
  76. ErrorCode.BAD_REQUEST,
  77. "Snapshot with name " + commitName + " already exists for collection " + collectionName);
  78. }
  79. log.info(
  80. "Creating a snapshot for collection={} with commitName={}", collectionName, commitName);
  81. // Create a node in ZK to store the collection level snapshot meta-data.
  82. SolrSnapshotManager.createCollectionLevelSnapshot(
  83. zkClient, collectionName, new CollectionSnapshotMetaData(commitName));
  84. log.info(
  85. "Created a ZK path to store snapshot information for collection={} with commitName={}",
  86. collectionName,
  87. commitName);
  88. NamedList<Object> shardRequestResults = new NamedList<>();
  89. Map<String, Slice> shardByCoreName = new HashMap<>();
  90. ShardHandler shardHandler = ccc.newShardHandler();
  91. final ShardRequestTracker shardRequestTracker =
  92. CollectionHandlingUtils.asyncRequestTracker(asyncId, ccc);
  93. for (Slice slice :
  94. ccc.getZkStateReader().getClusterState().getCollection(collectionName).getSlices()) {
  95. for (Replica replica : slice.getReplicas()) {
  96. if (replica.getState() != State.ACTIVE) {
  97. if (log.isInfoEnabled()) {
  98. log.info(
  99. "Replica {} is not active. Hence not sending the createsnapshot request",
  100. replica.getCoreName());
  101. }
  102. continue; // Since replica is not active - no point sending a request.
  103. }
  104. String coreName = replica.getStr(CORE_NAME_PROP);
  105. ModifiableSolrParams params = new ModifiableSolrParams();
  106. params.set(CoreAdminParams.ACTION, CoreAdminAction.CREATESNAPSHOT.toString());
  107. params.set(NAME, slice.getName());
  108. params.set(CORE_NAME_PROP, coreName);
  109. params.set(CoreAdminParams.COMMIT_NAME, commitName);
  110. shardRequestTracker.sendShardRequest(replica.getNodeName(), params, shardHandler);
  111. log.debug(
  112. "Sent createsnapshot request to core={} with commitName={}", coreName, commitName);
  113. shardByCoreName.put(coreName, slice);
  114. }
  115. }
  116. // At this point we want to make sure that at-least one replica for every shard
  117. // is able to create the snapshot. If that is not the case, then we fail the request.
  118. // This is to take care of the situation where e.g. entire shard is unavailable.
  119. Set<String> failedShards = new HashSet<>();
  120. shardRequestTracker.processResponses(shardRequestResults, shardHandler, false, null);
  121. NamedList<?> success = (NamedList<?>) shardRequestResults.get("success");
  122. List<CoreSnapshotMetaData> replicas = new ArrayList<>();
  123. if (success != null) {
  124. for (int i = 0; i < success.size(); i++) {
  125. @SuppressWarnings("unchecked")
  126. NamedList<Object> resp = (NamedList<Object>) success.getVal(i);
  127. // Check if this core is the leader for the shard. The idea here is that during the backup
  128. // operation we preferably use the snapshot of the "leader" replica since it is most likely
  129. // to have latest state.
  130. String coreName = (String) resp.get(CoreAdminParams.CORE);
  131. Slice slice = shardByCoreName.remove(coreName);
  132. boolean leader =
  133. (slice.getLeader() != null && slice.getLeader().getCoreName().equals(coreName));
  134. resp.add(SolrSnapshotManager.SHARD_ID, slice.getName());
  135. resp.add(SolrSnapshotManager.LEADER, leader);
  136. CoreSnapshotMetaData c = new CoreSnapshotMetaData(resp);
  137. replicas.add(c);
  138. if (log.isInfoEnabled()) {
  139. log.info(
  140. "Snapshot with commitName {} is created successfully for core {}",
  141. commitName,
  142. c.getCoreName());
  143. }
  144. }
  145. }
  146. if (!shardByCoreName.isEmpty()) { // One or more failures.
  147. log.warn(
  148. "Unable to create a snapshot with name {} for following cores {}",
  149. commitName,
  150. shardByCoreName.keySet());
  151. // Count number of failures per shard.
  152. Map<String, Integer> failuresByShardId = new HashMap<>();
  153. for (Map.Entry<String, Slice> entry : shardByCoreName.entrySet()) {
  154. int f = 0;
  155. if (failuresByShardId.get(entry.getValue().getName()) != null) {
  156. f = failuresByShardId.get(entry.getValue().getName());
  157. }
  158. failuresByShardId.put(entry.getValue().getName(), f + 1);
  159. }
  160. // Now that we know number of failures per shard, we can figure out
  161. // if at-least one replica per shard was able to create a snapshot or not.
  162. DocCollection collectionStatus =
  163. ccc.getZkStateReader().getClusterState().getCollection(collectionName);
  164. for (Map.Entry<String, Integer> entry : failuresByShardId.entrySet()) {
  165. int replicaCount = collectionStatus.getSlice(entry.getKey()).getReplicas().size();
  166. if (replicaCount <= entry.getValue()) {
  167. failedShards.add(entry.getKey());
  168. }
  169. }
  170. }
  171. if (failedShards.isEmpty()) { // No failures.
  172. CollectionSnapshotMetaData meta =
  173. new CollectionSnapshotMetaData(
  174. commitName, SnapshotStatus.Successful, creationDate, replicas);
  175. SolrSnapshotManager.updateCollectionLevelSnapshot(zkClient, collectionName, meta);
  176. if (log.isInfoEnabled()) {
  177. log.info(
  178. "Saved following snapshot information for collection={} with commitName={} in Zookeeper : {}",
  179. collectionName,
  180. commitName,
  181. meta.toNamedList());
  182. }
  183. } else {
  184. log.warn(
  185. "Failed to create a snapshot for collection {} with commitName = {}. Snapshot could not be captured for following shards {}",
  186. collectionName,
  187. commitName,
  188. failedShards);
  189. // Update the ZK meta-data to include only cores with the snapshot. This will enable users to
  190. // figure out which cores have the named snapshot.
  191. CollectionSnapshotMetaData meta =
  192. new CollectionSnapshotMetaData(commitName, SnapshotStatus.Failed, creationDate, replicas);
  193. SolrSnapshotManager.updateCollectionLevelSnapshot(zkClient, collectionName, meta);
  194. if (log.isInfoEnabled()) {
  195. log.info(
  196. "Saved following snapshot information for collection={} with commitName={} in Zookeeper : {}",
  197. collectionName,
  198. commitName,
  199. meta.toNamedList());
  200. }
  201. throw new SolrException(
  202. ErrorCode.SERVER_ERROR, "Failed to create snapshot on shards " + failedShards);
  203. }
  204. }
  205. }