blob: 7bf2c594a45ff520512cf49fc99c9823fa200eeb [file] [log] [blame]
// Copyright (C) 2018 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.multisite.forwarder;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.multisite.Configuration;
import com.googlesource.gerrit.plugins.multisite.forwarder.events.GroupIndexEvent;
import com.googlesource.gerrit.plugins.multisite.index.ForwardedIndexExecutor;
import com.googlesource.gerrit.plugins.multisite.index.GroupChecker;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Index a group using {@link GroupIndexer}. This class is meant to be used on the receiving side of
* the {@link IndexEventForwarder} since it will prevent indexed group to be forwarded again causing
* an infinite forwarding loop between the 2 nodes. It will also make sure no concurrent indexing is
* done for the same group uuid
*/
@Singleton
public class ForwardedIndexGroupHandler extends ForwardedIndexingHandler<String, GroupIndexEvent> {
private final GroupIndexer indexer;
private final GroupChecker groupChecker;
private final ScheduledExecutorService indexExecutor;
private final int retryInterval;
private final int maxTries;
@Inject
ForwardedIndexGroupHandler(
GroupIndexer indexer,
Configuration config,
GroupChecker groupChecker,
@ForwardedIndexExecutor ScheduledExecutorService indexExecutor) {
super(config.index().numStripedLocks());
this.indexer = indexer;
this.groupChecker = groupChecker;
this.indexExecutor = indexExecutor;
Configuration.Index indexConfig = config.index();
this.retryInterval = indexConfig != null ? indexConfig.retryInterval() : 0;
this.maxTries = indexConfig != null ? indexConfig.maxTries() : 0;
}
@Override
protected void doIndex(String uuid, Optional<GroupIndexEvent> event)
throws IOException, OrmException {
doIndex(uuid, event, 0);
}
protected void doIndex(String uuid, Optional<GroupIndexEvent> groupIndexEvent, int retryCount)
throws IOException {
indexer.index(new AccountGroup.UUID(uuid));
if (groupChecker.isGroupUpToDate(groupIndexEvent)) {
if (retryCount > 0) {
log.warn("Group '{}' has been eventually indexed after {} attempt(s)", uuid, retryCount);
} else {
log.debug("Group '{}' successfully indexed", uuid);
}
} else {
log.debug("Group '{}' rescheduling indexing", uuid);
rescheduleIndex(uuid, groupIndexEvent, retryCount + 1);
}
}
private boolean rescheduleIndex(
String uuid, Optional<GroupIndexEvent> indexEvent, int retryCount) {
if (retryCount > maxTries) {
log.error(
"Group '{}' could not be indexed after {} retries. Group index could be stale.",
uuid,
retryCount);
return false;
}
log.warn(
"Retrying for the #{} time to index Group {} after {} msecs",
retryCount,
uuid,
retryInterval);
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
indexExecutor.schedule(
() -> {
try {
Context.setForwardedEvent(true);
doIndex(uuid, indexEvent, retryCount);
} catch (Exception e) {
log.warn("Group {} could not be indexed", uuid, e);
}
},
retryInterval,
TimeUnit.MILLISECONDS);
return true;
}
@Override
protected void doDelete(String uuid, Optional<GroupIndexEvent> event) {
throw new UnsupportedOperationException("Delete from group index not supported");
}
}