rgrunber

Category: Eclipse

Hot-Code Replace With The Breakpoint Properties Page in Eclipse

This is a convenient exploitation of how the Breakpoint Properties Page works.

A lot of people are aware of hot-code replacement functionality in the Eclipse JDT (Java Development Tools). This allows one to modify source code while an application is being debugged and have the generated class files be used in the current runtime.

This is great but in the past I have run into issues where this functionality, for some reason fails. This also depends on having editable source files, which doesn’t seem like such a big deal, except that it’s very possible to have source artifacts (fetched by Maven) or source bundles (in the PDE Target Platform) that show up as class files and can’t be (immediately) edited.

So what should you do when you’d like to do a hot-code replace on a class for which you have read-only sources ?

Enter the JDT Breakpoint Properties Page. Generally, this page is meant to help set the conditions on which a breakpoint causes the thread to suspend. For example, you may have some kind of loop that iterates through many values, but only want to investigate what happens on a particular value. Rather than setting a breakpoint in the loop, seeing it suspend on the line, checking the value, hitting resume, over and over until you get the desired value, you could set a condition to suspend when your value is set.

eclipse-breakpoint-properties

So the suspend can be triggered on some condition that will be evaluated prior to executing the line. But there’s nothing stopping us from making the “condition” a code snippet that always returns “false”. The result is a breakpoint that never causes a suspend, but still evaluates the entire code snippet.

One of the simplest things for which this can be used is to insert “printf” statements without actually having to litter them throughout your codebase. Much easier to track and clean :

System.out.println("...");
return false;

With this simple pattern, we can basically emulate something like the CDT’s dynamic printfs .Of course, since this merely inserts code there are some limitations to what can be done versus an actual hot-code replace, but this comes pretty close.

Eclipse inside a Docker Container

I remember having to use mock to test Fedora Eclipse from different releases, and the main reason I used this was to avoid having to create a VM. While there might be some cases today where I’d go through all that (depending on what I’d need to test), Docker images and containers offer an easy way to run Eclipse.

FROM fedora:22
RUN useradd me
RUN dnf install -y eclipse-pde
COPY ./init.sh /
RUN chmod a+x init.sh
CMD [ "/init.sh" ]
#! /bin/bash

usermod -u $MY_UID -g $MY_GID me
su me -c eclipse

From here, we simply build the image, giving the path to the folder containing the Dockerfile and the init.sh file.

docker build -t eclipse .
...
docker run --rm --privileged -v /tmp/.X11-unix/:/tmp/.X11-unix/ -e DISPLAY=$DISPLAY -e MY_UID=$(id -u) -e MY_GID=$(id -g) eclipse

We ran the image in privileged mode, mounting the X11 socket, with the necessary environment variables. To keep from building up containers, we remove them upon exit.

The Eclipse instance should begin rendering within the host machine’s display. There have been a few cases where newer major versions of Eclipse had to be packaged as Copr repos because it wasn’t feasible to update the many required dependencies for a released version of Fedora. This approach seems like a nice way of getting the latest and greatest on an older host, or even testing an older release on a newer host.

If you’d like to use the graphics libraries from the container’s OS version, that can be done as well.

FROM fedora:22
RUN useradd me
RUN dnf install -y mutter gnome-settings-daemon tigervnc-server-minimal eclipse-pde
COPY ./init.sh /
RUN chmod a+x init.sh
CMD [ "/init.sh" ]
#! /bin/bash

# Set d-bus machine-id
if [ ! -e /etc/machine-id ]; then
  dbus-uuidgen > /etc/machine-id
fi

# Properly start d-bus
mkdir -p /var/run/dbus
dbus-daemon --system

rm -f /tmp/.X*-lock
Xvnc -SecurityTypes=none :3 &
mutter -d :3 &
su me -c eclipse

We build the image exactly as before and our image run command even becomes a little simpler. After the container is started, we connect to it on display :3 using a VNC client (eg. vncviewer from tigervnc), to see the running Eclipse instance.

$ docker build -t eclipse .
...
$ docker run --rm -it --privileged -e DISPLAY=:3 eclipse
...
$ vncviewer 172.17.0.2:3

 

Eclipse p2 Droplets in Rawhide

So p2 Droplets have been in Rawhide for a little while now, and since then we’ve converted most Eclipse plugins to build using the new format. With the exception of some cases that will be done manually, pretty much everything building with the XMvn macros (%mvn_build, %mvn_install) is guaranteed to be a p2 Droplet after a rebuild. We still support the old format (Dropins), and an installation on rawhide can detect both types, but the goal is to switch completely to Droplets.

If you’re unfamiliar with the term, you can think of p2 Droplets as a new way of packaging one or more Eclipse features. It contains the same jars and feature folders as before but with an additional file (fragment.info) containing some extra data.

The main reason for the switch was that Dropins (using the p2 Reconciler) has been deprecated for a while and has made it much more difficult to diagnose issues when it fails. Eclipse’s first launch actually caches a lot of data to make subsequent ones much faster, and the Reconciler can be a large chunk of that time. I have actually run into cases where installing just an extra package can take the first startup from around 10 seconds, to 3 minutes!

Testing was done with the following setup :

  • Fedora Rawhide Virtual Machine
  • ~700 OSGi bundles on the system
  • ~430 of these bundles to be tested through the Dropins and Droplets approaches
for i in {1..5}; do rm -rf $HOME/.eclipse/ ; (echo exit; echo y;) | /usr/bin/time -f "%E" eclipse -noexit -console ; done;

To test under Dropins, we simply took all the bundles packaged as Droplets and removed their ‘fragment.info’ file, along with the ‘p2.fragments’ line in ‘/etc/eclipse.ini’, just to be sure we completely disabled the new logic.

So what were the results ? Under Dropins, the average startup time was 17.63 seconds, and under Droplets, it was 9.44 seconds. The variance was very small, and nearly the same for both cases so there’s strong evidence that Droplets will be saving a lot of time on Eclipse’s first startup. Of course all subsequent launches (where $HOME/.eclipse is kept) would be much faster (~2s).

So one might ask what’s happened with all the work the Reconciler used to do.

  1. Fedora maintainers do a good job of making sure packages are using the latest version of a library even when upstream isn’t. As a result, things like the Reconciler aren’t as necessary in attempting to satisfy dependencies across different versions
  2. A lot of the logic to calculate dependencies and produce a self-sustaining package is done properly at build-time, and rightfully so because that’s where the provides/requires are generated.

We’ve been working on this change, along with the other aspects of simplifying Eclipse plugin packaging for a while now so it’s nice to see some easy wins immediately from adoption.