MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_info_file.cc
1 /* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <my_global.h>
17 #include <sql_priv.h>
18 #include <my_dir.h>
19 #include "rpl_info_file.h"
20 #include "mysqld.h"
21 #include "log.h"
22 
23 int init_ulongvar_from_file(ulong* var, IO_CACHE* f, ulong default_val);
24 int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
25  const char *default_val);
26 int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
27 int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
28 bool init_dynarray_intvar_from_file(char *buffer, size_t size,
29  char **buffer_act, IO_CACHE* f);
30 
31 Rpl_info_file::Rpl_info_file(const int nparam,
32  const char* param_pattern_fname,
33  const char* param_info_fname,
34  bool indexed_arg)
35  :Rpl_info_handler(nparam), info_fd(-1), name_indexed(indexed_arg)
36 {
37  DBUG_ENTER("Rpl_info_file::Rpl_info_file");
38 
39  memset(&info_file, 0, sizeof(info_file));
40  fn_format(pattern_fname, param_pattern_fname, mysql_data_home, "", 4 + 32);
41  fn_format(info_fname, param_info_fname, mysql_data_home, "", 4 + 32);
42 
43  DBUG_VOID_RETURN;
44 }
45 
46 Rpl_info_file::~Rpl_info_file()
47 {
48  DBUG_ENTER("Rpl_info_file::~Rpl_info_file");
49 
50  do_end_info();
51 
52  DBUG_VOID_RETURN;
53 }
54 
55 int Rpl_info_file::do_init_info(uint instance)
56 {
57  DBUG_ENTER("Rpl_info_file::do_init_info(uint)");
58 
59  char fname_local[FN_REFLEN];
60  char *pos= strmov(fname_local, pattern_fname);
61  if (name_indexed)
62  sprintf(pos, "%u", instance);
63 
64  fn_format(info_fname, fname_local, mysql_data_home, "", 4 + 32);
65  DBUG_RETURN(do_init_info());
66 }
67 
68 int Rpl_info_file::do_init_info()
69 {
70  int error= 0;
71  DBUG_ENTER("Rpl_info_file::do_init_info");
72 
73  /* does info file exist ? */
74  enum_return_check ret_check= do_check_info();
75  if (ret_check == REPOSITORY_DOES_NOT_EXIST)
76  {
77  /*
78  If someone removed the file from underneath our feet, just close
79  the old descriptor and re-create the old file
80  */
81  if (info_fd >= 0)
82  {
83  if (my_b_inited(&info_file))
84  end_io_cache(&info_file);
85  my_close(info_fd, MYF(MY_WME));
86  }
87  if ((info_fd = my_open(info_fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
88  {
89  sql_print_error("Failed to create a new info file (\
90 file '%s', errno %d)", info_fname, my_errno);
91  error= 1;
92  }
93  else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
94  MYF(MY_WME)))
95  {
96  sql_print_error("Failed to create a cache on info file (\
97 file '%s')", info_fname);
98  error= 1;
99  }
100  if (error)
101  {
102  if (info_fd >= 0)
103  my_close(info_fd, MYF(0));
104  info_fd= -1;
105  }
106  }
107  /* file exists */
108  else if (ret_check == REPOSITORY_EXISTS)
109  {
110  if (info_fd >= 0)
111  reinit_io_cache(&info_file, READ_CACHE, 0L,0,0);
112  else
113  {
114  if ((info_fd = my_open(info_fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
115  {
116  sql_print_error("Failed to open the existing info file (\
117 file '%s', errno %d)", info_fname, my_errno);
118  error= 1;
119  }
120  else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,
121  0, MYF(MY_WME)))
122  {
123  sql_print_error("Failed to create a cache on info file (\
124 file '%s')", info_fname);
125  error= 1;
126  }
127  if (error)
128  {
129  if (info_fd >= 0)
130  my_close(info_fd, MYF(0));
131  info_fd= -1;
132  }
133  }
134  }
135  else
136  error= 1;
137  DBUG_RETURN(error);
138 }
139 
140 int Rpl_info_file::do_prepare_info_for_read()
141 {
142  cursor= 0;
143  prv_error= FALSE;
144  return (reinit_io_cache(&info_file, READ_CACHE, 0L, 0, 0));
145 }
146 
147 int Rpl_info_file::do_prepare_info_for_write()
148 {
149  cursor= 0;
150  prv_error= FALSE;
151  return (reinit_io_cache(&info_file, WRITE_CACHE, 0L, 0, 1));
152 }
153 
154 inline enum_return_check do_check_repository_file(const char *fname)
155 {
156  if (my_access(fname, F_OK))
157  return REPOSITORY_DOES_NOT_EXIST;
158 
159  if (my_access(fname, F_OK | R_OK | W_OK))
160  return ERROR_CHECKING_REPOSITORY;
161 
162  return REPOSITORY_EXISTS;
163 }
164 
165 /*
166  The method verifies existence of an instance of the repository.
167 
168  @param instance an index in the repository
169  @retval REPOSITORY_EXISTS when the check is successful
170  @retval REPOSITORY_DOES_NOT_EXIST otherwise
171 
172  @note This method also verifies overall integrity
173  of the repositories to make sure they are indexed without any gaps.
174 */
175 enum_return_check Rpl_info_file::do_check_info(uint instance)
176 {
177  uint i;
178  enum_return_check last_check= REPOSITORY_EXISTS;
179  char fname_local[FN_REFLEN];
180  char *pos= NULL;
181 
182  for (i= 1; i <= instance && last_check == REPOSITORY_EXISTS; i++)
183  {
184  pos= strmov(fname_local, pattern_fname);
185  if (name_indexed)
186  sprintf(pos, "%u", i);
187  fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
188  last_check= do_check_repository_file(fname_local);
189  }
190  return last_check;
191 }
192 
193 enum_return_check Rpl_info_file::do_check_info()
194 {
195  return do_check_repository_file(info_fname);
196 }
197 
198 /*
199  The function counts number of files in a range starting
200  from one. The range degenerates into one item when @c indexed is false.
201  Scanning ends once the next indexed file is not found.
202 
203  @param nparam Number of fields
204  @param param_pattern
205  a string pattern to generate
206  the actual file name
207  @param indexed indicates whether the file is indexed and if so
208  there is a range to count in.
209  @param[out] counter the number of discovered instances before the first
210  unsuccess in locating the next file.
211 
212  @retval false All OK
213  @retval true An error
214 */
215 bool Rpl_info_file::do_count_info(const int nparam,
216  const char* param_pattern,
217  bool indexed,
218  uint* counter)
219 {
220  uint i= 0;
221  Rpl_info_file* info= NULL;
222 
223  char fname_local[FN_REFLEN];
224  char *pos= NULL;
225  enum_return_check last_check= REPOSITORY_EXISTS;
226 
227  DBUG_ENTER("Rpl_info_file::do_count_info");
228 
229  if (!(info= new Rpl_info_file(nparam, param_pattern, "", indexed)))
230  DBUG_RETURN(true);
231 
232  for (i= 1; last_check == REPOSITORY_EXISTS; i++)
233  {
234  pos= strmov(fname_local, param_pattern);
235  if (indexed)
236  {
237  sprintf(pos, "%u", i);
238  }
239  fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
240  if ((last_check= do_check_repository_file(fname_local)) == REPOSITORY_EXISTS)
241  (*counter)++;
242  // just one loop pass for MI and RLI file
243  if (!indexed)
244  break;
245  }
246  delete info;
247 
248  DBUG_RETURN(false);
249 }
250 
251 int Rpl_info_file::do_flush_info(const bool force)
252 {
253  int error= 0;
254 
255  DBUG_ENTER("Rpl_info_file::do_flush_info");
256 
257  if (flush_io_cache(&info_file))
258  error= 1;
259  if (!error && (force ||
260  (sync_period &&
261  ++(sync_counter) >= sync_period)))
262  {
263  if (my_sync(info_fd, MYF(MY_WME)))
264  error= 1;
265  sync_counter= 0;
266  }
267 
268  DBUG_RETURN(error);
269 }
270 
271 void Rpl_info_file::do_end_info()
272 {
273  DBUG_ENTER("Rpl_info_file::do_end_info");
274 
275  if (info_fd >= 0)
276  {
277  if (my_b_inited(&info_file))
278  end_io_cache(&info_file);
279  my_close(info_fd, MYF(MY_WME));
280  info_fd = -1;
281  }
282 
283  DBUG_VOID_RETURN;
284 }
285 
286 int Rpl_info_file::do_remove_info()
287 {
288  MY_STAT stat_area;
289  int error= 0;
290 
291  DBUG_ENTER("Rpl_info_file::do_remove_info");
292 
293  if (my_stat(info_fname, &stat_area, MYF(0)) && my_delete(info_fname, MYF(MY_WME)))
294  error= 1;
295 
296  DBUG_RETURN(error);
297 }
298 
299 int Rpl_info_file::do_clean_info()
300 {
301  /*
302  There is nothing to do here. Maybe we can truncate the
303  file in the future. Howerver, for now, there is no need.
304  */
305  return 0;
306 }
307 
308 int Rpl_info_file::do_reset_info(const int nparam,
309  const char* param_pattern,
310  bool indexed)
311 {
312  int error= false;
313  uint i= 0;
314  Rpl_info_file* info= NULL;
315  char fname_local[FN_REFLEN];
316  char *pos= NULL;
317  enum_return_check last_check= REPOSITORY_EXISTS;
318 
319  DBUG_ENTER("Rpl_info_file::do_count_info");
320 
321  if (!(info= new Rpl_info_file(nparam, param_pattern, "", indexed)))
322  DBUG_RETURN(true);
323 
324  for (i= 1; last_check == REPOSITORY_EXISTS; i++)
325  {
326  pos= strmov(fname_local, param_pattern);
327  if (indexed)
328  {
329  sprintf(pos, "%u", i);
330  }
331  fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
332  if ((last_check= do_check_repository_file(fname_local)) == REPOSITORY_EXISTS)
333  if (my_delete(fname_local, MYF(MY_WME)))
334  error= true;
335  // just one loop pass for MI and RLI file
336  if (!indexed)
337  break;
338  }
339  delete info;
340 
341  DBUG_RETURN(error);
342 }
343 
344 bool Rpl_info_file::do_set_info(const int pos, const char *value)
345 {
346  return (my_b_printf(&info_file, "%s\n", value) > (size_t) 0 ?
347  FALSE : TRUE);
348 }
349 
350 bool Rpl_info_file::do_set_info(const int pos, const uchar *value,
351  const size_t size)
352 {
353  return (my_b_write(&info_file, value, size));
354 }
355 
356 bool Rpl_info_file::do_set_info(const int pos, const ulong value)
357 {
358  return (my_b_printf(&info_file, "%lu\n", value) > (size_t) 0 ?
359  FALSE : TRUE);
360 }
361 
362 bool Rpl_info_file::do_set_info(const int pos, const int value)
363 {
364  return (my_b_printf(&info_file, "%d\n", value) > (size_t) 0 ?
365  FALSE : TRUE);
366 }
367 
368 bool Rpl_info_file::do_set_info(const int pos, const float value)
369 {
370  /*
371  64 bytes provide enough space considering that the precision is 3
372  bytes (See the appropriate set funciton):
373 
374  FLT_MAX The value of this macro is the maximum number representable
375  in type float. It is supposed to be at least 1E+37.
376  FLT_MIN Similar to the FLT_MAX, we have 1E-37.
377 
378  If a file is manually and not properly changed, this function may
379  crash the server.
380  */
381  char buffer[64];
382 
383  sprintf(buffer, "%.3f", value);
384 
385  return (my_b_printf(&info_file, "%s\n", buffer) > (size_t) 0 ?
386  FALSE : TRUE);
387 }
388 
389 bool Rpl_info_file::do_set_info(const int pos, const Dynamic_ids *value)
390 {
391  bool error= TRUE;
392  String buffer;
393 
394  /*
395  This produces a line listing the total number and all the server_ids.
396  */
397  if (const_cast<Dynamic_ids *>(value)->pack_dynamic_ids(&buffer))
398  goto err;
399 
400  error= (my_b_printf(&info_file, "%s\n", buffer.c_ptr_safe()) >
401  (size_t) 0 ? FALSE : TRUE);
402 err:
403  return error;
404 }
405 
406 bool Rpl_info_file::do_get_info(const int pos, char *value, const size_t size,
407  const char *default_value)
408 {
409  return (init_strvar_from_file(value, size, &info_file,
410  default_value));
411 }
412 
413 bool Rpl_info_file::do_get_info(const int pos, uchar *value, const size_t size,
414  const uchar *default_value)
415 {
416  return(my_b_read(&info_file, value, size));
417 }
418 
419 bool Rpl_info_file::do_get_info(const int pos, ulong *value,
420  const ulong default_value)
421 {
422  return (init_ulongvar_from_file(value, &info_file,
423  default_value));
424 }
425 
426 bool Rpl_info_file::do_get_info(const int pos, int *value,
427  const int default_value)
428 {
429  return (init_intvar_from_file((int *) value, &info_file,
430  (int) default_value));
431 }
432 
433 bool Rpl_info_file::do_get_info(const int pos, float *value,
434  const float default_value)
435 {
436  return (init_floatvar_from_file(value, &info_file,
437  default_value));
438 }
439 
440 bool Rpl_info_file::do_get_info(const int pos, Dynamic_ids *value,
441  const Dynamic_ids *default_value __attribute__((unused)))
442 {
443  /*
444  Static buffer to use most of the times. However, if it is not big
445  enough to accommodate the server ids, a new buffer is allocated.
446  */
447  const int array_size= 16 * (sizeof(long) * 3 + 1);
448  char buffer[array_size];
449  char *buffer_act= buffer;
450 
451  bool error= init_dynarray_intvar_from_file(buffer, sizeof(buffer),
452  &buffer_act,
453  &info_file);
454  if (!error)
455  value->unpack_dynamic_ids(buffer_act);
456 
457  if (buffer != buffer_act)
458  {
459  /*
460  Release the buffer allocated while reading the server ids
461  from the file.
462  */
463  my_free(buffer_act);
464  }
465 
466  return error;
467 }
468 
469 char* Rpl_info_file::do_get_description_info()
470 {
471  return info_fname;
472 }
473 
474 bool Rpl_info_file::do_is_transactional()
475 {
476  return FALSE;
477 }
478 
479 bool Rpl_info_file::do_update_is_transactional()
480 {
481  return FALSE;
482 }
483 
484 uint Rpl_info_file::do_get_rpl_info_type()
485 {
486  return INFO_REPOSITORY_FILE;
487 }
488 
489 int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
490  const char *default_val)
491 {
492  uint length;
493  DBUG_ENTER("init_strvar_from_file");
494 
495  if ((length=my_b_gets(f,var, max_size)))
496  {
497  char* last_p = var + length -1;
498  if (*last_p == '\n')
499  *last_p = 0; // if we stopped on newline, kill it
500  else
501  {
502  /*
503  If we truncated a line or stopped on last char, remove all chars
504  up to and including newline.
505  */
506  int c;
507  while (((c=my_b_get(f)) != '\n' && c != my_b_EOF)) ;
508  }
509  DBUG_RETURN(0);
510  }
511  else if (default_val)
512  {
513  strmake(var, default_val, max_size-1);
514  DBUG_RETURN(0);
515  }
516  DBUG_RETURN(1);
517 }
518 
519 int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
520 {
521  /*
522  32 bytes provide enough space:
523 
524  INT_MIN –2,147,483,648
525  INT_MAX +2,147,483,647
526  */
527  char buf[32];
528  DBUG_ENTER("init_intvar_from_file");
529 
530  if (my_b_gets(f, buf, sizeof(buf)))
531  {
532  *var = atoi(buf);
533  DBUG_RETURN(0);
534  }
535  else if (default_val)
536  {
537  *var = default_val;
538  DBUG_RETURN(0);
539  }
540  DBUG_RETURN(1);
541 }
542 
543 int init_ulongvar_from_file(ulong* var, IO_CACHE* f, ulong default_val)
544 {
545  /*
546  32 bytes provide enough space:
547 
548  ULONG_MAX 32 bit compiler +4,294,967,295
549  64 bit compiler +18,446,744,073,709,551,615
550  */
551  char buf[32];
552  DBUG_ENTER("init_ulongvar_from_file");
553 
554  if (my_b_gets(f, buf, sizeof(buf)))
555  {
556  *var = strtoul(buf, 0, 10);
557  DBUG_RETURN(0);
558  }
559  else if (default_val)
560  {
561  *var = default_val;
562  DBUG_RETURN(0);
563  }
564  DBUG_RETURN(1);
565 }
566 
567 int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val)
568 {
569  /*
570  64 bytes provide enough space considering that the precision is 3
571  bytes (See the appropriate set funciton):
572 
573  FLT_MAX The value of this macro is the maximum number representable
574  in type float. It is supposed to be at least 1E+37.
575  FLT_MIN Similar to the FLT_MAX, we have 1E-37.
576 
577  If a file is manually and not properly changed, this function may
578  crash the server.
579  */
580  char buf[64];
581  DBUG_ENTER("init_floatvar_from_file");
582 
583  if (my_b_gets(f, buf, sizeof(buf)))
584  {
585  if (sscanf(buf, "%f", var) != 1)
586  DBUG_RETURN(1);
587  else
588  DBUG_RETURN(0);
589  }
590  else if (default_val != 0.0)
591  {
592  *var = default_val;
593  DBUG_RETURN(0);
594  }
595  DBUG_RETURN(1);
596 }
597 
617 bool init_dynarray_intvar_from_file(char *buffer, size_t size,
618  char **buffer_act, IO_CACHE* f)
619 {
620  char *buf= buffer; // actual buffer can be dynamic if static is short
621  char *buf_act= buffer;
622  char *last;
623  uint num_items; // number of items of `arr'
624  size_t read_size;
625 
626  DBUG_ENTER("init_dynarray_intvar_from_file");
627 
628  if ((read_size= my_b_gets(f, buf_act, size)) == 0)
629  {
630  DBUG_RETURN(FALSE); // no line in master.info
631  }
632  if (read_size + 1 == size && buf[size - 2] != '\n')
633  {
634  /*
635  short read happend; allocate sufficient memory and make the 2nd read
636  */
637  char buf_work[(sizeof(long) * 3 + 1) * 16];
638  memcpy(buf_work, buf, sizeof(buf_work));
639  num_items= atoi(strtok_r(buf_work, " ", &last));
640  size_t snd_size;
641  /*
642  max size upper bound approximate estimation bases on the formula:
643  (the items number + items themselves) *
644  (decimal size + space) - 1 + `\n' + '\0'
645  */
646  size_t max_size= (1 + num_items) * (sizeof(long) * 3 + 1) + 1;
647  if (! (buf_act= (char*) my_malloc(max_size, MYF(MY_WME))))
648  DBUG_RETURN(TRUE);
649  *buffer_act= buf_act;
650  memcpy(buf_act, buf, read_size);
651  snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
652  if (snd_size == 0 ||
653  ((snd_size + 1 == max_size - read_size) && buf[max_size - 2] != '\n'))
654  {
655  /*
656  failure to make the 2nd read or short read again
657  */
658  DBUG_RETURN(TRUE);
659  }
660  }
661  DBUG_RETURN(FALSE);
662 }