Skip to content

Commit 6bcace1

Browse files
committed
Use single memory pool for result metadata and result set.
1 parent a072481 commit 6bcace1

11 files changed

+123
-83
lines changed

ext/mysqli/tests/mysqli_debug_mysqlnd_only.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ if (!$IS_MYSQLND)
9090
if (isset($functions_trace[$name]))
9191
$found++;
9292

93-
if ($found < 2) {
93+
if ($found < 1) {
9494
printf("[016] Only %d memory functions have been found, expecting at least %d.\n",
95-
$found, 2);
95+
$found, 1);
9696
var_dump($trace);
9797
}
9898

ext/mysqlnd/mysqlnd_block_alloc.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ static zend_always_inline void* mysqlnd_arena_alloc(zend_arena **arena_ptr, size
7676
}
7777
/* }}} */
7878

79+
static zend_always_inline void* mysqlnd_arena_checkpoint(zend_arena *arena)
80+
{
81+
return arena->ptr;
82+
}
83+
84+
static zend_always_inline void mysqlnd_arena_release(zend_arena **arena_ptr, void *checkpoint)
85+
{
86+
zend_arena *arena = *arena_ptr;
87+
88+
while (UNEXPECTED((char*)checkpoint > arena->end) ||
89+
UNEXPECTED((char*)checkpoint <= (char*)arena)) {
90+
zend_arena *prev = arena->prev;
91+
mnd_efree(arena);
92+
*arena_ptr = arena = prev;
93+
}
94+
ZEND_ASSERT((char*)checkpoint > (char*)arena && (char*)checkpoint <= arena->end);
95+
arena->ptr = (char*)checkpoint;
96+
}
97+
7998
/* {{{ mysqlnd_mempool_free_chunk */
8099
static void
81100
mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL * pool, void * ptr)
@@ -145,6 +164,8 @@ mysqlnd_mempool_create(size_t arena_size)
145164
arena = mysqlnd_arena_create(MAX(arena_size, sizeof(zend_arena)));
146165
ret = mysqlnd_arena_alloc(&arena, sizeof(MYSQLND_MEMORY_POOL));
147166
ret->arena = arena;
167+
ret->last = NULL;
168+
ret->checkpoint = NULL;
148169
ret->get_chunk = mysqlnd_mempool_get_chunk;
149170
ret->free_chunk = mysqlnd_mempool_free_chunk;
150171
ret->resize_chunk = mysqlnd_mempool_resize_chunk;
@@ -164,6 +185,29 @@ mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool)
164185
}
165186
/* }}} */
166187

188+
/* {{{ mysqlnd_mempool_save_state */
189+
PHPAPI void
190+
mysqlnd_mempool_save_state(MYSQLND_MEMORY_POOL * pool)
191+
{
192+
DBG_ENTER("mysqlnd_mempool_save_state");
193+
pool->checkpoint = mysqlnd_arena_checkpoint(pool->arena);
194+
DBG_VOID_RETURN;
195+
}
196+
/* }}} */
197+
198+
/* {{{ mysqlnd_mempool_restore_state */
199+
PHPAPI void
200+
mysqlnd_mempool_restore_state(MYSQLND_MEMORY_POOL * pool)
201+
{
202+
DBG_ENTER("mysqlnd_mempool_restore_state");
203+
if (pool->checkpoint) {
204+
mysqlnd_arena_release(&pool->arena, pool->checkpoint);
205+
pool->last = NULL;
206+
pool->checkpoint = NULL;
207+
}
208+
DBG_VOID_RETURN;
209+
}
210+
/* }}} */
167211

168212
/*
169213
* Local variables:

ext/mysqlnd/mysqlnd_block_alloc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
PHPAPI MYSQLND_MEMORY_POOL * mysqlnd_mempool_create(size_t arena_size);
2424
PHPAPI void mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool);
25+
PHPAPI void mysqlnd_mempool_save_state(MYSQLND_MEMORY_POOL * pool);
26+
PHPAPI void mysqlnd_mempool_restore_state(MYSQLND_MEMORY_POOL * pool);
2527

2628
#endif /* MYSQLND_BLOCK_ALLOC_H */
2729

ext/mysqlnd/mysqlnd_ps.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
8282
result->type = MYSQLND_RES_PS_BUF;
8383
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
8484

85-
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, TRUE);
85+
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result, result->field_count, TRUE);
8686
if (!result->stored_data) {
8787
SET_OOM_ERROR(conn->error_info);
8888
DBG_RETURN(NULL);
@@ -122,7 +122,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
122122
} else {
123123
COPY_CLIENT_ERROR(conn->error_info, result->stored_data->error_info);
124124
stmt->result->m.free_result_contents(stmt->result);
125-
mnd_efree(stmt->result);
125+
mysqlnd_mempool_destroy(stmt->result->memory_pool);
126126
stmt->result = NULL;
127127
stmt->state = MYSQLND_STMT_PREPARED;
128128
}
@@ -173,7 +173,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
173173
break;
174174
}
175175

176-
result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta);
176+
result->meta = stmt->result->meta->m->clone_metadata(result, stmt->result->meta);
177177
if (!result->meta) {
178178
SET_OOM_ERROR(conn->error_info);
179179
break;
@@ -251,14 +251,21 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s)
251251
unsigned int i = 0;
252252
enum_func_status ret = FAIL;
253253
MYSQLND_PACKET_RES_FIELD field_packet;
254+
MYSQLND_MEMORY_POOL * pool;
254255

255256
DBG_ENTER("mysqlnd_stmt_skip_metadata");
256257
if (!stmt || !conn) {
257258
DBG_RETURN(FAIL);
258259
}
260+
pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size));
261+
if (!pool) {
262+
DBG_RETURN(FAIL);
263+
}
259264
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
260265

261266
conn->payload_decoder_factory->m.init_result_field_packet(&field_packet);
267+
field_packet.memory_pool = pool;
268+
262269
ret = PASS;
263270
field_packet.skip_parsing = TRUE;
264271
for (;i < stmt->param_count; i++) {
@@ -268,6 +275,7 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s)
268275
}
269276
}
270277
PACKET_FREE(&field_packet);
278+
mysqlnd_mempool_destroy(pool);
271279

272280
DBG_RETURN(ret);
273281
}
@@ -1835,12 +1843,12 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s)
18351843
break;
18361844
}
18371845
result_meta->type = MYSQLND_RES_NORMAL;
1838-
result_meta->unbuf = mysqlnd_result_unbuffered_init(stmt->field_count, TRUE);
1846+
result_meta->unbuf = mysqlnd_result_unbuffered_init(result_meta, stmt->field_count, TRUE);
18391847
if (!result_meta->unbuf) {
18401848
break;
18411849
}
18421850
result_meta->unbuf->eof_reached = TRUE;
1843-
result_meta->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta);
1851+
result_meta->meta = stmt->result->meta->m->clone_metadata(result_meta, stmt->result->meta);
18441852
if (!result_meta->meta) {
18451853
break;
18461854
}

ext/mysqlnd/mysqlnd_result.c

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED *
190190
result->row_packet = NULL;
191191
}
192192

193-
mysqlnd_mempool_destroy(result->result_set_memory_pool);
193+
mysqlnd_mempool_restore_state(result->result_set_memory_pool);
194194

195195
DBG_VOID_RETURN;
196196
}
@@ -261,7 +261,7 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons
261261
set->row_buffers = NULL;
262262
}
263263

264-
mysqlnd_mempool_destroy(set->result_set_memory_pool);
264+
mysqlnd_mempool_restore_state(set->result_set_memory_pool);
265265

266266
DBG_VOID_RETURN;
267267
}
@@ -320,7 +320,7 @@ void MYSQLND_METHOD(mysqlnd_res, free_result_internal)(MYSQLND_RES * result)
320320
result->conn = NULL;
321321
}
322322

323-
mnd_efree(result);
323+
mysqlnd_mempool_destroy(result->memory_pool);
324324

325325
DBG_VOID_RETURN;
326326
}
@@ -344,7 +344,7 @@ MYSQLND_METHOD(mysqlnd_res, read_result_metadata)(MYSQLND_RES * result, MYSQLND_
344344
result->meta = NULL;
345345
}
346346

347-
result->meta = result->m.result_meta_init(result->field_count);
347+
result->meta = result->m.result_meta_init(result, result->field_count);
348348
if (!result->meta) {
349349
SET_OOM_ERROR(conn->error_info);
350350
DBG_RETURN(FAIL);
@@ -353,7 +353,7 @@ MYSQLND_METHOD(mysqlnd_res, read_result_metadata)(MYSQLND_RES * result, MYSQLND_
353353
/* 1. Read all fields metadata */
354354

355355
/* It's safe to reread without freeing */
356-
if (FAIL == result->meta->m->read_metadata(result->meta, conn)) {
356+
if (FAIL == result->meta->m->read_metadata(result->meta, conn, result)) {
357357
result->m.free_result_contents(result);
358358
DBG_RETURN(FAIL);
359359
}
@@ -514,7 +514,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
514514
if (FAIL == (ret = PACKET_READ(conn, &fields_eof))) {
515515
DBG_ERR("Error occurred while reading the EOF packet");
516516
result->m.free_result_contents(result);
517-
mnd_efree(result);
517+
mysqlnd_mempool_destroy(result->memory_pool);
518518
if (!stmt) {
519519
conn->current_result = NULL;
520520
} else {
@@ -906,7 +906,7 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, const zend_b
906906
result->type = MYSQLND_RES_PS_UNBUF;
907907
}
908908

909-
result->unbuf = mysqlnd_result_unbuffered_init(result->field_count, ps);
909+
result->unbuf = mysqlnd_result_unbuffered_init(result, result->field_count, ps);
910910
if (!result->unbuf) {
911911
goto oom;
912912
}
@@ -1389,14 +1389,14 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
13891389
SET_CONNECTION_STATE(&conn->state, CONN_FETCHING_DATA);
13901390

13911391
if (flags & MYSQLND_STORE_NO_COPY) {
1392-
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, flags & MYSQLND_STORE_PS);
1392+
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result, result->field_count, flags & MYSQLND_STORE_PS);
13931393
if (!result->stored_data) {
13941394
SET_OOM_ERROR(conn->error_info);
13951395
DBG_RETURN(NULL);
13961396
}
13971397
row_buffers = &result->stored_data->row_buffers;
13981398
} else if (flags & MYSQLND_STORE_COPY) {
1399-
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_c_init(result->field_count, flags & MYSQLND_STORE_PS);
1399+
result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_c_init(result, result->field_count, flags & MYSQLND_STORE_PS);
14001400
if (!result->stored_data) {
14011401
SET_OOM_ERROR(conn->error_info);
14021402
DBG_RETURN(NULL);
@@ -1886,14 +1886,20 @@ PHPAPI MYSQLND_RES *
18861886
mysqlnd_result_init(const unsigned int field_count)
18871887
{
18881888
const size_t alloc_size = sizeof(MYSQLND_RES) + mysqlnd_plugin_count() * sizeof(void *);
1889-
MYSQLND_RES * ret = mnd_ecalloc(1, alloc_size);
1889+
MYSQLND_MEMORY_POOL * pool;
1890+
MYSQLND_RES * ret;
18901891

18911892
DBG_ENTER("mysqlnd_result_init");
18921893

1893-
if (!ret) {
1894+
pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size));
1895+
if (!pool) {
18941896
DBG_RETURN(NULL);
18951897
}
18961898

1899+
ret = pool->get_chunk(pool, alloc_size);
1900+
memset(ret, 0, alloc_size);
1901+
1902+
ret->memory_pool = pool;
18971903
ret->field_count = field_count;
18981904
ret->m = *mysqlnd_result_get_methods();
18991905

@@ -1904,19 +1910,15 @@ mysqlnd_result_init(const unsigned int field_count)
19041910

19051911
/* {{{ mysqlnd_result_unbuffered_init */
19061912
PHPAPI MYSQLND_RES_UNBUFFERED *
1907-
mysqlnd_result_unbuffered_init(const unsigned int field_count, const zend_bool ps)
1913+
mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_count, const zend_bool ps)
19081914
{
19091915
const size_t alloc_size = sizeof(MYSQLND_RES_UNBUFFERED) + mysqlnd_plugin_count() * sizeof(void *);
1910-
MYSQLND_MEMORY_POOL * pool;
1916+
MYSQLND_MEMORY_POOL * pool = result->memory_pool;
19111917
MYSQLND_RES_UNBUFFERED * ret;
19121918

19131919
DBG_ENTER("mysqlnd_result_unbuffered_init");
19141920

1915-
pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size));
1916-
if (!pool) {
1917-
DBG_RETURN(NULL);
1918-
}
1919-
1921+
mysqlnd_mempool_save_state(pool);
19201922
ret = pool->get_chunk(pool, alloc_size);
19211923
memset(ret, 0, alloc_size);
19221924

@@ -1943,24 +1945,20 @@ mysqlnd_result_unbuffered_init(const unsigned int field_count, const zend_bool p
19431945

19441946
/* {{{ mysqlnd_result_buffered_zval_init */
19451947
PHPAPI MYSQLND_RES_BUFFERED_ZVAL *
1946-
mysqlnd_result_buffered_zval_init(const unsigned int field_count, const zend_bool ps)
1948+
mysqlnd_result_buffered_zval_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps)
19471949
{
19481950
const size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_ZVAL) + mysqlnd_plugin_count() * sizeof(void *);
1949-
MYSQLND_MEMORY_POOL * pool;
1951+
MYSQLND_MEMORY_POOL * pool = result->memory_pool;
19501952
MYSQLND_RES_BUFFERED_ZVAL * ret;
19511953

19521954
DBG_ENTER("mysqlnd_result_buffered_zval_init");
19531955

1954-
pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size));
1955-
if (!pool) {
1956-
DBG_RETURN(NULL);
1957-
}
1958-
1956+
mysqlnd_mempool_save_state(pool);
19591957
ret = pool->get_chunk(pool, alloc_size);
19601958
memset(ret, 0, alloc_size);
19611959

19621960
if (FAIL == mysqlnd_error_info_init(&ret->error_info, 0)) {
1963-
mysqlnd_mempool_destroy(pool);
1961+
mysqlnd_mempool_restore_state(pool);
19641962
DBG_RETURN(NULL);
19651963
}
19661964

@@ -1990,24 +1988,20 @@ mysqlnd_result_buffered_zval_init(const unsigned int field_count, const zend_boo
19901988

19911989
/* {{{ mysqlnd_result_buffered_c_init */
19921990
PHPAPI MYSQLND_RES_BUFFERED_C *
1993-
mysqlnd_result_buffered_c_init(const unsigned int field_count, const zend_bool ps)
1991+
mysqlnd_result_buffered_c_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps)
19941992
{
19951993
const size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_C) + mysqlnd_plugin_count() * sizeof(void *);
1996-
MYSQLND_MEMORY_POOL * pool;
1994+
MYSQLND_MEMORY_POOL * pool = result->memory_pool;
19971995
MYSQLND_RES_BUFFERED_C * ret;
19981996

19991997
DBG_ENTER("mysqlnd_result_buffered_c_init");
20001998

2001-
pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size));
2002-
if (!pool) {
2003-
DBG_RETURN(NULL);
2004-
}
2005-
1999+
mysqlnd_mempool_save_state(pool);
20062000
ret = pool->get_chunk(pool, alloc_size);
20072001
memset(ret, 0, alloc_size);
20082002

20092003
if (FAIL == mysqlnd_error_info_init(&ret->error_info, 0)) {
2010-
mysqlnd_mempool_destroy(pool);
2004+
mysqlnd_mempool_restore_state(pool);
20112005
DBG_RETURN(NULL);
20122006
}
20132007

ext/mysqlnd/mysqlnd_result.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
#define MYSQLND_RESULT_H
2222

2323
PHPAPI MYSQLND_RES * mysqlnd_result_init(const unsigned int field_count);
24-
PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(const unsigned int field_count, const zend_bool ps);
25-
PHPAPI MYSQLND_RES_BUFFERED_ZVAL * mysqlnd_result_buffered_zval_init(const unsigned int field_count, const zend_bool ps);
26-
PHPAPI MYSQLND_RES_BUFFERED_C * mysqlnd_result_buffered_c_init(const unsigned int field_count, const zend_bool ps);
24+
PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps);
25+
PHPAPI MYSQLND_RES_BUFFERED_ZVAL * mysqlnd_result_buffered_zval_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps);
26+
PHPAPI MYSQLND_RES_BUFFERED_C * mysqlnd_result_buffered_c_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps);
2727

2828
enum_func_status mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * stmt);
2929

0 commit comments

Comments
 (0)