LCOV - code coverage report
Current view: top level - server/group - PeriodicGroupIndexer.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 46 51 90.2 %
Date: 2022-11-19 15:00:39 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2018 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.group;
      16             : 
      17             : import static com.google.common.collect.ImmutableSet.toImmutableSet;
      18             : 
      19             : import com.google.common.collect.ImmutableSet;
      20             : import com.google.common.collect.Sets;
      21             : import com.google.common.flogger.FluentLogger;
      22             : import com.google.gerrit.entities.AccountGroup;
      23             : import com.google.gerrit.entities.GroupReference;
      24             : import com.google.gerrit.extensions.events.LifecycleListener;
      25             : import com.google.gerrit.lifecycle.LifecycleModule;
      26             : import com.google.gerrit.server.config.AllUsersName;
      27             : import com.google.gerrit.server.config.GerritServerConfig;
      28             : import com.google.gerrit.server.config.ScheduleConfig;
      29             : import com.google.gerrit.server.config.ScheduleConfig.Schedule;
      30             : import com.google.gerrit.server.git.GitRepositoryManager;
      31             : import com.google.gerrit.server.git.WorkQueue;
      32             : import com.google.gerrit.server.group.db.GroupNameNotes;
      33             : import com.google.gerrit.server.index.group.GroupIndexer;
      34             : import com.google.inject.Inject;
      35             : import com.google.inject.Provider;
      36             : import java.util.concurrent.TimeUnit;
      37             : import org.eclipse.jgit.lib.Config;
      38             : import org.eclipse.jgit.lib.Repository;
      39             : 
      40             : /**
      41             :  * Runnable to schedule periodic group reindexing.
      42             :  *
      43             :  * <p>Periodic group indexing is intended to run only on slaves. Replication to slaves happens on
      44             :  * Git level so that Gerrit is not aware of incoming replication events. But slaves need an updated
      45             :  * group index to resolve memberships of users for ACL validation. To keep the group index in slaves
      46             :  * up-to-date this class periodically scans the group refs in the All-Users repository to reindex
      47             :  * groups if they are stale. The ref states of the group refs are cached so that on each run deleted
      48             :  * groups can be detected and reindexed. This means callers of slaves may observe outdated group
      49             :  * information until the next indexing happens. The interval on which group indexing is done is
      50             :  * configurable by setting {@code index.scheduledIndexer.interval} in {@code gerrit.config}. By
      51             :  * default group indexing is done every 5 minutes.
      52             :  *
      53             :  * <p>This class is not able to detect group deletions that were replicated while the slave was
      54             :  * offline. This means if group refs are deleted while the slave is offline these groups are not
      55             :  * removed from the group index when the slave is started. However since group deletion is not
      56             :  * supported this should never happen and one can always do an offline reindex before starting the
      57             :  * slave.
      58             :  */
      59             : public class PeriodicGroupIndexer implements Runnable {
      60           4 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      61             : 
      62           4 :   public static class PeriodicGroupIndexerModule extends LifecycleModule {
      63             :     @Override
      64             :     protected void configure() {
      65           4 :       listener().to(Lifecycle.class);
      66           4 :     }
      67             :   }
      68             : 
      69             :   private static class Lifecycle implements LifecycleListener {
      70             :     private final Config cfg;
      71             :     private final WorkQueue queue;
      72             :     private final PeriodicGroupIndexer runner;
      73             : 
      74             :     @Inject
      75           4 :     Lifecycle(@GerritServerConfig Config cfg, WorkQueue queue, PeriodicGroupIndexer runner) {
      76           4 :       this.cfg = cfg;
      77           4 :       this.queue = queue;
      78           4 :       this.runner = runner;
      79           4 :     }
      80             : 
      81             :     @Override
      82             :     public void start() {
      83           4 :       boolean runOnStartup = cfg.getBoolean("index", "scheduledIndexer", "runOnStartup", true);
      84           4 :       if (runOnStartup) {
      85           4 :         runner.run();
      86             :       }
      87             : 
      88           4 :       boolean isEnabled = cfg.getBoolean("index", "scheduledIndexer", "enabled", true);
      89           4 :       if (!isEnabled) {
      90           1 :         logger.atWarning().log("index.scheduledIndexer is disabled");
      91           1 :         return;
      92             :       }
      93             : 
      94           4 :       Schedule schedule =
      95           4 :           ScheduleConfig.builder(cfg, "index")
      96           4 :               .setSubsection("scheduledIndexer")
      97           4 :               .buildSchedule()
      98           4 :               .orElseGet(() -> Schedule.createOrFail(TimeUnit.MINUTES.toMillis(5), "00:00"));
      99           4 :       queue.scheduleAtFixedRate(runner, schedule);
     100           4 :     }
     101             : 
     102             :     @Override
     103             :     public void stop() {
     104             :       // handled by WorkQueue.stop() already
     105           4 :     }
     106             :   }
     107             : 
     108             :   private final AllUsersName allUsersName;
     109             :   private final GitRepositoryManager repoManager;
     110             :   private final Provider<GroupIndexer> groupIndexerProvider;
     111             : 
     112             :   private ImmutableSet<AccountGroup.UUID> groupUuids;
     113             : 
     114             :   @Inject
     115             :   PeriodicGroupIndexer(
     116             :       AllUsersName allUsersName,
     117             :       GitRepositoryManager repoManager,
     118           4 :       Provider<GroupIndexer> groupIndexerProvider) {
     119           4 :     this.allUsersName = allUsersName;
     120           4 :     this.repoManager = repoManager;
     121           4 :     this.groupIndexerProvider = groupIndexerProvider;
     122           4 :   }
     123             : 
     124             :   @Override
     125             :   public synchronized void run() {
     126           4 :     try (Repository allUsers = repoManager.openRepository(allUsersName)) {
     127           4 :       ImmutableSet<AccountGroup.UUID> newGroupUuids =
     128           4 :           GroupNameNotes.loadAllGroups(allUsers).stream()
     129           4 :               .map(GroupReference::getUUID)
     130           4 :               .collect(toImmutableSet());
     131           4 :       GroupIndexer groupIndexer = groupIndexerProvider.get();
     132           4 :       int reindexCounter = 0;
     133           4 :       for (AccountGroup.UUID groupUuid : newGroupUuids) {
     134           4 :         if (groupIndexer.reindexIfStale(groupUuid)) {
     135           4 :           reindexCounter++;
     136             :         }
     137           4 :       }
     138           4 :       if (groupUuids != null) {
     139             :         // Check if any group was deleted since the last run and if yes remove these groups from the
     140             :         // index.
     141           1 :         for (AccountGroup.UUID groupUuid : Sets.difference(groupUuids, newGroupUuids)) {
     142           0 :           groupIndexer.index(groupUuid);
     143           0 :           reindexCounter++;
     144           0 :         }
     145             :       }
     146           4 :       groupUuids = newGroupUuids;
     147           4 :       logger.atInfo().log("Run group indexer, %s groups reindexed", reindexCounter);
     148           0 :     } catch (Exception t) {
     149           0 :       logger.atSevere().withCause(t).log("Failed to reindex groups");
     150           4 :     }
     151           4 :   }
     152             : }

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