MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
topkeys.c
1 #include <sys/types.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <inttypes.h>
5 #include <string.h>
6 #include <pthread.h>
7 #include <memcached/genhash.h>
8 #include "topkeys.h"
9 
10 static topkey_item_t *topkey_item_init(const void *key, int nkey, rel_time_t ctime) {
11  topkey_item_t *item = calloc(sizeof(topkey_item_t) + nkey, 1);
12  assert(item);
13  assert(key);
14  assert(nkey > 0);
15  item->nkey = nkey;
16  item->ctime = ctime;
17  item->atime = ctime;
18  /* Copy the key into the part trailing the struct */
19  memcpy(item->key, key, nkey);
20  return item;
21 }
22 
23 static inline size_t topkey_item_size(const topkey_item_t *item) {
24  return sizeof(topkey_item_t) + item->nkey;
25 }
26 
27 static inline topkey_item_t* topkeys_tail(topkeys_t *tk) {
28  return (topkey_item_t*)(tk->list.prev);
29 }
30 
31 static int my_hash_eq(const void *k1, size_t nkey1,
32  const void *k2, size_t nkey2) {
33  return nkey1 == nkey2 && memcmp(k1, k2, nkey1) == 0;
34 }
35 
36 topkeys_t *topkeys_init(int max_keys) {
37  topkeys_t *tk = calloc(sizeof(topkeys_t), 1);
38  if (tk == NULL) {
39  return NULL;
40  }
41 
42  pthread_mutex_init(&tk->mutex, NULL);
43  tk->max_keys = max_keys;
44  tk->list.next = &tk->list;
45  tk->list.prev = &tk->list;
46 
47  static struct hash_ops my_hash_ops = {
49  .hasheq = my_hash_eq,
50  .dupKey = NULL,
51  .dupValue = NULL,
52  .freeKey = NULL,
53  .freeValue = NULL,
54  };
55 
56  tk->hash = genhash_init(max_keys, my_hash_ops);
57  if (tk->hash == NULL) {
58  return NULL;
59  }
60  return tk;
61 }
62 
63 void topkeys_free(topkeys_t *tk) {
64  pthread_mutex_destroy(&tk->mutex);
65  genhash_free(tk->hash);
66  dlist_t *p = tk->list.next;
67  while (p != &tk->list) {
68  dlist_t *tmp = p->next;
69  free(p);
70  p = tmp;
71  }
72 }
73 
74 static inline void dlist_remove(dlist_t *list) {
75  assert(list->prev->next == list);
76  assert(list->next->prev == list);
77  list->prev->next = list->next;
78  list->next->prev = list->prev;
79 }
80 
81 static inline void dlist_insert_after(dlist_t *list, dlist_t *new) {
82  new->next = list->next;
83  new->prev = list;
84  list->next->prev = new;
85  list->next = new;
86 }
87 
88 static inline void dlist_iter(dlist_t *list,
89  void (*iterfunc)(dlist_t *item, void *arg),
90  void *arg)
91 {
92  dlist_t *p = list;
93  while ((p = p->next) != list) {
94  iterfunc(p, arg);
95  }
96 }
97 
98 static inline void topkeys_item_delete(topkeys_t *tk, topkey_item_t *item) {
99  genhash_delete(tk->hash, item->key, item->nkey);
100  dlist_remove(&item->list);
101  --tk->nkeys;
102  free(item);
103 }
104 
105 topkey_item_t *topkeys_item_get_or_create(topkeys_t *tk, const void *key, size_t nkey, const rel_time_t ctime) {
106  topkey_item_t *item = genhash_find(tk->hash, key, nkey);
107  if (item == NULL) {
108  item = topkey_item_init(key, nkey, ctime);
109  if (item != NULL) {
110  if (++tk->nkeys > tk->max_keys) {
111  topkeys_item_delete(tk, topkeys_tail(tk));
112  }
113  genhash_update(tk->hash, item->key, item->nkey,
114  item, topkey_item_size(item));
115  } else {
116  return NULL;
117  }
118  } else {
119  dlist_remove(&item->list);
120  }
121  dlist_insert_after(&tk->list, &item->list);
122  return item;
123 }
124 
125 static inline void append_stat(const void *cookie,
126  const char *name,
127  size_t namelen,
128  const char *key,
129  size_t nkey,
130  int value,
131  ADD_STAT add_stats) {
132  char key_str[128];
133  char val_str[128];
134  int klen, vlen;
135 
136  klen = sizeof(key_str) - namelen - 2;
137  if (nkey < klen) {
138  klen = nkey;
139  }
140  memcpy(key_str, key, klen);
141  key_str[klen] = '.';
142  memcpy(&key_str[klen+1], name, namelen + 1);
143  klen += namelen + 1;
144  vlen = snprintf(val_str, sizeof(val_str) - 1, "%d", value);
145  add_stats(key_str, klen, val_str, vlen, cookie);
146 }
147 
148 struct tk_context {
149  const void *cookie;
150  ADD_STAT add_stat;
151  rel_time_t current_time;
152 };
153 
154 #define TK_FMT(name) #name "=%d,"
155 #define TK_ARGS(name) item->name,
156 
157 static void tk_iterfunc(dlist_t *list, void *arg) {
158  struct tk_context *c = arg;
159  topkey_item_t *item = (topkey_item_t*)list;
160  char val_str[TK_MAX_VAL_LEN];
161  /* This line is magical. The missing comma before item->ctime is because the TK_ARGS macro ends with a comma. */
162  int vlen = snprintf(val_str, sizeof(val_str) - 1, TK_OPS(TK_FMT)"ctime=%"PRIu32",atime=%"PRIu32, TK_OPS(TK_ARGS)
163  c->current_time - item->ctime, c->current_time - item->atime);
164  c->add_stat(item->key, item->nkey, val_str, vlen, c->cookie);
165 }
166 
167 ENGINE_ERROR_CODE topkeys_stats(topkeys_t *tk,
168  const void *cookie,
169  const rel_time_t current_time,
170  ADD_STAT add_stat) {
171  struct tk_context context;
172  context.cookie = cookie;
173  context.add_stat = add_stat;
174  context.current_time = current_time;
175  assert(tk);
176  pthread_mutex_lock(&tk->mutex);
177  dlist_iter(&tk->list, tk_iterfunc, &context);
178  pthread_mutex_unlock(&tk->mutex);
179  return ENGINE_SUCCESS;
180 }