static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
                                    void *arg)
{
  handlerton *hton= plugin_hton(plugin);
  struct xarecover_st *info= (struct xarecover_st *) arg;
  int got;

  if (hton->state == SHOW_OPTION_YES && hton->recover)
  {
    while ((got= hton->recover(hton, info->list, info->len)) > 0 )
    {
      sql_print_information("Found %d prepared transaction(s) in %s",
                            got, hton_name(hton)->str);
      /* If wsrep_on=ON, XIDs are first ordered and then the range of
         recovered XIDs is checked for continuity. All the XIDs which
         are in continuous range can be safely committed if binlog
         is off since they have already ordered and certified in the
         cluster.

         The discontinuity of wsrep XIDs may happen because the GTID
         is assigned for transaction in wsrep_before_prepare(), but the
         commit order is entered in wsrep_before_commit(). This means that
         transactions may run prepare step out of order and may
         result in gap in wsrep XIDs. This can be the case for example
         if we have T1 with seqno 1 and T2 with seqno 2 and the server
         crashes after T2 finishes prepare step but before T1 starts
         the prepare.
      */
      my_xid wsrep_limit __attribute__((unused))= 0;

      /* Note that we could call this for binlog also that
         will not have WSREP(thd) but global wsrep on might
         be true.
      */
      if (WSREP_ON)
        wsrep_limit= wsrep_order_and_check_continuity(info->list, got);

      for (int i=0; i < got; i ++)
      {
        my_xid x= IF_WSREP(wsrep_is_wsrep_xid(&info->list[i]) ?
                           wsrep_xid_seqno(&info->list[i]) :
                           info->list[i].get_my_xid(),
                           info->list[i].get_my_xid());
        if (!x) // not "mine" - that is generated by external TM
        {
          DBUG_EXECUTE("info",{
            char buf[XIDDATASIZE*4+6];
            _db_doprnt_("ignore xid %s", xid_to_str(buf, info->list[i]));
            });
          xid_cache_insert(info->list + i);
          info->found_foreign_xids++;
          continue;
        }
        if (IF_WSREP(!(wsrep_emulate_bin_log &&
                       wsrep_is_wsrep_xid(info->list + i) &&
                       x <= wsrep_limit) && info->dry_run,
                     info->dry_run))
        {
          info->found_my_xids++;
          continue;
        }
        // recovery mode
        if (IF_WSREP((wsrep_emulate_bin_log &&
                      wsrep_is_wsrep_xid(info->list + i) &&
                      x <= wsrep_limit), false) ||
            (info->commit_list ?
             my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
             tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT))
        {
          int rc= hton->commit_by_xid(hton, info->list+i);
          if (rc == 0)
          {
            DBUG_EXECUTE("info",{
              char buf[XIDDATASIZE*4+6];
              _db_doprnt_("commit xid %s", xid_to_str(buf, info->list[i]));
              });
          }
        }
        else
        {
          int rc= hton->rollback_by_xid(hton, info->list+i);
          if (rc == 0)
          {
            DBUG_EXECUTE("info",{
              char buf[XIDDATASIZE*4+6];
              _db_doprnt_("rollback xid %s", xid_to_str(buf, info->list[i]));
              });
          }
        }
      }
      if (got < info->len)
        break;
    }
  }
  return FALSE;
}