* stable-5.6:
Silence API errors introduced by 093fbbd1
Bump Bazel version to 2.2.0
Expose FileStoreAttributes.setBackground()
Update reftable storage repo layout
Change-Id: I237eaaed7991e8bbd56a7624f47bbba985330026
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
tags/v5.7.0.202003090808-r
@@ -1 +1 @@ | |||
2.1.0 | |||
2.2.0 |
@@ -91,11 +91,6 @@ public class FileReftableTest extends SampleDataRepositoryTestCase { | |||
} | |||
} | |||
@Test | |||
public void additionalRefsAreRemoved() { | |||
assertFalse(new File(db.getDirectory(), Constants.HEAD).exists()); | |||
} | |||
@Test | |||
public void testCompactFully() throws Exception { | |||
ObjectId c1 = db.resolve("master^^"); | |||
@@ -108,9 +103,16 @@ public class FileReftableTest extends SampleDataRepositoryTestCase { | |||
} | |||
File tableDir = new File(db.getDirectory(), Constants.REFTABLE); | |||
assertTrue(tableDir.listFiles().length > 1); | |||
assertTrue(tableDir.listFiles().length > 2); | |||
((FileReftableDatabase)db.getRefDatabase()).compactFully(); | |||
assertEquals(tableDir.listFiles().length,1); | |||
assertEquals(tableDir.listFiles().length,2); | |||
} | |||
@Test | |||
public void testOpenConvert() throws Exception { | |||
try (FileRepository repo = new FileRepository(db.getDirectory())) { | |||
assertTrue(repo.getRefDatabase() instanceof FileReftableDatabase); | |||
} | |||
} | |||
@Test | |||
@@ -129,7 +131,7 @@ public class FileReftableTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void testConvertToRefdir() throws Exception { | |||
db.convertToPackedRefs(false); | |||
db.convertToPackedRefs(false, false); | |||
assertTrue(db.getRefDatabase() instanceof RefDirectory); | |||
Ref h = db.exactRef("HEAD"); | |||
assertTrue(h.isSymbolic()); | |||
@@ -143,6 +145,30 @@ public class FileReftableTest extends SampleDataRepositoryTestCase { | |||
assertFalse(db.getRefDatabase().hasFastTipsWithSha1()); | |||
} | |||
@Test | |||
public void testConvertToRefdirReflog() throws Exception { | |||
Ref a = db.exactRef("refs/heads/a"); | |||
String aCommit = a.getObjectId().getName(); | |||
RefUpdate u = db.updateRef("refs/heads/master"); | |||
u.setForceUpdate(true); | |||
u.setNewObjectId(ObjectId.fromString(aCommit)); | |||
u.setForceRefLog(true); | |||
u.setRefLogMessage("apple", false); | |||
u.update(); | |||
RefUpdate v = db.updateRef("refs/heads/master"); | |||
v.setForceUpdate(true); | |||
v.setNewObjectId(ObjectId.fromString(bCommit)); | |||
v.setForceRefLog(true); | |||
v.setRefLogMessage("banana", false); | |||
v.update(); | |||
db.convertToPackedRefs(true, false); | |||
List<ReflogEntry> logs = db.getReflogReader("refs/heads/master").getReverseEntries(2); | |||
assertEquals(logs.get(0).getComment(), "banana"); | |||
assertEquals(logs.get(1).getComment(), "apple"); | |||
} | |||
@Test | |||
public void testBatchrefUpdate() throws Exception { | |||
ObjectId cur = db.resolve("master"); |
@@ -37,6 +37,26 @@ | |||
<message_argument value="CONFIG_KEY_PACKED_GIT_WINDOWSIZE"/> | |||
</message_arguments> | |||
</filter> | |||
<filter id="1142947843"> | |||
<message_arguments> | |||
<message_argument value="5.6.2"/> | |||
<message_argument value="CONFIG_EXTENSIONS_SECTION"/> | |||
</message_arguments> | |||
</filter> | |||
<filter id="1142947843"> | |||
<message_arguments> | |||
<message_argument value="5.6.2"/> | |||
<message_argument value="CONFIG_KEY_REF_STORAGE"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/lib/Constants.java" type="org.eclipse.jgit.lib.Constants"> | |||
<filter id="1142947843"> | |||
<message_arguments> | |||
<message_argument value="5.6.2"/> | |||
<message_argument value="TABLES_LIST"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/storage/file/WindowCacheConfig.java" type="org.eclipse.jgit.storage.file.WindowCacheConfig"> | |||
<filter id="1142947843"> | |||
@@ -69,6 +89,14 @@ | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS$FileStoreAttributes"> | |||
<filter id="1226833923"> | |||
<message_arguments> | |||
<message_argument value="5.6.2"/> | |||
<message_argument value="setBackground(boolean)"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/util/Monitoring.java" type="org.eclipse.jgit.util.Monitoring"> | |||
<filter id="1109393411"> | |||
<message_arguments> |
@@ -64,6 +64,11 @@ public class FileReftableDatabase extends RefDatabase { | |||
private final FileReftableStack reftableStack; | |||
FileReftableDatabase(FileRepository repo) throws IOException { | |||
this(repo, new File(new File(repo.getDirectory(), Constants.REFTABLE), | |||
Constants.TABLES_LIST)); | |||
} | |||
FileReftableDatabase(FileRepository repo, File refstackName) throws IOException { | |||
this.fileRepository = repo; | |||
this.reftableStack = new FileReftableStack(refstackName, | |||
@@ -88,8 +93,7 @@ public class FileReftableDatabase extends RefDatabase { | |||
* @return whether the given repo uses reftable for refdb storage. | |||
*/ | |||
public static boolean isReftable(File repoDir) { | |||
return new File(repoDir, "refs").isFile() //$NON-NLS-1$ | |||
&& new File(repoDir, Constants.REFTABLE).isDirectory(); | |||
return new File(repoDir, Constants.REFTABLE).isDirectory(); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -593,8 +597,6 @@ public class FileReftableDatabase extends RefDatabase { | |||
/** | |||
* @param repo | |||
* the repository | |||
* @param refstackName | |||
* the filename for the stack | |||
* @param writeLogs | |||
* whether to write reflogs | |||
* @return a reftable based RefDB from an existing repository. | |||
@@ -602,22 +604,25 @@ public class FileReftableDatabase extends RefDatabase { | |||
* on IO error | |||
*/ | |||
public static FileReftableDatabase convertFrom(FileRepository repo, | |||
File refstackName, boolean writeLogs) throws IOException { | |||
boolean writeLogs) throws IOException { | |||
FileReftableDatabase newDb = null; | |||
File reftableList = null; | |||
try { | |||
File reftableDir = new File(repo.getDirectory(), Constants.REFTABLE); | |||
File reftableDir = new File(repo.getDirectory(), | |||
Constants.REFTABLE); | |||
reftableList = new File(reftableDir, Constants.TABLES_LIST); | |||
if (!reftableDir.isDirectory()) { | |||
reftableDir.mkdir(); | |||
} | |||
try (FileReftableStack stack = new FileReftableStack(refstackName, | |||
try (FileReftableStack stack = new FileReftableStack(reftableList, | |||
reftableDir, null, () -> repo.getConfig())) { | |||
stack.addReftable(rw -> writeConvertTable(repo, rw, writeLogs)); | |||
} | |||
refstackName = null; | |||
reftableList = null; | |||
} finally { | |||
if (refstackName != null) { | |||
refstackName.delete(); | |||
if (reftableList != null) { | |||
reftableList.delete(); | |||
} | |||
} | |||
return newDb; |
@@ -18,10 +18,13 @@ import static java.util.stream.Collectors.toList; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.text.MessageFormat; | |||
import java.text.ParseException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Locale; | |||
@@ -50,6 +53,7 @@ import org.eclipse.jgit.lib.ProgressMonitor; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.RefDatabase; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.lib.ReflogEntry; | |||
import org.eclipse.jgit.lib.ReflogReader; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.StoredConfig; | |||
@@ -173,20 +177,17 @@ public class FileRepository extends Repository { | |||
String reftype = repoConfig.getString( | |||
ConfigConstants.CONFIG_EXTENSIONS_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_REFSTORAGE); | |||
ConfigConstants.CONFIG_KEY_REF_STORAGE); | |||
if (repositoryFormatVersion >= 1 && reftype != null) { | |||
if (StringUtils.equalsIgnoreCase(reftype, | |||
ConfigConstants.CONFIG_REFSTORAGE_REFTABLE)) { | |||
refs = new FileReftableDatabase(this, | |||
new File(getDirectory(), "refs")); //$NON-NLS-1$ | |||
ConfigConstants.CONFIG_REF_STORAGE_REFTABLE)) { | |||
refs = new FileReftableDatabase(this); | |||
} else if (StringUtils.equalsIgnoreCase(reftype, | |||
ConfigConstants.CONFIG_REFSTORAGE_REFTREE)) { | |||
refs = new RefTreeDatabase(this, new RefDirectory(this)); | |||
} else { | |||
throw new IOException(JGitText.get().unknownRepositoryFormat); | |||
} | |||
} else if (FileReftableDatabase.isReftable(getDirectory())) { | |||
refs = new FileReftableDatabase(this, new File(getDirectory(), "refs")); //$NON-NLS-1$ | |||
} else { | |||
refs = new RefDirectory(this); | |||
} | |||
@@ -610,15 +611,18 @@ public class FileRepository extends Repository { | |||
* Converts the RefDatabase from reftable to RefDirectory. This operation is | |||
* not atomic. | |||
* | |||
* @param writeLogs | |||
* whether to write reflogs | |||
* @param backup | |||
* whether to rename or delete the old storage files. If set to | |||
* true, the reftable list is left in "refs.old", and the | |||
* reftable/ dir is left alone. If set to false, the reftable/ | |||
* dir is removed, and "refs" file is removed. | |||
* {@code true}, the reftable list is left in {@code refs.old}, | |||
* and the {@code reftable/} dir is left alone. If set to | |||
* {@code false}, the {@code reftable/} dir is removed, and | |||
* {@code refs} file is removed. | |||
* @throws IOException | |||
* on IO problem | |||
*/ | |||
void convertToPackedRefs(boolean backup) throws IOException { | |||
void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException { | |||
List<Ref> all = refs.getRefs(); | |||
File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); | |||
if (packedRefs.exists()) { | |||
@@ -627,26 +631,26 @@ public class FileRepository extends Repository { | |||
} | |||
File refsFile = new File(getDirectory(), "refs"); //$NON-NLS-1$ | |||
refs.close(); | |||
if (backup) { | |||
File refsOld = new File(getDirectory(), "refs.old"); //$NON-NLS-1$ | |||
if (refsOld.exists()) { | |||
throw new IOException(MessageFormat.format( | |||
JGitText.get().fileAlreadyExists, | |||
"refs.old")); //$NON-NLS-1$ | |||
} | |||
FileUtils.rename(refsFile, refsOld); | |||
} else { | |||
refsFile.delete(); | |||
} | |||
File refsHeadsFile = new File(refsFile, "heads");//$NON-NLS-1$ | |||
File headFile = new File(getDirectory(), Constants.HEAD); | |||
FileReftableDatabase oldDb = (FileReftableDatabase) refs; | |||
// Remove the dummy files that ensure compatibility with older git | |||
// versions (see convertToReftable). First make room for refs/heads/ | |||
refsHeadsFile.delete(); | |||
// RefDirectory wants to create the refs/ directory from scratch, so | |||
// remove that too. | |||
refsFile.delete(); | |||
// remove HEAD so its previous invalid value doesn't cause issues. | |||
headFile.delete(); | |||
// This is not atomic, but there is no way to instantiate a RefDirectory | |||
// that is disconnected from the current repo. | |||
refs = new RefDirectory(this); | |||
RefDirectory refDir = new RefDirectory(this); | |||
refs = refDir; | |||
refs.create(); | |||
ReflogWriter logWriter = refDir.newLogWriter(true); | |||
List<Ref> symrefs = new ArrayList<>(); | |||
BatchRefUpdate bru = refs.newBatchUpdate(); | |||
for (Ref r : all) { | |||
@@ -656,6 +660,15 @@ public class FileRepository extends Repository { | |||
bru.addCommand(new ReceiveCommand(ObjectId.zeroId(), | |||
r.getObjectId(), r.getName())); | |||
} | |||
if (writeLogs) { | |||
List<ReflogEntry> logs = oldDb.getReflogReader(r.getName()) | |||
.getReverseEntries(); | |||
Collections.reverse(logs); | |||
for (ReflogEntry e : logs) { | |||
logWriter.log(r.getName(), e); | |||
} | |||
} | |||
} | |||
try (RevWalk rw = new RevWalk(this)) { | |||
@@ -691,24 +704,39 @@ public class FileRepository extends Repository { | |||
FileUtils.delete(reftableDir, | |||
FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS); | |||
} | |||
repoConfig.unset(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_REFSTORAGE); | |||
ConfigConstants.CONFIG_KEY_REF_STORAGE); | |||
repoConfig.save(); | |||
} | |||
/** | |||
* Converts the RefDatabase from RefDirectory to reftable. This operation is | |||
* not atomic. | |||
* | |||
* @param writeLogs | |||
* whether to write reflogs | |||
* @param backup | |||
* whether to rename or delete the old storage files. If set to | |||
* {@code true}, the loose refs are left in {@code refs.old}, the | |||
* packed-refs in {@code packed-refs.old} and reflogs in | |||
* {@code refs.old/}. HEAD is left in {@code HEAD.old} and also | |||
* {@code .log} is appended to additional refs. If set to | |||
* {@code false}, the {@code refs/} and {@code logs/} directories | |||
* and {@code HEAD} and additional symbolic refs are removed. | |||
* @throws IOException | |||
* on IO problem | |||
*/ | |||
@SuppressWarnings("nls") | |||
void convertToReftable(boolean writeLogs, boolean backup) | |||
throws IOException { | |||
File newRefs = new File(getDirectory(), "refs.new"); | |||
File reftableDir = new File(getDirectory(), Constants.REFTABLE); | |||
File headFile = new File(getDirectory(), Constants.HEAD); | |||
if (reftableDir.exists() && reftableDir.listFiles().length > 0) { | |||
throw new IOException(JGitText.get().reftableDirExists); | |||
} | |||
// Ignore return value, as it is tied to temporary newRefs file. | |||
FileReftableDatabase.convertFrom(this, newRefs, writeLogs); | |||
FileReftableDatabase.convertFrom(this, writeLogs); | |||
File refsFile = new File(getDirectory(), "refs"); | |||
@@ -716,7 +744,6 @@ public class FileRepository extends Repository { | |||
File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); | |||
File logsDir = new File(getDirectory(), Constants.LOGS); | |||
List<String> additional = getRefDatabase().getAdditionalRefs().stream() | |||
.map(Ref::getName).collect(toList()); | |||
additional.add(Constants.HEAD); | |||
@@ -735,7 +762,8 @@ public class FileRepository extends Repository { | |||
new File(getDirectory(), r + ".old")); | |||
} | |||
} else { | |||
packedRefs.delete(); // ignore return value. | |||
FileUtils.delete(packedRefs, FileUtils.SKIP_MISSING); | |||
FileUtils.delete(headFile); | |||
FileUtils.delete(logsDir, FileUtils.RECURSIVE); | |||
FileUtils.delete(refsFile, FileUtils.RECURSIVE); | |||
for (String r : additional) { | |||
@@ -743,16 +771,26 @@ public class FileRepository extends Repository { | |||
} | |||
} | |||
// Put new data. | |||
FileUtils.rename(newRefs, refsFile); | |||
FileUtils.mkdir(refsFile, true); | |||
refs.close(); | |||
refs = new FileReftableDatabase(this, refsFile); | |||
// By putting in a dummy HEAD, old versions of Git still detect a repo | |||
// (that they can't read) | |||
try (OutputStream os = new FileOutputStream(headFile)) { | |||
os.write(Constants.encodeASCII("ref: refs/heads/.invalid")); | |||
} | |||
// Some tools might write directly into .git/refs/heads/BRANCH. By | |||
// putting a file here, this fails spectacularly. | |||
FileUtils.createNewFile(new File(refsFile, "heads")); | |||
repoConfig.setString(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_REFSTORAGE, | |||
ConfigConstants.CONFIG_REFSTORAGE_REFTABLE); | |||
ConfigConstants.CONFIG_KEY_REF_STORAGE, | |||
ConfigConstants.CONFIG_REF_STORAGE_REFTABLE); | |||
repoConfig.setLong(ConfigConstants.CONFIG_CORE_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1); | |||
repoConfig.save(); | |||
refs.close(); | |||
refs = new FileReftableDatabase(this); | |||
} | |||
/** | |||
@@ -775,7 +813,7 @@ public class FileRepository extends Repository { | |||
} | |||
} else if (format.equals("refdir")) {//$NON-NLS-1$ | |||
if (refs instanceof FileReftableDatabase) { | |||
convertToPackedRefs(backup); | |||
convertToPackedRefs(writeLogs, backup); | |||
} | |||
} else { | |||
throw new IOException(MessageFormat |
@@ -504,9 +504,18 @@ public final class ConfigConstants { | |||
*/ | |||
public static final String CONFIG_KEY_MIN_RACY_THRESHOLD = "minRacyThreshold"; | |||
/** | |||
* The "refStorage" key | |||
* | |||
* @since 5.6.2 | |||
*/ | |||
public static final String CONFIG_KEY_REF_STORAGE = "refStorage"; | |||
/** | |||
* The "extensions" section | |||
* @since 5.7 | |||
* | |||
* @since 5.6.2 | |||
*/ | |||
public static final String CONFIG_EXTENSIONS_SECTION = "extensions"; | |||
@@ -520,7 +529,7 @@ public final class ConfigConstants { | |||
* The "reftable" refStorage format | |||
* @since 5.7 | |||
*/ | |||
public static final String CONFIG_REFSTORAGE_REFTABLE = "reftable"; | |||
public static final String CONFIG_REF_STORAGE_REFTABLE = "reftable"; | |||
/** | |||
* The "reftree" refStorage format |
@@ -254,6 +254,12 @@ public final class Constants { | |||
*/ | |||
public static final String REFTABLE = "reftable"; | |||
/** | |||
* Reftable table list name. | |||
* @since 5.6.2 | |||
*/ | |||
public static final String TABLES_LIST = "tables.list"; | |||
/** Info refs folder */ | |||
public static final String INFO_REFS = "info/refs"; | |||
@@ -245,7 +245,16 @@ public abstract class FS { | |||
return t; | |||
}); | |||
private static void setBackground(boolean async) { | |||
/** | |||
* Whether FileStore attributes should be determined asynchronously | |||
* | |||
* @param async | |||
* whether FileStore attributes should be determined | |||
* asynchronously. If false access to cached attributes may block | |||
* for some seconds for the first call per FileStore | |||
* @since 5.6.2 | |||
*/ | |||
public static void setBackground(boolean async) { | |||
background.set(async); | |||
} | |||
@@ -709,7 +718,9 @@ public abstract class FS { | |||
* asynchronously. If false access to cached attributes may block | |||
* for some seconds for the first call per FileStore | |||
* @since 5.1.9 | |||
* @deprecated Use {@link FileStoreAttributes#setBackground} instead | |||
*/ | |||
@Deprecated | |||
public static void setAsyncFileStoreAttributes(boolean asynch) { | |||
FileStoreAttributes.setBackground(asynch); | |||
} |