Increases consumption of this tracker and its ancestors by 'bytes' only if they can all consume 'bytes' without exceeding limit (hard or soft) specified by 'mode'. If any limit would be exceed, no MemTrackers are updated. If the caller can tolerate an allocation failing, it should set mode=SOFT so that other callers that may not tolerate allocation failures have a better chance of success. Returns
| 176 | /// other callers that may not tolerate allocation failures have a better chance |
| 177 | /// of success. Returns true if the consumption was successfully updated. |
| 178 | WARN_UNUSED_RESULT |
| 179 | bool TryConsume(int64_t bytes, MemLimit mode = MemLimit::HARD) { |
| 180 | DCHECK_GE(bytes, 0); |
| 181 | DCHECK(!closed_) << label_; |
| 182 | if (UNLIKELY(bytes == 0)) return true; |
| 183 | if (UNLIKELY(bytes < 0)) return false; // needed in RELEASE, hits DCHECK in DEBUG |
| 184 | if (consumption_metric_ != nullptr) RefreshConsumptionFromMetric(); |
| 185 | int i; |
| 186 | // Walk the tracker tree top-down. |
| 187 | for (i = all_trackers_.size() - 1; i >= 0; --i) { |
| 188 | MemTracker* tracker = all_trackers_[i]; |
| 189 | const int64_t limit = tracker->GetLimit(mode); |
| 190 | if (limit < 0) { |
| 191 | tracker->consumption_->Add(bytes); // No limit at this tracker. |
| 192 | } else { |
| 193 | // If TryConsume fails, we can try to GC, but we may need to try several times if |
| 194 | // there are concurrent consumers because we don't take a lock before trying to |
| 195 | // update consumption_. |
| 196 | while (true) { |
| 197 | if (LIKELY(tracker->consumption_->TryAdd(bytes, limit))) break; |
| 198 | |
| 199 | VLOG_RPC << "TryConsume failed, bytes=" << bytes |
| 200 | << " consumption=" << tracker->consumption_->current_value() |
| 201 | << " limit=" << limit << " attempting to GC"; |
| 202 | if (UNLIKELY(tracker->GcMemory(limit - bytes))) { |
| 203 | DCHECK_GE(i, 0); |
| 204 | // Failed for this mem tracker. Roll back the ones that succeeded. |
| 205 | for (int j = all_trackers_.size() - 1; j > i; --j) { |
| 206 | all_trackers_[j]->consumption_->Add(-bytes); |
| 207 | } |
| 208 | return false; |
| 209 | } |
| 210 | VLOG_RPC << "GC succeeded, TryConsume bytes=" << bytes |
| 211 | << " consumption=" << tracker->consumption_->current_value() |
| 212 | << " limit=" << limit; |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | // Everyone succeeded, return. |
| 217 | DCHECK_EQ(i, -1); |
| 218 | return true; |
| 219 | } |
| 220 | |
| 221 | /// Decreases consumption of this tracker and its ancestors by 'bytes'. |
| 222 | void Release(int64_t bytes) { |