~drizzle-trunk/drizzle/development

1039.5.1 by Jay Pipes
* New serial event log plugin
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
5
 *  Copyright (C) 2010 Jay Pipes <jaypipes@gmail.com>
1039.5.1 by Jay Pipes
* New serial event log plugin
6
 *
1143.2.10 by Jay Pipes
Phase 2 new replication work:
7
 *  Authors:
8
 *
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
9
 *    Jay Pipes <jaypipes@gmail.com.com>
1143.2.10 by Jay Pipes
Phase 2 new replication work:
10
 *
1039.5.1 by Jay Pipes
* New serial event log plugin
11
 *  This program is free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  This program is distributed in the hope that it will be useful,
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 *  GNU General Public License for more details.
20
 *
21
 *  You should have received a copy of the GNU General Public License
22
 *  along with this program; if not, write to the Free Software
23
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24
 */
25
26
/**
27
 * @file
28
 *
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
29
 * Defines the implementation of the transaction log file descriptor.
1039.5.1 by Jay Pipes
* New serial event log plugin
30
 *
31
 * @details
32
 *
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
33
 * Currently, the transaction log file uses a simple, single-file, append-only
34
 * format.
1039.5.9 by Jay Pipes
Cleans up command_reader.cc to not call unecessary memset and to properly check all calls to read(). In addition, adds comments describing the atomic operations used in the serial event log plugin.
35
 *
36
 * We have an atomic off_t called log_offset which keeps track of the 
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
37
 * offset into the log file for writing the next log entry.  The log
38
 * entries are written, one after the other, in the following way:
39
 *
1405.4.5 by Jay Pipes
Changes Query_id to start at 0, not 1, since increment() will make the first Query ID 2, not 1.
40
 * <pre>
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
41
 * --------------------------------------
42
 * |<- 4 bytes ->|<- # Bytes of Entry ->|
43
 * --------------------------------------
44
 * |  Entry Type |  Serialized Entry    |
45
 * --------------------------------------
1405.4.5 by Jay Pipes
Changes Query_id to start at 0, not 1, since increment() will make the first Query ID 2, not 1.
46
 * </pre>
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
47
 *
48
 * The Entry Type is an integer defined as an enumeration in the 
49
 * /drizzled/message/transaction.proto file called TransactionLogEntry::Type.
50
 *
51
 * Each transaction log entry type is written to the log differently.  Here,
52
 * we cover the format of each log entry type.
53
 *
54
 * Committed and Prepared Transaction Log Entries
55
 * -----------------------------------------------
1405.4.5 by Jay Pipes
Changes Query_id to start at 0, not 1, since increment() will make the first Query ID 2, not 1.
56
 * 
57
 * <pre>
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
58
 * ------------------------------------------------------------------
59
 * |<- 4 bytes ->|<- # Bytes of Transaction Message ->|<- 4 bytes ->|
60
 * ------------------------------------------------------------------
61
 * |   Length    |   Serialized Transaction Message   |   Checksum  |
62
 * ------------------------------------------------------------------
1405.4.5 by Jay Pipes
Changes Query_id to start at 0, not 1, since increment() will make the first Query ID 2, not 1.
63
 * </pre>
1039.5.46 by Jay Pipes
Tiny style and comment cleanups.
64
 *
1039.5.1 by Jay Pipes
* New serial event log plugin
65
 * @todo
66
 *
67
 * Possibly look at a scoreboard approach with multiple file segments.  For
68
 * right now, though, this is just a quick simple implementation to serve
69
 * as a skeleton and a springboard.
70
 */
71
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
72
#include <config.h>
1143.2.10 by Jay Pipes
Phase 2 new replication work:
73
#include "transaction_log.h"
1039.5.1 by Jay Pipes
* New serial event log plugin
74
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
75
#include <sys/stat.h>
76
#include <fcntl.h>
1130.1.2 by Monty Taylor
Re-org'd the replication stuff into slots.
77
#include <unistd.h>
1273.21.3 by Jay Pipes
Add errno.h to a few files. Apparently, this is necessary on OSX.
78
#include <errno.h>
1130.1.2 by Monty Taylor
Re-org'd the replication stuff into slots.
79
80
#include <vector>
81
#include <string>
82
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
83
#include <drizzled/internal/my_sys.h> /* for internal::my_sync */
84
#include <drizzled/errmsg_print.h>
1039.5.1 by Jay Pipes
* New serial event log plugin
85
#include <drizzled/gettext.h>
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
86
#include <drizzled/message/transaction.pb.h>
1405.4.7 by Jay Pipes
* Fixes drizzled's atomics:
87
#include <drizzled/transaction_services.h>
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
88
#include <drizzled/algorithm/crc32.h>
89
90
#include <google/protobuf/io/coded_stream.h>
1039.5.1 by Jay Pipes
* New serial event log plugin
91
92
using namespace std;
1039.5.39 by Jay Pipes
This patch does a couple things in preparation for publisher and
93
using namespace drizzled;
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
94
using namespace google;
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
95
96
TransactionLog *transaction_log= NULL; /* The singleton transaction log */
97
2353.2.5 by Stewart Smith
fix TransactionLog constructor for const parameter
98
TransactionLog::TransactionLog(const string &in_log_file_path,
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
99
                               uint32_t in_flush_frequency,
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
100
                               bool in_do_checksum) : 
1039.5.39 by Jay Pipes
This patch does a couple things in preparation for publisher and
101
    state(OFFLINE),
1143.3.4 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log:
102
    log_file_path(in_log_file_path),
103
    has_error(false),
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
104
    error_message(),
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
105
    flush_frequency(in_flush_frequency),
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
106
    do_checksum(in_do_checksum)
1039.5.1 by Jay Pipes
* New serial event log plugin
107
{
1039.5.5 by Jay Pipes
This commit does two things:
108
  /* Setup our log file and determine the next write offset... */
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
109
  log_file= open(log_file_path.c_str(), O_APPEND|O_CREAT|O_SYNC|O_WRONLY, S_IRWXU);
1039.5.1 by Jay Pipes
* New serial event log plugin
110
  if (log_file == -1)
111
  {
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
112
    char errmsg[STRERROR_MAX];
113
    strerror_r(errno, errmsg, sizeof(errmsg));
1143.3.4 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log:
114
    error_message.assign(_("Failed to open transaction log file "));
115
    error_message.append(log_file_path);
116
    error_message.append("  Got error: ");
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
117
    error_message.append(errmsg);
1143.3.4 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log:
118
    error_message.push_back('\n');
119
    has_error= true;
1039.5.1 by Jay Pipes
* New serial event log plugin
120
    return;
121
  }
122
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
123
  /* For convenience, grab the log file name from the path */
1143.3.3 by Jay Pipes
Fix stupid error in calculation of filename vs. filepath in transaction log.
124
  if (log_file_path.find_first_of('/') != string::npos)
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
125
  {
1143.3.3 by Jay Pipes
Fix stupid error in calculation of filename vs. filepath in transaction log.
126
    /* Strip to last / */
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
127
    string tmp;
1143.3.3 by Jay Pipes
Fix stupid error in calculation of filename vs. filepath in transaction log.
128
    tmp= log_file_path.substr(log_file_path.find_last_of('/') + 1);
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
129
    log_file_name.assign(tmp);
130
  }
1143.3.3 by Jay Pipes
Fix stupid error in calculation of filename vs. filepath in transaction log.
131
  else
132
    log_file_name.assign(log_file_path);
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
133
1039.5.5 by Jay Pipes
This commit does two things:
134
  /* 
135
   * The offset of the next write is the current position of the log
136
   * file, since it's opened in append mode...
137
   */
138
  log_offset= lseek(log_file, 0, SEEK_END);
139
1039.5.39 by Jay Pipes
This patch does a couple things in preparation for publisher and
140
  state= ONLINE;
1039.5.1 by Jay Pipes
* New serial event log plugin
141
}
142
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
143
uint8_t *TransactionLog::packTransactionIntoLogEntry(const message::Transaction &trx,
144
                                                     uint8_t *buffer,
145
                                                     uint32_t *checksum_out)
146
{
147
  uint8_t *orig_buffer= buffer;
148
  size_t message_byte_length= trx.ByteSize();
149
150
  /*
151
   * Write the header information, which is the message type and
152
   * the length of the transaction message into the buffer
153
   */
154
  buffer= protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(
155
      static_cast<uint32_t>(ReplicationServices::TRANSACTION), buffer);
156
  buffer= protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(
157
      static_cast<uint32_t>(message_byte_length), buffer);
158
  
159
  /*
160
   * Now write the serialized transaction message, followed
161
   * by the optional checksum into the buffer.
162
   */
163
  buffer= trx.SerializeWithCachedSizesToArray(buffer);
164
165
  if (do_checksum)
166
  {
167
    *checksum_out= drizzled::algorithm::crc32(
168
        reinterpret_cast<char *>(buffer) - message_byte_length, message_byte_length);
169
  }
170
  else
171
    *checksum_out= 0;
172
173
  /* We always write in network byte order */
174
  buffer= protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(*checksum_out, buffer);
175
  /* Reset the pointer back to its original location... */
176
  buffer= orig_buffer;
177
  return orig_buffer;
178
}
179
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
180
off_t TransactionLog::writeEntry(const uint8_t *data, size_t data_length)
1039.5.1 by Jay Pipes
* New serial event log plugin
181
{
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
182
  ssize_t written= 0;
1039.5.1 by Jay Pipes
* New serial event log plugin
183
1039.5.6 by Jay Pipes
Changes the way the log_offset is atomically incremented and its value retrieved. Hopefully, this removes any race condition for the variable's contents, but there is a note in the code describing my concern about a possible race condition.
184
  /*
185
   * Do an atomic increment on the offset of the log file position
186
   */
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
187
  off_t cur_offset= log_offset.fetch_and_add(static_cast<off_t>(data_length));
1039.5.35 by Jay Pipes
Ensure std::string buffer is initialized to a blank string, otherwise crybaby Solaris segfaults.
188
1039.5.1 by Jay Pipes
* New serial event log plugin
189
  /* 
1143.2.15 by Jay Pipes
This patch does the following:
190
   * Quick safety...if an error occurs above in another writer, the log 
191
   * file will be in a crashed state.
1039.5.1 by Jay Pipes
* New serial event log plugin
192
   */
1039.5.39 by Jay Pipes
This patch does a couple things in preparation for publisher and
193
  if (unlikely(state == CRASHED))
1143.2.15 by Jay Pipes
This patch does the following:
194
  {
195
    /* 
196
     * Reset the log's offset in case we want to produce a decent error message including
197
     * the original offset where an error occurred.
198
     */
199
    log_offset= cur_offset;
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
200
    return log_offset;
1143.2.15 by Jay Pipes
This patch does the following:
201
  }
202
203
  /* Write the full buffer in one swoop */
1039.5.44 by Jay Pipes
Adds CRC32 checksumming to Command Log plugin (replication logging)
204
  do
205
  {
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
206
    written= pwrite(log_file, data, data_length, cur_offset);
1039.5.44 by Jay Pipes
Adds CRC32 checksumming to Command Log plugin (replication logging)
207
  }
208
  while (written == -1 && errno == EINTR); /* Just retry the write when interrupted by a signal... */
209
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
210
  if (unlikely(written != static_cast<ssize_t>(data_length)))
1039.5.44 by Jay Pipes
Adds CRC32 checksumming to Command Log plugin (replication logging)
211
  {
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
212
    char errmsg[STRERROR_MAX];
213
    strerror_r(errno, errmsg, sizeof(errmsg));
2126.3.3 by Brian Aker
Merge in error message rework. Many error messages are fixed in this patch.
214
    errmsg_printf(error::ERROR, 
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
215
                  _("Failed to write full size of log entry.  Tried to write %" PRId64
1143.2.12 by Jay Pipes
Fixes 64-bit length encoding to be 32-bit, which is what is supported by GPB. We will need to use a segment strategy for large blob records.
216
                    " bytes at offset %" PRId64 ", but only wrote %" PRId32 " bytes.  Error: %s\n"), 
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
217
                  static_cast<int64_t>(data_length),
1143.2.15 by Jay Pipes
This patch does the following:
218
                  static_cast<int64_t>(cur_offset),
1948.1.6 by Monty Taylor
Re-enabled -Wformat and then cleaned up the carnage.
219
                  static_cast<int32_t>(written), 
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
220
                  errmsg);
1143.2.15 by Jay Pipes
This patch does the following:
221
    state= CRASHED;
222
    /* 
223
     * Reset the log's offset in case we want to produce a decent error message including
224
     * the original offset where an error occurred.
225
     */
226
    log_offset= cur_offset;
227
  }
1143.2.29 by Jay Pipes
Added fdatasync() calls to transaction_log.cc. Not sure how nobody caught this :)
228
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
229
  int error_code= syncLogFile();
1143.2.29 by Jay Pipes
Added fdatasync() calls to transaction_log.cc. Not sure how nobody caught this :)
230
231
  if (unlikely(error_code != 0))
232
  {
2126.3.3 by Brian Aker
Merge in error message rework. Many error messages are fixed in this patch.
233
    sql_perror(_("Failed to sync log file."));
1143.2.29 by Jay Pipes
Added fdatasync() calls to transaction_log.cc. Not sure how nobody caught this :)
234
  }
2126.3.3 by Brian Aker
Merge in error message rework. Many error messages are fixed in this patch.
235
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
236
  return cur_offset;
1039.5.1 by Jay Pipes
* New serial event log plugin
237
}
238
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
239
int TransactionLog::syncLogFile()
240
{
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
241
  switch (flush_frequency)
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
242
  {
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
243
  case FLUSH_FREQUENCY_EVERY_WRITE:
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
244
    return internal::my_sync(log_file, 0);
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
245
  case FLUSH_FREQUENCY_EVERY_SECOND:
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
246
    {
247
      time_t now_time= time(NULL);
248
      if (last_sync_time <= (now_time - 1))
249
      {
250
        last_sync_time= now_time;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
251
        return internal::my_sync(log_file, 0);
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
252
      }
253
      return 0;
254
    }
1726.2.1 by Vijay Samuel
Merge changes to transaction_log. Changed --transaction-log.sync-method to --transaction-log.flush-frequency
255
  case FLUSH_FREQUENCY_OS:
1143.4.13 by Jay Pipes
This patch adds support for a new transaction log configuration/CLI
256
  default:
257
    return 0;
258
  }
259
}
260
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
261
const string &TransactionLog::getLogFilename()
262
{
263
  return log_file_name;
264
}
265
266
const string &TransactionLog::getLogFilepath()
267
{
268
  return log_file_path;
269
}
270
1143.2.10 by Jay Pipes
Phase 2 new replication work:
271
void TransactionLog::truncate()
1039.5.17 by Jay Pipes
Adds log truncation debugging functionality to the serial event log plugin. Cleans up the serial event log test suite to properly include and output result files.
272
{
273
  /* 
1039.5.20 by Jay Pipes
Addition fixups based on Stew's suggestions:
274
   * @note
275
   *
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
276
   * This is NOT THREAD SAFE! DEBUG/TEST code only!
1039.5.17 by Jay Pipes
Adds log truncation debugging functionality to the serial event log plugin. Cleans up the serial event log test suite to properly include and output result files.
277
   */
278
  log_offset= (off_t) 0;
1039.5.23 by Jay Pipes
Added explicit call to atomic<>.fetch_and_add() method. Added while loop on EINTR for ftruncate and no ignore of the result. Added static to methods in command_reader.cc.
279
  int result;
280
  do
281
  {
282
    result= ftruncate(log_file, log_offset);
283
  }
284
  while (result == -1 && errno == EINTR);
1039.5.17 by Jay Pipes
Adds log truncation debugging functionality to the serial event log plugin. Cleans up the serial event log test suite to properly include and output result files.
285
}
286
1143.2.10 by Jay Pipes
Phase 2 new replication work:
287
bool TransactionLog::findLogFilenameContainingTransactionId(const ReplicationServices::GlobalTransactionId&,
1143.3.2 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log - Phase 1. Does not currently output correctly. Pushing for some help.. :)
288
                                                            string &out_filename) const
1039.5.41 by Jay Pipes
Adds a new plugin class interface for a reader of Command messages,
289
{
290
  /* 
291
   * Currently, we simply return the single logfile name
292
   * Eventually, we'll have an index/hash with upper and
293
   * lower bounds to look up a log file with a transaction id
294
   */
295
  out_filename.assign(log_file_path);
296
  return true;
297
}
298
1143.3.4 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log:
299
bool TransactionLog::hasError() const
300
{
301
  return has_error;
302
}
303
304
void TransactionLog::clearError()
305
{
306
  has_error= false;
307
  error_message.clear();
308
}
309
1273.22.1 by Jay Pipes
Completes the blueprint for refactoring applier out of log descriptor.
310
const string &TransactionLog::getErrorMessage() const
1143.3.4 by Jay Pipes
Adds INFORMATION_SCHEMA views for the transaction log:
311
{
312
  return error_message;
313
}
1405.4.1 by Jay Pipes
Adds a vector of write buffers to the transaction log applier
314
315
size_t TransactionLog::getLogEntrySize(const message::Transaction &trx)
316
{
317
  return trx.ByteSize() + HEADER_TRAILER_BYTES;
318
}