powderkeg

cgrand 2017-03-27T08:35:02.469841Z

Issue #27 is killing me: how can we have not seen it sooner? (okay we are used to cycling the sparkcontext when things get weird)

cgrand 2017-03-27T08:38:33.505290Z

The core of the issue os that (defn foo …) creates a class named ns$foo and when you redefine it you get another class going by the same name. Once packaged and sent to workers, workers have two copies of the class and use the first one (the older one).

viesti 2017-03-27T08:58:05.707576Z

hmm so on every redefine, workers get another jar onto classpath?

cgrand 2017-03-27T08:58:59.717224Z

not on every redef, on every barrier (eg a call to rdd)

cgrand 2017-03-27T08:59:38.724368Z

so if you have severak redefs between two barriers only the last one is put in the jar

viesti 2017-03-27T09:07:40.810817Z

hum

viesti 2017-03-27T09:08:07.815300Z

thinking of a test for this :)

cgrand 2017-03-27T09:08:32.819723Z

not hard if you allow yourself to use eval

viesti 2017-03-27T09:08:38.820612Z

should read more about spark worker classpath management

viesti 2017-03-27T09:08:46.822118Z

ah, true

viesti 2017-03-27T09:09:42.831906Z

Clojure's dynamic classloader is probably not available on workers?

viesti 2017-03-27T09:10:30.840705Z

err, how does spark repl do this?

cgrand 2017-03-27T09:16:03.899011Z

spark repl = spark scala shell ?

viesti 2017-03-27T09:19:59.940104Z

yep, forgot the name

cgrand 2017-03-27T09:21:14.953222Z

a mix of private scala-specific stuff and not solving all issues

viesti 2017-03-27T09:37:14.120290Z

scala is not as repl centric as clojure, from what I remember, app in the repl is a bit foreign (keeping state not so straightforward)

viesti 2017-03-27T09:39:45.145318Z

I'd probably look into ClojureDynamicClassloader a bit, can't say immediate answer

cgrand 2017-03-27T09:41:16.160490Z

some options: • automatically cycle context on redefs 😞 • or document cycling cases (along with protocol redefs) • rename classes (either at broadcast time or by hotpatching clojure)

viesti 2017-03-27T09:46:07.209181Z

would class renaming work?

cgrand 2017-03-27T09:52:04.271503Z

If you want to be 99.99% certain it’s hard work

cgrand 2017-03-27T09:53:04.281668Z

because, before putting classes into the jar you have to transform the class to change its name and change all callers too to refer to the new name and...

cgrand 2017-03-27T09:53:54.290528Z

it’s not even going to work because at the other end we can’t change kry ClassResolver.

cgrand 2017-03-27T09:54:11.293230Z

so hotpatching

cgrand 2017-03-27T09:55:12.303788Z

this test should always be true https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L3932

viesti 2017-03-27T10:30:07.637960Z

this is just the kind of exciting way to learn Clojure internals 🙂

viesti 2017-03-27T10:39:44.722511Z

first thought that since this is related to loading classes, I’d look into DynamicClassloader, but now that I did so, it seems to be more of a cache compiled classes, for which the name munging has to be done first

cgrand 2017-03-27T10:47:43.789585Z

what was your general plan with DynClassLoader?

viesti 2017-03-27T11:05:53.947296Z

firstly to understand how Clojure class redefining works

cgrand 2017-03-27T11:09:00.973183Z

user=> (eval '(do (defn x [] 1) (def x1 x) (defn x [] 2) (def x2 x) [x1 x2]))
[#object[user$x 0xbe35cd9 "user$x@be35cd9"] #object[user$x 0x44821a96 "user$x@44821a96"]]
user=> (map #(%) *1)
(1 2)
user=> (map class *2)
(user$x user$x)
user=> (map #(.getClassLoader %) *1)
(#object[clojure.lang.DynamicClassLoader 0x72cde7cc "clojure.lang.DynamicClassLoader@72cde7cc"] #object[clojure.lang.DynamicClassLoader 0x696da30b "clojure.lang.DynamicClassLoader@696da30b"])
user=> (map #(.getParent %) *1)
(#object[clojure.lang.DynamicClassLoader 0x2accdbb5 "clojure.lang.DynamicClassLoader@2accdbb5"] #object[clojure.lang.DynamicClassLoader 0x2accdbb5 "clojure.lang.DynamicClassLoader@2accdbb5"])

cgrand 2017-03-27T11:09:44.979108Z

so despite classes having same name they have different classloaders (which share common ancestor)

cgrand 2017-03-27T11:10:07.982163Z

so they are different classes from a JVM point of view

viesti 2017-03-27T15:00:14.955738Z

right so re-defining also creates a classloader by which the class is loaded

viesti 2017-03-27T15:26:26.426573Z

tricky

cgrand 2017-03-27T15:56:27.960005Z

Looks like a step forward

user=> (class foo)
user$foo__1596
user=> (defn foo [])
#'user/foo
user=> (class foo)
user$foo__1601

viesti 2017-03-27T16:14:39.275179Z

would we need to patch other Exprs than FnExpr too?

viesti 2017-03-27T16:21:31.386790Z

so normally when one does defn foo in ns1, then uses ns1/foo in ns2/bar, in order to make ns2/bar use re-defined ns1/foo, one has to redefine ns2/bar, if I’m correct

viesti 2017-03-27T16:22:32.403520Z

just wondering that to keep similar behaviour, only new class name would be needed

cgrand 2017-03-27T16:33:04.576578Z

This is unrelated. You are conflating class names and car names.

viesti 2017-03-27T16:34:21.597181Z

🙂

cgrand 2017-03-27T16:52:32.884367Z

So when var A uses var B one doesn't have to redef in cascade. This is not true when it's the var value (instead of the var) that is closed over. The latter is more of a special case.

viesti 2017-03-27T17:22:21.360521Z

ah because one get’s to fetch the current binding of the var

viesti 2017-03-27T17:25:55.417100Z

http://blog.ndk.io/clojure-compilation.html