|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.gitblit.utils;
-
- import java.text.MessageFormat;
- import java.util.ArrayList;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.TimeUnit;
-
- import org.eclipse.jgit.lib.ObjectId;
- import org.eclipse.jgit.lib.Repository;
- import org.eclipse.jgit.revwalk.RevCommit;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import com.gitblit.models.RefModel;
- import com.gitblit.models.RepositoryCommit;
-
- /**
- * Caches repository commits for re-use in the dashboard and activity pages.
- *
- * @author James Moger
- *
- */
- public class CommitCache {
-
- private static final CommitCache instance;
-
- protected final Logger logger = LoggerFactory.getLogger(getClass());
-
- protected final Map<String, ObjectCache<List<RepositoryCommit>>> cache;
-
- protected int cacheDays = -1;
-
- public static CommitCache instance() {
- return instance;
- }
-
- static {
- instance = new CommitCache();
- }
-
- protected CommitCache() {
- cache = new ConcurrentHashMap<String, ObjectCache<List<RepositoryCommit>>>();
- }
-
- /**
- * Returns the cutoff date for the cache. Commits after this date are cached.
- * Commits before this date are not cached.
- *
- * @return
- */
- public Date getCutoffDate() {
- final Calendar cal = Calendar.getInstance();
- cal.setTimeInMillis(System.currentTimeMillis());
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- cal.set(Calendar.MILLISECOND, 0);
- cal.add(Calendar.DATE, -1*cacheDays);
- return cal.getTime();
- }
-
- /**
- * Sets the number of days to cache.
- *
- * @param days
- */
- public synchronized void setCacheDays(int days) {
- this.cacheDays = days;
- clear();
- }
-
- /**
- * Clears the entire commit cache.
- *
- */
- public void clear() {
- cache.clear();
- }
-
- /**
- * Clears the commit cache for a specific repository.
- *
- * @param repositoryName
- */
- public void clear(String repositoryName) {
- String repoKey = repositoryName.toLowerCase();
- ObjectCache<List<RepositoryCommit>> repoCache = cache.remove(repoKey);
- if (repoCache != null) {
- logger.info(MessageFormat.format("{0} commit cache cleared", repositoryName));
- }
- }
-
- /**
- * Clears the commit cache for a specific branch of a specific repository.
- *
- * @param repositoryName
- * @param branch
- */
- public void clear(String repositoryName, String branch) {
- String repoKey = repositoryName.toLowerCase();
- ObjectCache<List<RepositoryCommit>> repoCache = cache.get(repoKey);
- if (repoCache != null) {
- List<RepositoryCommit> commits = repoCache.remove(branch.toLowerCase());
- if (!ArrayUtils.isEmpty(commits)) {
- logger.info(MessageFormat.format("{0}:{1} commit cache cleared", repositoryName, branch));
- }
- }
- }
-
- /**
- * Get all commits for the specified repository:branch that are in the cache.
- *
- * @param repositoryName
- * @param repository
- * @param branch
- * @return a list of commits
- */
- public List<RepositoryCommit> getCommits(String repositoryName, Repository repository, String branch) {
- return getCommits(repositoryName, repository, branch, getCutoffDate());
- }
-
- /**
- * Get all commits for the specified repository:branch since a specific date.
- * These commits may be retrieved from the cache if the sinceDate is after
- * the cacheCutoffDate.
- *
- * @param repositoryName
- * @param repository
- * @param branch
- * @param sinceDate
- * @return a list of commits
- */
- public List<RepositoryCommit> getCommits(String repositoryName, Repository repository, String branch, Date sinceDate) {
- long start = System.nanoTime();
- Date cacheCutoffDate = getCutoffDate();
- List<RepositoryCommit> list;
- if (cacheDays > 0 && (sinceDate.getTime() >= cacheCutoffDate.getTime())) {
- // request fits within the cache window
- String repoKey = repositoryName.toLowerCase();
- if (!cache.containsKey(repoKey)) {
- cache.put(repoKey, new ObjectCache<List<RepositoryCommit>>());
- }
-
- ObjectCache<List<RepositoryCommit>> repoCache = cache.get(repoKey);
- String branchKey = branch.toLowerCase();
-
- RevCommit tip = JGitUtils.getCommit(repository, branch);
- Date tipDate = JGitUtils.getCommitDate(tip);
-
- List<RepositoryCommit> commits;
- if (!repoCache.hasCurrent(branchKey, tipDate)) {
- commits = repoCache.getObject(branchKey);
- if (ArrayUtils.isEmpty(commits)) {
- // we don't have any cached commits for this branch, reload
- commits = get(repositoryName, repository, branch, cacheCutoffDate);
- repoCache.updateObject(branchKey, tipDate, commits);
- logger.debug(MessageFormat.format("parsed {0} commits from {1}:{2} since {3,date,yyyy-MM-dd} in {4} msecs",
- commits.size(), repositoryName, branch, cacheCutoffDate, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
- } else {
- // incrementally update cache since the last cached commit
- ObjectId sinceCommit = commits.get(0).getId();
- List<RepositoryCommit> incremental = get(repositoryName, repository, branch, sinceCommit);
- logger.info(MessageFormat.format("incrementally added {0} commits to cache for {1}:{2} in {3} msecs",
- incremental.size(), repositoryName, branch, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
- incremental.addAll(commits);
- repoCache.updateObject(branchKey, tipDate, incremental);
- commits = incremental;
- }
- } else {
- // cache is current
- commits = repoCache.getObject(branchKey);
- // evict older commits outside the cache window
- commits = reduce(commits, cacheCutoffDate);
- // update cache
- repoCache.updateObject(branchKey, tipDate, commits);
- }
-
- if (sinceDate.equals(cacheCutoffDate)) {
- list = commits;
- } else {
- // reduce the commits to those since the specified date
- list = reduce(commits, sinceDate);
- }
- logger.debug(MessageFormat.format("retrieved {0} commits from cache of {1}:{2} since {3,date,yyyy-MM-dd} in {4} msecs",
- list.size(), repositoryName, branch, sinceDate, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
- } else {
- // not caching or request outside cache window
- list = get(repositoryName, repository, branch, sinceDate);
- logger.debug(MessageFormat.format("parsed {0} commits from {1}:{2} since {3,date,yyyy-MM-dd} in {4} msecs",
- list.size(), repositoryName, branch, sinceDate, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
- }
- return list;
- }
-
- /**
- * Returns a list of commits for the specified repository branch.
- *
- * @param repositoryName
- * @param repository
- * @param branch
- * @param sinceDate
- * @return a list of commits
- */
- protected List<RepositoryCommit> get(String repositoryName, Repository repository, String branch, Date sinceDate) {
- Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository, false);
- List<RepositoryCommit> commits = new ArrayList<RepositoryCommit>();
- for (RevCommit commit : JGitUtils.getRevLog(repository, branch, sinceDate)) {
- RepositoryCommit commitModel = new RepositoryCommit(repositoryName, branch, commit);
- commitModel.setRefs(allRefs.get(commitModel.getName()));
- commits.add(commitModel);
- }
- return commits;
- }
-
- /**
- * Returns a list of commits for the specified repository branch since the specified commit.
- *
- * @param repositoryName
- * @param repository
- * @param branch
- * @param sinceCommit
- * @return a list of commits
- */
- protected List<RepositoryCommit> get(String repositoryName, Repository repository, String branch, ObjectId sinceCommit) {
- Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository, false);
- List<RepositoryCommit> commits = new ArrayList<RepositoryCommit>();
- for (RevCommit commit : JGitUtils.getRevLog(repository, sinceCommit.getName(), branch)) {
- RepositoryCommit commitModel = new RepositoryCommit(repositoryName, branch, commit);
- commitModel.setRefs(allRefs.get(commitModel.getName()));
- commits.add(commitModel);
- }
- return commits;
- }
-
- /**
- * Reduces the list of commits to those since the specified date.
- *
- * @param commits
- * @param sinceDate
- * @return a list of commits
- */
- protected List<RepositoryCommit> reduce(List<RepositoryCommit> commits, Date sinceDate) {
- List<RepositoryCommit> filtered = new ArrayList<RepositoryCommit>();
- for (RepositoryCommit commit : commits) {
- if (commit.getCommitDate().compareTo(sinceDate) >= 0) {
- filtered.add(commit);
- }
- }
- return filtered;
- }
- }
|