From 57077fda223d7c77c4df4ffd1054fb5237a7b919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Wed, 15 May 2019 10:13:34 +0200 Subject: When rescheduling due to in-flight push log also the in-flight task ID When a push operation was rescheduled due to an in-flight push we logged a line like: [79bda07a] Rescheduling replication to https://host/foo.git to avoid collision with an in-flight push. This log was already useful but it didn't tell us which push task was actually in-flight. Add the ID of the in-flight push task to the log: [79bda07a] Rescheduling replication to https://host/foo.git to avoid collision with the in-flight push [80ceb18b]. This information is especially useful when a task gets repeatedly rescheduled and we need to identify the root cause of that. (cherry picked from commit f585eba0d21be222404b871bfe7a2b11e578eb14) Change-Id: I7866f964cab1e4f479b0d7d62ae4aac3019fab4b --- .../gerrit/plugins/replication/Destination.java | 11 ++--- .../gerrit/plugins/replication/PushOne.java | 13 ++++-- .../gerrit/plugins/replication/RunwayStatus.java | 49 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/googlesource/gerrit/plugins/replication/RunwayStatus.java diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java index 0cee37c..40f9900 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java @@ -460,18 +460,19 @@ public class Destination { return projectControlFactory.controlFor(project); } - boolean requestRunway(PushOne op) { + RunwayStatus requestRunway(PushOne op) { synchronized (stateLock) { if (op.wasCanceled()) { - return false; + return RunwayStatus.canceled(); } pending.remove(op.getURI()); - if (inFlight.containsKey(op.getURI())) { - return false; + PushOne inFlightOp = inFlight.get(op.getURI()); + if (inFlightOp != null) { + return RunwayStatus.denied(inFlightOp.getId()); } inFlight.put(op.getURI(), op); } - return true; + return RunwayStatus.allowed(); } void notifyFinished(PushOne op) { diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java index 20f5a0b..fdf6109 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java @@ -249,6 +249,10 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning { return states.toArray(new ReplicationState[states.size()]); } + public int getId() { + return id; + } + void addStates(ListMultimap states) { stateMap.putAll(states); } @@ -295,10 +299,13 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning { // created and scheduled for a future point in time.) // MDC.put(ID_MDC_KEY, IdGenerator.format(id)); - if (!pool.requestRunway(this)) { - if (!canceled) { + RunwayStatus status = pool.requestRunway(this); + if (!status.isAllowed()) { + if (!status.isCanceled()) { repLog.info( - "Rescheduling replication to {} to avoid collision with an in-flight push.", uri); + "Rescheduling replication to {} to avoid collision with the in-flight push [{}].", + uri, + IdGenerator.format(status.getInFlightPushId())); pool.reschedule(this, Destination.RetryReason.COLLISION); } return; diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/RunwayStatus.java b/src/main/java/com/googlesource/gerrit/plugins/replication/RunwayStatus.java new file mode 100644 index 0000000..bcb1e2f --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/RunwayStatus.java @@ -0,0 +1,49 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.replication; + +public class RunwayStatus { + public static RunwayStatus allowed() { + return new RunwayStatus(true, 0); + } + + public static RunwayStatus canceled() { + return new RunwayStatus(false, 0); + } + + public static RunwayStatus denied(int inFlightPushId) { + return new RunwayStatus(false, inFlightPushId); + } + + private final boolean allowed; + private final int inFlightPushId; + + private RunwayStatus(boolean allowed, int inFlightPushId) { + this.allowed = allowed; + this.inFlightPushId = inFlightPushId; + } + + public boolean isAllowed() { + return allowed; + } + + public boolean isCanceled() { + return !allowed && inFlightPushId == 0; + } + + public int getInFlightPushId() { + return inFlightPushId; + } +} -- cgit v1.2.3