~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_stats/logging_stats.cc

Remove dead memset call.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
/**
31
31
 * @details
32
32
 *
33
 
 * This tracks current user commands. The commands are logged using
34
 
 * the post() and postEnd() logging APIs. It uses a scoreboard
35
 
 * approach that initializes the scoreboard size to the value set
36
 
 * by logging_stats_scoreboard_size. Each ScoreBoardSlot wraps 
37
 
 * a UserCommand object containing the statistics for a particular
38
 
 * session. As other statistics are added they can then be added
39
 
 * to the ScoreBoardSlot object. 
 
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. 
40
47
 *
41
48
 * Locking  
42
 
 *
43
 
 * A RW lock is taken to locate a open slot for a session or to locate the
44
 
 * slot that the current session has claimed. 
45
 
 * 
46
 
 * A read lock is taken when the table is queried in the data_dictionary.
 
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 
47
80
 * 
48
81
 * TODO 
49
82
 *
50
 
 * To improve as more statistics are added, a pointer to the scoreboard
51
 
 * slot should be added to the Session object. This will avoid the session
52
 
 * having to do multiple lookups in the scoreboard.  
53
 
 *  
54
 
 * Save the statistics off into a vector so you can query by user/ip and get
55
 
 * commands run based on those keys over time. 
 
83
 * Allow expansion of Scoreboard and cumulative vector 
56
84
 * 
57
85
 */
58
86
 
59
87
#include "config.h"
 
88
#include "user_commands.h"
 
89
#include "status_vars.h"
 
90
#include "global_stats.h"
60
91
#include "logging_stats.h"
 
92
#include "status_tool.h"
61
93
#include "stats_schema.h"
 
94
#include <boost/program_options.hpp>
 
95
#include <drizzled/module/option_map.h>
62
96
#include <drizzled/session.h>
63
97
 
 
98
namespace po= boost::program_options;
64
99
using namespace drizzled;
65
100
using namespace plugin;
66
101
using namespace std;
67
102
 
68
 
static bool sysvar_logging_stats_enabled= false;
 
103
static bool sysvar_logging_stats_enabled= true;
69
104
 
70
105
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
71
106
 
72
 
pthread_rwlock_t LOCK_scoreboard;
 
107
static uint32_t sysvar_logging_stats_max_user_count= 500;
 
108
 
 
109
static uint32_t sysvar_logging_stats_bucket_count= 10;
73
110
 
74
111
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
75
112
{
76
 
  (void) pthread_rwlock_init(&LOCK_scoreboard, NULL);
77
 
  scoreboard_size= sysvar_logging_stats_scoreboard_size;
78
 
  score_board_slots= new ScoreBoardSlot[scoreboard_size];
79
 
  for (uint32_t j=0; j < scoreboard_size; j++)
80
 
  { 
81
 
    UserCommands *user_commands= new UserCommands();
82
 
    ScoreBoardSlot *score_board_slot= &score_board_slots[j];
83
 
    score_board_slot->setUserCommands(user_commands); 
84
 
  } 
 
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); 
85
117
}
86
118
 
87
119
LoggingStats::~LoggingStats()
88
120
{
89
 
  (void) pthread_rwlock_destroy(&LOCK_scoreboard);
90
 
  delete[] score_board_slots;
 
121
  delete current_scoreboard;
 
122
  delete cumulative_stats;
91
123
}
92
124
 
93
 
bool LoggingStats::isBeingLogged(Session *session)
94
 
{
95
 
  enum_sql_command sql_command= session->lex->sql_command;
96
 
 
97
 
  switch(sql_command)
98
 
  {
99
 
    case SQLCOM_UPDATE:
100
 
    case SQLCOM_DELETE:
101
 
    case SQLCOM_INSERT:
102
 
    case SQLCOM_ROLLBACK:
103
 
    case SQLCOM_COMMIT:
104
 
    case SQLCOM_CREATE_TABLE:
105
 
    case SQLCOM_ALTER_TABLE:
106
 
    case SQLCOM_DROP_TABLE:
107
 
    case SQLCOM_SELECT:
108
 
      return true;
109
 
    default:
110
 
      return false;
111
 
  }
112
 
113
 
 
114
 
void LoggingStats::updateScoreBoard(ScoreBoardSlot *score_board_slot,
115
 
                                    Session *session)
116
 
{
117
 
  enum_sql_command sql_command= session->lex->sql_command;
118
 
 
119
 
  UserCommands *user_commands= score_board_slot->getUserCommands();
120
 
 
121
 
  switch(sql_command)
122
 
  {
123
 
    case SQLCOM_UPDATE:
124
 
      user_commands->incrementUpdateCount();
125
 
      break;
126
 
    case SQLCOM_DELETE:
127
 
      user_commands->incrementDeleteCount();
128
 
      break;
129
 
    case SQLCOM_INSERT:
130
 
      user_commands->incrementInsertCount();
131
 
      break;
132
 
    case SQLCOM_ROLLBACK:
133
 
      user_commands->incrementRollbackCount();
134
 
      break;
135
 
    case SQLCOM_COMMIT:
136
 
      user_commands->incrementCommitCount();
137
 
      break;
138
 
    case SQLCOM_CREATE_TABLE:
139
 
      user_commands->incrementCreateCount();
140
 
      break;
141
 
    case SQLCOM_ALTER_TABLE:
142
 
      user_commands->incrementAlterCount();
143
 
      break;
144
 
    case SQLCOM_DROP_TABLE:
145
 
      user_commands->incrementDropCount();
146
 
      break;
147
 
    case SQLCOM_SELECT:
148
 
      user_commands->incrementSelectCount();
149
 
      break;
150
 
    default:
151
 
      return;
152
 
  }
 
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);
153
138
}
154
139
 
155
140
bool LoggingStats::post(Session *session)
159
144
    return false;
160
145
  }
161
146
 
162
 
  /* exit early if we are not logging this type of command */
163
 
  if (isBeingLogged(session) == false)
164
 
  {
165
 
    return false;
166
 
  }
167
 
 
168
 
  /* Find a slot that is unused */
169
 
 
170
 
  pthread_rwlock_wrlock(&LOCK_scoreboard);
171
 
  ScoreBoardSlot *score_board_slot;
172
 
  int our_slot= UNINITIALIZED; 
173
 
  int open_slot= UNINITIALIZED;
174
 
 
175
 
  for (uint32_t j=0; j < scoreboard_size; j++)
176
 
  {
177
 
    score_board_slot= &score_board_slots[j];
178
 
 
179
 
    if (score_board_slot->isInUse() == true)
180
 
    {
181
 
      /* Check if this session is the one using this slot */
182
 
      if (score_board_slot->getSessionId() == session->getSessionId())
183
 
      {
184
 
        our_slot= j;
185
 
        break; 
186
 
      } 
187
 
      else 
188
 
      {
189
 
        continue; 
190
 
      }
191
 
    }
192
 
    else 
193
 
    {
194
 
      /* save off the open slot */ 
195
 
      if (open_slot == -1)
196
 
      {
197
 
        open_slot= j;
198
 
      } 
199
 
      continue;
200
 
    }
201
 
  }
202
 
 
203
 
  if (our_slot != UNINITIALIZED)
204
 
  {
205
 
    pthread_rwlock_unlock(&LOCK_scoreboard); 
206
 
  }
207
 
  else if (open_slot != UNINITIALIZED)
208
 
  {
209
 
    score_board_slot= &score_board_slots[open_slot];
210
 
    score_board_slot->setInUse(true);
211
 
    score_board_slot->setSessionId(session->getSessionId());
212
 
    score_board_slot->setUser(session->getSecurityContext().getUser());
213
 
    score_board_slot->setIp(session->getSecurityContext().getIp());
214
 
    pthread_rwlock_unlock(&LOCK_scoreboard);
215
 
  }
216
 
  else 
217
 
  {
218
 
    pthread_rwlock_unlock(&LOCK_scoreboard);
219
 
    /* there was no available slot for this session */
220
 
    return false;
221
 
  }
222
 
 
223
 
  updateScoreBoard(score_board_slot, session);
224
 
 
 
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
  }
225
155
  return false;
226
156
}
227
157
 
228
158
bool LoggingStats::postEnd(Session *session)
229
159
{
230
 
  if (! isEnabled() || (session->getSessionId() == 0)) 
 
160
  if (! isEnabled() || (session->getSessionId() == 0))
231
161
  {
232
162
    return false;
233
163
  }
234
164
 
235
 
  ScoreBoardSlot *score_board_slot;
236
 
 
237
 
  pthread_rwlock_wrlock(&LOCK_scoreboard);
238
 
 
239
 
  for (uint32_t j=0; j < scoreboard_size; j++)
 
165
  bool isInScoreboard= false;
 
166
  ScoreboardSlot *scoreboard_slot= current_scoreboard->findOurScoreboardSlot(session);
 
167
 
 
168
  if (scoreboard_slot)
240
169
  {
241
 
    score_board_slot= &score_board_slots[j];
242
 
 
243
 
    if (score_board_slot->getSessionId() == session->getSessionId())
244
 
    {
245
 
      score_board_slot->reset();
246
 
      break;
247
 
    }
 
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());
248
183
  }
249
184
 
250
 
  pthread_rwlock_unlock(&LOCK_scoreboard);
 
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
  } 
251
200
 
252
201
  return false;
253
202
}
256
205
 
257
206
static LoggingStats *logging_stats= NULL;
258
207
 
259
 
static CommandsTool *commands_tool= NULL;
 
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;
260
223
 
261
224
static void enable(Session *,
262
225
                   drizzle_sys_var *,
280
243
 
281
244
static bool initTable()
282
245
{
283
 
  commands_tool= new(nothrow)CommandsTool(logging_stats);
284
 
 
285
 
  if (! commands_tool)
 
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)
286
298
  {
287
299
    return true;
288
300
  }
290
302
  return false;
291
303
}
292
304
 
293
 
static int init(drizzled::plugin::Context &context)
 
305
static int init(drizzled::module::Context &context)
294
306
{
 
307
  const module::option_map &vm= context.getOptions();
 
308
  if (vm.count("max-user-count"))
 
309
  {
 
310
    if (sysvar_logging_stats_max_user_count < 100 || sysvar_logging_stats_max_user_count > 50000)
 
311
    {
 
312
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for max-user-count\n"));
 
313
      exit(-1);
 
314
    }
 
315
  }
 
316
  if (vm.count("bucket-count"))
 
317
  {
 
318
    if (sysvar_logging_stats_bucket_count < 5 || sysvar_logging_stats_bucket_count > 500)
 
319
    {
 
320
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for bucket-count\n"));
 
321
      exit(-1);
 
322
    }
 
323
  }
 
324
 
 
325
  if (vm.count("scoreboard-size"))
 
326
  {
 
327
    if (sysvar_logging_stats_scoreboard_size < 10 || sysvar_logging_stats_scoreboard_size > 50000)
 
328
    {
 
329
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for scoreboard-size\n"));
 
330
      exit(-1);
 
331
    }
 
332
    else
 
333
      sysvar_logging_stats_scoreboard_size= vm["scoreboard-size"].as<uint32_t>(); 
 
334
  }
 
335
 
295
336
  logging_stats= new LoggingStats("logging_stats");
296
337
 
297
338
  if (initTable())
300
341
  }
301
342
 
302
343
  context.add(logging_stats);
303
 
  context.add(commands_tool);
 
344
  context.add(current_commands_tool);
 
345
  context.add(cumulative_commands_tool);
 
346
  context.add(global_statements_tool);
 
347
  context.add(session_statements_tool);
 
348
  context.add(session_status_tool);
 
349
  context.add(global_status_tool);
 
350
  context.add(cumulative_user_stats_tool);
 
351
  context.add(scoreboard_stats_tool);
304
352
 
305
353
  if (sysvar_logging_stats_enabled)
306
354
  {
310
358
  return 0;
311
359
}
312
360
 
 
361
static DRIZZLE_SYSVAR_UINT(max_user_count,
 
362
                           sysvar_logging_stats_max_user_count,
 
363
                           PLUGIN_VAR_RQCMDARG,
 
364
                           N_("Max number of users that will be logged"),
 
365
                           NULL, /* check func */
 
366
                           NULL, /* update func */
 
367
                           500, /* default */
 
368
                           100, /* minimum */
 
369
                           50000,
 
370
                           0);
 
371
 
 
372
static DRIZZLE_SYSVAR_UINT(bucket_count,
 
373
                           sysvar_logging_stats_bucket_count,
 
374
                           PLUGIN_VAR_RQCMDARG,
 
375
                           N_("Max number of range locks to use for Scoreboard"),
 
376
                           NULL, /* check func */
 
377
                           NULL, /* update func */
 
378
                           10, /* default */
 
379
                           5, /* minimum */
 
380
                           500,
 
381
                           0);
 
382
 
313
383
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
314
384
                           sysvar_logging_stats_scoreboard_size,
315
385
                           PLUGIN_VAR_RQCMDARG,
317
387
                           NULL, /* check func */
318
388
                           NULL, /* update func */
319
389
                           2000, /* default */
320
 
                           1000, /* minimum */
 
390
                           10, /* minimum */
321
391
                           50000, 
322
392
                           0);
323
393
 
327
397
                           N_("Enable Logging Statistics Collection"),
328
398
                           NULL, /* check func */
329
399
                           enable, /* update func */
330
 
                           false /* default */);
 
400
                           true /* default */);
 
401
 
 
402
static void init_options(drizzled::module::option_context &context)
 
403
{
 
404
  context("max-user-count",
 
405
          po::value<uint32_t>(&sysvar_logging_stats_max_user_count)->default_value(500),
 
406
          N_("Max number of users that will be logged"));
 
407
  context("bucket-count",
 
408
          po::value<uint32_t>(&sysvar_logging_stats_bucket_count)->default_value(10),
 
409
          N_("Max number of range locks to use for Scoreboard"));
 
410
  context("scoreboard-size",
 
411
          po::value<uint32_t>(&sysvar_logging_stats_scoreboard_size)->default_value(2000),
 
412
          N_("Max number of concurrent sessions that will be logged"));
 
413
  context("enable",
 
414
          po::value<bool>(&sysvar_logging_stats_enabled)->default_value(true)->zero_tokens(),
 
415
          N_("Enable Logging Statistics Collection"));
 
416
}
331
417
 
332
418
static drizzle_sys_var* system_var[]= {
 
419
  DRIZZLE_SYSVAR(max_user_count),
 
420
  DRIZZLE_SYSVAR(bucket_count),
333
421
  DRIZZLE_SYSVAR(scoreboard_size),
334
422
  DRIZZLE_SYSVAR(enable),
335
423
  NULL
345
433
  PLUGIN_LICENSE_BSD,
346
434
  init,   /* Plugin Init      */
347
435
  system_var, /* system variables */
348
 
  NULL    /* config options   */
 
436
  init_options    /* config options   */
349
437
}
350
438
DRIZZLE_DECLARE_PLUGIN_END;