Commit 03e0bcf1 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Write some generic code for a memory pool and apply it it VBC as

the initial guineapig.

We have a number of pools of objects we maintain dynamically and we
will get more in the future, so having a generic facility makes sense.

One particular aspect of some of our pools, is that the desired size
of object is variable over time, for instance workspaces which
depend on parameters etc.

Using generic code will allow us to use systematic parameters and
VSC stats for all pools, hopefully with some memory savings involved.
parent dcd622df
......@@ -34,6 +34,7 @@ varnishd_SOURCES = \
cache/cache_httpconn.c \
cache/cache_lck.c \
cache/cache_main.c \
cache/cache_mempool.c \
cache/cache_panic.c \
cache/cache_pipe.c \
cache/cache_pool.c \
......
......@@ -99,10 +99,12 @@ struct cli;
struct cli_proto;
struct director;
struct iovec;
struct mempool;
struct objcore;
struct object;
struct objhead;
struct pool;
struct poolparam;
struct sess;
struct sesspool;
struct vbc;
......@@ -667,6 +669,7 @@ void VDI_CloseFd(struct worker *wrk, struct vbc **vbp);
void VDI_RecycleFd(struct worker *wrk, struct vbc **vbp);
void VDI_AddHostHeader(struct worker *wrk, const struct vbc *vbc);
void VBE_Poll(void);
void VDI_Init(void);
/* cache_backend_cfg.c */
void VBE_InitCfg(void);
......@@ -849,6 +852,15 @@ int Lck_CondWait(pthread_cond_t *cond, struct lock *lck, struct timespec *ts);
#include "tbl/locks.h"
#undef LOCK
/* cache_mempool.c */
struct mempool * MPL_New(const char *name, struct lock *mtx,
volatile struct poolparam *pp, volatile unsigned *cur_size);
void *MPL_GetLocked(struct mempool *mpl, unsigned *size);
void *MPL_Get(struct mempool *mpl, unsigned *size);
void MPL_FreeLocked(struct mempool *mpl, void *item);
void MPL_Free(struct mempool *mpl, void *item);
/* cache_panic.c */
void PAN_Init(void);
......
......@@ -43,6 +43,16 @@
#include "vrt.h"
#include "vtcp.h"
static struct mempool *vbcpool;
static struct poolparam vbcpp = {
.min_pool = 10,
.max_pool = 100,
.max_age = 60,
};
static unsigned vbcps = sizeof(struct vbc);
/*--------------------------------------------------------------------
* The "simple" director really isn't, since thats where all the actual
* connections happen. Nontheless, pretend it is simple by sequestering
......@@ -82,14 +92,7 @@ VBE_ReleaseConn(struct vbc *vc)
CHECK_OBJ_NOTNULL(vc, VBC_MAGIC);
assert(vc->backend == NULL);
assert(vc->fd < 0);
vc->addr = NULL;
vc->addrlen = 0;
vc->recycled = 0;
Lck_Lock(&VBE_mtx);
VSC_C_main->n_vbc--;
Lck_Unlock(&VBE_mtx);
FREE_OBJ(vc);
MPL_Free(vbcpool, vc);
}
#define FIND_TMO(tmx, dst, sp, be) \
......@@ -221,12 +224,10 @@ vbe_NewConn(void)
{
struct vbc *vc;
ALLOC_OBJ(vc, VBC_MAGIC);
vc = MPL_Get(vbcpool, NULL);
XXXAN(vc);
vc->magic = VBC_MAGIC;
vc->fd = -1;
Lck_Lock(&VBE_mtx);
VSC_C_main->n_vbc++;
Lck_Unlock(&VBE_mtx);
return (vc);
}
......@@ -517,3 +518,11 @@ VRT_init_dir_simple(struct cli *cli, struct director **bp, int idx,
bp[idx] = &vs->dir;
}
void
VDI_Init(void)
{
vbcpool = MPL_New("vbc", NULL, &vbcpp, &vbcps);
AN(vbcpool);
}
......@@ -170,7 +170,6 @@ void VBE_ReleaseConn(struct vbc *vc);
struct backend *vdi_get_backend_if_simple(const struct director *d);
/* cache_backend_cfg.c */
extern struct lock VBE_mtx;
void VBE_DropRefConn(struct backend *);
void VBE_DropRefVcl(struct backend *);
void VBE_DropRefLocked(struct backend *b);
......
......@@ -43,9 +43,6 @@
#include "vcli_priv.h"
#include "vrt.h"
struct lock VBE_mtx;
/*
* The list of backends is not locked, it is only ever accessed from
* the CLI thread, so there is no need.
......@@ -502,6 +499,5 @@ void
VBE_InitCfg(void)
{
Lck_New(&VBE_mtx, lck_vbe);
CLI_AddFuncs(backend_cmds);
}
......@@ -117,6 +117,7 @@ child_main(void)
HTTP_Init();
VDI_Init();
VBO_Init();
VBE_InitCfg();
VBP_Init();
......
/*-
* Copyright (c) 2011 Varnish Software AS
* All rights reserved.
*
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Generic memory pool
*/
#include <stddef.h>
#include <stdlib.h>
#include "config.h"
#include "cache.h"
struct memitem {
unsigned magic;
#define MEMITEM_MAGIC 0x42e55401
VTAILQ_ENTRY(memitem) list;
unsigned size;
double payload;
};
struct mempool {
unsigned magic;
#define MEMPOOL_MAGIC 0x37a75a8d
VTAILQ_HEAD(,memitem) list;
struct lock *mtx;
struct lock imtx;
const char *name;
volatile struct poolparam *param;
volatile unsigned *cur_size;
struct VSC_C_mempool *vsc;
};
struct mempool *
MPL_New(const char *name,
struct lock *mtx,
volatile struct poolparam *pp,
volatile unsigned *cur_size)
{
struct mempool *mpl;
ALLOC_OBJ(mpl, MEMPOOL_MAGIC);
AN(mpl);
mpl->name = name;
mpl->param = pp;
mpl->cur_size = cur_size;
mpl->mtx = mtx;
VTAILQ_INIT(&mpl->list);
Lck_New(&mpl->imtx, lck_mempool);
if (mpl->mtx == NULL)
mpl->mtx = &mpl->imtx;
/* XXX: prealloc min_pool */
mpl->vsc = VSM_Alloc(sizeof *mpl->vsc,
VSC_CLASS, VSC_TYPE_MEMPOOL, name);
AN(mpl->vsc);
return (mpl);
}
void *
MPL_GetLocked(struct mempool *mpl, unsigned *size)
{
struct memitem *mi;
unsigned tsz;
CHECK_OBJ_NOTNULL(mpl, MEMPOOL_MAGIC);
Lck_AssertHeld(mpl->mtx);
mpl->vsc->allocs++;
mpl->vsc->live++;
do {
mi = VTAILQ_FIRST(&mpl->list);
if (mi == NULL)
break;
mpl->vsc->pool--;
CHECK_OBJ_NOTNULL(mi, MEMITEM_MAGIC);
VTAILQ_REMOVE(&mpl->list, mi, list);
if (mi->size < *mpl->cur_size) {
mpl->vsc->toosmall++;
FREE_OBJ(mi);
mi = NULL;
} else {
mpl->vsc->recycle++;
}
} while (mi == NULL);
if (mi == NULL) {
tsz = *mpl->cur_size;
mi = calloc(sizeof *mi + tsz, 1);
AN(mi);
mi->magic = MEMITEM_MAGIC;
mi->size = tsz;
}
if (size != NULL)
*size = mi->size;
return (&mi->payload);
}
void
MPL_FreeLocked(struct mempool *mpl, void *item)
{
struct memitem *mi;
CHECK_OBJ_NOTNULL(mpl, MEMPOOL_MAGIC);
Lck_AssertHeld(mpl->mtx);
mpl->vsc->frees++;
mpl->vsc->live--;
mi = (void*)((uintptr_t)item - offsetof(struct memitem, payload));
CHECK_OBJ_NOTNULL(mi, MEMITEM_MAGIC);
if (mi->size < *mpl->cur_size) {
mpl->vsc->toosmall++;
FREE_OBJ(mi);
} else {
mpl->vsc->pool++;
memset(item, 0, mi->size);
VTAILQ_INSERT_HEAD(&mpl->list, mi, list);
}
}
void *
MPL_Get(struct mempool *mpl, unsigned *size)
{
void *p;
CHECK_OBJ_NOTNULL(mpl, MEMPOOL_MAGIC);
Lck_Lock(mpl->mtx);
p = MPL_GetLocked(mpl, size);
Lck_Unlock(mpl->mtx);
return (p);
}
void
MPL_Free(struct mempool *mpl, void *item)
{
CHECK_OBJ_NOTNULL(mpl, MEMPOOL_MAGIC);
Lck_Lock(mpl->mtx);
MPL_FreeLocked(mpl, item);
Lck_Unlock(mpl->mtx);
}
......@@ -33,6 +33,12 @@
#define VSM_CLASS_PARAM "Params"
struct poolparam {
unsigned min_pool;
unsigned max_pool;
double max_age;
};
struct params {
/* Unprivileged user / group */
......
......@@ -46,9 +46,9 @@ LOCK(lru)
LOCK(cli)
LOCK(ban)
LOCK(vbp)
LOCK(vbe)
LOCK(backend)
LOCK(vcapace)
LOCK(nbusyobj)
LOCK(busyobj)
LOCK(mempool)
/*lint -restore */
......@@ -56,3 +56,9 @@ VSC_DO(VBE, vbe, VSC_TYPE_VBE)
#include "tbl/vsc_fields.h"
#undef VSC_DO_VBE
VSC_DONE(VBE, vbe, VSC_TYPE_VBE)
VSC_DO(MEMPOOL, mempool, VSC_TYPE_MEMPOOL)
#define VSC_DO_MEMPOOL
#include "tbl/vsc_fields.h"
#undef VSC_DO_MEMPOOL
VSC_DONE(MEMPOOL, mempool, VSC_TYPE_MEMPOOL)
......@@ -259,8 +259,6 @@ VSC_F(n_objectcore, uint64_t, 1, 'i', "N struct objectcore", "")
VSC_F(n_objecthead, uint64_t, 1, 'i', "N struct objecthead", "")
VSC_F(n_waitinglist, uint64_t, 1, 'i', "N struct waitinglist", "")
VSC_F(n_vbc, uint64_t, 0, 'i', "N struct vbc", "")
VSC_F(n_backend, uint64_t, 0, 'i', "N backends", "")
VSC_F(n_expired, uint64_t, 0, 'i', "N expired objects", "")
......
......@@ -106,3 +106,15 @@ VSC_F(happy, uint64_t, 0, 'b', "Happy health probes", "")
#endif
/**********************************************************************/
#ifdef VSC_DO_MEMPOOL
VSC_F(allocs, uint64_t, 0, 'c', "Allocations", "")
VSC_F(frees, uint64_t, 0, 'c', "Frees", "")
VSC_F(live, uint64_t, 0, 'g', "In use", "")
VSC_F(pool, uint64_t, 0, 'g', "In Pool", "")
VSC_F(recycle, uint64_t, 0, 'g', "Recycled from pool", "")
VSC_F(timeout, uint64_t, 0, 'g', "Timed out from pool", "")
VSC_F(toosmall, uint64_t, 0, 'g', "Too small to recycle", "")
#endif
......@@ -28,13 +28,14 @@
*
*/
#define VSC_CLASS "Stat"
#define VSC_CLASS "Stat"
#define VSC_TYPE_MAIN ""
#define VSC_TYPE_SMA "SMA"
#define VSC_TYPE_SMF "SMF"
#define VSC_TYPE_VBE "VBE"
#define VSC_TYPE_LCK "LCK"
#define VSC_TYPE_SMA "SMA"
#define VSC_TYPE_SMF "SMF"
#define VSC_TYPE_VBE "VBE"
#define VSC_TYPE_LCK "LCK"
#define VSC_TYPE_MEMPOOL "MEMPOOL"
#define VSC_F(n, t, l, f, e, d) t n;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment