~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_stats/logging_stats.cc

Cleanup around SAFEMALLOC

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 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. 
40
 
 *
41
 
 * Locking  
42
 
 *
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. 
45
 
 * 
46
 
 * A read lock is taken when the table is queried in the data_dictionary.
47
 
 * 
48
 
 * TODO 
49
 
 *
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.  
53
 
 *  
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. 
56
 
 * 
57
 
 */
58
 
 
59
 
#include "config.h"
60
 
#include "logging_stats.h"
61
 
#include "stats_schema.h"
62
 
#include <drizzled/session.h>
63
 
 
64
 
using namespace drizzled;
65
 
using namespace plugin;
66
 
using namespace std;
67
 
 
68
 
static bool sysvar_logging_stats_enabled= false;
69
 
 
70
 
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
71
 
 
72
 
pthread_rwlock_t LOCK_scoreboard;
73
 
 
74
 
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
75
 
{
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++)
80
 
  { 
81
 
    UserCommands *user_commands= new UserCommands();
82
 
    ScoreBoardSlot *score_board_slot= &score_board_slots[j];
83
 
    score_board_slot->setUserCommands(user_commands); 
84
 
  } 
85
 
}
86
 
 
87
 
LoggingStats::~LoggingStats()
88
 
{
89
 
  (void) pthread_rwlock_destroy(&LOCK_scoreboard);
90
 
  delete[] score_board_slots;
91
 
}
92
 
 
93
 
bool LoggingStats::isBeingLogged(Session *session)
94
 
{
95
 
  enum_sql_command sql_command= session->lex->sql_command;
96
 
 
97
 
  switch(sql_command)
98
 
  {
99
 
    case SQLCOM_UPDATE:
100
 
    case SQLCOM_DELETE:
101
 
    case SQLCOM_INSERT:
102
 
    case SQLCOM_ROLLBACK:
103
 
    case SQLCOM_COMMIT:
104
 
    case SQLCOM_CREATE_TABLE:
105
 
    case SQLCOM_ALTER_TABLE:
106
 
    case SQLCOM_DROP_TABLE:
107
 
    case SQLCOM_SELECT:
108
 
      return true;
109
 
    default:
110
 
      return false;
111
 
  }
112
 
113
 
 
114
 
void LoggingStats::updateScoreBoard(ScoreBoardSlot *score_board_slot,
115
 
                                    Session *session)
116
 
{
117
 
  enum_sql_command sql_command= session->lex->sql_command;
118
 
 
119
 
  UserCommands *user_commands= score_board_slot->getUserCommands();
120
 
 
121
 
  switch(sql_command)
122
 
  {
123
 
    case SQLCOM_UPDATE:
124
 
      user_commands->incrementUpdateCount();
125
 
      break;
126
 
    case SQLCOM_DELETE:
127
 
      user_commands->incrementDeleteCount();
128
 
      break;
129
 
    case SQLCOM_INSERT:
130
 
      user_commands->incrementInsertCount();
131
 
      break;
132
 
    case SQLCOM_ROLLBACK:
133
 
      user_commands->incrementRollbackCount();
134
 
      break;
135
 
    case SQLCOM_COMMIT:
136
 
      user_commands->incrementCommitCount();
137
 
      break;
138
 
    case SQLCOM_CREATE_TABLE:
139
 
      user_commands->incrementCreateCount();
140
 
      break;
141
 
    case SQLCOM_ALTER_TABLE:
142
 
      user_commands->incrementAlterCount();
143
 
      break;
144
 
    case SQLCOM_DROP_TABLE:
145
 
      user_commands->incrementDropCount();
146
 
      break;
147
 
    case SQLCOM_SELECT:
148
 
      user_commands->incrementSelectCount();
149
 
      break;
150
 
    default:
151
 
      return;
152
 
  }
153
 
}
154
 
 
155
 
bool LoggingStats::post(Session *session)
156
 
{
157
 
  if (! isEnabled() || (session->getSessionId() == 0))
158
 
  {
159
 
    return false;
160
 
  }
161
 
 
162
 
  /* exit early if we are not logging this type of command */
163
 
  if (isBeingLogged(session) == false)
164
 
  {
165
 
    return false;
166
 
  }
167
 
 
168
 
  /* Find a slot that is unused */
169
 
 
170
 
  pthread_rwlock_wrlock(&LOCK_scoreboard);
171
 
  ScoreBoardSlot *score_board_slot;
172
 
  int our_slot= UNINITIALIZED; 
173
 
  int open_slot= UNINITIALIZED;
174
 
 
175
 
  for (uint32_t j=0; j < scoreboard_size; j++)
176
 
  {
177
 
    score_board_slot= &score_board_slots[j];
178
 
 
179
 
    if (score_board_slot->isInUse() == true)
180
 
    {
181
 
      /* Check if this session is the one using this slot */
182
 
      if (score_board_slot->getSessionId() == session->getSessionId())
183
 
      {
184
 
        our_slot= j;
185
 
        break; 
186
 
      } 
187
 
      else 
188
 
      {
189
 
        continue; 
190
 
      }
191
 
    }
192
 
    else 
193
 
    {
194
 
      /* save off the open slot */ 
195
 
      if (open_slot == -1)
196
 
      {
197
 
        open_slot= j;
198
 
      } 
199
 
      continue;
200
 
    }
201
 
  }
202
 
 
203
 
  if (our_slot != UNINITIALIZED)
204
 
  {
205
 
    pthread_rwlock_unlock(&LOCK_scoreboard); 
206
 
  }
207
 
  else if (open_slot != UNINITIALIZED)
208
 
  {
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);
215
 
  }
216
 
  else 
217
 
  {
218
 
    pthread_rwlock_unlock(&LOCK_scoreboard);
219
 
    /* there was no available slot for this session */
220
 
    return false;
221
 
  }
222
 
 
223
 
  updateScoreBoard(score_board_slot, session);
224
 
 
225
 
  return false;
226
 
}
227
 
 
228
 
bool LoggingStats::postEnd(Session *session)
229
 
{
230
 
  if (! isEnabled() || (session->getSessionId() == 0)) 
231
 
  {
232
 
    return false;
233
 
  }
234
 
 
235
 
  ScoreBoardSlot *score_board_slot;
236
 
 
237
 
  pthread_rwlock_wrlock(&LOCK_scoreboard);
238
 
 
239
 
  for (uint32_t j=0; j < scoreboard_size; j++)
240
 
  {
241
 
    score_board_slot= &score_board_slots[j];
242
 
 
243
 
    if (score_board_slot->getSessionId() == session->getSessionId())
244
 
    {
245
 
      score_board_slot->reset();
246
 
      break;
247
 
    }
248
 
  }
249
 
 
250
 
  pthread_rwlock_unlock(&LOCK_scoreboard);
251
 
 
252
 
  return false;
253
 
}
254
 
 
255
 
/* Plugin initialization and system variables */
256
 
 
257
 
static LoggingStats *logging_stats= NULL;
258
 
 
259
 
static CommandsTool *commands_tool= NULL;
260
 
 
261
 
static void enable(Session *,
262
 
                   drizzle_sys_var *,
263
 
                   void *var_ptr,
264
 
                   const void *save)
265
 
{
266
 
  if (logging_stats)
267
 
  {
268
 
    if (*(bool *)save != false)
269
 
    {
270
 
      logging_stats->enable();
271
 
      *(bool *) var_ptr= (bool) true;
272
 
    }
273
 
    else
274
 
    {
275
 
      logging_stats->disable();
276
 
      *(bool *) var_ptr= (bool) false;
277
 
    }
278
 
  }
279
 
}
280
 
 
281
 
static bool initTable()
282
 
{
283
 
  commands_tool= new(nothrow)CommandsTool(logging_stats);
284
 
 
285
 
  if (! commands_tool)
286
 
  {
287
 
    return true;
288
 
  }
289
 
 
290
 
  return false;
291
 
}
292
 
 
293
 
static int init(drizzled::plugin::Context &context)
294
 
{
295
 
  logging_stats= new LoggingStats("logging_stats");
296
 
 
297
 
  if (initTable())
298
 
  {
299
 
    return 1;
300
 
  }
301
 
 
302
 
  context.add(logging_stats);
303
 
  context.add(commands_tool);
304
 
 
305
 
  if (sysvar_logging_stats_enabled)
306
 
  {
307
 
    logging_stats->enable();
308
 
  }
309
 
 
310
 
  return 0;
311
 
}
312
 
 
313
 
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
314
 
                           sysvar_logging_stats_scoreboard_size,
315
 
                           PLUGIN_VAR_RQCMDARG,
316
 
                           N_("Max number of concurrent sessions that will be logged"),
317
 
                           NULL, /* check func */
318
 
                           NULL, /* update func */
319
 
                           2000, /* default */
320
 
                           1000, /* minimum */
321
 
                           50000, 
322
 
                           0);
323
 
 
324
 
static DRIZZLE_SYSVAR_BOOL(enable,
325
 
                           sysvar_logging_stats_enabled,
326
 
                           PLUGIN_VAR_NOCMDARG,
327
 
                           N_("Enable Logging Statistics Collection"),
328
 
                           NULL, /* check func */
329
 
                           enable, /* update func */
330
 
                           false /* default */);
331
 
 
332
 
static drizzle_sys_var* system_var[]= {
333
 
  DRIZZLE_SYSVAR(scoreboard_size),
334
 
  DRIZZLE_SYSVAR(enable),
335
 
  NULL
336
 
};
337
 
 
338
 
DRIZZLE_DECLARE_PLUGIN
339
 
{
340
 
  DRIZZLE_VERSION_ID,
341
 
  "logging_stats",
342
 
  "0.1",
343
 
  "Joseph Daly",
344
 
  N_("User Statistics as DATA_DICTIONARY tables"),
345
 
  PLUGIN_LICENSE_BSD,
346
 
  init,   /* Plugin Init      */
347
 
  system_var, /* system variables */
348
 
  NULL    /* config options   */
349
 
}
350
 
DRIZZLE_DECLARE_PLUGIN_END;