Skip to content

Commit 4698ef0

Browse files
committed
Merge branch 'stable-3.11' into stable-3.12
* stable-3.11: Add --remote switch to replication start command Change-Id: I414161edf66faf9de4d2b384b479b338bdcb9880
2 parents b0e7aa6 + 24b0f4b commit 4698ef0

6 files changed

Lines changed: 119 additions & 13 deletions

File tree

src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.inject.Inject;
2323
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.GitUpdateProcessing;
2424
import com.googlesource.gerrit.plugins.replication.api.ReplicationConfig;
25+
import java.util.Set;
2526
import java.util.concurrent.Future;
2627
import java.util.concurrent.TimeUnit;
2728
import java.util.concurrent.atomic.AtomicReference;
@@ -53,7 +54,7 @@ public void start() {
5354
ReplicationState state = new ReplicationState(new GitUpdateProcessing(eventDispatcher.get()));
5455
pushAllFuture.set(
5556
pushAll
56-
.create(null, ReplicationFilter.all(), state, false)
57+
.create(null, Set.of(), ReplicationFilter.all(), state, false)
5758
.schedule(30, TimeUnit.SECONDS));
5859
}
5960
}

src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,27 @@
2020
import com.google.gerrit.server.project.ProjectCache;
2121
import com.google.inject.Inject;
2222
import com.google.inject.assistedinject.Assisted;
23+
import java.util.Set;
2324
import java.util.concurrent.Future;
2425
import java.util.concurrent.TimeUnit;
2526

2627
public class PushAll implements Runnable {
2728
private final ReplicationStateListener stateLog;
2829

2930
public interface Factory {
30-
PushAll create(String urlMatch, ReplicationFilter filter, ReplicationState state, boolean now);
31+
PushAll create(
32+
String urlMatch,
33+
Set<String> remotesToConsider,
34+
ReplicationFilter filter,
35+
ReplicationState state,
36+
boolean now);
3137
}
3238

3339
private final WorkQueue workQueue;
3440
private final ProjectCache projectCache;
3541
private final ReplicationQueue replication;
3642
private final String urlMatch;
43+
private final Set<String> remotesToConsider;
3744
private final ReplicationFilter filter;
3845
private final ReplicationState state;
3946
private final boolean now;
@@ -45,6 +52,7 @@ protected PushAll(
4552
ReplicationQueue rq,
4653
ReplicationStateListeners stateLog,
4754
@Assisted @Nullable String urlMatch,
55+
@Assisted Set<String> remotesToConsider,
4856
@Assisted ReplicationFilter filter,
4957
@Assisted ReplicationState state,
5058
@Assisted boolean now) {
@@ -53,6 +61,7 @@ protected PushAll(
5361
this.replication = rq;
5462
this.stateLog = stateLog;
5563
this.urlMatch = urlMatch;
64+
this.remotesToConsider = remotesToConsider;
5665
this.filter = filter;
5766
this.state = state;
5867
this.now = now;
@@ -67,7 +76,7 @@ public void run() {
6776
try {
6877
for (Project.NameKey nameKey : projectCache.all()) {
6978
if (filter.matches(nameKey)) {
70-
replication.scheduleFullSync(nameKey, urlMatch, state, now);
79+
replication.scheduleFullSync(nameKey, urlMatch, remotesToConsider, state, now);
7180
}
7281
}
7382
} catch (Exception e) {

src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,19 @@ public boolean isReplaying() {
132132

133133
public void scheduleFullSync(
134134
Project.NameKey project, String urlMatch, ReplicationState state, boolean now) {
135+
scheduleFullSync(project, urlMatch, Set.of(), state, now);
136+
}
137+
138+
public void scheduleFullSync(
139+
Project.NameKey project,
140+
String urlMatch,
141+
Set<String> remotesToConsider,
142+
ReplicationState state,
143+
boolean now) {
135144
fire(
136145
project,
137146
urlMatch,
147+
remotesToConsider,
138148
Set.of(new GitReferenceUpdated.UpdatedRef(PushOne.ALL_REFS, null, null, null)),
139149
state,
140150
now);
@@ -157,6 +167,16 @@ private void fire(
157167
Set<UpdatedRef> updatedRefs,
158168
ReplicationState state,
159169
boolean now) {
170+
fire(project, urlMatch, Set.of(), updatedRefs, state, now);
171+
}
172+
173+
private void fire(
174+
Project.NameKey project,
175+
String urlMatch,
176+
Set<String> remotesToConsider,
177+
Set<UpdatedRef> updatedRefs,
178+
ReplicationState state,
179+
boolean now) {
160180
if (!running) {
161181
stateLog.warn(
162182
"Replication plugin did not finish startup before event, event replication is postponed",
@@ -166,13 +186,15 @@ private void fire(
166186
}
167187

168188
for (Destination cfg : destinations.get().getAll(FilterType.ALL)) {
169-
pushReferences(
170-
cfg,
171-
project,
172-
urlMatch,
173-
updatedRefs.stream().map(UpdatedRef::getRefName).collect(Collectors.toSet()),
174-
state,
175-
now);
189+
if (remotesToConsider.isEmpty() || remotesToConsider.contains(cfg.getRemoteConfigName())) {
190+
pushReferences(
191+
cfg,
192+
project,
193+
urlMatch,
194+
updatedRefs.stream().map(UpdatedRef::getRefName).collect(Collectors.toSet()),
195+
state,
196+
now);
197+
}
176198
}
177199
}
178200

src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import com.google.inject.Inject;
2121
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.CommandProcessing;
2222
import java.util.ArrayList;
23+
import java.util.HashSet;
2324
import java.util.List;
25+
import java.util.Set;
2426
import java.util.concurrent.ExecutionException;
2527
import java.util.concurrent.Future;
2628
import java.util.concurrent.TimeUnit;
@@ -40,6 +42,9 @@ final class StartCommand extends SshCommand {
4042
@Option(name = "--url", metaVar = "PATTERN", usage = "pattern to match URL on")
4143
private String urlMatch;
4244

45+
@Option(name = "--remote", metaVar = "REMOTE", usage = "name of remote to replicate to")
46+
private Set<String> remotesToConsider = new HashSet<>();
47+
4348
@Option(name = "--wait", usage = "wait for replication to finish before exiting")
4449
private boolean wait;
4550

@@ -70,7 +75,9 @@ protected void run() throws Failure {
7075
}
7176

7277
Future<?> future =
73-
pushFactory.create(urlMatch, projectFilter, state, now).schedule(0, TimeUnit.SECONDS);
78+
pushFactory
79+
.create(urlMatch, remotesToConsider, projectFilter, state, now)
80+
.schedule(0, TimeUnit.SECONDS);
7481

7582
if (wait) {
7683
if (future != null) {

src/main/resources/Documentation/cmd-start.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SYNOPSIS
1212
ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ start
1313
[--now]
1414
[--wait]
15+
[--remote <REMOTE> ...]
1516
{--url <PATTERN> | [--url <PATTERN>] --all | [--url <PATTERN>] <PROJECT PATTERN> ...}
1617
```
1718

@@ -102,6 +103,12 @@ URL contains the substring `PATTERN`, or whose expanded project
102103
URL contains `PATTERN`. This can be useful to replicate only to
103104
a previously down node, which has been brought back online.
104105

106+
`--remote <REMOTE>`
107+
: Replicate only to the destination whose remote name exactly matches
108+
`REMOTE`. May be specified multiple times to target several remotes.
109+
Remote names correspond to the `[remote "name"]` sections in
110+
`replication.config`.
111+
105112
EXAMPLES
106113
--------
107114
Replicate every project, to every configured remote:
@@ -142,6 +149,18 @@ Replicate to only one specific destination URL:
142149
$ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ start --url https://example.com/tools/gerrit.git
143150
```
144151

152+
Replicate all projects to a specific named remote:
153+
154+
```console
155+
$ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ start --remote replica1 --all
156+
```
157+
158+
Replicate all projects to two named remotes:
159+
160+
```console
161+
$ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ start --remote replica1 --remote replica2 --all
162+
```
163+
145164
SEE ALSO
146165
--------
147166

src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationIT.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Arrays;
3434
import java.util.List;
3535
import java.util.Optional;
36+
import java.util.Set;
3637
import java.util.concurrent.CountDownLatch;
3738
import java.util.concurrent.ExecutorService;
3839
import java.util.concurrent.Executors;
@@ -242,7 +243,8 @@ public void pushAllWait() throws Exception {
242243
plugin
243244
.getSysInjector()
244245
.getInstance(PushAll.Factory.class)
245-
.create(null, new ReplicationFilter(Arrays.asList(project.get())), state, false)
246+
.create(
247+
null, Set.of(), new ReplicationFilter(Arrays.asList(project.get())), state, false)
246248
.schedule(0, TimeUnit.SECONDS);
247249

248250
future.get();
@@ -262,7 +264,8 @@ public void pushAllWaitCancelNotRunningTask() throws Exception {
262264
plugin
263265
.getSysInjector()
264266
.getInstance(PushAll.Factory.class)
265-
.create(null, new ReplicationFilter(Arrays.asList(project.get())), state, false)
267+
.create(
268+
null, Set.of(), new ReplicationFilter(Arrays.asList(project.get())), state, false)
266269
.schedule(0, TimeUnit.SECONDS);
267270

268271
CountDownLatch latch = new CountDownLatch(1);
@@ -453,6 +456,51 @@ public void shouldReplicateWithPushBatchSizeSetForRemote() throws Exception {
453456
}
454457
}
455458

459+
@Test
460+
public void shouldReplicateToMatchingRemote() throws Exception {
461+
Project.NameKey targetProject = createTestProject(project + "replica");
462+
463+
setReplicationDestination("foo", "replica", ALL_PROJECTS);
464+
reloadConfig();
465+
466+
String newRef = "refs/heads/newForTest";
467+
ObjectId newRefTip = createNewBranchWithoutPush("refs/heads/master", newRef);
468+
469+
plugin
470+
.getSysInjector()
471+
.getInstance(ReplicationQueue.class)
472+
.scheduleFullSync(project, null, Set.of("foo"), new ReplicationState(NO_OP), true);
473+
474+
try (Repository repo = repoManager.openRepository(targetProject)) {
475+
waitUntil(() -> checkedGetRef(repo, newRef) != null);
476+
477+
Ref targetBranchRef = getRef(repo, newRef);
478+
assertThat(targetBranchRef).isNotNull();
479+
assertThat(targetBranchRef.getObjectId()).isEqualTo(newRefTip);
480+
}
481+
}
482+
483+
@Test
484+
public void shouldNotReplicateToNonMatchingRemote() throws Exception {
485+
Project.NameKey targetProject = createTestProject(project + "replica");
486+
487+
setReplicationDestination("foo", "replica", ALL_PROJECTS);
488+
reloadConfig();
489+
490+
String newRef = "refs/heads/newForTest";
491+
createNewBranchWithoutPush("refs/heads/master", newRef);
492+
493+
plugin
494+
.getSysInjector()
495+
.getInstance(ReplicationQueue.class)
496+
.scheduleFullSync(project, null, Set.of("bar"), new ReplicationState(NO_OP), true);
497+
498+
try (Repository repo = repoManager.openRepository(targetProject)) {
499+
assertThrows(
500+
InterruptedException.class, () -> waitUntil(() -> checkedGetRef(repo, newRef) != null));
501+
}
502+
}
503+
456504
private void waitUntil(Supplier<Boolean> waitCondition) throws InterruptedException {
457505
WaitUtil.waitUntil(waitCondition, TEST_TIMEOUT);
458506
}

0 commit comments

Comments
 (0)