protected final synchronized DocCollection getDocCollection() { if (docCollection == null) { ZkStateReader zkStateReader = getCloudSolrServer().getZkStateReader(); docCollection = zkStateReader.getClusterState().getCollection(collection); // do basic checks once DocRouter docRouter = docCollection.getRouter(); if (docRouter instanceof ImplicitDocRouter) throw new IllegalStateException( "Implicit document routing not supported by this Partitioner!"); Collection<Slice> shards = getDocCollection().getSlices(); if (shards == null || shards.size() == 0) throw new IllegalStateException( "Collection '" + collection + "' does not have any shards!"); } return docCollection; }
@Override public int getPartition(Object o) { Object docId = null; if (o instanceof SolrInputDocument) { SolrInputDocument doc = (SolrInputDocument) o; docId = doc.getFieldValue(idField); if (docId == null) throw new IllegalArgumentException( "SolrInputDocument must contain a non-null value for " + idField); } else { docId = o; } if (!(docId instanceof String)) throw new IllegalArgumentException( "Only String document IDs are supported by this Partitioner!"); DocCollection dc = getDocCollection(); Slice slice = dc.getRouter().getTargetSlice((String) docId, null, null, null, dc); return getShardIndex(slice.getName(), dc); }
public String getShardId(String docId) { DocCollection dc = getDocCollection(); Slice slice = dc.getRouter().getTargetSlice(docId, null, null, null, dc); return slice.getName(); }
protected NamedList<Object> sendRequest(SolrRequest request) throws SolrServerException, IOException { connect(); ClusterState clusterState = zkStateReader.getClusterState(); boolean sendToLeaders = false; List<String> replicas = null; if (request instanceof IsUpdateRequest) { if (request instanceof UpdateRequest) { NamedList<Object> response = directUpdate((AbstractUpdateRequest) request, clusterState); if (response != null) { return response; } } sendToLeaders = true; replicas = new ArrayList<>(); } SolrParams reqParams = request.getParams(); if (reqParams == null) { reqParams = new ModifiableSolrParams(); } List<String> theUrlList = new ArrayList<>(); if (request.getPath().equals("/admin/collections") || request.getPath().equals("/admin/cores")) { Set<String> liveNodes = clusterState.getLiveNodes(); for (String liveNode : liveNodes) { theUrlList.add(zkStateReader.getBaseUrlForNodeName(liveNode)); } } else { String collection = reqParams.get(UpdateParams.COLLECTION, defaultCollection); if (collection == null) { throw new SolrServerException( "No collection param specified on request and no default collection has been set."); } Set<String> collectionsList = getCollectionList(clusterState, collection); if (collectionsList.size() == 0) { throw new SolrException(ErrorCode.BAD_REQUEST, "Could not find collection: " + collection); } String shardKeys = reqParams.get(ShardParams._ROUTE_); if (shardKeys == null) { shardKeys = reqParams.get(ShardParams.SHARD_KEYS); // deprecated } // TODO: not a big deal because of the caching, but we could avoid looking // at every shard // when getting leaders if we tweaked some things // Retrieve slices from the cloud state and, for each collection // specified, // add it to the Map of slices. Map<String, Slice> slices = new HashMap<>(); for (String collectionName : collectionsList) { DocCollection col = getDocCollection(clusterState, collectionName); Collection<Slice> routeSlices = col.getRouter().getSearchSlices(shardKeys, reqParams, col); ClientUtils.addSlices(slices, collectionName, routeSlices, true); } Set<String> liveNodes = clusterState.getLiveNodes(); List<String> leaderUrlList = null; List<String> urlList = null; List<String> replicasList = null; // build a map of unique nodes // TODO: allow filtering by group, role, etc Map<String, ZkNodeProps> nodes = new HashMap<>(); List<String> urlList2 = new ArrayList<>(); for (Slice slice : slices.values()) { for (ZkNodeProps nodeProps : slice.getReplicasMap().values()) { ZkCoreNodeProps coreNodeProps = new ZkCoreNodeProps(nodeProps); String node = coreNodeProps.getNodeName(); if (!liveNodes.contains(coreNodeProps.getNodeName()) || !coreNodeProps.getState().equals(ZkStateReader.ACTIVE)) continue; if (nodes.put(node, nodeProps) == null) { if (!sendToLeaders || (sendToLeaders && coreNodeProps.isLeader())) { String url; if (reqParams.get(UpdateParams.COLLECTION) == null) { url = ZkCoreNodeProps.getCoreUrl( nodeProps.getStr(ZkStateReader.BASE_URL_PROP), defaultCollection); } else { url = coreNodeProps.getCoreUrl(); } urlList2.add(url); } else if (sendToLeaders) { String url; if (reqParams.get(UpdateParams.COLLECTION) == null) { url = ZkCoreNodeProps.getCoreUrl( nodeProps.getStr(ZkStateReader.BASE_URL_PROP), defaultCollection); } else { url = coreNodeProps.getCoreUrl(); } replicas.add(url); } } } } if (sendToLeaders) { leaderUrlList = urlList2; replicasList = replicas; } else { urlList = urlList2; } if (sendToLeaders) { theUrlList = new ArrayList<>(leaderUrlList.size()); theUrlList.addAll(leaderUrlList); } else { theUrlList = new ArrayList<>(urlList.size()); theUrlList.addAll(urlList); } if (theUrlList.isEmpty()) { throw new SolrException( SolrException.ErrorCode.INVALID_STATE, "Not enough nodes to handle the request"); } Collections.shuffle(theUrlList, rand); if (sendToLeaders) { ArrayList<String> theReplicas = new ArrayList<>(replicasList.size()); theReplicas.addAll(replicasList); Collections.shuffle(theReplicas, rand); theUrlList.addAll(theReplicas); } } LBHttpSolrServer.Req req = new LBHttpSolrServer.Req(request, theUrlList); LBHttpSolrServer.Rsp rsp = lbServer.request(req); return rsp.getResponse(); }
private NamedList<Object> directUpdate(AbstractUpdateRequest request, ClusterState clusterState) throws SolrServerException { UpdateRequest updateRequest = (UpdateRequest) request; ModifiableSolrParams params = (ModifiableSolrParams) request.getParams(); ModifiableSolrParams routableParams = new ModifiableSolrParams(); ModifiableSolrParams nonRoutableParams = new ModifiableSolrParams(); if (params != null) { nonRoutableParams.add(params); routableParams.add(params); for (String param : NON_ROUTABLE_PARAMS) { routableParams.remove(param); } } String collection = nonRoutableParams.get(UpdateParams.COLLECTION, defaultCollection); if (collection == null) { throw new SolrServerException( "No collection param specified on request and no default collection has been set."); } // Check to see if the collection is an alias. Aliases aliases = zkStateReader.getAliases(); if (aliases != null) { Map<String, String> collectionAliases = aliases.getCollectionAliasMap(); if (collectionAliases != null && collectionAliases.containsKey(collection)) { collection = collectionAliases.get(collection); } } DocCollection col = getDocCollection(clusterState, collection); DocRouter router = col.getRouter(); if (router instanceof ImplicitDocRouter) { // short circuit as optimization return null; } // Create the URL map, which is keyed on slice name. // The value is a list of URLs for each replica in the slice. // The first value in the list is the leader for the slice. Map<String, List<String>> urlMap = buildUrlMap(col); if (urlMap == null) { // we could not find a leader yet - use unoptimized general path return null; } NamedList<Throwable> exceptions = new NamedList<>(); NamedList<NamedList> shardResponses = new NamedList<>(); Map<String, LBHttpSolrServer.Req> routes = updateRequest.getRoutes(router, col, urlMap, routableParams, this.idField); if (routes == null) { return null; } long start = System.nanoTime(); if (parallelUpdates) { final Map<String, Future<NamedList<?>>> responseFutures = new HashMap<>(routes.size()); for (final Map.Entry<String, LBHttpSolrServer.Req> entry : routes.entrySet()) { final String url = entry.getKey(); final LBHttpSolrServer.Req lbRequest = entry.getValue(); responseFutures.put( url, threadPool.submit( new Callable<NamedList<?>>() { @Override public NamedList<?> call() throws Exception { return lbServer.request(lbRequest).getResponse(); } })); } for (final Map.Entry<String, Future<NamedList<?>>> entry : responseFutures.entrySet()) { final String url = entry.getKey(); final Future<NamedList<?>> responseFuture = entry.getValue(); try { shardResponses.add(url, responseFuture.get()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { exceptions.add(url, e.getCause()); } } if (exceptions.size() > 0) { throw new RouteException(ErrorCode.SERVER_ERROR, exceptions, routes); } } else { for (Map.Entry<String, LBHttpSolrServer.Req> entry : routes.entrySet()) { String url = entry.getKey(); LBHttpSolrServer.Req lbRequest = entry.getValue(); try { NamedList<Object> rsp = lbServer.request(lbRequest).getResponse(); shardResponses.add(url, rsp); } catch (Exception e) { throw new SolrServerException(e); } } } UpdateRequest nonRoutableRequest = null; List<String> deleteQuery = updateRequest.getDeleteQuery(); if (deleteQuery != null && deleteQuery.size() > 0) { UpdateRequest deleteQueryRequest = new UpdateRequest(); deleteQueryRequest.setDeleteQuery(deleteQuery); nonRoutableRequest = deleteQueryRequest; } Set<String> paramNames = nonRoutableParams.getParameterNames(); Set<String> intersection = new HashSet<>(paramNames); intersection.retainAll(NON_ROUTABLE_PARAMS); if (nonRoutableRequest != null || intersection.size() > 0) { if (nonRoutableRequest == null) { nonRoutableRequest = new UpdateRequest(); } nonRoutableRequest.setParams(nonRoutableParams); List<String> urlList = new ArrayList<>(); urlList.addAll(routes.keySet()); Collections.shuffle(urlList, rand); LBHttpSolrServer.Req req = new LBHttpSolrServer.Req(nonRoutableRequest, urlList); try { LBHttpSolrServer.Rsp rsp = lbServer.request(req); shardResponses.add(urlList.get(0), rsp.getResponse()); } catch (Exception e) { throw new SolrException(ErrorCode.SERVER_ERROR, urlList.get(0), e); } } long end = System.nanoTime(); RouteResponse rr = condenseResponse(shardResponses, (long) ((end - start) / 1000000)); rr.setRouteResponses(shardResponses); rr.setRoutes(routes); return rr; }
public int createSubRequests(ResponseBuilder rb) throws IOException { SolrParams params = rb.req.getParams(); String id1[] = params.getParams("id"); String ids[] = params.getParams("ids"); if (id1 == null && ids == null) { return ResponseBuilder.STAGE_DONE; } List<String> allIds = new ArrayList<String>(); if (id1 != null) { for (String s : id1) { allIds.add(s); } } if (ids != null) { for (String s : ids) { allIds.addAll(StrUtils.splitSmart(s, ",", true)); } } // TODO: handle collection=...? ZkController zkController = rb.req.getCore().getCoreDescriptor().getCoreContainer().getZkController(); // if shards=... then use that if (zkController != null && params.get("shards") == null) { CloudDescriptor cloudDescriptor = rb.req.getCore().getCoreDescriptor().getCloudDescriptor(); String collection = cloudDescriptor.getCollectionName(); ClusterState clusterState = zkController.getClusterState(); DocCollection coll = clusterState.getCollection(collection); Map<String, List<String>> sliceToId = new HashMap<String, List<String>>(); for (String id : allIds) { Slice slice = coll.getRouter().getTargetSlice(id, null, params, coll); List<String> idsForShard = sliceToId.get(slice.getName()); if (idsForShard == null) { idsForShard = new ArrayList<String>(2); sliceToId.put(slice.getName(), idsForShard); } idsForShard.add(id); } for (Map.Entry<String, List<String>> entry : sliceToId.entrySet()) { String shard = entry.getKey(); String shardIdList = StrUtils.join(entry.getValue(), ','); ShardRequest sreq = new ShardRequest(); sreq.purpose = 1; // sreq.shards = new String[]{shard}; // TODO: would be nice if this would work... sreq.shards = sliceToShards(rb, collection, shard); sreq.actualShards = sreq.shards; sreq.params = new ModifiableSolrParams(); sreq.params.set( ShardParams.SHARDS_QT, "/get"); // TODO: how to avoid hardcoding this and hit the same handler? sreq.params.set("distrib", false); sreq.params.set("ids", shardIdList); rb.addRequest(this, sreq); } } else { String shardIdList = StrUtils.join(allIds, ','); ShardRequest sreq = new ShardRequest(); sreq.purpose = 1; sreq.shards = null; // ALL sreq.actualShards = sreq.shards; sreq.params = new ModifiableSolrParams(); sreq.params.set( ShardParams.SHARDS_QT, "/get"); // TODO: how to avoid hardcoding this and hit the same handler? sreq.params.set("distrib", false); sreq.params.set("ids", shardIdList); rb.addRequest(this, sreq); } return ResponseBuilder.STAGE_DONE; }