~drizzle-trunk/drizzle/development

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Copyright (C) 2008 Mark Atwood
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <drizzled/server_includes.h>
#include <drizzled/replicator.h>
#include <drizzled/gettext.h>
#include <drizzled/session.h>

int replicator_initializer(st_plugin_int *plugin)
{
  replicator_t *p;

  p= new replicator_t;
  if (p == NULL) return 1;
  memset(p, 0, sizeof(replicator_t));

  plugin->data= (void *)p;

  if (plugin->plugin->init)
  {
    if (plugin->plugin->init((void *)p))
    {
      /* TRANSLATORS: The leading word "replicator" is the name
        of the plugin api, and so should not be translated. */
      errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' init() failed"),
                      plugin->name.str);
      goto err;
    }
  }
  plugin->state= PLUGIN_IS_READY;

  return 0;

 err:
  delete p;
  return 1;
}

int replicator_finalizer(st_plugin_int *plugin)
{
  replicator_t *p= (replicator_t *) plugin->data;

  if (plugin->plugin->deinit)
    {
      if (plugin->plugin->deinit((void *)p))
        {
          /* TRANSLATORS: The leading word "replicator" is the name
             of the plugin api, and so should not be translated. */
          errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' deinit() failed"),
                          plugin->name.str);
        }
    }

  if (p) delete p;

  return 0;
}

/* This gets called by plugin_foreach once for each loaded replicator plugin */
static bool replicator_session_iterate(Session *session, plugin_ref plugin, void *)
{
  replicator_t *repl= plugin_data(plugin, replicator_t *);
  bool error;

  /* call this loaded replicator plugin's replicator_func1 function pointer */
  if (repl && repl->session_init)
  {
    error= repl->session_init(session);
    if (error)
    {
      /* TRANSLATORS: The leading word "replicator" is the name
        of the plugin api, and so should not be translated. */
      errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' session_init() failed"),
                      (char *)plugin_name(plugin));
      return true;
    }
  }

  return false;
}

/*
  This call is called once at the begining of each transaction.
*/
extern handlerton *binlog_hton;
bool replicator_session_init(Session *session)
{
  bool foreach_rv;

  if (session->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
    trans_register_ha(session, true, binlog_hton);
  trans_register_ha(session, false, binlog_hton);

  if (session->getReplicationData())
    return false;

  /* 
    call replicator_session_iterate
    once for each loaded replicator plugin
  */
  foreach_rv= plugin_foreach(session, replicator_session_iterate,
                             DRIZZLE_REPLICATOR_PLUGIN, NULL);

  return foreach_rv;
}

/* The plugin_foreach() iterator requires that we
   convert all the parameters of a plugin api entry point
   into just one single void ptr, plus the session.
   So we will take all the additional paramters of replicator_do2,
   and marshall them into a struct of this type, and
   then just pass in a pointer to it.
*/
enum repl_row_exec_t{
  repl_insert,
  repl_update,
  repl_delete
};

typedef struct replicator_row_parms_st
{
  repl_row_exec_t type;
  Table *table;
  const unsigned char *before;
  const unsigned char *after;
} replicator_row_parms_st;


/* This gets called by plugin_foreach once for each loaded replicator plugin */
static bool replicator_do_row_iterate (Session *session, plugin_ref plugin, void *p)
{
  replicator_t *repl= plugin_data(plugin, replicator_t *);
  replicator_row_parms_st *params= (replicator_row_parms_st *) p;

  switch (params->type) {
  case repl_insert:
    if (repl && repl->row_insert)
    {
      if (repl->row_insert(session, params->table))
      {
        /* TRANSLATORS: The leading word "replicator" is the name
          of the plugin api, and so should not be translated. */
        errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' row_insert() failed"),
                        (char *)plugin_name(plugin));

        return true;
      }
    }
    break;
  case repl_update:
    if (repl && repl->row_update)
    {
      if (repl->row_update(session, params->table, params->before, params->after))
      {
        /* TRANSLATORS: The leading word "replicator" is the name
          of the plugin api, and so should not be translated. */
        errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' row_update() failed"),
                        (char *)plugin_name(plugin));

        return true;
      }
    }
    break;
  case repl_delete:
    if (repl && repl->row_delete)
    {
      if (repl->row_delete(session, params->table))
      {
        /* TRANSLATORS: The leading word "replicator" is the name
          of the plugin api, and so should not be translated. */
        errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' row_delete() failed"),
                        (char *)plugin_name(plugin));

        return true;
      }
    }
    break;
  }
  return false;
}

/* This is the replicator_do2 entry point.
   This gets called by the rest of the Drizzle server code */
static bool replicator_do_row (Session *session, replicator_row_parms_st *params)
{
  bool foreach_rv;

  foreach_rv= plugin_foreach(session, replicator_do_row_iterate,
                             DRIZZLE_REPLICATOR_PLUGIN, params);
  return foreach_rv;
}

bool replicator_write_row(Session *session, Table *table)
{
  replicator_row_parms_st param;

  param.type= repl_insert;
  param.table= table;
  param.after= NULL;
  param.before= NULL;

  return replicator_do_row(session, &param);
}

bool replicator_update_row(Session *session, Table *table,
                           const unsigned char *before,
                           const unsigned char *after)
{
  replicator_row_parms_st param;

  param.type= repl_update;
  param.table= table;
  param.after= after;
  param.before= before;

  return replicator_do_row(session, &param);
}

bool replicator_delete_row(Session *session, Table *table)
{
  replicator_row_parms_st param;

  param.type= repl_delete;
  param.table= table;
  param.after= NULL;
  param.before= NULL;

  return replicator_do_row(session, &param);
}

/*
  Here be Dragons!

  Ok, not so much dragons, but this is where we handle either commits or rollbacks of
  statements.
*/
typedef struct replicator_row_end_st
{
  bool autocommit;
  bool commit;
} replicator_row_end_st;

/* We call this to end a statement (on each registered plugin) */
static bool replicator_end_transaction_iterate (Session *session, plugin_ref plugin, void *p)
{
  replicator_t *repl= plugin_data(plugin, replicator_t *);
  replicator_row_end_st *params= (replicator_row_end_st *)p;

  /* call this loaded replicator plugin's replicator_func1 function pointer */
  if (repl && repl->end_transaction)
  {
    if (repl->end_transaction(session, params->autocommit, params->commit))
    {
      /* TRANSLATORS: The leading word "replicator" is the name
        of the plugin api, and so should not be translated. */
      errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' end_transaction() failed"),
                      (char *)plugin_name(plugin));
      return true;
    }
  }

  return false;
}

bool replicator_end_transaction(Session *session, bool autocommit, bool commit)
{
  bool foreach_rv;
  replicator_row_end_st params;

  params.autocommit= autocommit;
  params.commit= commit;

  /* We need to free any data we did an init of for the session */
  foreach_rv= plugin_foreach(session, replicator_end_transaction_iterate,
                             DRIZZLE_REPLICATOR_PLUGIN, (void *) &params);

  return foreach_rv;
}

/*
  If you can do real 2PC this is your hook poing to know that the event is coming.

  Always true for the moment.

*/
bool replicator_prepare(Session *)
{
  return false;
}

/*
  Replicate statement.
*/
typedef struct replicator_statement_st
{
  const char *query;
  size_t query_length;
} replicator_statement_st;

/* We call this to end a statement (on each registered plugin) */
static bool replicator_statement_iterate(Session *session, plugin_ref plugin, void *p)
{
  replicator_t *repl= plugin_data(plugin, replicator_t *);
  replicator_statement_st *params= (replicator_statement_st *)p;

  /* call this loaded replicator plugin's replicator_func1 function pointer */
  if (repl && repl->statement)
  {
    if (repl->statement(session, params->query, params->query_length))
    {
      /* TRANSLATORS: The leading word "replicator" is the name
        of the plugin api, and so should not be translated. */
      errmsg_printf(ERRMSG_LVL_ERROR, _("replicator plugin '%s' statement() failed"),
                      (char *)plugin_name(plugin));
      return true;
    }
  }

  return false;
}

bool replicator_statement(Session *session, const char *query, size_t query_length)
{
  bool foreach_rv;
  replicator_statement_st params;
  
  params.query= query;
  params.query_length= query_length;

  /* We need to free any data we did an init of for the session */
  foreach_rv= plugin_foreach(session, replicator_statement_iterate,
                             DRIZZLE_REPLICATOR_PLUGIN, (void *) &params);

  return foreach_rv;
}