LCOV - code coverage report
Current view: top level - server/index/change - IndexedChangeQuery.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 46 51 90.2 %
Date: 2022-11-19 15:00:39 Functions: 13 16 81.2 %

          Line data    Source code
       1             : // Copyright (C) 2013 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.index.change;
      16             : 
      17             : import static com.google.common.base.Preconditions.checkState;
      18             : import static com.google.gerrit.server.index.change.ChangeField.CHANGE;
      19             : import static com.google.gerrit.server.index.change.ChangeField.PROJECT_SPEC;
      20             : 
      21             : import com.google.common.annotations.VisibleForTesting;
      22             : import com.google.common.collect.ImmutableList;
      23             : import com.google.common.collect.ImmutableSet;
      24             : import com.google.common.collect.Iterables;
      25             : import com.google.gerrit.entities.Change;
      26             : import com.google.gerrit.index.IndexConfig;
      27             : import com.google.gerrit.index.QueryOptions;
      28             : import com.google.gerrit.index.query.DataSource;
      29             : import com.google.gerrit.index.query.IndexPredicate;
      30             : import com.google.gerrit.index.query.IndexedQuery;
      31             : import com.google.gerrit.index.query.Matchable;
      32             : import com.google.gerrit.index.query.Predicate;
      33             : import com.google.gerrit.index.query.QueryParseException;
      34             : import com.google.gerrit.index.query.ResultSet;
      35             : import com.google.gerrit.server.query.change.ChangeData;
      36             : import com.google.gerrit.server.query.change.ChangeDataSource;
      37             : import com.google.gerrit.server.query.change.ChangeIndexPostFilterPredicate;
      38             : import java.util.HashMap;
      39             : import java.util.HashSet;
      40             : import java.util.Iterator;
      41             : import java.util.Map;
      42             : import java.util.Set;
      43             : 
      44             : /**
      45             :  * Wrapper combining an {@link IndexPredicate} together with a {@link ChangeDataSource} that returns
      46             :  * matching results from the index.
      47             :  *
      48             :  * <p>Appropriate to return as the rootmost predicate that can be processed using the secondary
      49             :  * index; such predicates must also implement {@link ChangeDataSource} to be chosen by the query
      50             :  * processor.
      51             :  */
      52             : public class IndexedChangeQuery extends IndexedQuery<Change.Id, ChangeData>
      53             :     implements ChangeDataSource, Matchable<ChangeData> {
      54             :   public static QueryOptions oneResult() {
      55           0 :     IndexConfig config = IndexConfig.createDefault();
      56           0 :     return createOptions(config, 0, 1, config.pageSizeMultiplier(), 1, ImmutableSet.of());
      57             :   }
      58             : 
      59             :   public static QueryOptions createOptions(
      60             :       IndexConfig config, int start, int limit, Set<String> fields) {
      61           6 :     return createOptions(config, start, limit, config.pageSizeMultiplier(), limit, fields);
      62             :   }
      63             : 
      64             :   public static QueryOptions createOptions(
      65             :       IndexConfig config,
      66             :       int start,
      67             :       int pageSize,
      68             :       int pageSizeMultiplier,
      69             :       int limit,
      70             :       Set<String> fields) {
      71             :     // Always include project since it is needed to load the change from NoteDb.
      72         111 :     if (!fields.contains(CHANGE.getName()) && !fields.contains(PROJECT_SPEC.getName())) {
      73          91 :       fields = new HashSet<>(fields);
      74          91 :       fields.add(PROJECT_SPEC.getName());
      75             :     }
      76         111 :     return QueryOptions.create(config, start, pageSize, pageSizeMultiplier, limit, fields);
      77             :   }
      78             : 
      79             :   @VisibleForTesting
      80             :   static QueryOptions convertOptions(QueryOptions opts) {
      81         111 :     opts = opts.convertForBackend();
      82         111 :     return IndexedChangeQuery.createOptions(
      83         111 :         opts.config(),
      84         111 :         opts.start(),
      85         111 :         opts.pageSize(),
      86         111 :         opts.pageSizeMultiplier(),
      87         111 :         opts.limit(),
      88         111 :         opts.fields());
      89             :   }
      90             : 
      91             :   private final Map<ChangeData, DataSource<ChangeData>> fromSource;
      92             : 
      93             :   public IndexedChangeQuery(ChangeIndex index, Predicate<ChangeData> pred, QueryOptions opts)
      94             :       throws QueryParseException {
      95         111 :     super(index, pred, convertOptions(opts));
      96         111 :     this.fromSource = new HashMap<>();
      97         111 :   }
      98             : 
      99             :   @Override
     100             :   public ResultSet<ChangeData> read() {
     101         111 :     final DataSource<ChangeData> currSource = source;
     102         111 :     final ResultSet<ChangeData> rs = currSource.read();
     103             : 
     104         111 :     return new ResultSet<>() {
     105             :       @Override
     106             :       public Iterator<ChangeData> iterator() {
     107         109 :         return Iterables.transform(
     108             :                 rs,
     109             :                 cd -> {
     110          97 :                   fromSource.put(cd, currSource);
     111          97 :                   return cd;
     112             :                 })
     113         109 :             .iterator();
     114             :       }
     115             : 
     116             :       @Override
     117             :       public ImmutableList<ChangeData> toList() {
     118          84 :         ImmutableList<ChangeData> r = rs.toList();
     119          84 :         for (ChangeData cd : r) {
     120          80 :           fromSource.put(cd, currSource);
     121          80 :         }
     122          84 :         return r;
     123             :       }
     124             : 
     125             :       @Override
     126             :       public void close() {
     127           0 :         rs.close();
     128           0 :       }
     129             : 
     130             :       @Override
     131             :       public Object searchAfter() {
     132          97 :         return rs.searchAfter();
     133             :       }
     134             :     };
     135             :   }
     136             : 
     137             :   public boolean postIndexMatch(Predicate<ChangeData> pred, ChangeData cd) {
     138          75 :     if (pred instanceof ChangeIndexPostFilterPredicate) {
     139           9 :       checkState(
     140           9 :           pred.isMatchable(),
     141             :           "match invoked, but child predicate %s doesn't implement %s",
     142             :           pred,
     143           9 :           Matchable.class.getName());
     144           9 :       return pred.asMatchable().match(cd);
     145             :     }
     146          75 :     for (int i = 0; i < pred.getChildCount(); i++) {
     147          71 :       if (!postIndexMatch(pred.getChild(i), cd)) {
     148           9 :         return false;
     149             :       }
     150             :     }
     151          75 :     return true;
     152             :   }
     153             : 
     154             :   @Override
     155             :   public boolean match(ChangeData cd) {
     156          75 :     Predicate<ChangeData> pred = getChild(0);
     157          75 :     if (source != null && fromSource.get(cd) == source && postIndexMatch(pred, cd)) {
     158          75 :       return true;
     159             :     }
     160             : 
     161           9 :     checkState(
     162           9 :         pred.isMatchable(),
     163             :         "match invoked, but child predicate %s doesn't implement %s",
     164             :         pred,
     165           9 :         Matchable.class.getName());
     166           9 :     return pred.asMatchable().match(cd);
     167             :   }
     168             : 
     169             :   @Override
     170             :   public int getCost() {
     171             :     // Index queries are assumed to be cheaper than any other type of query, so
     172             :     // so try to make sure they get picked. Note that pred's cost may be higher
     173             :     // because it doesn't know whether it's being used in an index query or not.
     174         103 :     return 1;
     175             :   }
     176             : 
     177             :   @Override
     178             :   public boolean hasChange() {
     179           0 :     return index.getSchema().hasField(ChangeField.CHANGE);
     180             :   }
     181             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750