~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_stats/logging_stats.cc

  • Committer: Brian Aker
  • Date: 2010-12-08 22:35:56 UTC
  • mfrom: (1819.9.158 update-innobase)
  • Revision ID: brian@tangent.org-20101208223556-37mi4omqg7lkjzf3
Merge in Stewart's changes, 1.3 changes.

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
typedef constrained_check<uint32_t, 50000, 10> scoreboard_size_constraint;
 
106
static scoreboard_size_constraint sysvar_logging_stats_scoreboard_size;
 
107
 
 
108
typedef constrained_check<uint32_t, 50000, 100> max_user_count_constraint;
 
109
static max_user_count_constraint sysvar_logging_stats_max_user_count;
 
110
 
 
111
typedef constrained_check<uint32_t, 500, 5> bucket_count_constraint;
 
112
static bucket_count_constraint sysvar_logging_stats_bucket_count;
 
113
 
 
114
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
 
115
{
 
116
  current_scoreboard= new Scoreboard(sysvar_logging_stats_scoreboard_size, 
 
117
                                     sysvar_logging_stats_bucket_count);
 
118
 
 
119
  cumulative_stats= new CumulativeStats(sysvar_logging_stats_max_user_count); 
 
120
}
 
121
 
 
122
LoggingStats::~LoggingStats()
 
123
{
 
124
  delete current_scoreboard;
 
125
  delete cumulative_stats;
 
126
}
 
127
 
 
128
void LoggingStats::updateCurrentScoreboard(ScoreboardSlot *scoreboard_slot,
 
129
                                           Session *session)
 
130
{
 
131
  enum_sql_command sql_command= session->lex->sql_command;
 
132
 
 
133
  scoreboard_slot->getUserCommands()->logCommand(sql_command);
 
134
 
 
135
  /* If a flush occurred copy over values before setting new values */
 
136
  if (scoreboard_slot->getStatusVars()->hasBeenFlushed(session))
 
137
  {
 
138
    cumulative_stats->logGlobalStatusVars(scoreboard_slot);
 
139
  }
 
140
  scoreboard_slot->getStatusVars()->logStatusVar(session);
 
141
}
 
142
 
 
143
bool LoggingStats::resetGlobalScoreboard()
 
144
{
 
145
  cumulative_stats->getGlobalStatusVars()->reset();
 
146
  cumulative_stats->getGlobalStats()->getUserCommands()->reset();
 
147
 
 
148
  ScoreBoardVectors *vector_of_scoreboard_vectors=
 
149
    current_scoreboard->getVectorOfScoreboardVectors();
 
150
 
 
151
  ScoreBoardVectors::iterator v_of_scoreboard_v_begin_it= vector_of_scoreboard_vectors->begin();
 
152
 
 
153
  ScoreBoardVectors::iterator v_of_scoreboard_v_end_it= vector_of_scoreboard_vectors->end();
 
154
 
 
155
  for (; v_of_scoreboard_v_begin_it != v_of_scoreboard_v_end_it; ++v_of_scoreboard_v_begin_it)
 
156
  {
 
157
    std::vector<ScoreboardSlot* > *scoreboard_vector= *v_of_scoreboard_v_begin_it;
 
158
 
 
159
    std::vector<ScoreboardSlot* >::iterator scoreboard_vector_it= scoreboard_vector->begin();
 
160
    std::vector<ScoreboardSlot* >::iterator scoreboard_vector_end= scoreboard_vector->end();
 
161
    for (; scoreboard_vector_it != scoreboard_vector_end; ++scoreboard_vector_it)
 
162
    {
 
163
      ScoreboardSlot *scoreboard_slot= *scoreboard_vector_it;
 
164
      scoreboard_slot->getStatusVars()->reset();
 
165
      scoreboard_slot->getUserCommands()->reset();
 
166
    }
 
167
  }
 
168
 
 
169
  return false;
 
170
}
 
171
 
 
172
bool LoggingStats::post(Session *session)
 
173
{
 
174
  if (! isEnabled() || (session->getSessionId() == 0))
 
175
  {
 
176
    return false;
 
177
  }
 
178
 
 
179
  ScoreboardSlot *scoreboard_slot= current_scoreboard->findScoreboardSlotToLog(session);
 
180
 
 
181
  /* Its possible that the scoreboard is full with active sessions in which case 
 
182
     this could be null */
 
183
  if (scoreboard_slot)
 
184
  {
 
185
    updateCurrentScoreboard(scoreboard_slot, session);
 
186
  }
 
187
  return false;
 
188
}
 
189
 
 
190
bool LoggingStats::postEnd(Session *session)
 
191
{
 
192
  if (! isEnabled() || (session->getSessionId() == 0))
 
193
  {
 
194
    return false;
 
195
  }
 
196
 
 
197
  bool isInScoreboard= false;
 
198
  ScoreboardSlot *scoreboard_slot= current_scoreboard->findOurScoreboardSlot(session);
 
199
 
 
200
  if (scoreboard_slot)
 
201
  {
 
202
    isInScoreboard= true;
 
203
  } 
 
204
  else 
 
205
  { 
 
206
    /* the session did not have a slot reserved, that could be because the scoreboard was
 
207
       full, but most likely its a failed authentication so post() is never called where
 
208
       the slot is assigned. Log the global status values below, and if the user has a slot
 
209
       log to it, but do not reserve a new slot for a user. If it was a failed authentication
 
210
       the scoreboard would be filled up quickly with invalid users. 
 
211
    */
 
212
    scoreboard_slot= new ScoreboardSlot();
 
213
    scoreboard_slot->setUser(session->getSecurityContext().getUser());
 
214
    scoreboard_slot->setIp(session->getSecurityContext().getIp());
 
215
  }
 
216
 
 
217
  scoreboard_slot->getStatusVars()->logStatusVar(session);
 
218
  scoreboard_slot->getStatusVars()->getStatusVarCounters()->connection_time= time(NULL) - session->start_time; 
 
219
 
 
220
  cumulative_stats->logUserStats(scoreboard_slot, isInScoreboard);
 
221
  cumulative_stats->logGlobalStats(scoreboard_slot);
 
222
  cumulative_stats->logGlobalStatusVars(scoreboard_slot);
 
223
 
 
224
  if (isInScoreboard)
 
225
  {
 
226
    scoreboard_slot->reset();
 
227
  } 
 
228
  else 
 
229
  {
 
230
    delete scoreboard_slot;
 
231
  } 
 
232
 
 
233
  return false;
 
234
}
 
235
 
 
236
/* Plugin initialization and system variables */
 
237
 
 
238
static LoggingStats *logging_stats= NULL;
 
239
 
 
240
static CurrentCommandsTool *current_commands_tool= NULL;
 
241
 
 
242
static CumulativeCommandsTool *cumulative_commands_tool= NULL;
 
243
 
 
244
static GlobalStatementsTool *global_statements_tool= NULL;
 
245
 
 
246
static SessionStatementsTool *session_statements_tool= NULL;
 
247
 
 
248
static StatusTool *global_status_tool= NULL;
 
249
 
 
250
static StatusTool *session_status_tool= NULL;
 
251
 
 
252
static CumulativeUserStatsTool *cumulative_user_stats_tool= NULL;
 
253
 
 
254
static ScoreboardStatsTool *scoreboard_stats_tool= NULL;
 
255
 
 
256
static void enable(Session *, sql_var_t)
 
257
{
 
258
  if (logging_stats)
 
259
  {
 
260
    if (sysvar_logging_stats_enabled)
 
261
    {
 
262
      logging_stats->enable();
 
263
    }
 
264
    else
 
265
    {
 
266
      logging_stats->disable();
 
267
    }
 
268
  }
 
269
}
 
270
 
 
271
static bool initTable()
 
272
{
 
273
  current_commands_tool= new(nothrow)CurrentCommandsTool(logging_stats);
 
274
 
 
275
  if (! current_commands_tool)
 
276
  {
 
277
    return true;
 
278
  }
 
279
 
 
280
  cumulative_commands_tool= new(nothrow)CumulativeCommandsTool(logging_stats);
 
281
 
 
282
  if (! cumulative_commands_tool)
 
283
  {
 
284
    return true;
 
285
  }
 
286
 
 
287
  global_statements_tool= new(nothrow)GlobalStatementsTool(logging_stats);
 
288
 
 
289
  if (! global_statements_tool)
 
290
  {
 
291
    return true;
 
292
  }
 
293
 
 
294
  session_statements_tool= new(nothrow)SessionStatementsTool(logging_stats);
 
295
 
 
296
  if (! session_statements_tool)
 
297
  {
 
298
    return true;
 
299
  }
 
300
 
 
301
  session_status_tool= new(nothrow)StatusTool(logging_stats, true);
 
302
 
 
303
  if (! session_status_tool)
 
304
  {
 
305
    return true;
 
306
  }
 
307
 
 
308
  global_status_tool= new(nothrow)StatusTool(logging_stats, false);
 
309
 
 
310
  if (! global_status_tool)
 
311
  {
 
312
    return true;
 
313
  }
 
314
 
 
315
  cumulative_user_stats_tool= new(nothrow)CumulativeUserStatsTool(logging_stats);
 
316
 
 
317
  if (! cumulative_user_stats_tool)
 
318
  {
 
319
    return true;
 
320
  }
 
321
 
 
322
  scoreboard_stats_tool= new(nothrow)ScoreboardStatsTool(logging_stats);
 
323
  
 
324
  if (! scoreboard_stats_tool)
 
325
  {
 
326
    return true;
 
327
  }
 
328
 
 
329
  return false;
 
330
}
 
331
 
 
332
static int init(drizzled::module::Context &context)
 
333
{
 
334
  const module::option_map &vm= context.getOptions();
 
335
 
 
336
  sysvar_logging_stats_enabled= (vm.count("disable")) ? false : true;
 
337
 
 
338
  logging_stats= new LoggingStats("logging_stats");
 
339
 
 
340
  if (initTable())
 
341
  {
 
342
    return 1;
 
343
  }
 
344
 
 
345
  context.add(logging_stats);
 
346
  context.add(current_commands_tool);
 
347
  context.add(cumulative_commands_tool);
 
348
  context.add(global_statements_tool);
 
349
  context.add(session_statements_tool);
 
350
  context.add(session_status_tool);
 
351
  context.add(global_status_tool);
 
352
  context.add(cumulative_user_stats_tool);
 
353
  context.add(scoreboard_stats_tool);
 
354
 
 
355
  if (sysvar_logging_stats_enabled)
 
356
  {
 
357
    logging_stats->enable();
 
358
  }
 
359
 
 
360
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("max_user_count", sysvar_logging_stats_max_user_count));
 
361
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("bucket_count", sysvar_logging_stats_bucket_count));
 
362
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("scoreboard_size", sysvar_logging_stats_scoreboard_size));
 
363
  context.registerVariable(new sys_var_bool_ptr("enable", &sysvar_logging_stats_enabled, enable));
 
364
 
 
365
  return 0;
 
366
}
 
367
 
 
368
 
 
369
static void init_options(drizzled::module::option_context &context)
 
370
{
 
371
  context("max-user-count",
 
372
          po::value<max_user_count_constraint>(&sysvar_logging_stats_max_user_count)->default_value(500),
 
373
          N_("Max number of users that will be logged"));
 
374
  context("bucket-count",
 
375
          po::value<bucket_count_constraint>(&sysvar_logging_stats_bucket_count)->default_value(10),
 
376
          N_("Max number of range locks to use for Scoreboard"));
 
377
  context("scoreboard-size",
 
378
          po::value<scoreboard_size_constraint>(&sysvar_logging_stats_scoreboard_size)->default_value(2000),
 
379
          N_("Max number of concurrent sessions that will be logged"));
 
380
  context("disable", N_("Enable Logging Statistics Collection"));
 
381
}
 
382
 
 
383
DRIZZLE_DECLARE_PLUGIN
 
384
{
 
385
  DRIZZLE_VERSION_ID,
 
386
  "logging_stats",
 
387
  "0.1",
 
388
  "Joseph Daly",
 
389
  N_("User Statistics as DATA_DICTIONARY tables"),
 
390
  PLUGIN_LICENSE_BSD,
 
391
  init,   /* Plugin Init      */
 
392
  NULL, /* system variables */
 
393
  init_options    /* config options   */
 
394
}
 
395
DRIZZLE_DECLARE_PLUGIN_END;