transactd 3.4.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CMakeLists.txt +2 -2
  3. data/bin/common/tdclc_32_3_5.dll +0 -0
  4. data/bin/common/tdclc_64_3_5.dll +0 -0
  5. data/build/common/options.cmake +12 -0
  6. data/build/common/transactd_cl_common.cmake +1 -0
  7. data/build/common/transactd_required.cmake +5 -0
  8. data/build/swig/ruby/tdclrb_wrap.cpp +1029 -130
  9. data/build/swig/tdcl.i +60 -5
  10. data/build/tdclc/CMakeLists.txt +30 -32
  11. data/build/tdclc/libtdclcm.map +1 -1
  12. data/build/tdclc/tdclc.cbproj +1 -1
  13. data/build/tdclc/tdclc.rc +4 -4
  14. data/build/tdclcpp/CMakeLists.txt +39 -48
  15. data/build/tdclcpp/tdclcpp.rc +4 -4
  16. data/build/tdclcpp/tdclcpp_bc.cbproj +4 -1
  17. data/build/tdclrb/CMakeLists.txt +5 -4
  18. data/build/tdclrb/tdclrb.rc +4 -4
  19. data/source/bzs/db/engine/mysql/database.cpp +45 -35
  20. data/source/bzs/db/engine/mysql/database.h +6 -8
  21. data/source/bzs/db/engine/mysql/dbManager.cpp +11 -0
  22. data/source/bzs/db/engine/mysql/dbManager.h +1 -0
  23. data/source/bzs/db/engine/mysql/ha.cpp +174 -0
  24. data/source/bzs/db/engine/mysql/ha.h +50 -0
  25. data/source/bzs/db/engine/mysql/mysqlInternal.h +18 -1
  26. data/source/bzs/db/engine/mysql/mysqlProtocol.cpp +222 -9
  27. data/source/bzs/db/engine/mysql/mysqlProtocol.h +5 -0
  28. data/source/bzs/db/protocol/tdap/client/client.cpp +23 -9
  29. data/source/bzs/db/protocol/tdap/client/client.h +125 -94
  30. data/source/bzs/db/protocol/tdap/client/connMgr.cpp +139 -30
  31. data/source/bzs/db/protocol/tdap/client/connMgr.h +40 -8
  32. data/source/bzs/db/protocol/tdap/client/database.cpp +17 -17
  33. data/source/bzs/db/protocol/tdap/client/database.h +15 -0
  34. data/source/bzs/db/protocol/tdap/client/dllmain.cpp +10 -4
  35. data/source/bzs/db/protocol/tdap/client/haNameResolver.cpp +486 -0
  36. data/source/bzs/db/protocol/tdap/client/haNameResolver.h +74 -0
  37. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +102 -71
  38. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +15 -3
  39. data/source/bzs/db/protocol/tdap/client/nsTable.cpp +2 -5
  40. data/source/bzs/db/protocol/tdap/client/nsTable.h +2 -1
  41. data/source/bzs/db/protocol/tdap/client/sqlBuilder.cpp +2 -2
  42. data/source/bzs/db/protocol/tdap/client/table.cpp +1 -2
  43. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +13 -0
  44. data/source/bzs/db/protocol/tdap/client/trnsctcl.def +1 -0
  45. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.cpp +9 -7
  46. data/source/bzs/db/protocol/tdap/mysql/recordsetReader.h +2 -2
  47. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +328 -117
  48. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.h +7 -8
  49. data/source/bzs/db/protocol/tdap/tdapcapi.h +81 -41
  50. data/source/bzs/db/transactd/connManager.cpp +118 -93
  51. data/source/bzs/db/transactd/connManager.h +6 -1
  52. data/source/bzs/db/transactd/connectionRecord.h +27 -7
  53. data/source/bzs/db/transactd/transactd.cpp +24 -13
  54. data/source/bzs/env/crosscompile.h +2 -0
  55. data/source/bzs/netsvc/client/iconnection.h +2 -0
  56. data/source/bzs/netsvc/client/tcpClient.cpp +45 -14
  57. data/source/bzs/netsvc/client/tcpClient.h +21 -4
  58. data/source/bzs/netsvc/server/IAppModule.h +1 -0
  59. data/source/bzs/netsvc/server/serverCpt.cpp +1 -1
  60. data/source/bzs/netsvc/server/serverPipe.cpp +2 -0
  61. data/source/bzs/netsvc/server/serverTpool.cpp +3 -5
  62. data/source/bzs/test/tdclatl/test_v3.js +91 -3
  63. data/source/bzs/test/tdclphp/transactd_v3_Test.php +89 -3
  64. data/source/bzs/test/tdclrb/transactd_v3_spec.rb +69 -2
  65. data/source/bzs/test/trdclengn/testField.h +19 -1
  66. data/source/bzs/test/trdclengn/test_tdclcpp_ha.cpp +388 -0
  67. data/source/bzs/test/trdclengn/test_tdclcpp_v3.cpp +6 -1
  68. data/source/bzs/test/trdclengn/test_trdclengn.cpp +1 -0
  69. data/source/bzs/test/trdclengn/testbase.h +7 -1
  70. data/source/global/replication/haCommand.cpp +843 -0
  71. data/source/global/replication/haCommand.h +78 -0
  72. data/source/global/replication/haMgr.cpp +321 -0
  73. data/source/global/replication/replCommand.cpp +696 -0
  74. data/source/global/replication/replCommand.h +161 -0
  75. data/source/global/tdclatl/BinlogPos.cpp +10 -0
  76. data/source/global/tdclatl/BinlogPos.h +1 -0
  77. data/source/global/tdclatl/ConnMgr.cpp +89 -2
  78. data/source/global/tdclatl/ConnMgr.h +13 -1
  79. data/source/global/tdclatl/ConnRecord.cpp +8 -2
  80. data/source/global/tdclatl/ConnRecord.h +4 -3
  81. data/source/global/tdclatl/Database.cpp +13 -0
  82. data/source/global/tdclatl/Database.h +2 -0
  83. data/source/global/tdclatl/HaNameREsolver.cpp +54 -0
  84. data/source/global/tdclatl/HaNameREsolver.h +68 -0
  85. data/source/global/tdclatl/resource.h +0 -0
  86. data/source/global/tdclatl/tdclatl.idl +76 -5
  87. metadata +16 -6
  88. data/bin/common/tdclc_32_3_4.dll +0 -0
  89. data/bin/common/tdclc_64_3_4.dll +0 -0
  90. data/source/bzs/db/protocol/tdap/mysql/debuglog.cpp +0 -423
  91. data/source/bzs/db/protocol/tdap/mysql/debuglog.h +0 -116
@@ -20,6 +20,8 @@
20
20
  #include "testField.h"
21
21
  #include <bzs/db/protocol/tdap/fieldComp.h>
22
22
 
23
+ void init_commandLine(char* argv){};
24
+
23
25
  class fixture
24
26
  {
25
27
  mutable database* m_db;
@@ -1056,11 +1058,14 @@ BOOST_AUTO_TEST_SUITE_END()
1056
1058
  BOOST_AUTO_TEST_SUITE(tablelist)
1057
1059
  BOOST_AUTO_TEST_CASE(tablelist)
1058
1060
  {
1059
- testTableList();
1061
+ testConnMgr();
1060
1062
  }
1061
1063
  BOOST_AUTO_TEST_CASE(createInfo)
1062
1064
  {
1063
1065
  testCreateInfo();
1064
1066
  }
1065
1067
  BOOST_AUTO_TEST_SUITE_END()
1068
+
1069
+
1070
+
1066
1071
  // ------------------------------------------------------------------------
@@ -22,6 +22,7 @@
22
22
 
23
23
  static const short fdi_id = 0;
24
24
  static const short fdi_name = 1;
25
+ void init_commandLine(char* argv){};
25
26
 
26
27
  class fixture
27
28
  {
@@ -77,6 +77,9 @@ static bool use_mysqlNullMode = true;
77
77
 
78
78
  boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]);
79
79
 
80
+ void init_commandLine(char* argv);
81
+
82
+
80
83
  boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[])
81
84
  {
82
85
  for (int i = 1; i < argc; ++i)
@@ -115,7 +118,10 @@ boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[])
115
118
  if (strstr(argv[i], "--nullfield=") == argv[i])
116
119
  use_nullfield = atol(argv[i] + 12) != 0;
117
120
  if (strstr(argv[i], "--mysqlnull=") == argv[i])
118
- use_mysqlNullMode = atol(argv[i] + 12) != 0;
121
+ use_mysqlNullMode = atol(argv[i] + 12) != 0;
122
+
123
+ init_commandLine(argv[i]);
124
+
119
125
  }
120
126
  printf("Transactd test ... \nMay look like progress is stopped, \n"
121
127
  "but it is such as record lock test, please wait.\n");
@@ -0,0 +1,843 @@
1
+ /*=================================================================
2
+ Copyright (C) 2016 BizStation Corp All rights reserved.
3
+
4
+ This program is free software; you can redistribute it and/or
5
+ modify it under the terms of the GNU General Public License
6
+ as published by the Free Software Foundation; either version 2
7
+ of the License, or (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17
+ 02111-1307, USA.
18
+ =================================================================*/
19
+ #pragma hdrstop
20
+ #include "haCommand.h"
21
+ #include <vector>
22
+ #include <algorithm>
23
+ #pragma package(smart_init)
24
+
25
+ using namespace std;
26
+ using namespace bzs::db::protocol::tdap;
27
+ using namespace bzs::db::protocol::tdap::client;
28
+
29
+ #define SLAVES_SIZE 4096
30
+
31
+ void split(vector<_tstring>& ss, const _TCHAR* s)
32
+ {
33
+ const _TCHAR* p = s;
34
+ const _TCHAR* pp = _tcschr(p, _T(','));
35
+ while (pp)
36
+ {
37
+ ss.push_back(_tstring(p, pp));
38
+ p = pp + 1;
39
+ pp = _tcschr(p, _T(','));
40
+ }
41
+ size_t len = _tcslen(p);
42
+ if (len)
43
+ ss.push_back(_tstring(p, p + len));
44
+ }
45
+
46
+ #ifdef _UNICODE
47
+ inline void notify(haNotify* nf, int status, const wchar_t* msg)
48
+ {
49
+ if (nf) nf->onUpdateStaus(status, msg);
50
+ }
51
+ inline void notify(haNotify* nf, int status, const char* msg)
52
+ {
53
+ if (nf)
54
+ {
55
+ wchar_t wbuf[1024];
56
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, msg, -1, wbuf, 1024);
57
+ nf->onUpdateStaus(status, wbuf);
58
+ }
59
+ }
60
+ #else
61
+ inline void notify(haNotify* nf, int status, const char* msg)
62
+ {
63
+ if (nf) nf->onUpdateStaus(status, msg);
64
+ }
65
+ #endif
66
+ inline void notify(haNotify* nf, int status, binlogPos& bpos)
67
+ {
68
+ if (nf)
69
+ {
70
+ char buf[2048];
71
+ sprintf_s(buf, 1024, "%s:%llu %s",bpos.filename, bpos.pos, bpos.gtid);
72
+ notify(nf, status, buf);
73
+ }
74
+ }
75
+
76
+ inline void nfSetHostName(haNotify* nf, const _TCHAR* host)
77
+ {
78
+ if (nf) nf->setHostName(host);
79
+ }
80
+
81
+ database_ptr createDb(const _TCHAR* host, const _TCHAR* user, const _TCHAR* passwd, bool newConnection)
82
+ {
83
+ connectParams cp(_T("tdap"), host, _T("mysql"),
84
+ NULL, user, passwd);
85
+ database_ptr db = createDatabaseObject();
86
+ if (db->connect(cp.uri(), newConnection))
87
+ db->open(cp.uri(), cp.type(), cp.mode());
88
+ return db;
89
+ }
90
+
91
+ connMgr_ptr getMasterMgr(database_ptr db, const node& nd)
92
+ {
93
+ connMgr_ptr mgr = createConnMgr(db.get());
94
+ connectParams cp(_T("tdap"), nd.host.c_str(),
95
+ _T(""), NULL, nd.user.c_str(), nd.passwd.c_str());
96
+ mgr->connect(cp.uri());
97
+ validateStatus(mgr, _T("getMasterMgr"));
98
+ return mgr;
99
+ }
100
+
101
+ _TCHAR* getHost(_TCHAR* hostStatus)
102
+ {
103
+ _TCHAR* p = _tcschr(hostStatus, _T('\t'));
104
+ if (p) *p = 0x00;
105
+ return hostStatus;
106
+ }
107
+
108
+ _TCHAR* slaveList(connMgr_ptr& mgr, _TCHAR* slaves)
109
+ { // auto listup slave hosts from masetr
110
+
111
+ const connMgr::records& recs = mgr->slaveHosts();
112
+ validateStatus(mgr, _T("slaveHost"));
113
+ _TCHAR tmp[MAX_PATH];
114
+ if (recs.size())
115
+ _tcscpy_s(slaves, SLAVES_SIZE, getHost((_TCHAR*)recs[0].value(tmp, MAX_PATH)));
116
+ for (size_t i = 1; i < recs.size(); ++i)
117
+ {
118
+ _tcscat_s(slaves, SLAVES_SIZE, _T(","));
119
+ _tcscat_s(slaves, SLAVES_SIZE, getHost((_TCHAR*)recs[i].value(tmp, MAX_PATH)));
120
+ }
121
+ return slaves;
122
+ }
123
+
124
+ int readHaVar(connMgr_ptr& mgr)
125
+ {
126
+ const connMgr::records& recs = mgr->statusvars();
127
+ int ha = HA_ROLE_SLAVE;
128
+ if (recs.size() > TD_SVAR_HA)
129
+ ha = (int)recs[TD_SVAR_HA].longValue;
130
+ return ha;
131
+ }
132
+
133
+ bool isEnableFailOver(int ha)
134
+ {
135
+ return (ha & HA_ENABLE_FAILOVER) == HA_ENABLE_FAILOVER;
136
+ }
137
+
138
+ bool isRoleMaster(int ha)
139
+ {
140
+ return (ha & HA_ROLE_MASTER) == HA_ROLE_MASTER;
141
+ }
142
+
143
+ bool isRoleMaster(connMgr_ptr& mgr)
144
+ {
145
+ return isRoleMaster(readHaVar(mgr));
146
+ }
147
+
148
+ void makeSlaveList(const failOverParam& pm, bool* roleMaster=NULL)
149
+ {
150
+ database_ptr db = createDatabaseObject();
151
+ connMgr_ptr mgr = getMasterMgr(db, pm.master);
152
+
153
+ _TCHAR slaves[SLAVES_SIZE] = {0};
154
+ slaveList(mgr, slaves);
155
+ pm.slaves = slaves;
156
+ if (roleMaster)
157
+ *roleMaster = isRoleMaster(mgr);
158
+ mgr.reset();
159
+ }
160
+
161
+ void getBinlogPos(connMgr_ptr mgr, binlogPos& bpos)
162
+ {
163
+ const connMgr::records& rs = mgr->extendedvars();
164
+ validateStatus(mgr, _T("extendedvars"));
165
+ if (rs.size() > TD_EXTENDED_VAR_BINLOG_GTID)
166
+ {
167
+ strcpy_s(bpos.filename, BINLOGNAME_SIZE, rs[TD_EXTENDED_VAR_BINLOG_FILE].name);
168
+ bpos.pos = (unsigned int)rs[TD_EXTENDED_VAR_BINLOG_POS].longValue;
169
+ bpos.setGtid(rs[TD_EXTENDED_VAR_BINLOG_GTID].value_ptr());
170
+ }
171
+ }
172
+
173
+ bool isMariadb(database_ptr db)
174
+ {
175
+ btrVersions vers;
176
+ db->getBtrVersion(&vers);
177
+ validateStatus(db, _T("isMariadb"));
178
+ btrVersion ver = vers.versions[VER_IDX_DB_SERVER];
179
+ return ver.isMariaDB();
180
+ }
181
+
182
+ string getChannlName(connMgr_ptr mgr, const _TCHAR* oldMaster)
183
+ {
184
+ connRecords_ptr recs_p = createConnRecords(mgr->channels());
185
+ connMgr::records& recs = *recs_p.get();
186
+
187
+ for (size_t i = 0;i < recs.size(); ++i)
188
+ {
189
+ const connMgr::records& rs = mgr->slaveStatus(recs[i].name);
190
+ if (rs.size() > SLAVE_STATUS_MASTER_HOST)
191
+ {
192
+ _TCHAR buf[MAX_PATH];
193
+ if (_tcsicmp(rs[SLAVE_STATUS_MASTER_HOST].value(buf, MAX_PATH), oldMaster) == 0)
194
+ return recs[i].name;
195
+ }
196
+ }
197
+ return "";
198
+ }
199
+
200
+ void changeMaster(const node& nd, const masterNode& master, database_ptr db,
201
+ connMgr_ptr mgr, binlogPos* bpos, haNotify* nf)
202
+ {
203
+ _TCHAR host[MAX_PATH];
204
+ _TCHAR port[20];
205
+ endPoint(db->uri(), host, MAX_PATH, port, 20);
206
+ if (port[0])
207
+ {
208
+ _tcscat_s(host, MAX_PATH -_tcslen(host), _T(":"));
209
+ _tcscat_s(host, MAX_PATH -_tcslen(host), port);
210
+ }
211
+
212
+ replicationParam pm;
213
+ pm.master = master;
214
+ pm.type = isMariadb(db) ? REP_TYPE_GTID_MA : REP_TYPE_GTID_MY;
215
+ pm.master.channel = getChannlName(mgr, nd.host.c_str());
216
+
217
+ nfSetHostName(nf, host);
218
+ notify(nf, HA_NF_CANNELNAME, pm.master.channel.c_str());
219
+ replSlave rpl(db, pm, mgr.get());
220
+ rpl.stop(all);
221
+ notify(nf, HA_SLAVE_STOP_ALL, _T(""));
222
+ if (bpos)
223
+ {
224
+ rpl.changeMaster(bpos);
225
+ notify(nf, HA_CHANGE_MASTER, bpos->gtid);
226
+ }
227
+ else
228
+ {
229
+ rpl.switchMaster(replSlave::slave_pos);
230
+ notify(nf, HA_SWITCH_MASTER, "slave_pos");
231
+ }
232
+ rpl.start();
233
+ notify(nf, HA_SLAVE_START, _T(""));
234
+ }
235
+
236
+ connMgr_ptr createMgr(database_ptr db, const _TCHAR* host, const node& nd, bool throwError)
237
+ {
238
+ connectParams cp(_T("tdap"), host, _T(""), NULL,
239
+ nd.user.c_str(), nd.passwd.c_str());
240
+
241
+ connMgr_ptr mgr = createConnMgr(db.get());
242
+ if (!mgr->connect(cp.uri()))
243
+ {
244
+ if (throwError)
245
+ validateStatus(mgr, _T("connMgr connect"));
246
+ }
247
+ return mgr;
248
+ }
249
+
250
+ class safeHaSalves
251
+ {
252
+ vector<connMgr_ptr> m_mgrs;
253
+ vector<_tstring>& m_slaves;
254
+ vector<database_ptr> m_dbs;
255
+ const string& m_channel;
256
+ const node& m_nd;
257
+ haNotify* m_nf;
258
+ size_t m_lockSize;
259
+ bool m_isSwitchOver;
260
+ bool m_isDisableOldMasterToSalve;
261
+ bool m_oldMasterRoleChanged;
262
+ bool m_newMasterRoleChanged;
263
+
264
+ void addMgr(const _TCHAR* host)
265
+ {
266
+ database_ptr db = createDatabaseObject();
267
+ m_dbs.push_back(db);
268
+ m_mgrs.push_back(createMgr(db, host, m_nd, m_isSwitchOver));
269
+ }
270
+
271
+ void createMgrList()
272
+ {
273
+ for (size_t i= 0; i< m_slaves.size(); ++i)
274
+ addMgr(m_slaves[i].c_str());
275
+ }
276
+
277
+ void addDbs(vector<database_ptr>& dbs, const _TCHAR* host, bool newConnection)
278
+ {
279
+ database_ptr db = createDb(host, m_nd.user.c_str(), m_nd.passwd.c_str(), newConnection);
280
+ if (m_isSwitchOver)
281
+ validateStatus(db, _T("database connect open"));
282
+ dbs.push_back(db);
283
+ }
284
+
285
+ void createDbList(vector<database_ptr>& dbs)
286
+ {
287
+ for (size_t i= 0; i< m_slaves.size(); ++i)
288
+ addDbs(dbs, m_slaves[i].c_str(), false);
289
+ }
290
+
291
+ void doChangeMaster(const masterNode& master, database_ptr db,
292
+ connMgr_ptr mgr, binlogPos* bpos)
293
+ {
294
+ ::changeMaster(m_nd, master, db, mgr, bpos, m_nf);
295
+ }
296
+
297
+ void setMasterRoleStatus(connMgr_ptr mgr)
298
+ {
299
+ mgr->setRole(HA_ROLE_MASTER);
300
+ validateStatus(mgr, _T("setRole"));
301
+ m_newMasterRoleChanged = true;
302
+ if (!m_isSwitchOver || m_isDisableOldMasterToSalve)
303
+ m_oldMasterRoleChanged = true;
304
+ }
305
+
306
+ void promoteMaster(const masterNode& master, database_ptr db, connMgr_ptr mgr,
307
+ binlogPos* bpos, bool readOnlyControl)
308
+ {
309
+ replicationParam pm;
310
+ pm.master = master;
311
+ pm.type = isMariadb(db) ? REP_TYPE_GTID_MA : REP_TYPE_GTID_MY;
312
+ if (m_isSwitchOver)
313
+ {
314
+ pm.master.channel = getChannlName(mgr, m_nd.host.c_str());
315
+ const_cast<masterNode&>(master).channel = pm.master.channel;
316
+ }
317
+ else
318
+ pm.master.channel = m_channel;
319
+
320
+ nfSetHostName(m_nf, master.host.c_str());
321
+ notify(m_nf, HA_NF_PROMOTE_MASTER, _T(""));
322
+ notify(m_nf, HA_NF_PROMOTE_CHANNEL, m_channel.c_str());
323
+
324
+ replSlave rpl(db, pm, mgr.get());
325
+
326
+ rpl.stop(one);
327
+ setMasterRoleStatus(mgr);
328
+ notify(m_nf, HA_NF_ROLE_MASTER, _T(""));
329
+ if (bpos)
330
+ { // Sync SQLthread binlog pos to old master
331
+ rpl.startUntil(*bpos);
332
+ notify(m_nf, HA_NF_WAIT_POS_START, _T(""));
333
+ rpl.waitForSlaveSync(*bpos, 2, NULL);
334
+ notify(m_nf, HA_NF_WAIT_POS_COMP, *bpos);
335
+
336
+ rpl.stop(one);
337
+ notify(m_nf, HA_SLAVE_STOP, _T(""));
338
+ }
339
+ rpl.resetAll(); // reset only this channel
340
+ if (readOnlyControl)
341
+ {
342
+ db->execSql("set global read_only=OFF");
343
+ validateStatus(db, _T("read_only off"));
344
+ notify(m_nf, HA_SET_READ_ONLY, _T(""));
345
+ }
346
+ }
347
+
348
+ public:
349
+
350
+ safeHaSalves(vector<_tstring>& slaves, const failOverParam& pm, haNotify* nf) :
351
+ m_slaves(slaves), m_channel(pm.newMaster.channel),
352
+ m_nd(pm.master), m_nf(nf), m_lockSize(0),
353
+ m_isSwitchOver(pm.isSwitchOver()),
354
+ m_isDisableOldMasterToSalve(pm.isDisableOldMasterToSalve()),
355
+ m_oldMasterRoleChanged(false),
356
+ m_newMasterRoleChanged(false)
357
+ {
358
+ createMgrList();
359
+ }
360
+
361
+ void lock()
362
+ {
363
+ m_lockSize = m_mgrs.size();
364
+ for (size_t i = 0; i < m_lockSize; ++i)
365
+ {
366
+ if (m_mgrs[i]->isOpen())
367
+ {
368
+ m_mgrs[i]->haLock();
369
+ validateStatus(m_mgrs[i], _T("haLock"));
370
+ }
371
+ }
372
+ }
373
+
374
+ int selectPromoteHost()
375
+ {
376
+ string fname;
377
+ unsigned int pos = 0;
378
+ int index = -1;
379
+ for (int i = 0; i < (int)m_mgrs.size(); ++i)
380
+ {
381
+ if (m_mgrs[i]->isOpen())
382
+ {
383
+ const connMgr::records& rss = m_mgrs[i]->statusvars();
384
+ if (rss.size() > TD_SVAR_HA)
385
+ {
386
+ int ha = (int)rss[TD_SVAR_HA].longValue;
387
+ if ((ha & HA_ENABLE_FAILOVER) != HA_ENABLE_FAILOVER)
388
+ return -2;
389
+ }
390
+ const connMgr::records& rs = m_mgrs[i]->slaveStatus(m_channel.c_str());
391
+ if (m_mgrs[i]->stat() == 0)
392
+ {
393
+ string tmp = rs[SLAVE_STATUS_MASTER_LOG_FILE].name;
394
+ unsigned int tmpPos = (unsigned int)rs[SLAVE_STATUS_EXEC_MASTER_LOG_POS].longValue;
395
+ if (tmp > fname)
396
+ {
397
+ fname = tmp;
398
+ pos = tmpPos;
399
+ index = i;
400
+ }else if(tmp == fname)
401
+ {
402
+ if (tmpPos > pos)
403
+ {
404
+ pos = tmpPos;
405
+ index = i;
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ return index;
412
+ }
413
+
414
+ void changeMaster(const masterNode& master, size_t newMasterIndex, binlogPos* bpos,
415
+ bool readOnlyControl )
416
+ {
417
+ vector<database_ptr> dbs;
418
+ createDbList(dbs);
419
+ if (dbs.size() == 0) return;
420
+ // First promote new master
421
+ promoteMaster(master, dbs[newMasterIndex],
422
+ m_mgrs[newMasterIndex], bpos, readOnlyControl);
423
+ if (m_isSwitchOver && !m_isDisableOldMasterToSalve)
424
+ {
425
+ // The old master change to slave.
426
+ addMgr(m_nd.host.c_str()); //Append old master.
427
+ vector<connMgr_ptr>::iterator itmgr = m_mgrs.end() -1;
428
+ database_ptr db = createDb(m_nd.host.c_str(), m_nd.user.c_str(), m_nd.passwd.c_str(), true);
429
+ doChangeMaster(master, db, *itmgr, bpos);
430
+ }
431
+
432
+ //Slaves change master.
433
+ for (size_t i = 0; i < dbs.size(); ++i)
434
+ {
435
+ if (i != newMasterIndex && dbs[i]->isOpened())
436
+ doChangeMaster(master, dbs[i], m_mgrs[i], NULL);
437
+ }
438
+ }
439
+
440
+ void setEnableFailOver(bool v)
441
+ {
442
+ for (size_t i = 0; i < m_mgrs.size(); ++i)
443
+ {
444
+ if (m_mgrs[i]->isOpen())
445
+ {
446
+ m_mgrs[i]->setEnableFailover(v);
447
+ validateStatus(m_mgrs[i], _T("setEnableFailOver"));
448
+ }
449
+ }
450
+ }
451
+
452
+ connMgr_ptr mgr(size_t index) { return m_mgrs[index];}
453
+
454
+ void setOldMasterRoleChanged() {m_oldMasterRoleChanged = true;}
455
+
456
+ void recoverMasterRole()
457
+ {
458
+ try
459
+ {
460
+ if (m_newMasterRoleChanged != m_oldMasterRoleChanged)
461
+ {
462
+ database_ptr db = createDatabaseObject();
463
+ connMgr_ptr mgr = createMgr(db, m_nd.host.c_str(), m_nd, m_isSwitchOver);
464
+ mgr->setRole(HA_ROLE_MASTER);
465
+ mgr.reset();
466
+ }
467
+ }
468
+ catch(...){}
469
+ }
470
+
471
+ void unlock()
472
+ {
473
+ if (m_lockSize)
474
+ {
475
+ for (int i = (int)m_lockSize - 1; i >= 0 ; --i)
476
+ {
477
+ if (m_mgrs[i]->isOpen())
478
+ m_mgrs[i]->haUnlock();
479
+ }
480
+ m_lockSize = 0;
481
+ }
482
+ }
483
+
484
+ ~safeHaSalves()
485
+ {
486
+ unlock();
487
+ recoverMasterRole();
488
+ m_mgrs.clear();
489
+ }
490
+ };
491
+
492
+ class masterControl
493
+ {
494
+ database_ptr m_db;
495
+ connMgr_ptr m_mgr;
496
+ const node& m_nd;
497
+ bool m_locked;
498
+
499
+ void trxLock()
500
+ {
501
+ m_mgr->setTrxBlock(true);
502
+ validateStatus(m_mgr, _T("Master trx lock"));
503
+ m_locked = true;
504
+ }
505
+
506
+ void trxUnlock()
507
+ {
508
+ if (m_locked)
509
+ m_mgr->setTrxBlock(false);
510
+ m_locked = false;
511
+ }
512
+
513
+ public:
514
+ masterControl(const node& nd) : m_nd(nd), m_locked(false)
515
+ {
516
+ m_db = createDatabaseObject();
517
+ m_mgr = getMasterMgr(m_db, nd);
518
+ }
519
+
520
+ ~masterControl()
521
+ {
522
+ trxUnlock();
523
+ m_mgr.reset();
524
+ }
525
+
526
+ void waitForFinishTrx(binlogPos& bpos)
527
+ {
528
+ trxLock();
529
+ bool cancel = false;
530
+ int trx_count;
531
+ size_t use_db_count;
532
+ //connMgr::records recs;
533
+ connRecords_ptr recs_p = createConnRecords();
534
+ connMgr::records& recs = *recs_p.get();
535
+ do
536
+ {
537
+ trx_count = 0;
538
+ use_db_count = 0;
539
+ recs = m_mgr->connections();
540
+ for (size_t i = 0; i < recs.size(); ++i)
541
+ {
542
+ Sleep(1);
543
+ int trx_per_connection = 0;
544
+ size_t use_db_per_connection = 0;
545
+ const connMgr::records& rs = m_mgr->inUseDatabases(recs[i].conId);
546
+ for (size_t j = 0 ;j < rs.size(); ++j)
547
+ {
548
+ trx_per_connection += rs[j].inTransaction;
549
+ trx_count += trx_per_connection;
550
+ }
551
+ use_db_count += rs.size();
552
+ use_db_per_connection = rs.size();
553
+ // Killing connection that using database and no transactions.
554
+ if (trx_per_connection == 0 && use_db_per_connection)
555
+ m_mgr->postDisconnectOne(recs[i].conId);
556
+ }
557
+ }while ((trx_count != 0 || use_db_count != 0) && !cancel);
558
+
559
+ getBinlogPos(m_mgr, bpos);
560
+
561
+ trxUnlock();
562
+ }
563
+
564
+ bool setRole(int v)
565
+ {
566
+ m_mgr->setRole(v);
567
+ validateStatus(m_mgr, _T("setRole"));
568
+ return true;
569
+ }
570
+ };
571
+
572
+ class masterReadOnly
573
+ {
574
+ database_ptr m_db;
575
+ public:
576
+ masterReadOnly(const node& nd, bool toReadOnly)
577
+ {
578
+ if (toReadOnly)
579
+ {
580
+ m_db = createDb(nd.host.c_str(), nd.user.c_str(), nd.passwd.c_str(), true);
581
+ //db->execSql("flush tables with read lock");
582
+ //validateStatus(db, _T("flush tables"));
583
+ m_db->execSql("set global read_only=ON");
584
+ validateStatus(m_db, _T("read_only ON"));
585
+ }
586
+ }
587
+ void check()
588
+ {
589
+ m_db.reset();
590
+ }
591
+ ~masterReadOnly()
592
+ {
593
+ if (m_db)
594
+ m_db->execSql("set global read_only=OFF");
595
+ }
596
+ };
597
+
598
+ string getNewMasterPort(const string& host, const string& map)
599
+ {
600
+ char tmp[MAX_PATH];
601
+ char* p;
602
+ strcpy_s(tmp, sizeof(tmp), host.c_str());
603
+ p = strchr(tmp, ':');
604
+ if (p)
605
+ {
606
+ ++p;
607
+ strcat_s(p, sizeof(tmp) - (p - tmp), ":");
608
+ size_t pos = map.find(p);
609
+ if (pos != string::npos)
610
+ {
611
+ int n = atol(map.c_str() + pos + strlen(p));
612
+ _ltoa_s(n, tmp, sizeof(tmp), 10);
613
+ return tmp;
614
+ }
615
+ }
616
+ return "3306";
617
+ }
618
+
619
+ void doSwitchOrver(const failOverParam& pm, haNotify* nf)
620
+ {
621
+ vector<_tstring> slaves;
622
+ slaves.reserve(10);
623
+ overrideCompatibleMode cpblMode(database::CMP_MODE_MYSQL_NULL);
624
+ size_t newMasterIndex;
625
+ if (pm.slaves == _T(""))
626
+ THROW_BZS_ERROR_WITH_MSG(_T("No slave host(s)."));
627
+ split(slaves, pm.slaves.c_str());
628
+ if (pm.isSwitchOver())
629
+ {
630
+ vector<_tstring>::iterator it = find(slaves.begin(), slaves.end(), pm.newMaster.host);
631
+ newMasterIndex = it - slaves.begin();
632
+ }
633
+ binlogPos* bpos_ptr = NULL;
634
+ binlogPos bpos;
635
+ bool readOnlyControl = (pm.option & OPT_READONLY_CONTROL) != 0;
636
+
637
+ nfSetHostName(nf, _T(""));
638
+ notify(nf, HA_NF_SLAVE_LIST, pm.slaves.c_str());
639
+ safeHaSalves slvs(slaves, pm, nf);
640
+ slvs.lock();
641
+ if (pm.isSwitchOver())
642
+ {
643
+ masterReadOnly read_only(pm.master, readOnlyControl);
644
+ {
645
+ masterControl oldMaster(pm.master);
646
+ // block new connection to old master
647
+ if (oldMaster.setRole(HA_ROLE_SLAVE))
648
+ {
649
+ slvs.setOldMasterRoleChanged();
650
+ nfSetHostName(nf, pm.master.host.c_str());
651
+ notify(nf, HA_NF_ROLE_SLAVE, _T(""));
652
+ }
653
+ // wait for current transaction
654
+ notify(nf, HA_NF_WAIT_TRX_START, _T(""));
655
+ oldMaster.waitForFinishTrx(bpos);
656
+ notify(nf, HA_NF_WAIT_TRX_COMP, bpos);
657
+ bpos_ptr = &bpos;
658
+ // release master trx lock
659
+ }
660
+ read_only.check();
661
+ }else if (pm.isFailOver())
662
+ {
663
+ int index = slvs.selectPromoteHost();
664
+ if (index < 0 || index >= (int)slaves.size())
665
+ {
666
+ if (index == -2)
667
+ THROW_BZS_ERROR_WITH_MSG(_T("Failover is disabled."));
668
+ else
669
+ THROW_BZS_ERROR_WITH_MSG(_T("Invalid new Master."));
670
+ }
671
+ newMasterIndex = (size_t)index;
672
+ failOverParam& mp = const_cast<failOverParam&>(pm);
673
+ mp.newMaster.host = slaves[newMasterIndex];
674
+ mp.newMaster.repPort = getNewMasterPort(toUtf8(pm.newMaster.host), pm.portMap);
675
+ }
676
+ slvs.changeMaster(pm.newMaster, newMasterIndex, bpos_ptr, readOnlyControl);
677
+ }
678
+
679
+ void failOrver(const failOverParam& pm, haNotify* nf)
680
+ {
681
+ pm.option |= OPT_FO_FAILOVER;
682
+ pm.option &= ~OPT_SO_AUTO_SLVAE_LIST;
683
+ doSwitchOrver(pm, nf);
684
+ }
685
+
686
+ void switchOrver(const failOverParam& pm, haNotify* nf)
687
+ {
688
+ if (pm.option & OPT_SO_AUTO_SLVAE_LIST)
689
+ makeSlaveList(pm);
690
+ pm.option &= ~OPT_FO_FAILOVER;
691
+ doSwitchOrver(pm, nf);
692
+ }
693
+
694
+ void demoteToSlave(const failOverParam& pm, haNotify* nf)
695
+ {
696
+ overrideCompatibleMode cpblMode(database::CMP_MODE_MYSQL_NULL);
697
+ database_ptr dbt = createDb(pm.master.host.c_str(), pm.master.user.c_str(),
698
+ pm.master.passwd.c_str(), false);
699
+ nfSetHostName(nf, pm.master.host.c_str());
700
+ database_ptr db = createDatabaseObject();
701
+ connMgr_ptr mgr = getMasterMgr(db, pm.master);
702
+
703
+ mgr->setRole(HA_ROLE_SLAVE);
704
+ validateStatus(mgr, _T("setRoleMaster"));
705
+ notify(nf, HA_NF_ROLE_SLAVE, _T(""));
706
+ changeMaster(pm.master, pm.newMaster, dbt, mgr, NULL, nf);
707
+ mgr.reset();
708
+ }
709
+
710
+ void setEnableFailOver(const failOverParam& pm, bool v)
711
+ {
712
+ if (pm.option & OPT_SO_AUTO_SLVAE_LIST)
713
+ makeSlaveList(pm);
714
+ vector<_tstring> slaves;
715
+ split(slaves, pm.slaves.c_str());
716
+ pm.option &= ~OPT_FO_FAILOVER;
717
+ safeHaSalves slvs(slaves, pm, NULL);
718
+ slvs.setEnableFailOver(v);
719
+ }
720
+
721
+ void setServerRole(const failOverParam& pm, int v)
722
+ {
723
+ masterControl srv(pm.master);
724
+ srv.setRole(v);
725
+ }
726
+
727
+ const _TCHAR* roleName(bool isMaster)
728
+ {
729
+ return isMaster ? _T("Role = Master") : _T("Role = Slave");
730
+ }
731
+
732
+ void notifyBrank(haNotify* nf)
733
+ {
734
+ nfSetHostName(nf, _T(""));
735
+ notify(nf, HA_NF_BLANK, _T(""));
736
+ }
737
+
738
+ bool lockTest(connMgr_ptr mgr, haNotify* nf)
739
+ {
740
+ bool lock = mgr->haLock();
741
+ if (lock)
742
+ mgr->haUnlock();
743
+ notify(nf, lock ? HA_NF_MSG_OK : HA_NF_MSG_NG, "HA lock");
744
+ return lock;
745
+ }
746
+
747
+ int healthCheck(const failOverParam& pm, haNotify* nf)
748
+ {
749
+ int ret = 0;
750
+ overrideCompatibleMode cpblMode(database::CMP_MODE_MYSQL_NULL);
751
+ bool roleMaster;
752
+
753
+ vector<_tstring> slaves_param;
754
+ split(slaves_param, pm.slaves.c_str());
755
+
756
+ makeSlaveList(pm, &roleMaster);
757
+ vector<_tstring> slaves;
758
+ split(slaves, pm.slaves.c_str());
759
+ nfSetHostName(nf, _T(""));
760
+ if (slaves_param.size())
761
+ {
762
+ vector<_tstring> slaves_tmp = slaves;
763
+ if (slaves_param.size() != slaves_tmp.size())
764
+ {
765
+ _TCHAR tmp[256];
766
+ _stprintf_s(tmp, 256 ,_T("slaves count(%u) not equal real slave count(%u)"),
767
+ (unsigned int)slaves_param.size(), (unsigned int)slaves_tmp.size());
768
+ notify(nf, HA_NF_BLANK, tmp);
769
+ ++ret;
770
+ }
771
+ std::sort(slaves_param.begin(), slaves_param.end());
772
+ std::sort(slaves_tmp.begin(), slaves_tmp.end());
773
+ size_t n = min(slaves_param.size(), slaves_tmp.size());
774
+ for (size_t i = 0; i < n; ++i)
775
+ {
776
+ if (slaves_param[i] != slaves_tmp[i])
777
+ {
778
+ _TCHAR tmp[1024];
779
+ _stprintf_s(tmp, 1024 ,_T("Unmatch host name beetween the command line and slaveHosts of master.")
780
+ _T("\n command line=%s : master detect=%s"),
781
+ slaves_param[i].c_str(), slaves_tmp[i].c_str());
782
+ notify(nf, HA_NF_BLANK, tmp);
783
+ ++ret;
784
+ }
785
+ }
786
+ }
787
+
788
+ notify(nf, HA_NF_SLAVE_LIST, pm.slaves.c_str());
789
+ nfSetHostName(nf, pm.master.host.c_str());
790
+ notify(nf, roleMaster ? HA_NF_MSG_OK : HA_NF_MSG_NG, roleName(roleMaster));
791
+ if (!roleMaster) ++ret;
792
+
793
+ { //master lock test
794
+ database_ptr db = createDatabaseObject();
795
+ connMgr_ptr mgr = createMgr(db, pm.master.host.c_str(), pm.master, false);
796
+ if (!lockTest(mgr, nf)) ++ret;
797
+ }
798
+
799
+ for (size_t i=0;i < slaves.size(); ++i)
800
+ {
801
+ database_ptr db = createDatabaseObject();
802
+ connMgr_ptr mgr = createMgr(db, slaves[i].c_str(), pm.master, false);
803
+ notifyBrank(nf);
804
+ nfSetHostName(nf, slaves[i].c_str());
805
+ int ha = readHaVar(mgr);
806
+ roleMaster = isRoleMaster(ha);
807
+ notify(nf, roleMaster ? HA_NF_MSG_NG : HA_NF_MSG_OK, roleName(roleMaster));
808
+ if (roleMaster) ++ret;
809
+
810
+ bool fo = isEnableFailOver(ha);
811
+ notify(nf, fo ? HA_NF_MSG_OK : HA_NF_MSG_NG, fo ? "Failover is enabled" : "Failover is disabled");
812
+ if (!fo) ++ret;
813
+
814
+ if (!lockTest(mgr, nf)) ++ret;
815
+
816
+ string channel = getChannlName(mgr, pm.master.host.c_str());
817
+ notify(nf, HA_NF_CANNELNAME, channel.c_str());
818
+ const connMgr::records& recs = mgr->slaveStatus(channel.c_str());
819
+ if (recs.size() <= SLAVE_STATUS_EXEC_MASTER_LOG_POS)
820
+ {
821
+ notify(nf, HA_NF_MSG_NG, _T("Can not read slave status."));
822
+ ++ret;
823
+ }
824
+ else
825
+ {
826
+ bool sql_run = _stricmp(recs[SLAVE_STATUS_SLAVE_SQL_RUNNING].name, "Yes") == 0;
827
+ bool io_run = _stricmp(recs[SLAVE_STATUS_SLAVE_IO_RUNNING].name, "Yes") == 0;
828
+ notify(nf, sql_run ? HA_NF_MSG_OK : HA_NF_MSG_NG, _T("SQL thread running"));
829
+ notify(nf, sql_run ? HA_NF_MSG_OK : HA_NF_MSG_NG, _T("IO thread running"));
830
+ if (!sql_run) ++ret;
831
+ if (!io_run) ++ret;
832
+ __int64 read_pos = recs[SLAVE_STATUS_READ_MASTER_LOG_POS].longValue;
833
+ __int64 write_pos = recs[SLAVE_STATUS_EXEC_MASTER_LOG_POS].longValue;
834
+ _TCHAR tmp[50];
835
+ _i64tot_s(read_pos - write_pos, tmp, 50, 10);
836
+ notify(nf, HA_NF_DELAY, tmp);
837
+ }
838
+ mgr.reset();
839
+ }
840
+ return ret;
841
+ }
842
+
843
+