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 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.
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.
46
* A read lock is taken when the table is queried in the data_dictionary.
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.
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.
60
#include "logging_stats.h"
61
#include "stats_schema.h"
62
#include <drizzled/session.h>
64
using namespace drizzled;
65
using namespace plugin;
68
static bool sysvar_logging_stats_enabled= false;
70
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
72
pthread_rwlock_t LOCK_scoreboard;
74
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
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++)
81
UserCommands *user_commands= new UserCommands();
82
ScoreBoardSlot *score_board_slot= &score_board_slots[j];
83
score_board_slot->setUserCommands(user_commands);
87
LoggingStats::~LoggingStats()
89
(void) pthread_rwlock_destroy(&LOCK_scoreboard);
90
delete[] score_board_slots;
93
bool LoggingStats::isBeingLogged(Session *session)
95
enum_sql_command sql_command= session->lex->sql_command;
102
case SQLCOM_ROLLBACK:
104
case SQLCOM_CREATE_TABLE:
105
case SQLCOM_ALTER_TABLE:
106
case SQLCOM_DROP_TABLE:
114
void LoggingStats::updateScoreBoard(ScoreBoardSlot *score_board_slot,
117
enum_sql_command sql_command= session->lex->sql_command;
119
UserCommands *user_commands= score_board_slot->getUserCommands();
124
user_commands->incrementUpdateCount();
127
user_commands->incrementDeleteCount();
130
user_commands->incrementInsertCount();
132
case SQLCOM_ROLLBACK:
133
user_commands->incrementRollbackCount();
136
user_commands->incrementCommitCount();
138
case SQLCOM_CREATE_TABLE:
139
user_commands->incrementCreateCount();
141
case SQLCOM_ALTER_TABLE:
142
user_commands->incrementAlterCount();
144
case SQLCOM_DROP_TABLE:
145
user_commands->incrementDropCount();
148
user_commands->incrementSelectCount();
155
bool LoggingStats::post(Session *session)
157
if (! isEnabled() || (session->getSessionId() == 0))
162
/* exit early if we are not logging this type of command */
163
if (isBeingLogged(session) == false)
168
/* Find a slot that is unused */
170
pthread_rwlock_wrlock(&LOCK_scoreboard);
171
ScoreBoardSlot *score_board_slot;
172
int our_slot= UNINITIALIZED;
173
int open_slot= UNINITIALIZED;
175
for (uint32_t j=0; j < scoreboard_size; j++)
177
score_board_slot= &score_board_slots[j];
179
if (score_board_slot->isInUse() == true)
181
/* Check if this session is the one using this slot */
182
if (score_board_slot->getSessionId() == session->getSessionId())
194
/* save off the open slot */
203
if (our_slot != UNINITIALIZED)
205
pthread_rwlock_unlock(&LOCK_scoreboard);
207
else if (open_slot != UNINITIALIZED)
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);
218
pthread_rwlock_unlock(&LOCK_scoreboard);
219
/* there was no available slot for this session */
223
updateScoreBoard(score_board_slot, session);
228
bool LoggingStats::postEnd(Session *session)
230
if (! isEnabled() || (session->getSessionId() == 0))
235
ScoreBoardSlot *score_board_slot;
237
pthread_rwlock_wrlock(&LOCK_scoreboard);
239
for (uint32_t j=0; j < scoreboard_size; j++)
241
score_board_slot= &score_board_slots[j];
243
if (score_board_slot->getSessionId() == session->getSessionId())
245
score_board_slot->reset();
250
pthread_rwlock_unlock(&LOCK_scoreboard);
255
/* Plugin initialization and system variables */
257
static LoggingStats *logging_stats= NULL;
259
static CommandsTool *commands_tool= NULL;
261
static void enable(Session *,
268
if (*(bool *)save != false)
270
logging_stats->enable();
271
*(bool *) var_ptr= (bool) true;
275
logging_stats->disable();
276
*(bool *) var_ptr= (bool) false;
281
static bool initTable()
283
commands_tool= new(nothrow)CommandsTool(logging_stats);
293
static int init(drizzled::plugin::Context &context)
295
logging_stats= new LoggingStats("logging_stats");
302
context.add(logging_stats);
303
context.add(commands_tool);
305
if (sysvar_logging_stats_enabled)
307
logging_stats->enable();
313
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
314
sysvar_logging_stats_scoreboard_size,
316
N_("Max number of concurrent sessions that will be logged"),
317
NULL, /* check func */
318
NULL, /* update func */
324
static DRIZZLE_SYSVAR_BOOL(enable,
325
sysvar_logging_stats_enabled,
327
N_("Enable Logging Statistics Collection"),
328
NULL, /* check func */
329
enable, /* update func */
330
false /* default */);
332
static drizzle_sys_var* system_var[]= {
333
DRIZZLE_SYSVAR(scoreboard_size),
334
DRIZZLE_SYSVAR(enable),
338
DRIZZLE_DECLARE_PLUGIN
344
N_("User Statistics as DATA_DICTIONARY tables"),
346
init, /* Plugin Init */
347
system_var, /* system variables */
348
NULL /* config options */
350
DRIZZLE_DECLARE_PLUGIN_END;