~mysqlatfacebook/mysqlatfacebook/tools

« back to all changes in this revision

Viewing changes to faker/slave.c

  • Committer: Domas Mituzas
  • Date: 2012-09-04 10:46:59 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: domas@fb.com-20120904104659-pvzx1973dli3iv6u
Faker: C implementation of InnoDB fake changes based replication prefetcher

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright 2012 Facebook
 
3
 
 
4
   Licensed under the Apache License, Version 2.0 (the "License");
 
5
   you may not use this file except in compliance with the License.
 
6
   You may obtain a copy of the License at
 
7
 
 
8
       http://www.apache.org/licenses/LICENSE-2.0
 
9
 
 
10
   Unless required by applicable law or agreed to in writing, software
 
11
   distributed under the License is distributed on an "AS IS" BASIS,
 
12
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
   See the License for the specific language governing permissions and
 
14
   limitations under the License.
 
15
*/
 
16
 
 
17
#include "faker.h"
 
18
 
 
19
/* Very very persistent attempts */
 
20
void connect_or_keep_connecting(MYSQL * mysql)
 
21
{
 
22
    while (!mysql_real_connect
 
23
           (mysql, "127.0.0.1", db_username, db_password, NULL,
 
24
            db_port, NULL, CLIENT_MULTI_STATEMENTS)) {
 
25
        g_warning("Couldn't connect to MySQL: %s", mysql_error(mysql));
 
26
        sleep(1);
 
27
    }
 
28
}
 
29
 
 
30
/* Initialize MySQL connection to a slave */
 
31
MYSQL *init_slave(char *init_command)
 
32
{
 
33
    /* Return always-ready MySQL connect handle */
 
34
    MYSQL *mysql = mysql_init(NULL);
 
35
    if (init_command)
 
36
        mysql_options(mysql, MYSQL_INIT_COMMAND, init_command);
 
37
    my_bool reconnect = 1;
 
38
    mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
 
39
    connect_or_keep_connecting(mysql);
 
40
    return mysql;
 
41
}
 
42
 
 
43
/* Run a query, whenever server comes back up, return lats resultset data */
 
44
MYSQL_RES *slave_query(MYSQL * slave, char *query, unsigned long length)
 
45
{
 
46
    MYSQL_RES *res = NULL, *ret = NULL;
 
47
    int i = 0, status = 0;
 
48
 
 
49
    if (!length)
 
50
        length = strlen(query);
 
51
    while (mysql_real_query(slave, query, length)) {
 
52
        /* We will reconnect and try again,
 
53
           don't trust MySQL API reconnects */
 
54
        if (mysql_errno(slave) == CR_SERVER_LOST)
 
55
            connect_or_keep_connecting(slave);
 
56
        else {
 
57
            g_warning("%s", mysql_error(slave));
 
58
            return NULL;
 
59
        }
 
60
        /* There were enough reconnects to prove ourselves
 
61
           that we get disconnected while running this query,
 
62
           oh noes. */
 
63
        if (i++ >= 3)
 
64
            return NULL;
 
65
    }
 
66
 
 
67
/* The very awesome MySQL C API boilerplate */
 
68
 
 
69
    do {
 
70
        res = mysql_store_result(slave);
 
71
        if (res) {
 
72
            if (ret)
 
73
                mysql_free_result(ret);
 
74
            ret = res;
 
75
        }
 
76
        if ((status = mysql_next_result(slave)) > 0)
 
77
            if (mysql_errno(slave) != 1180 && mysql_errno(slave) != 1062)
 
78
                g_warning("Could not execute statement: %s (%d)",
 
79
                          mysql_error(slave), mysql_errno(slave));
 
80
    } while (status == 0);
 
81
    return ret;
 
82
}
 
83
 
 
84
 
 
85
 
 
86
/* Opens relay log based on SLAVE STATUS and @@datadir */
 
87
BINLOG *relaylog_from_slave(MYSQL * slave, BINLOG * relaylog)
 
88
{
 
89
    MYSQL_RES *res = slave_query(slave, "SHOW SLAVE STATUS", 0);
 
90
    if (!res)
 
91
        return NULL;
 
92
 
 
93
    MYSQL_ROW row = mysql_fetch_row(res);
 
94
    BINLOG *bl;
 
95
 
 
96
    /* Does not have valid relay log */
 
97
    if (!row || !row[7] || !row[7][0]) {
 
98
        mysql_free_result(res);
 
99
        return NULL;
 
100
    }
 
101
    char *filename = row[7];
 
102
    guint32 position = atoi(row[8]);
 
103
    /* Not an absolute filename, need to construct some */
 
104
    if (row[7][0] != '/') {
 
105
        filename = g_strdup_printf("%s/%s", log_directory, filename);
 
106
    } else {
 
107
        filename = g_strdup(filename);
 
108
    }
 
109
    mysql_free_result(res);
 
110
 
 
111
    // No relay log known/passed
 
112
    if (!relaylog)
 
113
        bl = open_binlog(filename);
 
114
 
 
115
    // Different filename, must reopen
 
116
    else if (strcmp(filename, relaylog->filename)) {
 
117
        free_binlog(relaylog);
 
118
        bl = open_binlog(filename);
 
119
    } else {
 
120
        // Same file, we'll need just to seek
 
121
        bl = relaylog;
 
122
        g_free(filename);
 
123
    }
 
124
 
 
125
    if (bl)
 
126
        seek_binlog(bl, position);
 
127
    return bl;
 
128
}
 
129
 
 
130
/* Sleeps and tells why it is sleeping via MySQL processlist */
 
131
void slave_sleep(MYSQL * slave, float t, const char *message)
 
132
{
 
133
    char *query = g_strdup_printf("SELECT /* %s */ SLEEP(%f)", message, t);
 
134
    MYSQL_RES *res = slave_query(slave, query, 0);
 
135
    if (res)
 
136
        mysql_free_result(res);
 
137
    g_free(query);
 
138
}
 
139
 
 
140
/* Reports SLAVE STATUS to a structure specified */
 
141
void slave_status(MYSQL * slave, SLAVE_STATUS * st)
 
142
{
 
143
    st->io_running = 0;
 
144
    st->sql_running = 0;
 
145
    st->lag = 0;
 
146
    MYSQL_RES *res = slave_query(slave, "SHOW SLAVE STATUS", 0);
 
147
    if (!res)
 
148
        return;
 
149
    MYSQL_ROW row = mysql_fetch_row(res);
 
150
    if (row) {
 
151
        if (row[10] && !strcmp(row[10], "Yes"))
 
152
            st->io_running = 1;
 
153
        if (row[11] && !strcmp(row[11], "Yes"))
 
154
            st->sql_running = 1;
 
155
        if (row[32]) {
 
156
            st->lag = atoi(row[32]);
 
157
            if (st->lag < 0)
 
158
                st->lag = 0;
 
159
        } else {
 
160
            /* Unknown lag may be lag too, if I/O thread is dead */
 
161
            st->lag = -1;
 
162
        }
 
163
    }
 
164
    mysql_free_result(res);
 
165
}