1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
/*
* Copyright (C) 2022, Tencent.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.internal.storage.file;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.commitgraph.CommitGraphFormatException;
import org.eclipse.jgit.internal.storage.commitgraph.CommitGraphLoader;
import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph;
import org.eclipse.jgit.lib.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Traditional file system for commit-graph.
* <p>
* This is the commit-graph file representation for a Git object database. Each
* call to {@link FileCommitGraph#get()} will recheck for newer versions.
*/
public class FileCommitGraph {
private final static Logger LOG = LoggerFactory
.getLogger(FileCommitGraph.class);
private final AtomicReference<GraphSnapshot> baseGraph;
/**
* Initialize a reference to an on-disk commit-graph.
*
* @param objectsDir
* the location of the <code>objects</code> directory.
*/
FileCommitGraph(File objectsDir) {
this.baseGraph = new AtomicReference<>(new GraphSnapshot(
new File(objectsDir, Constants.INFO_COMMIT_GRAPH)));
}
/**
* The method will first scan whether the ".git/objects/info/commit-graph"
* has been modified, if so, it will re-parse the file, otherwise it will
* return the same result as the last time.
*
* @return commit-graph or null if commit-graph file does not exist or
* corrupt.
*/
CommitGraph get() {
GraphSnapshot original = baseGraph.get();
synchronized (baseGraph) {
GraphSnapshot o, n;
do {
o = baseGraph.get();
if (o != original) {
// Another thread did the scan for us, while we
// were blocked on the monitor above.
//
return o.getCommitGraph();
}
n = o.refresh();
if (n == o) {
return n.getCommitGraph();
}
} while (!baseGraph.compareAndSet(o, n));
return n.getCommitGraph();
}
}
private static final class GraphSnapshot {
private final File file;
private final FileSnapshot snapshot;
private final CommitGraph graph;
GraphSnapshot(@NonNull File file) {
this(file, null, null);
}
GraphSnapshot(@NonNull File file, FileSnapshot snapshot,
CommitGraph graph) {
this.file = file;
this.snapshot = snapshot;
this.graph = graph;
}
CommitGraph getCommitGraph() {
return graph;
}
GraphSnapshot refresh() {
if (graph == null && !file.exists()) {
// commit-graph file didn't exist
return this;
}
if (snapshot != null && !snapshot.isModified(file)) {
// commit-graph file was not modified
return this;
}
return new GraphSnapshot(file, FileSnapshot.save(file),
open(file));
}
private static CommitGraph open(File file) {
try {
return CommitGraphLoader.open(file);
} catch (FileNotFoundException noFile) {
// ignore if file do not exist
return null;
} catch (IOException e) {
if (e instanceof CommitGraphFormatException) {
LOG.warn(
MessageFormat.format(
JGitText.get().corruptCommitGraph, file),
e);
} else {
LOG.error(MessageFormat.format(
JGitText.get().exceptionWhileLoadingCommitGraph,
file), e);
}
return null;
}
}
}
}
|