Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-89727: Fix os.fwalk RecursionError on deep trees#100347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
jonburdo wants to merge31 commits intopython:mainfromjonburdo:iterative-os-fwalk

Conversation

jonburdo
Copy link
Contributor

@jonburdojonburdo commentedDec 19, 2022
edited by bedevere-bot
Loading

Use a stack to implement os.fwalk iteratively instead of recursively to avoid hitting recursion limits on deeply nested trees.

Similar to how this is done foros.walk in#99803

@bedevere-bot
Copy link

Most changes to Pythonrequire a NEWS entry.

Please add it using theblurb_it web app or theblurb command-line tool.

@bedevere-bot
Copy link

Most changes to Pythonrequire a NEWS entry.

Please add it using theblurb_it web app or theblurb command-line tool.

@jonburdo
Copy link
ContributorAuthor

jonburdo commentedDec 19, 2022
edited
Loading

TODO:

jonburdoand others added13 commitsDecember 20, 2022 10:05
Use a stack to implement os.walk iteratively instead of recursively toavoid hitting recursion limits on deeply nested trees.
…2015)Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>Co-authored-by: Christian Heimes <christian@python.org>Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>Fixespython#89051
@AlexWaygoodAlexWaygood removed request fora team and1st1December 20, 2022 15:13
@gpsheadgpshead self-requested a reviewDecember 24, 2022 02:45
@jonburdojonburdo marked this pull request as draftJanuary 4, 2023 22:56
Make sure file descriptors get closed if an exception occurs right after the file descriptor was popped from the stack. Also catch exceptions thrown by calling os.close on an already-closed file-descriptor when doing file descriptor cleanup.
@arhadthedevarhadthedev added the stdlibPython modules in the Lib dir labelMar 23, 2023
@jonburdo
Copy link
ContributorAuthor

jonburdo commentedMar 23, 2023
edited
Loading

Note that handling of a single exception should function the same, but repeated errors will interrupt the file descriptor cleanup (closing).

Imagine a user holds downctrl-c sending a burst ofKeyboardExceptions. Previously in the recursive version there were nested try-finally statements making sureclose(fd) gets called. I believe each exception might cause one of theseclose(fd) calls to be missed (if it occurs in the finally beforeclose(fd) is executed), but after the burst of exceptions is over, the remaining calls would be made. Now the cleanup is handled in a loop, so a single exception would end the fd cleanup:

try:            ...except:forfdinreversed(fd_stack):try:close(fd)exceptOSError:passraise

I'm not sure this is a problem. If I understand correctly, neither versions handles this perfectly. It seemed worth mentioning though.

I thought about changing theexcept OSError: is this cleanup loop to a bareexcept:, but then you get kind of a weird, inconsistent behavior where aKeyboardInterrupt that happens to fall just before the try-except starts will end the loop, but one that falls in the try-except won't.

@jonburdojonburdo marked this pull request as ready for reviewMarch 23, 2023 15:16
@jonburdojonburdo requested review fromAlexWaygood and removed request forgpsheadMarch 24, 2023 00:35
@jonburdo
Copy link
ContributorAuthor

Opening this up for review in response to#89727 (comment)

If an exception occurred between `close(fd_stack[-1])` and `fd_stack.pop()`, then we would close the fd a second time in the except clause. It would be better to risk leaving the fd open, as the previous implementation of fwalk could
Copy link
Contributor

@barneygalebarneygale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

LGTM, nice work!

@barneygale
Copy link
Contributor

barneygale commentedMar 31, 2023
edited
Loading

A thought: could you merge_fwalk() intofwalk()? As we're no longer calling_fwalk() recursively, the separation appears pointless, and theyield from indirection will have a small performance cost.

jonburdo reacted with thumbs up emoji

Lib/os.py Outdated
Comment on lines 563 to 570
except:
for action, value in reversed(stack):
if action is _WalkAction.CLOSE:
try:
close(value)
except OSError:
pass
raise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Could this be afinally: block?

AlexWaygood reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Sure, would you consider that more readable or explicit? I just didn't see any benefit, since this is only needed if an exception occurs. The only functional difference would be that we'd iterate over an empty list if no exceptions occur right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think I'd consider it more explicit, though feel free to wait for another opinion if you'd like.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'd also preferfinally here. Not sure if it actually delivers any functional benefit here (can't remember the exact semantics off the top of my head...), but it does feel at least more readable to me.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Makes sense, thanks for clarifying. I'll change it tofinally. Functionally, I thinkfinally is slightly worse but it's negligible.

In this case, changing tofinally is functionally equivalent to adding anelse clause with the same for-loop:

try:            ...except:foraction,valueinreversed(stack): ...raiseelse:foraction,valueinreversed(stack): ...

If no exception occurs in thetry, thenstack will be empty and all of the fds will have been closed already. So changing tofinally means we're adding a step where we simply iterate over an empty list - unnecessary, but costs almost nothing.

To me, a bareexcept indicates a cleanup step, butfinally is even more explicit, so it probably makes sense here.

@barneygale
Copy link
Contributor

@jonburdo I've fixed this in another PR -#119638. Shamefully I forgot about this PR :(.

Comparing our code, I think we arrived at similar solutions, the main difference being that I moved thelstat() of directory entries our of thescandir() loop. If there's anything you think I've missed in my implementation please let me know or log another PR and I'll review. Thanks and sorry.

@jonburdo
Copy link
ContributorAuthor

@barneygale No worries! Thanks for mentioning it. I meant to follow up on this. I'll take a look at your PR.

Thanks for working on this function and the related ones! It feels great to see these improvements :)

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@barneygalebarneygalebarneygale approved these changes

@AlexWaygoodAlexWaygoodAwaiting requested review from AlexWaygood

Assignees
No one assigned
Labels
awaiting mergestdlibPython modules in the Lib dir
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

12 participants
@jonburdo@bedevere-bot@barneygale@AlexWaygood@arhadthedev@slateny@graingert@tbwolfe@rkojedzinszky@fnesveda@pablogsal@erlend-aasland

[8]ページ先頭

©2009-2025 Movatter.jp