Skip to content

Commit

Permalink
add proxy to avoid too much connections
Browse files Browse the repository at this point in the history
  • Loading branch information
Jimilian committed Feb 20, 2018
1 parent b95acf0 commit 5e98942
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.GerritProject;
import hudson.util.TimeUnit2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Keeps map between url and dynamic trigger configuration.
* It's used to speed up execution time during updating
* trigger jobs and reduce number of connections for the duplicated configs.
*/
final class DynamicConfigurationCacheProxy {
private static final DynamicConfigurationCacheProxy CACHE_PROXY = new DynamicConfigurationCacheProxy();
private final Map<String, List<GerritProject>> cache = new HashMap<String, List<GerritProject>>();
private static final Logger logger = LoggerFactory.getLogger(DynamicConfigurationCacheProxy.class);
private final Map<String, Long> ttl = new HashMap<String, Long>();

/**
* Private constructor.
*/
private DynamicConfigurationCacheProxy() {
}

/**
* Returns dynamic trigger config from the cache if it's available.
* Otherwise send query.
*
* @param url url to dynamic trigger config.
* @return list of gerrit projects.
* @throws IOException if so.
* @throws ParseException if so.
*/
synchronized List<GerritProject> fetchThroughCache(String url) throws IOException, ParseException {
if (cache.containsKey(url) && !isExpired(url)) {
logger.debug("Get dynamic projects from cache for URL: " + url);
return cache.get(url);
}

logger.info("Get dynamic projects directly for URL: {}", url);
List<GerritProject> gerritProjects = GerritDynamicUrlProcessor.fetch(url);
ttl.put(url, System.currentTimeMillis());
cache.put(url, gerritProjects);

return gerritProjects;
}

/**
* Return global cache proxy objects.
*
* @return cache proxy object.
*/
static DynamicConfigurationCacheProxy getInstance() {
return CACHE_PROXY;
}

/**
* Check the need to update specified url.
*
* @param url url.
* @return true if cached value is expired.
*/
private boolean isExpired(String url) {
Long lastTimeUpdated = ttl.get(url);
if (lastTimeUpdated == null) {
lastTimeUpdated = System.currentTimeMillis();
}

long updateInterval = GerritTriggerTimer.getInstance().calculateAverageDynamicConfigRefreshInterval();
return TimeUnit2.MILLISECONDS.toSeconds(System.currentTimeMillis() - lastTimeUpdated) > updateInterval;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.GerritProject;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.Topic;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -53,6 +55,7 @@
*
* @author Fredrik Abrahamson &lt;fredrik.abrahamson@sonymobile.com&gt;
*/
@Restricted(NoExternalUse.class)
public final class GerritDynamicUrlProcessor {

private static final Logger logger = LoggerFactory.getLogger(GerritDynamicUrlProcessor.class);
Expand Down Expand Up @@ -126,13 +129,12 @@ private static String regexEscapted(char symbol) {
* Read and parse the dynamic trigger configuration.
*
* @param reader stream from which to read the config
* @param serverName the name of the Gerrit server configured in the project, could be null.
*
* @return List of Gerrit projects
* @throws ParseException when the fetched content couldn't be parsed
* @throws IOException for all other kinds of fetch errors
*/
private static List<GerritProject> readAndParseTriggerConfig(BufferedReader reader, String serverName)
private static List<GerritProject> readAndParseTriggerConfig(BufferedReader reader)
throws IOException, ParseException {
Pattern linePattern = buildLinePattern();

Expand Down Expand Up @@ -238,12 +240,11 @@ private static List<GerritProject> readAndParseTriggerConfig(BufferedReader read
* since the last fetch, it returns null.
*
* @param gerritTriggerConfigUrl the URL to fetch
* @param serverName name of the Gerrit server.
* @return a list of GerritProjects if successful, or null if no change
* @throws ParseException when the fetched content couldn't be parsed
* @throws IOException for all other kinds of fetch errors
*/
public static List<GerritProject> fetch(String gerritTriggerConfigUrl, String serverName)
public static List<GerritProject> fetch(String gerritTriggerConfigUrl)
throws IOException, ParseException {

if (gerritTriggerConfigUrl == null) {
Expand All @@ -264,13 +265,17 @@ public static List<GerritProject> fetch(String gerritTriggerConfigUrl, String se
try {
instream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(instream, Charset.forName("UTF-8")));
return readAndParseTriggerConfig(reader, serverName);
return readAndParseTriggerConfig(reader);
} finally {
if (reader != null) {
reader.close();
} else if (instream != null) {
instream.close();
}
try {
if (reader != null) {
reader.close();
}
} finally {
if (instream != null) {
instream.close();
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1720,33 +1720,27 @@ public void updateTriggerConfigURL() {
}
triggerInformationAction.setErrorMessage("");
try {
if (isAnyServer()) {
triggerInformationAction.setErrorMessage("Dynamic trigger configuration needs "
+ "a specific configured server");
} else {
List<GerritProject> fetchedProjects = GerritDynamicUrlProcessor.fetch(triggerConfigURL, serverName);
dynamicGerritProjects = fetchedProjects;
}
dynamicGerritProjects = DynamicConfigurationCacheProxy.getInstance().fetchThroughCache(triggerConfigURL);
} catch (ParseException pe) {
String logErrorMessage = MessageFormat.format(
"ParseException for project: {0} and URL: {1} Message: {2}",
new Object[]{job.getName(), triggerConfigURL, pe.getMessage()});
job.getName(), triggerConfigURL, pe.getMessage());
logger.error(logErrorMessage, pe);
String triggerInformationMessage = MessageFormat.format(
"ParseException when fetching dynamic trigger url: {0}", pe.getMessage());
triggerInformationAction.setErrorMessage(triggerInformationMessage);
} catch (MalformedURLException mue) {
String logErrorMessage = MessageFormat.format(
"MalformedURLException for project: {0} and URL: {1} Message: {2}",
new Object[]{job.getName(), triggerConfigURL, mue.getMessage()});
job.getName(), triggerConfigURL, mue.getMessage());
logger.error(logErrorMessage, mue);
String triggerInformationMessage = MessageFormat.format(
"MalformedURLException when fetching dynamic trigger url: {0}", mue.getMessage());
triggerInformationAction.setErrorMessage(triggerInformationMessage);
} catch (SocketTimeoutException ste) {
String logErrorMessage = MessageFormat.format(
"SocketTimeoutException for project: {0} and URL: {1} Message: {2}",
new Object[]{job.getName(), triggerConfigURL, ste.getMessage()});
job.getName(), triggerConfigURL, ste.getMessage());
logger.error(logErrorMessage, ste);
String triggerInformationMessage = MessageFormat.format(
"SocketTimeoutException when fetching dynamic trigger url: {0}", ste.getMessage());
Expand All @@ -1755,7 +1749,7 @@ public void updateTriggerConfigURL() {
} catch (IOException ioe) {
String logErrorMessage = MessageFormat.format(
"IOException for project: {0} and URL: {1} Message: {2}",
new Object[]{job.getName(), triggerConfigURL, ioe.getMessage()});
job.getName(), triggerConfigURL, ioe.getMessage());
logger.error(logErrorMessage, ioe);
String triggerInformationMessage = MessageFormat.format(
"IOException when fetching dynamic trigger url: {0}", ioe.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private long calculateDynamicConfigRefreshInterval(@Nonnull GerritTrigger trigge
*
* @return the average value.
*/
private long calculateAverageDynamicConfigRefreshInterval() {
long calculateAverageDynamicConfigRefreshInterval() {
long total = 0;
for (GerritServer server : PluginImpl.getServers_()) {
total += server.getConfig().getDynamicConfigRefreshInterval();
Expand All @@ -136,7 +136,6 @@ public void schedule(GerritTriggerTimerTask timerTask, @Nonnull GerritTrigger tr
logger.debug("Schedule task " + timerTask + " for every " + timerPeriod + "ms");
jenkins.util.Timer.get().scheduleWithFixedDelay(timerTask, DELAY_MILLISECONDS, timerPeriod,
TimeUnit.MILLISECONDS);

} catch (IllegalArgumentException iae) {
logger.error("Attempted use of negative delay", iae);
} catch (IllegalStateException ise) {
Expand Down

0 comments on commit 5e98942

Please sign in to comment.