MCPcopy Create free account
hub / github.com/ByConity/ByConity / allocImpl

Method allocImpl

src/Common/MemoryTracker.cpp:161–284  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

159
160
161void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
162{
163 if (size < 0)
164 throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Negative size ({}) is passed to MemoryTracker. It is a bug.", size);
165
166 if (BlockerInThread::isBlocked(level))
167 {
168 /// Since the BlockerInThread should respect the level, we should go to the next parent.
169 if (auto * loaded_next = parent.load(std::memory_order_relaxed))
170 loaded_next->allocImpl(size, throw_if_memory_exceeded);
171 return;
172 }
173
174 /** Using memory_order_relaxed means that if allocations are done simultaneously,
175 * we allow exception about memory limit exceeded to be thrown only on next allocation.
176 * So, we allow over-allocations.
177 */
178 Int64 will_be = size + amount.fetch_add(size, std::memory_order_relaxed);
179
180 auto metric_loaded = metric.load(std::memory_order_relaxed);
181 if (metric_loaded != CurrentMetrics::end())
182 CurrentMetrics::add(metric_loaded, size);
183
184 Int64 current_hard_limit = hard_limit.load(std::memory_order_relaxed);
185 Int64 current_profiler_limit = profiler_limit.load(std::memory_order_relaxed);
186
187 /// Cap the limit to the total_memory_tracker, since it may include some drift
188 /// for user-level memory tracker.
189 ///
190 /// And since total_memory_tracker is reset to the process resident
191 /// memory peridically (in AsynchronousMetrics::update()), any limit can be
192 /// capped to it, to avoid possible drift.
193 if (unlikely(current_hard_limit
194 && will_be > current_hard_limit
195 && level == VariableContext::User))
196 {
197 Int64 total_amount = total_memory_tracker.get();
198 if (amount > total_amount)
199 {
200 set(total_amount);
201 will_be = size + total_amount;
202 }
203 }
204
205#ifdef MEMORY_TRACKER_DEBUG_CHECKS
206 if (unlikely(memory_tracker_always_throw_logical_error_on_allocation))
207 {
208 memory_tracker_always_throw_logical_error_on_allocation = false;
209 throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Memory tracker: allocations not allowed.");
210 }
211#endif
212
213 std::bernoulli_distribution fault(fault_probability);
214 if (unlikely(fault_probability && fault(thread_local_rng)) && throw_if_memory_exceeded && memoryTrackerCanThrow(level, true))
215 {
216 ProfileEvents::increment(ProfileEvents::QueryMemoryLimitExceeded);
217 amount.fetch_sub(size, std::memory_order_relaxed);
218

Callers 2

allocImplFunction · 0.80
checkFunction · 0.80

Calls 11

addFunction · 0.85
memoryTrackerCanThrowFunction · 0.85
collectFunction · 0.85
ExceptionClass · 0.70
endFunction · 0.70
setFunction · 0.70
incrementFunction · 0.70
StackTraceClass · 0.70
loadMethod · 0.45
getMethod · 0.45

Tested by

no test coverage detected