public void process()

in solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java [117:378]


  public void process(ResponseBuilder rb) throws IOException {
    SolrQueryRequest req = rb.req;
    SolrQueryResponse rsp = rb.rsp;
    SolrParams params = req.getParams();
    CloudDescriptor cloudDesc = req.getCore().getCoreDescriptor().getCloudDescriptor();

    if (cloudDesc != null) {
      Replica.Type replicaType = cloudDesc.getReplicaType();
      if (replicaType != null) {
        if (replicaType == Replica.Type.PULL) {
          throw new SolrException(
              ErrorCode.BAD_REQUEST,
              String.format(
                  Locale.ROOT,
                  "%s can't handle realtime get requests. Replicas of type %s do not support these type of requests",
                  cloudDesc.getCoreNodeName(),
                  Replica.Type.PULL));
        }
        // non-leader TLOG replicas should not respond to distrib /get requests, but internal
        // requests are OK
      }
    }

    if (!params.getBool(COMPONENT_NAME, true)) {
      return;
    }

    // TODO remove this at Solr 10
    // After SOLR-14641 other nodes won't call RTG with this param.
    // Just keeping here for backward-compatibility, if we remove this, nodes with older versions
    // will assume that this node can't handle version ranges.
    String val = params.get("checkCanHandleVersionRanges");
    if (val != null) {
      rb.rsp.add("canHandleVersionRanges", true);
      return;
    }

    val = params.get("getFingerprint");
    if (val != null) {
      processGetFingeprint(rb);
      return;
    }

    val = params.get("getVersions");
    if (val != null) {
      processGetVersions(rb);
      return;
    }

    val = params.get("getUpdates");
    if (val != null) {
      // solrcloud_debug
      if (log.isDebugEnabled()) {
        try {
          RefCounted<SolrIndexSearcher> searchHolder = req.getCore().getNewestSearcher(false);
          SolrIndexSearcher searcher = searchHolder.get();
          try {
            if (log.isDebugEnabled()) {
              log.debug(
                  "{} min count to sync to (from most recent searcher view) {}",
                  req.getCoreContainer().getZkController().getNodeName(),
                  searcher.count(new MatchAllDocsQuery()));
            }
          } finally {
            searchHolder.decref();
          }
        } catch (Exception e) {
          log.debug("Error in solrcloud_debug block", e);
        }
      }

      processGetUpdates(rb);
      return;
    }

    val = params.get("getInputDocument");
    if (val != null) {
      processGetInputDocument(rb);
      return;
    }

    final IdsRequested reqIds = IdsRequested.parseParams(req);

    if (reqIds.allIds.isEmpty()) {
      return;
    }

    // parse any existing filters
    try {
      String[] fqs = req.getParams().getParams(CommonParams.FQ);
      if (fqs != null && fqs.length != 0) {
        List<Query> filters = rb.getFilters();
        // if filters already exists, make a copy instead of modifying the original
        filters = filters == null ? new ArrayList<>(fqs.length) : new ArrayList<>(filters);
        filters.addAll(QueryUtils.parseFilterQueries(req));
        if (!filters.isEmpty()) {
          rb.setFilters(filters);
        }
      }
    } catch (SyntaxError e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
    }

    final SolrCore core = req.getCore();
    SchemaField idField = core.getLatestSchema().getUniqueKeyField();
    FieldType fieldType = idField.getType();

    SolrDocumentList docList = new SolrDocumentList();
    UpdateLog ulog = core.getUpdateHandler().getUpdateLog();

    SearcherInfo searcherInfo = new SearcherInfo(core);

    // this is initialized & set on the context *after* any searcher (re-)opening
    ResultContext resultContext = null;
    final DocTransformer transformer = rsp.getReturnFields().getTransformer();

    // true in any situation where we have to use a realtime searcher rather then returning docs
    // directly from the UpdateLog
    final boolean mustUseRealtimeSearcher =
        // if we have filters, we need to check those against the indexed form of the doc
        (rb.getFilters() != null)
            || ((null != transformer) && transformer.needsSolrIndexSearcher());

    try {

      boolean opennedRealtimeSearcher = false;
      BytesRefBuilder idBytes = new BytesRefBuilder();
      DocValuesIteratorCache reuseDvIters = null;
      for (String idStr : reqIds.allIds) {
        fieldType.readableToIndexed(idStr, idBytes);
        // if _route_ is passed, id is a child doc.  TODO remove in SOLR-15064
        if (!opennedRealtimeSearcher && !params.get(ShardParams._ROUTE_, idStr).equals(idStr)) {
          searcherInfo.clear();
          resultContext = null;
          ulog.openRealtimeSearcher(); // force open a new realtime searcher
          opennedRealtimeSearcher = true;
        } else if (ulog != null) {
          Object o = ulog.lookup(idBytes.get());
          if (o != null) {
            // should currently be a List<Oper,Ver,Doc/Id>
            List<?> entry = (List<?>) o;
            assert entry.size() >= 3;
            int oper = (Integer) entry.get(UpdateLog.FLAGS_IDX) & UpdateLog.OPERATION_MASK;
            switch (oper) {
              case UpdateLog.UPDATE_INPLACE: // fall through to ADD
              case UpdateLog.ADD:
                if (mustUseRealtimeSearcher) {
                  // close handles to current searchers & result context
                  if (!opennedRealtimeSearcher) {
                    searcherInfo.clear();
                    resultContext = null;
                    ulog.openRealtimeSearcher(); // force open a new realtime searcher
                    opennedRealtimeSearcher = true;
                  }
                  // pretend we never found this record and fall through to use the searcher
                  o = null;
                  break;
                }

                SolrDocument doc;
                if (oper == UpdateLog.ADD) {
                  doc =
                      toSolrDoc(
                          (SolrInputDocument) entry.get(entry.size() - 1), core.getLatestSchema());
                  // toSolrDoc filtered copy-field targets already
                  if (transformer != null) {
                    transformer.transform(doc, -1, DocIterationInfo.NONE); // unknown docID
                  }
                } else if (oper == UpdateLog.UPDATE_INPLACE) {
                  assert entry.size() == 5;
                  // For in-place update case, we have obtained the partial document till now. We
                  // need to resolve it to a full document to be returned to the user.
                  // resolveFullDocument applies the transformer, if present.
                  doc =
                      resolveFullDocument(
                          core,
                          idBytes.get(),
                          rsp.getReturnFields(),
                          (SolrInputDocument) entry.get(entry.size() - 1),
                          entry);
                  if (doc == null) {
                    break; // document has been deleted as the resolve was going on
                  }
                  doc.visitSelfAndNestedDocs(
                      (label, d) -> removeCopyFieldTargets(d, req.getSchema()));
                } else {
                  throw new SolrException(
                      ErrorCode.INVALID_STATE, "Expected ADD or UPDATE_INPLACE. Got: " + oper);
                }

                docList.add(doc);
                break;
              case UpdateLog.DELETE:
                break;
              default:
                throw new SolrException(
                    SolrException.ErrorCode.SERVER_ERROR, "Unknown Operation! " + oper);
            }
            if (o != null) continue;
          }
        }

        // didn't find it in the update log, so it should be in the newest searcher opened
        searcherInfo.init();
        // don't bother with ResultContext yet, we won't need it if doc doesn't match filters

        int docid = -1;
        long segAndId = searcherInfo.getSearcher().lookupId(idBytes.get());
        if (segAndId >= 0) {
          int segid = (int) segAndId;
          LeafReaderContext ctx =
              searcherInfo.getSearcher().getTopReaderContext().leaves().get((int) (segAndId >> 32));
          docid = segid + ctx.docBase;

          if (rb.getFilters() != null) {
            for (Query raw : rb.getFilters()) {
              raw = makeQueryable(raw);
              Query q = raw.rewrite(searcherInfo.getSearcher().getIndexReader());
              Scorer scorer =
                  searcherInfo
                      .getSearcher()
                      .createWeight(q, ScoreMode.COMPLETE_NO_SCORES, 1f)
                      .scorer(ctx);
              if (scorer == null || segid != scorer.iterator().advance(segid)) {
                // filter doesn't match.
                docid = -1;
                break;
              }
            }
          }
        }

        if (docid < 0) continue;

        SolrDocumentFetcher docFetcher = searcherInfo.getSearcher().getDocFetcher();
        Document luceneDocument =
            docFetcher.doc(docid, rsp.getReturnFields().getLuceneFieldNames());
        SolrDocument doc = toSolrDoc(luceneDocument, core.getLatestSchema());
        if (reuseDvIters == null) {
          reuseDvIters = new DocValuesIteratorCache(searcherInfo.getSearcher());
        }
        docFetcher.decorateDocValueFields(
            doc, docid, docFetcher.getNonStoredDVs(true), reuseDvIters);
        if (null != transformer) {
          if (null == resultContext) {
            // either first pass, or we've re-opened searcher - either way now we setContext
            resultContext =
                new RTGResultContext(rsp.getReturnFields(), searcherInfo.getSearcher(), req);
            transformer.setContext(
                resultContext); // we avoid calling setContext unless searcher is new/changed
          }
          transformer.transform(doc, docid, DocIterationInfo.NONE);
        }
        docList.add(doc);
      } // loop on ids

    } finally {
      searcherInfo.clear();
    }

    addDocListToResponse(rb, docList);
  }