Full_Name: Leonid Yuriev Version: 2.4.40 OS: RHEL7 URL: ftp://ftp.openldap.org/incoming/ Submission from: (NULL) (31.130.36.33)
In continue of ITS#7969 and ITS#7970.
An additional pages may be allocated unreasonable from map. Also the MDB_MAP_FULL error may returned while the space is really available.
As we can see on lines 2500-2550 of mdb.c the field mr_txnid updated after the mr_pid, which is also is a flag of that reader's slot is occupied and other fields are valid, e.g. it is: ti->mti_readers[i].mr_pid = pid; /* setup reader's pid, and indicate that other fields is valid. / ti->mti_readers[i].mr_tid = tid; /* setup reader's thread id. */ ... /* do a little bit of something. / r->mr_txnid = ti->mti_txnid; / * update a "detent" for reclaiming. */
The problem is that not all cases, the value mr_txnid correctly before being updated, but will be counted immediately after setup pid in reader's slot. Valid value for mr_txnid can be any number not less than the last transaction to now. We can easily verify that the MRC may be incorrect adding mdb_eassert(env, r->mr_txnid >= ti->mti_txnid) after updating mti_numreaders. diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 262373e..f2ed653 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -2522,6 +2522,7 @@ mdb_txn_renew0(MDB_txn *txn) return rc; } %%7} + mdb_eassert(env, r->mr_txnid >= ti->mti_txnid);
do /* ITS# */ r->mr_txnid = ti->mti_txnid;
And then by 'make test' got:
#2 0x0000000000403722 in mdb_assert_fail (env=env@entry=0x134e010, expr_txt=expr_txt@entry=0x40fd14 "r->mr_txnid >= ti->mti_txnid", func=func@entry=0x41067f <__FUNCTION__.7150> "mdb_txn_renew0", line=line@entry=2525, file=0x40fd08 "mdb.c") at mdb.c:1347 buf = "mdb.c:2525: Assertion 'r->mr_txnid >= ti->mti_txnid' failed in mdb_txn_renew0()\000\000\000\000\000\000\000\000\000 \025\063\337\273\177\000\000\360\360\316\367\377\177\000\000\340\360\316\367\377\177\000\000\236,]\242\000\000\000\000x\n@\000\000\000\000\000\377\377\377\377\000\000\000\000\002\000\000\000\000\000\000\000\320\016C3C357\336\273\177\000\000\310\344\062\337\273\177\000\000\001\000\000\000\000\000\000\000\003", '\000' <repeats 15 times>, "M\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000"... #3 0x0000000000403de8 in mdb_txn_renew0 (txn=txn@entry=0x134e210) at mdb.c:2525 r = 0x7fbbdf32b080 env = 0x134e010 ti = 0x7fbbdf32b000 meta = <optimised out> i = <optimised out> nr = <optimised out> x = <optimised out> rc = <optimised out> new_notls = 0 __FUNCTION__ = "mdb_txn_renew0" #4 0x00000000004045b8 in mdb_txn_begin (env=0x134e010, parent=parent@entry=0x0, flags=flags@entry=131072, ret=ret@entry=0x7ffff7cef2f0) at mdb.c:2706 txn = 0x134e210 ntxn = <optimised out> rc = <optimised out> size = <optimised out> tsize = 136
There is a possibility that the writer will call mdb_page_alloc() while the value of mr is wrong. In such case it is possible then reclaiming couldn't be done and a new page will be allocated from the map. But also possible the MDB_MAP_FULL error.
Thus, because of this bug additional pages may be allocated unreasonable, and the MDB_MAP_FULL error may happen while the space is available.