Forum Stats

  • 3,875,416 Users
  • 2,266,914 Discussions
  • 7,912,203 Comments

Discussions

For the impatient: how to patch the JDK and make File -> Open fast again in SQL Dev 22.2 on Windows

user9540031
user9540031 Member Posts: 245 Gold Badge
edited Nov 18, 2022 1:16AM in SQL Developer

If you find the File -> Open dialog very slow in SQL Developer 22.2 on Windows, and you just can't wait, here's how to fix it yourself... if you're ready to build the JDK from the sources, that is. It's not a very difficult thing to do, provided you're familiar enough with the required tools.

For a reminder about why the File -> Open (or Save As) dialog can be so slow in SQL Developer 22.2 on Windows, please see this thread. This issue may also affect the IndexPreferences task.

Here I will share a tiny patch for the JDK, to be applied to the sources of the OpenJDK project, along with a summary of how I did the build, and used it along with SQL Developer 22.2.1.

Important: you should be familiar with installation and use of the Cygwin environment (it is required for building the JDK on Windows), and with build procedures in general.

1/ Links

2/ Requirements

2.a/ Hardware requirements

A powerful enough PC is needed, with plenty of RAM, plus disk space on a fast SSD drive: on top of the requirements for building the JDK (2-4 CPU cores advisable, 2-4 Gb of RAM, 6 Gb of free disk space), you may have to add a lot more if you'll be using a virtual machine for setting up the build environment: say 16 Gb of RAM (of which 8 Gb for the virtual machine), and 150 Gb of free disk space on your SSD drive.

2.b/ Software requirements

When building for the Windows target platform, the software requirements include:

  • Cygwin (preferably in a fresh enough release)
  • Microsoft Visual Studio, 2019 or higher

I don't have Microsoft Visual Studio 2019, and my Windows 7 PC is now out of support, and too old for installing it anyway... Fortunately, a quick and easy solution is available: Microsoft provides pre-built evaluation VMs of Windows 11, with Visual Studio 2022 (Community Edition) pre-installed, and that's all we need. 🙂 So I just upgraded VirtualBox, to the latest 6.1.40 release, downloaded the pre-built VM gently provided by Microsoft, and fired it up. It turned out to be perfect for the job.

2.c/ Bootstrap JDK

It takes one to build one: you need a working JDK to build a newer one from its sources, and in principle that "bootstrap" JDK should be of the previous major release. What is release N-1 for Java 11? I don't know; meanwhile, the build instructions mention that the JDK should be able to "build itself", so that's what I used here.

3/ The Patch

The patch reads as follows (including the final blank line):

diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
index efe64b1a57..6b91cd7b0f 100644
--- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java
+++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
@@ -60,6 +60,21 @@ class WinNTFileSystem extends FileSystem {
         }
     }
 
+    // Whether listRoots() will skip invoking File.exists() on each available
+    // filesystem root or not. By default, each available root is checked, and
+    // this check is bypassed if and only if the property is set, ignoring
+    // case, to the string "true".
+    private static final boolean UNCHECKED_LISTROOTS;
+    static {
+        String uncheckedListRoots = GetPropertyAction.privilegedGetProperty(
+                "java.io.WinNTFileSystem.uncheckedListRoots");
+        if (uncheckedListRoots != null) {
+            UNCHECKED_LISTROOTS = uncheckedListRoots.equalsIgnoreCase(Boolean.TRUE.toString());
+        } else {
+            UNCHECKED_LISTROOTS = false;
+        }
+    }
+
     public WinNTFileSystem() {
         Properties props = GetPropertyAction.privilegedGetProperties();
         slash = props.getProperty("file.separator").charAt(0);
@@ -642,7 +657,9 @@ class WinNTFileSystem extends FileSystem {
             .valueOf(new long[] {listRoots0()})
             .stream()
             .mapToObj(i -> new File((char)('A' + i) + ":" + slash))
-            .filter(f -> access(f.getPath()) && f.exists())
+            .filter((UNCHECKED_LISTROOTS
+                    ? f -> access(f.getPath())
+                    : f -> access(f.getPath()) && f.exists()))
             .toArray(File[]::new);
     }

I include the patch file here (compressed with gzip) in order to spare error-prone file manipulations.

In simple words, what this does is:

a) At class-initialization time, find out whether the java.io.WinNTFileSystem.uncheckedListRoots JVM property is set and equal to true.

b) If (and only if) it is, subsequently calls to File.exists() which, in the listRoots() method, check whether each filesystem root actually exists, will be disabled, thereby reverting listRoots() to its pre-Java 11 behaviour—known to be incorrect, but much faster, and (hopefully) good enough for SQL Developer 22.2.

4/ Software setup

4.a/ Windows 11 guest host

The Windows 11 evaluation pre-built VM comes with Microsoft Visual Studio 2022 (Community Edition) pre-installed, hence not much else is needed aside of Cygwin. I installed Firefox, gvim, Git, KDiff3, and other software in order to feel more at home, but actually none of these is stricly necessary.

4.b/ Cygwin

According to the build instructions, the mandatory Cygwin packages for building the JDK are as follows:

  • autoconf
  • make
  • zip
  • unzip

To the above I added the following:

  • diffutils
  • p7zip
  • patch

4.c/ Bootstrap JDK

I downloaded the binaries of the Open JDK from adoptium.net, in release jdk-11.0.16.1+1 (see Links above), using the ZIP archive (aka non-installer), and I deflated it in such a way that the actual path to the java.exe binary is C:\Products\Java\OpenJDK\jdk-11.0.16.1+1\bin\java.exe

5/ Download the sources

Because SQL Developer 22.2.1 comes bundled with the Oracle JDK in release 11.0.16.1, we'll use the closest corresponding release from the OpenJDK project, namely 11.0.16.1-ga. See Links above.

6/ Build step

6.a/ Working directory

My top-level work directory is C:\Projects\src

The JDK sources will be deflated into C:\Projects\src\jdk11u-dev-jdk-11.0.16.1-ga

Everything will be built in subdirectories of that directory.

6.b/ Expand the JDK sources

cd /cygdrive/C/Projects/src

For convenience, I used 7zip for extracting from the zip package

7z x jdk11u-dev-jdk-11.0.16.1-ga.zip

6.c/ CD into the top directory of the source tree

cd jdk11u-dev-jdk-11.0.16.1-ga

6.d/ Apply the patch

patch --verbose -p1 < /cygdrive/C/path_to/WinNTFileSystem.java.diff

Hmm...  Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
|index efe64b1a57..6b91cd7b0f 100644
|--- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java
|+++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
--------------------------
patching file src/java.base/windows/classes/java/io/WinNTFileSystem.java
Using Plan A...
Hunk #1 succeeded at 60.
Hunk #2 succeeded at 657.
done

6.e/ Run configure

$ bash ./configure \
    --with-boot-jdk=/cygdrive/C/Products/Java/OpenJDK/jdk-11.0.16.1+1 \
    --with-tools-dir="/cygdrive/C/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE"

6.f/ Run make

make

make product-images

On my old PC (quad-core i7-860 from 2009 + SATA SSD), the build times were 39 mins for make, then 7 mins for make product-images.

(With virus-scanning temporarily disabled, as it appeared to eat a lot of CPU-time, possibly slowing things down.)

6.g/ Check the results

Everything is built in the build/windows-x86_64-normal-server-release subdirectory. Log files are available in that directory as configure.log, build.log, build.log.old.

The final JDK image is found in the images/jdk subdirectory of that directory.

cd build/windows-x86_64-normal-server-release/images/jdk

./bin/java -version

openjdk version "11.0.16.1-internal" 2022-08-12
OpenJDK Runtime Environment (build 11.0.16.1-internal+0-adhoc.User.jdk11u-dev-jdk-11.0.16.1-ga)
OpenJDK 64-Bit Server VM (build 11.0.16.1-internal+0-adhoc.User.jdk11u-dev-jdk-11.0.16.1-ga, mixed mode)

It seems to work! 🙂

6.h/ Zip the new JDK image

zip -r jdku11.0.16.1-ga+.zip .

At this stage, the new JDK, packed as a ZIP archive, is ready to be moved from the guest host to the target host.

The name of the archive (jdku11.0.16.1-ga+.zip) ends with a "+" character, as a small reminder that this is the GA release plus one patch—of course this is a strictly "home-only" build, not meant to be redistributed.

7/ Using it in SQL Developer 22.2.1

7.a/ Expand the new JDK from its zip archive into its installation folder

In my case, I installed the new JDK into the following location:

F:\Produits\Win_7\Java\OpenJDK\jdku11.0.16.1-ga+

So that the new java.exe binary is F:\Produits\Win_7\Java\OpenJDK\jdku11.0.16.1-ga+\bin\java.exe

7.b/ Update product.conf

The following line must be added to product.conf, in the %APPDATA%\sqldeveloper\22.2.1 directory:

SetJavaHome F:\Produits\Win_7\Java\OpenJDK\jdku11.0.16.1-ga+

7.c/ Update sqldeveloper.conf

The sqldeveloper.conf file, in the sqldeveloper\bin subdirectory under the top-level installation directory of SQL Developer 22.2.1, must be changed by adding the following 2 lines:

#Enable unchecked File.listRoots()
AddVMOption -Djava.io.WinNTFileSystem.uncheckedListRoots=true

7.d/ Start SQL Developer

Then you may use the Help -> About dialog, Properties tab, and check the following JVM properties:

java.home              F:\Produits\Win_7\Java\OpenJDK\jdku11.0.16.1-ga+
java.version           11.0.16.1-internal
java.vm.version        11.0.16.1-internal+0-adhoc.User.jdk11u-dev-jdk-11.0.16.1-ga
java.runtime.version   11.0.16.1-internal+0-adhoc.User.jdk11u-dev-jdk-11.0.16.1-ga

And, of course, our special JVM property for making File.listRoots() fast again:

java.io.WinNTFileSystem.uncheckedListRoots   true

Then try File -> Open, see if it makes a difference for you.

If that works, fine! 😎

Just remember that this lands you in a totally unsupported territory: only Oracle JDKs are officially supported with SQL Developer, which means that, should you encounter a bug, Oracle may ask you to reproduce it using a supported Oracle JDK. In principle, the JDK from the OpenJDK project and the corresponding Oracle JDK at the same release level are distinct, in that the Oracle JDK may have an unspecified number of additional fixes on top of the OpenJDK sources—the exact list is not publicly available, but we may expect it to be small; AFAIU, the idea is that Oracle may push specific fixes that its clients need, but which are not (or not yet) included in the main OpenJDK sources.

Hope this helps...

Regards,