~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to sql/rpl_mi_file.cc

  • Committer: Alexander Nozdrin
  • Date: 2009-04-24 10:04:14 UTC
  • mfrom: (2651.1.45 mysql-6.0)
  • Revision ID: alik@sun.com-20090424100414-92m55kfywauveb56
PullĀ fromĀ 6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2003 MySQL AB
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include <my_global.h> // For HAVE_REPLICATION
 
17
#include "mysql_priv.h"
 
18
#include <my_dir.h>
 
19
 
 
20
#include <rpl_mi_file.h>
 
21
 
 
22
#ifdef HAVE_REPLICATION
 
23
 
 
24
// Defined in slave.cc
 
25
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
 
26
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
 
27
                          const char *default_val);
 
28
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
 
29
int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
 
30
 
 
31
enum {
 
32
  LINES_IN_MASTER_INFO_WITH_SSL= 14,
 
33
 
 
34
  /* 5.1.16 added value of master_ssl_verify_server_cert */
 
35
  LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
 
36
 
 
37
  /* 6.0 added value of master_heartbeat_period */
 
38
  LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
 
39
 
 
40
  /* 6.0 added value of master_ignore_server_id */
 
41
  LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 17,
 
42
 
 
43
  /* Number of lines currently used when saving master info file */
 
44
  LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS
 
45
};
 
46
 
 
47
Master_info_file::Master_info_file(const char* param_info_fname)
 
48
  :info_fname(param_info_fname), info_fd(-1),
 
49
  sync_counter(0)
 
50
{
 
51
  DBUG_ENTER("Master_info_file::Master_info_file");
 
52
 
 
53
  bzero((char*) &info_file, sizeof(info_file));
 
54
 
 
55
  DBUG_VOID_RETURN;
 
56
}
 
57
 
 
58
int Master_info_file::do_check()
 
59
{
 
60
  char fname[FN_REFLEN+128];
 
61
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
 
62
 
 
63
  return (access(fname,F_OK));
 
64
}
 
65
 
 
66
int Master_info_file::do_init_info()
 
67
{
 
68
  int error;
 
69
  char fname[FN_REFLEN+128];
 
70
  DBUG_ENTER("Master_info_file::do_init_info");
 
71
 
 
72
  mysql= 0;
 
73
  file_id= 1;
 
74
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
 
75
 
 
76
  /* does master.info exist ? */
 
77
  if (access(fname,F_OK))
 
78
  {
 
79
    /*
 
80
      if someone removed the file from underneath our feet, just close
 
81
      the old descriptor and re-create the old file
 
82
    */
 
83
    if (info_fd >= 0)
 
84
      my_close(info_fd, MYF(MY_WME));
 
85
    if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
 
86
    {
 
87
      sql_print_error("Failed to create a new master info file (\
 
88
file '%s', errno %d)", fname, my_errno);
 
89
      goto err;
 
90
    }
 
91
    if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
 
92
                      MYF(MY_WME)))
 
93
    {
 
94
      sql_print_error("Failed to create a cache on master info file (\
 
95
file '%s')", fname);
 
96
      goto err;
 
97
    }
 
98
 
 
99
    init_master_log_pos(this);
 
100
  }
 
101
  else // file exists
 
102
  {
 
103
    if (info_fd >= 0)
 
104
      reinit_io_cache(&info_file, READ_CACHE, 0L,0,0);
 
105
    else
 
106
    {
 
107
      if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
 
108
      {
 
109
        sql_print_error("Failed to open the existing master info file (\
 
110
file '%s', errno %d)", fname, my_errno);
 
111
        goto err;
 
112
      }
 
113
      if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,
 
114
                        0, MYF(MY_WME)))
 
115
      {
 
116
        sql_print_error("Failed to create a cache on master info file (\
 
117
file '%s')", fname);
 
118
        goto err;
 
119
      }
 
120
    }
 
121
 
 
122
    int var_port, var_connect_retry, var_master_log_pos, lines;
 
123
    int var_ssl= 0, var_ssl_verify_server_cert= 0;
 
124
    float var_master_heartbeat_period= 0.0;
 
125
    char *first_non_digit;
 
126
 
 
127
    /*
 
128
       Starting from 4.1.x master.info has new format. Now its
 
129
       first line contains number of lines in file. By reading this
 
130
       number we will be always distinguish to which version our
 
131
       master.info corresponds to. We can't simply count lines in
 
132
       file since versions before 4.1.x could generate files with more
 
133
       lines than needed.
 
134
       If first line doesn't contain a number or contain number less than
 
135
       LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
 
136
       from pre 4.1.1 version.
 
137
       There is no ambiguity when reading an old master.info, as before
 
138
       4.1.1, the first line contained the binlog's name, which is either
 
139
       empty or has an extension (contains a '.'), so can't be confused
 
140
       with an integer.
 
141
 
 
142
       So we're just reading first line and trying to figure which version
 
143
       is this.
 
144
    */
 
145
 
 
146
    /*
 
147
       The first row is temporarily stored in master_log_name,
 
148
       if it is line count and not binlog name (new format) it will be
 
149
       overwritten by the second row later.
 
150
    */
 
151
    if (init_strvar_from_file(master_log_name,
 
152
                              sizeof(master_log_name), &info_file,
 
153
                              ""))
 
154
      goto errwithmsg;
 
155
 
 
156
    lines= strtoul(master_log_name, &first_non_digit, 10);
 
157
 
 
158
    if (master_log_name[0]!='\0' &&
 
159
        *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
 
160
    {
 
161
      /* Seems to be new format => read master log name from next line */
 
162
      if (init_strvar_from_file(master_log_name,
 
163
            sizeof(master_log_name), &info_file, ""))
 
164
        goto errwithmsg;
 
165
    }
 
166
    else
 
167
      lines= 7;
 
168
 
 
169
    if (init_intvar_from_file(&var_master_log_pos, &info_file, 4) ||
 
170
        init_strvar_from_file(host, sizeof(host), &info_file, 0) ||
 
171
        init_strvar_from_file(user, sizeof(user), &info_file, "test") ||
 
172
        init_strvar_from_file(password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
 
173
                              &info_file, 0 ) ||
 
174
        init_intvar_from_file(&var_port, &info_file, MYSQL_PORT) ||
 
175
        init_intvar_from_file(&var_connect_retry, &info_file, DEFAULT_CONNECT_RETRY))
 
176
      goto errwithmsg;
 
177
 
 
178
    /*
 
179
      If file has ssl part use it even if we have server without
 
180
      SSL support. But these option will be ignored later when
 
181
      slave will try connect to master, so in this case warning
 
182
      is printed.
 
183
    */
 
184
    if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
 
185
    {
 
186
      if (init_intvar_from_file(&var_ssl, &info_file, 0) ||
 
187
          init_strvar_from_file(ssl_ca, sizeof(ssl_ca),
 
188
                                &info_file, 0) ||
 
189
          init_strvar_from_file(ssl_capath, sizeof(ssl_capath),
 
190
                                &info_file, 0) ||
 
191
          init_strvar_from_file(ssl_cert, sizeof(ssl_cert),
 
192
                                &info_file, 0) ||
 
193
          init_strvar_from_file(ssl_cipher, sizeof(ssl_cipher),
 
194
                                &info_file, 0) ||
 
195
          init_strvar_from_file(ssl_key, sizeof(ssl_key),
 
196
                               &info_file, 0))
 
197
      goto errwithmsg;
 
198
 
 
199
      /*
 
200
        Starting from 5.1.16 ssl_verify_server_cert might be
 
201
        in the file
 
202
      */
 
203
      if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
 
204
          init_intvar_from_file(&var_ssl_verify_server_cert, &info_file, 0))
 
205
        goto errwithmsg;
 
206
      /*
 
207
        Starting from 6.0 master_heartbeat_period might be
 
208
        in the file
 
209
      */
 
210
      if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD &&
 
211
          init_floatvar_from_file(&var_master_heartbeat_period, &info_file, 0.0))
 
212
        goto errwithmsg;
 
213
      /*
 
214
        Starting from 6.0 list of server_id of ignorable servers might be
 
215
        in the file
 
216
      */
 
217
      if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS &&
 
218
          init_dynarray_intvar_from_file(&ignore_server_ids, &info_file))
 
219
      {
 
220
        sql_print_error("Failed to initialize master info ignore_server_ids");
 
221
        goto errwithmsg;
 
222
      }
 
223
    }
 
224
 
 
225
#ifndef HAVE_OPENSSL
 
226
    if (var_ssl)
 
227
      sql_print_warning("SSL information in the master info file "
 
228
                      "('%s') are ignored because this MySQL slave was "
 
229
                      "compiled without SSL support.", fname);
 
230
#endif /* HAVE_OPENSSL */
 
231
 
 
232
    /*
 
233
      This has to be handled here as init_intvar_from_file can't handle
 
234
      my_off_t types
 
235
    */
 
236
    master_log_pos= (my_off_t) var_master_log_pos;
 
237
    port= (uint) var_port;
 
238
    connect_retry= (uint) var_connect_retry;
 
239
    ssl= (my_bool) var_ssl;
 
240
    ssl_verify_server_cert= var_ssl_verify_server_cert;
 
241
    heartbeat_period= var_master_heartbeat_period;
 
242
  }
 
243
  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
 
244
                            master_log_name,
 
245
                            (ulong) master_log_pos));
 
246
 
 
247
  // now change cache READ -> WRITE - must do this before flush_info
 
248
  reinit_io_cache(&info_file, WRITE_CACHE, 0L, 0, 1);
 
249
  if ((error=test(do_flush_info())))
 
250
    sql_print_error("Failed to flush master info file");
 
251
  DBUG_RETURN(error);
 
252
 
 
253
errwithmsg:
 
254
  sql_print_error("Error reading master configuration");
 
255
 
 
256
err:
 
257
  if (info_fd >= 0)
 
258
  {
 
259
    my_close(info_fd, MYF(0));
 
260
    end_io_cache(&info_file);
 
261
  }
 
262
  info_fd= -1;
 
263
  DBUG_RETURN(1);
 
264
}
 
265
 
 
266
/**
 
267
  Flushes the master info to a file.
 
268
  
 
269
  @retval 1 if it failed,
 
270
  @retval 0 otherwise.
 
271
*/
 
272
int Master_info_file::do_flush_info()
 
273
{
 
274
  IO_CACHE* file = &info_file;
 
275
  char lbuf[22];
 
276
  int err= 0;
 
277
 
 
278
  DBUG_ENTER("Master_info_file::do_flush_info");
 
279
  DBUG_PRINT("enter",("master_pos: %ld", (long) master_log_pos));
 
280
 
 
281
  /*
 
282
     In certain cases this code may create master.info files that seems
 
283
     corrupted, because of extra lines filled with garbage in the end
 
284
     file (this happens if new contents take less space than previous
 
285
     contents of file). But because of number of lines in the first line
 
286
     of file we don't care about this garbage.
 
287
  */
 
288
  char heartbeat_buf[sizeof(heartbeat_period) * 4]; // buffer to suffice always
 
289
  my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", heartbeat_period));
 
290
  /*
 
291
    produce a line listing the total number and all the ignored server_id:s
 
292
  */
 
293
  char* ignore_server_ids_buf;
 
294
  {
 
295
    ignore_server_ids_buf=
 
296
      (char *) my_malloc((sizeof(::server_id) * 3 + 1) *
 
297
                         (1 + ignore_server_ids.elements), MYF(MY_WME));
 
298
    if (!ignore_server_ids_buf)
 
299
      DBUG_RETURN(1);
 
300
    for (ulong i= 0, cur_len= my_sprintf(ignore_server_ids_buf,
 
301
                                         (ignore_server_ids_buf, "%u",
 
302
                                          ignore_server_ids.elements));
 
303
         i < ignore_server_ids.elements; i++)
 
304
    {
 
305
      ulong s_id;
 
306
      get_dynamic(&ignore_server_ids, (uchar*) &s_id, i);
 
307
      cur_len +=my_sprintf(ignore_server_ids_buf + cur_len,
 
308
                           (ignore_server_ids_buf + cur_len,
 
309
                            " %lu", s_id));
 
310
    }
 
311
  }
 
312
  my_b_seek(file, 0L);
 
313
  my_b_printf(file,
 
314
              "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n",
 
315
              LINES_IN_MASTER_INFO,
 
316
              master_log_name, llstr(master_log_pos, lbuf),
 
317
              host, user,
 
318
              password, port, connect_retry,
 
319
              (int)(ssl), ssl_ca, ssl_capath, ssl_cert,
 
320
              ssl_cipher, ssl_key, ssl_verify_server_cert,
 
321
              heartbeat_buf,
 
322
              ignore_server_ids_buf);
 
323
  my_free(ignore_server_ids_buf, MYF(0));
 
324
  err= flush_io_cache(file);
 
325
  if (sync_masterinfo_period && !err && 
 
326
      ++(sync_counter) >= sync_masterinfo_period)
 
327
  {
 
328
    err= my_sync(info_fd, MYF(MY_WME));
 
329
    sync_counter= 0;
 
330
  }
 
331
  DBUG_RETURN(-err);
 
332
}
 
333
 
 
334
void Master_info_file::do_end_info()
 
335
{
 
336
  DBUG_ENTER("Master_info_file::do_end_info");
 
337
 
 
338
  if (!inited)
 
339
    DBUG_VOID_RETURN;
 
340
 
 
341
  if (info_fd >= 0)
 
342
  {
 
343
    end_io_cache(&info_file);
 
344
    (void)my_close(info_fd, MYF(MY_WME));
 
345
    info_fd = -1;
 
346
  }
 
347
  inited = 0;
 
348
 
 
349
  DBUG_VOID_RETURN;
 
350
}
 
351
 
 
352
int Master_info_file::do_reset_info() 
 
353
{
 
354
  MY_STAT stat_area;
 
355
  char fname[FN_REFLEN];
 
356
  int error= 0;
 
357
 
 
358
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
 
359
  if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
 
360
    error= 1;
 
361
 
 
362
  return (error);
 
363
}
 
364
#endif /* HAVE_REPLICATION */