FileRepository: Support extensions.refsBackendType = RefTree

This experimental code can be enabled in $GIT_DIR/config:

  [core]
    repositoryformatversion = 1

  [extensions]
    refsBackendType = RefTree

When these are set the repository will read references from the
RefTree rooted by the $GIT_DIR/refs/txn/committed reference.

Update debug-rebuild-ref-tree to rebuild refs/txn/committed only from
the bootstrap layer.  This avoids misuse by rebuilding using packed-refs
and $GIT_DIR/refs tree.

Change-Id: Icf600e4a36b2f7867822a7ab1f1617d73c710a4b
This commit is contained in:
Shawn Pearce 2016-01-09 12:51:14 -08:00
parent 48e245fc60
commit 088c2fc6e3
4 changed files with 64 additions and 13 deletions

View File

@ -48,6 +48,7 @@
import java.util.Map;
import org.eclipse.jgit.internal.storage.reftree.RefTree;
import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@ -59,12 +60,11 @@
import org.eclipse.jgit.pgm.Command;
import org.eclipse.jgit.pgm.TextBuiltin;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Argument;
@Command(usage = "usage_RebuildRefTree")
class RebuildRefTree extends TextBuiltin {
@Argument(index = 0, required = true, metaVar = "metaVar_ref", usage = "usage_updateRef")
String refName;
private String txnNamespace;
private String txnCommitted;
@Override
protected void run() throws Exception {
@ -72,10 +72,25 @@ protected void run() throws Exception {
RevWalk rw = new RevWalk(reader);
ObjectInserter inserter = db.newObjectInserter()) {
RefDatabase refDb = db.getRefDatabase();
if (refDb instanceof RefTreeDatabase) {
RefTreeDatabase d = (RefTreeDatabase) refDb;
refDb = d.getBootstrap();
txnNamespace = d.getTxnNamespace();
txnCommitted = d.getTxnCommitted();
} else {
RefTreeDatabase d = new RefTreeDatabase(db, refDb);
txnNamespace = d.getTxnNamespace();
txnCommitted = d.getTxnCommitted();
}
errw.format("Rebuilding %s from %s", //$NON-NLS-1$
txnCommitted, refDb.getClass().getSimpleName());
errw.println();
errw.flush();
CommitBuilder b = new CommitBuilder();
Ref ref = db.getRefDatabase().exactRef(refName);
RefUpdate update = db.updateRef(refName);
Ref ref = refDb.exactRef(txnCommitted);
RefUpdate update = refDb.newUpdate(txnCommitted, true);
ObjectId oldTreeId;
if (ref != null && ref.getObjectId() != null) {
@ -116,10 +131,10 @@ private RefTree rebuild(Map<String, Ref> refMap) {
= new ArrayList<>();
for (Ref r : refMap.values()) {
if (refName.equals(r.getName())) {
if (r.getName().equals(txnCommitted)
|| r.getName().startsWith(txnNamespace)) {
continue;
}
cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
null,
db.peel(r)));

View File

@ -104,7 +104,7 @@ public void unknownRepositoryFormatVersion() throws Exception {
Repository r = createWorkRepository();
StoredConfig config = r.getConfig();
config.setLong(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1);
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 999999);
config.save();
try {

View File

@ -63,6 +63,7 @@
import org.eclipse.jgit.events.ConfigChangedListener;
import org.eclipse.jgit.events.IndexChangedEvent;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle;
import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository;
import org.eclipse.jgit.lib.BaseRepositoryBuilder;
@ -201,7 +202,22 @@ public void onConfigChanged(ConfigChangedEvent event) {
}
});
refs = new RefDirectory(this);
final long repositoryFormatVersion = getConfig().getLong(
ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
String reftype = repoConfig.getString(
"extensions", null, "refsBackendType"); //$NON-NLS-1$ //$NON-NLS-2$
if (repositoryFormatVersion >= 1 && reftype != null) {
if (StringUtils.equalsIgnoreCase(reftype, "reftree")) { //$NON-NLS-1$
refs = new RefTreeDatabase(this, new RefDirectory(this));
} else {
throw new IOException(JGitText.get().unknownRepositoryFormat);
}
} else {
refs = new RefDirectory(this);
}
objectDatabase = new ObjectDirectory(repoConfig, //
options.getObjectDirectory(), //
options.getAlternateObjectDirectories(), //
@ -209,10 +225,7 @@ public void onConfigChanged(ConfigChangedEvent event) {
new File(getDirectory(), Constants.SHALLOW));
if (objectDatabase.exists()) {
final long repositoryFormatVersion = getConfig().getLong(
ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
if (repositoryFormatVersion > 0)
if (repositoryFormatVersion > 1)
throw new IOException(MessageFormat.format(
JGitText.get().unknownRepositoryFormat2,
Long.valueOf(repositoryFormatVersion)));

View File

@ -54,6 +54,7 @@
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
@ -88,6 +89,28 @@ public class RefTreeDatabase extends RefDatabase {
private final String txnNamespace;
private volatile Scanner.Result refs;
/**
* Create a RefTreeDb for a repository.
*
* @param repo
* the repository using references in this database.
* @param bootstrap
* bootstrap reference database storing the references that
* anchor the {@link RefTree}.
*/
public RefTreeDatabase(Repository repo, RefDatabase bootstrap) {
Config cfg = repo.getConfig();
String committed = cfg.getString("reftree", null, "committedRef"); //$NON-NLS-1$ //$NON-NLS-2$
if (committed == null || committed.isEmpty()) {
committed = "refs/txn/committed"; //$NON-NLS-1$
}
this.repo = repo;
this.bootstrap = bootstrap;
this.txnNamespace = initNamespace(committed);
this.txnCommitted = committed;
}
/**
* Create a RefTreeDb for a repository.
*