From 5194d97d72e4d4c4737ff304c7b6ea4134e242b0 Mon Sep 17 00:00:00 2001 From: phk Date: Mon, 21 Aug 2006 17:32:41 +0000 Subject: [PATCH] Retire sessions if the workspace size changes, properly cache the workspace size so we do not get caught unaware when it changes. Implement flip-flop free queue where SES_New() can read from one of them without a lock, which frees happen to the other one under lock. If the lock-less queue is empty, SES_New() flips the two queues under lock and tries again. If that queue is also empty call malloc(3). git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@873 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache_session.c | 61 +++++++++++++++++----- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/varnish-cache/bin/varnishd/cache_session.c b/varnish-cache/bin/varnishd/cache_session.c index 7edbd103..0cfea524 100644 --- a/varnish-cache/bin/varnishd/cache_session.c +++ b/varnish-cache/bin/varnishd/cache_session.c @@ -33,13 +33,18 @@ struct sessmem { struct sess sess; struct http http; struct sockaddr sockaddr[2]; /* INET6 hack */ + unsigned workspace; TAILQ_ENTRY(sessmem) list; }; /*--------------------------------------------------------------------*/ -static TAILQ_HEAD(,sessmem) ses_free_mem = - TAILQ_HEAD_INITIALIZER(ses_free_mem); +static TAILQ_HEAD(,sessmem) ses_free_mem[2] = { + TAILQ_HEAD_INITIALIZER(ses_free_mem[0]), + TAILQ_HEAD_INITIALIZER(ses_free_mem[1]), +}; + +static unsigned ses_qp; TAILQ_HEAD(srcaddrhead ,srcaddr); static struct srcaddrhead srcaddr_hash[CLIENT_HASH]; @@ -188,15 +193,37 @@ struct sess * SES_New(struct sockaddr *addr, unsigned len) { struct sessmem *sm; + unsigned u; - AZ(pthread_mutex_lock(&ses_mem_mtx)); - sm = TAILQ_FIRST(&ses_free_mem); - if (sm != NULL) - TAILQ_REMOVE(&ses_free_mem, sm, list); - AZ(pthread_mutex_unlock(&ses_mem_mtx)); + + /* + * One of the two queues is unlocked because only one + * thread ever gets here to empty it. + */ + assert(ses_qp <= 1); + sm = TAILQ_FIRST(&ses_free_mem[ses_qp]); if (sm == NULL) { - sm = calloc(sizeof *sm + params->mem_workspace, 1); + /* + * If that queue is empty, flip queues holding the lock + * and try the new unlocked queue. + */ + AZ(pthread_mutex_lock(&ses_mem_mtx)); + ses_qp = 1 - ses_qp; + AZ(pthread_mutex_unlock(&ses_mem_mtx)); + sm = TAILQ_FIRST(&ses_free_mem[ses_qp]); + } + if (sm != NULL) { + TAILQ_REMOVE(&ses_free_mem[ses_qp], sm, list); + } else { + /* + * If that fails, alloc new one. + */ + u = params->mem_workspace; + sm = malloc(sizeof *sm + u); + if (sm == NULL) + return (NULL); sm->magic = SESSMEM_MAGIC; + sm->workspace = u; VSL_stats->n_sess_mem++; } if (sm == NULL) @@ -215,7 +242,7 @@ SES_New(struct sockaddr *addr, unsigned len) sm->sess.sockaddrlen = len; } - http_Setup(&sm->http, (void *)(sm + 1), params->mem_workspace); + http_Setup(&sm->http, (void *)(sm + 1), sm->workspace); sm->sess.acct.first = time(NULL); @@ -226,8 +253,12 @@ void SES_Delete(struct sess *sp) { struct acct *b = &sp->acct; + struct sessmem *sm; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + sm = sp->mem; + CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC); + assert(sp->obj == NULL); assert(sp->vcl == NULL); VSL_stats->n_sess--; @@ -236,10 +267,14 @@ SES_Delete(struct sess *sp) sp->addr, sp->port, time(NULL) - b->first, b->sess, b->req, b->pipe, b->pass, b->fetch, b->hdrbytes, b->bodybytes); - CHECK_OBJ_NOTNULL(sp->mem, SESSMEM_MAGIC); - AZ(pthread_mutex_lock(&ses_mem_mtx)); - TAILQ_INSERT_HEAD(&ses_free_mem, sp->mem, list); - AZ(pthread_mutex_unlock(&ses_mem_mtx)); + if (sm->workspace != params->mem_workspace) { + VSL_stats->n_sess_mem--; + free(sm); + } else { + AZ(pthread_mutex_lock(&ses_mem_mtx)); + TAILQ_INSERT_HEAD(&ses_free_mem[1 - ses_qp], sm, list); + AZ(pthread_mutex_unlock(&ses_mem_mtx)); + } } /*--------------------------------------------------------------------*/ -- 2.39.5