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 #include <drizzled/errmsg_print.h>
00032 #include <drizzled/sys_var.h>
00033 
00034 #include <string>
00035 #include <vector>
00036 #include <algorithm>
00037 #include <functional>
00038 
00039 namespace drizzled {
00040 namespace plugin {
00041 
00042 typedef std::vector<XaResourceManager*> xa_resource_managers_t;
00043 static xa_resource_managers_t xa_resource_managers;
00044 
00045 int XaResourceManager::commitOrRollbackXID(XID *xid, bool commit)
00046 {
00047   std::vector<int> results;
00048   BOOST_FOREACH(XaResourceManager* it, xa_resource_managers)
00049     results.push_back(commit ? it->xaCommitXid(xid) : it->xaRollbackXid(xid));
00050   return std::find(results.begin(), results.end(), 0) == results.end();
00051 }
00052 
00069 class XaRecover : std::unary_function<XaResourceManager *, void>
00070 {
00071 private:
00072   int trans_len, found_foreign_xids, found_my_xids;
00073   bool result;
00074   XID *trans_list;
00075   const XaResourceManager::commit_list_set &commit_list;
00076   bool dry_run;
00077 public:
00078   XaRecover(XID *trans_list_arg, int trans_len_arg,
00079             const XaResourceManager::commit_list_set& commit_list_arg,
00080             bool dry_run_arg)
00081     : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
00082       result(false),
00083       trans_list(trans_list_arg), commit_list(commit_list_arg),
00084       dry_run(dry_run_arg)
00085   {}
00086 
00087   int getForeignXIDs()
00088   {
00089     return found_foreign_xids;
00090   }
00091 
00092   int getMyXIDs()
00093   {
00094     return found_my_xids;
00095   }
00096 
00097   result_type operator() (argument_type resource_manager)
00098   {
00099 
00100     int got;
00101 
00102     while ((got= resource_manager->xaRecover(trans_list, trans_len)) > 0 )
00103     {
00104       errmsg_printf(error::INFO,
00105                     _("Found %d prepared transaction(s) in resource manager."),
00106                     got);
00107       for (int i=0; i < got; i ++)
00108       {
00109         my_xid x=trans_list[i].get_my_xid();
00110         if (!x) // not "mine" - that is generated by external TM
00111         {
00112           found_foreign_xids++;
00113           continue;
00114         }
00115         if (dry_run)
00116         {
00117           found_my_xids++;
00118           continue;
00119         }
00120         // recovery mode
00121         if (commit_list.size() ?
00122             commit_list.find(x) != commit_list.end() :
00123             tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
00124         {
00125           resource_manager->xaCommitXid(trans_list+i);
00126         }
00127         else
00128         {
00129           resource_manager->xaRollbackXid(trans_list+i);
00130         }
00131       }
00132       if (got < trans_len)
00133         break;
00134     }
00135   }
00136 };
00137 
00138 int XaResourceManager::recoverAllXids()
00139 {
00140   const XaResourceManager::commit_list_set empty_commit_set;
00141   return recoverAllXids(empty_commit_set);
00142 }
00143 
00144 int XaResourceManager::recoverAllXids(const XaResourceManager::commit_list_set &commit_list)
00145 {
00146   XID *trans_list= NULL;
00147   int trans_len= 0;
00148 
00149   bool dry_run= (commit_list.size() == 0 && tc_heuristic_recover==0);
00150 
00151   /* commit_list and tc_heuristic_recover cannot be set both */
00152   assert(commit_list.size() == 0 || tc_heuristic_recover == 0);
00153 
00154   if (xa_resource_managers.size() <= 1)
00155     return 0;
00156 
00157   tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
00158   dry_run=false;
00159   for (trans_len= MAX_XID_LIST_SIZE ;
00160        trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
00161   {
00162     trans_list=(XID *)malloc(trans_len*sizeof(XID));
00163   }
00164   if (!trans_list)
00165   {
00166     errmsg_printf(error::ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
00167     return 1;
00168   }
00169 
00170   if (commit_list.size())
00171     errmsg_printf(error::INFO, _("Starting crash recovery..."));
00172 
00173   XaRecover recover_func(trans_list, trans_len, commit_list, dry_run);
00174   std::for_each(xa_resource_managers.begin(),
00175                 xa_resource_managers.end(),
00176                 recover_func);
00177   free(trans_list);
00178 
00179   if (recover_func.getForeignXIDs())
00180     errmsg_printf(error::WARN,
00181                   _("Found %d prepared XA transactions"),
00182                   recover_func.getForeignXIDs());
00183 
00184   if (dry_run && recover_func.getMyXIDs())
00185   {
00186     errmsg_printf(error::ERROR,
00187                   _("Found %d prepared transactions! It means that drizzled "
00188                     "was not shut down properly last time and critical "
00189                     "recovery information (last binlog or %s file) was "
00190                     "manually deleted after a crash. You have to start "
00191                     "drizzled with the --tc-heuristic-recover switch to "
00192                     "commit or rollback pending transactions."),
00193                     recover_func.getMyXIDs(), opt_tc_log_file);
00194     return 1;
00195   }
00196 
00197   if (commit_list.size())
00198     errmsg_printf(error::INFO, _("Crash recovery finished."));
00199 
00200   return 0;
00201 }
00202 
00203 bool XaResourceManager::addPlugin(XaResourceManager *resource_manager)
00204 {
00205   xa_resource_managers.push_back(resource_manager);
00206   return false;
00207 }
00208 
00209 void XaResourceManager::removePlugin(XaResourceManager *)
00210 {
00211   xa_resource_managers.clear();
00212 }
00213 
00214 } /* namespace plugin */
00215 } /* namespace drizzled */