Drizzled Public API Documentation

xa_resource_manager.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008 Sun Microsystems, Inc.
5  * Copyright (C) 2010 Jay Pipes <jaypipes@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <config.h>
22 
24 
25 #include <drizzled/definitions.h>
26 #include <drizzled/session.h>
27 #include <drizzled/error.h>
28 #include <drizzled/gettext.h>
29 #include <drizzled/plugin/xa_resource_manager.h>
30 #include <drizzled/xid.h>
31 #include <drizzled/errmsg_print.h>
32 #include <drizzled/sys_var.h>
33 
34 #include <string>
35 #include <vector>
36 #include <algorithm>
37 #include <functional>
38 
39 namespace drizzled {
40 namespace plugin {
41 
42 typedef std::vector<XaResourceManager*> xa_resource_managers_t;
43 static xa_resource_managers_t xa_resource_managers;
44 
46 {
47  std::vector<int> results;
48  BOOST_FOREACH(XaResourceManager* it, xa_resource_managers)
49  results.push_back(commit ? it->xaCommitXid(xid) : it->xaRollbackXid(xid));
50  return std::find(results.begin(), results.end(), 0) == results.end();
51 }
52 
69 class XaRecover : std::unary_function<XaResourceManager *, void>
70 {
71 private:
72  int trans_len, found_foreign_xids, found_my_xids;
73  bool result;
74  XID *trans_list;
75  const XaResourceManager::commit_list_set &commit_list;
76  bool dry_run;
77 public:
78  XaRecover(XID *trans_list_arg, int trans_len_arg,
79  const XaResourceManager::commit_list_set& commit_list_arg,
80  bool dry_run_arg)
81  : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
82  result(false),
83  trans_list(trans_list_arg), commit_list(commit_list_arg),
84  dry_run(dry_run_arg)
85  {}
86 
87  int getForeignXIDs()
88  {
89  return found_foreign_xids;
90  }
91 
92  int getMyXIDs()
93  {
94  return found_my_xids;
95  }
96 
97  result_type operator() (argument_type resource_manager)
98  {
99 
100  int got;
101 
102  while ((got= resource_manager->xaRecover(trans_list, trans_len)) > 0 )
103  {
104  errmsg_printf(error::INFO,
105  _("Found %d prepared transaction(s) in resource manager."),
106  got);
107  for (int i=0; i < got; i ++)
108  {
109  my_xid x=trans_list[i].get_my_xid();
110  if (!x) // not "mine" - that is generated by external TM
111  {
112  found_foreign_xids++;
113  continue;
114  }
115  if (dry_run)
116  {
117  found_my_xids++;
118  continue;
119  }
120  // recovery mode
121  if (commit_list.size() ?
122  commit_list.find(x) != commit_list.end() :
123  tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
124  {
125  resource_manager->xaCommitXid(trans_list+i);
126  }
127  else
128  {
129  resource_manager->xaRollbackXid(trans_list+i);
130  }
131  }
132  if (got < trans_len)
133  break;
134  }
135  }
136 };
137 
138 int XaResourceManager::recoverAllXids()
139 {
140  const XaResourceManager::commit_list_set empty_commit_set;
141  return recoverAllXids(empty_commit_set);
142 }
143 
144 int XaResourceManager::recoverAllXids(const XaResourceManager::commit_list_set &commit_list)
145 {
146  XID *trans_list= NULL;
147  int trans_len= 0;
148 
149  bool dry_run= (commit_list.size() == 0 && tc_heuristic_recover==0);
150 
151  /* commit_list and tc_heuristic_recover cannot be set both */
152  assert(commit_list.size() == 0 || tc_heuristic_recover == 0);
153 
154  if (xa_resource_managers.size() <= 1)
155  return 0;
156 
157  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
158  dry_run=false;
159  for (trans_len= MAX_XID_LIST_SIZE ;
160  trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
161  {
162  trans_list=(XID *)malloc(trans_len*sizeof(XID));
163  }
164  if (!trans_list)
165  {
166  errmsg_printf(error::ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
167  return 1;
168  }
169 
170  if (commit_list.size())
171  errmsg_printf(error::INFO, _("Starting crash recovery..."));
172 
173  XaRecover recover_func(trans_list, trans_len, commit_list, dry_run);
174  std::for_each(xa_resource_managers.begin(),
175  xa_resource_managers.end(),
176  recover_func);
177  free(trans_list);
178 
179  if (recover_func.getForeignXIDs())
180  errmsg_printf(error::WARN,
181  _("Found %d prepared XA transactions"),
182  recover_func.getForeignXIDs());
183 
184  if (dry_run && recover_func.getMyXIDs())
185  {
186  errmsg_printf(error::ERROR,
187  _("Found %d prepared transactions! It means that drizzled "
188  "was not shut down properly last time and critical "
189  "recovery information was "
190  "manually deleted after a crash. "
191  "This should never happen."),
192  recover_func.getMyXIDs());
193  return 1;
194  }
195 
196  if (commit_list.size())
197  errmsg_printf(error::INFO, _("Crash recovery finished."));
198 
199  return 0;
200 }
201 
202 bool XaResourceManager::addPlugin(XaResourceManager *resource_manager)
203 {
204  xa_resource_managers.push_back(resource_manager);
205  return false;
206 }
207 
208 void XaResourceManager::removePlugin(XaResourceManager *)
209 {
210  xa_resource_managers.clear();
211 }
212 
213 } /* namespace plugin */
214 } /* namespace drizzled */