Skip to content

Fix deadlock in OvercommitTracker logging#38246

Merged
novikd merged 7 commits intomasterfrom
overcommit-deadlock-fix
Jun 27, 2022
Merged

Fix deadlock in OvercommitTracker logging#38246
novikd merged 7 commits intomasterfrom
overcommit-deadlock-fix

Conversation

@novikd
Copy link
Copy Markdown
Member

@novikd novikd commented Jun 20, 2022

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in official stable or prestable release)

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

Do not allow recursive usage of OvercommitTracker during logging. Fixes #37794
cc @tavplubix @davenger

@robot-clickhouse robot-clickhouse added the pr-bugfix Pull request with bugfix, not backported by default label Jun 20, 2022
@davenger davenger self-assigned this Jun 20, 2022
@nikitamikhaylov
Copy link
Copy Markdown
Member

I'd rather tried to get rid of all allocations (as much as possible) in the OvercommitMemoryTracker. Because that code will work under high memory pressure and that could be an issue when we are trying to allocate more memory when we have to free it for another query.

@novikd
Copy link
Copy Markdown
Member Author

novikd commented Jun 20, 2022

@nikitamikhaylov The problem here is that we have logging inside of the OvercommitTracker (for debug purposes). And logging may lead to the allocation of the memory. I can't get rid of these allocations (if we remove logs from here, I don't know how to debug it).
We definitely shouldn't have in call stack something like: OvercommitTracker -> Logging -> OvercommitTracker. This PR tries to do it correctly.

@tavplubix
Copy link
Copy Markdown
Member

@novikd, there's another problem and it's not only about logging. When some code does memory allocations it may throw exceptions like MEMORY_LIMIT_EXCEEDED/CANNOT_ALLOCATE_MEMORY/std::bad_alloc/etc from unexpected places. It may cause obscure and hard-to-debug issues on high memory pressure if that code is not exception-safe. For example:

allow_release = true;
required_memory += amount;
required_per_thread[tracker] = amount;

Looks like the line 68 may allocate memory and therefore throw (at least it's not clear from the code why it cannot). In this case changes to allow_release and required_memory will not be undone. Consider using DENY_ALLOCATIONS_IN_SCOPE or NOEXCEPT_SCOPE macros here to avoid such issues.

@novikd
Copy link
Copy Markdown
Member Author

novikd commented Jun 21, 2022

@tavplubix @nikitamikhaylov I removed usage of unordered_map in OvercommitTracker, and now we have no allocations there. But at some point, we'd like to have a FIFO order for thread releasing, which will highly likely require memory allocations.

@tavplubix
Copy link
Copy Markdown
Member

and now we have no allocations there

Let's add DENY_ALLOCATIONS_IN_SCOPE just to be sure

@davenger
Copy link
Copy Markdown
Member

Isn't logging itself doing allocations when formatting strings?

@tavplubix
Copy link
Copy Markdown
Member

Isn't logging itself doing allocations when formatting strings?

It is. We can use something like

DENY_ALLOCATIONS_IN_SCOPE;
doCriticalStuff();
{
    ALLOW_ALLOCATIONS_IN_SCOPE;
    LOG_INFO(log, "It can do allocations");
}
continueDoingCriticalStuff();

Or a bit more paranoid:

DENY_ALLOCATIONS_IN_SCOPE;
doCriticalStuff();
{
    NOEXCEPT_SCOPE;
    /// logging is done in try-catch, so we don't expect any exceptions here
    ALLOW_ALLOCATIONS_IN_SCOPE;
    LOG_INFO(log, "It can do allocations");
}
continueDoingCriticalStuff();

@davenger
Copy link
Copy Markdown
Member

Maybe do it in the macro, like this:

  #define LOG_DEBUG_SAFE(...)                       \
    do {                                            \
        OvercommitTrackerBlockerInThread blocker;   \
        try                                         \ 
        {                                           \
            ALLOW_ALLOCATIONS_IN_SCOPE;             \
            LOG_DEBUG(__VA_ARGS__);                 \
        }                                           \
        catch (std::badalloc &)                     \
        {                                           \
             fprintf(stderr, "Allocation failed when writing to log in OvercommitTracker\n");   \
        }                                           \
    } while (false)

@tavplubix tavplubix self-assigned this Jun 21, 2022
Copy link
Copy Markdown
Member

@tavplubix tavplubix left a comment

Choose a reason for hiding this comment

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

LGTM

@novikd
Copy link
Copy Markdown
Member Author

novikd commented Jun 23, 2022

@Mergifyio update

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Jun 23, 2022

update

✅ Branch has been successfully updated

@novikd
Copy link
Copy Markdown
Member Author

novikd commented Jun 24, 2022

@Mergifyio update

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Jun 24, 2022

update

✅ Branch has been successfully updated

@novikd novikd added the pr-must-backport Pull request should be backported intentionally. Use this label with great care! label Jun 27, 2022
@novikd
Copy link
Copy Markdown
Member Author

novikd commented Jun 27, 2022

PullRequestCI / TestsBugfixCheck (pull_request) Failing after 27s — TestsBugfixCheck

Ok. No tests added.

@novikd novikd merged commit b629d55 into master Jun 27, 2022
@novikd novikd deleted the overcommit-deadlock-fix branch June 27, 2022 19:57
novikd added a commit that referenced this pull request Jun 29, 2022
Backport #38246 to 22.6: ('Fix deadlock in OvercommitTracker logging',)
novikd added a commit that referenced this pull request Jul 1, 2022
Backport #38246 to 22.5: ('Fix deadlock in OvercommitTracker logging',)
@Felixoid Felixoid added the pr-backports-created Backport PRs are successfully created, it won't be processed by CI script anymore label Jul 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-backports-created Backport PRs are successfully created, it won't be processed by CI script anymore pr-bugfix Pull request with bugfix, not backported by default pr-must-backport Pull request should be backported intentionally. Use this label with great care!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deadlock in ProcessList

6 participants