[ 
https://issues.apache.org/jira/browse/MAPREDUCE-5508?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13767396#comment-13767396
 ] 

Chris Nauroth commented on MAPREDUCE-5508:
------------------------------------------

I was +1 for Xi's patch, but I didn't want to commit it too hastily so that the 
participants on MAPREDUCE-5351 would get a chance to review.  Sandy, thank you 
for responding so quickly.

bq. Have you tested this fix?

Yes, Xi repeated his test run of ~200,000 jobs with this patch, and the heap 
dump no longer showed leaked instances of {{DistributedFileSystem}}.  This is 
definitely the source of the leak.

bq. The deeper problem to me is that we are creating a new UGI, which can have 
a new subject, which can create a new entry in the FS cache, every time 
CleanupQueue#deletePath is called with a null UGI.

Just to clarify, the problem we saw is that a new {{UserGroupInformation}}/new 
{{Subject}} gets created regardless of whether or not a null UGI was passed to 
{{CleanupQueue#deletePath}}.  It's buried behind the last line of this code 
snippet:

{code}
    protected void deletePath() throws IOException, InterruptedException {
      final Path p = getPathForCleanup();
      (ugi == null ? UserGroupInformation.getLoginUser() : ugi).doAs(
          new PrivilegedExceptionAction<Object>() {
            public Object run() throws IOException {
              FileSystem fs = p.getFileSystem(conf);
{code}

The last line eventually hits {{FileSystem#Cache#get}}, which calls 
{{UserGroupInformation#getCurrentUser}} while constructing the cache key, but 
that doesn't always result in the same underlying {{Subject}} instance as the 
one that initially created the FS cache entry.

bq. A better fix would be to avoid this, either by having CleanupQueue hold a 
UGI of the login user for use in these situations or to avoid the doAs entirely 
when the given UGI is null.

We can tell from the heap dump that the leaked instances are associated with 
the user UGI and not the login UGI, so I don't think there is a way to use the 
login UGI to remove those cache entries.  I don't see a way to avoid the doAs, 
because we're seeing the leak in the case of the user UGI, so we'd want the 
impersonation in place.

Side note: the return value of {{UserGroupInformation#getLoginUser}} is cached 
for the lifetime of the process, so it's always going to have the same 
{{Subject}} instance.  That makes it impossible to have a large, visible leak 
in the FS cache for entries associated to the login user.

The only other potential solution I can think of is explicitly passing the 
{{FileSystem}} instance to use for the delete and close into 
{{PathDeletionContext}}.  Then, it wouldn't need to infer the FS to use by 
calling {{Path#getFileSystem}} with its implicit creation of a new {{Subject}}. 
 Do you think something like that would work?

BTW, this problem also made me wonder if it's incorrect for UGI to use an 
identity hash code.  I couldn't track down the rationale for that.  Presumably 
it's related to performance.  The code of {{Subject#hashCode}} combines data 
from a lot of internal data structures, and it all happens while holding the 
monitor.  This made me think changing the hash code would be too risky.
                
> JobTracker memory leak caused by unreleased FileSystem objects in 
> JobInProgress#cleanupJob
> ------------------------------------------------------------------------------------------
>
>                 Key: MAPREDUCE-5508
>                 URL: https://issues.apache.org/jira/browse/MAPREDUCE-5508
>             Project: Hadoop Map/Reduce
>          Issue Type: Bug
>          Components: jobtracker
>    Affects Versions: 1-win, 1.2.1
>            Reporter: Xi Fang
>            Assignee: Xi Fang
>            Priority: Critical
>         Attachments: MAPREDUCE-5508.patch
>
>
> MAPREDUCE-5351 fixed a memory leak problem but introducing another filesystem 
> object (see "tempDirFs") that is not properly released.
> {code} JobInProgress#cleanupJob()
>   void cleanupJob() {
> ...
>           tempDirFs = jobTempDirPath.getFileSystem(conf);
>           CleanupQueue.getInstance().addToQueue(
>               new PathDeletionContext(jobTempDirPath, conf, userUGI, jobId));
> ...
>  if (tempDirFs != fs) {
>       try {
>         fs.close();
>       } catch (IOException ie) {
> ...
> }
> {code}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to