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:
Robert Greenwalt 2012-06-12 15:52:56 -07:00 committed by Android Git Automerger
commit c5cab3452d
3 changed files with 135 additions and 1 deletions

View File

@ -1170,6 +1170,15 @@ entry_equals( const Entry* e1, const Entry* e2 )
* inlined in the Entry structure. * 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 { typedef struct resolv_cache {
int max_entries; int max_entries;
int num_entries; int num_entries;
@ -1178,6 +1187,7 @@ typedef struct resolv_cache {
unsigned generation; unsigned generation;
int last_id; int last_id;
Entry* entries; Entry* entries;
PendingReqInfo pending_requests;
} Cache; } Cache;
typedef struct resolv_cache_info { typedef struct resolv_cache_info {
@ -1191,6 +1201,107 @@ typedef struct resolv_cache_info {
#define HTABLE_VALID(x) ((x) != NULL && (x) != HTABLE_DELETED) #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 static void
_cache_flush_locked( Cache* cache ) _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->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
cache->num_entries = 0; cache->num_entries = 0;
cache->last_id = 0; cache->last_id = 0;
@ -1491,7 +1605,17 @@ _resolv_cache_lookup( struct resolv_cache* cache,
if (e == NULL) { if (e == NULL) {
XLOG( "NOT IN CACHE"); XLOG( "NOT IN CACHE");
// calling thread will wait if an outstanding request is found
// that matching this query
if (!_cache_check_pending_request_locked(cache, key)) {
goto Exit; goto Exit;
} else {
lookup = _cache_lookup_p(cache, key);
e = *lookup;
if (e == NULL) {
goto Exit;
}
}
} }
now = _time_now(); now = _time_now();
@ -1594,6 +1718,7 @@ _resolv_cache_add( struct resolv_cache* cache,
_cache_dump_mru(cache); _cache_dump_mru(cache);
#endif #endif
Exit: Exit:
_cache_notify_waiting_tid_locked(cache, key);
pthread_mutex_unlock( &cache->lock ); pthread_mutex_unlock( &cache->lock );
} }

View File

@ -646,6 +646,9 @@ res_nsend(res_state statp,
errno = terrno; errno = terrno;
return (-1); return (-1);
fail: fail:
#if USE_RESOLV_CACHE
_resolv_cache_query_failed(cache, buf, buflen);
#endif
res_nclose(statp); res_nclose(statp);
return (-1); return (-1);
} }

View File

@ -95,4 +95,10 @@ _resolv_cache_add( struct resolv_cache* cache,
const void* answer, const void* answer,
int answerlen ); 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_ */ #endif /* _RESOLV_CACHE_H_ */