All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.handler.admin.CoreAdminHandler Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * 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.handler.admin;

import java.io.File;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutorService;

import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.api.Api;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CommonAdminParams;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricsContext;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthorizationContext;
import org.apache.solr.security.PermissionNameProvider;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import static org.apache.solr.common.params.CoreAdminParams.ACTION;
import static org.apache.solr.common.params.CoreAdminParams.CoreAdminAction.STATUS;
import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
import static org.apache.solr.security.PermissionNameProvider.Name.CORE_READ_PERM;

/**
 *
 * @since solr 1.3
 */
public class CoreAdminHandler extends RequestHandlerBase implements PermissionNameProvider {
  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  protected final CoreContainer coreContainer;
  protected final Map> requestStatusMap;
  private final CoreAdminHandlerApi coreAdminHandlerApi;

  protected ExecutorService parallelExecutor = ExecutorUtil.newMDCAwareFixedThreadPool(50,
      new SolrNamedThreadFactory("parallelCoreAdminExecutor"));

  protected static int MAX_TRACKED_REQUESTS = 100;
  public static String RUNNING = "running";
  public static String COMPLETED = "completed";
  public static String FAILED = "failed";
  public static String RESPONSE = "Response";
  public static String RESPONSE_STATUS = "STATUS";
  public static String RESPONSE_MESSAGE = "msg";

  public CoreAdminHandler() {
    super();
    // Unlike most request handlers, CoreContainer initialization 
    // should happen in the constructor...  
    this.coreContainer = null;
    HashMap> map = new HashMap<>(3, 1.0f);
    map.put(RUNNING, Collections.synchronizedMap(new LinkedHashMap()));
    map.put(COMPLETED, Collections.synchronizedMap(new LinkedHashMap()));
    map.put(FAILED, Collections.synchronizedMap(new LinkedHashMap()));
    requestStatusMap = Collections.unmodifiableMap(map);
    coreAdminHandlerApi = new CoreAdminHandlerApi(this);
  }


  /**
   * Overloaded ctor to inject CoreContainer into the handler.
   *
   * @param coreContainer Core Container of the solr webapp installed.
   */
  public CoreAdminHandler(final CoreContainer coreContainer) {
    this.coreContainer = coreContainer;
    HashMap> map = new HashMap<>(3, 1.0f);
    map.put(RUNNING, Collections.synchronizedMap(new LinkedHashMap()));
    map.put(COMPLETED, Collections.synchronizedMap(new LinkedHashMap()));
    map.put(FAILED, Collections.synchronizedMap(new LinkedHashMap()));
    requestStatusMap = Collections.unmodifiableMap(map);
    coreAdminHandlerApi = new CoreAdminHandlerApi(this);
  }


  @Override
  final public void init(@SuppressWarnings({"rawtypes"})NamedList args) {
    throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
            "CoreAdminHandler should not be configured in solrconf.xml\n" +
                    "it is a special Handler configured directly by the RequestDispatcher");
  }

  @Override
  public void initializeMetrics(SolrMetricsContext parentContext, String scope) {
    super.initializeMetrics(parentContext, scope);
    parallelExecutor = MetricUtils.instrumentedExecutorService(parallelExecutor, this, solrMetricsContext.getMetricRegistry(),
        SolrMetricManager.mkName("parallelCoreAdminExecutor", getCategory().name(), scope, "threadPool"));
  }
  @Override
  public Boolean registerV2() {
    return Boolean.TRUE;
  }

  /**
   * The instance of CoreContainer this handler handles. This should be the CoreContainer instance that created this
   * handler.
   *
   * @return a CoreContainer instance
   */
  public CoreContainer getCoreContainer() {
    return this.coreContainer;
  }

  @Override
  public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
    // Make sure the cores is enabled
    try {
      CoreContainer cores = getCoreContainer();
      if (cores == null) {
        throw new SolrException(ErrorCode.BAD_REQUEST,
                "Core container instance missing");
      }
      //boolean doPersist = false;
      final String taskId = req.getParams().get(CommonAdminParams.ASYNC);
      final TaskObject taskObject = new TaskObject(taskId);

      if(taskId != null) {
        // Put the tasks into the maps for tracking
        if (getRequestStatusMap(RUNNING).containsKey(taskId) || getRequestStatusMap(COMPLETED).containsKey(taskId) || getRequestStatusMap(FAILED).containsKey(taskId)) {
          throw new SolrException(ErrorCode.BAD_REQUEST,
              "Duplicate request with the same requestid found.");
        }

        addTask(RUNNING, taskObject);
      }

      // Pick the action
      CoreAdminOperation op = opMap.get(req.getParams().get(ACTION, STATUS.toString()).toLowerCase(Locale.ROOT));
      if (op == null) {
        handleCustomAction(req, rsp);
        return;
      }

      final CallInfo callInfo = new CallInfo(this, req, rsp, op);
      String coreName = req.getParams().get(CoreAdminParams.CORE);
      if (coreName == null) {
        coreName = req.getParams().get(CoreAdminParams.NAME);
      }
      MDCLoggingContext.setCoreName(coreName);
      if (taskId == null) {
        callInfo.call();
      } else {
        try {
          MDC.put("CoreAdminHandler.asyncId", taskId);
          MDC.put("CoreAdminHandler.action", op.action.toString());
          parallelExecutor.execute(() -> {
            boolean exceptionCaught = false;
            try {
              callInfo.call();
              taskObject.setRspObject(callInfo.rsp);
            } catch (Exception e) {
              exceptionCaught = true;
              taskObject.setRspObjectFromException(e);
            } finally {
              removeTask("running", taskObject.taskId);
              if (exceptionCaught) {
                addTask("failed", taskObject, true);
              } else {
                addTask("completed", taskObject, true);
              }
            }
          });
        } finally {
          MDC.remove("CoreAdminHandler.asyncId");
          MDC.remove("CoreAdminHandler.action");
        }
      }
    } finally {
      rsp.setHttpCaching(false);

    }
  }

  /**
   * Handle Custom Action.
   * 

* This method could be overridden by derived classes to handle custom actions.
By default - this method throws a * solr exception. Derived classes are free to write their derivation if necessary. */ protected void handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported operation: " + req.getParams().get(ACTION)); } public static ImmutableMap paramToProp = ImmutableMap.builder() .put(CoreAdminParams.CONFIG, CoreDescriptor.CORE_CONFIG) .put(CoreAdminParams.SCHEMA, CoreDescriptor.CORE_SCHEMA) .put(CoreAdminParams.DATA_DIR, CoreDescriptor.CORE_DATADIR) .put(CoreAdminParams.ULOG_DIR, CoreDescriptor.CORE_ULOGDIR) .put(CoreAdminParams.CONFIGSET, CoreDescriptor.CORE_CONFIGSET) .put(CoreAdminParams.LOAD_ON_STARTUP, CoreDescriptor.CORE_LOADONSTARTUP) .put(CoreAdminParams.TRANSIENT, CoreDescriptor.CORE_TRANSIENT) .put(CoreAdminParams.SHARD, CoreDescriptor.CORE_SHARD) .put(CoreAdminParams.COLLECTION, CoreDescriptor.CORE_COLLECTION) .put(CoreAdminParams.ROLES, CoreDescriptor.CORE_ROLES) .put(CoreAdminParams.CORE_NODE_NAME, CoreDescriptor.CORE_NODE_NAME) .put(ZkStateReader.NUM_SHARDS_PROP, CloudDescriptor.NUM_SHARDS) .put(CoreAdminParams.REPLICA_TYPE, CloudDescriptor.REPLICA_TYPE) .build(); protected static Map buildCoreParams(SolrParams params) { Map coreParams = new HashMap<>(); // standard core create parameters for (Map.Entry entry : paramToProp.entrySet()) { String value = params.get(entry.getKey(), null); if (StringUtils.isNotEmpty(value)) { coreParams.put(entry.getValue(), value); } } // extra properties Iterator paramsIt = params.getParameterNamesIterator(); while (paramsIt.hasNext()) { String param = paramsIt.next(); if (param.startsWith(CoreAdminParams.PROPERTY_PREFIX)) { String propName = param.substring(CoreAdminParams.PROPERTY_PREFIX.length()); String propValue = params.get(param); coreParams.put(propName, propValue); } if (param.startsWith(ZkController.COLLECTION_PARAM_PREFIX)) { coreParams.put(param, params.get(param)); } } return coreParams; } protected static String normalizePath(String path) { if (path == null) return null; path = path.replace('/', File.separatorChar); path = path.replace('\\', File.separatorChar); return path; } public static ModifiableSolrParams params(String... params) { ModifiableSolrParams msp = new ModifiableSolrParams(); for (int i=0; i getRequestStatusMap(String key) { return requestStatusMap.get(key); } /** * Method to ensure shutting down of the ThreadPool Executor. */ public void shutdown() { if (parallelExecutor != null) ExecutorUtil.shutdownAndAwaitTermination(parallelExecutor); } private static final Map opMap = new HashMap<>(); static class CallInfo { final CoreAdminHandler handler; final SolrQueryRequest req; final SolrQueryResponse rsp; final CoreAdminOperation op; CallInfo(CoreAdminHandler handler, SolrQueryRequest req, SolrQueryResponse rsp, CoreAdminOperation op) { this.handler = handler; this.req = req; this.rsp = rsp; this.op = op; } void call() throws Exception { op.execute(this); } } @Override public Collection getApis() { return coreAdminHandlerApi.getApis(); } static { for (CoreAdminOperation op : CoreAdminOperation.values()) opMap.put(op.action.toString().toLowerCase(Locale.ROOT), op); } /** * used by the INVOKE action of core admin handler */ public interface Invocable { Map invoke(SolrQueryRequest req); } interface CoreAdminOp { /** * @param it request/response object * * If the request is invalid throw a SolrException with SolrException.ErrorCode.BAD_REQUEST ( 400 ) * If the execution of the command fails throw a SolrException with SolrException.ErrorCode.SERVER_ERROR ( 500 ) * * Any non-SolrException's are wrapped at a higher level as a SolrException with SolrException.ErrorCode.SERVER_ERROR. */ void execute(CallInfo it) throws Exception; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy