ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/whowas.c
(Generate patch)

Comparing:
ircd-hybrid-8/src/whowas.c (file contents), Revision 1298 by michael, Tue Feb 28 18:51:13 2012 UTC vs.
ircd-hybrid/trunk/src/whowas.c (file contents), Revision 7490 by michael, Sat Mar 19 18:58:29 2016 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  whowas.c: WHOWAS user cache.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2005 by the past and present ircd coders, and others.
4 > *  Copyright (c) 1997-2016 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 16 | Line 15
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18 < *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
20 > */
21 >
22 > /*! \file whowas.c
23 > * \brief WHOWAS user cache.
24 > * \version $Id$
25   */
26  
27   #include "stdinc.h"
28 + #include "list.h"
29 + #include "mempool.h"
30   #include "whowas.h"
31   #include "client.h"
32   #include "hash.h"
33   #include "irc_string.h"
34   #include "ircd.h"
35 < #include "ircd_defs.h"
32 < #include "numeric.h"
33 < #include "s_serv.h"
34 < #include "s_user.h"
35 < #include "send.h"
36 < #include "s_conf.h"
37 < #include "memory.h"
38 <
39 < /* internally defined function */
40 < static void add_whowas_to_clist(struct Whowas **, struct Whowas *);
41 < static void del_whowas_from_clist(struct Whowas **, struct Whowas *);
42 < static void add_whowas_to_list(struct Whowas **, struct Whowas *);
43 < static void del_whowas_from_list(struct Whowas **, struct Whowas *);
35 > #include "conf.h"
36  
45 struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
46 struct Whowas *WHOWASHASH[HASHSIZE];
37  
38 < static unsigned int whowas_next = 0;
38 > static mp_pool_t *whowas_pool;
39  
40 < void
41 < add_history(struct Client *client_p, int online)
52 < {
53 <  struct Whowas *who = &WHOWAS[whowas_next];
40 > static dlink_list whowas_list;  /*! Chain of struct Whowas pointers */
41 > static dlink_list whowas_hash[HASHSIZE];
42  
55  assert(client_p && client_p->servptr);
43  
44 <  if (who->hashv != -1)
45 <  {
46 <    if (who->online)
47 <      del_whowas_from_clist(&(who->online->whowas),who);
48 <    del_whowas_from_list(&WHOWASHASH[who->hashv], who);
49 <  }
44 > /*! \brief Initializes the whowas memory pool.
45 > */
46 > void
47 > whowas_init(void)
48 > {
49 >  whowas_pool = mp_pool_new(sizeof(struct Whowas), MP_CHUNK_SIZE_WHOWAS);
50 > }
51  
52 <  who->hashv = strhash(client_p->name);
53 <  who->logoff = CurrentTime;
52 > /*! \brief Returns a slot of the whowas_hash by the hash value associated with it.
53 > * \param hashv Hash value.
54 > */
55 > const dlink_list *
56 > whowas_get_hash(unsigned int hashv)
57 > {
58 >  if (hashv >= HASHSIZE)
59 >    return NULL;
60  
61 <  /* NOTE: strcpy ok here, the sizes in the client struct MUST
62 <   * match the sizes in the whowas struct
69 <   */
70 <  strlcpy(who->name, client_p->name, sizeof(who->name));
71 <  strcpy(who->username, client_p->username);
72 <  strcpy(who->hostname, client_p->host);
73 <  strcpy(who->realname, client_p->info);
61 >  return &whowas_hash[hashv];
62 > }
63  
64 <  strlcpy(who->servername, client_p->servptr->name, sizeof(who->servername));
64 > /*! \brief Unlinks a Whowas struct from its associated lists.
65 > * \param whowas Pointer to Whowas struct to be unlinked.
66 > */
67 > static struct Whowas *
68 > whowas_unlink(struct Whowas *whowas)
69 > {
70 >  if (!whowas)  /* Can be NULL. */
71 >    return NULL;
72  
73 <  if (online)
74 <  {
79 <    who->online = client_p;
80 <    add_whowas_to_clist(&(client_p->whowas), who);
81 <  }
82 <  else
83 <    who->online = NULL;
73 >  if (whowas->online)
74 >    dlinkDelete(&whowas->cnode, &whowas->online->whowas_list);
75  
76 <  add_whowas_to_list(&WHOWASHASH[who->hashv], who);
77 <  whowas_next++;
76 >  dlinkDelete(&whowas->hnode, &whowas_hash[whowas->hashv]);
77 >  dlinkDelete(&whowas->lnode, &whowas_list);
78  
79 <  if (whowas_next == NICKNAMEHISTORYLENGTH)
89 <    whowas_next = 0;
79 >  return whowas;
80   }
81  
82 < void
83 < off_history(struct Client *client_p)
82 > /*! \brief Unlinks a Whowas struct from its associated lists
83 > *         and returns memory back to the pooling allocator.
84 > * \param whowas Pointer to Whowas struct to be unlinked and freed.
85 > */
86 > static void
87 > whowas_free(struct Whowas *whowas)
88   {
89 <  struct Whowas *temp, *next;
90 <
97 <  for (temp = client_p->whowas; temp; temp=next)
98 <  {
99 <    next = temp->cnext;
100 <    temp->online = NULL;
101 <    del_whowas_from_clist(&(client_p->whowas), temp);
102 <  }
89 >  whowas_unlink(whowas);
90 >  mp_pool_release(whowas);
91   }
92  
93 < struct Client *
94 < get_history(const char *nick, time_t timelimit)
93 > /*! \brief Returns a Whowas struct for further use. Either allocates
94 > *         a new one, or returns the oldest entry from the whowas_list
95 > *         if it ran over ConfigGeneral.whowas_history_length
96 > */
97 > static struct Whowas *
98 > whowas_make(void)
99   {
100 <  struct Whowas *temp;
109 <
110 <  timelimit = CurrentTime - timelimit;
111 <  temp = WHOWASHASH[strhash(nick)];
100 >  struct Whowas *whowas;
101  
102 <  for (; temp; temp = temp->next)
103 <  {
104 <    if (irccmp(nick, temp->name))
105 <      continue;
117 <    if (temp->logoff < timelimit)
118 <      continue;
119 <    return temp->online;
120 <  }
102 >  if (dlink_list_length(&whowas_list) >= ConfigGeneral.whowas_history_length)
103 >    whowas = whowas_unlink(whowas_list.tail->data);  /* Re-use oldest item */
104 >  else
105 >    whowas = mp_pool_get(whowas_pool);
106  
107 <  return NULL;
107 >  return whowas;
108   }
109  
110 + /*! \brief Trims the whowas_list if necessary until there are no
111 + *         more than ConfigGeneral.whowas_history_length Whowas
112 + *         struct items.
113 + */
114   void
115 < count_whowas_memory(unsigned int *wwu, uint64_t *wwum)
115 > whowas_trim(void)
116   {
117 <  const struct Whowas *tmp;
129 <  int i;
130 <  unsigned int u = 0;
131 <  uint64_t um = 0;
132 <
133 <  /* count the number of used whowas structs in 'u'   */
134 <  /* count up the memory used of whowas structs in um */
135 <  for (i = 0, tmp = &WHOWAS[0]; i < NICKNAMEHISTORYLENGTH; ++i, ++tmp)
117 >  while (dlink_list_length(&whowas_list) >= ConfigGeneral.whowas_history_length)
118    {
119 <    if (tmp->hashv != -1)
120 <    {
139 <      ++u;
140 <      um += sizeof(struct Whowas);
141 <    }
142 <  }
119 >    if (!whowas_list.tail)
120 >      return;  /* whowas_list is now empty. No more items can be freed. */
121  
122 <  *wwu = u;
123 <  *wwum = um;
122 >    whowas_free(whowas_list.tail->data);
123 >  }
124   }
125  
126 + /*! \brief Adds the currently defined name of the client to history.
127 + *         Usually called before changing to a new name (nick).
128 + *         Client must be a fully registered user.
129 + * \param client_p Pointer to Client struct to add to whowas history
130 + * \param online   Either 1 if it's a nick change or 0 on client exit
131 + */
132   void
133 < init_whowas(void)
133 > whowas_add_history(struct Client *client_p, const int online)
134   {
135 <  int i;
135 >  struct Whowas *whowas = whowas_make();
136 >
137 >  if (!whowas)  /* Can be NULL. */
138 >    return;
139  
140 <  for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
140 >  assert(IsClient(client_p));
141 >
142 >  whowas->hashv = strhash(client_p->name);
143 >  whowas->shide = IsHidden(client_p->servptr) != 0;
144 >  whowas->logoff = CurrentTime;
145 >
146 >  strlcpy(whowas->account, client_p->account, sizeof(whowas->account));
147 >  strlcpy(whowas->name, client_p->name, sizeof(whowas->name));
148 >  strlcpy(whowas->username, client_p->username, sizeof(whowas->username));
149 >  strlcpy(whowas->hostname, client_p->host, sizeof(whowas->hostname));
150 >  strlcpy(whowas->sockhost, client_p->sockhost, sizeof(whowas->sockhost));
151 >  strlcpy(whowas->realname, client_p->info, sizeof(whowas->realname));
152 >  strlcpy(whowas->servername, client_p->servptr->name, sizeof(whowas->servername));
153 >
154 >  if (online)
155    {
156 <    memset(&WHOWAS[i], 0, sizeof(struct Whowas));
157 <    WHOWAS[i].hashv = -1;
156 >    whowas->online = client_p;
157 >    dlinkAdd(whowas, &whowas->cnode, &client_p->whowas_list);
158    }
159 +  else
160 +    whowas->online = NULL;
161  
162 <  for (i = 0; i < HASHSIZE; ++i)
163 <    WHOWASHASH[i] = NULL;        
162 >  dlinkAdd(whowas, &whowas->hnode, &whowas_hash[whowas->hashv]);
163 >  dlinkAdd(whowas, &whowas->lnode, &whowas_list);
164   }
165  
166 < static void
167 < add_whowas_to_clist(struct Whowas **bucket, struct Whowas *whowas)
166 > /*! \brief This must be called when the client structure is about to
167 > *         be released. History mechanism keeps pointers to client
168 > *         structures and it must know when they cease to exist.
169 > * \param client_p Pointer to Client struct
170 > */
171 > void
172 > whowas_off_history(struct Client *client_p)
173   {
174 <  whowas->cprev = NULL;
174 >  while (client_p->whowas_list.head)
175 >  {
176 >    struct Whowas *whowas = client_p->whowas_list.head->data;
177  
178 <  if ((whowas->cnext = *bucket) != NULL)
179 <    whowas->cnext->cprev = whowas;
180 <  *bucket = whowas;
171 < }
172 <
173 < static void
174 < del_whowas_from_clist(struct Whowas **bucket, struct Whowas *whowas)
175 < {
176 <  if (whowas->cprev)
177 <    whowas->cprev->cnext = whowas->cnext;
178 <  else
179 <    *bucket = whowas->cnext;
180 <  if (whowas->cnext)
181 <    whowas->cnext->cprev = whowas->cprev;
178 >    whowas->online = NULL;
179 >    dlinkDelete(&whowas->cnode, &client_p->whowas_list);
180 >  }
181   }
182  
183 < static void
184 < add_whowas_to_list(struct Whowas **bucket, struct Whowas *whowas)
183 > /*! \brief Returns the current client that was using the given
184 > *         nickname within the timelimit. Returns NULL, if no
185 > *         one found.
186 > * \param name      Name of the nick
187 > * \param timelimit Maximum age for a client since log-off
188 > */
189 > struct Client *
190 > whowas_get_history(const char *name, uintmax_t timelimit)
191   {
192 <  whowas->prev = NULL;
192 >  dlink_node *node = NULL;
193 >
194 >  timelimit = CurrentTime - timelimit;
195  
196 <  if ((whowas->next = *bucket) != NULL)
197 <    whowas->next->prev = whowas;
198 <  *bucket = whowas;
196 >  DLINK_FOREACH(node, whowas_hash[strhash(name)].head)
197 >  {
198 >    struct Whowas *whowas = node->data;
199 >
200 >    if (whowas->logoff < timelimit)
201 >      continue;
202 >    if (irccmp(name, whowas->name))
203 >      continue;
204 >    return whowas->online;
205 >  }
206 >
207 >  return NULL;
208   }
209 <
210 < static void
211 < del_whowas_from_list(struct Whowas **bucket, struct Whowas *whowas)
209 >
210 > /*! \brief For debugging. Counts allocated structures stored in whowas_list
211 > */
212 > void
213 > whowas_count_memory(unsigned int *const count, size_t *const bytes)
214   {
215 <  if (whowas->prev)
216 <    whowas->prev->next = whowas->next;
199 <  else
200 <    *bucket = whowas->next;
201 <  if (whowas->next)
202 <    whowas->next->prev = whowas->prev;
215 >  (*count) = dlink_list_length(&whowas_list);
216 >  (*bytes) = dlink_list_length(&whowas_list) * sizeof(struct Whowas);
217   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)