Merge changes Ifc34e96a,I72be0a0d
* changes: Fix javadoc in org.eclipse.jgit rewalk package Fix javadoc in org.eclipse.jgit ketch package
This commit is contained in:
commit
1e141469f1
|
@ -45,7 +45,9 @@
|
||||||
|
|
||||||
import org.eclipse.jgit.revwalk.FooterKey;
|
import org.eclipse.jgit.revwalk.FooterKey;
|
||||||
|
|
||||||
/** Frequently used constants in a Ketch system. */
|
/**
|
||||||
|
* Frequently used constants in a Ketch system.
|
||||||
|
*/
|
||||||
public class KetchConstants {
|
public class KetchConstants {
|
||||||
/**
|
/**
|
||||||
* Default reference namespace holding {@link #ACCEPTED} and
|
* Default reference namespace holding {@link #ACCEPTED} and
|
||||||
|
|
|
@ -69,11 +69,15 @@
|
||||||
/**
|
/**
|
||||||
* A leader managing consensus across remote followers.
|
* A leader managing consensus across remote followers.
|
||||||
* <p>
|
* <p>
|
||||||
* A leader instance starts up in {@link State#CANDIDATE} and tries to begin a
|
* A leader instance starts up in
|
||||||
* new term by sending an {@link ElectionRound} to all replicas. Its term starts
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#CANDIDATE} and tries
|
||||||
* if a majority of replicas have accepted this leader instance for the term.
|
* to begin a new term by sending an
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.ElectionRound} to all replicas. Its
|
||||||
|
* term starts if a majority of replicas have accepted this leader instance for
|
||||||
|
* the term.
|
||||||
* <p>
|
* <p>
|
||||||
* Once elected by a majority the instance enters {@link State#LEADER} and runs
|
* Once elected by a majority the instance enters
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#LEADER} and runs
|
||||||
* proposals offered to {@link #queueProposal(Proposal)}. This continues until
|
* proposals offered to {@link #queueProposal(Proposal)}. This continues until
|
||||||
* the leader is timed out for inactivity, or is deposed by a competing leader
|
* the leader is timed out for inactivity, or is deposed by a competing leader
|
||||||
* gaining its own majority.
|
* gaining its own majority.
|
||||||
|
@ -81,36 +85,42 @@
|
||||||
* Once timed out or deposed this {@code KetchLeader} instance should be
|
* Once timed out or deposed this {@code KetchLeader} instance should be
|
||||||
* discarded, and a new instance takes over.
|
* discarded, and a new instance takes over.
|
||||||
* <p>
|
* <p>
|
||||||
* Each leader instance coordinates a group of {@link KetchReplica}s. Replica
|
* Each leader instance coordinates a group of
|
||||||
* instances are owned by the leader instance and must be discarded when the
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica}s. Replica instances are
|
||||||
* leader is discarded.
|
* owned by the leader instance and must be discarded when the leader is
|
||||||
|
* discarded.
|
||||||
* <p>
|
* <p>
|
||||||
* In Ketch all push requests are issued through the leader. The steps are as
|
* In Ketch all push requests are issued through the leader. The steps are as
|
||||||
* follows (see {@link KetchPreReceive} for an example):
|
* follows (see {@link org.eclipse.jgit.internal.ketch.KetchPreReceive} for an
|
||||||
|
* example):
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Create a {@link Proposal} with the
|
* <li>Create a {@link org.eclipse.jgit.internal.ketch.Proposal} with the
|
||||||
* {@link org.eclipse.jgit.transport.ReceiveCommand}s that represent the push.
|
* {@link org.eclipse.jgit.transport.ReceiveCommand}s that represent the push.
|
||||||
* <li>Invoke {@link #queueProposal(Proposal)} on the leader instance.
|
* <li>Invoke {@link #queueProposal(Proposal)} on the leader instance.
|
||||||
* <li>Wait for consensus with {@link Proposal#await()}.
|
* <li>Wait for consensus with
|
||||||
* <li>To examine the status of the push, check {@link Proposal#getCommands()},
|
* {@link org.eclipse.jgit.internal.ketch.Proposal#await()}.
|
||||||
* looking at
|
* <li>To examine the status of the push, check
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.Proposal#getCommands()}, looking at
|
||||||
* {@link org.eclipse.jgit.internal.storage.reftree.Command#getResult()}.
|
* {@link org.eclipse.jgit.internal.storage.reftree.Command#getResult()}.
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* The leader gains consensus by first pushing the needed objects and a
|
* The leader gains consensus by first pushing the needed objects and a
|
||||||
* {@link RefTree} representing the desired target repository state to the
|
* {@link org.eclipse.jgit.internal.storage.reftree.RefTree} representing the
|
||||||
* {@code refs/txn/accepted} branch on each of the replicas. Once a majority has
|
* desired target repository state to the {@code refs/txn/accepted} branch on
|
||||||
* succeeded, the leader commits the state by either pushing the
|
* each of the replicas. Once a majority has succeeded, the leader commits the
|
||||||
* {@code refs/txn/accepted} value to {@code refs/txn/committed} (for
|
* state by either pushing the {@code refs/txn/accepted} value to
|
||||||
* Ketch-aware replicas) or by pushing updates to {@code refs/heads/master},
|
* {@code refs/txn/committed} (for Ketch-aware replicas) or by pushing updates
|
||||||
* etc. for stock Git replicas.
|
* to {@code refs/heads/master}, etc. for stock Git replicas.
|
||||||
* <p>
|
* <p>
|
||||||
* Internally, the actual transport to replicas is performed on background
|
* Internally, the actual transport to replicas is performed on background
|
||||||
* threads via the {@link KetchSystem}'s executor service. For performance, the
|
* threads via the {@link org.eclipse.jgit.internal.ketch.KetchSystem}'s
|
||||||
* {@link KetchLeader}, {@link KetchReplica} and {@link Proposal} objects share
|
* executor service. For performance, the
|
||||||
* some state, and may invoke each other's methods on different threads. This
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader},
|
||||||
* access is protected by the leader's {@link #lock} object. Care must be taken
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica} and
|
||||||
* to prevent concurrent access by correctly obtaining the leader's lock.
|
* {@link org.eclipse.jgit.internal.ketch.Proposal} objects share some state,
|
||||||
|
* and may invoke each other's methods on different threads. This access is
|
||||||
|
* protected by the leader's {@link #lock} object. Care must be taken to prevent
|
||||||
|
* concurrent access by correctly obtaining the leader's lock.
|
||||||
*/
|
*/
|
||||||
public abstract class KetchLeader {
|
public abstract class KetchLeader {
|
||||||
private static final Logger log = LoggerFactory.getLogger(KetchLeader.class);
|
private static final Logger log = LoggerFactory.getLogger(KetchLeader.class);
|
||||||
|
@ -295,7 +305,7 @@ private static LocalReplica findLocal(Collection<KetchReplica> voters) {
|
||||||
* The caller will close the repository.
|
* The caller will close the repository.
|
||||||
*
|
*
|
||||||
* @return opened repository for use by the leader thread.
|
* @return opened repository for use by the leader thread.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* cannot reopen the repository for the leader.
|
* cannot reopen the repository for the leader.
|
||||||
*/
|
*/
|
||||||
protected abstract Repository openRepository() throws IOException;
|
protected abstract Repository openRepository() throws IOException;
|
||||||
|
@ -307,16 +317,17 @@ private static LocalReplica findLocal(Collection<KetchReplica> voters) {
|
||||||
* checked to look for risks of conflicts, and then submitted into the queue
|
* checked to look for risks of conflicts, and then submitted into the queue
|
||||||
* for distribution as soon as possible.
|
* for distribution as soon as possible.
|
||||||
* <p>
|
* <p>
|
||||||
* Callers must use {@link Proposal#await()} to see if the proposal is done.
|
* Callers must use {@link org.eclipse.jgit.internal.ketch.Proposal#await()}
|
||||||
|
* to see if the proposal is done.
|
||||||
*
|
*
|
||||||
* @param proposal
|
* @param proposal
|
||||||
* the proposed reference updates to queue for consideration.
|
* the proposed reference updates to queue for consideration.
|
||||||
* Once execution is complete the individual reference result
|
* Once execution is complete the individual reference result
|
||||||
* fields will be populated with the outcome.
|
* fields will be populated with the outcome.
|
||||||
* @throws InterruptedException
|
* @throws java.lang.InterruptedException
|
||||||
* current thread was interrupted. The proposal may have been
|
* current thread was interrupted. The proposal may have been
|
||||||
* aborted if it was not yet queued for execution.
|
* aborted if it was not yet queued for execution.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* unrecoverable error preventing proposals from being attempted
|
* unrecoverable error preventing proposals from being attempted
|
||||||
* by this leader.
|
* by this leader.
|
||||||
*/
|
*/
|
||||||
|
@ -577,7 +588,11 @@ void nextRound() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return snapshot this leader. */
|
/**
|
||||||
|
* Snapshot this leader
|
||||||
|
*
|
||||||
|
* @return snapshot of this leader
|
||||||
|
*/
|
||||||
public LeaderSnapshot snapshot() {
|
public LeaderSnapshot snapshot() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -599,7 +614,9 @@ public LeaderSnapshot snapshot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gracefully shutdown this leader and cancel outstanding operations. */
|
/**
|
||||||
|
* Gracefully shutdown this leader and cancel outstanding operations.
|
||||||
|
*/
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -617,6 +634,7 @@ public void shutdown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return snapshot().toString();
|
return snapshot().toString();
|
||||||
|
|
|
@ -82,7 +82,7 @@ public KetchLeaderCache(KetchSystem system) {
|
||||||
* @param repo
|
* @param repo
|
||||||
* repository to get the leader for.
|
* repository to get the leader for.
|
||||||
* @return the leader instance for the repository.
|
* @return the leader instance for the repository.
|
||||||
* @throws URISyntaxException
|
* @throws java.net.URISyntaxException
|
||||||
* remote configuration contains an invalid URL.
|
* remote configuration contains an invalid URL.
|
||||||
*/
|
*/
|
||||||
public KetchLeader get(Repository repo)
|
public KetchLeader get(Repository repo)
|
||||||
|
|
|
@ -64,9 +64,10 @@
|
||||||
/**
|
/**
|
||||||
* PreReceiveHook for handling push traffic in a Ketch system.
|
* PreReceiveHook for handling push traffic in a Ketch system.
|
||||||
* <p>
|
* <p>
|
||||||
* Install an instance on {@link ReceivePack} to capture the commands and other
|
* Install an instance on {@link org.eclipse.jgit.transport.ReceivePack} to
|
||||||
* connection state and relay them through the {@link KetchLeader}, allowing the
|
* capture the commands and other connection state and relay them through the
|
||||||
* leader to gain consensus about the new reference state.
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader}, allowing the leader to
|
||||||
|
* gain consensus about the new reference state.
|
||||||
*/
|
*/
|
||||||
public class KetchPreReceive implements PreReceiveHook {
|
public class KetchPreReceive implements PreReceiveHook {
|
||||||
private static final Logger log = LoggerFactory.getLogger(KetchPreReceive.class);
|
private static final Logger log = LoggerFactory.getLogger(KetchPreReceive.class);
|
||||||
|
@ -74,7 +75,8 @@ public class KetchPreReceive implements PreReceiveHook {
|
||||||
private final KetchLeader leader;
|
private final KetchLeader leader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a hook executing updates through a {@link KetchLeader}.
|
* Construct a hook executing updates through a
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader}.
|
||||||
*
|
*
|
||||||
* @param leader
|
* @param leader
|
||||||
* leader for this repository.
|
* leader for this repository.
|
||||||
|
@ -83,6 +85,7 @@ public KetchPreReceive(KetchLeader leader) {
|
||||||
this.leader = leader;
|
this.leader = leader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> cmds) {
|
public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> cmds) {
|
||||||
cmds = ReceiveCommand.filter(cmds, NOT_ATTEMPTED);
|
cmds = ReceiveCommand.filter(cmds, NOT_ATTEMPTED);
|
||||||
|
|
|
@ -82,26 +82,32 @@
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Ketch replica, either {@link LocalReplica} or {@link RemoteGitReplica}.
|
* A Ketch replica, either {@link org.eclipse.jgit.internal.ketch.LocalReplica}
|
||||||
|
* or {@link org.eclipse.jgit.internal.ketch.RemoteGitReplica}.
|
||||||
* <p>
|
* <p>
|
||||||
* Replicas can be either a stock Git replica, or a Ketch-aware replica.
|
* Replicas can be either a stock Git replica, or a Ketch-aware replica.
|
||||||
* <p>
|
* <p>
|
||||||
* A stock Git replica has no special knowledge of Ketch and simply stores
|
* A stock Git replica has no special knowledge of Ketch and simply stores
|
||||||
* objects and references. Ketch communicates with the stock Git replica using
|
* objects and references. Ketch communicates with the stock Git replica using
|
||||||
* the Git push wire protocol. The {@link KetchLeader} commits an agreed upon
|
* the Git push wire protocol. The
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader} commits an agreed upon
|
||||||
* state by pushing all references to the Git replica, for example
|
* state by pushing all references to the Git replica, for example
|
||||||
* {@code "refs/heads/master"} is pushed during commit. Stock Git replicas use
|
* {@code "refs/heads/master"} is pushed during commit. Stock Git replicas use
|
||||||
* {@link CommitMethod#ALL_REFS} to record the final state.
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#ALL_REFS} to
|
||||||
|
* record the final state.
|
||||||
* <p>
|
* <p>
|
||||||
* Ketch-aware replicas understand the {@code RefTree} sent during the proposal
|
* Ketch-aware replicas understand the {@code RefTree} sent during the proposal
|
||||||
* and during commit are able to update their own reference space to match the
|
* and during commit are able to update their own reference space to match the
|
||||||
* state represented by the {@code RefTree}. Ketch-aware replicas typically use
|
* state represented by the {@code RefTree}. Ketch-aware replicas typically use
|
||||||
* a {@link org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase} and
|
* a {@link org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase} and
|
||||||
* {@link CommitMethod#TXN_COMMITTED} to record the final state.
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#TXN_COMMITTED}
|
||||||
|
* to record the final state.
|
||||||
* <p>
|
* <p>
|
||||||
* KetchReplica instances are tightly coupled with a single {@link KetchLeader}.
|
* KetchReplica instances are tightly coupled with a single
|
||||||
* Some state may be accessed by the leader thread and uses the leader's own
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader}. Some state may be
|
||||||
* {@link KetchLeader#lock} to protect shared data.
|
* accessed by the leader thread and uses the leader's own
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} to protect shared
|
||||||
|
* data.
|
||||||
*/
|
*/
|
||||||
public abstract class KetchReplica {
|
public abstract class KetchReplica {
|
||||||
static final Logger log = LoggerFactory.getLogger(KetchReplica.class);
|
static final Logger log = LoggerFactory.getLogger(KetchReplica.class);
|
||||||
|
@ -223,37 +229,65 @@ protected KetchReplica(KetchLeader leader, String name, ReplicaConfig cfg) {
|
||||||
this.queued = new ArrayList<>(4);
|
this.queued = new ArrayList<>(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return system configuration. */
|
/**
|
||||||
|
* Get system configuration.
|
||||||
|
*
|
||||||
|
* @return system configuration.
|
||||||
|
*/
|
||||||
public KetchSystem getSystem() {
|
public KetchSystem getSystem() {
|
||||||
return getLeader().getSystem();
|
return getLeader().getSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return leader instance this replica follows. */
|
/**
|
||||||
|
* Get leader instance this replica follows.
|
||||||
|
*
|
||||||
|
* @return leader instance this replica follows.
|
||||||
|
*/
|
||||||
public KetchLeader getLeader() {
|
public KetchLeader getLeader() {
|
||||||
return leader;
|
return leader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return unique-ish name for debugging. */
|
/**
|
||||||
|
* Get unique-ish name for debugging.
|
||||||
|
*
|
||||||
|
* @return unique-ish name for debugging.
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return replicaName;
|
return replicaName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return description of this replica for error/debug logging purposes. */
|
/**
|
||||||
|
* Get description of this replica for error/debug logging purposes.
|
||||||
|
*
|
||||||
|
* @return description of this replica for error/debug logging purposes.
|
||||||
|
*/
|
||||||
protected String describeForLog() {
|
protected String describeForLog() {
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return how the replica participates in this Ketch system. */
|
/**
|
||||||
|
* Get how the replica participates in this Ketch system.
|
||||||
|
*
|
||||||
|
* @return how the replica participates in this Ketch system.
|
||||||
|
*/
|
||||||
public Participation getParticipation() {
|
public Participation getParticipation() {
|
||||||
return participation;
|
return participation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return how Ketch will commit to the repository. */
|
/**
|
||||||
|
* Get how Ketch will commit to the repository.
|
||||||
|
*
|
||||||
|
* @return how Ketch will commit to the repository.
|
||||||
|
*/
|
||||||
public CommitMethod getCommitMethod() {
|
public CommitMethod getCommitMethod() {
|
||||||
return commitMethod;
|
return commitMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return when Ketch will commit to the repository. */
|
/**
|
||||||
|
* Get when Ketch will commit to the repository.
|
||||||
|
*
|
||||||
|
* @return when Ketch will commit to the repository.
|
||||||
|
*/
|
||||||
public CommitSpeed getCommitSpeed() {
|
public CommitSpeed getCommitSpeed() {
|
||||||
return commitSpeed;
|
return commitSpeed;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +298,8 @@ public CommitSpeed getCommitSpeed() {
|
||||||
* Default implementation cancels any scheduled retry. Subclasses may add
|
* Default implementation cancels any scheduled retry. Subclasses may add
|
||||||
* additional logic before or after calling {@code super.shutdown()}.
|
* additional logic before or after calling {@code super.shutdown()}.
|
||||||
* <p>
|
* <p>
|
||||||
* Called with {@link KetchLeader#lock} held by caller.
|
* Called with {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} held
|
||||||
|
* by caller.
|
||||||
*/
|
*/
|
||||||
protected void shutdown() {
|
protected void shutdown() {
|
||||||
Future<?> f = retryFuture;
|
Future<?> f = retryFuture;
|
||||||
|
@ -541,8 +576,8 @@ private void doRetryPush() {
|
||||||
/**
|
/**
|
||||||
* Begin executing a single push.
|
* Begin executing a single push.
|
||||||
* <p>
|
* <p>
|
||||||
* This method must move processing onto another thread.
|
* This method must move processing onto another thread. Called with
|
||||||
* Called with {@link KetchLeader#lock} held by caller.
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} held by caller.
|
||||||
*
|
*
|
||||||
* @param req
|
* @param req
|
||||||
* the request to send to the replica.
|
* the request to send to the replica.
|
||||||
|
@ -666,20 +701,21 @@ private static ObjectId readId(ReplicaPushRequest req,
|
||||||
/**
|
/**
|
||||||
* Fetch objects from the remote using the calling thread.
|
* Fetch objects from the remote using the calling thread.
|
||||||
* <p>
|
* <p>
|
||||||
* Called without {@link KetchLeader#lock}.
|
* Called without {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock}.
|
||||||
*
|
*
|
||||||
* @param repo
|
* @param repo
|
||||||
* local repository to fetch objects into.
|
* local repository to fetch objects into.
|
||||||
* @param req
|
* @param req
|
||||||
* the request to fetch from a replica.
|
* the request to fetch from a replica.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* communication with the replica was not possible.
|
* communication with the replica was not possible.
|
||||||
*/
|
*/
|
||||||
protected abstract void blockingFetch(Repository repo,
|
protected abstract void blockingFetch(Repository repo,
|
||||||
ReplicaFetchRequest req) throws IOException;
|
ReplicaFetchRequest req) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a list of commands to commit {@link CommitMethod#ALL_REFS}.
|
* Build a list of commands to commit
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#ALL_REFS}.
|
||||||
*
|
*
|
||||||
* @param git
|
* @param git
|
||||||
* local leader repository to read committed state from.
|
* local leader repository to read committed state from.
|
||||||
|
@ -689,7 +725,7 @@ protected abstract void blockingFetch(Repository repo,
|
||||||
* @param committed
|
* @param committed
|
||||||
* state being pushed to {@code refs/txn/committed}.
|
* state being pushed to {@code refs/txn/committed}.
|
||||||
* @return commands to update during commit.
|
* @return commands to update during commit.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* cannot read the committed state.
|
* cannot read the committed state.
|
||||||
*/
|
*/
|
||||||
protected Collection<ReceiveCommand> prepareCommit(Repository git,
|
protected Collection<ReceiveCommand> prepareCommit(Repository git,
|
||||||
|
|
|
@ -81,12 +81,17 @@
|
||||||
* Full scale installations are expected to subclass and override methods to
|
* Full scale installations are expected to subclass and override methods to
|
||||||
* provide consistent configuration across all managed repositories.
|
* provide consistent configuration across all managed repositories.
|
||||||
* <p>
|
* <p>
|
||||||
* Servers should configure their own {@link ScheduledExecutorService}.
|
* Servers should configure their own
|
||||||
|
* {@link java.util.concurrent.ScheduledExecutorService}.
|
||||||
*/
|
*/
|
||||||
public class KetchSystem {
|
public class KetchSystem {
|
||||||
private static final Random RNG = new Random();
|
private static final Random RNG = new Random();
|
||||||
|
|
||||||
/** @return default executor, one thread per available processor. */
|
/**
|
||||||
|
* Get default executor, one thread per available processor.
|
||||||
|
*
|
||||||
|
* @return default executor, one thread per available processor.
|
||||||
|
*/
|
||||||
public static ScheduledExecutorService defaultExecutor() {
|
public static ScheduledExecutorService defaultExecutor() {
|
||||||
return DefaultExecutorHolder.I;
|
return DefaultExecutorHolder.I;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +103,9 @@ public static ScheduledExecutorService defaultExecutor() {
|
||||||
private final String txnCommitted;
|
private final String txnCommitted;
|
||||||
private final String txnStage;
|
private final String txnStage;
|
||||||
|
|
||||||
/** Create a default system with a thread pool of 1 thread per CPU. */
|
/**
|
||||||
|
* Create a default system with a thread pool of 1 thread per CPU.
|
||||||
|
*/
|
||||||
public KetchSystem() {
|
public KetchSystem() {
|
||||||
this(defaultExecutor(), new MonotonicSystemClock(), DEFAULT_TXN_NAMESPACE);
|
this(defaultExecutor(), new MonotonicSystemClock(), DEFAULT_TXN_NAMESPACE);
|
||||||
}
|
}
|
||||||
|
@ -125,17 +132,29 @@ public KetchSystem(ScheduledExecutorService executor, MonotonicClock clock,
|
||||||
this.txnStage = txnNamespace + STAGE;
|
this.txnStage = txnNamespace + STAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return executor to perform background operations. */
|
/**
|
||||||
|
* Get executor to perform background operations.
|
||||||
|
*
|
||||||
|
* @return executor to perform background operations.
|
||||||
|
*/
|
||||||
public ScheduledExecutorService getExecutor() {
|
public ScheduledExecutorService getExecutor() {
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return clock to obtain timestamps from. */
|
/**
|
||||||
|
* Get clock to obtain timestamps from.
|
||||||
|
*
|
||||||
|
* @return clock to obtain timestamps from.
|
||||||
|
*/
|
||||||
public MonotonicClock getClock() {
|
public MonotonicClock getClock() {
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get how long the leader will wait for the {@link #getClock()}'s
|
||||||
|
* {@code ProposedTimestamp} used in commits proposed to the RefTree graph
|
||||||
|
* ({@link #getTxnAccepted()})
|
||||||
|
*
|
||||||
* @return how long the leader will wait for the {@link #getClock()}'s
|
* @return how long the leader will wait for the {@link #getClock()}'s
|
||||||
* {@code ProposedTimestamp} used in commits proposed to the RefTree
|
* {@code ProposedTimestamp} used in commits proposed to the RefTree
|
||||||
* graph ({@link #getTxnAccepted()}). Defaults to 5 seconds.
|
* graph ({@link #getTxnAccepted()}). Defaults to 5 seconds.
|
||||||
|
@ -145,8 +164,12 @@ public Duration getMaxWaitForMonotonicClock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if elections should require monotonically increasing commit
|
* Whether elections should require monotonically increasing commit
|
||||||
* timestamps. This requires a very good {@link MonotonicClock}.
|
* timestamps
|
||||||
|
*
|
||||||
|
* @return {@code true} if elections should require monotonically increasing
|
||||||
|
* commit timestamps. This requires a very good
|
||||||
|
* {@link org.eclipse.jgit.util.time.MonotonicClock}.
|
||||||
*/
|
*/
|
||||||
public boolean requireMonotonicLeaderElections() {
|
public boolean requireMonotonicLeaderElections() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -161,22 +184,36 @@ public String getTxnNamespace() {
|
||||||
return txnNamespace;
|
return txnNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return name of the accepted RefTree graph. */
|
/**
|
||||||
|
* Get name of the accepted RefTree graph.
|
||||||
|
*
|
||||||
|
* @return name of the accepted RefTree graph.
|
||||||
|
*/
|
||||||
public String getTxnAccepted() {
|
public String getTxnAccepted() {
|
||||||
return txnAccepted;
|
return txnAccepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return name of the committed RefTree graph. */
|
/**
|
||||||
|
* Get name of the committed RefTree graph.
|
||||||
|
*
|
||||||
|
* @return name of the committed RefTree graph.
|
||||||
|
*/
|
||||||
public String getTxnCommitted() {
|
public String getTxnCommitted() {
|
||||||
return txnCommitted;
|
return txnCommitted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return prefix for staged objects, e.g. {@code "refs/txn/stage/"}. */
|
/**
|
||||||
|
* Get prefix for staged objects, e.g. {@code "refs/txn/stage/"}.
|
||||||
|
*
|
||||||
|
* @return prefix for staged objects, e.g. {@code "refs/txn/stage/"}.
|
||||||
|
*/
|
||||||
public String getTxnStage() {
|
public String getTxnStage() {
|
||||||
return txnStage;
|
return txnStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Create new committer {@code PersonIdent} for ketch system
|
||||||
|
*
|
||||||
* @param time
|
* @param time
|
||||||
* timestamp for the committer.
|
* timestamp for the committer.
|
||||||
* @return identity line for the committer header of a RefTreeGraph.
|
* @return identity line for the committer header of a RefTreeGraph.
|
||||||
|
@ -220,7 +257,7 @@ public String newLeaderTag() {
|
||||||
* @param repo
|
* @param repo
|
||||||
* local repository stored by the leader.
|
* local repository stored by the leader.
|
||||||
* @return leader instance.
|
* @return leader instance.
|
||||||
* @throws URISyntaxException
|
* @throws java.net.URISyntaxException
|
||||||
* a follower configuration contains an unsupported URI.
|
* a follower configuration contains an unsupported URI.
|
||||||
*/
|
*/
|
||||||
public KetchLeader createLeader(final Repository repo)
|
public KetchLeader createLeader(final Repository repo)
|
||||||
|
@ -246,7 +283,7 @@ protected Repository openRepository() {
|
||||||
* @param repo
|
* @param repo
|
||||||
* repository to get the replicas of.
|
* repository to get the replicas of.
|
||||||
* @return collection of replicas for the specified repository.
|
* @return collection of replicas for the specified repository.
|
||||||
* @throws URISyntaxException
|
* @throws java.net.URISyntaxException
|
||||||
* a configured URI is invalid.
|
* a configured URI is invalid.
|
||||||
*/
|
*/
|
||||||
protected List<KetchReplica> createReplicas(KetchLeader leader,
|
protected List<KetchReplica> createReplicas(KetchLeader leader,
|
||||||
|
|
|
@ -46,9 +46,15 @@
|
||||||
import org.eclipse.jgit.nls.NLS;
|
import org.eclipse.jgit.nls.NLS;
|
||||||
import org.eclipse.jgit.nls.TranslationBundle;
|
import org.eclipse.jgit.nls.TranslationBundle;
|
||||||
|
|
||||||
/** Translation bundle for the Ketch implementation. */
|
/**
|
||||||
|
* Translation bundle for the Ketch implementation.
|
||||||
|
*/
|
||||||
public class KetchText extends TranslationBundle {
|
public class KetchText extends TranslationBundle {
|
||||||
/** @return instance of this translation bundle. */
|
/**
|
||||||
|
* Get an instance of this translation bundle.
|
||||||
|
*
|
||||||
|
* @return instance of this translation bundle.
|
||||||
|
*/
|
||||||
public static KetchText get() {
|
public static KetchText get() {
|
||||||
return NLS.getBundleFor(KetchText.class);
|
return NLS.getBundleFor(KetchText.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ private void initRevWalk() {
|
||||||
rw.setRetainBody(false);
|
rw.setRetainBody(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (rw != null) {
|
if (rw != null) {
|
||||||
|
|
|
@ -53,7 +53,9 @@
|
||||||
import org.eclipse.jgit.annotations.Nullable;
|
import org.eclipse.jgit.annotations.Nullable;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
/** A snapshot of a leader and its view of the world. */
|
/**
|
||||||
|
* A snapshot of a leader and its view of the world.
|
||||||
|
*/
|
||||||
public class LeaderSnapshot {
|
public class LeaderSnapshot {
|
||||||
final List<ReplicaSnapshot> replicas = new ArrayList<>();
|
final List<ReplicaSnapshot> replicas = new ArrayList<>();
|
||||||
KetchLeader.State state;
|
KetchLeader.State state;
|
||||||
|
@ -65,17 +67,28 @@ public class LeaderSnapshot {
|
||||||
LeaderSnapshot() {
|
LeaderSnapshot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return unmodifiable view of configured replicas. */
|
/**
|
||||||
|
* Get unmodifiable view of configured replicas.
|
||||||
|
*
|
||||||
|
* @return unmodifiable view of configured replicas.
|
||||||
|
*/
|
||||||
public Collection<ReplicaSnapshot> getReplicas() {
|
public Collection<ReplicaSnapshot> getReplicas() {
|
||||||
return Collections.unmodifiableList(replicas);
|
return Collections.unmodifiableList(replicas);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return current state of the leader. */
|
/**
|
||||||
|
* Get current state of the leader.
|
||||||
|
*
|
||||||
|
* @return current state of the leader.
|
||||||
|
*/
|
||||||
public KetchLeader.State getState() {
|
public KetchLeader.State getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Whether the leader is not running a round to reach consensus, and has no
|
||||||
|
* rounds queued.
|
||||||
|
*
|
||||||
* @return {@code true} if the leader is not running a round to reach
|
* @return {@code true} if the leader is not running a round to reach
|
||||||
* consensus, and has no rounds queued.
|
* consensus, and has no rounds queued.
|
||||||
*/
|
*/
|
||||||
|
@ -84,14 +97,19 @@ public boolean isIdle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get term of this leader
|
||||||
|
*
|
||||||
* @return term of this leader. Valid only if {@link #getState()} is
|
* @return term of this leader. Valid only if {@link #getState()} is
|
||||||
* currently {@link KetchLeader.State#LEADER}.
|
* currently
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#LEADER}.
|
||||||
*/
|
*/
|
||||||
public long getTerm() {
|
public long getTerm() {
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get end of the leader's log
|
||||||
|
*
|
||||||
* @return end of the leader's log; null if leader hasn't started up enough
|
* @return end of the leader's log; null if leader hasn't started up enough
|
||||||
* to begin its own election.
|
* to begin its own election.
|
||||||
*/
|
*/
|
||||||
|
@ -101,6 +119,9 @@ public LogIndex getHead() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get state the leader knows is committed on a majority of participant
|
||||||
|
* replicas
|
||||||
|
*
|
||||||
* @return state the leader knows is committed on a majority of participant
|
* @return state the leader knows is committed on a majority of participant
|
||||||
* replicas. Null until the leader instance has committed a log
|
* replicas. Null until the leader instance has committed a log
|
||||||
* index within its own term.
|
* index within its own term.
|
||||||
|
@ -110,6 +131,7 @@ public LogIndex getCommitted() {
|
||||||
return committedIndex;
|
return committedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
|
|
|
@ -67,7 +67,10 @@
|
||||||
import org.eclipse.jgit.util.time.MonotonicClock;
|
import org.eclipse.jgit.util.time.MonotonicClock;
|
||||||
import org.eclipse.jgit.util.time.ProposedTimestamp;
|
import org.eclipse.jgit.util.time.ProposedTimestamp;
|
||||||
|
|
||||||
/** Ketch replica running on the same system as the {@link KetchLeader}. */
|
/**
|
||||||
|
* Ketch replica running on the same system as the
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader}.
|
||||||
|
*/
|
||||||
public class LocalReplica extends KetchReplica {
|
public class LocalReplica extends KetchReplica {
|
||||||
/**
|
/**
|
||||||
* Configure a local replica.
|
* Configure a local replica.
|
||||||
|
@ -83,6 +86,7 @@ public LocalReplica(KetchLeader leader, String name, ReplicaConfig cfg) {
|
||||||
super(leader, name, cfg);
|
super(leader, name, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected String describeForLog() {
|
protected String describeForLog() {
|
||||||
return String.format("%s (leader)", getName()); //$NON-NLS-1$
|
return String.format("%s (leader)", getName()); //$NON-NLS-1$
|
||||||
|
@ -116,6 +120,7 @@ void initialize(Repository repo) throws IOException {
|
||||||
getSystem().getTxnCommitted()));
|
getSystem().getTxnCommitted()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected void startPush(final ReplicaPushRequest req) {
|
protected void startPush(final ReplicaPushRequest req) {
|
||||||
getSystem().getExecutor().execute(new Runnable() {
|
getSystem().getExecutor().execute(new Runnable() {
|
||||||
|
@ -137,6 +142,7 @@ public void run() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
|
protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -54,17 +54,18 @@
|
||||||
* LogIndex provides a performance optimization for Ketch, the same information
|
* LogIndex provides a performance optimization for Ketch, the same information
|
||||||
* can be obtained from {@link org.eclipse.jgit.revwalk.RevWalk}.
|
* can be obtained from {@link org.eclipse.jgit.revwalk.RevWalk}.
|
||||||
* <p>
|
* <p>
|
||||||
* Index values are only valid within a single {@link KetchLeader} instance
|
* Index values are only valid within a single
|
||||||
* after it has won an election. By restricting scope to a single leader new
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader} instance after it has won
|
||||||
* leaders do not need to traverse the entire history to determine the next
|
* an election. By restricting scope to a single leader new leaders do not need
|
||||||
* {@code index} for new proposals. This differs from Raft, where leader
|
* to traverse the entire history to determine the next {@code index} for new
|
||||||
* election uses the log index and the term number to determine which replica
|
* proposals. This differs from Raft, where leader election uses the log index
|
||||||
* holds a sufficiently up-to-date log. Since Ketch uses Git objects for storage
|
* and the term number to determine which replica holds a sufficiently
|
||||||
* of its replicated log, it keeps the term number as Raft does but uses
|
* up-to-date log. Since Ketch uses Git objects for storage of its replicated
|
||||||
* standard Git operations to imply the log index.
|
* log, it keeps the term number as Raft does but uses standard Git operations
|
||||||
|
* to imply the log index.
|
||||||
* <p>
|
* <p>
|
||||||
* {@link Round#runAsync(AnyObjectId)} bumps the index as each new round is
|
* {@link org.eclipse.jgit.internal.ketch.Round#runAsync(AnyObjectId)} bumps the
|
||||||
* constructed.
|
* index as each new round is constructed.
|
||||||
*/
|
*/
|
||||||
public class LogIndex extends ObjectId {
|
public class LogIndex extends ObjectId {
|
||||||
static LogIndex unknown(AnyObjectId id) {
|
static LogIndex unknown(AnyObjectId id) {
|
||||||
|
@ -82,7 +83,11 @@ LogIndex nextIndex(AnyObjectId id) {
|
||||||
return new LogIndex(id, index + 1);
|
return new LogIndex(id, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return index provided by the current leader instance. */
|
/**
|
||||||
|
* Get index provided by the current leader instance.
|
||||||
|
*
|
||||||
|
* @return index provided by the current leader instance.
|
||||||
|
*/
|
||||||
public long getIndex() {
|
public long getIndex() {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +108,9 @@ boolean isBefore(LogIndex c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Create string suitable for debug logging containing the log index and
|
||||||
|
* abbreviated ObjectId.
|
||||||
|
*
|
||||||
* @return string suitable for debug logging containing the log index and
|
* @return string suitable for debug logging containing the log index and
|
||||||
* abbreviated ObjectId.
|
* abbreviated ObjectId.
|
||||||
*/
|
*/
|
||||||
|
@ -111,6 +119,7 @@ public String describeForLog() {
|
||||||
return String.format("%5d/%s", index, abbreviate(6).name()); //$NON-NLS-1$
|
return String.format("%5d/%s", index, abbreviate(6).name()); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@SuppressWarnings("boxing")
|
@SuppressWarnings("boxing")
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -78,10 +78,11 @@
|
||||||
* area under the {@code refs/txn/stage/} namespace. If the proposal succeeds
|
* area under the {@code refs/txn/stage/} namespace. If the proposal succeeds
|
||||||
* then the changes are durable and the leader can commit the proposal.
|
* then the changes are durable and the leader can commit the proposal.
|
||||||
* <p>
|
* <p>
|
||||||
* Proposals are executed by {@link KetchLeader#queueProposal(Proposal)}, which
|
* Proposals are executed by
|
||||||
* runs them asynchronously in the background. Proposals are thread-safe futures
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader#queueProposal(Proposal)},
|
||||||
* allowing callers to {@link #await()} for results or be notified by callback
|
* which runs them asynchronously in the background. Proposals are thread-safe
|
||||||
* using {@link #addListener(Runnable)}.
|
* futures allowing callers to {@link #await()} for results or be notified by
|
||||||
|
* callback using {@link #addListener(Runnable)}.
|
||||||
*/
|
*/
|
||||||
public class Proposal {
|
public class Proposal {
|
||||||
/** Current state of the proposal. */
|
/** Current state of the proposal. */
|
||||||
|
@ -146,9 +147,9 @@ public Proposal(List<Command> cmds) {
|
||||||
* walker to assist in preparing commands.
|
* walker to assist in preparing commands.
|
||||||
* @param cmds
|
* @param cmds
|
||||||
* list of pending commands.
|
* list of pending commands.
|
||||||
* @throws MissingObjectException
|
* @throws org.eclipse.jgit.errors.MissingObjectException
|
||||||
* newId of a command is not found locally.
|
* newId of a command is not found locally.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* local objects cannot be accessed.
|
* local objects cannot be accessed.
|
||||||
*/
|
*/
|
||||||
public Proposal(RevWalk rw, Collection<ReceiveCommand> cmds)
|
public Proposal(RevWalk rw, Collection<ReceiveCommand> cmds)
|
||||||
|
@ -166,12 +167,20 @@ private static List<Command> asCommandList(RevWalk rw,
|
||||||
return Collections.unmodifiableList(commands);
|
return Collections.unmodifiableList(commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return commands from this proposal. */
|
/**
|
||||||
|
* Get commands from this proposal.
|
||||||
|
*
|
||||||
|
* @return commands from this proposal.
|
||||||
|
*/
|
||||||
public Collection<Command> getCommands() {
|
public Collection<Command> getCommands() {
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return optional author of the proposal. */
|
/**
|
||||||
|
* Get optional author of the proposal.
|
||||||
|
*
|
||||||
|
* @return optional author of the proposal.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public PersonIdent getAuthor() {
|
public PersonIdent getAuthor() {
|
||||||
return author;
|
return author;
|
||||||
|
@ -189,7 +198,11 @@ public Proposal setAuthor(@Nullable PersonIdent who) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return optional message for the commit log of the RefTree. */
|
/**
|
||||||
|
* Get optional message for the commit log of the RefTree.
|
||||||
|
*
|
||||||
|
* @return optional message for the commit log of the RefTree.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
|
@ -207,7 +220,11 @@ public Proposal setMessage(@Nullable String msg) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return optional certificate signing the references. */
|
/**
|
||||||
|
* Get optional certificate signing the references.
|
||||||
|
*
|
||||||
|
* @return optional certificate signing the references.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public PushCertificate getPushCertificate() {
|
public PushCertificate getPushCertificate() {
|
||||||
return pushCert;
|
return pushCert;
|
||||||
|
@ -226,6 +243,8 @@ public Proposal setPushCertificate(@Nullable PushCertificate cert) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get timestamps that Ketch must block for.
|
||||||
|
*
|
||||||
* @return timestamps that Ketch must block for. These may have been used as
|
* @return timestamps that Ketch must block for. These may have been used as
|
||||||
* commit times inside the objects involved in the proposal.
|
* commit times inside the objects involved in the proposal.
|
||||||
*/
|
*/
|
||||||
|
@ -240,6 +259,7 @@ public List<ProposedTimestamp> getProposedTimestamps() {
|
||||||
* Request the proposal to wait for the affected timestamps to resolve.
|
* Request the proposal to wait for the affected timestamps to resolve.
|
||||||
*
|
*
|
||||||
* @param ts
|
* @param ts
|
||||||
|
* a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
|
||||||
* @return {@code this}.
|
* @return {@code this}.
|
||||||
*/
|
*/
|
||||||
public Proposal addProposedTimestamp(ProposedTimestamp ts) {
|
public Proposal addProposedTimestamp(ProposedTimestamp ts) {
|
||||||
|
@ -253,9 +273,11 @@ public Proposal addProposedTimestamp(ProposedTimestamp ts) {
|
||||||
/**
|
/**
|
||||||
* Add a callback to be invoked when the proposal is done.
|
* Add a callback to be invoked when the proposal is done.
|
||||||
* <p>
|
* <p>
|
||||||
* A proposal is done when it has entered either {@link State#EXECUTED} or
|
* A proposal is done when it has entered either
|
||||||
* {@link State#ABORTED} state. If the proposal is already done
|
* {@link org.eclipse.jgit.internal.ketch.Proposal.State#EXECUTED} or
|
||||||
* {@code callback.run()} is immediately invoked on the caller's thread.
|
* {@link org.eclipse.jgit.internal.ketch.Proposal.State#ABORTED} state. If
|
||||||
|
* the proposal is already done {@code callback.run()} is immediately
|
||||||
|
* invoked on the caller's thread.
|
||||||
*
|
*
|
||||||
* @param callback
|
* @param callback
|
||||||
* method to run after the proposal is done. The callback may be
|
* method to run after the proposal is done. The callback may be
|
||||||
|
@ -291,12 +313,18 @@ void abort() {
|
||||||
notifyState(ABORTED);
|
notifyState(ABORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return read the current state of the proposal. */
|
/**
|
||||||
|
* Read the current state of the proposal.
|
||||||
|
*
|
||||||
|
* @return read the current state of the proposal.
|
||||||
|
*/
|
||||||
public State getState() {
|
public State getState() {
|
||||||
return state.get();
|
return state.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Whether the proposal was attempted
|
||||||
|
*
|
||||||
* @return {@code true} if the proposal was attempted. A true value does not
|
* @return {@code true} if the proposal was attempted. A true value does not
|
||||||
* mean consensus was reached, only that the proposal was considered
|
* mean consensus was reached, only that the proposal was considered
|
||||||
* and will not be making any more progress beyond its current
|
* and will not be making any more progress beyond its current
|
||||||
|
@ -309,7 +337,7 @@ public boolean isDone() {
|
||||||
/**
|
/**
|
||||||
* Wait for the proposal to be attempted and {@link #isDone()} to be true.
|
* Wait for the proposal to be attempted and {@link #isDone()} to be true.
|
||||||
*
|
*
|
||||||
* @throws InterruptedException
|
* @throws java.lang.InterruptedException
|
||||||
* caller was interrupted before proposal executed.
|
* caller was interrupted before proposal executed.
|
||||||
*/
|
*/
|
||||||
public void await() throws InterruptedException {
|
public void await() throws InterruptedException {
|
||||||
|
@ -328,7 +356,7 @@ public void await() throws InterruptedException {
|
||||||
* @param unit
|
* @param unit
|
||||||
* unit describing the wait time.
|
* unit describing the wait time.
|
||||||
* @return true if the proposal is done; false if the method timed out.
|
* @return true if the proposal is done; false if the method timed out.
|
||||||
* @throws InterruptedException
|
* @throws java.lang.InterruptedException
|
||||||
* caller was interrupted before proposal executed.
|
* caller was interrupted before proposal executed.
|
||||||
*/
|
*/
|
||||||
public boolean await(long wait, TimeUnit unit) throws InterruptedException {
|
public boolean await(long wait, TimeUnit unit) throws InterruptedException {
|
||||||
|
@ -351,7 +379,7 @@ public boolean await(long wait, TimeUnit unit) throws InterruptedException {
|
||||||
* @param unit
|
* @param unit
|
||||||
* unit describing the wait time.
|
* unit describing the wait time.
|
||||||
* @return true if the proposal exited the state; false on time out.
|
* @return true if the proposal exited the state; false on time out.
|
||||||
* @throws InterruptedException
|
* @throws java.lang.InterruptedException
|
||||||
* caller was interrupted before proposal executed.
|
* caller was interrupted before proposal executed.
|
||||||
*/
|
*/
|
||||||
public boolean awaitStateChange(State notIn, long wait, TimeUnit unit)
|
public boolean awaitStateChange(State notIn, long wait, TimeUnit unit)
|
||||||
|
@ -378,6 +406,7 @@ void notifyState(State s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
|
|
|
@ -80,7 +80,8 @@
|
||||||
/**
|
/**
|
||||||
* Representation of a Git repository on a remote replica system.
|
* Representation of a Git repository on a remote replica system.
|
||||||
* <p>
|
* <p>
|
||||||
* {@link KetchLeader} will contact the replica using the Git wire protocol.
|
* {@link org.eclipse.jgit.internal.ketch.KetchLeader} will contact the replica
|
||||||
|
* using the Git wire protocol.
|
||||||
* <p>
|
* <p>
|
||||||
* The remote replica may be fully Ketch-aware, or a standard Git server.
|
* The remote replica may be fully Ketch-aware, or a standard Git server.
|
||||||
*/
|
*/
|
||||||
|
@ -110,22 +111,32 @@ public RemoteGitReplica(KetchLeader leader, String name, URIish uri,
|
||||||
this.remoteConfig = rc;
|
this.remoteConfig = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return URI to contact the remote peer repository. */
|
/**
|
||||||
|
* Get URI to contact the remote peer repository.
|
||||||
|
*
|
||||||
|
* @return URI to contact the remote peer repository.
|
||||||
|
*/
|
||||||
public URIish getURI() {
|
public URIish getURI() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return optional configuration describing how to contact the peer. */
|
/**
|
||||||
|
* Get optional configuration describing how to contact the peer.
|
||||||
|
*
|
||||||
|
* @return optional configuration describing how to contact the peer.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
protected RemoteConfig getRemoteConfig() {
|
protected RemoteConfig getRemoteConfig() {
|
||||||
return remoteConfig;
|
return remoteConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected String describeForLog() {
|
protected String describeForLog() {
|
||||||
return String.format("%s @ %s", getName(), getURI()); //$NON-NLS-1$
|
return String.format("%s @ %s", getName(), getURI()); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected void startPush(final ReplicaPushRequest req) {
|
protected void startPush(final ReplicaPushRequest req) {
|
||||||
getSystem().getExecutor().execute(new Runnable() {
|
getSystem().getExecutor().execute(new Runnable() {
|
||||||
|
@ -240,6 +251,7 @@ private static void abort(List<RemoteCommand> cmds) {
|
||||||
ReceiveCommand.abort(tmp);
|
ReceiveCommand.abort(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
|
protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
|
||||||
throws NotSupportedException, TransportException {
|
throws NotSupportedException, TransportException {
|
||||||
|
|
|
@ -65,7 +65,9 @@
|
||||||
import org.eclipse.jgit.internal.ketch.KetchReplica.Participation;
|
import org.eclipse.jgit.internal.ketch.KetchReplica.Participation;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
|
||||||
/** Configures a {@link KetchReplica}. */
|
/**
|
||||||
|
* Configures a {@link org.eclipse.jgit.internal.ketch.KetchReplica}.
|
||||||
|
*/
|
||||||
public class ReplicaConfig {
|
public class ReplicaConfig {
|
||||||
/**
|
/**
|
||||||
* Read a configuration from a config block.
|
* Read a configuration from a config block.
|
||||||
|
@ -86,17 +88,29 @@ public static ReplicaConfig newFromConfig(Config cfg, String name) {
|
||||||
private long minRetry = SECONDS.toMillis(5);
|
private long minRetry = SECONDS.toMillis(5);
|
||||||
private long maxRetry = MINUTES.toMillis(1);
|
private long maxRetry = MINUTES.toMillis(1);
|
||||||
|
|
||||||
/** @return participation of the replica in the system. */
|
/**
|
||||||
|
* Get participation of the replica in the system.
|
||||||
|
*
|
||||||
|
* @return participation of the replica in the system.
|
||||||
|
*/
|
||||||
public Participation getParticipation() {
|
public Participation getParticipation() {
|
||||||
return participation;
|
return participation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return how Ketch should apply committed changes. */
|
/**
|
||||||
|
* Get how Ketch should apply committed changes.
|
||||||
|
*
|
||||||
|
* @return how Ketch should apply committed changes.
|
||||||
|
*/
|
||||||
public CommitMethod getCommitMethod() {
|
public CommitMethod getCommitMethod() {
|
||||||
return commitMethod;
|
return commitMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return how quickly should Ketch commit. */
|
/**
|
||||||
|
* Get how quickly should Ketch commit.
|
||||||
|
*
|
||||||
|
* @return how quickly should Ketch commit.
|
||||||
|
*/
|
||||||
public CommitSpeed getCommitSpeed() {
|
public CommitSpeed getCommitSpeed() {
|
||||||
return commitSpeed;
|
return commitSpeed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,9 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
|
||||||
/** A fetch request to obtain objects from a replica, and its result. */
|
/**
|
||||||
|
* A fetch request to obtain objects from a replica, and its result.
|
||||||
|
*/
|
||||||
public class ReplicaFetchRequest {
|
public class ReplicaFetchRequest {
|
||||||
private final Set<String> wantRefs;
|
private final Set<String> wantRefs;
|
||||||
private final Set<ObjectId> wantObjects;
|
private final Set<ObjectId> wantObjects;
|
||||||
|
@ -70,23 +72,37 @@ public ReplicaFetchRequest(Set<String> wantRefs,
|
||||||
this.wantObjects = wantObjects;
|
this.wantObjects = wantObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return references to be fetched. */
|
/**
|
||||||
|
* Get references to be fetched.
|
||||||
|
*
|
||||||
|
* @return references to be fetched.
|
||||||
|
*/
|
||||||
public Set<String> getWantRefs() {
|
public Set<String> getWantRefs() {
|
||||||
return wantRefs;
|
return wantRefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return objects to be fetched. */
|
/**
|
||||||
|
* Get objects to be fetched.
|
||||||
|
*
|
||||||
|
* @return objects to be fetched.
|
||||||
|
*/
|
||||||
public Set<ObjectId> getWantObjects() {
|
public Set<ObjectId> getWantObjects() {
|
||||||
return wantObjects;
|
return wantObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return remote references, usually from the advertisement. */
|
/**
|
||||||
|
* Get remote references, usually from the advertisement.
|
||||||
|
*
|
||||||
|
* @return remote references, usually from the advertisement.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Map<String, Ref> getRefs() {
|
public Map<String, Ref> getRefs() {
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Set references observed from the replica.
|
||||||
|
*
|
||||||
* @param refs
|
* @param refs
|
||||||
* references observed from the replica.
|
* references observed from the replica.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -54,8 +54,8 @@
|
||||||
/**
|
/**
|
||||||
* A push request sending objects to a replica, and its result.
|
* A push request sending objects to a replica, and its result.
|
||||||
* <p>
|
* <p>
|
||||||
* Implementors of {@link KetchReplica} must populate the command result fields,
|
* Implementors of {@link org.eclipse.jgit.internal.ketch.KetchReplica} must
|
||||||
* {@link #setRefs(Map)}, and call one of
|
* populate the command result fields, {@link #setRefs(Map)}, and call one of
|
||||||
* {@link #setException(Repository, Throwable)} or {@link #done(Repository)} to
|
* {@link #setException(Repository, Throwable)} or {@link #done(Repository)} to
|
||||||
* finish processing.
|
* finish processing.
|
||||||
*/
|
*/
|
||||||
|
@ -80,18 +80,28 @@ public ReplicaPushRequest(KetchReplica replica,
|
||||||
this.commands = commands;
|
this.commands = commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return commands to be executed, and their results. */
|
/**
|
||||||
|
* Get commands to be executed, and their results.
|
||||||
|
*
|
||||||
|
* @return commands to be executed, and their results.
|
||||||
|
*/
|
||||||
public Collection<ReceiveCommand> getCommands() {
|
public Collection<ReceiveCommand> getCommands() {
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return remote references, usually from the advertisement. */
|
/**
|
||||||
|
* Get remote references, usually from the advertisement.
|
||||||
|
*
|
||||||
|
* @return remote references, usually from the advertisement.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Map<String, Ref> getRefs() {
|
public Map<String, Ref> getRefs() {
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Set references observed from the replica.
|
||||||
|
*
|
||||||
* @param refs
|
* @param refs
|
||||||
* references observed from the replica.
|
* references observed from the replica.
|
||||||
*/
|
*/
|
||||||
|
@ -99,7 +109,11 @@ public void setRefs(Map<String, Ref> refs) {
|
||||||
this.refs = refs;
|
this.refs = refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return exception thrown, if any. */
|
/**
|
||||||
|
* Get exception thrown, if any.
|
||||||
|
*
|
||||||
|
* @return exception thrown, if any.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Throwable getException() {
|
public Throwable getException() {
|
||||||
return exception;
|
return exception;
|
||||||
|
|
|
@ -65,31 +65,50 @@ public class ReplicaSnapshot {
|
||||||
this.replica = replica;
|
this.replica = replica;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the replica this snapshot describes the state of. */
|
/**
|
||||||
|
* Get the replica this snapshot describes the state of
|
||||||
|
*
|
||||||
|
* @return the replica this snapshot describes the state of
|
||||||
|
*/
|
||||||
public KetchReplica getReplica() {
|
public KetchReplica getReplica() {
|
||||||
return replica;
|
return replica;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return current state of the replica. */
|
/**
|
||||||
|
* Get current state of the replica
|
||||||
|
*
|
||||||
|
* @return current state of the replica
|
||||||
|
*/
|
||||||
public KetchReplica.State getState() {
|
public KetchReplica.State getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return last known Git commit at {@code refs/txn/accepted}. */
|
/**
|
||||||
|
* Get last known Git commit at {@code refs/txn/accepted}
|
||||||
|
*
|
||||||
|
* @return last known Git commit at {@code refs/txn/accepted}
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public ObjectId getAccepted() {
|
public ObjectId getAccepted() {
|
||||||
return accepted;
|
return accepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return last known Git commit at {@code refs/txn/committed}. */
|
/**
|
||||||
|
* Get last known Git commit at {@code refs/txn/committed}
|
||||||
|
*
|
||||||
|
* @return last known Git commit at {@code refs/txn/committed}
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public ObjectId getCommitted() {
|
public ObjectId getCommitted() {
|
||||||
return committed;
|
return committed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return if {@link #getState()} == {@link KetchReplica.State#OFFLINE} an
|
* Get error message
|
||||||
* optional human-readable message from the transport system
|
*
|
||||||
|
* @return if {@link #getState()} ==
|
||||||
|
* {@link org.eclipse.jgit.internal.ketch.KetchReplica.State#OFFLINE}
|
||||||
|
* an optional human-readable message from the transport system
|
||||||
* explaining the failure.
|
* explaining the failure.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -98,6 +117,9 @@ public String getErrorMessage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get when the leader will retry communication with the offline or lagging
|
||||||
|
* replica
|
||||||
|
*
|
||||||
* @return time (usually in the future) when the leader will retry
|
* @return time (usually in the future) when the leader will retry
|
||||||
* communication with the offline or lagging replica; null if no
|
* communication with the offline or lagging replica; null if no
|
||||||
* retry is scheduled or necessary.
|
* retry is scheduled or necessary.
|
||||||
|
|
|
@ -66,7 +66,9 @@
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
||||||
|
|
||||||
/** Constructs a set of commands to stage content during a proposal. */
|
/**
|
||||||
|
* Constructs a set of commands to stage content during a proposal.
|
||||||
|
*/
|
||||||
public class StageBuilder {
|
public class StageBuilder {
|
||||||
/**
|
/**
|
||||||
* Acceptable number of references to send in a single stage transaction.
|
* Acceptable number of references to send in a single stage transaction.
|
||||||
|
@ -119,14 +121,15 @@ public StageBuilder(String txnStageNamespace, ObjectId txnId) {
|
||||||
* from.
|
* from.
|
||||||
* @param oldTree
|
* @param oldTree
|
||||||
* accepted RefTree on the replica ({@code refs/txn/accepted}).
|
* accepted RefTree on the replica ({@code refs/txn/accepted}).
|
||||||
* Use {@link ObjectId#zeroId()} if the remote does not have any
|
* Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} if the
|
||||||
* ref tree, e.g. a new replica catching up.
|
* remote does not have any ref tree, e.g. a new replica catching
|
||||||
|
* up.
|
||||||
* @param newTree
|
* @param newTree
|
||||||
* RefTree being sent to the replica. The trees will be compared.
|
* RefTree being sent to the replica. The trees will be compared.
|
||||||
* @return list of commands to create {@code "refs/txn/stage/..."}
|
* @return list of commands to create {@code "refs/txn/stage/..."}
|
||||||
* references on replicas anchoring new objects into the repository
|
* references on replicas anchoring new objects into the repository
|
||||||
* while a transaction gains consensus.
|
* while a transaction gains consensus.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* {@code git} cannot be accessed to compare {@code oldTree} and
|
* {@code git} cannot be accessed to compare {@code oldTree} and
|
||||||
* {@code newTree} to build the object set.
|
* {@code newTree} to build the object set.
|
||||||
*/
|
*/
|
||||||
|
@ -172,7 +175,7 @@ public List<ReceiveCommand> makeStageList(Repository git, ObjectId oldTree,
|
||||||
* @return list of commands to create {@code "refs/txn/stage/..."}
|
* @return list of commands to create {@code "refs/txn/stage/..."}
|
||||||
* references on replicas anchoring {@code newObjs} into the
|
* references on replicas anchoring {@code newObjs} into the
|
||||||
* repository while a transaction gains consensus.
|
* repository while a transaction gains consensus.
|
||||||
* @throws IOException
|
* @throws java.io.IOException
|
||||||
* {@code git} cannot be accessed to perform minification of
|
* {@code git} cannot be accessed to perform minification of
|
||||||
* {@code newObjs}.
|
* {@code newObjs}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -73,6 +73,7 @@ public AddToBitmapFilter(BitmapBuilder bitmap) {
|
||||||
this.bitmap = bitmap;
|
this.bitmap = bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean include(RevWalk walker, RevCommit cmit) {
|
public final boolean include(RevWalk walker, RevCommit cmit) {
|
||||||
Bitmap visitedBitmap;
|
Bitmap visitedBitmap;
|
||||||
|
@ -93,11 +94,13 @@ public final boolean include(RevWalk walker, RevCommit cmit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final RevFilter clone() {
|
public final RevFilter clone() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean requiresCommitBody() {
|
public final boolean requiresCommitBody() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -81,6 +81,7 @@ public AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmap) {
|
||||||
this.bitmap = bitmap;
|
this.bitmap = bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean include(RevWalk walker, RevCommit cmit) {
|
public final boolean include(RevWalk walker, RevCommit cmit) {
|
||||||
Bitmap visitedBitmap;
|
Bitmap visitedBitmap;
|
||||||
|
@ -101,11 +102,13 @@ public final boolean include(RevWalk walker, RevCommit cmit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final RevFilter clone() {
|
public final RevFilter clone() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean requiresCommitBody() {
|
public final boolean requiresCommitBody() {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue