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.
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
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
* 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
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.
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.
69
* logging_stats_scoreboard_size - the size of the scoreboard this corresponds
70
* to the maximum number of concurrent connections that can be tracked
72
* logging_stats_max_user_count - this is used for cumulative statistics it
73
* represents the maximum users that can be tracked
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.
79
* logging_stats_enabled - enable/disable plugin
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.
83
* Allow expansion of Scoreboard and cumulative vector
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>
98
namespace po= boost::program_options;
64
99
using namespace drizzled;
65
100
using namespace plugin;
66
101
using namespace std;
68
static bool sysvar_logging_stats_enabled= false;
103
static bool sysvar_logging_stats_enabled= true;
70
105
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
72
pthread_rwlock_t LOCK_scoreboard;
107
static uint32_t sysvar_logging_stats_max_user_count= 500;
109
static uint32_t sysvar_logging_stats_bucket_count= 10;
74
111
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);
113
current_scoreboard= new Scoreboard(sysvar_logging_stats_scoreboard_size,
114
sysvar_logging_stats_bucket_count);
116
cumulative_stats= new CumulativeStats(sysvar_logging_stats_max_user_count);
87
119
LoggingStats::~LoggingStats()
89
(void) pthread_rwlock_destroy(&LOCK_scoreboard);
90
delete[] score_board_slots;
121
delete current_scoreboard;
122
delete cumulative_stats;
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();
125
void LoggingStats::updateCurrentScoreboard(ScoreboardSlot *scoreboard_slot,
128
enum_sql_command sql_command= session->lex->sql_command;
130
scoreboard_slot->getUserCommands()->logCommand(sql_command);
132
/* If a flush occurred copy over values before setting new values */
133
if (scoreboard_slot->getStatusVars()->hasBeenFlushed(session))
135
cumulative_stats->logGlobalStatusVars(scoreboard_slot);
137
scoreboard_slot->getStatusVars()->logStatusVar(session);
155
140
bool LoggingStats::post(Session *session)
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);
147
ScoreboardSlot *scoreboard_slot= current_scoreboard->findScoreboardSlotToLog(session);
149
/* Its possible that the scoreboard is full with active sessions in which case
150
this could be null */
153
updateCurrentScoreboard(scoreboard_slot, session);
228
158
bool LoggingStats::postEnd(Session *session)
230
if (! isEnabled() || (session->getSessionId() == 0))
160
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++)
165
bool isInScoreboard= false;
166
ScoreboardSlot *scoreboard_slot= current_scoreboard->findOurScoreboardSlot(session);
241
score_board_slot= &score_board_slots[j];
243
if (score_board_slot->getSessionId() == session->getSessionId())
245
score_board_slot->reset();
170
isInScoreboard= true;
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.
180
scoreboard_slot= new ScoreboardSlot();
181
scoreboard_slot->setUser(session->getSecurityContext().getUser());
182
scoreboard_slot->setIp(session->getSecurityContext().getIp());
250
pthread_rwlock_unlock(&LOCK_scoreboard);
185
scoreboard_slot->getStatusVars()->logStatusVar(session);
186
scoreboard_slot->getStatusVars()->getStatusVarCounters()->connection_time= time(NULL) - session->start_time;
188
cumulative_stats->logUserStats(scoreboard_slot, isInScoreboard);
189
cumulative_stats->logGlobalStats(scoreboard_slot);
190
cumulative_stats->logGlobalStatusVars(scoreboard_slot);
194
scoreboard_slot->reset();
198
delete scoreboard_slot;
281
244
static bool initTable()
283
commands_tool= new(nothrow)CommandsTool(logging_stats);
246
current_commands_tool= new(nothrow)CurrentCommandsTool(logging_stats);
248
if (! current_commands_tool)
253
cumulative_commands_tool= new(nothrow)CumulativeCommandsTool(logging_stats);
255
if (! cumulative_commands_tool)
260
global_statements_tool= new(nothrow)GlobalStatementsTool(logging_stats);
262
if (! global_statements_tool)
267
session_statements_tool= new(nothrow)SessionStatementsTool(logging_stats);
269
if (! session_statements_tool)
274
session_status_tool= new(nothrow)StatusTool(logging_stats, true);
276
if (! session_status_tool)
281
global_status_tool= new(nothrow)StatusTool(logging_stats, false);
283
if (! global_status_tool)
288
cumulative_user_stats_tool= new(nothrow)CumulativeUserStatsTool(logging_stats);
290
if (! cumulative_user_stats_tool)
295
scoreboard_stats_tool= new(nothrow)ScoreboardStatsTool(logging_stats);
297
if (! scoreboard_stats_tool)
327
397
N_("Enable Logging Statistics Collection"),
328
398
NULL, /* check func */
329
399
enable, /* update func */
330
false /* default */);
402
static void init_options(drizzled::module::option_context &context)
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"));
414
po::value<bool>(&sysvar_logging_stats_enabled)->default_value(true)->zero_tokens(),
415
N_("Enable Logging Statistics Collection"));
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),