After much pain mucking about in namespaces, I finally managed to load GemStone code saved in Store using atomic loading.
Atomic loading first loads code into a temporary namespace called the shadow namespace. Once everything is compiled there and it looks good, the system is re-compiled into the real namespace and the shadow namespace disappears.
With GemStone code, I thought I had everything setup to compile the code into the shadow namespace but when I did the actual compile, the code ended up in the real namespace right away. This is bad because in the shadow world, the system would add the compilerClass and classCompilerClass methods to tell the shadow class what the compiler is. You don't want to move these methods into the real namespace because it would cause crashes - which it did.
To allow me to quickly see what was going on, I wrote a tool that simply showed a tree view with a portion of the namespace hierarchy that I was interested in along with the shadow hierarchy. It also showed the identityHashes of the namespaces so I could quickly tell what namespace I was looking at in an inspector. If the namespace contained shared variables or classes, it would show those in the tree and if the classes had methods, it would show those as well. Here's what it looked like.
Now for the problem. When you login to GemStone as a user (for example, David), GemKit creates a namespace for you called Root.GemStone.AllUsers.David. It also aliases this as Root.GemStone.CurrentUser. You can see that in the above image.
When you create the shadow environment, Store creates a mimic of the namespace structure. Since CurrentUser wasn't marked as a namespace link, Store didn't create it in Shadow. Ok, fair enough. I augmented the system to create CurrentUser in the shadow namespace. Sadly, that wasn't enough to fix the problem.
Now when I try to compile, the system locates Root.GemStone in the shadow namespace (so far so good) and asks it to resolve the symbol #UserGlobals. This is where it will put the class it's compiling. UserGlobals isn't in GemStone directly but rather in CurrentUser which is in the imports of GemStone. The problem: The imported namespace CurrentUser is coming from the real environment instead of the shadow environment. It finds UserGlobals in the real world and compiles the class directly there.
Aaarg - ok, I go and smash the imports in the shadow GemStone namespace to point to the CurrentUser in the shadow. Now it complains about a method conflict during the install. When you try to move the shadow classes to the real environment, you must first move the class then move the methods. When you move a GemStone class to the real world, you automatically get a class method called gsst_definition. When we try to move the gsst_definition method from the shadow world to the real world, the system detects that there's a conflict and stops.
As it turns out, you have to change both imported namespaces in the shadow GemStone to point to the shadow and you also need to change the imported namespaces in the shadow GemStone.Globals to point back to the shadow GemStone instead of the real GemStone.
<sigh> After all that, atomic loading works with GemStone code. Yay! I think I'll pop a bottle of bubbly and share it with my wife tonight.
For my next challenge: Cincom switched Store to use Glorp instead of the older direct mechanism. GemKit has tools which are coded for the old mechanism and need to be modified to work with Glorp.
No comments:
Post a Comment