LCOV - code coverage report
Current view: top level - server/index/change - ReindexAfterRefUpdate.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 51 59 86.4 %
Date: 2022-11-19 15:00:39 Functions: 9 12 75.0 %

          Line data    Source code
       1             : // Copyright (C) 2014 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.util.concurrent.MoreExecutors.directExecutor;
      18             : import static com.google.gerrit.server.query.change.ChangeData.asChanges;
      19             : 
      20             : import com.google.common.flogger.FluentLogger;
      21             : import com.google.common.util.concurrent.FutureCallback;
      22             : import com.google.common.util.concurrent.Futures;
      23             : import com.google.common.util.concurrent.ListeningExecutorService;
      24             : import com.google.gerrit.entities.Account;
      25             : import com.google.gerrit.entities.BranchNameKey;
      26             : import com.google.gerrit.entities.Change;
      27             : import com.google.gerrit.entities.Project;
      28             : import com.google.gerrit.entities.RefNames;
      29             : import com.google.gerrit.extensions.events.GitBatchRefUpdateListener;
      30             : import com.google.gerrit.server.change.MergeabilityComputationBehavior;
      31             : import com.google.gerrit.server.config.AllUsersName;
      32             : import com.google.gerrit.server.config.GerritServerConfig;
      33             : import com.google.gerrit.server.git.QueueProvider.QueueType;
      34             : import com.google.gerrit.server.index.IndexExecutor;
      35             : import com.google.gerrit.server.index.account.AccountIndexer;
      36             : import com.google.gerrit.server.query.change.InternalChangeQuery;
      37             : import com.google.gerrit.server.util.ManualRequestContext;
      38             : import com.google.gerrit.server.util.OneOffRequestContext;
      39             : import com.google.gerrit.server.util.RequestContext;
      40             : import com.google.inject.Inject;
      41             : import com.google.inject.Provider;
      42             : import java.util.List;
      43             : import java.util.concurrent.Callable;
      44             : import java.util.concurrent.Future;
      45             : import org.eclipse.jgit.lib.Config;
      46             : 
      47             : /**
      48             :  * Listener for ref update events that reindexes entities in case the updated Git reference was used
      49             :  * to compute contents of an index document.
      50             :  *
      51             :  * <p>Reindexes any open changes that has a destination branch that was updated to ensure that
      52             :  * 'mergeable' is still current.
      53             :  *
      54             :  * <p>Will reindex accounts when the account's NoteDb ref changes.
      55             :  */
      56             : public class ReindexAfterRefUpdate implements GitBatchRefUpdateListener {
      57         151 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      58             : 
      59             :   private final OneOffRequestContext requestContext;
      60             :   private final Provider<InternalChangeQuery> queryProvider;
      61             :   private final ChangeIndexer.Factory indexerFactory;
      62             :   private final ChangeIndexCollection indexes;
      63             :   private final AllUsersName allUsersName;
      64             :   private final Provider<AccountIndexer> indexer;
      65             :   private final ListeningExecutorService executor;
      66             :   private final boolean enabled;
      67             : 
      68             :   @Inject
      69             :   ReindexAfterRefUpdate(
      70             :       @GerritServerConfig Config cfg,
      71             :       OneOffRequestContext requestContext,
      72             :       Provider<InternalChangeQuery> queryProvider,
      73             :       ChangeIndexer.Factory indexerFactory,
      74             :       ChangeIndexCollection indexes,
      75             :       AllUsersName allUsersName,
      76             :       Provider<AccountIndexer> indexer,
      77         151 :       @IndexExecutor(QueueType.BATCH) ListeningExecutorService executor) {
      78         151 :     this.requestContext = requestContext;
      79         151 :     this.queryProvider = queryProvider;
      80         151 :     this.indexerFactory = indexerFactory;
      81         151 :     this.indexes = indexes;
      82         151 :     this.allUsersName = allUsersName;
      83         151 :     this.indexer = indexer;
      84         151 :     this.executor = executor;
      85         151 :     this.enabled = MergeabilityComputationBehavior.fromConfig(cfg).includeInIndex();
      86         151 :   }
      87             : 
      88             :   @Override
      89             :   public void onGitBatchRefUpdate(GitBatchRefUpdateListener.Event event) {
      90         151 :     if (allUsersName.get().equals(event.getProjectName())) {
      91         151 :       for (UpdatedRef ref : event.getUpdatedRefs()) {
      92         151 :         if (!RefNames.REFS_CONFIG.equals(ref.getRefName())) {
      93         151 :           if (ref.getRefName().startsWith(RefNames.REFS_STARRED_CHANGES)) {
      94          10 :             break;
      95             :           }
      96         151 :           Account.Id accountId = Account.Id.fromRef(ref.getRefName());
      97         151 :           if (accountId != null) {
      98         151 :             indexer.get().index(accountId);
      99             :           }
     100             :         }
     101         151 :       }
     102             :       // The update is in All-Users and not on refs/meta/config. So it's not a change. Return early.
     103         151 :       return;
     104             :     }
     105             : 
     106         145 :     for (UpdatedRef ref : event.getUpdatedRefs()) {
     107         145 :       if (!enabled
     108          14 :           || ref.getRefName().startsWith(RefNames.REFS_CHANGES)
     109          14 :           || ref.getRefName().startsWith(RefNames.REFS_DRAFT_COMMENTS)
     110          14 :           || ref.getRefName().startsWith(RefNames.REFS_USERS)) {
     111           0 :         continue;
     112             :       }
     113          14 :       Futures.addCallback(
     114          14 :           executor.submit(new GetChanges(event.getProjectName(), ref)),
     115          14 :           new FutureCallback<List<Change>>() {
     116             :             @Override
     117             :             public void onSuccess(List<Change> changes) {
     118          14 :               for (Change c : changes) {
     119             :                 @SuppressWarnings("unused")
     120          11 :                 Future<?> possiblyIgnoredError =
     121          11 :                     indexerFactory.create(executor, indexes).indexAsync(c.getProject(), c.getId());
     122          11 :               }
     123          14 :             }
     124             : 
     125             :             @Override
     126             :             public void onFailure(Throwable ignored) {
     127             :               // Logged by {@link GetChanges#call()}.
     128           0 :             }
     129             :           },
     130          14 :           directExecutor());
     131          14 :     }
     132         145 :   }
     133             : 
     134             :   private abstract class Task<V> implements Callable<V> {
     135             :     protected UpdatedRef updatedRef;
     136             : 
     137          14 :     protected Task(UpdatedRef updatedRef) {
     138          14 :       this.updatedRef = updatedRef;
     139          14 :     }
     140             : 
     141             :     @Override
     142             :     public final V call() throws Exception {
     143          14 :       try (ManualRequestContext ctx = requestContext.open()) {
     144          14 :         return impl(ctx);
     145           0 :       } catch (Exception e) {
     146           0 :         logger.atSevere().withCause(e).log("Failed to reindex changes after %s", updatedRef);
     147           0 :         throw e;
     148             :       }
     149             :     }
     150             : 
     151             :     protected abstract V impl(RequestContext ctx) throws Exception;
     152             : 
     153             :     protected abstract void remove();
     154             :   }
     155             : 
     156             :   private class GetChanges extends Task<List<Change>> {
     157             :     protected String projectName;
     158             : 
     159          14 :     private GetChanges(String projectName, UpdatedRef updatedRef) {
     160          14 :       super(updatedRef);
     161          14 :       this.projectName = projectName;
     162          14 :     }
     163             : 
     164             :     @Override
     165             :     protected List<Change> impl(RequestContext ctx) {
     166          14 :       String ref = updatedRef.getRefName();
     167          14 :       Project.NameKey project = Project.nameKey(projectName);
     168          14 :       if (ref.equals(RefNames.REFS_CONFIG)) {
     169          14 :         return asChanges(queryProvider.get().byProjectOpen(project));
     170             :       }
     171          14 :       return asChanges(queryProvider.get().byBranchNew(BranchNameKey.create(project, ref)));
     172             :     }
     173             : 
     174             :     @Override
     175             :     public String toString() {
     176           0 :       return "Get changes to reindex caused by "
     177           0 :           + updatedRef.getRefName()
     178             :           + " update of project "
     179             :           + projectName;
     180             :     }
     181             : 
     182             :     @Override
     183           0 :     protected void remove() {}
     184             :   }
     185             : }

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