Commit f394f0ad authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

The new VSM api:

Instead of the diag() callback, use a vsb to collect diagnostics
and return it with VSM_Error().

Simpler logic around open/close.

More useful Abandonned() and StillValid() functions.

Still not happy with __itern(), will revisit later.
parent 900920c3
......@@ -26,14 +26,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This is the public API for the VSM/VSC/VSL access.
* This is the public API for the VSM access.
*
* The VSM "class" acts as parent class for the VSL and VSC subclasses.
*
*/
#ifndef VAPI_VSM_H_INCLUDED
#define VAPI_VSM_H_INCLUDED
struct VSM_head;
struct VSM_chunk;
struct VSM_data;
......@@ -45,7 +46,7 @@ struct VSM_fantom {
struct VSM_chunk *chunk;
void *b; /* first byte of payload */
void *e; /* first byte past payload */
uintptr_t priv;
uintptr_t priv; /* VSM private */
};
/*---------------------------------------------------------------------
......@@ -56,20 +57,22 @@ struct VSM_data *VSM_New(void);
/*
* Allocate and initialize a VSL_data handle structure.
* This is the first thing you will have to do, always.
* You can have multiple active VSL_data handles at the same time
* You can have multiple active VSM_data handles at the same time
* referencing the same or different shared memory files.
* Returns:
* Pointer to usable VSL_data handle.
* NULL: malloc failed.
*/
typedef void VSM_diag_f(void *priv, const char *fmt, ...);
void VSM_Delete(struct VSM_data *vd);
/*
* Close and deallocate all storage and mappings.
* (including any VSC and VSL "sub-classes")
*/
void VSM_Diag(struct VSM_data *vd, VSM_diag_f *func, void *priv);
const char *VSM_Error(const struct VSM_data *vd);
/*
* Set the diagnostics reporting function.
* Default is fprintf(stderr, ...)
* If func is NULL, diagnostics are disabled.
* Return the latest error message.
*/
#define VSM_n_USAGE "[-n varnish_name]"
......@@ -77,11 +80,10 @@ void VSM_Diag(struct VSM_data *vd, VSM_diag_f *func, void *priv);
int VSM_n_Arg(struct VSM_data *vd, const char *n_arg);
/*
* Configure which varnishd instance to access.
* Can also be, and normally is done through the VSL_Log_arg()
* and VSC_Arg() functions.
* Can also be, and normally is done through VSC_Arg()/VSL_Arg().
* Returns:
* 1 on success
* -1 on failure, with diagnostic.
* <0 on failure, use VSM_Error() to get diagnostics.
*/
const char *VSM_Name(const struct VSM_data *vd);
......@@ -89,42 +91,32 @@ const char *VSM_Name(const struct VSM_data *vd);
* Return the instance name.
*/
void VSM_Delete(struct VSM_data *vd);
/*
* Close and deallocate all storage and mappings.
*/
/* XXX: extension: Patience argument for sleeps */
int VSM_Open(struct VSM_data *vd, int diag);
int VSM_Open(struct VSM_data *vd);
/*
* Attempt to open and map the shared memory file.
* Attempt to open and map the VSM file.
* If diag is non-zero, diagnostics are emitted.
* Returns:
* 0 on success
* != 0 on failure
* <0 on failure, use VSM_Error() to get diagnostics.
*/
int VSM_ReOpen(struct VSM_data *vd, int diag);
int VSM_Abandonned(const struct VSM_data *vd);
/*
* Check if shared memory segment needs to be reopened/remapped
* typically when the varnishd master process restarts.
* diag is passed to VSM_Open()
* Find out if the VSM file has been abandonned or closed and should
* be reopened. This function calls stat(2) and should only be
* used when lack of activity or invalidation of fantoms indicate
* abandonment.
*
* Returns:
* 0 No reopen needed.
* 1 shared memory reopened/remapped.
* -1 failure to reopen.
* 1 VSM abandonned.
*/
unsigned VSM_Seq(const struct VSM_data *vd);
void VSM_Close(struct VSM_data *vd);
/*
* Return the allocation sequence number
* Close and unmap shared memory, if open.
*/
struct VSM_head *VSM_Head(const struct VSM_data *vd);
/*
* Return the head of the VSM.
*/
void VSM__iter0(const struct VSM_data *vd, struct VSM_fantom *vf);
int VSM__itern(const struct VSM_data *vd, struct VSM_fantom *vf);
......@@ -139,8 +131,12 @@ int VSM__itern(const struct VSM_data *vd, struct VSM_fantom *vf);
int VSM_StillValid(const struct VSM_data *vd, struct VSM_fantom *vf);
/*
* This is a cheap syscall-less check to see if the fantom is still
* valid. Further checking with VSM_Abandonned() may be a good
* idea.
*
* Return:
* 0: fantom is invalid now.
* 0: fantom is not valid any more.
* 1: fantom is still the same.
* 2: a fantom with same dimensions exist, check class/type/ident
*/
......@@ -153,41 +149,4 @@ int VSM_Get(const struct VSM_data *vd, struct VSM_fantom *vf,
* class is mandatory, type and ident optional.
*/
void VSM_Close(struct VSM_data *vd);
/*
* Unmap shared memory
* Deallocate all storage (including VSC and VSL allocations)
*/
/**********************************************************************
* These are old API functions which are less safe because there is
* fantom protecting the chunks worked on.
* They will g
*/
/* OBSOLETE: Will disappear from Varnish 4.x */
void *VSM_Find_Chunk(const struct VSM_data *vd, const char *class,
const char *type, const char *ident, unsigned *lenp);
/*
* Find a given chunk in the shared memory.
* Returns pointer or NULL.
* Lenp, if non-NULL, is set to length of chunk.
*/
/* OBSOLETE: Will disappear from Varnish 4.x */
struct VSM_chunk *VSM_iter0(struct VSM_data *vd);
/* OBSOLETE: Will disappear from Varnish 4.x */
void VSM_itern(struct VSM_data *vd, struct VSM_chunk **pp);
/* OBSOLETE: Will disappear from Varnish 4.x */
#define VSM_FOREACH(var, vd) \
for((var) = VSM_iter0((vd)); (var) != NULL; VSM_itern((vd), &(var)))
/*
* Iterate over all chunks in shared memory
* var = "struct VSM_chunk *"
* vd = "struct VSM_data"
*/
#endif /* VAPI_VSM_H_INCLUDED */
......@@ -35,6 +35,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -47,12 +48,14 @@
#include "vapi/vsm.h"
#include "vapi/vsm_int.h"
#include "vin.h"
#include "vsb.h"
#include "vsm_api.h"
#ifndef MAP_HASSEMAPHORE
#define MAP_HASSEMAPHORE 0 /* XXX Linux */
#endif
/*--------------------------------------------------------------------*/
struct VSM_data *
......@@ -64,9 +67,6 @@ VSM_New(void)
if (vd == NULL)
return (vd);
vd->diag = (VSM_diag_f*)fprintf;
vd->priv = stderr;
vd->vsm_fd = -1;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
......@@ -75,16 +75,35 @@ VSM_New(void)
/*--------------------------------------------------------------------*/
void
VSM_Diag(struct VSM_data *vd, VSM_diag_f *func, void *priv)
static int
vsm_diag(struct VSM_data *vd, const char *fmt, ...)
{
va_list ap;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (func == NULL)
vd->diag = (VSM_diag_f*)getpid;
AN(fmt);
if (vd->diag == NULL)
vd->diag = VSB_new_auto();
AN(vd->diag);
va_start(ap, fmt);
VSB_vprintf(vd->diag, fmt, ap);
va_end(ap);
AZ(VSB_finish(vd->diag));
return (-1);
}
/*--------------------------------------------------------------------*/
const char *
VSM_Error(const struct VSM_data *vd)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (vd->diag == NULL)
return (NULL);
else
vd->diag = func;
vd->priv = priv;
return (VSB_data(vd->diag));
}
/*--------------------------------------------------------------------*/
......@@ -94,13 +113,12 @@ VSM_n_Arg(struct VSM_data *vd, const char *opt)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
REPLACE(vd->n_opt, opt);
AN(vd->n_opt);
if (VIN_N_Arg(vd->n_opt, NULL, NULL, &vd->fname)) {
vd->diag(vd->priv, "Invalid instance name: %s\n",
strerror(errno));
return (-1);
}
REPLACE(vd->n_opt, opt);
if (VIN_N_Arg(vd->n_opt, NULL, NULL, &vd->fname))
return (vsm_diag(vd, "Invalid instance name: %s\n",
strerror(errno)));
return (1);
}
......@@ -111,6 +129,7 @@ VSM_Name(const struct VSM_data *vd)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
return (vd->n_opt);
}
......@@ -123,15 +142,12 @@ VSM_Delete(struct VSM_data *vd)
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
VSM_Close(vd);
free(vd->n_opt);
free(vd->fname);
if (vd->vsc != NULL)
VSC_Delete(vd);
if (vd->vsl != NULL)
VSL_Delete(vd);
FREE_OBJ(vd);
}
......@@ -144,64 +160,59 @@ VSM_Delete(struct VSM_data *vd)
*
*/
static int
vsm_open(struct VSM_data *vd, int diag)
/*--------------------------------------------------------------------*/
int
VSM_Open(struct VSM_data *vd)
{
int i;
struct VSM_head slh;
void *v;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AZ(vd->head);
if (!vd->n_opt)
(void)VSM_n_Arg(vd, "");
AZ(vd->head);
AN(vd->fname);
vd->vsm_fd = open(vd->fname, O_RDONLY);
if (vd->vsm_fd < 0) {
if (diag)
vd->diag(vd->priv, "Cannot open %s: %s\n",
vd->fname, strerror(errno));
return (-1);
}
if (vd->vsm_fd < 0)
return (vsm_diag(vd, "Cannot open %s: %s\n",
vd->fname, strerror(errno)));
AZ(fstat(vd->vsm_fd, &vd->fstat));
if (!S_ISREG(vd->fstat.st_mode)) {
if (diag)
vd->diag(vd->priv, "%s is not a regular file\n",
vd->fname);
AZ(close(vd->vsm_fd));
vd->vsm_fd = -1;
return (-1);
return (vsm_diag(vd, "%s is not a regular file\n",
vd->fname));
}
i = read(vd->vsm_fd, &slh, sizeof slh);
if (i != sizeof slh) {
if (diag)
vd->diag(vd->priv, "Cannot read %s: %s\n",
vd->fname, strerror(errno));
AZ(close(vd->vsm_fd));
vd->vsm_fd = -1;
return (-1);
return(vsm_diag(vd, "Cannot read %s: %s\n",
vd->fname, strerror(errno)));
}
if (memcmp(slh.marker, VSM_HEAD_MARKER, sizeof slh.marker) ||
slh.alloc_seq == 0) {
if (diag)
vd->diag(vd->priv, "Not a VSM file %s\n",
vd->fname);
AZ(close(vd->vsm_fd));
vd->vsm_fd = -1;
return (-1);
return (vsm_diag(vd, "Not a VSM file %s\n", vd->fname));
}
v = mmap(NULL, slh.shm_size,
PROT_READ, MAP_SHARED|MAP_HASSEMAPHORE, vd->vsm_fd, 0);
if (v == MAP_FAILED) {
if (diag)
vd->diag(vd->priv, "Cannot mmap %s: %s\n",
vd->fname, strerror(errno));
AZ(close(vd->vsm_fd));
vd->vsm_fd = -1;
return (-1);
return (vsm_diag(vd, "Cannot mmap %s: %s\n",
vd->fname, strerror(errno)));
}
vd->head = v;
vd->b = v;
......@@ -212,25 +223,12 @@ vsm_open(struct VSM_data *vd, int diag)
/*--------------------------------------------------------------------*/
int
VSM_Open(struct VSM_data *vd, int diag)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AZ(vd->head);
if (!vd->n_opt)
(void)VSM_n_Arg(vd, "");
return (vsm_open(vd, diag));
}
/*--------------------------------------------------------------------*/
void
VSM_Close(struct VSM_data *vd)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (vd->head == NULL)
return;
......@@ -246,42 +244,24 @@ VSM_Close(struct VSM_data *vd)
/*--------------------------------------------------------------------*/
int
VSM_ReOpen(struct VSM_data *vd, int diag)
VSM_Abandonned(const struct VSM_data *vd)
{
struct stat st;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AN(vd->head);
if (vd->head->alloc_seq &&
!stat(vd->fname, &st) &&
st.st_dev == vd->fstat.st_dev &&
st.st_ino == vd->fstat.st_ino)
return (0);
VSM_Close(vd);
return (vsm_open(vd, diag));
}
/*--------------------------------------------------------------------*/
unsigned
VSM_Seq(const struct VSM_data *vd)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
return (vd->head->alloc_seq);
}
/*--------------------------------------------------------------------*/
struct VSM_head *
VSM_Head(const struct VSM_data *vd)
{
if (vd->head == NULL)
return (1);
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AN(vd->head);
return(vd->head);
if (!vd->head->alloc_seq)
return (1);
if (!stat(vd->fname, &st))
return (1);
if (st.st_dev != vd->fstat.st_dev)
return (1);
if (st.st_ino != vd->fstat.st_ino)
return (1);
return (0);
}
/*--------------------------------------------------------------------*/
......@@ -291,15 +271,20 @@ VSM__iter0(const struct VSM_data *vd, struct VSM_fantom *vf)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AN(vf);
memset(vf, 0, sizeof *vf);
}
/* XXX: revisit, logic is unclear */
int
VSM__itern(const struct VSM_data *vd, struct VSM_fantom *vf)
{
void *p;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
AN(vf);
if (vd->head->alloc_seq == 0)
return (0); /* abandonned VSM */
else if (vf->priv != 0) {
......@@ -325,7 +310,7 @@ VSM__itern(const struct VSM_data *vd, struct VSM_fantom *vf)
vf->b = (void*)(vf->chunk + 1);
vf->e = (char*)vf->b + vf->chunk->len;
if (vd->priv == 0)
if (vf->priv == 0)
return (0); /* abandonned VSM */
if (vf->b == vf->e)
return (0); /* freed chunk */
......@@ -342,14 +327,13 @@ VSM_StillValid(const struct VSM_data *vd, struct VSM_fantom *vf)
struct VSM_fantom f2;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (vf == NULL)
return (vd->head->alloc_seq ? 1 : 0);
AN(vf);
if (!vd->head->alloc_seq)
return (0);
if (vf->priv == vd->head->alloc_seq)
return (1);
VSM_FOREACH_SAFE(&f2, vd) {
if (f2.chunk == vf->chunk &&
f2.b == vf->b &&
f2.e == vf->e) {
if (f2.chunk == vf->chunk && f2.b == vf->b && f2.e == vf->e) {
vf->priv = vd->head->alloc_seq;
return (2);
}
......@@ -375,45 +359,3 @@ VSM_Get(const struct VSM_data *vd, struct VSM_fantom *vf,
memset(vf, 0, sizeof *vf);
return (0);
}
/*--------------------------------------------------------------------*/
void *
VSM_Find_Chunk(const struct VSM_data *vd, const char *class,
const char *type, const char *ident, unsigned *lenp)
{
struct VSM_fantom vf;
if (VSM_Get(vd, &vf, class, type, ident)) {
if (lenp != NULL)
*lenp = (char*)vf.e - (char*)vf.b;
return (vf.chunk);
}
if (lenp != NULL)
*lenp = 0;
return (NULL);
}
/*--------------------------------------------------------------------*/
struct VSM_chunk *
VSM_iter0(struct VSM_data *vd)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
VSM__iter0(vd, &vd->compat_vf);
if (VSM__itern(vd, &vd->compat_vf))
return(vd->compat_vf.chunk);
return (NULL);
}
void
VSM_itern(struct VSM_data *vd, struct VSM_chunk **pp)
{
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (VSM__itern(vd, &vd->compat_vf))
*pp = vd->compat_vf.chunk;
else
*pp = NULL;
}
......@@ -29,13 +29,13 @@
*/
struct vsc;
struct vsb;
struct VSM_data {
unsigned magic;
#define VSM_MAGIC 0x6e3bd69b
VSM_diag_f *diag;
void *priv;
struct vsb *diag;
char *n_opt;
char *fname;
......
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