database: Potential data race for mutual exclusion
## What
There may be a data race when needing to acquire mutual exclusive access to `monerod`'s database, e.g. when resizing.

## Invariant
When resizing LMDB's memory map, the caller must ensure they have mutual exclusive access to it.

As per [`mdb_env_set_mapsize()`](http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5) docs:
> This function [...] may be called at later times if no transactions are active in this process. Note that the library does not check for this condition, the caller must ensure it explicitly.

An error is returned if there are other write transactions and presumably UB will occur if read transaction(s) exist.

## Implementation
The solution to this was implemented in https://github.com/monero-project/monero/pull/289, and is still used today. My understanding of this code is:

There are 2 atomic values used to achieve mutual exclusive access to the database:

https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L354-L355

The atomic bool is used to indicate "do not enter, we are resizing". Before starting a transaction, this bool will be spinned on until it is `false`. It is set to `true` when LMDB is resizing:
https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L448-L451

When resizing, this prevents _new_ transactions from starting.

To handle _currently_ active transactions, each transaction will `num_active_txns++` after successfully passing the atomic bool, and will `num_active_txns--` when done. The thread resizing will spin until `num_active_txns` is 0, indicating there are no more transactions:

https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L453-L456

Now, with no new transactions allowed, and all current ones gone, we _should_ have mutual exclusive access to the database and resizing should be OK.

## Problem
2 atomic operations back-to-back are not atomic. Other threads are free to execute in-between 2 atomic operations. What may occur in the above implementation is such:
```text
  Thread 1 (resizing)                             Thread 2 (normal read tx)
          |                                                 |
          |                                                 |
          |                                           lmdb_txn_begin()
          |                                     "not resizing, OK to start tx"
  prevent_new_txns()                                        |
"no new tx's can start"                                     |
          |                                                 |
 wait_no_active_txns()                                      |
  "spin until 0 tx's"                                       |
          |                                          num_active_txns++
          |                                                 |
 mdb_env_set_mapsize()   <--- ⚠️ unsafe ⚠️ --->   start_doing_tx_stuff()
``` 
There is space in-between `Thread 2` succesfully entering a transaction and updating `num_active_txns`.

If `Thread 2` is scheduled out by the OS after `lmdb_txn_begin()` but before `num_active_txns++` (unlikely but non-zero chance) `Thread 1` will incorrectly assume it has mutual exclusive access and start the resize.

https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L606-L608

Some crashes occurring near a resize that could be explained by this:
- https://github.com/monero-project/monero/issues/2851
- https://github.com/monero-project/monero/issues/2911
- https://github.com/monero-project/monero/issues/3230