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
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)
00121 {
00122 found_foreign_xids++;
00123 continue;
00124 }
00125 if (dry_run)
00126 {
00127 found_my_xids++;
00128 continue;
00129 }
00130
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
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;
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 }
00225 }