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 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.
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.
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
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.
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
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.
59
86
#include "config.h"
70
97
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
72
pthread_rwlock_t LOCK_scoreboard;
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;
74
105
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);
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);
87
120
LoggingStats::~LoggingStats()
89
(void) pthread_rwlock_destroy(&LOCK_scoreboard);
90
delete[] score_board_slots;
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;
93
150
bool LoggingStats::isBeingLogged(Session *session)
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)
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)
181
/* Check if this session is the one using this slot */
182
if (score_board_slot->getSessionId() == session->getSessionId())
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 */
194
/* save off the open slot */
267
updateCumulativeStatsByUserVector(scoreboard_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);
269
delete scoreboard_slot;
228
bool LoggingStats::postEnd(Session *session)
275
void LoggingStats::updateCumulativeStatsByUserVector(ScoreboardSlot *current_scoreboard_slot)
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();
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);
250
pthread_rwlock_unlock(&LOCK_scoreboard);
255
297
/* Plugin initialization and system variables */
257
299
static LoggingStats *logging_stats= NULL;
259
static CommandsTool *commands_tool= NULL;
301
static CurrentCommandsTool *current_commands_tool= NULL;
303
static CumulativeCommandsTool *cumulative_commands_tool= NULL;
261
305
static void enable(Session *,
262
306
drizzle_sys_var *,
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 */
313
387
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
314
388
sysvar_logging_stats_scoreboard_size,
315
389
PLUGIN_VAR_RQCMDARG,