Skip to content

Commit 95b7de3

Browse files
authored
bugfix: runtime extend block pool (#2965)
1 parent 257134d commit 95b7de3

4 files changed

Lines changed: 111 additions & 44 deletions

File tree

src/brpc/rdma/block_pool.cpp

Lines changed: 91 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ DEFINE_int32(rdma_memory_pool_initial_size_mb, 1024,
3636
"Initial size of memory pool for RDMA (MB)");
3737
DEFINE_int32(rdma_memory_pool_increase_size_mb, 1024,
3838
"Increased size of memory pool for RDMA (MB)");
39-
DEFINE_int32(rdma_memory_pool_max_regions, 4, "Max number of regions");
39+
DEFINE_int32(rdma_memory_pool_max_regions, 1, "Max number of regions");
4040
DEFINE_int32(rdma_memory_pool_buckets, 4, "Number of buckets to reduce race");
4141
DEFINE_int32(rdma_memory_pool_tls_cache_num, 128, "Number of cached block in tls");
42+
DEFINE_bool(rdma_memory_pool_user_specified_memory, false,
43+
"If true, the user must call UserExtendBlockPool() to extend "
44+
"memory. bRPC will not handle memory extension.");
4245

4346
static RegisterCallback g_cb = NULL;
4447

@@ -125,31 +128,13 @@ uint32_t GetRegionId(const void* buf) {
125128
return r->id;
126129
}
127130

128-
// Extend the block pool with a new region (with different region ID)
129-
static void* ExtendBlockPool(size_t region_size, int block_type) {
130-
if (region_size < 1) {
131-
errno = EINVAL;
132-
return NULL;
133-
}
134-
131+
static void* ExtendBlockPoolImpl(void* region_base, size_t region_size,
132+
int block_type) {
135133
if (g_region_num == FLAGS_rdma_memory_pool_max_regions) {
136134
LOG(INFO) << "Memory pool reaches max regions";
137135
errno = ENOMEM;
138136
return NULL;
139137
}
140-
141-
// Regularize region size
142-
region_size = region_size * BYTES_IN_MB / g_block_size[block_type] / g_buckets;
143-
region_size *= g_block_size[block_type] * g_buckets;
144-
145-
LOG(INFO) << "Start extend rdma memory " << region_size / BYTES_IN_MB << "MB";
146-
147-
void* region_base = NULL;
148-
if (posix_memalign(&region_base, 4096, region_size) != 0) {
149-
PLOG_EVERY_SECOND(ERROR) << "Memory not enough";
150-
return NULL;
151-
}
152-
153138
uint32_t id = g_cb(region_base, region_size);
154139
if (id == 0) {
155140
free(region_base);
@@ -168,7 +153,7 @@ static void* ExtendBlockPool(size_t region_size, int block_type) {
168153
return NULL;
169154
}
170155
}
171-
156+
172157
Region* region = &g_regions[g_region_num++];
173158
region->start = (uintptr_t)region_base;
174159
region->size = region_size;
@@ -178,23 +163,79 @@ static void* ExtendBlockPool(size_t region_size, int block_type) {
178163
for (size_t i = 0; i < g_buckets; ++i) {
179164
node[i]->start = (void*)(region->start + i * (region_size / g_buckets));
180165
node[i]->len = region_size / g_buckets;
181-
node[i]->next = NULL;
166+
node[i]->next = g_info->idle_list[block_type][i];
182167
g_info->idle_list[block_type][i] = node[i];
183168
g_info->idle_size[block_type][i] += node[i]->len;
184169
}
185170

186171
return region_base;
187172
}
188173

189-
void* InitBlockPool(RegisterCallback cb) {
190-
if (!cb) {
174+
// Extend the block pool with a new region (with different region ID)
175+
static void* ExtendBlockPool(size_t region_size, int block_type) {
176+
if (region_size < 1) {
191177
errno = EINVAL;
192178
return NULL;
193179
}
180+
181+
if (FLAGS_rdma_memory_pool_user_specified_memory) {
182+
LOG_EVERY_SECOND(ERROR) << "Fail to extend new region, "
183+
"rdma_memory_pool_user_specified_memory is "
184+
"true, ExtendBlockPool is disabled";
185+
return NULL;
186+
}
187+
188+
// Regularize region size
189+
region_size = region_size * BYTES_IN_MB / g_block_size[block_type] / g_buckets;
190+
region_size *= g_block_size[block_type] * g_buckets;
191+
192+
LOG(INFO) << "Start extend rdma memory " << region_size / BYTES_IN_MB << "MB";
193+
194+
void* region_base = NULL;
195+
if (posix_memalign(&region_base, 4096, region_size) != 0) {
196+
PLOG_EVERY_SECOND(ERROR) << "Memory not enough";
197+
return NULL;
198+
}
199+
200+
return ExtendBlockPoolImpl(region_base, region_size, block_type);
201+
}
202+
203+
void* ExtendBlockPoolByUser(void* region_base, size_t region_size,
204+
int block_type) {
205+
if (FLAGS_rdma_memory_pool_user_specified_memory == false) {
206+
LOG_EVERY_SECOND(ERROR) << "User extend memory is disabled";
207+
return NULL;
208+
}
209+
if (reinterpret_cast<uintptr_t>(region_base) % 4096 != 0) {
210+
LOG_EVERY_SECOND(ERROR) << "region_base must be 4096 aligned";
211+
return NULL;
212+
}
213+
214+
uint64_t index = butil::fast_rand() % g_buckets;
215+
BAIDU_SCOPED_LOCK(*g_info->lock[block_type][index]);
216+
BAIDU_SCOPED_LOCK(g_info->extend_lock);
217+
218+
if (g_region_num > 1 && FLAGS_rdma_memory_pool_buckets > 1) {
219+
LOG_EVERY_SECOND(ERROR)
220+
<< "Runtime extend memory only support single bucket";
221+
return NULL;
222+
}
223+
region_size =
224+
region_size * BYTES_IN_MB / g_block_size[block_type] / g_buckets;
225+
region_size *= g_block_size[block_type] * g_buckets;
226+
227+
return ExtendBlockPoolImpl(region_base, region_size, block_type);
228+
}
229+
230+
bool InitBlockPool(RegisterCallback cb) {
231+
if (!cb) {
232+
errno = EINVAL;
233+
return false;
234+
}
194235
if (g_cb) {
195236
LOG(WARNING) << "Do not initialize block pool repeatedly";
196237
errno = EINVAL;
197-
return NULL;
238+
return false;
198239
}
199240
g_cb = cb;
200241
if (FLAGS_rdma_memory_pool_max_regions < RDMA_MEMORY_POOL_MIN_REGIONS ||
@@ -204,7 +245,7 @@ void* InitBlockPool(RegisterCallback cb) {
204245
<< RDMA_MEMORY_POOL_MIN_REGIONS << ","
205246
<< RDMA_MEMORY_POOL_MAX_REGIONS << "]!";
206247
errno = EINVAL;
207-
return NULL;
248+
return false;
208249
}
209250
if (FLAGS_rdma_memory_pool_initial_size_mb < RDMA_MEMORY_POOL_MIN_SIZE ||
210251
FLAGS_rdma_memory_pool_initial_size_mb > RDMA_MEMORY_POOL_MAX_SIZE) {
@@ -213,7 +254,7 @@ void* InitBlockPool(RegisterCallback cb) {
213254
<< RDMA_MEMORY_POOL_MIN_SIZE << ","
214255
<< RDMA_MEMORY_POOL_MAX_SIZE << "]!";
215256
errno = EINVAL;
216-
return NULL;
257+
return false;
217258
}
218259
if (FLAGS_rdma_memory_pool_increase_size_mb < RDMA_MEMORY_POOL_MIN_SIZE ||
219260
FLAGS_rdma_memory_pool_increase_size_mb > RDMA_MEMORY_POOL_MAX_SIZE) {
@@ -222,7 +263,7 @@ void* InitBlockPool(RegisterCallback cb) {
222263
<< RDMA_MEMORY_POOL_MIN_SIZE << ","
223264
<< RDMA_MEMORY_POOL_MAX_SIZE << "]!";
224265
errno = EINVAL;
225-
return NULL;
266+
return false;
226267
}
227268
if (FLAGS_rdma_memory_pool_buckets < RDMA_MEMORY_POOL_MIN_BUCKETS ||
228269
FLAGS_rdma_memory_pool_buckets > RDMA_MEMORY_POOL_MAX_BUCKETS) {
@@ -231,41 +272,54 @@ void* InitBlockPool(RegisterCallback cb) {
231272
<< RDMA_MEMORY_POOL_MIN_BUCKETS << ","
232273
<< RDMA_MEMORY_POOL_MAX_BUCKETS << "]!";
233274
errno = EINVAL;
234-
return NULL;
275+
return false;
276+
}
277+
// runtime extend block pool only support 1 bucket
278+
if (FLAGS_rdma_memory_pool_max_regions > 1 &&
279+
FLAGS_rdma_memory_pool_buckets > 1) {
280+
LOG(WARNING) << "rdma runtime extend block pool only support 1 bucket";
281+
return false;
235282
}
236283
g_buckets = FLAGS_rdma_memory_pool_buckets;
237284

238285
g_info = new (std::nothrow) GlobalInfo;
239286
if (!g_info) {
240-
return NULL;
287+
return false;
241288
}
242289

243290
for (int i = 0; i < BLOCK_SIZE_COUNT; ++i) {
244291
g_info->idle_list[i].resize(g_buckets, NULL);
245292
if (g_info->idle_list[i].size() != g_buckets) {
246-
return NULL;
293+
return false;
247294
}
248295
g_info->lock[i].resize(g_buckets, NULL);
249296
if (g_info->lock[i].size() != g_buckets) {
250-
return NULL;
297+
return false;
251298
}
252299
g_info->idle_size[i].resize(g_buckets, 0);
253300
if (g_info->idle_size[i].size() != g_buckets) {
254-
return NULL;
301+
return false;
255302
}
256303
for (size_t j = 0; j < g_buckets; ++j) {
257304
g_info->lock[i][j] = new (std::nothrow) butil::Mutex;
258305
if (!g_info->lock[i][j]) {
259-
return NULL;
306+
return false;
260307
}
261308
}
262309
}
263310

264311
g_dump_mutex = new butil::Mutex;
265312
g_tls_info_mutex = new butil::Mutex;
266313

267-
return ExtendBlockPool(FLAGS_rdma_memory_pool_initial_size_mb,
268-
BLOCK_DEFAULT);
314+
if (FLAGS_rdma_memory_pool_user_specified_memory) {
315+
return true;
316+
}
317+
318+
if (ExtendBlockPool(FLAGS_rdma_memory_pool_initial_size_mb,
319+
BLOCK_DEFAULT) != NULL) {
320+
return true;
321+
}
322+
return false;
269323
}
270324

271325
static void* AllocBlockFrom(int block_type) {

src/brpc/rdma/block_pool.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,15 @@ typedef uint32_t (*RegisterCallback)(void*, size_t);
7373
// region. It should be the memory registration in brpc. However,
7474
// in block_pool, we just abstract it into a function to get region id.
7575
// Return the first region's address, NULL if failed and errno is set.
76-
void* InitBlockPool(RegisterCallback cb);
76+
bool InitBlockPool(RegisterCallback cb);
77+
78+
// In scenarios where users need to manually specify memory regions (e.g., using
79+
// hugepages or custom memory pools), when
80+
// FLAGS_rdma_memory_pool_user_specified_memory is true, user is responsibility
81+
// of extending memory blocks , this ensuring flexibility for advanced use
82+
// cases.
83+
void* ExtendBlockPoolByUser(void* region_base, size_t region_size,
84+
int block_type);
7785

7886
// Allocate a buf with length at least @a size (require: size>0)
7987
// Return the address allocated, NULL if failed and errno is set.

src/brpc/rdma/rdma_helper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ static void GlobalRelease() {
168168
}
169169
}
170170

171+
void* UserExtendBlockPool(void* region_base, size_t region_size,
172+
int block_type) {
173+
return ExtendBlockPoolByUser(region_base, region_size, block_type);
174+
}
175+
171176
uint32_t RdmaRegisterMemory(void* buf, size_t size) {
172177
// Register the memory as callback in block_pool
173178
// The thread-safety should be guaranteed by the caller

test/brpc_block_pool_unittest.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ TEST_F(BlockPoolTest, single_thread) {
5454
FLAGS_rdma_memory_pool_increase_size_mb = 1024;
5555
FLAGS_rdma_memory_pool_max_regions = 16;
5656
FLAGS_rdma_memory_pool_buckets = 4;
57-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
57+
EXPECT_TRUE(InitBlockPool(DummyCallback));
5858

5959
size_t num = 1024;
6060
void* buf[num];
@@ -108,7 +108,7 @@ TEST_F(BlockPoolTest, multiple_thread) {
108108
FLAGS_rdma_memory_pool_increase_size_mb = 1024;
109109
FLAGS_rdma_memory_pool_max_regions = 16;
110110
FLAGS_rdma_memory_pool_buckets = 4;
111-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
111+
EXPECT_TRUE(InitBlockPool(DummyCallback));
112112

113113
uintptr_t thread_num = 32;
114114
bthread_t tid[thread_num];
@@ -130,7 +130,7 @@ TEST_F(BlockPoolTest, extend) {
130130
FLAGS_rdma_memory_pool_increase_size_mb = 64;
131131
FLAGS_rdma_memory_pool_max_regions = 16;
132132
FLAGS_rdma_memory_pool_buckets = 1;
133-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
133+
EXPECT_TRUE(InitBlockPool(DummyCallback));
134134

135135
EXPECT_EQ(1, GetRegionNum());
136136
size_t num = 15 * 64 * 1024 * 1024 / GetBlockSize(2);
@@ -153,7 +153,7 @@ TEST_F(BlockPoolTest, memory_not_enough) {
153153
FLAGS_rdma_memory_pool_increase_size_mb = 64;
154154
FLAGS_rdma_memory_pool_max_regions = 2;
155155
FLAGS_rdma_memory_pool_buckets = 1;
156-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
156+
EXPECT_TRUE(InitBlockPool(DummyCallback));
157157

158158
EXPECT_EQ(1, GetRegionNum());
159159
size_t num = 64 * 1024 * 1024 / GetBlockSize(2);
@@ -179,7 +179,7 @@ TEST_F(BlockPoolTest, invalid_use) {
179179
FLAGS_rdma_memory_pool_increase_size_mb = 64;
180180
FLAGS_rdma_memory_pool_max_regions = 2;
181181
FLAGS_rdma_memory_pool_buckets = 1;
182-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
182+
EXPECT_TRUE(InitBlockPool(DummyCallback));
183183

184184
void* buf = AllocBlock(0);
185185
EXPECT_EQ(NULL, buf);
@@ -201,7 +201,7 @@ TEST_F(BlockPoolTest, dump_info) {
201201
FLAGS_rdma_memory_pool_increase_size_mb = 64;
202202
FLAGS_rdma_memory_pool_max_regions = 2;
203203
FLAGS_rdma_memory_pool_buckets = 4;
204-
EXPECT_TRUE(InitBlockPool(DummyCallback) != NULL);
204+
EXPECT_TRUE(InitBlockPool(DummyCallback));
205205
DumpMemoryPoolInfo(std::cout);
206206
void* buf = AllocBlock(8192);
207207
DumpMemoryPoolInfo(std::cout);

0 commit comments

Comments
 (0)