~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/logging_stats/logging_stats.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2010, Joseph Daly <skinny.moey@gmail.com>
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *
 
8
 *   * Redistributions of source code must retain the above copyright notice,
 
9
 *     this list of conditions and the following disclaimer.
 
10
 *   * Redistributions in binary form must reproduce the above copyright notice,
 
11
 *     this list of conditions and the following disclaimer in the documentation
 
12
 *     and/or other materials provided with the distribution.
 
13
 *   * Neither the name of Joseph Daly nor the names of its contributors
 
14
 *     may be used to endorse or promote products derived from this software
 
15
 *     without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
20
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 
21
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
27
 * THE POSSIBILITY OF SUCH DAMAGE.
 
28
 */
 
29
 
 
30
/**
 
31
 * @details
 
32
 *
 
33
 * This plugin tracks session and global statistics, as well as user statistics. 
 
34
 * The commands are logged using the post() and postEnd() logging APIs. 
 
35
 * The statistics are stored in a Scoreboard where each active session owns a 
 
36
 * ScoreboardSlot during the sessions active lifetime. 
 
37
 * 
 
38
 * Scoreboard
 
39
 *
 
40
 * The scoreboard is a pre-allocated vector of vectors of ScoreboardSlots. It 
 
41
 * can be thought of as a vector of buckets where each bucket contains 
 
42
 * pre-allocated ScoreboardSlots. To determine which bucket gets used for 
 
43
 * recording statistics the modulus operator is used on the session_id. This 
 
44
 * will result in a bucket to search for a unused ScoreboardSlot. Once a 
 
45
 * ScoreboardSlot is found the index of the slot is stored in the Session 
 
46
 * for later use. 
 
47
 *
 
48
 * Locking  
 
49
 * 
 
50
 * Each vector in the Scoreboard has its own lock. This allows session 2 
 
51
 * to not have to wait for session 1 to locate a slot to use, as they
 
52
 * will be in different buckets.  A lock is taken to locate a open slot
 
53
 * in the scoreboard. Subsequent queries by the session will not take
 
54
 * a lock.  
 
55
 *
 
56
 * A read lock is taken on the scoreboard vector when the table is queried 
 
57
 * in the data_dictionary. The "show status" and "show global status" do
 
58
 * not take a read lock when the data_dictionary table is queried, the 
 
59
 * user is not displayed in these results so it is not necessary. 
 
60
 *
 
61
 * Atomics
 
62
 *
 
63
 * The cumulative statistics use atomics, for the index into the vector
 
64
 * marking the last index that is used by a user. New users will increment
 
65
 * the atomic and claim the slot for use.  
 
66
 * 
 
67
 * System Variables
 
68
 * 
 
69
 * logging_stats_scoreboard_size - the size of the scoreboard this corresponds
 
70
 *   to the maximum number of concurrent connections that can be tracked
 
71
 *
 
72
 * logging_stats_max_user_count - this is used for cumulative statistics it 
 
73
 *   represents the maximum users that can be tracked 
 
74
 * 
 
75
 * logging_stats_bucket_count - the number of buckets to have in the scoreboard
 
76
 *   this splits up locking across several buckets so the entire scoreboard is 
 
77
 *   not locked at a single point in time.
 
78
 * 
 
79
 * logging_stats_enabled - enable/disable plugin 
 
80
 * 
 
81
 * TODO 
 
82
 *
 
83
 * Allow expansion of Scoreboard and cumulative vector 
 
84
 * 
 
85
 */
 
86
 
 
87
#include "config.h"
 
88
#include "user_commands.h"
 
89
#include "status_vars.h"
 
90
#include "global_stats.h"
 
91
#include "logging_stats.h"
 
92
#include "status_tool.h"
 
93
#include "stats_schema.h"
 
94
#include <boost/program_options.hpp>
 
95
#include <drizzled/module/option_map.h>
 
96
#include <drizzled/session.h>
 
97
 
 
98
namespace po= boost::program_options;
 
99
using namespace drizzled;
 
100
using namespace plugin;
 
101
using namespace std;
 
102
 
 
103
static bool sysvar_logging_stats_enabled= true;
 
104
 
 
105
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
 
106
 
 
107
static uint32_t sysvar_logging_stats_max_user_count= 500;
 
108
 
 
109
static uint32_t sysvar_logging_stats_bucket_count= 10;
 
110
 
 
111
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
 
112
{
 
113
  current_scoreboard= new Scoreboard(sysvar_logging_stats_scoreboard_size, 
 
114
                                     sysvar_logging_stats_bucket_count);
 
115
 
 
116
  cumulative_stats= new CumulativeStats(sysvar_logging_stats_max_user_count); 
 
117
}
 
118
 
 
119
LoggingStats::~LoggingStats()
 
120
{
 
121
  delete current_scoreboard;
 
122
  delete cumulative_stats;
 
123
}
 
124
 
 
125
void LoggingStats::updateCurrentScoreboard(ScoreboardSlot *scoreboard_slot,
 
126
                                           Session *session)
 
127
{
 
128
  enum_sql_command sql_command= session->lex->sql_command;
 
129
 
 
130
  scoreboard_slot->getUserCommands()->logCommand(sql_command);
 
131
 
 
132
  /* If a flush occurred copy over values before setting new values */
 
133
  if (scoreboard_slot->getStatusVars()->hasBeenFlushed(session))
 
134
  {
 
135
    cumulative_stats->logGlobalStatusVars(scoreboard_slot);
 
136
  }
 
137
  scoreboard_slot->getStatusVars()->logStatusVar(session);
 
138
}
 
139
 
 
140
bool LoggingStats::post(Session *session)
 
141
{
 
142
  if (! isEnabled() || (session->getSessionId() == 0))
 
143
  {
 
144
    return false;
 
145
  }
 
146
 
 
147
  ScoreboardSlot *scoreboard_slot= current_scoreboard->findScoreboardSlotToLog(session);
 
148
 
 
149
  /* Its possible that the scoreboard is full with active sessions in which case 
 
150
     this could be null */
 
151
  if (scoreboard_slot)
 
152
  {
 
153
    updateCurrentScoreboard(scoreboard_slot, session);
 
154
  }
 
155
  return false;
 
156
}
 
157
 
 
158
bool LoggingStats::postEnd(Session *session)
 
159
{
 
160
  if (! isEnabled() || (session->getSessionId() == 0))
 
161
  {
 
162
    return false;
 
163
  }
 
164
 
 
165
  bool isInScoreboard= false;
 
166
  ScoreboardSlot *scoreboard_slot= current_scoreboard->findOurScoreboardSlot(session);
 
167
 
 
168
  if (scoreboard_slot)
 
169
  {
 
170
    isInScoreboard= true;
 
171
  } 
 
172
  else 
 
173
  { 
 
174
    /* the session did not have a slot reserved, that could be because the scoreboard was
 
175
       full, but most likely its a failed authentication so post() is never called where
 
176
       the slot is assigned. Log the global status values below, and if the user has a slot
 
177
       log to it, but do not reserve a new slot for a user. If it was a failed authentication
 
178
       the scoreboard would be filled up quickly with invalid users. 
 
179
    */
 
180
    scoreboard_slot= new ScoreboardSlot();
 
181
    scoreboard_slot->setUser(session->getSecurityContext().getUser());
 
182
    scoreboard_slot->setIp(session->getSecurityContext().getIp());
 
183
  }
 
184
 
 
185
  scoreboard_slot->getStatusVars()->logStatusVar(session);
 
186
  scoreboard_slot->getStatusVars()->getStatusVarCounters()->connection_time= time(NULL) - session->start_time; 
 
187
 
 
188
  cumulative_stats->logUserStats(scoreboard_slot, isInScoreboard);
 
189
  cumulative_stats->logGlobalStats(scoreboard_slot);
 
190
  cumulative_stats->logGlobalStatusVars(scoreboard_slot);
 
191
 
 
192
  if (isInScoreboard)
 
193
  {
 
194
    scoreboard_slot->reset();
 
195
  } 
 
196
  else 
 
197
  {
 
198
    delete scoreboard_slot;
 
199
  } 
 
200
 
 
201
  return false;
 
202
}
 
203
 
 
204
/* Plugin initialization and system variables */
 
205
 
 
206
static LoggingStats *logging_stats= NULL;
 
207
 
 
208
static CurrentCommandsTool *current_commands_tool= NULL;
 
209
 
 
210
static CumulativeCommandsTool *cumulative_commands_tool= NULL;
 
211
 
 
212
static GlobalStatementsTool *global_statements_tool= NULL;
 
213
 
 
214
static SessionStatementsTool *session_statements_tool= NULL;
 
215
 
 
216
static StatusTool *global_status_tool= NULL;
 
217
 
 
218
static StatusTool *session_status_tool= NULL;
 
219
 
 
220
static CumulativeUserStatsTool *cumulative_user_stats_tool= NULL;
 
221
 
 
222
static ScoreboardStatsTool *scoreboard_stats_tool= NULL;
 
223
 
 
224
static void enable(Session *,
 
225
                   drizzle_sys_var *,
 
226
                   void *var_ptr,
 
227
                   const void *save)
 
228
{
 
229
  if (logging_stats)
 
230
  {
 
231
    if (*(bool *)save != false)
 
232
    {
 
233
      logging_stats->enable();
 
234
      *(bool *) var_ptr= (bool) true;
 
235
    }
 
236
    else
 
237
    {
 
238
      logging_stats->disable();
 
239
      *(bool *) var_ptr= (bool) false;
 
240
    }
 
241
  }
 
242
}
 
243
 
 
244
static bool initTable()
 
245
{
 
246
  current_commands_tool= new(nothrow)CurrentCommandsTool(logging_stats);
 
247
 
 
248
  if (! current_commands_tool)
 
249
  {
 
250
    return true;
 
251
  }
 
252
 
 
253
  cumulative_commands_tool= new(nothrow)CumulativeCommandsTool(logging_stats);
 
254
 
 
255
  if (! cumulative_commands_tool)
 
256
  {
 
257
    return true;
 
258
  }
 
259
 
 
260
  global_statements_tool= new(nothrow)GlobalStatementsTool(logging_stats);
 
261
 
 
262
  if (! global_statements_tool)
 
263
  {
 
264
    return true;
 
265
  }
 
266
 
 
267
  session_statements_tool= new(nothrow)SessionStatementsTool(logging_stats);
 
268
 
 
269
  if (! session_statements_tool)
 
270
  {
 
271
    return true;
 
272
  }
 
273
 
 
274
  session_status_tool= new(nothrow)StatusTool(logging_stats, true);
 
275
 
 
276
  if (! session_status_tool)
 
277
  {
 
278
    return true;
 
279
  }
 
280
 
 
281
  global_status_tool= new(nothrow)StatusTool(logging_stats, false);
 
282
 
 
283
  if (! global_status_tool)
 
284
  {
 
285
    return true;
 
286
  }
 
287
 
 
288
  cumulative_user_stats_tool= new(nothrow)CumulativeUserStatsTool(logging_stats);
 
289
 
 
290
  if (! cumulative_user_stats_tool)
 
291
  {
 
292
    return true;
 
293
  }
 
294
 
 
295
  scoreboard_stats_tool= new(nothrow)ScoreboardStatsTool(logging_stats);
 
296
  
 
297
  if (! scoreboard_stats_tool)
 
298
  {
 
299
    return true;
 
300
  }
 
301
 
 
302
  return false;
 
303
}
 
304
 
 
305
static int init(drizzled::module::Context &context)
 
306
{
 
307
  const module::option_map &vm= context.getOptions();
 
308
 
 
309
  sysvar_logging_stats_enabled= (vm.count("disable")) ? false : true;
 
310
 
 
311
  if (vm.count("max-user-count"))
 
312
  {
 
313
    if (sysvar_logging_stats_max_user_count < 100 || sysvar_logging_stats_max_user_count > 50000)
 
314
    {
 
315
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for max-user-count\n"));
 
316
      exit(-1);
 
317
    }
 
318
  }
 
319
  if (vm.count("bucket-count"))
 
320
  {
 
321
    if (sysvar_logging_stats_bucket_count < 5 || sysvar_logging_stats_bucket_count > 500)
 
322
    {
 
323
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for bucket-count\n"));
 
324
      exit(-1);
 
325
    }
 
326
  }
 
327
 
 
328
  if (vm.count("scoreboard-size"))
 
329
  {
 
330
    if (sysvar_logging_stats_scoreboard_size < 10 || sysvar_logging_stats_scoreboard_size > 50000)
 
331
    {
 
332
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for scoreboard-size\n"));
 
333
      exit(-1);
 
334
    }
 
335
    else
 
336
      sysvar_logging_stats_scoreboard_size= vm["scoreboard-size"].as<uint32_t>(); 
 
337
  }
 
338
 
 
339
  logging_stats= new LoggingStats("logging_stats");
 
340
 
 
341
  if (initTable())
 
342
  {
 
343
    return 1;
 
344
  }
 
345
 
 
346
  context.add(logging_stats);
 
347
  context.add(current_commands_tool);
 
348
  context.add(cumulative_commands_tool);
 
349
  context.add(global_statements_tool);
 
350
  context.add(session_statements_tool);
 
351
  context.add(session_status_tool);
 
352
  context.add(global_status_tool);
 
353
  context.add(cumulative_user_stats_tool);
 
354
  context.add(scoreboard_stats_tool);
 
355
 
 
356
  if (sysvar_logging_stats_enabled)
 
357
  {
 
358
    logging_stats->enable();
 
359
  }
 
360
 
 
361
  return 0;
 
362
}
 
363
 
 
364
static DRIZZLE_SYSVAR_UINT(max_user_count,
 
365
                           sysvar_logging_stats_max_user_count,
 
366
                           PLUGIN_VAR_RQCMDARG,
 
367
                           N_("Max number of users that will be logged"),
 
368
                           NULL, /* check func */
 
369
                           NULL, /* update func */
 
370
                           500, /* default */
 
371
                           100, /* minimum */
 
372
                           50000,
 
373
                           0);
 
374
 
 
375
static DRIZZLE_SYSVAR_UINT(bucket_count,
 
376
                           sysvar_logging_stats_bucket_count,
 
377
                           PLUGIN_VAR_RQCMDARG,
 
378
                           N_("Max number of range locks to use for Scoreboard"),
 
379
                           NULL, /* check func */
 
380
                           NULL, /* update func */
 
381
                           10, /* default */
 
382
                           5, /* minimum */
 
383
                           500,
 
384
                           0);
 
385
 
 
386
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
 
387
                           sysvar_logging_stats_scoreboard_size,
 
388
                           PLUGIN_VAR_RQCMDARG,
 
389
                           N_("Max number of concurrent sessions that will be logged"),
 
390
                           NULL, /* check func */
 
391
                           NULL, /* update func */
 
392
                           2000, /* default */
 
393
                           10, /* minimum */
 
394
                           50000, 
 
395
                           0);
 
396
 
 
397
static DRIZZLE_SYSVAR_BOOL(enable,
 
398
                           sysvar_logging_stats_enabled,
 
399
                           PLUGIN_VAR_NOCMDARG,
 
400
                           N_("Enable Logging Statistics Collection"),
 
401
                           NULL, /* check func */
 
402
                           enable, /* update func */
 
403
                           true /* default */);
 
404
 
 
405
static void init_options(drizzled::module::option_context &context)
 
406
{
 
407
  context("max-user-count",
 
408
          po::value<uint32_t>(&sysvar_logging_stats_max_user_count)->default_value(500),
 
409
          N_("Max number of users that will be logged"));
 
410
  context("bucket-count",
 
411
          po::value<uint32_t>(&sysvar_logging_stats_bucket_count)->default_value(10),
 
412
          N_("Max number of range locks to use for Scoreboard"));
 
413
  context("scoreboard-size",
 
414
          po::value<uint32_t>(&sysvar_logging_stats_scoreboard_size)->default_value(2000),
 
415
          N_("Max number of concurrent sessions that will be logged"));
 
416
  context("disable", N_("Enable Logging Statistics Collection"));
 
417
}
 
418
 
 
419
static drizzle_sys_var* system_var[]= {
 
420
  DRIZZLE_SYSVAR(max_user_count),
 
421
  DRIZZLE_SYSVAR(bucket_count),
 
422
  DRIZZLE_SYSVAR(scoreboard_size),
 
423
  DRIZZLE_SYSVAR(enable),
 
424
  NULL
 
425
};
 
426
 
 
427
DRIZZLE_DECLARE_PLUGIN
 
428
{
 
429
  DRIZZLE_VERSION_ID,
 
430
  "logging_stats",
 
431
  "0.1",
 
432
  "Joseph Daly",
 
433
  N_("User Statistics as DATA_DICTIONARY tables"),
 
434
  PLUGIN_LICENSE_BSD,
 
435
  init,   /* Plugin Init      */
 
436
  system_var, /* system variables */
 
437
  init_options    /* config options   */
 
438
}
 
439
DRIZZLE_DECLARE_PLUGIN_END;