Fix possible "nmalloc >= ndalloc" assertion

In arena_stats_merge() first nmalloc was read, and after ndalloc.

However with this order, it is possible for some thread to incement
ndalloc in between, and then nmalloc < ndalloc, and assertion will fail,
like again found by ClickHouse CI [1] (even after #2234).

  [1]: https://github.com/ClickHouse/ClickHouse/issues/31531

Swap the order to avoid possible assertion.

Cc: @interwq
Follow-up for: #2234
This commit is contained in:
Azat Khuzhin 2022-07-03 20:23:59 +03:00 committed by Qi Wang
parent a9215bf18a
commit cb578bbe01

View File

@ -106,18 +106,21 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
astats->metadata_thp += metadata_thp; astats->metadata_thp += metadata_thp;
for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) { for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) {
uint64_t nmalloc = locked_read_u64(tsdn, /* ndalloc should be read before nmalloc,
LOCKEDINT_MTX(arena->stats.mtx), * since otherwise it is possible for ndalloc to be incremented,
&arena->stats.lstats[i].nmalloc); * and the following can become true: ndalloc > nmalloc */
locked_inc_u64_unsynchronized(&lstats[i].nmalloc, nmalloc);
astats->nmalloc_large += nmalloc;
uint64_t ndalloc = locked_read_u64(tsdn, uint64_t ndalloc = locked_read_u64(tsdn,
LOCKEDINT_MTX(arena->stats.mtx), LOCKEDINT_MTX(arena->stats.mtx),
&arena->stats.lstats[i].ndalloc); &arena->stats.lstats[i].ndalloc);
locked_inc_u64_unsynchronized(&lstats[i].ndalloc, ndalloc); locked_inc_u64_unsynchronized(&lstats[i].ndalloc, ndalloc);
astats->ndalloc_large += ndalloc; astats->ndalloc_large += ndalloc;
uint64_t nmalloc = locked_read_u64(tsdn,
LOCKEDINT_MTX(arena->stats.mtx),
&arena->stats.lstats[i].nmalloc);
locked_inc_u64_unsynchronized(&lstats[i].nmalloc, nmalloc);
astats->nmalloc_large += nmalloc;
uint64_t nrequests = locked_read_u64(tsdn, uint64_t nrequests = locked_read_u64(tsdn,
LOCKEDINT_MTX(arena->stats.mtx), LOCKEDINT_MTX(arena->stats.mtx),
&arena->stats.lstats[i].nrequests); &arena->stats.lstats[i].nrequests);