xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/history/BoundaryChangesets.java (revision 1ac922307dfc3e74934e9f7289af210d162ebaf0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
22  */
23 package org.opengrok.indexer.history;
24 
25 import org.jetbrains.annotations.TestOnly;
26 import org.opengrok.indexer.configuration.RuntimeEnvironment;
27 import org.opengrok.indexer.logger.LoggerFactory;
28 import org.opengrok.indexer.util.Statistics;
29 
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 
36 /**
37  * Helper class to split sequence of VCS changesets into number of intervals.
38  * This is then used in {@link Repository#createCache(HistoryCache, String)}
39  * to store history in chunks, for VCS repositories that support this.
40  */
41 public class BoundaryChangesets {
42     private int cnt = 0;
43     private final List<String> result = new ArrayList<>();
44 
45     private final int maxCount;
46     private final RepositoryWithPerPartesHistory repository;
47 
48     private static final Logger LOGGER = LoggerFactory.getLogger(BoundaryChangesets.class);
49 
BoundaryChangesets(RepositoryWithPerPartesHistory repository)50     public BoundaryChangesets(RepositoryWithPerPartesHistory repository) {
51         this.repository = repository;
52 
53         int globalPerPartesCount = RuntimeEnvironment.getInstance().getHistoryChunkCount();
54         if (globalPerPartesCount > 0) {
55             this.maxCount = globalPerPartesCount;
56         } else {
57             this.maxCount = repository.getPerPartesCount();
58         }
59         if (maxCount <= 1) {
60             throw new RuntimeException(String.format("per partes count for repository ''%s'' " +
61                     "must be strictly greater than 1", repository.getDirectoryName()));
62         }
63         LOGGER.log(Level.FINER, "using history cache chunks with {0} entries for repository {1}",
64                 new Object[]{this.maxCount, repository});
65     }
66 
reset()67     private void reset() {
68         cnt = 0;
69         result.clear();
70     }
71 
72     @TestOnly
getMaxCount()73     int getMaxCount() {
74         return maxCount;
75     }
76 
77     /**
78      * @param sinceRevision start revision ID
79      * @return immutable list of revision IDs denoting the intervals
80      * @throws HistoryException if there is problem traversing the changesets in the repository
81      */
getBoundaryChangesetIDs(String sinceRevision)82     public synchronized List<String> getBoundaryChangesetIDs(String sinceRevision) throws HistoryException {
83         reset();
84 
85         LOGGER.log(Level.FINE, "getting boundary changesets for ''{0}''", repository.getDirectoryName());
86         Statistics stat = new Statistics();
87 
88         repository.accept(sinceRevision, this::visit);
89 
90         // The changesets need to go from oldest to newest.
91         Collections.reverse(result);
92 
93         stat.report(LOGGER, Level.FINE,
94                 String.format("Done getting boundary changesets for ''%s'' (%d entries)",
95                         repository.getDirectoryName(), result.size()));
96 
97         return List.copyOf(result);
98     }
99 
visit(String id)100     private void visit(String id) {
101         if (cnt != 0 && cnt % maxCount == 0) {
102             result.add(id);
103         }
104         cnt++;
105     }
106 }
107