MCPcopy Create free account
hub / github.com/apache/impala / FreeSystemMemory

Method FreeSystemMemory

be/src/runtime/bufferpool/buffer-allocator.cc:630–709  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

628}
629
630pair<int64_t, int64_t> BufferPool::FreeBufferArena::FreeSystemMemory(
631 int64_t target_bytes_to_free, int64_t target_bytes_to_claim,
632 std::unique_lock<SpinLock>* arena_lock) {
633 DCHECK_GT(target_bytes_to_free, 0);
634 DCHECK_GE(target_bytes_to_free, target_bytes_to_claim);
635 int64_t bytes_freed = 0;
636 // If the caller is acquiring the lock, just lock for the whole method.
637 // Otherwise lazily acquire the lock the first time we find some memory
638 // to free.
639 std::unique_lock<SpinLock> al(lock_, std::defer_lock_t());
640 if (arena_lock != nullptr) al.lock();
641
642 vector<BufferHandle> buffers;
643 // Search from largest to smallest to avoid freeing many small buffers unless
644 // necessary.
645 for (int i = NumBufferSizes() - 1; i >= 0; --i) {
646 PerSizeLists* lists = &buffer_sizes_[i];
647 // Check before acquiring lock to avoid expensive lock acquisition and make scanning
648 // empty lists much cheaper.
649 if (lists->num_free_buffers.Load() == 0 && lists->num_clean_pages.Load() == 0) {
650 continue;
651 }
652 if (!al.owns_lock()) al.lock();
653 FreeList* free_buffers = &lists->free_buffers;
654 InternalList<Page>* clean_pages = &lists->clean_pages;
655 DCHECK_EQ(lists->num_free_buffers.Load(), free_buffers->Size());
656 DCHECK_EQ(lists->num_clean_pages.Load(), clean_pages->size());
657
658 // Figure out how many of the buffers in the free list we should free.
659 DCHECK_GT(target_bytes_to_free, bytes_freed);
660 const int64_t buffer_len = 1L << (i + parent_->log_min_buffer_len_);
661 int64_t buffers_to_free = min(free_buffers->Size(),
662 BitUtil::Ceil(target_bytes_to_free - bytes_freed, buffer_len));
663 int64_t buffer_bytes_to_free = buffers_to_free * buffer_len;
664
665 // Evict clean pages by moving their buffers to the free page list before freeing
666 // them. This ensures that they are freed based on memory address in the expected
667 // order.
668 int num_pages_evicted = 0;
669 int64_t page_bytes_evicted = 0;
670 while (bytes_freed + buffer_bytes_to_free < target_bytes_to_free) {
671 Page* page = clean_pages->Dequeue();
672 if (page == nullptr) break;
673 BufferHandle page_buffer;
674 {
675 lock_guard<SpinLock> pl(page->buffer_lock);
676 page_buffer = move(page->buffer);
677 }
678 ++buffers_to_free;
679 buffer_bytes_to_free += page_buffer.len();
680 ++num_pages_evicted;
681 page_bytes_evicted += page_buffer.len();
682 free_buffers->AddFreeBuffer(move(page_buffer));
683 }
684 lists->num_free_buffers.Add(num_pages_evicted);
685 lists->num_clean_pages.Add(-num_pages_evicted);
686 parent_->clean_page_bytes_remaining_.Add(page_bytes_evicted);
687

Callers 2

ScavengeBuffersMethod · 0.80
ReleaseMemoryMethod · 0.80

Calls 13

minFunction · 0.85
moveFunction · 0.85
owns_lockMethod · 0.80
FreeToSystemMethod · 0.80
GetBuffersToFreeMethod · 0.80
lockMethod · 0.45
LoadMethod · 0.45
SizeMethod · 0.45
sizeMethod · 0.45
DequeueMethod · 0.45
lenMethod · 0.45
AddFreeBufferMethod · 0.45

Tested by

no test coverage detected