Line data Source code
1 : // Copyright (C) 2022 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.schema; 16 : 17 : import com.google.common.base.Stopwatch; 18 : import com.google.common.collect.Iterables; 19 : import com.google.common.collect.Sets; 20 : import com.google.gerrit.entities.Project; 21 : import com.google.gerrit.server.git.GitRepositoryManager; 22 : import com.google.gerrit.server.project.ProjectConfig; 23 : import java.io.IOException; 24 : import java.io.UncheckedIOException; 25 : import java.util.List; 26 : import java.util.NavigableSet; 27 : import java.util.Set; 28 : import java.util.concurrent.ExecutorService; 29 : import java.util.concurrent.Executors; 30 : import java.util.concurrent.Future; 31 : import java.util.concurrent.TimeUnit; 32 : import java.util.concurrent.atomic.AtomicInteger; 33 : import org.eclipse.jgit.errors.ConfigInvalidException; 34 : import org.eclipse.jgit.lib.PersonIdent; 35 : 36 : /** 37 : * Migrates the label configurations of all projects to copy conditions. 38 : * 39 : * @see MigrateLabelConfigToCopyCondition 40 : */ 41 2 : public class Schema_185 implements NoteDbSchemaVersion { 42 2 : private AtomicInteger i = new AtomicInteger(); 43 2 : private Stopwatch sw = Stopwatch.createStarted(); 44 : private int size; 45 : 46 : @Override 47 : public void upgrade(Arguments args, UpdateUI ui) throws Exception { 48 1 : ui.message("Migrating label configurations"); 49 : 50 1 : NavigableSet<Project.NameKey> projects = args.repoManager.list(); 51 1 : size = projects.size(); 52 : 53 1 : Set<List<Project.NameKey>> batches = Sets.newHashSet(Iterables.partition(projects, 50)); 54 1 : ExecutorService pool = createExecutor(ui); 55 : try { 56 1 : batches.stream() 57 1 : .forEach( 58 : batch -> { 59 : @SuppressWarnings("unused") 60 1 : Future<?> possiblyIgnoredError = 61 1 : pool.submit(() -> processBatch(args.repoManager, args.serverUser, batch, ui)); 62 1 : }); 63 1 : pool.shutdown(); 64 1 : pool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 65 0 : } catch (InterruptedException e) { 66 0 : throw new RuntimeException(e); 67 1 : } 68 1 : ui.message( 69 1 : String.format( 70 : "... (%.3f s) Migrated label configurations of all %d projects to schema 185", 71 1 : elapsed(), i.get())); 72 1 : } 73 : 74 : private ExecutorService createExecutor(UpdateUI ui) { 75 : int threads; 76 : try { 77 0 : threads = Integer.parseInt(System.getProperty("threadcount")); 78 1 : } catch (NumberFormatException e) { 79 1 : threads = Runtime.getRuntime().availableProcessors(); 80 0 : } 81 1 : ui.message(String.format("... using %d threads ...", threads)); 82 1 : return Executors.newFixedThreadPool(threads); 83 : } 84 : 85 : private void processBatch( 86 : GitRepositoryManager repoManager, 87 : PersonIdent serverUser, 88 : List<Project.NameKey> batch, 89 : UpdateUI ui) { 90 : try { 91 1 : for (Project.NameKey project : batch) { 92 : try { 93 1 : new MigrateLabelConfigToCopyCondition(repoManager, serverUser).execute(project); 94 1 : int count = i.incrementAndGet(); 95 1 : showProgress(ui, count); 96 1 : } catch (ConfigInvalidException e) { 97 1 : ui.message( 98 1 : String.format( 99 : "WARNING: Skipping migration of label configurations for project %s" 100 : + " since its %s file is invalid: %s", 101 1 : project, ProjectConfig.PROJECT_CONFIG, e.getMessage())); 102 1 : } 103 1 : } 104 0 : } catch (IOException e) { 105 0 : throw new UncheckedIOException( 106 0 : String.format("Failed to migrate batch of projects to schema 185: %s", batch), e); 107 1 : } 108 1 : } 109 : 110 : private double elapsed() { 111 1 : return sw.elapsed(TimeUnit.MILLISECONDS) / 1000d; 112 : } 113 : 114 : private void showProgress(UpdateUI ui, int count) { 115 1 : if (count % 100 == 0) { 116 1 : ui.message( 117 1 : String.format( 118 : "... (%.3f s) migrated label configurations of %d%% (%d/%d) projects", 119 1 : elapsed(), Math.round(100.0 * count / size), count, size)); 120 : } 121 1 : } 122 : }