/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.sync.engine.session.rate.limiter;
import com.google.common.util.concurrent.RateLimiter;
import com.liferay.sync.engine.model.SyncAccount;
import com.liferay.sync.engine.model.SyncProp;
import com.liferay.sync.engine.service.SyncAccountService;
import com.liferay.sync.engine.service.SyncPropService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Jonathan McCann
*/
public class RateLimiterManager {
public static synchronized RateLimiter getDownloadRateLimiter(
long syncAccountId) {
RateLimiter rateLimiter = getRateLimiter(
syncAccountId, _downloadRateLimiters);
_downloadRateLimiterCount++;
updateDownloadRateLimits();
return rateLimiter;
}
public static synchronized RateLimiter getUploadRateLimiter(
long syncAccountId) {
RateLimiter rateLimiter = getRateLimiter(
syncAccountId, _uploadRateLimiters);
_uploadRateLimiterCount++;
updateUploadRateLimits();
return rateLimiter;
}
public static synchronized void removeDownloadRateLimiter(
long syncAccountId, RateLimiter rateLimiter) {
List<RateLimiter> rateLimiters = _downloadRateLimiters.get(
syncAccountId);
if (!rateLimiters.remove(rateLimiter)) {
return;
}
_downloadRateLimiterCount--;
updateDownloadRateLimits();
}
public static synchronized void removeUploadRateLimiter(
long syncAccountId, RateLimiter rateLimiter) {
List<RateLimiter> rateLimiters = _uploadRateLimiters.get(syncAccountId);
if (!rateLimiters.remove(rateLimiter)) {
return;
}
_uploadRateLimiterCount--;
updateUploadRateLimits();
}
public static synchronized void updateDownloadRateLimits() {
if (_downloadRateLimiterCount == 0) {
return;
}
int globalMaxDownloadRate =
SyncPropService.getInteger(SyncProp.KEY_GLOBAL_MAX_DOWNLOAD_RATE) /
_downloadRateLimiterCount;
for (Map.Entry<Long, List<RateLimiter>> entry :
_downloadRateLimiters.entrySet()) {
long syncAccountId = entry.getKey();
List<RateLimiter> rateLimiters = entry.getValue();
if (rateLimiters.isEmpty()) {
continue;
}
SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(
syncAccountId);
updateRateLimits(
rateLimiters, globalMaxDownloadRate,
syncAccount.getMaxDownloadRate() / rateLimiters.size());
}
}
public static synchronized void updateUploadRateLimits() {
if (_uploadRateLimiterCount == 0) {
return;
}
int globalMaxUploadRate =
SyncPropService.getInteger(SyncProp.KEY_GLOBAL_MAX_UPLOAD_RATE) /
_uploadRateLimiterCount;
for (Map.Entry<Long, List<RateLimiter>> entry :
_uploadRateLimiters.entrySet()) {
long syncAccountId = entry.getKey();
List<RateLimiter> rateLimiters = entry.getValue();
if (rateLimiters.isEmpty()) {
continue;
}
SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(
syncAccountId);
updateRateLimits(
rateLimiters, globalMaxUploadRate,
syncAccount.getMaxUploadRate() / rateLimiters.size());
}
}
protected static RateLimiter getRateLimiter(
long syncAccountId, Map<Long, List<RateLimiter>> rateLimiterMap) {
RateLimiter rateLimiter = RateLimiter.create(1);
List<RateLimiter> rateLimiters = rateLimiterMap.get(syncAccountId);
if (rateLimiters == null) {
rateLimiters = new ArrayList<>();
rateLimiters.add(rateLimiter);
rateLimiterMap.put(syncAccountId, rateLimiters);
}
else {
rateLimiters.add(rateLimiter);
}
return rateLimiter;
}
protected static void updateRateLimits(
List<RateLimiter> rateLimiters, int globalMaxRateLimit,
int maxRateLimit) {
int rate = 0;
if ((globalMaxRateLimit == 0) && (maxRateLimit == 0)) {
rate = Integer.MAX_VALUE;
}
else if (globalMaxRateLimit == 0) {
rate = maxRateLimit;
}
else if (maxRateLimit == 0) {
rate = globalMaxRateLimit;
}
else {
rate = Math.min(globalMaxRateLimit, maxRateLimit);
}
for (RateLimiter rateLimiter : rateLimiters) {
rateLimiter.setRate(rate);
}
}
private static int _downloadRateLimiterCount;
private static final Map<Long, List<RateLimiter>> _downloadRateLimiters =
new HashMap<>();
private static int _uploadRateLimiterCount;
private static final Map<Long, List<RateLimiter>> _uploadRateLimiters =
new HashMap<>();
}