@@ -221,16 +221,33 @@ coro::task<void> MemoryReserveOrWait::periodic_memory_check() {
221221 last_reservation_success = Clock::now ();
222222 }
223223
224- // Reaching this point means we hit the timeout. Let's extract the smallest
225- // request, even if it does not fit in the available memory.
224+ // Reaching this point means we hit the timeout. We force progress by selecting
225+ // among the smallest pending requests, preferring the one with the largest
226+ // future_release_potential.
226227 std::unique_lock lock (mutex_);
227228 if (reservation_requests_.empty ()) {
228229 co_return ;
229230 }
230- // The set is sorted by size (ascending). For equal sizes, the request with the
231- // smallest sequence number comes first.
232- Request request =
233- reservation_requests_.extract (reservation_requests_.begin ()).value ();
231+
232+ // The set is sorted by size (ascending). First, find the smallest size.
233+ auto first = reservation_requests_.begin ();
234+ auto const smallest_size = first->size ;
235+
236+ // Consider all requests with that size.
237+ auto same_size_end = std::ranges::upper_bound (
238+ reservation_requests_, smallest_size, std::less<>{}, &Request::size
239+ );
240+
241+ // Among the smallest requests, pick the one with the largest
242+ // future_release_potential. If multiple requests tie, we pick the oldest one,
243+ // since the set is ordered by size and then sequence_number (ascending).
244+ auto it = std::ranges::max_element (
245+ std::ranges::subrange (first, same_size_end),
246+ std::less<>{},
247+ &Request::future_release_potential
248+ );
249+
250+ Request request = reservation_requests_.extract (it).value ();
234251 lock.unlock ();
235252
236253 // Reserve memory and accept a zero-size result if it does not fit into the
0 commit comments