~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/log.cc

  • Committer: Brian Aker
  • Date: 2008-12-08 20:19:05 UTC
  • Revision ID: brian@tangent.org-20081208201905-ud33hfoidmke55iv
Removd dead TRX binlog code (we log straight... no attempt to optimize for
rollback).

Show diffs side-by-side

added added

removed removed

Lines of Context:
107
107
  void operator=(Mutex_sentry const&);
108
108
};
109
109
 
110
 
/*
111
 
  Helper class to store binary log transaction data.
112
 
*/
113
 
class binlog_trx_data {
114
 
public:
115
 
  binlog_trx_data()
116
 
    : at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
117
 
  {
118
 
    trans_log.end_of_file= max_binlog_cache_size;
119
 
  }
120
 
 
121
 
  ~binlog_trx_data()
122
 
  {
123
 
    assert(pending() == NULL);
124
 
    close_cached_file(&trans_log);
125
 
  }
126
 
 
127
 
  my_off_t position() const {
128
 
    return my_b_tell(&trans_log);
129
 
  }
130
 
 
131
 
  bool empty() const
132
 
  {
133
 
    return pending() == NULL && my_b_tell(&trans_log) == 0;
134
 
  }
135
 
 
136
 
  /*
137
 
    Truncate the transaction cache to a certain position. This
138
 
    includes deleting the pending event.
139
 
   */
140
 
  void truncate(my_off_t pos)
141
 
  {
142
 
    delete pending();
143
 
    set_pending(0);
144
 
    reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
145
 
    if (pos < before_stmt_pos)
146
 
      before_stmt_pos= MY_OFF_T_UNDEF;
147
 
 
148
 
    /*
149
 
      The only valid positions that can be truncated to are at the
150
 
      beginning of a statement. We are relying on this fact to be able
151
 
      to set the at_least_one_stmt flag correctly. In other word, if
152
 
      we are truncating to the beginning of the transaction cache,
153
 
      there will be no statements in the cache, otherwhise, we will
154
 
      have at least one statement in the transaction cache.
155
 
     */
156
 
    at_least_one_stmt= (pos > 0);
157
 
  }
158
 
 
159
 
  /*
160
 
    Reset the entire contents of the transaction cache, emptying it
161
 
    completely.
162
 
   */
163
 
  void reset() {
164
 
    if (!empty())
165
 
      truncate(0);
166
 
    before_stmt_pos= MY_OFF_T_UNDEF;
167
 
    trans_log.end_of_file= max_binlog_cache_size;
168
 
  }
169
 
 
170
 
  Rows_log_event *pending() const
171
 
  {
172
 
    return m_pending;
173
 
  }
174
 
 
175
 
  void set_pending(Rows_log_event *const pending)
176
 
  {
177
 
    m_pending= pending;
178
 
  }
179
 
 
180
 
  IO_CACHE trans_log;                         // The transaction cache
181
 
 
182
 
  /**
183
 
    Boolean that is true if there is at least one statement in the
184
 
    transaction cache.
185
 
  */
186
 
  bool at_least_one_stmt;
187
 
 
188
 
private:
189
 
  /*
190
 
    Pending binrows event. This event is the event where the rows are
191
 
    currently written.
192
 
   */
193
 
  Rows_log_event *m_pending;
194
 
 
195
 
public:
196
 
  /*
197
 
    Binlog position before the start of the current statement.
198
 
  */
199
 
  my_off_t before_stmt_pos;
200
 
};
201
 
 
202
110
handlerton *binlog_hton;
203
111
 
204
112
 
218
126
 */
219
127
 
220
128
static void
221
 
binlog_trans_log_savepos(Session *session, my_off_t *pos)
 
129
binlog_trans_log_savepos(Session *, my_off_t *pos)
222
130
{
223
131
  assert(pos != NULL);
224
 
  if (session_get_ha_data(session, binlog_hton) == NULL)
225
 
    session->binlog_setup_trx_data();
226
 
  binlog_trx_data *const trx_data=
227
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
228
 
  assert(drizzle_bin_log.is_open());
229
 
  *pos= trx_data->position();
 
132
 
230
133
  return;
231
134
}
232
135
 
253
156
  return 0;
254
157
}
255
158
 
256
 
static int binlog_close_connection(handlerton *, Session *session)
 
159
static int binlog_close_connection(handlerton *, Session *)
257
160
{
258
 
  binlog_trx_data *const trx_data=
259
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
260
 
  assert(trx_data->empty());
261
 
  session_set_ha_data(session, binlog_hton, NULL);
262
 
  trx_data->~binlog_trx_data();
263
 
  free((unsigned char*)trx_data);
 
161
 
264
162
  return 0;
265
163
}
266
164
 
267
 
/*
268
 
  End a transaction.
269
 
 
270
 
  SYNOPSIS
271
 
    binlog_end_trans()
272
 
 
273
 
    session      The thread whose transaction should be ended
274
 
    trx_data Pointer to the transaction data to use
275
 
    end_ev   The end event to use, or NULL
276
 
    all      True if the entire transaction should be ended, false if
277
 
             only the statement transaction should be ended.
278
 
 
279
 
  DESCRIPTION
280
 
 
281
 
    End the currently open transaction. The transaction can be either
282
 
    a real transaction (if 'all' is true) or a statement transaction
283
 
    (if 'all' is false).
284
 
 
285
 
    If 'end_ev' is NULL, the transaction is a rollback of only
286
 
    transactional tables, so the transaction cache will be truncated
287
 
    to either just before the last opened statement transaction (if
288
 
    'all' is false), or reset completely (if 'all' is true).
289
 
 */
290
 
static int
291
 
binlog_end_trans(Session *session, binlog_trx_data *trx_data,
292
 
                 Log_event *end_ev, bool all)
293
 
{
294
 
  int error=0;
295
 
  IO_CACHE *trans_log= &trx_data->trans_log;
296
 
 
297
 
  /*
298
 
    NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
299
 
    only transactional tables.  If the transaction contain changes to
300
 
    any non-transactiona tables, we need write the transaction and log
301
 
    a ROLLBACK last.
302
 
  */
303
 
  if (end_ev != NULL)
304
 
  {
305
 
    /*
306
 
      Doing a commit or a rollback including non-transactional tables,
307
 
      i.e., ending a transaction where we might write the transaction
308
 
      cache to the binary log.
309
 
 
310
 
      We can always end the statement when ending a transaction since
311
 
      transactions are not allowed inside stored functions.  If they
312
 
      were, we would have to ensure that we're not ending a statement
313
 
      inside a stored function.
314
 
     */
315
 
    session->binlog_flush_pending_rows_event(true);
316
 
 
317
 
    error= drizzle_bin_log.write(session, &trx_data->trans_log, end_ev);
318
 
    trx_data->reset();
319
 
 
320
 
    /*
321
 
      We need to step the table map version after writing the
322
 
      transaction cache to disk.
323
 
    */
324
 
    drizzle_bin_log.update_table_map_version();
325
 
    statistic_increment(binlog_cache_use, &LOCK_status);
326
 
    if (trans_log->disk_writes != 0)
327
 
    {
328
 
      statistic_increment(binlog_cache_disk_use, &LOCK_status);
329
 
      trans_log->disk_writes= 0;
330
 
    }
331
 
  }
332
 
  else
333
 
  {
334
 
    /*
335
 
      If rolling back an entire transaction or a single statement not
336
 
      inside a transaction, we reset the transaction cache.
337
 
 
338
 
      If rolling back a statement in a transaction, we truncate the
339
 
      transaction cache to remove the statement.
340
 
     */
341
 
    if (all || !(session->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
342
 
    {
343
 
      trx_data->reset();
344
 
 
345
 
      assert(!session->binlog_get_pending_rows_event());
346
 
      session->clear_binlog_table_maps();
347
 
    }
348
 
    else                                        // ...statement
349
 
      trx_data->truncate(trx_data->before_stmt_pos);
350
 
 
351
 
    /*
352
 
      We need to step the table map version on a rollback to ensure
353
 
      that a new table map event is generated instead of the one that
354
 
      was written to the thrown-away transaction cache.
355
 
    */
356
 
    drizzle_bin_log.update_table_map_version();
357
 
  }
358
 
 
359
 
  return(error);
360
 
}
361
 
 
362
165
static int binlog_prepare(handlerton *, Session *session, bool)
363
166
{
364
167
  /*
388
191
*/
389
192
static int binlog_commit(handlerton *, Session *session, bool all)
390
193
{
391
 
  binlog_trx_data *const trx_data=
392
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
393
 
 
394
 
  if (trx_data->empty())
395
 
  {
396
 
    // we're here because trans_log was flushed in DRIZZLE_BIN_LOG::log_xid()
397
 
    trx_data->reset();
398
 
    return(0);
399
 
  }
400
 
 
401
194
  /*
402
195
    Decision table for committing a transaction. The top part, the
403
196
    *conditions* represent different cases that can occur, and hte
457
250
    Otherwise, we accumulate the statement
458
251
  */
459
252
 
460
 
  uint64_t const in_transaction=
461
 
    session->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
462
 
 
463
 
 
464
 
  if ((in_transaction && (all || (!trx_data->at_least_one_stmt && session->transaction.stmt.modified_non_trans_table))) || (!in_transaction && !all))
 
253
  if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) 
465
254
  {
466
 
    Query_log_event qev(session, STRING_WITH_LEN("COMMIT"), true, false);
467
 
    qev.error_code= 0; // see comment in DRIZZLE_LOG::write(Session, IO_CACHE)
468
 
    /* TODO: Fix return type */
469
 
    int error= binlog_end_trans(session, trx_data, &qev, all);
470
 
    (void)replicator_end_transaction(session, all, true);
471
 
    return(error);
 
255
    return replicator_end_transaction(session, all, true);
472
256
  }
 
257
 
473
258
  return(0);
474
259
}
475
260
 
491
276
static int binlog_rollback(handlerton *, Session *session, bool all)
492
277
{
493
278
  int error=0;
494
 
  binlog_trx_data *const trx_data=
495
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
496
279
 
497
280
  /* TODO: Fix return type */
498
281
  (void)replicator_end_transaction(session, all, false);
499
282
 
500
 
  if (trx_data->empty()) 
501
 
  {
502
 
    trx_data->reset();
503
 
 
504
 
    return(0);
505
 
  }
506
 
 
507
 
  if ((all && session->transaction.all.modified_non_trans_table) ||
508
 
      (!all && session->transaction.stmt.modified_non_trans_table) ||
509
 
      (session->options & OPTION_KEEP_LOG))
510
 
  {
511
 
    /*
512
 
      We write the transaction cache with a rollback last if we have
513
 
      modified any non-transactional table. We do this even if we are
514
 
      committing a single statement that has modified a
515
 
      non-transactional table since it can have modified a
516
 
      transactional table in that statement as well, which needs to be
517
 
      rolled back on the slave.
518
 
    */
519
 
    Query_log_event qev(session, STRING_WITH_LEN("ROLLBACK"), true, false);
520
 
    qev.error_code= 0; // see comment in DRIZZLE_LOG::write(Session, IO_CACHE)
521
 
    error= binlog_end_trans(session, trx_data, &qev, all);
522
 
  }
523
 
  else if ((all && !session->transaction.all.modified_non_trans_table) ||
524
 
           (!all && !session->transaction.stmt.modified_non_trans_table))
525
 
  {
526
 
    /*
527
 
      If we have modified only transactional tables, we can truncate
528
 
      the transaction cache without writing anything to the binary
529
 
      log.
530
 
     */
531
 
    error= binlog_end_trans(session, trx_data, 0, all);
532
 
  }
533
 
 
534
283
  return(error);
535
284
}
536
285
 
2083
1832
          query_id_param >= session->binlog_evt_union.first_query_id);
2084
1833
}
2085
1834
 
2086
 
 
2087
 
/*
2088
 
  These functions are placed in this file since they need access to
2089
 
  binlog_hton, which has internal linkage.
2090
 
*/
2091
 
 
2092
 
int Session::binlog_setup_trx_data()
2093
 
{
2094
 
  binlog_trx_data *trx_data=
2095
 
    (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2096
 
 
2097
 
  if (trx_data)
2098
 
    return(0);                             // Already set up
2099
 
 
2100
 
  trx_data= (binlog_trx_data*) malloc(sizeof(binlog_trx_data));
2101
 
  memset(trx_data, 0, sizeof(binlog_trx_data));
2102
 
  if (!trx_data ||
2103
 
      open_cached_file(&trx_data->trans_log, drizzle_tmpdir,
2104
 
                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
2105
 
  {
2106
 
    free((unsigned char*)trx_data);
2107
 
    return(1);                      // Didn't manage to set it up
2108
 
  }
2109
 
  session_set_ha_data(this, binlog_hton, trx_data);
2110
 
 
2111
 
  trx_data= new (session_get_ha_data(this, binlog_hton)) binlog_trx_data;
2112
 
 
2113
 
  return(0);
2114
 
}
2115
 
 
2116
 
void Session::binlog_set_stmt_begin() {
2117
 
  binlog_trx_data *trx_data=
2118
 
    (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2119
 
 
2120
 
  /*
2121
 
    The call to binlog_trans_log_savepos() might create the trx_data
2122
 
    structure, if it didn't exist before, so we save the position
2123
 
    into an auto variable and then write it into the transaction
2124
 
    data for the binary log (i.e., trx_data).
2125
 
  */
2126
 
  my_off_t pos= 0;
2127
 
  binlog_trans_log_savepos(this, &pos);
2128
 
  trx_data= (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2129
 
  trx_data->before_stmt_pos= pos;
2130
 
}
2131
 
 
2132
 
 
2133
 
Rows_log_event*
2134
 
Session::binlog_get_pending_rows_event() const
2135
 
{
2136
 
  binlog_trx_data *const trx_data=
2137
 
    (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2138
 
  /*
2139
 
    This is less than ideal, but here's the story: If there is no
2140
 
    trx_data, prepare_pending_rows_event() has never been called
2141
 
    (since the trx_data is set up there). In that case, we just return
2142
 
    NULL.
2143
 
   */
2144
 
  return trx_data ? trx_data->pending() : NULL;
2145
 
}
2146
 
 
2147
 
void
2148
 
Session::binlog_set_pending_rows_event(Rows_log_event* ev)
2149
 
{
2150
 
  if (session_get_ha_data(this, binlog_hton) == NULL)
2151
 
    binlog_setup_trx_data();
2152
 
 
2153
 
  binlog_trx_data *const trx_data=
2154
 
    (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2155
 
 
2156
 
  assert(trx_data);
2157
 
  trx_data->set_pending(ev);
2158
 
}
2159
 
 
2160
 
 
2161
1835
/*
2162
1836
  Moves the last bunch of rows from the pending Rows event to the binlog
2163
1837
  (either cached binlog if transaction, or disk binlog). Sets a new pending
2164
1838
  event.
2165
1839
*/
2166
1840
int
2167
 
DRIZZLE_BIN_LOG::flush_and_set_pending_rows_event(Session *session,
2168
 
                                                Rows_log_event* event)
 
1841
DRIZZLE_BIN_LOG::flush_and_set_pending_rows_event(Session *, Rows_log_event*)
2169
1842
{
2170
1843
  assert(drizzle_bin_log.is_open());
2171
1844
 
2172
 
  int error= 0;
2173
 
 
2174
 
  binlog_trx_data *const trx_data=
2175
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
2176
 
 
2177
 
  assert(trx_data);
2178
 
 
2179
 
  if (Rows_log_event* pending= trx_data->pending())
2180
 
  {
2181
 
    IO_CACHE *file= &log_file;
2182
 
 
2183
 
    /*
2184
 
      Decide if we should write to the log file directly or to the
2185
 
      transaction log.
2186
 
    */
2187
 
    if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
2188
 
      file= &trx_data->trans_log;
2189
 
 
2190
 
    /*
2191
 
      If we are writing to the log file directly, we could avoid
2192
 
      locking the log. This does not work since we need to step the
2193
 
      m_table_map_version below, and that change has to be protected
2194
 
      by the LOCK_log mutex.
2195
 
    */
2196
 
    pthread_mutex_lock(&LOCK_log);
2197
 
 
2198
 
    /*
2199
 
      Write pending event to log file or transaction cache
2200
 
    */
2201
 
    if (pending->write(file))
2202
 
    {
2203
 
      pthread_mutex_unlock(&LOCK_log);
2204
 
      return(1);
2205
 
    }
2206
 
 
2207
 
    /*
2208
 
      We step the table map version if we are writing an event
2209
 
      representing the end of a statement.  We do this regardless of
2210
 
      wheather we write to the transaction cache or to directly to the
2211
 
      file.
2212
 
 
2213
 
      In an ideal world, we could avoid stepping the table map version
2214
 
      if we were writing to a transaction cache, since we could then
2215
 
      reuse the table map that was written earlier in the transaction
2216
 
      cache.  This does not work since STMT_END_F implies closing all
2217
 
      table mappings on the slave side.
2218
 
 
2219
 
      TODO: Find a solution so that table maps does not have to be
2220
 
      written several times within a transaction.
2221
 
     */
2222
 
    if (pending->get_flags(Rows_log_event::STMT_END_F))
2223
 
      ++m_table_map_version;
2224
 
 
2225
 
    delete pending;
2226
 
 
2227
 
    if (file == &log_file)
2228
 
    {
2229
 
      error= flush_and_sync();
2230
 
      if (!error)
2231
 
      {
2232
 
        signal_update();
2233
 
        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
2234
 
      }
2235
 
    }
2236
 
 
2237
 
    pthread_mutex_unlock(&LOCK_log);
2238
 
  }
2239
 
 
2240
 
  session->binlog_set_pending_rows_event(event);
2241
 
 
2242
 
  return(error);
 
1845
  return false;
2243
1846
}
2244
1847
 
2245
1848
/**
2272
1875
    we are inside a stored function, we do not end the statement since
2273
1876
    this will close all tables on the slave.
2274
1877
  */
2275
 
  bool const end_stmt= false;
2276
 
  session->binlog_flush_pending_rows_event(end_stmt);
2277
1878
 
2278
1879
  pthread_mutex_lock(&LOCK_log);
2279
1880
 
2297
1898
    }
2298
1899
 
2299
1900
    /*
2300
 
      Should we write to the binlog cache or to the binlog on disk?
2301
 
      Write to the binlog cache if:
2302
 
      - it is already not empty (meaning we're in a transaction; note that the
2303
 
     present event could be about a non-transactional table, but still we need
2304
 
     to write to the binlog cache in that case to handle updates to mixed
2305
 
     trans/non-trans table types the best possible in binlogging)
2306
 
      - or if the event asks for it (cache_stmt == TRUE).
2307
 
    */
2308
 
    if (opt_using_transactions && session)
2309
 
    {
2310
 
      if (session->binlog_setup_trx_data())
2311
 
        goto err;
2312
 
 
2313
 
      binlog_trx_data *const trx_data=
2314
 
        (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
2315
 
      IO_CACHE *trans_log= &trx_data->trans_log;
2316
 
      my_off_t trans_log_pos= my_b_tell(trans_log);
2317
 
      if (event_info->get_cache_stmt() || trans_log_pos != 0)
2318
 
      {
2319
 
        file= trans_log;
2320
 
      }
2321
 
      /*
2322
 
        TODO as Mats suggested, for all the cases above where we write to
2323
 
        trans_log, it sounds unnecessary to lock LOCK_log. We should rather
2324
 
        test first if we want to write to trans_log, and if not, lock
2325
 
        LOCK_log.
2326
 
      */
2327
 
    }
2328
 
 
2329
 
    /*
2330
1901
       Write the SQL command
2331
1902
     */
2332
1903
 
3508
3079
int TC_LOG_BINLOG::log_xid(Session *session, my_xid xid)
3509
3080
{
3510
3081
  Xid_log_event xle(session, xid);
3511
 
  binlog_trx_data *trx_data=
3512
 
    (binlog_trx_data*) session_get_ha_data(session, binlog_hton);
3513
3082
  /* TODO: Fix return type */
3514
 
  (void)replicator_end_transaction(session, true, true);
3515
3083
  /*
3516
3084
    We always commit the entire transaction when writing an XID. Also
3517
3085
    note that the return value is inverted.
 
3086
 
 
3087
    TODO: fix backasswards logic on this method
3518
3088
   */
3519
 
  return(!binlog_end_trans(session, trx_data, &xle, true));
 
3089
 
 
3090
  return replicator_end_transaction(session, true, true) ? false : true;
3520
3091
}
3521
3092
 
3522
3093
void TC_LOG_BINLOG::unlog(ulong, my_xid)