Transactional update of software levels in a dynamic code loading environment.
Original Publication Date: 2004-Feb-25
Included in the Prior Art Database: 2004-Feb-25
This article describes a system which can avoid inconsistent sets of executable code or data being loaded and used while updates to the same set of code or data are potentially being performed at the same time. For example: the problem exists with traditionally dynamically loaded code (.dlls in windows) or java class files loaded by name while an update to a set of jars or dlls is applied. The solution suggested involves a transactional data store in which the code is deposited, and loaded from: such as a database or transactional file system. Affinity between compatible sets of code and data are established as meta-data, which is used to control the loading process, to avoid inconsistent sets of code or data being used by programs currently executing.
Transactional update of software levels in a dynamic code loading environment .
Lets start with a description of the problem, expressed using a java programming model:
Java* Class A relies on java class B. B being middleware for example, A being the application using it. Often A and B are provided by different authors/companies. A is packaged in one jar, and B in another.
Suppose the versions of classes A and B (A0 and B0) are installed and currently being used. The java class loader will have A and B cached in its' class cache. If a software update updates A and B (A1 and B1), then both jars on disk are updated "together". The program shuts down. When it next starts up, A1 and B1 are used, instead of A0 and B0. This is the simple case.
Now suppose the program uses dynamic loading. A0 and B0 are there when the program starts. A0 is loaded, but the loading of B0 is deferred until later. Now the software update is applied, and A0 and B0 on disk are replaced by A1 and B1. Now the program requires the dynamic loading of the B class... so B1gets picked up. A0 and B1 are not compatible.... Bang!
So the problem is to keep track of the fact that A0 requires B0. And not to let the update to A1 and B1 take effect until the
A more tricky problem is that if two instances of the JVM and program are fired-up... how to let A0+B0 run in one JVM, when you update the machine so that the 2nd JVM can run A1+B1.
Another tricky problem is to prevent timing windows such that the A0-A1 upgrade doesn't interact with the starting of a second JVM...which might load A1 before the B0-B1 upgrade is complete...which could mean the second JVM program loading A1 and B0... bang !
OK, so putting all the classes into a single Jar might be a solution, but its' not that elegant... and often isn't possible... if jars are signed, you can't unpack-repack them for example. Often re-packaging is also not possible for legal reasons. Proposed solution: Unpack jars, and Put all the classes in a database. Have a class loader which takes the class files out of the database. Create a "level" of classes, which lists the version of classes A and B used when each JVM starts up. When a JVM starts loading class A, note that this JVM needs to load A0, B0...etc. When updates to the database are made, make them atomic... using a transaction. Hold the old versions in the database until we're sure nothing needs them...this also allows us to "roll-back" changes from the A1 level to the A0 level later if A1 turns out to be bad.
When A second JVM loads A from the database, that loader notes that A1 was loaded, so level 1 of all other classes is needed... so B1 will be loaded when required for this JVM later if class B is dynamically loaded that is. If the original JVM loads B, it will get B0...This sho...