~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/serial_event_log/serial_event_log.cc

* New serial event log plugin

Implemented in /plugin/serial_event_log/.

Adds a very simple serialized event log to the server.  This simple
applier takes Command messages and writes them to a log file as it
received them.  Nothing complex for right now.

* New default replicator plugin

This plugin is extremely simple and merely passes a received Command
message on to all registered Appliers (of which the new serial event
log is one of those appliers)

The plugin is disabled by default.  It can be enabled on startup
with --default-replicator-enable.

* New command reader test program

There is a new test program in /drizzled/message/ which is similar to
the transaction_reader program but can read single Command messages, 
and not Transaction messages which contain a vector of Command messages.

* New serial_event_log test suite

The test case is very simple right now, but serves to show how plugin
test suites can be written, and how test programs in the server source
tree can be used in the drizzletest program language.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008-2009 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
/**
 
22
 * @file
 
23
 *
 
24
 * Defines the implementation of the default serial event log.
 
25
 *
 
26
 * @see drizzled/plugin/replicator.h
 
27
 * @see drizzled/plugin/applier.h
 
28
 *
 
29
 * @details
 
30
 *
 
31
 * Currently, this is a very simple implementation.  We have a global
 
32
 * lock on the file writer and write the events as the are received, 
 
33
 * first writing a 64-bit length and then the serialized transaction/command.
 
34
 *
 
35
 * @todo
 
36
 *
 
37
 * Possibly look at a scoreboard approach with multiple file segments.  For
 
38
 * right now, though, this is just a quick simple implementation to serve
 
39
 * as a skeleton and a springboard.
 
40
 */
 
41
 
 
42
#include "serial_event_log.h"
 
43
 
 
44
#include <drizzled/gettext.h>
 
45
#include <drizzled/message/transaction.pb.h>
 
46
 
 
47
#include <vector>
 
48
#include <string>
 
49
 
 
50
using namespace std;
 
51
 
 
52
/** Serial Event Log plugin system variable - The path to the log file used */
 
53
static char* sysvar_serial_event_log_file= NULL;
 
54
static const char DEFAULT_LOG_FILE_PATH[16]= "event.log"; /* In datadir... */
 
55
 
 
56
SerialEventLog::SerialEventLog(const char *in_log_file_path)
 
57
  : 
 
58
    drizzled::plugin::Applier(),
 
59
    state(SerialEventLog::OFFLINE),
 
60
    is_active(false),
 
61
    log_file_path(in_log_file_path)
 
62
{
 
63
  /* Setup our lock protection and our log file... */
 
64
  if (pthread_mutex_init(&lock, NULL) != 0)
 
65
  {
 
66
    errmsg_printf(ERRMSG_LVL_ERROR, _("Failed to initialize lock on serial event log.  Got error: %s"), strerror(errno));
 
67
    is_active= false;
 
68
    return;
 
69
  }
 
70
 
 
71
  log_file= open(log_file_path, O_APPEND|O_CREAT|O_SYNC|O_WRONLY, S_IRWXU);
 
72
  if (log_file == -1)
 
73
  {
 
74
    errmsg_printf(ERRMSG_LVL_ERROR, _("Failed to open serial event log file.  Got error: %s"), strerror(errno));
 
75
    is_active= false;
 
76
    return;
 
77
  }
 
78
 
 
79
  state= SerialEventLog::ONLINE;
 
80
  is_active= true;
 
81
}
 
82
 
 
83
SerialEventLog::~SerialEventLog()
 
84
{
 
85
  /* Clear up any resources we've consumed */
 
86
  if (is_active && state != SerialEventLog::CRASHED && log_file != -1)
 
87
  {
 
88
    (void) close(log_file);
 
89
  }
 
90
  if (pthread_mutex_destroy(&lock) != 0)
 
91
  {
 
92
    errmsg_printf(ERRMSG_LVL_ERROR, _("Failed to destroy lock on serial event log.  Got error: %s"), strerror(errno));
 
93
  }
 
94
}
 
95
 
 
96
bool SerialEventLog::isActive()
 
97
{
 
98
  return is_active;
 
99
}
 
100
 
 
101
void SerialEventLog::apply(drizzled::message::Command *to_apply)
 
102
{
 
103
  std::string buffer; /* Buffer we will write serialized command to */
 
104
  size_t length;
 
105
  size_t written;
 
106
 
 
107
  to_apply->SerializeToString(&buffer);
 
108
  length= buffer.length();
 
109
 
 
110
  pthread_mutex_lock(&lock);
 
111
 
 
112
  /* 
 
113
   * Quick safety...if an error occurs below, the log file will
 
114
   * not be active, therefore a caller could have been waiting 
 
115
   * to write...
 
116
   */
 
117
  if (unlikely(state == SerialEventLog::CRASHED))
 
118
  {
 
119
    pthread_mutex_unlock(&lock);
 
120
    return;
 
121
  }
 
122
 
 
123
  written= write(log_file, &length, sizeof(uint64_t));
 
124
  if (unlikely(written != sizeof(uint64_t)))
 
125
  {
 
126
    errmsg_printf(ERRMSG_LVL_ERROR, 
 
127
                  _("Failed to write full size of command.  Tried to write %" PRId64 ", but only wrote %" PRId64 ".  Error: %s"), 
 
128
                  (uint64_t) length, 
 
129
                  (uint64_t) written, 
 
130
                  strerror(errno));
 
131
    state= CRASHED;
 
132
    is_active= false;
 
133
    pthread_mutex_unlock(&lock);
 
134
    return;
 
135
  }
 
136
 
 
137
  written= write(log_file, buffer.c_str(), length);
 
138
  if (unlikely(written != length))
 
139
  {
 
140
    errmsg_printf(ERRMSG_LVL_ERROR, 
 
141
                  _("Failed to write full serialized command.  Tried to write %" PRId64 ", but only wrote %" PRId64 ".  Error: %s"), 
 
142
                  (uint64_t) length, 
 
143
                  (uint64_t) written, 
 
144
                  strerror(errno));
 
145
    state= CRASHED;
 
146
    is_active= false;
 
147
    pthread_mutex_unlock(&lock);
 
148
    return;
 
149
  }
 
150
  pthread_mutex_unlock(&lock);
 
151
}
 
152
 
 
153
static SerialEventLog *serial_event_log= NULL; /* The singleton serial log */
 
154
 
 
155
static int init(PluginRegistry &registry)
 
156
{
 
157
  serial_event_log= new SerialEventLog(sysvar_serial_event_log_file);
 
158
  registry.add(serial_event_log);
 
159
  return 0;
 
160
}
 
161
 
 
162
static int deinit(PluginRegistry &registry)
 
163
{
 
164
  if (serial_event_log)
 
165
  {
 
166
    registry.remove(serial_event_log);
 
167
    delete serial_event_log;
 
168
  }
 
169
  return 0;
 
170
}
 
171
 
 
172
static DRIZZLE_SYSVAR_STR(log_file,
 
173
                          sysvar_serial_event_log_file,
 
174
                          PLUGIN_VAR_READONLY,
 
175
                          N_("Path to the file to use for serial event log."),
 
176
                          NULL, /* check func */
 
177
                          NULL, /* update func*/
 
178
                          DEFAULT_LOG_FILE_PATH /* default */);
 
179
 
 
180
static struct st_mysql_sys_var* system_variables[]= {
 
181
  DRIZZLE_SYSVAR(log_file),
 
182
  NULL
 
183
};
 
184
 
 
185
drizzle_declare_plugin(serial_event_log)
 
186
{
 
187
  "serial_event_log",
 
188
  "0.1",
 
189
  "Jay Pipes",
 
190
  N_("Default Serial Event Log"),
 
191
  PLUGIN_LICENSE_GPL,
 
192
  init, /* Plugin Init */
 
193
  deinit, /* Plugin Deinit */
 
194
  NULL, /* status variables */
 
195
  system_variables, /* system variables */
 
196
  NULL    /* config options */
 
197
}
 
198
drizzle_declare_plugin_end;