LCOV - code coverage report
Current view: top level - server/group/db - RenameGroupOp.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 37 58 63.8 %
Date: 2022-11-19 15:00:39 Functions: 4 5 80.0 %

          Line data    Source code
       1             : // Copyright (C) 2011 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.db;
      16             : 
      17             : import static com.google.gerrit.server.project.ProjectCache.illegalState;
      18             : 
      19             : import com.google.common.flogger.FluentLogger;
      20             : import com.google.gerrit.entities.AccountGroup;
      21             : import com.google.gerrit.entities.CachedProjectConfig;
      22             : import com.google.gerrit.entities.GroupReference;
      23             : import com.google.gerrit.entities.Project;
      24             : import com.google.gerrit.server.git.DefaultQueueOp;
      25             : import com.google.gerrit.server.git.WorkQueue;
      26             : import com.google.gerrit.server.git.meta.MetaDataUpdate;
      27             : import com.google.gerrit.server.project.ProjectCache;
      28             : import com.google.gerrit.server.project.ProjectConfig;
      29             : import com.google.inject.Inject;
      30             : import com.google.inject.assistedinject.Assisted;
      31             : import java.io.IOException;
      32             : import java.util.ArrayList;
      33             : import java.util.List;
      34             : import java.util.Optional;
      35             : import java.util.concurrent.Future;
      36             : import java.util.concurrent.TimeUnit;
      37             : import org.eclipse.jgit.errors.ConfigInvalidException;
      38             : import org.eclipse.jgit.errors.RepositoryNotFoundException;
      39             : import org.eclipse.jgit.lib.PersonIdent;
      40             : 
      41             : class RenameGroupOp extends DefaultQueueOp {
      42           3 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      43             : 
      44             :   interface Factory {
      45             :     RenameGroupOp create(
      46             :         @Assisted("author") PersonIdent author,
      47             :         @Assisted AccountGroup.UUID uuid,
      48             :         @Assisted("oldName") String oldName,
      49             :         @Assisted("newName") String newName);
      50             :   }
      51             : 
      52             :   private static final int MAX_TRIES = 10;
      53             : 
      54             :   private final ProjectCache projectCache;
      55             :   private final MetaDataUpdate.Server metaDataUpdateFactory;
      56             :   private final ProjectConfig.Factory projectConfigFactory;
      57             : 
      58             :   private final PersonIdent author;
      59             :   private final AccountGroup.UUID uuid;
      60             :   private final String oldName;
      61             :   private final String newName;
      62             :   private final List<Project.NameKey> retryOn;
      63             : 
      64             :   private boolean tryingAgain;
      65             : 
      66             :   @Inject
      67             :   public RenameGroupOp(
      68             :       WorkQueue workQueue,
      69             :       ProjectCache projectCache,
      70             :       MetaDataUpdate.Server metaDataUpdateFactory,
      71             :       ProjectConfig.Factory projectConfigFactory,
      72             :       @Assisted("author") PersonIdent author,
      73             :       @Assisted AccountGroup.UUID uuid,
      74             :       @Assisted("oldName") String oldName,
      75             :       @Assisted("newName") String newName) {
      76           3 :     super(workQueue);
      77           3 :     this.projectCache = projectCache;
      78           3 :     this.metaDataUpdateFactory = metaDataUpdateFactory;
      79           3 :     this.projectConfigFactory = projectConfigFactory;
      80             : 
      81           3 :     this.author = author;
      82           3 :     this.uuid = uuid;
      83           3 :     this.oldName = oldName;
      84           3 :     this.newName = newName;
      85           3 :     this.retryOn = new ArrayList<>();
      86           3 :   }
      87             : 
      88             :   @Override
      89             :   public void run() {
      90           3 :     Iterable<Project.NameKey> names = tryingAgain ? retryOn : projectCache.all();
      91           3 :     for (Project.NameKey projectName : names) {
      92           3 :       CachedProjectConfig config =
      93           3 :           projectCache.get(projectName).orElseThrow(illegalState(projectName)).getConfig();
      94           3 :       Optional<GroupReference> ref = config.getGroup(uuid);
      95           3 :       if (!ref.isPresent() || newName.equals(ref.get().getName())) {
      96           0 :         continue;
      97             :       }
      98             : 
      99           1 :       try (MetaDataUpdate md = metaDataUpdateFactory.create(projectName)) {
     100           1 :         rename(md);
     101           0 :       } catch (RepositoryNotFoundException noProject) {
     102           0 :         continue;
     103           0 :       } catch (ConfigInvalidException | IOException err) {
     104           0 :         logger.atSevere().withCause(err).log("Cannot rename group %s in %s", oldName, projectName);
     105           1 :       }
     106           1 :     }
     107             : 
     108             :     // If one or more projects did not update, wait 5 minutes and give it
     109             :     // another attempt. If it doesn't update after that, give up.
     110           3 :     if (!retryOn.isEmpty() && !tryingAgain) {
     111           0 :       tryingAgain = true;
     112             :       @SuppressWarnings("unused")
     113           0 :       Future<?> possiblyIgnoredError = start(5, TimeUnit.MINUTES);
     114             :     }
     115           3 :   }
     116             : 
     117             :   private void rename(MetaDataUpdate md) throws IOException, ConfigInvalidException {
     118           1 :     boolean success = false;
     119           1 :     for (int attempts = 0; !success && attempts < MAX_TRIES; attempts++) {
     120           1 :       ProjectConfig config = projectConfigFactory.read(md);
     121             : 
     122             :       // The group isn't referenced, or its name has been fixed already.
     123             :       //
     124           1 :       GroupReference ref = config.getGroup(uuid);
     125           1 :       if (ref == null || newName.equals(ref.getName())) {
     126           0 :         projectCache.evictAndReindex(config.getProject());
     127           0 :         return;
     128             :       }
     129             : 
     130           1 :       config.renameGroup(uuid, newName);
     131           1 :       md.getCommitBuilder().setAuthor(author);
     132           1 :       md.setMessage("Rename group " + oldName + " to " + newName + "\n");
     133             :       try {
     134           1 :         config.commit(md);
     135           1 :         projectCache.evictAndReindex(config.getProject());
     136           1 :         success = true;
     137           0 :       } catch (IOException e) {
     138           0 :         logger.atSevere().withCause(e).log(
     139             :             "Could not commit rename of group %s to %s in %s",
     140           0 :             oldName, newName, md.getProjectName().get());
     141             :         try {
     142           0 :           Thread.sleep(25 /* milliseconds */);
     143           0 :         } catch (InterruptedException wakeUp) {
     144           0 :           continue;
     145           0 :         }
     146           1 :       }
     147             :     }
     148             : 
     149           1 :     if (!success) {
     150           0 :       if (tryingAgain) {
     151           0 :         logger.atWarning().log(
     152           0 :             "Could not rename group %s to %s in %s", oldName, newName, md.getProjectName().get());
     153             :       } else {
     154           0 :         retryOn.add(md.getProjectName());
     155             :       }
     156             :     }
     157           1 :   }
     158             : 
     159             :   @Override
     160             :   public String toString() {
     161           0 :     return "Rename Group " + oldName;
     162             :   }
     163             : }

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