All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.azure.cosmos.implementation.changefeed.epkversion.PartitionControllerImpl Maven / Gradle / Ivy
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.cosmos.implementation.changefeed.epkversion;
import com.azure.cosmos.implementation.changefeed.CancellationToken;
import com.azure.cosmos.implementation.changefeed.CancellationTokenSource;
import com.azure.cosmos.implementation.changefeed.Lease;
import com.azure.cosmos.implementation.changefeed.LeaseContainer;
import com.azure.cosmos.implementation.changefeed.LeaseManager;
import com.azure.cosmos.implementation.changefeed.PartitionController;
import com.azure.cosmos.implementation.changefeed.PartitionSupervisor;
import com.azure.cosmos.implementation.changefeed.PartitionSupervisorFactory;
import com.azure.cosmos.implementation.changefeed.exceptions.FeedRangeGoneException;
import com.azure.cosmos.implementation.changefeed.exceptions.LeaseLostException;
import com.azure.cosmos.implementation.changefeed.exceptions.TaskCancelledException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Implementation for {@link PartitionController}.
*/
class PartitionControllerImpl implements PartitionController {
private static final Logger logger = LoggerFactory.getLogger(PartitionControllerImpl.class);
private final Map currentlyOwnedPartitions = new ConcurrentHashMap<>();
private final LeaseContainer leaseContainer;
private final LeaseManager leaseManager;
private final PartitionSupervisorFactory partitionSupervisorFactory;
private final PartitionSynchronizer synchronizer;
private CancellationTokenSource shutdownCts;
private final Scheduler scheduler;
public PartitionControllerImpl(
LeaseContainer leaseContainer,
LeaseManager leaseManager,
PartitionSupervisorFactory partitionSupervisorFactory,
PartitionSynchronizer synchronizer,
Scheduler scheduler) {
this.leaseContainer = leaseContainer;
this.leaseManager = leaseManager;
this.partitionSupervisorFactory = partitionSupervisorFactory;
this.synchronizer = synchronizer;
this.scheduler = scheduler;
}
@Override
public Mono initialize() {
this.shutdownCts = new CancellationTokenSource();
return this.loadLeases();
}
@Override
public synchronized Mono addOrUpdateLease(final Lease lease) {
WorkerTask workerTask = this.currentlyOwnedPartitions.get(lease.getLeaseToken());
if (workerTask != null && workerTask.isRunning()) {
return this.leaseManager.updateProperties(lease)
.map(updatedLease -> {
logger.debug("Lease with token {}: updated.", updatedLease.getLeaseToken());
return updatedLease;
});
}
return this.leaseManager.acquire(lease)
.map(updatedLease -> {
WorkerTask checkTask = this.currentlyOwnedPartitions.get(lease.getLeaseToken());
if (checkTask == null) {
logger.info("Lease with token {}: acquired.", updatedLease.getLeaseToken());
PartitionSupervisor supervisor = this.partitionSupervisorFactory.create(updatedLease);
this.currentlyOwnedPartitions.put(updatedLease.getLeaseToken(), this.processPartition(supervisor, updatedLease));
}
return updatedLease;
})
.onErrorResume(throwable -> {
logger.warn("Lease with token {}: unexpected error; removing lease from current cache.", lease.getLeaseToken(), throwable);
return this.removeLease(lease).then(Mono.error(throwable));
});
}
@Override
public Mono shutdown() {
// TODO: wait for the threads to finish.
this.shutdownCts.cancel();
// this.currentlyOwnedPartitions.clear();
return Mono.empty();
}
private Mono loadLeases() {
logger.debug("Starting renew leases assigned to this host on initialize.");
return this.leaseContainer.getOwnedLeases()
.flatMap( lease -> {
logger.info("Lease with token {}: Acquired on startup.", lease.getLeaseToken());
return this.addOrUpdateLease(lease);
}).then();
}
private Mono removeLease(Lease lease) {
return Mono.just(this)
.flatMap(value -> {
WorkerTask workerTask = this.currentlyOwnedPartitions.remove(lease.getLeaseToken());
if (workerTask != null && workerTask.isRunning()) {
workerTask.cancelJob();
}
logger.info("Lease with token {}: released.", lease.getLeaseToken());
return this.leaseManager.release(lease);
})
.onErrorResume(e -> {
if (e instanceof LeaseLostException) {
logger.warn("Lease with token {}: lease already removed.", lease.getLeaseToken());
} else {
logger.warn("Lease with token {}: failed to remove lease.", lease.getLeaseToken(), e);
}
return Mono.empty();
})
.doOnSuccess(aVoid -> {
logger.info("Lease with token {}: successfully removed lease.", lease.getLeaseToken());
});
}
private WorkerTask processPartition(PartitionSupervisor partitionSupervisor, Lease lease) {
CancellationToken shutdownToken = this.shutdownCts.getToken();
WorkerTask partitionSupervisorTask =
new WorkerTask(
lease,
partitionSupervisor,
getWorkerJob(partitionSupervisor, lease, shutdownToken));
this.scheduler.schedule(partitionSupervisorTask);
return partitionSupervisorTask;
}
private Mono getWorkerJob(
PartitionSupervisor partitionSupervisor,
Lease lease,
CancellationToken shutdownToken) {
return partitionSupervisor.run(shutdownToken)
.onErrorResume(throwable -> {
if (throwable instanceof FeedRangeGoneException) {
FeedRangeGoneException ex = (FeedRangeGoneException) throwable;
return this.handleFeedRangeGone(lease, ex.getLastContinuation());
} else if (throwable instanceof TaskCancelledException) {
logger.debug("Lease with token {}: processing canceled.", lease.getLeaseToken());
} else {
logger.warn("Lease with token {}: processing failed.", lease.getLeaseToken(), throwable);
}
return Mono.empty();
})
.then(this.removeLease(lease));
}
private Mono handleFeedRangeGone(Lease lease, String lastContinuationToken) {
lease.setContinuationToken(lastContinuationToken);
return this.synchronizer.getFeedRangeGoneHandler(lease)
.flatMap(partitionGoneHandler -> {
return partitionGoneHandler.handlePartitionGone()
.flatMap(l -> {
if (partitionGoneHandler.shouldSkipDirectLeaseAssignment()) {
return Mono.empty();
} else {
l.setProperties(lease.getProperties());
return this.addOrUpdateLease(l);
}
})
.then(this.tryDeleteGoneLease(lease, partitionGoneHandler.shouldDeleteCurrentLease()));
})
.onErrorResume(throwable -> {
logger.warn("Lease with token {}: failed to handle partition gone", lease.getLeaseToken(), throwable);
return Mono.empty();
});
}
private Mono tryDeleteGoneLease(Lease lease, boolean shouldRemoveLease) {
if (shouldRemoveLease) {
return this.leaseManager.delete(lease);
}
return Mono.empty();
}
}