ul_db_failover.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* sp-ul_db module
  2. *
  3. * Copyright (C) 2007 1&1 Internet AG
  4. *
  5. * This file is part of Kamailio, a free SIP server.
  6. *
  7. * Kamailio 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; either version 2 of the License, or
  10. * (at your option) any later version
  11. *
  12. * Kamailio is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "ul_db_failover.h"
  22. #include "ul_db_failover_func.h"
  23. #include "ul_db_handle.h"
  24. #include "ul_db.h"
  25. #include "p_usrloc_mod.h"
  26. static ul_db_handle_t spare;
  27. static ul_db_t tmp;
  28. static char query[UL_DB_QUERY_LEN];
  29. static int ul_db_failover_get_spare(db_func_t * dbf, db1_con_t * dbh, ul_db_t * db);
  30. static int ul_db_failover_switch(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no);
  31. static int ul_db_failover_normal(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no);
  32. int db_failover(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no) {
  33. if(failover_level & FAILOVER_MODE_NORMAL){
  34. if(ul_db_failover_normal(dbf, dbh, handle, no) < 0){
  35. LM_ERR("could not switch to spare, try to "
  36. "turn off broken db id %i, db %i.\n",
  37. handle->id, no);
  38. } else {
  39. return 0;
  40. }
  41. }
  42. if(failover_level & (FAILOVER_MODE_NONE | FAILOVER_MODE_NORMAL)){
  43. if(db_failover_deactivate(dbf, dbh, handle, no) < 0){
  44. LM_ERR("could not deactivate "
  45. "id %i, db %i.\n",
  46. handle->id, no);
  47. return -1;
  48. }
  49. }
  50. return 0;
  51. }
  52. static int ul_db_failover_normal(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no){
  53. ul_db_t * db = NULL;
  54. if(ul_db_failover_prepare(dbf, dbh) < 0){
  55. LM_ERR("could not "
  56. "initiate failover transaction, rollback.\n");
  57. ul_db_failover_rollback(dbf, dbh);
  58. return -1;
  59. }
  60. if((db = get_db_by_num(handle, no)) == NULL){
  61. LM_ERR("could not find id %i, "
  62. "db %i.\n", handle->id, no);
  63. ul_db_failover_rollback(dbf, dbh);
  64. return -1;
  65. }
  66. if(ul_db_failover_get_spare(dbf, dbh, db) < 0){
  67. LM_ERR("no spare found. "
  68. "id %i, db %i.\n", handle->id, no);
  69. ul_db_failover_rollback(dbf, dbh);
  70. return -1;
  71. }
  72. if(ul_db_failover_switch(dbf, dbh, handle, no) < 0){
  73. LM_ERR("switch to spare on "
  74. "id %i, db %i.\n", handle->id, no);
  75. ul_db_failover_rollback(dbf, dbh);
  76. return -1;
  77. }
  78. if(ul_db_failover_commit(dbf, dbh) < 0){
  79. LM_ERR("could not "
  80. "commit failover transaction, rollback.\n");
  81. ul_db_failover_rollback(dbf, dbh);
  82. return -1;
  83. }
  84. return 0;
  85. }
  86. static int ul_db_failover_get_spare(db_func_t * dbf, db1_con_t * dbh, ul_db_t * db) {
  87. db1_res_t * res = NULL;
  88. db_row_t * row;
  89. int query_len;
  90. str tmp;
  91. if(!dbf || !dbh || !db) {
  92. LM_ERR("Null pointer as parameter.\n");
  93. return -1;
  94. }
  95. memset(&spare, 0, sizeof(ul_db_handle_t));
  96. memset(query, 0, UL_DB_QUERY_LEN);
  97. query_len = 100
  98. + id_col.len
  99. + num_col.len
  100. + url_col.len
  101. + 2 * risk_group_col.len
  102. + reg_table.len
  103. + spare_col.len
  104. + status_col.len;
  105. if(query_len >= UL_DB_QUERY_LEN){
  106. LM_ERR("weird: extremely long query.\n");
  107. return -1;
  108. }
  109. if (sprintf(query,
  110. "SELECT "
  111. "%.*s, "
  112. "%.*s, "
  113. "%.*s, "
  114. "%.*s "
  115. "FROM %.*s "
  116. "WHERE "
  117. "%.*s=1 AND "
  118. "%.*s!=%i AND "
  119. "%.*s=%i "
  120. "LIMIT 1 "
  121. "FOR UPDATE",
  122. id_col.len, id_col.s,
  123. num_col.len, num_col.s,
  124. url_col.len, url_col.s,
  125. risk_group_col.len, risk_group_col.s,
  126. reg_table.len, reg_table.s,
  127. spare_col.len, spare_col.s,
  128. risk_group_col.len, risk_group_col.s, db->rg,
  129. status_col.len, status_col.s, DB_ON) < 0) {
  130. LM_ERR("could not print query\n");
  131. return -1;
  132. }
  133. tmp.s = query;
  134. tmp.len = strlen(query);
  135. if(dbf->raw_query(dbh, &tmp, &res) < 0) {
  136. LM_ERR("could not query database.\n");
  137. return -1;
  138. }
  139. if(RES_ROW_N(res) == 0) {
  140. LM_ERR("no spare left.\n");
  141. dbf->free_result(dbh, res);
  142. return -1;
  143. }
  144. row = RES_ROWS(res);
  145. spare.id = VAL_INT(ROW_VALUES(row) + 0);
  146. spare.db[0].no = VAL_INT(ROW_VALUES(row) + 1);
  147. if(strlen(VAL_STRING(ROW_VALUES(row) + 2)) >= UL_DB_URL_LEN){
  148. LM_ERR("weird: "
  149. "db URL longer than %i.\n", UL_DB_URL_LEN);
  150. dbf->free_result(dbh, res);
  151. return -1;
  152. }
  153. strcpy(spare.db[0].url.s, VAL_STRING(ROW_VALUES(row) + 2));
  154. spare.db[0].url.len = strlen(spare.db[0].url.s);
  155. spare.db[0].rg = VAL_INT(ROW_VALUES(row) + 3);
  156. dbf->free_result(dbh, res);
  157. return 0;
  158. }
  159. static int ul_db_failover_switch(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no) {
  160. ul_db_t * db;
  161. int check;
  162. int old_num, new_num;
  163. if((db = get_db_by_num(handle, no)) == NULL){
  164. LM_ERR("could not find id %i, "
  165. "db %i.\n", handle->id, no);
  166. return -1;
  167. }
  168. memset(&tmp, 0, sizeof(ul_db_t));
  169. memmove(&tmp, db, sizeof(ul_db_t));
  170. memset(tmp.url.s, 0, UL_DB_URL_LEN);
  171. memmove(tmp.url.s, db->url.s, UL_DB_URL_LEN);
  172. check = check_handle_data(dbf, dbh, db, handle->id);
  173. if(check < 0){
  174. LM_ERR("data check failed.\n");
  175. return -1;
  176. } else if(check > 0){
  177. LM_ERR("failover already done.\n");
  178. return 0;
  179. }
  180. if((new_num = get_max_no_of_db_id(dbf, dbh, spare.id)) < 0){
  181. LM_ERR("getting highest num failed.\n");
  182. return -1;
  183. }
  184. new_num++;
  185. old_num = tmp.no;
  186. tmp.no = new_num;
  187. tmp.status = DB_OFF;
  188. tmp.failover_time = time(NULL);
  189. tmp.spare = 1;
  190. if(store_handle_data(dbf, dbh, &tmp, handle->id, old_num, spare.id) < 0){
  191. LM_ERR("storing data of broken db failed.\n");
  192. return -1;
  193. }
  194. spare.db[0].failover_time = time(NULL);
  195. spare.db[0].errors = 0;
  196. old_num = spare.db[0].no;
  197. spare.db[0].no = db->no;
  198. if(store_handle_data(dbf, dbh, &spare.db[0], spare.id, old_num, handle->id) < 0){
  199. LM_ERR("storing data of activated spare db failed.\n");
  200. return -1;
  201. }
  202. return 0;
  203. }
  204. int db_failover_deactivate(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no) {
  205. db_key_t cols[3];
  206. db_key_t keys[3];
  207. db_val_t vals[3];
  208. db_val_t key_vals[3];
  209. db_op_t op[2];
  210. cols[0] = &status_col;
  211. vals[0].type = DB1_INT;
  212. vals[0].nul = 0;
  213. vals[0].val.int_val = DB_OFF;
  214. cols[1] = &failover_time_col;
  215. vals[1].type = DB1_DATETIME;
  216. vals[1].nul = 0;
  217. vals[1].val.time_val = time(NULL);
  218. keys[0] = &id_col;
  219. op[0] = OP_EQ;
  220. key_vals[0].type = DB1_INT;
  221. key_vals[0].nul = 0;
  222. key_vals[0].val.int_val = handle->id;
  223. keys[1] = &num_col;
  224. op[1] = OP_EQ;
  225. key_vals[1].type = DB1_INT;
  226. key_vals[1].nul = 0;
  227. key_vals[1].val.int_val = no;
  228. if(dbf->use_table(dbh, &reg_table) < 0) {
  229. LM_ERR("could not use reg_table.\n");
  230. return -1;
  231. }
  232. if(dbf->update(dbh, keys, op, key_vals, cols, vals, 2, 2) < 0) {
  233. LM_ERR("could not update reg_table.\n");
  234. return -1;
  235. }
  236. return 0;
  237. }
  238. int db_failover_reactivate(db_func_t * dbf, db1_con_t * dbh, ul_db_handle_t * handle, int no) {
  239. db_key_t cols[3];
  240. db_key_t keys[2];
  241. db_val_t vals[3];
  242. db_val_t key_vals[2];
  243. db_op_t op[2];
  244. cols[0] = &status_col;
  245. vals[0].type = DB1_INT;
  246. vals[0].nul = 0;
  247. vals[0].val.int_val = DB_ON;
  248. cols[1] = &failover_time_col;
  249. vals[1].type = DB1_DATETIME;
  250. vals[1].nul = 0;
  251. vals[1].val.time_val = time(NULL);
  252. cols[2] = &error_col;
  253. vals[2].type = DB1_INT;
  254. vals[2].nul = 0;
  255. vals[2].val.time_val = 0;
  256. keys[0] = &id_col;
  257. op[0] = OP_EQ;
  258. key_vals[0].type = DB1_INT;
  259. key_vals[0].nul = 0;
  260. key_vals[0].val.int_val = handle->id;
  261. keys[1] = &num_col;
  262. op[1] = OP_EQ;
  263. key_vals[1].type = DB1_INT;
  264. key_vals[1].nul = 0;
  265. key_vals[1].val.int_val = no;
  266. if(dbf->use_table(dbh, &reg_table) < 0) {
  267. LM_ERR("could not use reg_table.\n");
  268. return -1;
  269. }
  270. if(dbf->update(dbh, keys, op, key_vals, cols, vals, 2, 3) < 0) {
  271. LM_ERR("could not update reg_table.\n");
  272. return -1;
  273. }
  274. return 0;
  275. }
  276. int db_failover_reset(db_func_t * dbf, db1_con_t * dbh,int id, int no){
  277. db_key_t cols[1];
  278. db_key_t keys[2];
  279. db_val_t vals[1];
  280. db_val_t key_vals[2];
  281. db_op_t op[2];
  282. cols[0] = &failover_time_col;
  283. vals[0].type = DB1_DATETIME;
  284. vals[0].nul = 0;
  285. vals[0].val.time_val = UL_DB_ZERO_TIME;
  286. keys[0] = &id_col;
  287. op[0] = OP_EQ;
  288. key_vals[0].type = DB1_INT;
  289. key_vals[0].nul = 0;
  290. key_vals[0].val.int_val = id;
  291. keys[1] = &num_col;
  292. op[1] = OP_EQ;
  293. key_vals[1].type = DB1_INT;
  294. key_vals[1].nul = 0;
  295. key_vals[1].val.int_val = no;
  296. if(dbf->use_table(dbh, &reg_table) < 0) {
  297. LM_ERR("could not use reg_table.\n");
  298. return -1;
  299. }
  300. if(dbf->update(dbh, keys, op, key_vals, cols, vals, 2, 1) < 0) {
  301. LM_ERR("could not update reg_table.\n");
  302. return -1;
  303. }
  304. return 0;
  305. }