YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/memory/arena.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2010 Google Inc.  All Rights Reserved
2
//
3
// Licensed to the Apache Software Foundation (ASF) under one
4
// or more contributor license agreements.  See the NOTICE file
5
// distributed with this work for additional information
6
// regarding copyright ownership.  The ASF licenses this file
7
// to you under the Apache License, Version 2.0 (the
8
// "License"); you may not use this file except in compliance
9
// with the License.  You may obtain a copy of the License at
10
//
11
//   http://www.apache.org/licenses/LICENSE-2.0
12
//
13
// Unless required by applicable law or agreed to in writing,
14
// software distributed under the License is distributed on an
15
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
// KIND, either express or implied.  See the License for the
17
// specific language governing permissions and limitations
18
// under the License.
19
//
20
// The following only applies to changes made to this file as part of YugaByte development.
21
//
22
// Portions Copyright (c) YugaByte, Inc.
23
//
24
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
25
// in compliance with the License.  You may obtain a copy of the License at
26
//
27
// http://www.apache.org/licenses/LICENSE-2.0
28
//
29
// Unless required by applicable law or agreed to in writing, software distributed under the License
30
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
31
// or implied.  See the License for the specific language governing permissions and limitations
32
// under the License.
33
//
34
35
#include "yb/util/memory/arena.h"
36
37
#include <algorithm>
38
#include <mutex>
39
40
#include "yb/util/alignment.h"
41
#include "yb/util/debug-util.h"
42
#include "yb/util/flag_tags.h"
43
44
using std::copy;
45
using std::max;
46
using std::min;
47
using std::reverse;
48
using std::shared_ptr;
49
using std::sort;
50
using std::swap;
51
52
DEFINE_uint64(arena_warn_threshold_bytes, 256*1024*1024,
53
             "Number of bytes beyond which to emit a warning for a large arena");
54
TAG_FLAG(arena_warn_threshold_bytes, hidden);
55
56
namespace yb {
57
namespace internal {
58
59
template <class Traits>
60
576M
uint8_t* ArenaComponent<Traits>::AllocateBytesAligned(const size_t size, const size_t alignment) {
61
  // Special case check the allowed alignments. Currently, we only ensure
62
  // the allocated buffer components are 16-byte aligned, and the code path
63
  // doesn't support larger alignment.
64
576M
  DCHECK(alignment == 1 || alignment == 2 || alignment == 4 ||
65
485k
         alignment == 8 || alignment == 16)
66
485k
    << "bad alignment: " << alignment;
67
68
576M
  for (;;) {
69
575M
    uint8_t* position = position_;
70
71
575M
    const auto aligned = align_up(position, alignment);
72
575M
    const auto new_position = aligned + size;
73
74
575M
    if (PREDICT_TRUE(new_position <= end_)) {
75
574M
      bool success = Traits::CompareExchange(new_position, &position_, &position);
76
575M
      if (
PREDICT_TRUE574M
(success)) {
77
575M
        AsanUnpoison(aligned, size);
78
575M
        return aligned;
79
575M
      }
80
574M
    } else {
81
1.02M
      return nullptr;
82
1.02M
    }
83
575M
  }
84
576M
}
yb::internal::ArenaComponent<yb::internal::ThreadSafeArenaTraits>::AllocateBytesAligned(unsigned long, unsigned long)
Line
Count
Source
60
544M
uint8_t* ArenaComponent<Traits>::AllocateBytesAligned(const size_t size, const size_t alignment) {
61
  // Special case check the allowed alignments. Currently, we only ensure
62
  // the allocated buffer components are 16-byte aligned, and the code path
63
  // doesn't support larger alignment.
64
544M
  DCHECK(alignment == 1 || alignment == 2 || alignment == 4 ||
65
472k
         alignment == 8 || alignment == 16)
66
472k
    << "bad alignment: " << alignment;
67
68
544M
  for (;;) {
69
544M
    uint8_t* position = position_;
70
71
544M
    const auto aligned = align_up(position, alignment);
72
544M
    const auto new_position = aligned + size;
73
74
544M
    if (
PREDICT_TRUE544M
(new_position <= end_)) {
75
544M
      bool success = Traits::CompareExchange(new_position, &position_, &position);
76
545M
      if (
PREDICT_TRUE544M
(success)) {
77
545M
        AsanUnpoison(aligned, size);
78
545M
        return aligned;
79
545M
      }
80
18.4E
    } else {
81
18.4E
      return nullptr;
82
18.4E
    }
83
544M
  }
84
544M
}
yb::internal::ArenaComponent<yb::internal::ArenaTraits>::AllocateBytesAligned(unsigned long, unsigned long)
Line
Count
Source
60
31.1M
uint8_t* ArenaComponent<Traits>::AllocateBytesAligned(const size_t size, const size_t alignment) {
61
  // Special case check the allowed alignments. Currently, we only ensure
62
  // the allocated buffer components are 16-byte aligned, and the code path
63
  // doesn't support larger alignment.
64
31.1M
  DCHECK(alignment == 1 || alignment == 2 || alignment == 4 ||
65
13.1k
         alignment == 8 || alignment == 16)
66
13.1k
    << "bad alignment: " << alignment;
67
68
31.1M
  for (;;) {
69
31.1M
    uint8_t* position = position_;
70
71
31.1M
    const auto aligned = align_up(position, alignment);
72
31.1M
    const auto new_position = aligned + size;
73
74
31.1M
    if (PREDICT_TRUE(new_position <= end_)) {
75
30.1M
      bool success = Traits::CompareExchange(new_position, &position_, &position);
76
30.1M
      if (PREDICT_TRUE(success)) {
77
30.0M
        AsanUnpoison(aligned, size);
78
30.0M
        return aligned;
79
30.0M
      }
80
30.1M
    } else {
81
1.04M
      return nullptr;
82
1.04M
    }
83
31.1M
  }
84
31.1M
}
85
86
template <class Traits>
87
692M
inline void ArenaComponent<Traits>::AsanUnpoison(const void* addr, size_t size) {
88
#ifdef ADDRESS_SANITIZER
89
  std::lock_guard<mutex_type> l(asan_lock_);
90
  ASAN_UNPOISON_MEMORY_REGION(addr, size);
91
#endif
92
692M
}
yb::internal::ArenaComponent<yb::internal::ThreadSafeArenaTraits>::AsanUnpoison(void const*, unsigned long)
Line
Count
Source
87
660M
inline void ArenaComponent<Traits>::AsanUnpoison(const void* addr, size_t size) {
88
#ifdef ADDRESS_SANITIZER
89
  std::lock_guard<mutex_type> l(asan_lock_);
90
  ASAN_UNPOISON_MEMORY_REGION(addr, size);
91
#endif
92
660M
}
yb::internal::ArenaComponent<yb::internal::ArenaTraits>::AsanUnpoison(void const*, unsigned long)
Line
Count
Source
87
31.8M
inline void ArenaComponent<Traits>::AsanUnpoison(const void* addr, size_t size) {
88
#ifdef ADDRESS_SANITIZER
89
  std::lock_guard<mutex_type> l(asan_lock_);
90
  ASAN_UNPOISON_MEMORY_REGION(addr, size);
91
#endif
92
31.8M
}
93
94
// Fast-path allocation should get inlined, and fall-back
95
// to non-inline function call for allocation failure
96
template <class Traits>
97
574M
inline void *ArenaBase<Traits>::AllocateBytesAligned(const size_t size, const size_t align) {
98
574M
  void* result = AcquireLoadCurrent()->AllocateBytesAligned(size, align);
99
574M
  if (
PREDICT_TRUE574M
(result != nullptr)) return result;
100
18.4E
  return AllocateBytesFallback(size, align);
101
574M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::AllocateBytesAligned(unsigned long, unsigned long)
Line
Count
Source
97
544M
inline void *ArenaBase<Traits>::AllocateBytesAligned(const size_t size, const size_t align) {
98
544M
  void* result = AcquireLoadCurrent()->AllocateBytesAligned(size, align);
99
545M
  if (
PREDICT_TRUE544M
(result != nullptr)) return result;
100
18.4E
  return AllocateBytesFallback(size, align);
101
544M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::AllocateBytesAligned(unsigned long, unsigned long)
Line
Count
Source
97
30.1M
inline void *ArenaBase<Traits>::AllocateBytesAligned(const size_t size, const size_t align) {
98
30.1M
  void* result = AcquireLoadCurrent()->AllocateBytesAligned(size, align);
99
30.1M
  if (PREDICT_TRUE(result != nullptr)) 
return result29.6M
;
100
556k
  return AllocateBytesFallback(size, align);
101
30.1M
}
102
103
template <class Traits>
104
337
inline uint8_t* ArenaBase<Traits>::AddSlice(const Slice& value) {
105
337
  return reinterpret_cast<uint8_t *>(AddBytes(value.data(), value.size()));
106
337
}
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::AddSlice(yb::Slice const&)
yb::internal::ArenaBase<yb::internal::ArenaTraits>::AddSlice(yb::Slice const&)
Line
Count
Source
104
337
inline uint8_t* ArenaBase<Traits>::AddSlice(const Slice& value) {
105
337
  return reinterpret_cast<uint8_t *>(AddBytes(value.data(), value.size()));
106
337
}
107
108
template <class Traits>
109
337
inline void *ArenaBase<Traits>::AddBytes(const void *data, size_t len) {
110
337
  void* destination = AllocateBytes(len);
111
337
  if (destination == nullptr) 
return nullptr0
;
112
337
  memcpy(destination, data, len);
113
337
  return destination;
114
337
}
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::AddBytes(void const*, unsigned long)
yb::internal::ArenaBase<yb::internal::ArenaTraits>::AddBytes(void const*, unsigned long)
Line
Count
Source
109
337
inline void *ArenaBase<Traits>::AddBytes(const void *data, size_t len) {
110
337
  void* destination = AllocateBytes(len);
111
337
  if (destination == nullptr) 
return nullptr0
;
112
337
  memcpy(destination, data, len);
113
337
  return destination;
114
337
}
115
116
template <class Traits>
117
0
inline bool ArenaBase<Traits>::RelocateSlice(const Slice &src, Slice *dst) {
118
0
  void* destination = AllocateBytes(src.size());
119
0
  if (destination == nullptr) return false;
120
0
  memcpy(destination, src.data(), src.size());
121
0
  *dst = Slice(reinterpret_cast<uint8_t *>(destination), src.size());
122
0
  return true;
123
0
}
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::RelocateSlice(yb::Slice const&, yb::Slice*)
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ArenaTraits>::RelocateSlice(yb::Slice const&, yb::Slice*)
124
125
template <class Traits>
126
ArenaBase<Traits>::ArenaBase(
127
  BufferAllocator* const buffer_allocator,
128
  size_t initial_buffer_size,
129
  size_t max_buffer_size)
130
    : buffer_allocator_(buffer_allocator),
131
683k
      max_buffer_size_(max_buffer_size) {
132
683k
  AddComponentUnlocked(NewBuffer(initial_buffer_size, 0));
133
683k
}
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::ArenaBase(yb::BufferAllocator*, unsigned long, unsigned long)
yb::internal::ArenaBase<yb::internal::ArenaTraits>::ArenaBase(yb::BufferAllocator*, unsigned long, unsigned long)
Line
Count
Source
131
683k
      max_buffer_size_(max_buffer_size) {
132
683k
  AddComponentUnlocked(NewBuffer(initial_buffer_size, 0));
133
683k
}
134
135
template <class Traits>
136
ArenaBase<Traits>::ArenaBase(size_t initial_buffer_size, size_t max_buffer_size)
137
    : buffer_allocator_(HeapBufferAllocator::Get()),
138
27.2M
      max_buffer_size_(max_buffer_size) {
139
27.2M
  AddComponentUnlocked(NewBuffer(initial_buffer_size, 0));
140
27.2M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::ArenaBase(unsigned long, unsigned long)
Line
Count
Source
138
26.7M
      max_buffer_size_(max_buffer_size) {
139
26.7M
  AddComponentUnlocked(NewBuffer(initial_buffer_size, 0));
140
26.7M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::ArenaBase(unsigned long, unsigned long)
Line
Count
Source
138
550k
      max_buffer_size_(max_buffer_size) {
139
550k
  AddComponentUnlocked(NewBuffer(initial_buffer_size, 0));
140
550k
}
141
142
template <class Traits>
143
27.5M
ArenaBase<Traits>::~ArenaBase() {
144
27.5M
  AcquireLoadCurrent()->Destroy(buffer_allocator_);
145
27.5M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::~ArenaBase()
Line
Count
Source
143
26.2M
ArenaBase<Traits>::~ArenaBase() {
144
26.2M
  AcquireLoadCurrent()->Destroy(buffer_allocator_);
145
26.2M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::~ArenaBase()
Line
Count
Source
143
1.23M
ArenaBase<Traits>::~ArenaBase() {
144
1.23M
  AcquireLoadCurrent()->Destroy(buffer_allocator_);
145
1.23M
}
146
147
template <class Traits>
148
503k
void *ArenaBase<Traits>::AllocateBytesFallback(const size_t size, const size_t align) {
149
503k
  std::lock_guard<mutex_type> lock(component_lock_);
150
151
  // It's possible another thread raced with us and already allocated
152
  // a new component, in which case we should try the "fast path" again
153
503k
  Component* cur = CHECK_NOTNULL(AcquireLoadCurrent());
154
503k
  void * result = cur->AllocateBytesAligned(size, align);
155
503k
  if (PREDICT_FALSE(result != nullptr)) 
return result2.31k
;
156
157
  // Really need to allocate more space.
158
501k
  const size_t buffer_size = size + sizeof(Component);
159
  // But, allocate enough, even if the request is large. In this case,
160
  // might violate the max_element_size bound.
161
501k
  size_t next_component_size = std::max(std::min(2 * cur->full_size(), max_buffer_size_),
162
501k
                                        buffer_size);
163
164
  // If soft quota is exhausted we will only get the "minimal" amount of memory
165
  // we ask for. In this case if we always use "size" as minimal, we may degrade
166
  // to allocating a lot of tiny components, one for each string added to the
167
  // arena. This would be very inefficient, so let's first try something between
168
  // "size" and "next_component_size". If it fails due to hard quota being
169
  // exhausted, we'll fall back to using "size" as minimal.
170
501k
  size_t minimal = (buffer_size + next_component_size) / 2;
171
501k
  CHECK_LE(buffer_size, minimal);
172
501k
  CHECK_LE(minimal, next_component_size);
173
  // Now, just make sure we can actually get the memory.
174
501k
  Buffer buffer = NewBufferInTwoAttempts(next_component_size, minimal, buffer_size);
175
501k
  if (!buffer) 
return nullptr1
;
176
177
  // Now, must succeed. The component has at least 'size' bytes.
178
501k
  ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
179
501k
  auto component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
180
501k
  result = component->AllocateBytesAligned(size, align);
181
501k
  CHECK(result != nullptr);
182
183
  // Now add it to the arena.
184
501k
  AddComponentUnlocked(std::move(buffer), component);
185
186
501k
  return result;
187
501k
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::AllocateBytesFallback(unsigned long, unsigned long)
Line
Count
Source
148
3.23k
void *ArenaBase<Traits>::AllocateBytesFallback(const size_t size, const size_t align) {
149
3.23k
  std::lock_guard<mutex_type> lock(component_lock_);
150
151
  // It's possible another thread raced with us and already allocated
152
  // a new component, in which case we should try the "fast path" again
153
3.23k
  Component* cur = CHECK_NOTNULL(AcquireLoadCurrent());
154
3.23k
  void * result = cur->AllocateBytesAligned(size, align);
155
3.23k
  if (PREDICT_FALSE(result != nullptr)) 
return result2.31k
;
156
157
  // Really need to allocate more space.
158
922
  const size_t buffer_size = size + sizeof(Component);
159
  // But, allocate enough, even if the request is large. In this case,
160
  // might violate the max_element_size bound.
161
922
  size_t next_component_size = std::max(std::min(2 * cur->full_size(), max_buffer_size_),
162
922
                                        buffer_size);
163
164
  // If soft quota is exhausted we will only get the "minimal" amount of memory
165
  // we ask for. In this case if we always use "size" as minimal, we may degrade
166
  // to allocating a lot of tiny components, one for each string added to the
167
  // arena. This would be very inefficient, so let's first try something between
168
  // "size" and "next_component_size". If it fails due to hard quota being
169
  // exhausted, we'll fall back to using "size" as minimal.
170
922
  size_t minimal = (buffer_size + next_component_size) / 2;
171
922
  CHECK_LE(buffer_size, minimal);
172
922
  CHECK_LE(minimal, next_component_size);
173
  // Now, just make sure we can actually get the memory.
174
922
  Buffer buffer = NewBufferInTwoAttempts(next_component_size, minimal, buffer_size);
175
922
  if (!buffer) 
return nullptr0
;
176
177
  // Now, must succeed. The component has at least 'size' bytes.
178
922
  ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
179
922
  auto component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
180
922
  result = component->AllocateBytesAligned(size, align);
181
922
  CHECK(result != nullptr);
182
183
  // Now add it to the arena.
184
922
  AddComponentUnlocked(std::move(buffer), component);
185
186
922
  return result;
187
922
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::AllocateBytesFallback(unsigned long, unsigned long)
Line
Count
Source
148
500k
void *ArenaBase<Traits>::AllocateBytesFallback(const size_t size, const size_t align) {
149
500k
  std::lock_guard<mutex_type> lock(component_lock_);
150
151
  // It's possible another thread raced with us and already allocated
152
  // a new component, in which case we should try the "fast path" again
153
500k
  Component* cur = CHECK_NOTNULL(AcquireLoadCurrent());
154
500k
  void * result = cur->AllocateBytesAligned(size, align);
155
500k
  if (PREDICT_FALSE(result != nullptr)) 
return result0
;
156
157
  // Really need to allocate more space.
158
500k
  const size_t buffer_size = size + sizeof(Component);
159
  // But, allocate enough, even if the request is large. In this case,
160
  // might violate the max_element_size bound.
161
500k
  size_t next_component_size = std::max(std::min(2 * cur->full_size(), max_buffer_size_),
162
500k
                                        buffer_size);
163
164
  // If soft quota is exhausted we will only get the "minimal" amount of memory
165
  // we ask for. In this case if we always use "size" as minimal, we may degrade
166
  // to allocating a lot of tiny components, one for each string added to the
167
  // arena. This would be very inefficient, so let's first try something between
168
  // "size" and "next_component_size". If it fails due to hard quota being
169
  // exhausted, we'll fall back to using "size" as minimal.
170
500k
  size_t minimal = (buffer_size + next_component_size) / 2;
171
500k
  CHECK_LE(buffer_size, minimal);
172
500k
  CHECK_LE(minimal, next_component_size);
173
  // Now, just make sure we can actually get the memory.
174
500k
  Buffer buffer = NewBufferInTwoAttempts(next_component_size, minimal, buffer_size);
175
500k
  if (!buffer) 
return nullptr1
;
176
177
  // Now, must succeed. The component has at least 'size' bytes.
178
500k
  ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
179
500k
  auto component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
180
500k
  result = component->AllocateBytesAligned(size, align);
181
500k
  CHECK(result != nullptr);
182
183
  // Now add it to the arena.
184
500k
  AddComponentUnlocked(std::move(buffer), component);
185
186
500k
  return result;
187
500k
}
188
189
template <class Traits>
190
Buffer ArenaBase<Traits>::NewBufferInTwoAttempts(size_t requested_size,
191
                                                     size_t mid_size,
192
501k
                                                     size_t min_size) {
193
501k
  Buffer buffer = NewBuffer(requested_size, mid_size);
194
501k
  if (!buffer) {
195
1
    return NewBuffer(requested_size, min_size);
196
1
  }
197
501k
  return buffer;
198
501k
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::NewBufferInTwoAttempts(unsigned long, unsigned long, unsigned long)
Line
Count
Source
192
2.50k
                                                     size_t min_size) {
193
2.50k
  Buffer buffer = NewBuffer(requested_size, mid_size);
194
2.50k
  if (!buffer) {
195
0
    return NewBuffer(requested_size, min_size);
196
0
  }
197
2.50k
  return buffer;
198
2.50k
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::NewBufferInTwoAttempts(unsigned long, unsigned long, unsigned long)
Line
Count
Source
192
499k
                                                     size_t min_size) {
193
499k
  Buffer buffer = NewBuffer(requested_size, mid_size);
194
499k
  if (!buffer) {
195
1
    return NewBuffer(requested_size, min_size);
196
1
  }
197
499k
  return buffer;
198
499k
}
199
200
template <class Traits>
201
118M
Buffer ArenaBase<Traits>::NewBuffer(size_t requested_size, size_t minimum_size) {
202
118M
  const size_t min_possible = sizeof(Component) * 2;
203
118M
  requested_size = std::max(requested_size, min_possible);
204
118M
  minimum_size = std::max(minimum_size, min_possible);
205
118M
  Buffer buffer = buffer_allocator_->BestEffortAllocate(requested_size, minimum_size);
206
118M
  if (!buffer)
207
2
    return buffer;
208
209
118M
  CHECK_EQ(reinterpret_cast<uintptr_t>(buffer.data()) & (16 - 1), 0)
210
0
      << "Components should be 16-byte aligned: " << buffer.data();
211
212
118M
  ASAN_POISON_MEMORY_REGION(buffer.data(), buffer.size());
213
214
118M
  return buffer;
215
118M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::NewBuffer(unsigned long, unsigned long)
Line
Count
Source
201
116M
Buffer ArenaBase<Traits>::NewBuffer(size_t requested_size, size_t minimum_size) {
202
116M
  const size_t min_possible = sizeof(Component) * 2;
203
116M
  requested_size = std::max(requested_size, min_possible);
204
116M
  minimum_size = std::max(minimum_size, min_possible);
205
116M
  Buffer buffer = buffer_allocator_->BestEffortAllocate(requested_size, minimum_size);
206
116M
  if (!buffer)
207
0
    return buffer;
208
209
116M
  CHECK_EQ(reinterpret_cast<uintptr_t>(buffer.data()) & (16 - 1), 0)
210
0
      << "Components should be 16-byte aligned: " << buffer.data();
211
212
116M
  ASAN_POISON_MEMORY_REGION(buffer.data(), buffer.size());
213
214
116M
  return buffer;
215
116M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::NewBuffer(unsigned long, unsigned long)
Line
Count
Source
201
1.73M
Buffer ArenaBase<Traits>::NewBuffer(size_t requested_size, size_t minimum_size) {
202
1.73M
  const size_t min_possible = sizeof(Component) * 2;
203
1.73M
  requested_size = std::max(requested_size, min_possible);
204
1.73M
  minimum_size = std::max(minimum_size, min_possible);
205
1.73M
  Buffer buffer = buffer_allocator_->BestEffortAllocate(requested_size, minimum_size);
206
1.73M
  if (!buffer)
207
2
    return buffer;
208
209
1.73M
  CHECK_EQ(reinterpret_cast<uintptr_t>(buffer.data()) & (16 - 1), 0)
210
0
      << "Components should be 16-byte aligned: " << buffer.data();
211
212
1.73M
  ASAN_POISON_MEMORY_REGION(buffer.data(), buffer.size());
213
214
1.73M
  return buffer;
215
1.73M
}
216
217
// LOCKING: component_lock_ must be held by the current thread.
218
template <class Traits>
219
118M
void ArenaBase<Traits>::AddComponentUnlocked(Buffer buffer, Component* component) {
220
118M
  if (!component) {
221
117M
    ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
222
117M
    component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
223
117M
  }
224
225
118M
  buffer.Release();
226
118M
  ReleaseStoreCurrent(component);
227
118M
  arena_footprint_ += component->full_size();
228
118M
  if (PREDICT_FALSE(arena_footprint_ > FLAGS_arena_warn_threshold_bytes) && 
!warned_0
) {
229
0
    LOG(WARNING) << "Arena " << reinterpret_cast<const void *>(this)
230
0
                 << " footprint (" << arena_footprint_ << " bytes) exceeded warning threshold ("
231
0
                 << FLAGS_arena_warn_threshold_bytes << " bytes)\n"
232
0
                 << GetStackTrace();
233
0
    warned_ = true;
234
0
  }
235
118M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::AddComponentUnlocked(yb::Buffer, yb::internal::ArenaComponent<yb::internal::ThreadSafeArenaTraits>*)
Line
Count
Source
219
116M
void ArenaBase<Traits>::AddComponentUnlocked(Buffer buffer, Component* component) {
220
116M
  if (!component) {
221
116M
    ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
222
116M
    component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
223
116M
  }
224
225
116M
  buffer.Release();
226
116M
  ReleaseStoreCurrent(component);
227
116M
  arena_footprint_ += component->full_size();
228
116M
  if (PREDICT_FALSE(arena_footprint_ > FLAGS_arena_warn_threshold_bytes) && 
!warned_0
) {
229
0
    LOG(WARNING) << "Arena " << reinterpret_cast<const void *>(this)
230
0
                 << " footprint (" << arena_footprint_ << " bytes) exceeded warning threshold ("
231
0
                 << FLAGS_arena_warn_threshold_bytes << " bytes)\n"
232
0
                 << GetStackTrace();
233
0
    warned_ = true;
234
0
  }
235
116M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::AddComponentUnlocked(yb::Buffer, yb::internal::ArenaComponent<yb::internal::ArenaTraits>*)
Line
Count
Source
219
1.73M
void ArenaBase<Traits>::AddComponentUnlocked(Buffer buffer, Component* component) {
220
1.73M
  if (!component) {
221
1.23M
    ASAN_UNPOISON_MEMORY_REGION(buffer.data(), sizeof(Component));
222
1.23M
    component = new (buffer.data()) Component(buffer.size(), AcquireLoadCurrent());
223
1.23M
  }
224
225
1.73M
  buffer.Release();
226
1.73M
  ReleaseStoreCurrent(component);
227
1.73M
  arena_footprint_ += component->full_size();
228
1.73M
  if (PREDICT_FALSE(arena_footprint_ > FLAGS_arena_warn_threshold_bytes) && 
!warned_0
) {
229
0
    LOG(WARNING) << "Arena " << reinterpret_cast<const void *>(this)
230
0
                 << " footprint (" << arena_footprint_ << " bytes) exceeded warning threshold ("
231
0
                 << FLAGS_arena_warn_threshold_bytes << " bytes)\n"
232
0
                 << GetStackTrace();
233
0
    warned_ = true;
234
0
  }
235
1.73M
}
236
237
template <class Traits>
238
89.7M
void ArenaBase<Traits>::Reset() {
239
89.7M
  std::lock_guard<mutex_type> lock(component_lock_);
240
241
89.7M
  auto* current = CHECK_NOTNULL(AcquireLoadCurrent());
242
89.7M
  current->Reset(buffer_allocator_);
243
89.7M
  arena_footprint_ = current->full_size();
244
89.7M
  warned_ = false;
245
246
89.7M
#ifndef NDEBUG
247
  // In debug mode release the last component too for (hopefully) better
248
  // detection of memory-related bugs (invalid shallow copies, etc.).
249
89.7M
  size_t last_size = current->full_size();
250
89.7M
  current->Destroy(buffer_allocator_);
251
89.7M
  arena_footprint_ = 0;
252
89.7M
  ReleaseStoreCurrent(nullptr);
253
89.7M
  AddComponentUnlocked(NewBuffer(last_size, 0));
254
89.7M
#endif
255
89.7M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::Reset()
Line
Count
Source
238
89.7M
void ArenaBase<Traits>::Reset() {
239
89.7M
  std::lock_guard<mutex_type> lock(component_lock_);
240
241
89.7M
  auto* current = CHECK_NOTNULL(AcquireLoadCurrent());
242
89.7M
  current->Reset(buffer_allocator_);
243
89.7M
  arena_footprint_ = current->full_size();
244
89.7M
  warned_ = false;
245
246
89.7M
#ifndef NDEBUG
247
  // In debug mode release the last component too for (hopefully) better
248
  // detection of memory-related bugs (invalid shallow copies, etc.).
249
89.7M
  size_t last_size = current->full_size();
250
89.7M
  current->Destroy(buffer_allocator_);
251
89.7M
  arena_footprint_ = 0;
252
89.7M
  ReleaseStoreCurrent(nullptr);
253
89.7M
  AddComponentUnlocked(NewBuffer(last_size, 0));
254
89.7M
#endif
255
89.7M
}
yb::internal::ArenaBase<yb::internal::ArenaTraits>::Reset()
Line
Count
Source
238
1
void ArenaBase<Traits>::Reset() {
239
1
  std::lock_guard<mutex_type> lock(component_lock_);
240
241
1
  auto* current = CHECK_NOTNULL(AcquireLoadCurrent());
242
1
  current->Reset(buffer_allocator_);
243
1
  arena_footprint_ = current->full_size();
244
1
  warned_ = false;
245
246
1
#ifndef NDEBUG
247
  // In debug mode release the last component too for (hopefully) better
248
  // detection of memory-related bugs (invalid shallow copies, etc.).
249
1
  size_t last_size = current->full_size();
250
1
  current->Destroy(buffer_allocator_);
251
1
  arena_footprint_ = 0;
252
1
  ReleaseStoreCurrent(nullptr);
253
1
  AddComponentUnlocked(NewBuffer(last_size, 0));
254
1
#endif
255
1
}
256
257
template <class Traits>
258
79.3M
size_t ArenaBase<Traits>::memory_footprint() const {
259
79.3M
  std::lock_guard<mutex_type> lock(component_lock_);
260
79.3M
  return arena_footprint_;
261
79.3M
}
yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>::memory_footprint() const
Line
Count
Source
258
79.3M
size_t ArenaBase<Traits>::memory_footprint() const {
259
79.3M
  std::lock_guard<mutex_type> lock(component_lock_);
260
79.3M
  return arena_footprint_;
261
79.3M
}
Unexecuted instantiation: yb::internal::ArenaBase<yb::internal::ArenaTraits>::memory_footprint() const
262
263
// Explicit instantiation.
264
template class ArenaBase<ThreadSafeArenaTraits>;
265
template class ArenaBase<ArenaTraits>;
266
267
}  // namespace internal
268
}  // namespace yb