~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_gearman/logging_gearman.cc

This patch completes the first step in the splitting of
the XA resource manager API from the storage engine API,
as outlined in the specification here:

http://drizzle.org/wiki/XaStorageEngine

* Splits plugin::StorageEngine into a base StorageEngine
  class and two derived classes, TransactionalStorageEngine
  and XaStorageEngine.  XaStorageEngine derives from
  TransactionalStorageEngine and creates the XA Resource
  Manager API for storage engines.

  - The methods moved from StorageEngine to TransactionalStorageEngine
    include releaseTemporaryLatches(), startConsistentSnapshot(), 
    commit(), rollback(), setSavepoint(), releaseSavepoint(),
    rollbackToSavepoint() and hasTwoPhaseCommit()
  - The methods moved from StorageEngine to XaStorageEngine
    include recover(), commitXid(), rollbackXid(), and prepare()

* Places all static "EngineVector"s into their proper
  namespaces (typedefs belong in header files, not implementation files)
  and places all static methods corresponding
  to either only transactional engines or only XA engines
  into their respective files in /drizzled/plugin/

* Modifies the InnoDB "handler" files to extend plugin::XaStorageEngine
  and not plugin::StorageEngine

The next step, as outlined in the wiki spec page above, is to isolate
the XA Resource Manager API into its own plugin class and modify
plugin::XaStorageEngine to implement plugin::XaResourceManager via
composition.  This is necessary to enable building plugins which can
participate in an XA transaction *without having to have that plugin
implement the entire storage engine API*

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008, 2009 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008,2009 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
17
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include <config.h>
21
 
 
22
 
#include <boost/scoped_array.hpp>
23
 
 
 
20
#include "config.h"
24
21
#include <drizzled/plugin/logging.h>
25
22
#include <drizzled/gettext.h>
26
23
#include <drizzled/session.h>
27
 
#include <drizzled/errmsg_print.h>
28
 
#include <boost/date_time.hpp>
29
 
#include <boost/program_options.hpp>
30
 
#include <drizzled/module/option_map.h>
 
24
 
31
25
#include <libgearman/gearman.h>
32
26
#include <limits.h>
 
27
#include <sys/time.h>
33
28
#include <sys/types.h>
34
29
#include <sys/stat.h>
35
30
#include <fcntl.h>
36
 
#include <cstdio>
37
 
#include <cerrno>
38
 
#include <memory>
39
 
 
40
 
 
41
 
namespace drizzle_plugin
42
 
{
43
 
 
44
 
namespace po= boost::program_options;
 
31
 
 
32
 
 
33
using namespace drizzled;
 
34
 
45
35
 
46
36
/* TODO make this dynamic as needed */
47
37
static const int MAX_MSG_LEN= 32*1024;
48
38
 
 
39
static bool sysvar_logging_gearman_enable= false;
 
40
static char* sysvar_logging_gearman_host= NULL;
 
41
static char* sysvar_logging_gearman_function= NULL;
 
42
 
 
43
 
 
44
/* stolen from mysys/my_getsystime
 
45
   until the Session has a good utime "now" we can use
 
46
   will have to use this instead */
 
47
 
 
48
static uint64_t get_microtime()
 
49
{
 
50
#if defined(HAVE_GETHRTIME)
 
51
  return gethrtime()/1000;
 
52
#else
 
53
  uint64_t newtime;
 
54
  struct timeval t;
 
55
  /*
 
56
    The following loop is here because gettimeofday may fail on some systems
 
57
  */
 
58
  while (gettimeofday(&t, NULL) != 0) {}
 
59
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
 
60
  return newtime;
 
61
#endif  /* defined(HAVE_GETHRTIME) */
 
62
}
 
63
 
49
64
/* quote a string to be safe to include in a CSV line
50
65
   that means backslash quoting all commas, doublequotes, backslashes,
51
66
   and all the ASCII unprintable characters
154
169
  return dst;
155
170
}
156
171
 
157
 
class LoggingGearman :
158
 
  public drizzled::plugin::Logging
 
172
class LoggingGearman : public plugin::Logging
159
173
{
160
174
 
161
 
  const std::string _host;
162
 
  const std::string _function;
163
 
 
164
 
  int _gearman_client_ok;
165
 
  gearman_client_st _gearman_client;
166
 
 
167
 
  LoggingGearman();
168
 
  LoggingGearman(const LoggingGearman&);
 
175
  int gearman_client_ok;
 
176
  gearman_client_st gearman_client;
169
177
 
170
178
public:
171
179
 
172
 
  LoggingGearman(const std::string &host,
173
 
                 const std::string &function) :
174
 
    drizzled::plugin::Logging("LoggingGearman"),
175
 
    _host(host),
176
 
    _function(function),
177
 
    _gearman_client_ok(0),
178
 
    _gearman_client()
 
180
  LoggingGearman()
 
181
    : plugin::Logging("LoggingGearman"),
 
182
      gearman_client_ok(0)
179
183
  {
180
184
    gearman_return_t ret;
181
185
 
182
 
 
183
 
    if (gearman_client_create(&_gearman_client) == NULL)
 
186
    if (sysvar_logging_gearman_enable == false)
 
187
      return;
 
188
 
 
189
    if (sysvar_logging_gearman_host == NULL)
 
190
      return;
 
191
 
 
192
 
 
193
    if (gearman_client_create(&gearman_client) == NULL)
184
194
    {
185
 
      drizzled::sql_perror(_("fail gearman_client_create()"));
 
195
      errmsg_printf(ERRMSG_LVL_ERROR, _("fail gearman_client_create(): %s"),
 
196
                    strerror(errno));
186
197
      return;
187
198
    }
188
199
 
189
200
    /* TODO, be able to override the port */
190
201
    /* TODO, be able send to multiple servers */
191
 
    ret= gearman_client_add_server(&_gearman_client,
192
 
                                   host.c_str(), 0);
 
202
    ret= gearman_client_add_server(&gearman_client,
 
203
                                   sysvar_logging_gearman_host, 0);
193
204
    if (ret != GEARMAN_SUCCESS)
194
205
    {
195
 
      drizzled::errmsg_printf(drizzled::error::ERROR, _("fail gearman_client_add_server(): %s"),
196
 
                              gearman_client_error(&_gearman_client));
 
206
      errmsg_printf(ERRMSG_LVL_ERROR, _("fail gearman_client_add_server(): %s"),
 
207
                    gearman_client_error(&gearman_client));
197
208
      return;
198
209
    }
199
210
 
200
 
    _gearman_client_ok= 1;
 
211
    gearman_client_ok= 1;
201
212
 
202
213
  }
203
214
 
204
215
  ~LoggingGearman()
205
216
  {
206
 
    if (_gearman_client_ok)
 
217
    if (gearman_client_ok)
207
218
    {
208
 
      gearman_client_free(&_gearman_client);
 
219
      gearman_client_free(&gearman_client);
209
220
    }
210
221
  }
211
222
 
212
 
  virtual bool post(drizzled::Session *session)
 
223
  virtual bool post(Session *session)
213
224
  {
214
 
    boost::scoped_array<char> msgbuf(new char[MAX_MSG_LEN]);
 
225
    char msgbuf[MAX_MSG_LEN];
215
226
    int msgbuf_len= 0;
216
227
  
217
228
    assert(session != NULL);
220
231
       but that crashes the server, so for now, we just lie a little bit
221
232
    */
222
233
 
223
 
    if (not _gearman_client_ok)
 
234
    if (!gearman_client_ok)
224
235
        return false;
225
236
  
226
 
    /* 
227
 
      TODO, the session object should have a "utime command completed"
228
 
      inside itself, so be more accurate, and so this doesnt have to
229
 
      keep calling current_utime, which can be slow.
230
 
    */
231
 
    uint64_t t_mark= session->getCurrentTimestamp(false);
232
 
  
233
 
 
 
237
    /* TODO, the session object should have a "utime command completed"
 
238
       inside itself, so be more accurate, and so this doesnt have to
 
239
       keep calling current_utime, which can be slow */
 
240
  
 
241
    uint64_t t_mark= get_microtime();
 
242
  
234
243
    // buffer to quotify the query
235
244
    unsigned char qs[255];
236
245
  
237
246
    // to avoid trying to printf %s something that is potentially NULL
238
 
    drizzled::util::string::const_shared_ptr dbs(session->schema());
 
247
    const char *dbs= session->db.empty() ? "" : session->db.c_str();
239
248
  
240
249
    msgbuf_len=
241
 
      snprintf(msgbuf.get(), MAX_MSG_LEN,
 
250
      snprintf(msgbuf, MAX_MSG_LEN,
242
251
               "%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
243
252
               "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64","
244
253
               "%"PRIu32",%"PRIu32",%"PRIu32",\"%s\"",
246
255
               session->thread_id,
247
256
               session->getQueryId(),
248
257
               // dont need to quote the db name, always CSV safe
249
 
               (int)dbs->size(), dbs->c_str(),
 
258
               (int)session->db.length(), dbs,
250
259
               // do need to quote the query
251
 
               quotify((const unsigned char *)session->getQueryString()->c_str(), session->getQueryString()->length(), qs, sizeof(qs)),
252
 
               // getCommandName is defined in drizzled/sql_parse.h dont
253
 
               // need to quote the command name, always CSV safe
254
 
               (int)drizzled::getCommandName(session->command).size(),
255
 
               drizzled::getCommandName(session->command).c_str(),
 
260
               quotify((unsigned char *)session->getQueryString(),
 
261
                       session->getQueryLength(), qs, sizeof(qs)),
 
262
               // command_name is defined in drizzled/sql_parse.cc
 
263
               // dont need to quote the command name, always CSV safe
 
264
               (int)command_name[session->command].length,
 
265
               command_name[session->command].str,
256
266
               // counters are at end, to make it easier to add more
257
267
               (t_mark - session->getConnectMicroseconds()),
258
 
               (session->getElapsedTime()),
 
268
               (t_mark - session->start_utime),
259
269
               (t_mark - session->utime_after_lock),
260
270
               session->sent_row_count,
261
271
               session->examined_row_count,
262
272
               session->tmp_table,
263
273
               session->total_warn_count,
264
274
               session->getServerId(),
265
 
               drizzled::getServerHostname().c_str()
 
275
               glob_hostname
266
276
               );
267
277
  
268
278
    char job_handle[GEARMAN_JOB_HANDLE_SIZE];
269
279
  
270
 
    (void) gearman_client_do_background(&_gearman_client,
271
 
                                        _function.c_str(),
 
280
    (void) gearman_client_do_background(&gearman_client,
 
281
                                        sysvar_logging_gearman_function,
272
282
                                        NULL,
273
 
                                        (void *) msgbuf.get(),
 
283
                                        (void *) msgbuf,
274
284
                                        (size_t) msgbuf_len,
275
285
                                        job_handle);
276
286
  
280
290
 
281
291
static LoggingGearman *handler= NULL;
282
292
 
283
 
static int logging_gearman_plugin_init(drizzled::module::Context &context)
284
 
{
285
 
  const drizzled::module::option_map &vm= context.getOptions();
286
 
 
287
 
  handler= new LoggingGearman(vm["host"].as<std::string>(),
288
 
                              vm["function"].as<std::string>());
289
 
  context.add(handler);
290
 
  context.registerVariable(new drizzled::sys_var_const_string_val("host", vm["host"].as<std::string>()));
291
 
  context.registerVariable(new drizzled::sys_var_const_string_val("function", vm["function"].as<std::string>()));
292
 
 
293
 
  return 0;
294
 
}
295
 
 
296
 
static void init_options(drizzled::module::option_context &context)
297
 
{
298
 
  context("host",
299
 
          po::value<std::string>()->default_value("localhost"),
300
 
          _("Hostname for logging to a Gearman server"));
301
 
  context("function",
302
 
          po::value<std::string>()->default_value("drizzlelog"),
303
 
          _("Gearman Function to send logging to"));
304
 
}
305
 
 
306
 
} /* namespace drizzle_plugin */
 
293
static int logging_gearman_plugin_init(plugin::Registry &registry)
 
294
{
 
295
  handler= new LoggingGearman();
 
296
  registry.add(handler);
 
297
 
 
298
  return 0;
 
299
}
 
300
 
 
301
static int logging_gearman_plugin_deinit(plugin::Registry &registry)
 
302
{
 
303
  registry.remove(handler);
 
304
  delete handler;
 
305
 
 
306
  return 0;
 
307
}
 
308
 
 
309
static DRIZZLE_SYSVAR_BOOL(
 
310
                           enable,
 
311
                           sysvar_logging_gearman_enable,
 
312
                           PLUGIN_VAR_NOCMDARG,
 
313
                           N_("Enable logging to a gearman server"),
 
314
                           NULL, /* check func */
 
315
                           NULL, /* update func */
 
316
                           false /* default */);
 
317
 
 
318
static DRIZZLE_SYSVAR_STR(
 
319
                          host,
 
320
                          sysvar_logging_gearman_host,
 
321
                          PLUGIN_VAR_READONLY,
 
322
                          N_("Hostname for logging to a Gearman server"),
 
323
                          NULL, /* check func */
 
324
                          NULL, /* update func*/
 
325
                          "localhost" /* default */);
 
326
 
 
327
static DRIZZLE_SYSVAR_STR(
 
328
                          function,
 
329
                          sysvar_logging_gearman_function,
 
330
                          PLUGIN_VAR_READONLY,
 
331
                          N_("Gearman Function to send logging to"),
 
332
                          NULL, /* check func */
 
333
                          NULL, /* update func*/
 
334
                          "drizzlelog" /* default */);
 
335
 
 
336
static drizzle_sys_var* logging_gearman_system_variables[]= {
 
337
  DRIZZLE_SYSVAR(enable),
 
338
  DRIZZLE_SYSVAR(host),
 
339
  DRIZZLE_SYSVAR(function),
 
340
  NULL
 
341
};
307
342
 
308
343
DRIZZLE_DECLARE_PLUGIN
309
344
{
310
345
  DRIZZLE_VERSION_ID,
311
 
    "logging-gearman",
 
346
    "logging_gearman",
312
347
    "0.1",
313
348
    "Mark Atwood <mark@fallenpegasus.com>",
314
349
    N_("Log queries to a Gearman server"),
315
 
    drizzled::PLUGIN_LICENSE_GPL,
316
 
    drizzle_plugin::logging_gearman_plugin_init,
317
 
    NULL,
318
 
    drizzle_plugin::init_options
 
350
    PLUGIN_LICENSE_GPL,
 
351
    logging_gearman_plugin_init,
 
352
    logging_gearman_plugin_deinit,
 
353
    NULL,   /* status variables */
 
354
    logging_gearman_system_variables,
 
355
    NULL
319
356
}
320
357
DRIZZLE_DECLARE_PLUGIN_END;