~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_stats/logging_stats.cc

  • Committer: Brian Aker
  • Date: 2009-10-15 00:22:33 UTC
  • mto: (1183.1.11 merge)
  • mto: This revision was merged to the branch mainline in revision 1198.
  • Revision ID: brian@gaz-20091015002233-fa4ao2mbc67wls91
First pass of information engine. OMG, ponies... is it so much easier to
deal with creating and engine.

The list table iterator though... its ass, needs to go. We should also
abstract out share. Very few engines need a custom one. Just say'in

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;