1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.linecorp.centraldogma.server.internal.storage.repository.git;
18
19 import static java.util.Objects.requireNonNull;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.concurrent.Executor;
24 import java.util.concurrent.TimeUnit;
25 import java.util.function.BiConsumer;
26 import java.util.function.Supplier;
27
28 import javax.annotation.Nullable;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.linecorp.armeria.common.util.TextFormatter;
34 import com.linecorp.centraldogma.common.Author;
35 import com.linecorp.centraldogma.common.CentralDogmaException;
36 import com.linecorp.centraldogma.common.RepositoryExistsException;
37 import com.linecorp.centraldogma.common.RepositoryNotFoundException;
38 import com.linecorp.centraldogma.internal.Util;
39 import com.linecorp.centraldogma.server.internal.storage.DirectoryBasedStorageManager;
40 import com.linecorp.centraldogma.server.internal.storage.repository.RepositoryCache;
41 import com.linecorp.centraldogma.server.storage.project.Project;
42 import com.linecorp.centraldogma.server.storage.repository.Repository;
43 import com.linecorp.centraldogma.server.storage.repository.RepositoryManager;
44
45 public class GitRepositoryManager extends DirectoryBasedStorageManager<Repository>
46 implements RepositoryManager {
47
48 private static final Logger logger = LoggerFactory.getLogger(GitRepositoryManager.class);
49
50 private final Project parent;
51 private final Executor repositoryWorker;
52
53 @Nullable
54 private final RepositoryCache cache;
55
56 public GitRepositoryManager(Project parent, File rootDir, Executor repositoryWorker,
57 Executor purgeWorker, @Nullable RepositoryCache cache) {
58 super(rootDir, Repository.class, purgeWorker);
59 this.parent = requireNonNull(parent, "parent");
60 this.repositoryWorker = requireNonNull(repositoryWorker, "repositoryWorker");
61 this.cache = cache;
62 init();
63 }
64
65 @Override
66 public Project parent() {
67 return parent;
68 }
69
70 @Override
71 protected Repository openChild(File childDir) throws Exception {
72 return new GitRepository(parent, childDir, repositoryWorker, cache);
73 }
74
75 private static void deleteCruft(File dir) throws IOException {
76 logger.info("Deleting the cruft from previous migration: {}", dir);
77 Util.deleteFileTree(dir);
78 logger.info("Deleted the cruft from previous migration: {}", dir);
79 }
80
81 @Override
82 protected Repository createChild(File childDir, Author author, long creationTimeMillis) throws Exception {
83 return new GitRepository(parent, childDir, repositoryWorker,
84 creationTimeMillis, author, cache);
85 }
86
87 @Override
88 protected void closeChild(File childDir, Repository child,
89 Supplier<CentralDogmaException> failureCauseSupplier) {
90 ((GitRepository) child).close(failureCauseSupplier);
91 }
92
93 @Override
94 protected CentralDogmaException newStorageExistsException(String name) {
95 return new RepositoryExistsException(parent().name() + '/' + name);
96 }
97
98 @Override
99 protected CentralDogmaException newStorageNotFoundException(String name) {
100 return new RepositoryNotFoundException(parent().name() + '/' + name);
101 }
102
103
104
105
106 private static class MigrationProgressLogger implements BiConsumer<Integer, Integer> {
107
108 private static final long REPORT_INTERVAL_NANOS = TimeUnit.SECONDS.toNanos(10);
109
110 private final String name;
111 private final long startTimeNanos;
112 private long lastReportTimeNanos;
113
114 MigrationProgressLogger(Repository repo) {
115 name = repo.parent().name() + '/' + repo.name();
116 startTimeNanos = lastReportTimeNanos = System.nanoTime();
117 }
118
119 @Override
120 public void accept(Integer current, Integer total) {
121 final long currentTimeNanos = System.nanoTime();
122 final long elapsedTimeNanos = currentTimeNanos - startTimeNanos;
123 if (currentTimeNanos - lastReportTimeNanos > REPORT_INTERVAL_NANOS) {
124 logger.info("{}: {}% ({}/{}) - took {}",
125 name, (int) ((double) current / total * 100),
126 current, total, TextFormatter.elapsed(elapsedTimeNanos));
127 lastReportTimeNanos = currentTimeNanos;
128 } else if (current.equals(total)) {
129 logger.info("{}: 100% ({}/{}) - took {}",
130 name, current, total,
131 TextFormatter.elapsed(elapsedTimeNanos));
132 }
133 }
134 }
135 }