Bug 560414 - JGit performs DNS lookup at startup
Summary: JGit performs DNS lookup at startup
Status: RESOLVED FIXED
Alias: None
Product: JGit
Classification: Technology
Component: JGit (show other bugs)
Version: 5.6   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 5.6.2   Edit
Assignee: Alex Blewitt CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 553535 560449
  Show dependency tree
 
Reported: 2020-02-22 07:23 EST by Alex Blewitt CLA
Modified: 2020-03-10 18:29 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Blewitt CLA 2020-02-22 07:23:50 EST
EGit/JGit has a path whereby the hostname of the current machine is used to acquire a (presumably unique) key. The problem with this approach is that it will result in potential network delays (depending on network configuration) when starting up JGit.

https://github.com/eclipse/jgit/blob/67b9effc655d8ba75acb7db5e49687224d1c7a6a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java#L207-L210

The construction of the JAVA_VERSION_PREFIX (including the hostname) occurs when this class is loaded; in EGit's case, it happens because it's setting the FS.async to true, which is unrelated.

If the key was calculated on demand, then the cost of this hit would be the first time it is used, as opposed to when the class is loaded; however, it would seem better to avoid having any calculation on the host name at all, and instead use (say) a UUID instead.

Worse, we actually perform two lookups; once to get the hostname by the getLocalHost, and the second by doing a canonicalisation lookup.
Comment 1 Alex Blewitt CLA 2020-02-22 07:29:16 EST
This was caused by the change in 551850
Comment 2 Alex Blewitt CLA 2020-02-22 07:32:19 EST
Introduced in e102bbed995f0e6d3a1a8e5db6d08f9804fd3260 but perhaps should be reverted?
Comment 3 Alex Blewitt CLA 2020-02-22 07:39:54 EST
Reverting saves about 100ms on the startup of egit.core.

An alternative would be to compute the key on demand when it is called for the first time.

Another alternative would be to wrap it in a new class, which won't be initialised until it is accessed for the first time:

class FS {
...
static class Constant {
  private static final JAVA_VERSION_PREFIX = getSlowName() + version;
}
...
getConfigKey(String key) {
  ...
  return Constant.JAVA_VERSION_PREFIX + key;
}
...
}

This will increase the size of the code slightly (overhead of another class) but will defer the constant creation until the first time getConfigKey is used.
Comment 4 Alex Blewitt CLA 2020-02-22 12:33:28 EST
FWIW the difference between 5.5.1 and 5.6.1 is about 25ms for the following call:

FS.setAsyncFileStoreAttributes(true);

Mostly it's not the call that's the cost, but the loading of the associated classes and the network class lookup.

--- 8< ---
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>testy</groupId>
  <artifactId>testy</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <exec.mainClass>Testy</exec.mainClass>
  </properties>
  <dependencies>
    <dependency>
	  <groupId>org.eclipse.jgit</groupId>
	  <artifactId>org.eclipse.jgit</artifactId>
	  <!--version>5.6.1.202002131546-r</version-->
	  <version>5.5.1.201910021850-r</version>
	</dependency>
  </dependencies>
</project>
--- 8< ---

--- 8< ---
import org.eclipse.jgit.util.*;
import org.slf4j.*;

public class Testy {
		public static void main(String args[]) throws Exception {
				log();
				fs();
		}
		public static void fs() throws Exception {
				long start = System.currentTimeMillis();
				FS.setAsyncFileStoreAttributes(true);
				long end = System.currentTimeMillis();
				System.out.println("Time FS: " + (end - start) + "ms");
		}
		public static void log() throws Exception {
				long start = System.currentTimeMillis();
				LoggerFactory.getLogger(Testy.class).info("Logger loaded");
				long end = System.currentTimeMillis();
				System.out.println("Time log: " + (end - start) + "ms");
		}
}
--- 8< ---

The logger setup is there to prevent the time taken for logging setup to be confused with the FS setup.
Comment 5 Eclipse Genie CLA 2020-02-22 17:06:38 EST
New Gerrit change created: https://git.eclipse.org/r/158138
Comment 6 Eclipse Genie CLA 2020-02-22 17:22:52 EST
Gerrit change https://git.eclipse.org/r/158138 was merged to [stable-5.6].
Commit: http://git.eclipse.org/c/jgit/jgit.git/commit/?id=abb461533fccfd59117c3415cf9c0ed06e460473
Comment 7 Lars Vogel CLA 2020-03-10 18:28:04 EDT
Thanks, Alex