@ -844,6 +844,8 @@ struct MDB_txn {
# define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */
# define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */
/** @} */
/** @} */
unsigned int mt_flags ; /**< @ref mdb_txn */
unsigned int mt_flags ; /**< @ref mdb_txn */
/** dirty_list maxsize - #allocated pages including in parent txns */
unsigned int mt_dirty_room ;
/** Tracks which of the two meta pages was used at the start
/** Tracks which of the two meta pages was used at the start
* of this transaction .
* of this transaction .
*/
*/
@ -1285,7 +1287,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
* mp = NULL ;
* mp = NULL ;
/* If our dirty list is already full, we can't do anything */
/* If our dirty list is already full, we can't do anything */
if ( txn - > mt_u . dirty_list [ 0 ] . mid > = MDB_IDL_UM_MAX )
if ( txn - > mt_dirty_room = = 0 )
return MDB_TXN_FULL ;
return MDB_TXN_FULL ;
/* The free list won't have any content at all until txn 2 has
/* The free list won't have any content at all until txn 2 has
@ -1524,6 +1526,7 @@ none:
} else {
} else {
mdb_mid2l_insert ( txn - > mt_u . dirty_list , & mid ) ;
mdb_mid2l_insert ( txn - > mt_u . dirty_list , & mid ) ;
}
}
txn - > mt_dirty_room - - ;
* mp = np ;
* mp = np ;
return MDB_SUCCESS ;
return MDB_SUCCESS ;
@ -1628,8 +1631,6 @@ finish:
return 0 ;
return 0 ;
}
}
}
}
if ( mc - > mc_txn - > mt_u . dirty_list [ 0 ] . mid > = MDB_IDL_UM_MAX )
return MDB_TXN_FULL ;
/* No - copy it */
/* No - copy it */
np = mdb_page_malloc ( mc ) ;
np = mdb_page_malloc ( mc ) ;
if ( ! np )
if ( ! np )
@ -1821,6 +1822,7 @@ mdb_txn_renew0(MDB_txn *txn)
if ( txn - > mt_txnid = = mdb_debug_start )
if ( txn - > mt_txnid = = mdb_debug_start )
mdb_debug = 1 ;
mdb_debug = 1 ;
# endif
# endif
txn - > mt_dirty_room = MDB_IDL_UM_MAX ;
txn - > mt_u . dirty_list = env - > me_dirty_list ;
txn - > mt_u . dirty_list = env - > me_dirty_list ;
txn - > mt_u . dirty_list [ 0 ] . mid = 0 ;
txn - > mt_u . dirty_list [ 0 ] . mid = 0 ;
txn - > mt_free_pgs = env - > me_free_pgs ;
txn - > mt_free_pgs = env - > me_free_pgs ;
@ -1921,6 +1923,7 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
}
}
txn - > mt_txnid = parent - > mt_txnid ;
txn - > mt_txnid = parent - > mt_txnid ;
txn - > mt_toggle = parent - > mt_toggle ;
txn - > mt_toggle = parent - > mt_toggle ;
txn - > mt_dirty_room = parent - > mt_dirty_room ;
txn - > mt_u . dirty_list [ 0 ] . mid = 0 ;
txn - > mt_u . dirty_list [ 0 ] . mid = 0 ;
txn - > mt_free_pgs [ 0 ] = 0 ;
txn - > mt_free_pgs [ 0 ] = 0 ;
txn - > mt_next_pgno = parent - > mt_next_pgno ;
txn - > mt_next_pgno = parent - > mt_next_pgno ;
@ -2099,9 +2102,16 @@ mdb_txn_commit(MDB_txn *txn)
if ( txn - > mt_parent ) {
if ( txn - > mt_parent ) {
MDB_txn * parent = txn - > mt_parent ;
MDB_txn * parent = txn - > mt_parent ;
unsigned x , y ;
unsigned x , y , len ;
MDB_ID2L dst , src ;
MDB_ID2L dst , src ;
/* Append our free list to parent's */
if ( mdb_midl_append_list ( & parent - > mt_free_pgs , txn - > mt_free_pgs ) ) {
mdb_txn_abort ( txn ) ;
return ENOMEM ;
}
mdb_midl_free ( txn - > mt_free_pgs ) ;
parent - > mt_next_pgno = txn - > mt_next_pgno ;
parent - > mt_next_pgno = txn - > mt_next_pgno ;
parent - > mt_flags = txn - > mt_flags ;
parent - > mt_flags = txn - > mt_flags ;
@ -2113,32 +2123,40 @@ mdb_txn_commit(MDB_txn *txn)
memcpy ( parent - > mt_dbflags , txn - > mt_dbflags , txn - > mt_numdbs ) ;
memcpy ( parent - > mt_dbflags , txn - > mt_dbflags , txn - > mt_numdbs ) ;
txn - > mt_parent - > mt_numdbs = txn - > mt_numdbs ;
txn - > mt_parent - > mt_numdbs = txn - > mt_numdbs ;
/* Append our free list to parent's */
mdb_midl_append_list ( & txn - > mt_parent - > mt_free_pgs ,
txn - > mt_free_pgs ) ;
mdb_midl_free ( txn - > mt_free_pgs ) ;
/* Merge our dirty list with parent's */
dst = txn - > mt_parent - > mt_u . dirty_list ;
dst = txn - > mt_parent - > mt_u . dirty_list ;
src = txn - > mt_u . dirty_list ;
src = txn - > mt_u . dirty_list ;
x = mdb_mid2l_search ( dst , src [ 1 ] . mid ) ;
/* Find len = length of merging our dirty list with parent's */
for ( y = 1 ; y < = src [ 0 ] . mid ; y + + ) {
while ( x < = dst [ 0 ] . mid & & dst [ x ] . mid ! = src [ y ] . mid ) x + + ;
if ( x > dst [ 0 ] . mid )
break ;
free ( dst [ x ] . mptr ) ;
dst [ x ] . mptr = src [ y ] . mptr ;
}
x = dst [ 0 ] . mid ;
x = dst [ 0 ] . mid ;
for ( ; y < = src [ 0 ] . mid ; y + + ) {
dst [ 0 ] . mid = 0 ; /* simplify loops */
if ( + + x > = MDB_IDL_UM_MAX ) {
if ( parent - > mt_parent ) {
mdb_txn_abort ( txn ) ;
len = x + src [ 0 ] . mid ;
return MDB_TXN_FULL ;
y = mdb_mid2l_search ( src , dst [ x ] . mid + 1 ) - 1 ;
for ( i = x ; y & & i ; y - - ) {
pgno_t yp = src [ y ] . mid ;
while ( yp < dst [ i ] . mid )
i - - ;
if ( yp = = dst [ i ] . mid ) {
i - - ;
len - - ;
}
}
}
dst [ x ] = src [ y ] ;
} else { /* Simplify the above for single-ancestor case */
len = MDB_IDL_UM_MAX - txn - > mt_dirty_room ;
}
}
dst [ 0 ] . mid = x ;
/* Merge our dirty list with parent's */
y = src [ 0 ] . mid ;
for ( i = len ; y ; dst [ i - - ] = src [ y - - ] ) {
pgno_t yp = src [ y ] . mid ;
while ( yp < dst [ x ] . mid )
dst [ i - - ] = dst [ x - - ] ;
if ( yp = = dst [ x ] . mid )
free ( dst [ x - - ] . mptr ) ;
}
assert ( i = = x ) ;
dst [ 0 ] . mid = len ;
free ( txn - > mt_u . dirty_list ) ;
free ( txn - > mt_u . dirty_list ) ;
parent - > mt_dirty_room = txn - > mt_dirty_room ;
txn - > mt_parent - > mt_child = NULL ;
txn - > mt_parent - > mt_child = NULL ;
free ( ( ( MDB_ntxn * ) txn ) - > mnt_pgstate . mf_pgfree ) ;
free ( ( ( MDB_ntxn * ) txn ) - > mnt_pgstate . mf_pgfree ) ;
free ( txn ) ;
free ( txn ) ;