semihsalihoglu/distributed_graph_debugger — pull request #30 by netj (2014-05-21 03:06:14+00:00)
Title: More robust "Sandwich" instrumentation

Using two classes: one at the top and another at the bottom.
The bottom class which extends user's Computation class intercepts API
calls originating from Giraph, e.g., compute(), initialize(),
preSuperstep(), while the top class intercepts API calls originating
from user's code, e.g., sendMessage().

The bottom class is renamed by appending a `Debug` postfix to user's
Computation class' name, which will be executed by the giraph-debug
script instead of the user's original Computation class.

The top class has to be injected between the ancestor class of user's
Computation class and the AbstractComputation class (which the top class
extends).

Changing the superclass of a class using Javassist involved three steps:
1. Use CtClass#setSuperclass(), then
2. Use CtClass#replaceClassName() to replace all occurences. Otherwise,
any reference to `super`, e.g., `super.compute()` causes problem.
3. Use CtClass#setGenericSignature() to make sure the type signature is
consistent with the new inheritance chain. Otherwise, any type
parameter checks will fail and Giraph will refuse to start the job.

The most tricky part was rewiring user's top class that extends
AbstractComputation to correctly extend our
AbstractInterceptingComputation instead. The generic signature
`Lorg/apache/giraph/graph/AbstractComputation;`
had to be replaced carefully (looking for AbstractComputation's
JVM descriptor without the semicolon, and substitute it with our
AbstractInterceptingComputation's JVM descriptor without the semicolon)
to make user's type parameters for I,V,E,M1,M2 all work correctly.