~drizzle-trunk/drizzle/development

1320.4.1 by Joe Daly
scoreboard implementation for statistics
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
 *
1320.4.6 by Joe Daly
update comment
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  
1320.4.5 by Joe Daly
fix tests which were may not have been deterministic because of the ip field, add comments, add scoreboard size as a system var, remove multiple setting in a scoreboard slot
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 
1320.4.6 by Joe Daly
update comment
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
 *  
1320.4.5 by Joe Daly
fix tests which were may not have been deterministic because of the ip field, add comments, add scoreboard size as a system var, remove multiple setting in a scoreboard slot
54
 * Save the statistics off into a vector so you can query by user/ip and get
1320.4.6 by Joe Daly
update comment
55
 * commands run based on those keys over time. 
1320.4.5 by Joe Daly
fix tests which were may not have been deterministic because of the ip field, add comments, add scoreboard size as a system var, remove multiple setting in a scoreboard slot
56
 * 
1320.4.1 by Joe Daly
scoreboard implementation for statistics
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
1320.4.3 by Joe Daly
initialize session id and scoreboard size
70
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
1320.4.1 by Joe Daly
scoreboard implementation for statistics
71
72
pthread_rwlock_t LOCK_scoreboard;
73
1320.4.7 by Joe Daly
fix up some variable names, and namespaces paths in *.cc files, and add constant for UNINITIALIZED
74
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
1320.4.1 by Joe Daly
scoreboard implementation for statistics
75
{
76
  scoreboard_size= sysvar_logging_stats_scoreboard_size;
77
  score_board_slots= new ScoreBoardSlot[scoreboard_size];
78
  for (uint32_t j=0; j < scoreboard_size; j++)
79
  { 
80
    UserCommands *user_commands= new UserCommands();
81
    ScoreBoardSlot *score_board_slot= &score_board_slots[j];
82
    score_board_slot->setUserCommands(user_commands); 
83
  } 
84
}
85
86
LoggingStats::~LoggingStats()
87
{
88
  delete[] score_board_slots;
89
}
90
91
bool LoggingStats::isBeingLogged(Session *session)
92
{
93
  enum_sql_command sql_command= session->lex->sql_command;
94
95
  switch(sql_command)
96
  {
97
    case SQLCOM_UPDATE:
98
    case SQLCOM_DELETE:
99
    case SQLCOM_INSERT:
100
    case SQLCOM_ROLLBACK:
101
    case SQLCOM_COMMIT:
102
    case SQLCOM_CREATE_TABLE:
103
    case SQLCOM_ALTER_TABLE:
104
    case SQLCOM_DROP_TABLE:
105
    case SQLCOM_SELECT:
106
      return true;
107
    default:
108
      return false;
109
  }
110
} 
111
112
void LoggingStats::updateScoreBoard(ScoreBoardSlot *score_board_slot,
113
                                    Session *session)
114
{
115
  enum_sql_command sql_command= session->lex->sql_command;
116
117
  UserCommands *user_commands= score_board_slot->getUserCommands();
118
119
  switch(sql_command)
120
  {
121
    case SQLCOM_UPDATE:
122
      user_commands->incrementUpdateCount();
123
      break;
124
    case SQLCOM_DELETE:
125
      user_commands->incrementDeleteCount();
126
      break;
127
    case SQLCOM_INSERT:
128
      user_commands->incrementInsertCount();
129
      break;
130
    case SQLCOM_ROLLBACK:
131
      user_commands->incrementRollbackCount();
132
      break;
133
    case SQLCOM_COMMIT:
134
      user_commands->incrementCommitCount();
135
      break;
136
    case SQLCOM_CREATE_TABLE:
137
      user_commands->incrementCreateCount();
138
      break;
139
    case SQLCOM_ALTER_TABLE:
140
      user_commands->incrementAlterCount();
141
      break;
142
    case SQLCOM_DROP_TABLE:
143
      user_commands->incrementDropCount();
144
      break;
145
    case SQLCOM_SELECT:
146
      user_commands->incrementSelectCount();
147
      break;
148
    default:
149
      return;
150
  }
151
}
152
153
bool LoggingStats::post(Session *session)
154
{
155
  if (! isEnabled())
156
  {
157
    return false;
158
  }
159
160
  /* exit early if we are not logging this type of command */
161
  if (isBeingLogged(session) == false)
162
  {
163
    return false;
164
  }
165
166
  /* Find a slot that is unused */
167
168
  pthread_rwlock_wrlock(&LOCK_scoreboard);
169
  ScoreBoardSlot *score_board_slot;
1320.4.7 by Joe Daly
fix up some variable names, and namespaces paths in *.cc files, and add constant for UNINITIALIZED
170
  int our_slot= UNINITIALIZED; 
171
  int open_slot= UNINITIALIZED;
1320.4.1 by Joe Daly
scoreboard implementation for statistics
172
173
  for (uint32_t j=0; j < scoreboard_size; j++)
174
  {
175
    score_board_slot= &score_board_slots[j];
176
177
    if (score_board_slot->isInUse() == true)
178
    {
179
      /* Check if this session is the one using this slot */
180
      if (score_board_slot->getSessionId() == session->getSessionId())
181
      {
182
        our_slot= j;
183
        break; 
184
      } 
185
      else 
186
      {
187
        continue; 
188
      }
189
    }
190
    else 
191
    {
192
      /* save off the open slot */ 
1320.4.2 by Joe Daly
add tests and get them working
193
      if (open_slot == -1)
194
      {
195
        open_slot= j;
196
      } 
1320.4.1 by Joe Daly
scoreboard implementation for statistics
197
      continue;
198
    }
199
  }
200
1320.4.7 by Joe Daly
fix up some variable names, and namespaces paths in *.cc files, and add constant for UNINITIALIZED
201
  if (our_slot != UNINITIALIZED)
1320.4.1 by Joe Daly
scoreboard implementation for statistics
202
  {
203
    pthread_rwlock_unlock(&LOCK_scoreboard); 
204
  }
1320.4.7 by Joe Daly
fix up some variable names, and namespaces paths in *.cc files, and add constant for UNINITIALIZED
205
  else if (open_slot != UNINITIALIZED)
1320.4.2 by Joe Daly
add tests and get them working
206
  {
207
    score_board_slot= &score_board_slots[open_slot];
1393.2.6 by Joe Daly
add a lock in postEnd, as other threads could be reading this in post() function
208
    score_board_slot->setInUse(true);
1320.4.2 by Joe Daly
add tests and get them working
209
    score_board_slot->setSessionId(session->getSessionId());
1393.2.6 by Joe Daly
add a lock in postEnd, as other threads could be reading this in post() function
210
    score_board_slot->setUser(session->getSecurityContext().getUser());
211
    score_board_slot->setIp(session->getSecurityContext().getIp());
1320.4.2 by Joe Daly
add tests and get them working
212
    pthread_rwlock_unlock(&LOCK_scoreboard);
213
  }
1320.4.1 by Joe Daly
scoreboard implementation for statistics
214
  else 
215
  {
216
    pthread_rwlock_unlock(&LOCK_scoreboard);
217
    /* there was no available slot for this session */
218
    return false;
219
  }
220
221
  updateScoreBoard(score_board_slot, session);
222
223
  return false;
224
}
225
226
bool LoggingStats::postEnd(Session *session)
227
{
228
  if (! isEnabled())
229
  {
230
    return false;
231
  }
232
233
  ScoreBoardSlot *score_board_slot;
234
1393.2.6 by Joe Daly
add a lock in postEnd, as other threads could be reading this in post() function
235
  pthread_rwlock_wrlock(&LOCK_scoreboard);
236
1320.4.1 by Joe Daly
scoreboard implementation for statistics
237
  for (uint32_t j=0; j < scoreboard_size; j++)
238
  {
239
    score_board_slot= &score_board_slots[j];
240
241
    if (score_board_slot->getSessionId() == session->getSessionId())
242
    {
243
      score_board_slot->reset();
244
      break;
245
    }
246
  }
1393.2.6 by Joe Daly
add a lock in postEnd, as other threads could be reading this in post() function
247
248
  pthread_rwlock_unlock(&LOCK_scoreboard);
249
1320.4.1 by Joe Daly
scoreboard implementation for statistics
250
  return false;
251
}
252
253
/* Plugin initialization and system variables */
254
255
static LoggingStats *logging_stats= NULL;
256
257
static CommandsTool *commands_tool= NULL;
258
259
static void enable(Session *,
260
                   drizzle_sys_var *,
261
                   void *var_ptr,
262
                   const void *save)
263
{
264
  if (logging_stats)
265
  {
266
    if (*(bool *)save != false)
267
    {
268
      logging_stats->enable();
269
      *(bool *) var_ptr= (bool) true;
270
    }
271
    else
272
    {
273
      logging_stats->disable();
274
      *(bool *) var_ptr= (bool) false;
275
    }
276
  }
277
}
278
279
static bool initTable()
280
{
1320.4.7 by Joe Daly
fix up some variable names, and namespaces paths in *.cc files, and add constant for UNINITIALIZED
281
  commands_tool= new(nothrow)CommandsTool(logging_stats);
1320.4.1 by Joe Daly
scoreboard implementation for statistics
282
283
  if (! commands_tool)
284
  {
285
    return true;
286
  }
287
288
  return false;
289
}
290
1381 by Brian Aker
Merge Monty.
291
static int init(drizzled::plugin::Context &context)
1320.4.1 by Joe Daly
scoreboard implementation for statistics
292
{
293
  logging_stats= new LoggingStats("logging_stats");
294
295
  if (initTable())
296
  {
297
    return 1;
298
  }
299
1381 by Brian Aker
Merge Monty.
300
  context.add(logging_stats);
301
  context.add(commands_tool);
1320.4.1 by Joe Daly
scoreboard implementation for statistics
302
303
  if (sysvar_logging_stats_enabled)
304
  {
305
    logging_stats->enable();
306
  }
307
308
  return 0;
309
}
310
1320.4.5 by Joe Daly
fix tests which were may not have been deterministic because of the ip field, add comments, add scoreboard size as a system var, remove multiple setting in a scoreboard slot
311
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
312
                           sysvar_logging_stats_scoreboard_size,
313
                           PLUGIN_VAR_RQCMDARG,
314
                           N_("Max number of concurrent sessions that will be logged"),
315
                           NULL, /* check func */
316
                           NULL, /* update func */
317
                           2000, /* default */
318
                           1000, /* minimum */
319
                           50000, 
320
                           0);
321
1320.4.1 by Joe Daly
scoreboard implementation for statistics
322
static DRIZZLE_SYSVAR_BOOL(enable,
323
                           sysvar_logging_stats_enabled,
324
                           PLUGIN_VAR_NOCMDARG,
325
                           N_("Enable Logging Statistics Collection"),
326
                           NULL, /* check func */
327
                           enable, /* update func */
328
                           false /* default */);
329
330
static drizzle_sys_var* system_var[]= {
1320.4.5 by Joe Daly
fix tests which were may not have been deterministic because of the ip field, add comments, add scoreboard size as a system var, remove multiple setting in a scoreboard slot
331
  DRIZZLE_SYSVAR(scoreboard_size),
1320.4.1 by Joe Daly
scoreboard implementation for statistics
332
  DRIZZLE_SYSVAR(enable),
333
  NULL
334
};
335
336
DRIZZLE_DECLARE_PLUGIN
337
{
338
  DRIZZLE_VERSION_ID,
339
  "logging_stats",
340
  "0.1",
341
  "Joseph Daly",
342
  N_("User Statistics as DATA_DICTIONARY tables"),
343
  PLUGIN_LICENSE_BSD,
344
  init,   /* Plugin Init      */
345
  system_var, /* system variables */
346
  NULL    /* config options   */
347
}
348
DRIZZLE_DECLARE_PLUGIN_END;