@@ -219,6 +219,42 @@ DList::ReserveLoadingResourceWithTimeout(const ResourceUsage& original_size, std
219219
220220bool
221221DList::reserveResourceInternal (const ResourceUsage& size) {
222+ auto rollback = []() {};
223+ auto [success, _] = reserveResourceInternalImpl (size, rollback);
224+ return success;
225+ }
226+
227+ std::pair<bool , ResourceUsage>
228+ DList::reserveResourceInternalWithTracker (const ResourceUsage& loaded, const ResourceUsage& overhead,
229+ uint64_t overhead_handle, LoadingOverheadTracker* tracker) {
230+ // Compute tracker delta first so space check uses the actual amount, not the uncapped overhead.
231+ // This avoids rejecting loads that would fit after tracker capping (e.g., delta=0 when group is saturated).
232+ auto delta = overhead;
233+ if (overhead_handle != LoadingOverheadTracker::kInvalidHandle && tracker != nullptr ) {
234+ delta = tracker->Reserve (overhead_handle, overhead);
235+ }
236+ auto actual_size = (loaded + delta) * eviction_config_.loading_resource_factor ;
237+
238+ auto rollback = [overhead_handle, overhead, tracker]() {
239+ if (overhead_handle != LoadingOverheadTracker::kInvalidHandle && tracker != nullptr ) {
240+ tracker->Release (overhead_handle, overhead);
241+ }
242+ };
243+
244+ auto [success, _] = reserveResourceInternalImpl (actual_size, rollback);
245+ if (!success) {
246+ return {false , {}};
247+ }
248+
249+ auto unscaled = loaded + delta;
250+ LOG_TRACE (" [MCL] reserve with tracker: loaded={}, overhead={}, delta={}, unscaled={}, scaled={}, total_loading={}" ,
251+ loaded.ToString (), overhead.ToString (), delta.ToString (), unscaled.ToString (), actual_size.ToString (),
252+ total_loading_size_.load ().ToString ());
253+ return {true , unscaled};
254+ }
255+
256+ std::pair<bool , ResourceUsage>
257+ DList::reserveResourceInternalImpl (const ResourceUsage& size, std::function<void ()> rollback) {
222258 auto using_resources = total_loaded_size_.load () + total_loading_size_.load ();
223259
224260 // Combined logical and physical memory limit check
@@ -268,10 +304,13 @@ DList::reserveResourceInternal(const ResourceUsage& size) {
268304 " [MCL] reserve resource with size={} failed due to all zero evicted_size, "
269305 " eviction_target={}, min_eviction={}" ,
270306 size.ToString (), eviction_target.ToString (), min_eviction.ToString ());
271- return false ;
307+ rollback ();
308+ return {false , {}};
272309 }
310+
311+ using_resources -= evicted_size;
273312 // logical limit is accurate, thus we can guarantee after one successful eviction, logical limit is satisfied.
274- logical_limit_exceeded = false ;
313+ logical_limit_exceeded = !max_resource_limit_. load (). CanHold (using_resources + size) ;
275314
276315 if (!physical_eviction_needed.AnyGTZero ()) {
277316 // we only need to evict for logical limit and we have succeeded.
@@ -290,79 +329,10 @@ DList::reserveResourceInternal(const ResourceUsage& size) {
290329 }
291330
292331 total_loading_size_ += size;
293- LOG_TRACE (" [MCL] reserve resource with size={} success, total_loading_size={}, total_loaded_size={}" ,
294- size.ToString (), total_loading_size_.load ().ToString (), total_loaded_size_.load ().ToString ());
295-
296- return true ;
297- }
298-
299- std::pair<bool , ResourceUsage>
300- DList::reserveResourceInternalWithTracker (const ResourceUsage& loaded, const ResourceUsage& overhead,
301- uint64_t overhead_handle, LoadingOverheadTracker* tracker) {
302- // Compute tracker delta first so space check uses the actual amount, not the uncapped overhead.
303- // This avoids rejecting loads that would fit after tracker capping (e.g., delta=0 when group is saturated).
304- auto delta = overhead;
305- if (overhead_handle != LoadingOverheadTracker::kInvalidHandle && tracker != nullptr ) {
306- delta = tracker->Reserve (overhead_handle, overhead);
307- }
308- auto actual_size = (loaded + delta) * eviction_config_.loading_resource_factor ;
309- auto using_resources = total_loaded_size_.load () + total_loading_size_.load ();
332+ LOG_TRACE (" [MCL] reserve resource success, size={}, total_loading_size={}, total_loaded_size={}" , size.ToString (),
333+ total_loading_size_.load ().ToString (), total_loaded_size_.load ().ToString ());
310334
311- bool logical_limit_exceeded = !max_resource_limit_.load ().CanHold (using_resources + actual_size);
312- auto physical_eviction_needed = checkPhysicalMemoryLimit (actual_size);
313-
314- while (logical_limit_exceeded || physical_eviction_needed.AnyGTZero ()) {
315- ResourceUsage eviction_target;
316- ResourceUsage min_eviction;
317-
318- if (logical_limit_exceeded) {
319- eviction_target = using_resources + actual_size - low_watermark_;
320- min_eviction = using_resources + actual_size - max_resource_limit_.load ();
321- if (eviction_target.memory_bytes < 0 )
322- eviction_target.memory_bytes = 0 ;
323- if (eviction_target.file_bytes < 0 )
324- eviction_target.file_bytes = 0 ;
325- if (min_eviction.memory_bytes < 0 )
326- min_eviction.memory_bytes = 0 ;
327- if (min_eviction.file_bytes < 0 )
328- min_eviction.file_bytes = 0 ;
329- }
330-
331- if (physical_eviction_needed.AnyGTZero ()) {
332- eviction_target.memory_bytes =
333- std::max (eviction_target.memory_bytes , physical_eviction_needed.memory_bytes );
334- eviction_target.file_bytes = std::max (eviction_target.file_bytes , physical_eviction_needed.file_bytes );
335- min_eviction.memory_bytes = std::max (min_eviction.memory_bytes , physical_eviction_needed.memory_bytes );
336- min_eviction.file_bytes = std::max (min_eviction.file_bytes , physical_eviction_needed.file_bytes );
337- }
338-
339- ResourceUsage evicted_size = tryEvict (eviction_target, min_eviction);
340- if (!evicted_size.AnyGTZero ()) {
341- LOG_WARN (
342- " [MCL] reserve with tracker failed: loaded={}, overhead={}, delta={}, eviction_target={}, "
343- " min_eviction={}" ,
344- loaded.ToString (), overhead.ToString (), delta.ToString (), eviction_target.ToString (),
345- min_eviction.ToString ());
346- // Rollback tracker state on failure
347- if (overhead_handle != LoadingOverheadTracker::kInvalidHandle && tracker != nullptr ) {
348- tracker->Release (overhead_handle, overhead);
349- }
350- return {false , {}};
351- }
352- logical_limit_exceeded = false ;
353-
354- if (!physical_eviction_needed.AnyGTZero ())
355- break ;
356- if (physical_eviction_needed = checkPhysicalMemoryLimit (actual_size); !physical_eviction_needed.AnyGTZero ())
357- break ;
358- }
359-
360- total_loading_size_ += actual_size;
361- auto unscaled = loaded + delta;
362- LOG_TRACE (" [MCL] reserve with tracker: loaded={}, overhead={}, delta={}, unscaled={}, scaled={}, total_loading={}" ,
363- loaded.ToString (), overhead.ToString (), delta.ToString (), unscaled.ToString (), actual_size.ToString (),
364- total_loading_size_.load ().ToString ());
365- return {true , unscaled};
335+ return {true , size};
366336}
367337
368338void
@@ -643,16 +613,18 @@ DList::UpdateHighWatermark(const ResourceUsage& new_high_watermark) {
643613 cachinglayer::monitor::cache_high_watermark_bytes (StorageType::DISK).Set (high_watermark_.load ().file_bytes );
644614}
645615
646- void
616+ ResourceUsage
647617DList::ReleaseLoadingResource (const ResourceUsage& loaded, const ResourceUsage& overhead, uint64_t overhead_handle) {
648618 std::vector<std::unique_ptr<WaitingRequest>> to_destroy;
619+ ResourceUsage unscaled{};
649620 {
650621 std::unique_lock<std::mutex> lock (list_mtx_);
651622 auto delta = overhead;
652623 if (overhead_handle != LoadingOverheadTracker::kInvalidHandle && loading_overhead_tracker_) {
653624 delta = loading_overhead_tracker_->Release (overhead_handle, overhead);
654625 }
655- auto actual = (loaded + delta) * eviction_config_.loading_resource_factor ;
626+ unscaled = loaded + delta;
627+ auto actual = unscaled * eviction_config_.loading_resource_factor ;
656628 total_loading_size_ -= actual;
657629 ClampNonNegative (total_loading_size_, [&](const ResourceUsage& curr) {
658630 LOG_ERROR (
@@ -663,6 +635,7 @@ DList::ReleaseLoadingResource(const ResourceUsage& loaded, const ResourceUsage&
663635 to_destroy = handleWaitingRequests ();
664636 }
665637 // Destroy requests outside lock to avoid deadlock with cancel callbacks
638+ return unscaled;
666639}
667640
668641void
@@ -884,14 +857,16 @@ DList::handleWaitingRequests() {
884857 waiting_queue_.pop ();
885858 } else {
886859 // Check if this request is permanently impossible (required size exceeds capacity).
887- // If so, fail it immediately instead of blocking the entire queue until timeout.
860+ // Use required_size for both paths: (loaded + overhead) * factor for tracker-aware,
861+ // which is the upper bound of what the request could need.
888862 if (!max_resource_limit_.load ().CanHold (request_ptr_ref->required_size )) {
889863 auto request = std::move (request_ptr_ref);
890864 if (waiting_requests_map_.erase (request->request_id ) > 0 ) {
891865 LOG_WARN (
892866 " [MCL] Request {} is permanently impossible (required_size={} > capacity={}), "
893867 " failing immediately." ,
894- request->request_id , request->required_size .ToString (), max_resource_limit_.load ().ToString ());
868+ request->request_id , request->required_size .ToString (),
869+ max_resource_limit_.load ().ToString ());
895870 request->setValue (false );
896871 }
897872 requests_to_destroy.push_back (std::move (request));
0 commit comments