2
* Copyright (c) 2010, Joseph Daly <skinny.moey@gmail.com>
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
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.
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.
33
* This plugin tracks the current user commands for a session, and copies
34
* them into a cumulative vector of all commands run by a user over time.
35
* The commands are logged using the post() and postEnd() logging APIs.
36
* User commands are stored in a Scoreboard where each active session
37
* owns a ScoreboardSlot.
41
* The scoreboard is a pre-allocated vector of vectors of ScoreboardSlots. It
42
* can be thought of as a vector of buckets where each bucket contains
43
* pre-allocated ScoreboardSlots. To determine which bucket gets used for
44
* recording statistics the modulus operator is used on the session_id. This
45
* will result in a bucket to search for a unused ScoreboardSlot.
49
* Each vector in the Scoreboard has its own lock. This allows session 2
50
* to not have to wait for session 1 to locate a slot to use, as they
51
* will be in different buckets. A lock is taken to locate a open slot
52
* in the scoreboard for a session or to locate the slot that the current
53
* session has claimed.
55
* A read lock is taken on the scoreboard vector when the table is queried
56
* in the data_dictionary.
58
* A lock is taken when a new user is added to the cumulative vector
59
* repeat connections with a already used user will not use a lock.
63
* logging_stats_scoreboard_size - the size of the scoreboard this corresponds
64
* to the maximum number of concurrent connections that can be tracked
66
* logging_stats_max_user_count - this is used for cumulative statistics it
67
* represents the maximum users that can be tracked
69
* logging_stats_bucket_count - the number of buckets to have in the scoreboard
70
* this splits up locking across several buckets so the entire scoreboard is
71
* not locked at a single point in time.
73
* logging_stats_enabled - enable/disable plugin
77
* A pointer to the scoreboard slot could be added to the Session object.
78
* This will avoid the session having to do multiple lookups in the scoreboard,
79
* this will also avoid having to take a lock to locate the scoreboard slot
80
* being used by a particular session.
82
* Allow expansion of Scoreboard and cumulative vector
87
#include "logging_stats.h"
88
#include "stats_schema.h"
89
#include <drizzled/session.h>
91
using namespace drizzled;
92
using namespace plugin;
95
static bool sysvar_logging_stats_enabled= false;
97
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
99
static uint32_t sysvar_logging_stats_max_user_count= 10000;
101
static uint32_t sysvar_logging_stats_bucket_count= 10;
103
pthread_rwlock_t LOCK_cumulative_scoreboard_index;
105
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
107
(void) pthread_rwlock_init(&LOCK_cumulative_scoreboard_index, NULL);
108
cumulative_stats_by_user_index= 0;
110
current_scoreboard= new Scoreboard(sysvar_logging_stats_scoreboard_size,
111
sysvar_logging_stats_bucket_count);
113
cumulative_stats_by_user_max= sysvar_logging_stats_max_user_count;
115
cumulative_stats_by_user_vector= new vector<ScoreboardSlot *>(cumulative_stats_by_user_max);
116
preAllocateScoreboardSlotVector(sysvar_logging_stats_max_user_count,
117
cumulative_stats_by_user_vector);
120
LoggingStats::~LoggingStats()
122
(void) pthread_rwlock_destroy(&LOCK_cumulative_scoreboard_index);
123
deleteScoreboardSlotVector(cumulative_stats_by_user_vector);
124
delete current_scoreboard;
127
void LoggingStats::preAllocateScoreboardSlotVector(uint32_t size,
128
vector<ScoreboardSlot *> *scoreboard_slot_vector)
130
vector<ScoreboardSlot *>::iterator it= scoreboard_slot_vector->begin();
131
for (uint32_t j=0; j < size; ++j)
133
ScoreboardSlot *scoreboard_slot= new ScoreboardSlot();
134
it= scoreboard_slot_vector->insert(it, scoreboard_slot);
136
scoreboard_slot_vector->resize(size);
139
void LoggingStats::deleteScoreboardSlotVector(vector<ScoreboardSlot *> *scoreboard_slot_vector)
141
vector<ScoreboardSlot *>::iterator it= scoreboard_slot_vector->begin();
142
for (; it < scoreboard_slot_vector->end(); ++it)
146
scoreboard_slot_vector->clear();
147
delete scoreboard_slot_vector;
150
bool LoggingStats::isBeingLogged(Session *session)
152
enum_sql_command sql_command= session->lex->sql_command;
159
case SQLCOM_ROLLBACK:
161
case SQLCOM_CREATE_TABLE:
162
case SQLCOM_ALTER_TABLE:
163
case SQLCOM_DROP_TABLE:
171
void LoggingStats::updateCurrentScoreboard(ScoreboardSlot *scoreboard_slot,
174
enum_sql_command sql_command= session->lex->sql_command;
176
UserCommands *user_commands= scoreboard_slot->getUserCommands();
181
user_commands->incrementUpdateCount();
184
user_commands->incrementDeleteCount();
187
user_commands->incrementInsertCount();
189
case SQLCOM_ROLLBACK:
190
user_commands->incrementRollbackCount();
193
user_commands->incrementCommitCount();
195
case SQLCOM_CREATE_TABLE:
196
user_commands->incrementCreateCount();
198
case SQLCOM_ALTER_TABLE:
199
user_commands->incrementAlterCount();
201
case SQLCOM_DROP_TABLE:
202
user_commands->incrementDropCount();
205
user_commands->incrementSelectCount();
212
bool LoggingStats::post(Session *session)
214
if (! isEnabled() || (session->getSessionId() == 0))
219
/* exit early if we are not logging this type of command */
220
if (isBeingLogged(session) == false)
225
ScoreboardSlot *scoreboard_slot= current_scoreboard->findScoreboardSlotToLog(session);
227
/* Its possible that the scoreboard is full with active sessions in which case
228
this could be null */
231
updateCurrentScoreboard(scoreboard_slot, session);
236
bool LoggingStats::postEnd(Session *session)
238
if (! isEnabled() || (session->getSessionId() == 0))
243
ScoreboardSlot *scoreboard_slot= current_scoreboard->findAndResetScoreboardSlot(session);
247
vector<ScoreboardSlot *>::iterator cumulative_it= cumulative_stats_by_user_vector->begin();
250
/* Search if this is a pre-existing user */
251
for (uint32_t h= 0; h < cumulative_stats_by_user_index; ++h)
253
ScoreboardSlot *cumulative_scoreboard_slot= *cumulative_it;
254
string user= cumulative_scoreboard_slot->getUser();
255
if (user.compare(scoreboard_slot->getUser()) == 0)
258
cumulative_scoreboard_slot->merge(scoreboard_slot);
264
/* this will add a new user */
267
updateCumulativeStatsByUserVector(scoreboard_slot);
269
delete scoreboard_slot;
275
void LoggingStats::updateCumulativeStatsByUserVector(ScoreboardSlot *current_scoreboard_slot)
277
/* Check twice if the user table is full, do not grab a lock each time */
278
if (cumulative_stats_by_user_max > cumulative_stats_by_user_index)
280
pthread_rwlock_wrlock(&LOCK_cumulative_scoreboard_index);
282
if (cumulative_stats_by_user_max > cumulative_stats_by_user_index)
284
ScoreboardSlot *cumulative_scoreboard_slot=
285
cumulative_stats_by_user_vector->at(cumulative_stats_by_user_index);
286
string cumulative_scoreboard_user(current_scoreboard_slot->getUser());
287
cumulative_scoreboard_slot->setUser(cumulative_scoreboard_user);
288
cumulative_scoreboard_slot->merge(current_scoreboard_slot);
289
++cumulative_stats_by_user_index;
292
pthread_rwlock_unlock(&LOCK_cumulative_scoreboard_index);
297
/* Plugin initialization and system variables */
299
static LoggingStats *logging_stats= NULL;
301
static CurrentCommandsTool *current_commands_tool= NULL;
303
static CumulativeCommandsTool *cumulative_commands_tool= NULL;
305
static void enable(Session *,
312
if (*(bool *)save != false)
314
logging_stats->enable();
315
*(bool *) var_ptr= (bool) true;
319
logging_stats->disable();
320
*(bool *) var_ptr= (bool) false;
325
static bool initTable()
327
current_commands_tool= new(nothrow)CurrentCommandsTool(logging_stats);
329
if (! current_commands_tool)
334
cumulative_commands_tool= new(nothrow)CumulativeCommandsTool(logging_stats);
336
if (! cumulative_commands_tool)
344
static int init(Context &context)
346
logging_stats= new LoggingStats("logging_stats");
353
context.add(logging_stats);
354
context.add(current_commands_tool);
355
context.add(cumulative_commands_tool);
357
if (sysvar_logging_stats_enabled)
359
logging_stats->enable();
365
static DRIZZLE_SYSVAR_UINT(max_user_count,
366
sysvar_logging_stats_max_user_count,
368
N_("Max number of users that will be logged"),
369
NULL, /* check func */
370
NULL, /* update func */
376
static DRIZZLE_SYSVAR_UINT(bucket_count,
377
sysvar_logging_stats_bucket_count,
379
N_("Max number of vector buckets to construct for logging"),
380
NULL, /* check func */
381
NULL, /* update func */
387
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
388
sysvar_logging_stats_scoreboard_size,
390
N_("Max number of concurrent sessions that will be logged"),
391
NULL, /* check func */
392
NULL, /* update func */
398
static DRIZZLE_SYSVAR_BOOL(enable,
399
sysvar_logging_stats_enabled,
401
N_("Enable Logging Statistics Collection"),
402
NULL, /* check func */
403
enable, /* update func */
404
false /* default */);
406
static drizzle_sys_var* system_var[]= {
407
DRIZZLE_SYSVAR(max_user_count),
408
DRIZZLE_SYSVAR(bucket_count),
409
DRIZZLE_SYSVAR(scoreboard_size),
410
DRIZZLE_SYSVAR(enable),
414
DRIZZLE_DECLARE_PLUGIN
420
N_("User Statistics as DATA_DICTIONARY tables"),
422
init, /* Plugin Init */
423
system_var, /* system variables */
424
NULL /* config options */
426
DRIZZLE_DECLARE_PLUGIN_END;