1 /* Copyright (c) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <arpa/inet.h>
29 #include <rpcsvc/nis.h>
31 #include <sys/param.h>
39 /* Number of times a value is reloaded without being used. UINT_MAX
41 unsigned int reload_count
= DEFAULT_RELOAD_LIMIT
;
44 /* Search the cache for a matching entry and return it when found. If
45 this fails search the negative cache and return (void *) -1 if this
46 search was successful. Otherwise return NULL.
48 This function must be called with the read-lock held. */
50 cache_search (request_type type
, void *key
, size_t len
,
51 struct database_dyn
*table
, uid_t owner
)
53 unsigned long int hash
= __nis_hash (key
, len
) % table
->head
->module
;
55 unsigned long int nsearched
= 0;
56 struct datahead
*result
= NULL
;
58 ref_t work
= table
->head
->array
[hash
];
59 while (work
!= ENDREF
)
63 struct hashentry
*here
= (struct hashentry
*) (table
->data
+ work
);
65 if (type
== here
->type
&& len
== here
->len
66 && memcmp (key
, table
->data
+ here
->key
, len
) == 0
67 && here
->owner
== owner
)
69 /* We found the entry. Increment the appropriate counter. */
71 = (struct datahead
*) (table
->data
+ here
->packet
);
73 /* See whether we must ignore the entry. */
76 /* We do not synchronize the memory here. The statistics
77 data is not crucial, we synchronize only once in a while
78 in the cleanup threads. */
80 ++table
->head
->neghit
;
83 ++table
->head
->poshit
;
85 if (dh
->nreloads
!= 0)
97 if (nsearched
> table
->head
->maxnsearched
)
98 table
->head
->maxnsearched
= nsearched
;
103 /* Add a new entry to the cache. The return value is zero if the function
106 This function must be called with the read-lock held.
108 We modify the table but we nevertheless only acquire a read-lock.
109 This is ok since we use operations which would be safe even without
110 locking, given that the `prune_cache' function never runs. Using
111 the readlock reduces the chance of conflicts. */
113 cache_add (int type
, const void *key
, size_t len
, struct datahead
*packet
,
114 bool first
, struct database_dyn
*table
,
117 if (__builtin_expect (debug_level
>= 2, 0))
120 char buf
[INET6_ADDRSTRLEN
+ 1];
121 if (type
== GETHOSTBYADDR
|| type
== GETHOSTBYADDRv6
)
122 str
= inet_ntop (type
== GETHOSTBYADDR
? AF_INET
: AF_INET6
,
123 key
, buf
, sizeof (buf
));
127 dbg_log (_("add new entry \"%s\" of type %s for %s to cache%s"),
128 str
, serv2str
[type
], dbnames
[table
- dbs
],
129 first
? " (first)" : "");
132 unsigned long int hash
= __nis_hash (key
, len
) % table
->head
->module
;
133 struct hashentry
*newp
;
135 newp
= mempool_alloc (table
, sizeof (struct hashentry
));
136 /* If we cannot allocate memory, just do not do anything. */
143 newp
->key
= (char *) key
- table
->data
;
144 assert (newp
->key
+ newp
->len
<= table
->head
->first_free
);
146 newp
->packet
= (char *) packet
- table
->data
;
148 /* Put the new entry in the first position. */
150 newp
->next
= table
->head
->array
[hash
];
151 while (atomic_compare_and_exchange_bool_acq (&table
->head
->array
[hash
],
152 (ref_t
) ((char *) newp
154 (ref_t
) newp
->next
));
156 /* Update the statistics. */
157 if (packet
->notfound
)
158 ++table
->head
->negmiss
;
160 ++table
->head
->posmiss
;
162 /* We depend on this value being correct and at least as high as the
163 real number of entries. */
164 atomic_increment (&table
->head
->nentries
);
166 /* It does not matter that we are not loading the just increment
167 value, this is just for statistics. */
168 unsigned long int nentries
= table
->head
->nentries
;
169 if (nentries
> table
->head
->maxnentries
)
170 table
->head
->maxnentries
= nentries
;
175 /* Walk through the table and remove all entries which lifetime ended.
177 We have a problem here. To actually remove the entries we must get
178 the write-lock. But since we want to keep the time we have the
179 lock as short as possible we cannot simply acquire the lock when we
180 start looking for timedout entries.
182 Therefore we do it in two stages: first we look for entries which
183 must be invalidated and remember them. Then we get the lock and
184 actually remove them. This is complicated by the way we have to
185 free the data structures since some hash table entries share the same
188 prune_cache (struct database_dyn
*table
, time_t now
)
190 size_t cnt
= table
->head
->module
;
192 /* If this table is not actually used don't do anything. */
196 /* If we check for the modification of the underlying file we invalidate
197 the entries also in this case. */
198 if (table
->check_file
)
202 if (stat (table
->filename
, &st
) < 0)
205 /* We cannot stat() the file, disable file checking if the
206 file does not exist. */
207 dbg_log (_("cannot stat() file `%s': %s"),
208 table
->filename
, strerror_r (errno
, buf
, sizeof (buf
)));
210 table
->check_file
= 0;
214 if (st
.st_mtime
!= table
->file_mtime
)
216 /* The file changed. Invalidate all entries. */
218 table
->file_mtime
= st
.st_mtime
;
223 /* We run through the table and find values which are not valid anymore.
225 Note that for the initial step, finding the entries to be removed,
226 we don't need to get any lock. It is at all timed assured that the
227 linked lists are set up correctly and that no second thread prunes
230 size_t first
= cnt
+ 1;
232 char *const data
= table
->data
;
237 ref_t run
= table
->head
->array
[--cnt
];
239 while (run
!= ENDREF
)
241 struct hashentry
*runp
= (struct hashentry
*) (data
+ run
);
242 struct datahead
*dh
= (struct datahead
*) (data
+ runp
->packet
);
244 /* Check whether the entry timed out. */
245 if (dh
->timeout
< now
)
247 /* This hash bucket could contain entries which need to
251 first
= MIN (first
, cnt
);
252 last
= MAX (last
, cnt
);
254 /* We only have to look at the data of the first entries
255 since the count information is kept in the data part
260 /* At this point there are two choices: we reload the
261 value or we discard it. Do not change NRELOADS if
262 we never not reload the record. */
263 if ((reload_count
!= UINT_MAX
264 && __builtin_expect (dh
->nreloads
>= reload_count
, 0))
265 /* We always remove negative entries. */
267 /* Discard everything if the user explicitly
271 /* Remove the value. */
274 /* We definitely have some garbage entries now. */
279 /* Reload the value. We do this only for the
280 initially used key, not the additionally
281 added derived value. */
285 readdpwbyname (table
, runp
, dh
);
289 readdpwbyuid (table
, runp
, dh
);
293 readdgrbyname (table
, runp
, dh
);
297 readdgrbygid (table
, runp
, dh
);
301 readdhstbyname (table
, runp
, dh
);
304 case GETHOSTBYNAMEv6
:
305 readdhstbynamev6 (table
, runp
, dh
);
309 readdhstbyaddr (table
, runp
, dh
);
312 case GETHOSTBYADDRv6
:
313 readdhstbyaddrv6 (table
, runp
, dh
);
317 readdhstai (table
, runp
, dh
);
321 assert (! "should never happen");
324 /* If the entry has been replaced, we might need
340 struct hashentry
*head
= NULL
;
342 /* Now we have to get the write lock since we are about to modify
344 if (__builtin_expect (pthread_rwlock_trywrlock (&table
->lock
) != 0, 0))
346 ++table
->head
->wrlockdelayed
;
347 pthread_rwlock_wrlock (&table
->lock
);
350 while (first
<= last
)
354 ref_t
*old
= &table
->head
->array
[first
];
355 ref_t run
= table
->head
->array
[first
];
357 while (run
!= ENDREF
)
359 struct hashentry
*runp
= (struct hashentry
*) (data
+ run
);
361 = (struct datahead
*) (data
+ runp
->packet
);
365 /* We need the list only for debugging but it is
366 more costly to avoid creating the list than
368 runp
->dellist
= head
;
371 /* No need for an atomic operation, we have the
373 --table
->head
->nentries
;
375 run
= *old
= runp
->next
;
389 pthread_rwlock_unlock (&table
->lock
);
391 /* Make sure the data is saved to disk. */
392 if (table
->persistent
)
394 table
->data
+ table
->head
->first_free
- (char *) table
->head
,
397 /* One extra pass if we do debugging. */
398 if (__builtin_expect (debug_level
> 0, 0))
400 struct hashentry
*runp
= head
;
404 char buf
[INET6_ADDRSTRLEN
];
407 if (runp
->type
== GETHOSTBYADDR
|| runp
->type
== GETHOSTBYADDRv6
)
409 inet_ntop (runp
->type
== GETHOSTBYADDR
? AF_INET
: AF_INET6
,
410 table
->data
+ runp
->key
, buf
, sizeof (buf
));
414 str
= table
->data
+ runp
->key
;
416 dbg_log ("remove %s entry \"%s\"", serv2str
[runp
->type
], str
);
418 runp
= runp
->dellist
;
423 /* Run garbage collection if any entry has been removed or replaced. */