* stable-5.1: Prepare 5.1.12-SNAPSHOT builds JGit v5.1.11.201909031202-r Prepare 4.11.10-SNAPSHOT builds JGit v4.11.9.201909030838-r Bazel: Update bazlets to the latest master revision Bazel: Remove FileTreeIteratorWithTimeControl from BUILD file BatchRefUpdate: repro racy atomic update, and fix it Delete unused FileTreeIteratorWithTimeControl Fix RacyGitTests#testRacyGitDetection Change RacyGitTests to create a racy git situation in a stable way Silence API warnings Change-Id: Iac5dc9683cea97db04d20f27c10f2e103d3ae7b5 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v5.3.5.201909031855-r
load("//tools:bazlets.bzl", "load_bazlets") | load("//tools:bazlets.bzl", "load_bazlets") | ||||
load_bazlets(commit = "8528a0df69dadf6311d8d3f81c1b693afda8bcf1") | |||||
load_bazlets(commit = "09a035e98077dce549d5f6a7472d06c4b8f792d2") | |||||
load( | load( | ||||
"@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", | "@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
<component id="org.eclipse.jgit.lfs.server" version="2"> | <component id="org.eclipse.jgit.lfs.server" version="2"> | ||||
<resource path="META-INF/MANIFEST.MF"> | |||||
<filter id="924844039"> | |||||
<message_arguments> | |||||
<message_argument value="5.2.3"/> | |||||
<message_argument value="5.2.0"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java" type="org.eclipse.jgit.lfs.server.fs.ObjectUploadListener"> | <resource path="src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java" type="org.eclipse.jgit.lfs.server.fs.ObjectUploadListener"> | ||||
<filter id="1142947843"> | <filter id="1142947843"> | ||||
<message_arguments> | <message_arguments> |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
<component id="org.eclipse.jgit.lfs" version="2"> | |||||
<resource path="META-INF/MANIFEST.MF"> | |||||
<filter id="924844039"> | |||||
<message_arguments> | |||||
<message_argument value="5.2.3"/> | |||||
<message_argument value="5.2.0"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
</component> |
package org.eclipse.jgit.internal.storage.file; | package org.eclipse.jgit.internal.storage.file; | ||||
import static java.nio.charset.StandardCharsets.UTF_8; | |||||
import static java.util.concurrent.TimeUnit.NANOSECONDS; | import static java.util.concurrent.TimeUnit.NANOSECONDS; | ||||
import static java.util.concurrent.TimeUnit.SECONDS; | import static java.util.concurrent.TimeUnit.SECONDS; | ||||
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.LOCK_FAILURE; | import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.LOCK_FAILURE; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.file.Files; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
refsChangedEvents = 0; | refsChangedEvents = 0; | ||||
} | } | ||||
@Test | |||||
public void packedRefsFileIsSorted() throws IOException { | |||||
assumeTrue(atomic); | |||||
for (int i = 0; i < 2; i++) { | |||||
BatchRefUpdate bu = diskRepo.getRefDatabase().newBatchUpdate(); | |||||
String b1 = String.format("refs/heads/a%d",i); | |||||
String b2 = String.format("refs/heads/b%d",i); | |||||
bu.setAtomic(atomic); | |||||
ReceiveCommand c1 = new ReceiveCommand(ObjectId.zeroId(), A, b1); | |||||
ReceiveCommand c2 = new ReceiveCommand(ObjectId.zeroId(), B, b2); | |||||
bu.addCommand(c1, c2); | |||||
try (RevWalk rw = new RevWalk(diskRepo)) { | |||||
bu.execute(rw, NullProgressMonitor.INSTANCE); | |||||
} | |||||
assertEquals(c1.getResult(), ReceiveCommand.Result.OK); | |||||
assertEquals(c2.getResult(), ReceiveCommand.Result.OK); | |||||
} | |||||
File packed = new File(diskRepo.getDirectory(), "packed-refs"); | |||||
String packedStr = new String(Files.readAllBytes(packed.toPath()), UTF_8); | |||||
int a2 = packedStr.indexOf("refs/heads/a1"); | |||||
int b1 = packedStr.indexOf("refs/heads/b0"); | |||||
assertTrue(a2 < b1); | |||||
} | |||||
@Test | @Test | ||||
public void simpleNoForce() throws IOException { | public void simpleNoForce() throws IOException { | ||||
writeLooseRef("refs/heads/master", A); | writeLooseRef("refs/heads/master", A); |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
<component id="org.eclipse.jgit" version="2"> | <component id="org.eclipse.jgit" version="2"> | ||||
<resource path="META-INF/MANIFEST.MF"> | |||||
<filter id="924844039"> | |||||
<message_arguments> | |||||
<message_argument value="5.2.3"/> | |||||
<message_argument value="5.2.0"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/dircache/DirCacheEntry.java" type="org.eclipse.jgit.dircache.DirCacheEntry"> | <resource path="src/org/eclipse/jgit/dircache/DirCacheEntry.java" type="org.eclipse.jgit.dircache.DirCacheEntry"> | ||||
<filter id="1142947843"> | <filter id="1142947843"> | ||||
<message_arguments> | <message_arguments> | ||||
</message_arguments> | </message_arguments> | ||||
</filter> | </filter> | ||||
</resource> | </resource> | ||||
<resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$DefaultRemoteReader"> | |||||
<filter id="338792546"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/> | |||||
<message_argument value="readFile(String, String, String)"/> | |||||
</message_arguments> | |||||
</filter> | |||||
<filter id="338792546"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/> | |||||
<message_argument value="readFileFromRepo(Repository, String, String)"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$RemoteReader"> | |||||
<filter id="403804204"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader"/> | |||||
<message_argument value="readFileWithMode(String, String, String)"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants"> | <resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants"> | ||||
<filter id="1142947843"> | <filter id="1142947843"> | ||||
<message_arguments> | <message_arguments> | ||||
</message_arguments> | </message_arguments> | ||||
</filter> | </filter> | ||||
</resource> | </resource> | ||||
<resource path="src/org/eclipse/jgit/lib/GitmoduleEntry.java" type="org.eclipse.jgit.lib.GitmoduleEntry"> | |||||
<filter id="1109393411"> | |||||
<message_arguments> | |||||
<message_argument value="4.7.5"/> | |||||
<message_argument value="org.eclipse.jgit.lib.GitmoduleEntry"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/lib/ObjectChecker.java" type="org.eclipse.jgit.lib.ObjectChecker"> | |||||
<filter id="1142947843"> | |||||
<message_arguments> | |||||
<message_argument value="4.7.5"/> | |||||
<message_argument value="getGitsubmodules()"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/revwalk/DepthWalk.java" type="org.eclipse.jgit.revwalk.DepthWalk"> | |||||
<filter id="403804204"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/> | |||||
<message_argument value="getDeepenNotFlag()"/> | |||||
</message_arguments> | |||||
</filter> | |||||
<filter id="404000815"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/> | |||||
<message_argument value="getDeepenNots()"/> | |||||
</message_arguments> | |||||
</filter> | |||||
<filter id="404000815"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/> | |||||
<message_argument value="getDeepenSince()"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/storage/pack/PackConfig.java" type="org.eclipse.jgit.storage.pack.PackConfig"> | <resource path="src/org/eclipse/jgit/storage/pack/PackConfig.java" type="org.eclipse.jgit.storage.pack.PackConfig"> | ||||
<filter id="336658481"> | <filter id="336658481"> | ||||
<message_arguments> | <message_arguments> | ||||
</message_arguments> | </message_arguments> | ||||
</filter> | </filter> | ||||
</resource> | </resource> | ||||
<resource path="src/org/eclipse/jgit/transport/RemoteSession.java" type="org.eclipse.jgit.transport.RemoteSession"> | |||||
<filter id="404000815"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.transport.RemoteSession"/> | |||||
<message_argument value="getFtpChannel()"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/transport/TransferConfig.java" type="org.eclipse.jgit.transport.TransferConfig"> | <resource path="src/org/eclipse/jgit/transport/TransferConfig.java" type="org.eclipse.jgit.transport.TransferConfig"> | ||||
<filter id="1159725059"> | <filter id="1159725059"> | ||||
<message_arguments> | <message_arguments> | ||||
</message_arguments> | </message_arguments> | ||||
</filter> | </filter> | ||||
</resource> | </resource> | ||||
<resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection"> | |||||
<filter id="403804204"> | |||||
<message_arguments> | |||||
<message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/> | |||||
<message_argument value="getHeaderFields(String)"/> | |||||
</message_arguments> | |||||
</filter> | |||||
</resource> | |||||
<resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator"> | <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator"> | ||||
<filter id="1142947843"> | <filter id="1142947843"> | ||||
<message_arguments> | <message_arguments> |
import java.io.IOException; | import java.io.IOException; | ||||
import java.text.MessageFormat; | import java.text.MessageFormat; | ||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.Comparator; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.LinkedHashMap; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
private static RefList<Ref> applyUpdates(RevWalk walk, RefList<Ref> refs, | private static RefList<Ref> applyUpdates(RevWalk walk, RefList<Ref> refs, | ||||
List<ReceiveCommand> commands) throws IOException { | List<ReceiveCommand> commands) throws IOException { | ||||
int nDeletes = 0; | |||||
List<ReceiveCommand> adds = new ArrayList<>(commands.size()); | |||||
// Construct a new RefList by merging the old list with the updates. | |||||
// This assumes that each ref occurs at most once as a ReceiveCommand. | |||||
Collections.sort(commands, new Comparator<ReceiveCommand>() { | |||||
@Override | |||||
public int compare(ReceiveCommand a, ReceiveCommand b) { | |||||
return a.getRefName().compareTo(b.getRefName()); | |||||
} | |||||
}); | |||||
int delta = 0; | |||||
for (ReceiveCommand c : commands) { | for (ReceiveCommand c : commands) { | ||||
if (c.getType() == ReceiveCommand.Type.CREATE) { | |||||
adds.add(c); | |||||
} else if (c.getType() == ReceiveCommand.Type.DELETE) { | |||||
nDeletes++; | |||||
switch (c.getType()) { | |||||
case DELETE: | |||||
delta--; | |||||
break; | |||||
case CREATE: | |||||
delta++; | |||||
break; | |||||
default: | |||||
} | } | ||||
} | } | ||||
int addIdx = 0; | |||||
// Construct a new RefList by linearly scanning the old list, and merging in | |||||
// any updates. | |||||
Map<String, ReceiveCommand> byName = byName(commands); | |||||
RefList.Builder<Ref> b = | |||||
new RefList.Builder<>(refs.size() - nDeletes + adds.size()); | |||||
for (Ref ref : refs) { | |||||
String name = ref.getName(); | |||||
ReceiveCommand cmd = byName.remove(name); | |||||
if (cmd == null) { | |||||
b.add(ref); | |||||
continue; | |||||
} | |||||
if (!cmd.getOldId().equals(ref.getObjectId())) { | |||||
lockFailure(cmd, commands); | |||||
return null; | |||||
RefList.Builder<Ref> b = new RefList.Builder<>(refs.size() + delta); | |||||
int refIdx = 0; | |||||
int cmdIdx = 0; | |||||
while (refIdx < refs.size() || cmdIdx < commands.size()) { | |||||
Ref ref = (refIdx < refs.size()) ? refs.get(refIdx) : null; | |||||
ReceiveCommand cmd = (cmdIdx < commands.size()) | |||||
? commands.get(cmdIdx) | |||||
: null; | |||||
int cmp = 0; | |||||
if (ref != null && cmd != null) { | |||||
cmp = ref.getName().compareTo(cmd.getRefName()); | |||||
} else if (ref == null) { | |||||
cmp = 1; | |||||
} else if (cmd == null) { | |||||
cmp = -1; | |||||
} | } | ||||
// Consume any adds between the last and current ref. | |||||
while (addIdx < adds.size()) { | |||||
ReceiveCommand currAdd = adds.get(addIdx); | |||||
if (currAdd.getRefName().compareTo(name) < 0) { | |||||
b.add(peeledRef(walk, currAdd)); | |||||
byName.remove(currAdd.getRefName()); | |||||
} else { | |||||
break; | |||||
if (cmp < 0) { | |||||
b.add(ref); | |||||
refIdx++; | |||||
} else if (cmp > 0) { | |||||
assert cmd != null; | |||||
if (cmd.getType() != ReceiveCommand.Type.CREATE) { | |||||
lockFailure(cmd, commands); | |||||
return null; | |||||
} | } | ||||
addIdx++; | |||||
} | |||||
if (cmd.getType() != ReceiveCommand.Type.DELETE) { | |||||
b.add(peeledRef(walk, cmd)); | b.add(peeledRef(walk, cmd)); | ||||
} | |||||
} | |||||
// All remaining adds are valid, since the refs didn't exist. | |||||
while (addIdx < adds.size()) { | |||||
ReceiveCommand cmd = adds.get(addIdx++); | |||||
byName.remove(cmd.getRefName()); | |||||
b.add(peeledRef(walk, cmd)); | |||||
} | |||||
cmdIdx++; | |||||
} else { | |||||
assert cmd != null; | |||||
assert ref != null; | |||||
if (!cmd.getOldId().equals(ref.getObjectId())) { | |||||
lockFailure(cmd, commands); | |||||
return null; | |||||
} | |||||
// Any remaining updates/deletes do not correspond to any existing refs, so | |||||
// they are lock failures. | |||||
if (!byName.isEmpty()) { | |||||
lockFailure(byName.values().iterator().next(), commands); | |||||
return null; | |||||
if (cmd.getType() != ReceiveCommand.Type.DELETE) { | |||||
b.add(peeledRef(walk, cmd)); | |||||
} | |||||
cmdIdx++; | |||||
refIdx++; | |||||
} | |||||
} | } | ||||
return b.toRefList(); | return b.toRefList(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private static Map<String, ReceiveCommand> byName( | |||||
List<ReceiveCommand> commands) { | |||||
Map<String, ReceiveCommand> ret = new LinkedHashMap<>(); | |||||
for (ReceiveCommand cmd : commands) { | |||||
ret.put(cmd.getRefName(), cmd); | |||||
} | |||||
return ret; | |||||
} | |||||
private static Ref peeledRef(RevWalk walk, ReceiveCommand cmd) | private static Ref peeledRef(RevWalk walk, ReceiveCommand cmd) | ||||
throws IOException { | throws IOException { | ||||
ObjectId newId = cmd.getNewId().copy(); | ObjectId newId = cmd.getNewId().copy(); |