am 028ccf5d
: Merge "Avoid multiple dns lookups for the same query"
* commit '028ccf5d40dd9a945ea92aa79822c08c6f6aa1d2': Avoid multiple dns lookups for the same query
This commit is contained in:
commit
c5cab3452d
@ -1170,6 +1170,15 @@ entry_equals( const Entry* e1, const Entry* e2 )
|
||||
* inlined in the Entry structure.
|
||||
*/
|
||||
|
||||
/* Maximum time for a thread to wait for an pending request */
|
||||
#define PENDING_REQUEST_TIMEOUT 20;
|
||||
|
||||
typedef struct pending_req_info {
|
||||
unsigned int hash;
|
||||
pthread_cond_t cond;
|
||||
struct pending_req_info* next;
|
||||
} PendingReqInfo;
|
||||
|
||||
typedef struct resolv_cache {
|
||||
int max_entries;
|
||||
int num_entries;
|
||||
@ -1178,6 +1187,7 @@ typedef struct resolv_cache {
|
||||
unsigned generation;
|
||||
int last_id;
|
||||
Entry* entries;
|
||||
PendingReqInfo pending_requests;
|
||||
} Cache;
|
||||
|
||||
typedef struct resolv_cache_info {
|
||||
@ -1191,6 +1201,107 @@ typedef struct resolv_cache_info {
|
||||
|
||||
#define HTABLE_VALID(x) ((x) != NULL && (x) != HTABLE_DELETED)
|
||||
|
||||
static void
|
||||
_cache_flush_pending_requests_locked( struct resolv_cache* cache )
|
||||
{
|
||||
struct pending_req_info *ri, *tmp;
|
||||
if (cache) {
|
||||
ri = cache->pending_requests.next;
|
||||
|
||||
while (ri) {
|
||||
tmp = ri;
|
||||
ri = ri->next;
|
||||
pthread_cond_broadcast(&tmp->cond);
|
||||
|
||||
pthread_cond_destroy(&tmp->cond);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
cache->pending_requests.next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* return 0 if no pending request is found matching the key
|
||||
* if a matching request is found the calling thread will wait
|
||||
* and return 1 when released */
|
||||
static int
|
||||
_cache_check_pending_request_locked( struct resolv_cache* cache, Entry* key )
|
||||
{
|
||||
struct pending_req_info *ri, *prev;
|
||||
int exist = 0;
|
||||
|
||||
if (cache && key) {
|
||||
ri = cache->pending_requests.next;
|
||||
prev = &cache->pending_requests;
|
||||
while (ri) {
|
||||
if (ri->hash == key->hash) {
|
||||
exist = 1;
|
||||
break;
|
||||
}
|
||||
prev = ri;
|
||||
ri = ri->next;
|
||||
}
|
||||
|
||||
if (!exist) {
|
||||
ri = calloc(1, sizeof(struct pending_req_info));
|
||||
if (ri) {
|
||||
ri->hash = key->hash;
|
||||
pthread_cond_init(&ri->cond, NULL);
|
||||
prev->next = ri;
|
||||
}
|
||||
} else {
|
||||
struct timespec ts = {0,0};
|
||||
ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT;
|
||||
int rv = pthread_cond_timedwait(&ri->cond, &cache->lock, &ts);
|
||||
}
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
/* notify any waiting thread that waiting on a request
|
||||
* matching the key has been added to the cache */
|
||||
static void
|
||||
_cache_notify_waiting_tid_locked( struct resolv_cache* cache, Entry* key )
|
||||
{
|
||||
struct pending_req_info *ri, *prev;
|
||||
|
||||
if (cache && key) {
|
||||
ri = cache->pending_requests.next;
|
||||
prev = &cache->pending_requests;
|
||||
while (ri) {
|
||||
if (ri->hash == key->hash) {
|
||||
pthread_cond_broadcast(&ri->cond);
|
||||
break;
|
||||
}
|
||||
prev = ri;
|
||||
ri = ri->next;
|
||||
}
|
||||
|
||||
// remove item from list and destroy
|
||||
if (ri) {
|
||||
prev->next = ri->next;
|
||||
pthread_cond_destroy(&ri->cond);
|
||||
free(ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* notify the cache that the query failed */
|
||||
void
|
||||
_resolv_cache_query_failed( struct resolv_cache* cache,
|
||||
const void* query,
|
||||
int querylen)
|
||||
{
|
||||
Entry key[1];
|
||||
|
||||
if (cache && entry_init_key(key, query, querylen)) {
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
_cache_notify_waiting_tid_locked(cache, key);
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cache_flush_locked( Cache* cache )
|
||||
{
|
||||
@ -1208,6 +1319,9 @@ _cache_flush_locked( Cache* cache )
|
||||
}
|
||||
}
|
||||
|
||||
// flush pending request
|
||||
_cache_flush_pending_requests_locked(cache);
|
||||
|
||||
cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
|
||||
cache->num_entries = 0;
|
||||
cache->last_id = 0;
|
||||
@ -1491,7 +1605,17 @@ _resolv_cache_lookup( struct resolv_cache* cache,
|
||||
|
||||
if (e == NULL) {
|
||||
XLOG( "NOT IN CACHE");
|
||||
goto Exit;
|
||||
// calling thread will wait if an outstanding request is found
|
||||
// that matching this query
|
||||
if (!_cache_check_pending_request_locked(cache, key)) {
|
||||
goto Exit;
|
||||
} else {
|
||||
lookup = _cache_lookup_p(cache, key);
|
||||
e = *lookup;
|
||||
if (e == NULL) {
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
now = _time_now();
|
||||
@ -1594,6 +1718,7 @@ _resolv_cache_add( struct resolv_cache* cache,
|
||||
_cache_dump_mru(cache);
|
||||
#endif
|
||||
Exit:
|
||||
_cache_notify_waiting_tid_locked(cache, key);
|
||||
pthread_mutex_unlock( &cache->lock );
|
||||
}
|
||||
|
||||
|
@ -646,6 +646,9 @@ res_nsend(res_state statp,
|
||||
errno = terrno;
|
||||
return (-1);
|
||||
fail:
|
||||
#if USE_RESOLV_CACHE
|
||||
_resolv_cache_query_failed(cache, buf, buflen);
|
||||
#endif
|
||||
res_nclose(statp);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -95,4 +95,10 @@ _resolv_cache_add( struct resolv_cache* cache,
|
||||
const void* answer,
|
||||
int answerlen );
|
||||
|
||||
/* Notify the cache a request failed */
|
||||
extern void
|
||||
_resolv_cache_query_failed( struct resolv_cache* cache,
|
||||
const void* query,
|
||||
int querylen);
|
||||
|
||||
#endif /* _RESOLV_CACHE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user