00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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)
00111 {
00112 found_foreign_xids++;
00113 continue;
00114 }
00115 if (dry_run)
00116 {
00117 found_my_xids++;
00118 continue;
00119 }
00120
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
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;
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 }
00215 }