| 55 | } |
| 56 | |
| 57 | void mutation_buffer::commit(decree d, commit_type ct) |
| 58 | { |
| 59 | if (d <= last_committed_decree()) |
| 60 | return; |
| 61 | |
| 62 | CHECK_EQ_PREFIX(ct, COMMIT_TO_DECREE_HARD); |
| 63 | |
| 64 | ballot last_bt = 0; |
| 65 | for (decree d0 = last_committed_decree() + 1; d0 <= d; d0++) { |
| 66 | mutation_ptr next_committed_mutation = get_mutation_by_decree(d0); |
| 67 | // The unexpected case as follow: next_committed_decree is out of prepare_list[start~end] |
| 68 | // |
| 69 | // last_committed_decree - next_committed_decree |
| 70 | // | | |
| 71 | // n n+1 |
| 72 | // |
| 73 | // [min_decree------max_decree] |
| 74 | // | | |
| 75 | // n+m(m>1) n+k(k>=m) |
| 76 | // |
| 77 | // just LOG_ERROR but not CHECK if mutation loss or other problem, it's different from |
| 78 | // base class implement. And from the error and perf-counter, we can choose restart |
| 79 | // duplication |
| 80 | // or ignore the loss. |
| 81 | if (next_committed_mutation == nullptr || !next_committed_mutation->is_logged()) { |
| 82 | LOG_ERROR_PREFIX("mutation[{}] is lost in prepare_list: " |
| 83 | "prepare_last_committed_decree={}, prepare_min_decree={}, " |
| 84 | "prepare_max_decree={}", |
| 85 | d0, |
| 86 | last_committed_decree(), |
| 87 | min_decree(), |
| 88 | max_decree()); |
| 89 | _counter_dulication_mutation_loss_count->set(min_decree() - last_committed_decree()); |
| 90 | // if next_commit_mutation loss, let last_commit_decree catch up with min_decree, and |
| 91 | // the next loop will commit from min_decree |
| 92 | _last_committed_decree = min_decree() - 1; |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | CHECK_GE_PREFIX(next_committed_mutation->data.header.ballot, last_bt); |
| 97 | _last_committed_decree++; |
| 98 | last_bt = next_committed_mutation->data.header.ballot; |
| 99 | _committer(next_committed_mutation); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | error_s mutation_batch::add(mutation_ptr mu) |
| 104 | { |