Skip to content

Commit 163612b

Browse files
committed
Merge branch 'stable-3.12' into stable-3.13
* stable-3.12: Add --remote switch to replication start command Change-Id: Ifa94395155956f48dae777e0e41222a79554afbd
2 parents 8dafd93 + 4698ef0 commit 163612b

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
@@ -34,6 +34,7 @@
3434
import java.util.Arrays;
3535
import java.util.List;
3636
import java.util.Optional;
37+
import java.util.Set;
3738
import java.util.concurrent.CountDownLatch;
3839
import java.util.concurrent.ExecutorService;
3940
import java.util.concurrent.Executors;
@@ -281,7 +282,8 @@ public void pushAllWait() throws Exception {
281282
plugin
282283
.getSysInjector()
283284
.getInstance(PushAll.Factory.class)
284-
.create(null, new ReplicationFilter(Arrays.asList(project.get())), state, false)
285+
.create(
286+
null, Set.of(), new ReplicationFilter(Arrays.asList(project.get())), state, false)
285287
.schedule(0, TimeUnit.SECONDS);
286288

287289
future.get();
@@ -301,7 +303,8 @@ public void pushAllWaitCancelNotRunningTask() throws Exception {
301303
plugin
302304
.getSysInjector()
303305
.getInstance(PushAll.Factory.class)
304-
.create(null, new ReplicationFilter(Arrays.asList(project.get())), state, false)
306+
.create(
307+
null, Set.of(), new ReplicationFilter(Arrays.asList(project.get())), state, false)
305308
.schedule(0, TimeUnit.SECONDS);
306309

307310
CountDownLatch latch = new CountDownLatch(1);
@@ -492,6 +495,51 @@ public void shouldReplicateWithPushBatchSizeSetForRemote() throws Exception {
492495
}
493496
}
494497

498+
@Test
499+
public void shouldReplicateToMatchingRemote() throws Exception {
500+
Project.NameKey targetProject = createTestProject(project + "replica");
501+
502+
setReplicationDestination("foo", "replica", ALL_PROJECTS);
503+
reloadConfig();
504+
505+
String newRef = "refs/heads/newForTest";
506+
ObjectId newRefTip = createNewBranchWithoutPush("refs/heads/master", newRef);
507+
508+
plugin
509+
.getSysInjector()
510+
.getInstance(ReplicationQueue.class)
511+
.scheduleFullSync(project, null, Set.of("foo"), new ReplicationState(NO_OP), true);
512+
513+
try (Repository repo = repoManager.openRepository(targetProject)) {
514+
waitUntil(() -> checkedGetRef(repo, newRef) != null);
515+
516+
Ref targetBranchRef = getRef(repo, newRef);
517+
assertThat(targetBranchRef).isNotNull();
518+
assertThat(targetBranchRef.getObjectId()).isEqualTo(newRefTip);
519+
}
520+
}
521+
522+
@Test
523+
public void shouldNotReplicateToNonMatchingRemote() throws Exception {
524+
Project.NameKey targetProject = createTestProject(project + "replica");
525+
526+
setReplicationDestination("foo", "replica", ALL_PROJECTS);
527+
reloadConfig();
528+
529+
String newRef = "refs/heads/newForTest";
530+
createNewBranchWithoutPush("refs/heads/master", newRef);
531+
532+
plugin
533+
.getSysInjector()
534+
.getInstance(ReplicationQueue.class)
535+
.scheduleFullSync(project, null, Set.of("bar"), new ReplicationState(NO_OP), true);
536+
537+
try (Repository repo = repoManager.openRepository(targetProject)) {
538+
assertThrows(
539+
InterruptedException.class, () -> waitUntil(() -> checkedGetRef(repo, newRef) != null));
540+
}
541+
}
542+
495543
private void waitUntil(Supplier<Boolean> waitCondition) throws InterruptedException {
496544
WaitUtil.waitUntil(waitCondition, TEST_TIMEOUT);
497545
}

0 commit comments

Comments
 (0)