If anyone else is interested, looks like the code is at https://github.com/JulesGosnell/dada/tree/master/dada-core/src/main/java/clojure/lang
Pretty simple modifications actually. Thanks to Jules for figuring it out. On Tue, Apr 26, 2011 at 2:16 PM, kovas boguta <kovas.bog...@gmail.com> wrote: > Hi, > > This sounds very interesting and useful. > > Is the source code available somewhere? Or a more detailed description? > > Thanks > > On Fri, Mar 4, 2011 at 1:48 AM, Jules <jules.gosn...@gmail.com> wrote: >> >> So, >> >> Just a quick update. >> >> I gave the client-side ClassLoader encapsulation idea some more >> thought and rejeted it (sorry) for the reasons that : >> >> - I've lived through J2EE ClassLoader hell and don't want to repeat >> the experience >> >> - I'm looking towards an architecture where I can define new types on >> any node of my Clojure data-grid and have them accessible in any other >> node. This might be done by keeping my class-name:bytecode table in a >> clustered cache and inserting a single ClusteredClassLoader (NYI) into >> the client's ClassLoader hierarchy. Each client would be able to mix >> classes from multiple server JVMs without having to be concerned about >> keeping them all segregated. >> >> So, I introduced the concept of a per-jvm id and hacked it into RT, >> Compiler and LispReader. There were not too many places that needed to >> be changed. >> >> The result is, I can now create a type in one jvm, create an instance >> of the type, serialise it, ship the bytes to another jvm and >> deserialise it, at which point the instance's class is pulled from the >> original jvm. No more nasty exceptions because of name collisions etc. >> >> I have plumbed this infrastructure in underneath my app and, with the >> exception of some unrelated bugs that I am chasing down, everything >> seems to work beautifully :-) >> >> There are some limitations with this technique that I haven't looked >> into too deeply yet - the most obvious one is that whilst remote types >> can be made available within a local jvm, this is only at the java >> level, so extra things that defrecord might do for you like intern the >> classname as a symbol in your current namespace are not being done - >> which, I can currently live with, but I can see this being a tripping >> point to a completely transparent solution. >> >> For me, this is a great leap forward as I have found each Clojure JVM >> an island until I got this working, but now I should be able to build >> a distributed app in Clojure without having to sacrifice Clojure's >> dynamicity in the process - I can have my cake and eat it :-) >> >> I'm going to play with it for a few days, iron out all my other issues >> and investigate exactly what I have achieved, then I will post back a >> proper description in case anyone else is trying to build distributed >> Clojure apps in a similar manner. >> >> cheers >> >> >> Jules >> >> On Mar 3, 2:30 pm, Jules <jules.gosn...@gmail.com> wrote: >>> On Mar 3, 1:22 pm, Alessio Stalla <alessiosta...@gmail.com> wrote: >>> >>> >>> >>> >>> >>> > On Thursday, March 3, 2011 11:46:03 AM UTC+1, Jules wrote: >>> >>> > > Thanks, Alessio, >>> >>> > > I did know this, but it is a welcome addition to the thread. >>> >>> > Ok. Classloaders are a tricky matter and many people don't have clear >>> > ideas >>> > about them - sorry for assuming you were one of those people :) >>> >>> np :-) >>> >>> > > I reread my last posting and it was a bit confused - I've done a >>> > > little research in the Compiler class and can now clarify what I think >>> > > is happening. >>> >>> > > Clojure 1.3.0-alpha4 >>> > > user=> (type (fn [])) >>> > > user$eval1$fn__2 >>> > > user=> >>> >>> > > Here I have created a new function and asked it for its class. Clojure >>> > > has emitted bytecode on the fly to implement this and packed this into >>> > > a Java Class. A Class has a name unique - as you pointed out - within >>> > > its ClassLoader, so to avoid name collisions, Clojure attempts to >>> > > create a unique name for the class. This is composed, amongst other >>> > > things from its namespace and RT.nextID() (I'm assuming RT = RunTime). >>> >>> > > RT.nextID seems to start at 0 and allocate ids sequentially - lets >>> > > create another fn : >>> >>> > > user=> (type (fn [])) >>> > > user$eval5$fn__6 >>> > > user=> >>> >>> > > I suspect that the gap between 2 and 6 is due to other processes going >>> > > on behind the scenes which require ids, rather than some intentional >>> > > design - but haven't checked. >>> >>> > > This all works fine in a single JVM - no two functions will end up >>> > > creating types with the same name - however if I take the class for a >>> > > function from [a ClassLoader in] one clojure runtime and copy it >>> > > across to another clojure runtime that has already allocated this >>> > > classes id to another [in the receiving ClassLoader] then I would see >>> > > a collision. >>> >>> > > I think that this is what is happening above. I am serialising an >>> > > object in one jvm, putting it into a message and sending the message >>> > > to another jvm. Upon receipt I attempt to deserialise the object >>> > > contained in the message. This involves looking up its class by name >>> > > [within the scope of a ClassLoader] - but the name has already been >>> > > allocated to a local class [within the same ClassLoader] which is >>> > > mistakenly then used to try to deserialise the object. The object's >>> > > data is not presented in the format that the local class expects for >>> > > one of its own instances - hence the Exception in my posting above. >>> >>> > > This is currently only theory. >>> >>> > Makes sense. >>> >>> > > I think that the easiest way to fix it is to use not just a jvm-local >>> > > uid as part of the class name, but also an id which uniquely >>> > > identifies this jvm amongst all the jvms involved in my cluster. It >>> > > looks like not too many classes make use of RT.nextID(), so I think my >>> > > next move will be to add an e.g. RT.jvmID and use this in conjunction >>> > > with RT.nextID(). If this resolves my problem then there is a good >>> > > chance that my supposition was correct - otherwise it is back to the >>> > > drawing board. >>> >>> > I think a better option is to make sure that the classloader you use for >>> > deserializing is completely separated from the classloader Clojure uses to >>> > load compiled functions. Then, no possibility of collision exists, >>> > regardless of how you generate class names.- Hide quoted text - >>> >>> > - Show quoted text - >>> >>> That's an interesting idea, that I haven't really pursued, I think, >>> OTOH, because client-side, I think that I want to be able to mix >>> objects that herald from both local and remote jvms... - but this is >>> just a gut feeling, I haven't really looked for any concrete usecases >>> in any detail, so I'll give your suggestion consideration and see >>> whether it would fit the bill. >>> >>> Using your approach would also be a good way of checking that my >>> assumption about the name collision was correct, so I may see if I can >>> set up my code to use a different ClassLoader in which to deserialise >>> to see if that solves my problem. >>> >>> Thanks for this idea, it may help me a lot :-) >>> >>> Jules- Hide quoted text - >>> >>> - Show quoted text - >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegroups.com >> Note that posts from new members are moderated - please be patient with your >> first post. >> To unsubscribe from this group, send email to >> clojure+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en