LCOV - code coverage report
Current view: top level - server/update - ChainedReceiveCommands.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 33 38 86.8 %
Date: 2022-11-19 15:00:39 Functions: 8 10 80.0 %

          Line data    Source code
       1             : // Copyright (C) 2016 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.update;
      16             : 
      17             : import static com.google.common.base.Preconditions.checkArgument;
      18             : import static java.util.Objects.requireNonNull;
      19             : 
      20             : import com.google.gerrit.server.git.RefCache;
      21             : import com.google.gerrit.server.git.RepoRefCache;
      22             : import java.io.IOException;
      23             : import java.util.Collections;
      24             : import java.util.LinkedHashMap;
      25             : import java.util.Map;
      26             : import java.util.Optional;
      27             : import org.eclipse.jgit.lib.BatchRefUpdate;
      28             : import org.eclipse.jgit.lib.ObjectId;
      29             : import org.eclipse.jgit.lib.Repository;
      30             : import org.eclipse.jgit.transport.ReceiveCommand;
      31             : 
      32             : /**
      33             :  * Collection of {@link ReceiveCommand}s that supports multiple updates per ref.
      34             :  *
      35             :  * <p>The underlying behavior of {@link BatchRefUpdate} is undefined (an implementations vary) when
      36             :  * more than one command per ref is added. This class works around that limitation by allowing
      37             :  * multiple updates per ref, as long as the previous new SHA-1 matches the next old SHA-1.
      38             :  */
      39             : public class ChainedReceiveCommands implements RefCache {
      40         110 :   private final Map<String, ReceiveCommand> commands = new LinkedHashMap<>();
      41             :   private final RepoRefCache refCache;
      42             :   private final boolean closeRefCache;
      43             : 
      44             :   public ChainedReceiveCommands(Repository repo) {
      45         110 :     this(new RepoRefCache(repo), true);
      46         110 :   }
      47             : 
      48             :   public ChainedReceiveCommands(RepoRefCache refCache) {
      49           0 :     this(refCache, false);
      50           0 :   }
      51             : 
      52         110 :   private ChainedReceiveCommands(RepoRefCache refCache, boolean closeRefCache) {
      53         110 :     this.refCache = requireNonNull(refCache);
      54         110 :     this.closeRefCache = closeRefCache;
      55         110 :   }
      56             : 
      57             :   public RepoRefCache getRepoRefCache() {
      58          59 :     return refCache;
      59             :   }
      60             : 
      61             :   public boolean isEmpty() {
      62         110 :     return commands.isEmpty();
      63             :   }
      64             : 
      65             :   /**
      66             :    * Add a command.
      67             :    *
      68             :    * @param cmd command to add. If a command has been previously added for the same ref, the new
      69             :    *     SHA-1 of the most recent previous command must match the old SHA-1 of this command.
      70             :    */
      71             :   public void add(ReceiveCommand cmd) {
      72         109 :     checkArgument(!cmd.getOldId().equals(cmd.getNewId()), "ref update is a no-op: %s", cmd);
      73         109 :     ReceiveCommand old = commands.get(cmd.getRefName());
      74         109 :     if (old == null) {
      75         109 :       commands.put(cmd.getRefName(), cmd);
      76         109 :       return;
      77             :     }
      78           9 :     checkArgument(
      79           9 :         old.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED,
      80             :         "cannot chain ref update %s after update %s with result %s",
      81             :         cmd,
      82             :         old,
      83           9 :         old.getResult());
      84           9 :     checkArgument(
      85           9 :         cmd.getOldId().equals(old.getNewId()),
      86             :         "cannot chain ref update %s after update %s with different new ID",
      87             :         cmd,
      88             :         old);
      89           9 :     commands.put(
      90           9 :         cmd.getRefName(), new ReceiveCommand(old.getOldId(), cmd.getNewId(), cmd.getRefName()));
      91           9 :   }
      92             : 
      93             :   /**
      94             :    * Get the latest value of a ref according to this sequence of commands.
      95             :    *
      96             :    * <p>After the value for a ref is read from the repo once, it is cached as in {@link
      97             :    * RepoRefCache}.
      98             :    *
      99             :    * @see RefCache#get(String)
     100             :    */
     101             :   @Override
     102             :   public Optional<ObjectId> get(String refName) throws IOException {
     103         103 :     ReceiveCommand cmd = commands.get(refName);
     104         103 :     if (cmd != null) {
     105         103 :       return !cmd.getNewId().equals(ObjectId.zeroId())
     106         103 :           ? Optional.of(cmd.getNewId())
     107          12 :           : Optional.empty();
     108             :     }
     109         103 :     return refCache.get(refName);
     110             :   }
     111             : 
     112             :   /**
     113             :    * Add commands from this instance to a native JGit batch update.
     114             :    *
     115             :    * <p>Exactly one command per ref will be added to the update. The old SHA-1 will be the old SHA-1
     116             :    * of the first command added to this instance for that ref; the new SHA-1 will be the new SHA-1
     117             :    * of the last command.
     118             :    *
     119             :    * @param bru batch update
     120             :    */
     121             :   public void addTo(BatchRefUpdate bru) {
     122         109 :     for (ReceiveCommand cmd : commands.values()) {
     123         109 :       bru.addCommand(cmd);
     124         109 :     }
     125         109 :   }
     126             : 
     127             :   /** Returns an unmodifiable view of commands. */
     128             :   public Map<String, ReceiveCommand> getCommands() {
     129         110 :     return Collections.unmodifiableMap(commands);
     130             :   }
     131             : 
     132             :   @Override
     133             :   public void close() {
     134           0 :     if (closeRefCache) {
     135           0 :       refCache.close();
     136             :     }
     137           0 :   }
     138             : }

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