Bug #101260 Off-by-one error in fil_system sharding
Submitted: 21 Oct 2020 7:42 Modified: 8 Dec 2020 21:19
Reporter: Alexey Kopytov Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S3 (Non-critical)
Version:8.0 OS:Any
Assigned to: CPU Architecture:Any

[21 Oct 2020 7:42] Alexey Kopytov
Description:
The following code in storage/innobase/fil0fil.cc:

```
/** Maximum number of shards supported. */
static const size_t MAX_SHARDS = 64;

/** The redo log is in its own shard. */
static const size_t REDO_SHARD = MAX_SHARDS - 1;

/** Number of undo shards to reserve. */
static const size_t UNDO_SHARDS = 4;

/** The UNDO logs have their own shards (4). */
static const size_t UNDO_SHARDS_START = REDO_SHARD - (UNDO_SHARDS + 1);

...

  Fil_shard *shard_by_id(space_id_t space_id) const
      MY_ATTRIBUTE((warn_unused_result)) {
    if (space_id == dict_sys_t::s_log_space_first_id) {
      return (m_shards[REDO_SHARD]);

    } else if (fsp_is_undo_tablespace(space_id)) {
      const size_t limit = space_id % UNDO_SHARDS;

      return (m_shards[UNDO_SHARDS_START + limit]);
    }

    ut_ad(m_shards.size() == MAX_SHARDS);

```

There's clearly an off-by-one error here: shard #62 will never be used,
because we don't really need that "+ 1" when defining UNDO_SHARDS_START
to "REDO_SHARD - (UNDO_SHARDS + 1)"

While we are at it, can we define MAX_SHARDS to 69 to make division by
UNDO_SHARDS_START fast? We divide by UNDO_SHARDS (which is already a
power of two) and UNDO_SHARDS_START, which is currently 58 (will be 59
after the fix). We never divide by MAX_SHARDS, so if we define it to 69,
calculating the shard for regular tablespaces will also become a simple
bit operation.

How to repeat:
Look at the code snippet above.
[21 Oct 2020 14:06] MySQL Verification Team
Hello Kaamos,

Thank you for your bug report.

We have carefully analysed the code and we concluded that you are correct.

Verified as reported.
[8 Dec 2020 21:19] Daniel Price
Posted by developer:
 
Fixed as of the upcoming 8.0.23 release, and here's the proposed changelog entry from the documentation team:

An off-by-one error in Fil_system sharding code was corrected, and the
maximum number of shards (MAX_SHARDS) was changed to 69.
[9 Dec 2020 13:36] MySQL Verification Team
Thank you, Daniel .......