~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/log.cc

  • Committer: Brian Aker
  • Date: 2009-04-13 16:22:40 UTC
  • mfrom: (971.1.78 mordred)
  • Revision ID: brian@gaz-20090413162240-ugi3gvhofmcuglzl
Merge Monty

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
 
 
17
 
/**
18
 
  @file
19
 
 
20
 
  @brief
21
 
  logging of commands
22
 
 
23
 
  @todo
24
 
    Abort logging when we get an error in reading or writing log files
25
 
*/
26
 
 
27
 
#include <drizzled/server_includes.h>
28
 
#include <drizzled/replicator.h>
29
 
#include <mysys/hash.h>
30
 
 
31
 
#include <mysys/my_dir.h>
32
 
#include <stdarg.h>
33
 
 
34
 
#include <drizzled/plugin.h>
35
 
#include <drizzled/error.h>
36
 
#include <drizzled/errmsg_print.h>
37
 
#include <drizzled/gettext.h>
38
 
#include <drizzled/data_home.h>
39
 
#include <drizzled/session.h>
40
 
#include <drizzled/handler.h>
41
 
 
42
 
#include <string>
43
 
 
44
 
using namespace std;
45
 
 
46
 
static const string engine_name("binlog");
47
 
 
48
 
StorageEngine *binlog_engine= NULL;
49
 
 
50
 
/*
51
 
  Save position of binary log transaction cache.
52
 
 
53
 
  SYNPOSIS
54
 
    binlog_trans_log_savepos()
55
 
 
56
 
    session      The thread to take the binlog data from
57
 
    pos      Pointer to variable where the position will be stored
58
 
 
59
 
  DESCRIPTION
60
 
 
61
 
    Save the current position in the binary log transaction cache into
62
 
    the variable pointed to by 'pos'
63
 
*/
64
 
 
65
 
static void
66
 
binlog_trans_log_savepos(Session *, my_off_t *pos)
67
 
{
68
 
  assert(pos != NULL);
69
 
 
70
 
  return;
71
 
}
72
 
 
73
 
 
74
 
class BinlogEngine : public StorageEngine
75
 
{
76
 
public:
77
 
  BinlogEngine(const string &name_arg)
78
 
    : StorageEngine(name_arg,
79
 
                    HTON_NOT_USER_SELECTABLE | HTON_HIDDEN,
80
 
                    sizeof(my_off_t)) {}
81
 
 
82
 
  virtual int close_connection(Session *)
83
 
  {
84
 
  
85
 
    return 0;
86
 
  }
87
 
  
88
 
  virtual int prepare(Session *session, bool)
89
 
  {
90
 
    /*
91
 
      do nothing.
92
 
      just pretend we can do 2pc, so that MySQL won't
93
 
      switch to 1pc.
94
 
      real work will be done in DRIZZLE_BIN_LOG::log_xid()
95
 
    */
96
 
  
97
 
    (void)replicator_prepare(session);
98
 
  
99
 
    return 0;
100
 
  }
101
 
  
102
 
  /**
103
 
    This function is called once after each statement.
104
 
  
105
 
    It has the responsibility to flush the transaction cache to the
106
 
    binlog file on commits.
107
 
  
108
 
    @param engine  The binlog StorageEngine.
109
 
    @param session   The client thread that executes the transaction.
110
 
    @param all   This is @c true if this is a real transaction commit, and
111
 
                 @false otherwise.
112
 
  
113
 
    @see StorageEngine::commit
114
 
  */
115
 
  virtual int commit(Session *session, bool all)
116
 
  {
117
 
    /*
118
 
      Decision table for committing a transaction. The top part, the
119
 
      *conditions* represent different cases that can occur, and hte
120
 
      bottom part, the *actions*, represent what should be done in that
121
 
      particular case.
122
 
  
123
 
      Real transaction        'all' was true
124
 
  
125
 
      Statement in cache      There were at least one statement in the
126
 
                              transaction cache
127
 
  
128
 
      In transaction          We are inside a transaction
129
 
  
130
 
      Stmt modified non-trans The statement being committed modified a
131
 
                              non-transactional table
132
 
  
133
 
      All modified non-trans  Some statement before this one in the
134
 
                              transaction modified a non-transactional
135
 
                              table
136
 
  
137
 
  
138
 
      =============================  = = = = = = = = = = = = = = = =
139
 
      Real transaction               N N N N N N N N N N N N N N N N
140
 
      Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
141
 
      In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
142
 
      Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
143
 
      All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
144
 
  
145
 
      Action: (C)ommit/(A)ccumulate  C C - C A C - C - - - - A A - A
146
 
      =============================  = = = = = = = = = = = = = = = =
147
 
  
148
 
  
149
 
      =============================  = = = = = = = = = = = = = = = =
150
 
      Real transaction               Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
151
 
      Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
152
 
      In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
153
 
      Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
154
 
      All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
155
 
  
156
 
      (C)ommit/(A)ccumulate/(-)      - - - - C C - C - - - - C C - C
157
 
      =============================  = = = = = = = = = = = = = = = =
158
 
  
159
 
      In other words, we commit the transaction if and only if both of
160
 
      the following are true:
161
 
       - We are not in a transaction and committing a statement
162
 
  
163
 
       - We are in a transaction and one (or more) of the following are
164
 
         true:
165
 
  
166
 
         - A full transaction is committed
167
 
  
168
 
           OR
169
 
  
170
 
         - A non-transactional statement is committed and there is
171
 
           no statement cached
172
 
  
173
 
      Otherwise, we accumulate the statement
174
 
    */
175
 
  
176
 
    if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) 
177
 
    {
178
 
      return replicator_end_transaction(session, all, true);
179
 
    }
180
 
  
181
 
    return(0);
182
 
  }
183
 
  
184
 
  /**
185
 
    This function is called when a transaction involving a transactional
186
 
    table is rolled back.
187
 
  
188
 
    It has the responsibility to flush the transaction cache to the
189
 
    binlog file. However, if the transaction does not involve
190
 
    non-transactional tables, nothing needs to be logged.
191
 
  
192
 
    @param engine  The binlog StorageEngine.
193
 
    @param session   The client thread that executes the transaction.
194
 
    @param all   This is @c true if this is a real transaction rollback, and
195
 
                 @false otherwise.
196
 
  
197
 
    @see StorageEngine::rollback
198
 
  */
199
 
  virtual int rollback(Session *session, bool all)
200
 
  {
201
 
    int error=0;
202
 
  
203
 
    /* TODO: Fix return type */
204
 
    (void)replicator_end_transaction(session, all, false);
205
 
  
206
 
    return(error);
207
 
  }
208
 
  
209
 
  /**
210
 
    @note
211
 
    How do we handle this (unlikely but legal) case:
212
 
    @verbatim
213
 
      [transaction] + [update to non-trans table] + [rollback to savepoint] ?
214
 
    @endverbatim
215
 
    The problem occurs when a savepoint is before the update to the
216
 
    non-transactional table. Then when there's a rollback to the savepoint, if we
217
 
    simply truncate the binlog cache, we lose the part of the binlog cache where
218
 
    the update is. If we want to not lose it, we need to write the SAVEPOINT
219
 
    command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
220
 
    is easy: it's just write at the end of the binlog cache, but the former
221
 
    should be *inserted* to the place where the user called SAVEPOINT. The
222
 
    solution is that when the user calls SAVEPOINT, we write it to the binlog
223
 
    cache (so no need to later insert it). As transactions are never intermixed
224
 
    in the binary log (i.e. they are serialized), we won't have conflicts with
225
 
    savepoint names when using mysqlbinlog or in the slave SQL thread.
226
 
    Then when ROLLBACK TO SAVEPOINT is called, if we updated some
227
 
    non-transactional table, we don't truncate the binlog cache but instead write
228
 
    ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
229
 
    will chop the SAVEPOINT command from the binlog cache, which is good as in
230
 
    that case there is no need to have it in the binlog).
231
 
  */
232
 
  
233
 
  virtual int savepoint_set_hook(Session *session, void *sv)
234
 
  {
235
 
    bool error;
236
 
    binlog_trans_log_savepos(session, (my_off_t*) sv);
237
 
    /* Write it to the binary log */
238
 
  
239
 
    error= replicator_statement(session, session->query, session->query_length);
240
 
  
241
 
    return(error);
242
 
  }
243
 
  
244
 
  virtual int savepoint_rollback_hook(Session *session, void *)
245
 
  {
246
 
    bool error;
247
 
  
248
 
    error= replicator_statement(session, session->query, session->query_length);
249
 
  
250
 
    return error;
251
 
  }
252
 
 
253
 
  virtual handler* create(TABLE_SHARE*, MEM_ROOT*)
254
 
  {
255
 
    return NULL;
256
 
  }
257
 
 
258
 
 
259
 
};
260
 
 
261
 
/*
262
 
  this function is mostly a placeholder.
263
 
  conceptually, binlog initialization (now mostly done in DRIZZLE_BIN_LOG::open)
264
 
  should be moved here.
265
 
*/
266
 
 
267
 
int binlog_init(void *p)
268
 
{
269
 
  StorageEngine** engine= static_cast<StorageEngine **>(p);
270
 
 
271
 
  if (binlog_engine == NULL)
272
 
  {
273
 
    binlog_engine= new BinlogEngine(engine_name);
274
 
  }
275
 
 
276
 
  *engine= binlog_engine;
277
 
 
278
 
  return 0;
279
 
}
280
 
 
281
 
drizzle_declare_plugin(binlog)
282
 
{
283
 
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
284
 
  "binlog",
285
 
  "1.0",
286
 
  "MySQL AB",
287
 
  "This is a pseudo storage engine to represent the binlog in a transaction",
288
 
  PLUGIN_LICENSE_GPL,
289
 
  binlog_init, /* Plugin Init */
290
 
  NULL, /* Plugin Deinit */
291
 
  NULL,                       /* status variables                */
292
 
  NULL,                       /* system variables                */
293
 
  NULL                        /* config options                  */
294
 
}
295
 
drizzle_declare_plugin_end;