Drizzled Public API Documentation

xa_resource_manager.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *  Copyright (C) 2010 Jay Pipes <jaypipes@gmail.com>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; version 2 of the License.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <drizzled/cached_directory.h>
00024 
00025 #include <drizzled/definitions.h>
00026 #include <drizzled/session.h>
00027 #include <drizzled/error.h>
00028 #include <drizzled/gettext.h>
00029 #include <drizzled/plugin/xa_resource_manager.h>
00030 #include <drizzled/xid.h>
00031 
00032 
00033 #include <string>
00034 #include <vector>
00035 #include <algorithm>
00036 #include <functional>
00037 
00038 namespace drizzled
00039 {
00040 
00041 namespace plugin
00042 {
00043 
00044 static std::vector<XaResourceManager *> xa_resource_managers;
00045 
00046 int XaResourceManager::commitOrRollbackXID(XID *xid, bool commit)
00047 {
00048   std::vector<int> results;
00049 
00050   if (commit)
00051     transform(xa_resource_managers.begin(), xa_resource_managers.end(), results.begin(),
00052               std::bind2nd(std::mem_fun(&XaResourceManager::xaCommitXid), xid));
00053   else
00054     transform(xa_resource_managers.begin(), xa_resource_managers.end(), results.begin(),
00055               std::bind2nd(std::mem_fun(&XaResourceManager::xaRollbackXid), xid));
00056 
00057   if (std::find_if(results.begin(), results.end(), std::bind2nd(std::equal_to<int>(),0)) == results.end())
00058     return 1;
00059 
00060   return 0;
00061 }
00062 
00079 class XaRecover : std::unary_function<XaResourceManager *, void>
00080 {
00081 private:
00082   int trans_len, found_foreign_xids, found_my_xids;
00083   bool result;
00084   XID *trans_list;
00085   const XaResourceManager::commit_list_set &commit_list;
00086   bool dry_run;
00087 public:
00088   XaRecover(XID *trans_list_arg, int trans_len_arg,
00089             const XaResourceManager::commit_list_set& commit_list_arg,
00090             bool dry_run_arg)
00091     : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
00092       result(false),
00093       trans_list(trans_list_arg), commit_list(commit_list_arg),
00094       dry_run(dry_run_arg)
00095   {}
00096 
00097   int getForeignXIDs()
00098   {
00099     return found_foreign_xids;
00100   }
00101 
00102   int getMyXIDs()
00103   {
00104     return found_my_xids;
00105   }
00106 
00107   result_type operator() (argument_type resource_manager)
00108   {
00109 
00110     int got;
00111 
00112     while ((got= resource_manager->xaRecover(trans_list, trans_len)) > 0 )
00113     {
00114       errmsg_printf(error::INFO,
00115                     _("Found %d prepared transaction(s) in resource manager."),
00116                     got);
00117       for (int i=0; i < got; i ++)
00118       {
00119         my_xid x=trans_list[i].get_my_xid();
00120         if (!x) // not "mine" - that is generated by external TM
00121         {
00122           found_foreign_xids++;
00123           continue;
00124         }
00125         if (dry_run)
00126         {
00127           found_my_xids++;
00128           continue;
00129         }
00130         // recovery mode
00131         if (commit_list.size() ?
00132             commit_list.find(x) != commit_list.end() :
00133             tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
00134         {
00135           resource_manager->xaCommitXid(trans_list+i);
00136         }
00137         else
00138         {
00139           resource_manager->xaRollbackXid(trans_list+i);
00140         }
00141       }
00142       if (got < trans_len)
00143         break;
00144     }
00145   }
00146 };
00147 
00148 int XaResourceManager::recoverAllXids()
00149 {
00150   const XaResourceManager::commit_list_set empty_commit_set;
00151   return recoverAllXids(empty_commit_set);
00152 }
00153 
00154 int XaResourceManager::recoverAllXids(const XaResourceManager::commit_list_set &commit_list)
00155 {
00156   XID *trans_list= NULL;
00157   int trans_len= 0;
00158 
00159   bool dry_run= (commit_list.size() == 0 && tc_heuristic_recover==0);
00160 
00161   /* commit_list and tc_heuristic_recover cannot be set both */
00162   assert(commit_list.size() == 0 || tc_heuristic_recover == 0);
00163 
00164   if (xa_resource_managers.size() <= 1)
00165     return 0;
00166 
00167   tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
00168   dry_run=false;
00169   for (trans_len= MAX_XID_LIST_SIZE ;
00170        trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
00171   {
00172     trans_list=(XID *)malloc(trans_len*sizeof(XID));
00173   }
00174   if (!trans_list)
00175   {
00176     errmsg_printf(error::ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
00177     return(1);
00178   }
00179 
00180   if (commit_list.size())
00181     errmsg_printf(error::INFO, _("Starting crash recovery..."));
00182 
00183   XaRecover recover_func(trans_list, trans_len, commit_list, dry_run);
00184   std::for_each(xa_resource_managers.begin(),
00185                 xa_resource_managers.end(),
00186                 recover_func);
00187   free(trans_list);
00188 
00189   if (recover_func.getForeignXIDs())
00190     errmsg_printf(error::WARN,
00191                   _("Found %d prepared XA transactions"),
00192                   recover_func.getForeignXIDs());
00193 
00194   if (dry_run && recover_func.getMyXIDs())
00195   {
00196     errmsg_printf(error::ERROR,
00197                   _("Found %d prepared transactions! It means that drizzled "
00198                     "was not shut down properly last time and critical "
00199                     "recovery information (last binlog or %s file) was "
00200                     "manually deleted after a crash. You have to start "
00201                     "drizzled with the --tc-heuristic-recover switch to "
00202                     "commit or rollback pending transactions."),
00203                     recover_func.getMyXIDs(), opt_tc_log_file);
00204     return(1);
00205   }
00206 
00207   if (commit_list.size())
00208     errmsg_printf(error::INFO, _("Crash recovery finished."));
00209 
00210   return(0);
00211 }
00212 
00213 bool XaResourceManager::addPlugin(XaResourceManager *resource_manager)
00214 {
00215   xa_resource_managers.push_back(resource_manager);
00216   return false;
00217 }
00218 
00219 void XaResourceManager::removePlugin(XaResourceManager *)
00220 {
00221   xa_resource_managers.clear();
00222 }
00223 
00224 } /* namespace plugin */
00225 } /* namespace drizzled */