On 6/8/07, Enzo Michelangeli <[EMAIL PROTECTED]> wrote:
> ----- Original Message -----
> From: "Doğacan Güney" <[EMAIL PROTECTED]>
> Sent: Friday, June 08, 2007 3:49 PM
>
> [...]
> >> Any idea?
> >
> > This will certainly help a lot. If it is not too much trouble, can you
> > add debug outputs for hashCodes of conf objects (both for the one in
> > the cache and for the parameter, because it seems Configuration object
> > is created more than once so their hashCode may be different, which in
> > turn causes the change in CACHE's hashCode(*)) and a stack trace?
> > A stack trace of depth 2-3 will probably suffice, I am just wondering
> > what is calling PluginRepository.get(conf).
>
> OK, I changed my debug code as follows:
>
>   public static synchronized PluginRepository get(Configuration conf) {
>     PluginRepository result = CACHE.get(conf);
>         /* --- start debug code */
>         String tr = "";
>         StackTraceElement[] tes = Thread.currentThread().getStackTrace();
>         for(int j=2; j<tes.length; j++)
>             tr = tr+"\n    "+tes[j].toString();
>         LOG.info("In thread "+Thread.currentThread()+
>                  " a static method of the class "+
>                  (new CurrentClassGetter()).getCurrentClass()+
>                  " called CACHE.get("+conf+
>                  "), where CACHE is "+CACHE+
>                  " and CACHE.hashCode() = "+CACHE.hashCode()+
>                  " - got result = "+result+
>                  " conf.hashCode() was: "+conf.hashCode()+
>                  " hashCode was: "+conf.hashCode()+
>                  " Stack Trace:"+tr);
>         /* end debug code --- */
>     if (result == null) {
>       result = new PluginRepository(conf);
>       CACHE.put(conf, result);
>     }
>     return result;
>   }
>
>   /* --- start debug code */
>   public static class CurrentClassGetter extends SecurityManager {
>     public String getCurrentClass() {
>       Class cl = super.getClassContext()[1];
>       return cl.toString() + "@" + cl.hashCode();
>     }
>   }
>   /* end debug code --- */
>
> (With full stack trace: bytes are cheap ;-) )
>
> I did not bother to print the hashCode of the keys in CACHE because it's
> become evident why CACHE.get(conf) returns null: the hashCode of conf
> changes!

That's true. Take a look at this code from LocalJobRunner.Job.run:
for (int i = 0; i < splits.length; i++) {
          String mapId = "map_" + newId() ;
          mapIds.add(mapId);
          MapTask map = new MapTask(jobId, file, "tip_m_" + mapId,
                                    mapId, i,
                                    splits[i]);
          JobConf localConf = new JobConf(job);
          map.localizeConfiguration(localConf);
          map.setConf(localConf);
          map_tasks += 1;
          myMetrics.launchMap();
          map.run(localConf, this);
          myMetrics.completeMap();
          map_tasks -= 1;
        }

For each new map task, hadoop creates a new configuration object
(which of course makes sense), so its hashCode changes and all hell
breaks loose.

If I understood the code correctly, this will not be a problem in
distributed environment. Each new map task gets its own process
anyway, so there should be no leak.

> This is strange, because, as you can see below, the strings that
> make keys and values of conf appears unchanged. Perhaps we should override
> the equals() method in org.apache.hadoop.conf.Configuration (invoked by
> CACHE.get(), according to the specs of the java.util.Map interface), so that
> the hashCode()s of the keys get ignored, and conf1.equals(conf2) return true
> if and only if:
>
>  1. conf1.size() == conf2.size(),
>
>  2. for each key k1 of conf1 there is a key k2 in conf2 such as:
>   2.1 k1.equals(k2)
>   2.2 conf1.get(k1).equals(conf2.get(k2))

This has been suggested before and I have to say I don't like this
one, because this means that each call to PluginRepository.get(conf)
will end up comparing all key value pairs, which, IMO, is
excessive(because if I am not mistaken, we don't need this when
running nutch in a distributed environment.). Unfortunately, this may
be the only way to fix this leak.

This is probably not a good idea, but here it goes: Perhaps, we can
change LocaJobRunner.Job.run method. First, it clones the JobConf
object (clonedConf).  It then runs a MapTask with the original
JobConf. Upon completion, it copies everything from clonedConf back to
original JobConf. This way, original JobConf's hashCode won't change,
so there should be no leak.


>
> Anyway, I'm attaching the log below.
>
> > Thanks for the detailed analysis!
>
> Glad to be of help!
>
> Enzo
>

-- 
Doğacan Güney
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Nutch-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/nutch-general

Reply via email to