/*-
 * Copyright (c) 2006 Verdens Gang AS
 * Copyright (c) 2006-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.
 *
 * This defines the backend interface between the stevedore and the
 * pluggable storage implementations.
 *
 */

struct stevedore;
struct sess;
struct busyobj;
struct objcore;
struct worker;
struct lru;
struct vsl_log;
struct vfp_ctx;

/* Storage -----------------------------------------------------------*/

struct storage {
	unsigned		magic;
#define STORAGE_MAGIC		0x1a4e51c0


	VTAILQ_ENTRY(storage)	list;
	void			*priv;

	unsigned char		*ptr;
	unsigned		len;
	unsigned		space;
};

/* Object ------------------------------------------------------------*/

VTAILQ_HEAD(storagehead, storage);

struct object {
	unsigned		magic;
#define OBJECT_MAGIC		0x32851d42
	struct storage		*objstore;

	/* Fixed size attributes */
#define OBJ_FIXATTR(U, l, s)			\
	uint8_t			fa_##l[s];
#include "tbl/obj_attr.h"
#undef OBJ_FIXATTR

	/* Variable size attributes */
#define OBJ_VARATTR(U, l)			\
	uint8_t			*va_##l;
#include "tbl/obj_attr.h"
#undef OBJ_VARATTR
#define OBJ_VARATTR(U, l)			\
	unsigned		va_##l##_len;
#include "tbl/obj_attr.h"
#undef OBJ_VARATTR

	/* Auxiliary attributes */
#define OBJ_AUXATTR(U, l)			\
	struct storage		*aa_##l;
#include "tbl/obj_attr.h"
#undef OBJ_AUXATTR

	struct storagehead	list;
	ssize_t			len;
};

/* Methods on objcore ------------------------------------------------*/

typedef void updatemeta_f(struct worker *, struct objcore *oc);
typedef void freeobj_f(struct worker *, struct objcore *oc);

/*
 * Stevedores can either be simple, and provide just this method:
 */

typedef struct object *getobj_f(struct worker *, struct objcore *oc);

/*
 * Or the can be "complex" and provide all of these methods:
 * (Described in comments in cache_obj.c)
 */
typedef void *objiterbegin_f(struct worker *, struct objcore *oc);
typedef enum objiter_status objiter_f(struct objcore *oc, void *oix,
    void **p, ssize_t *l);
typedef void objiterend_f(struct objcore *, void **oix);
typedef int objgetspace_f(struct worker *, struct objcore *,
     ssize_t *sz, uint8_t **ptr);
typedef int objextend_f(struct worker *, struct objcore *, ssize_t l);
typedef void objtrimstore_f(struct worker *, struct objcore *);
typedef void objslim_f(struct worker *, struct objcore *);
typedef const void *objgetattr_f(struct worker *, struct objcore *,
    int attr, ssize_t *len);
typedef void *objsetattr_f(struct worker *, struct objcore *,
    int attr, ssize_t len, const void *ptr);
typedef int objsaveattr_f(struct worker *, struct objcore *);
typedef uint64_t objgetlen_f(struct worker *, struct objcore *);
typedef int objfinish_f(struct worker *, struct objcore *);
typedef void objpanic_f(struct vsb *, const struct objcore *);

struct storeobj_methods {
	freeobj_f	*freeobj;
	updatemeta_f	*updatemeta;

	getobj_f	*getobj;

	objiterbegin_f	*objiterbegin;
	objiter_f	*objiter;
	objiterend_f	*objiterend;
	objgetspace_f	*objgetspace;
	objextend_f	*objextend;
	objgetlen_f	*objgetlen;
	objtrimstore_f	*objtrimstore;
	objslim_f	*objslim;
	objgetattr_f	*objgetattr;
	objsetattr_f	*objsetattr;
	objsaveattr_f	*objsaveattr;
	objfinish_f	*objfinish;
	objpanic_f	*objpanic;
};

/* Prototypes --------------------------------------------------------*/

typedef void storage_init_f(struct stevedore *, int ac, char * const *av);
typedef void storage_open_f(struct stevedore *);
typedef struct storage *storage_alloc_f(const struct stevedore *, size_t size);
typedef void storage_trim_f(struct storage *, size_t size, int move_ok);
typedef void storage_free_f(struct storage *);
typedef int storage_allocobj_f(struct worker *, const struct stevedore *,
    struct objcore *, unsigned valen, ssize_t bodylen);
typedef void storage_close_f(const struct stevedore *);
typedef void storage_signal_close_f(const struct stevedore *);

/* Prototypes for VCL variable responders */
#define VRTSTVTYPE(ct) typedef ct storage_var_##ct(const struct stevedore *);
#include "tbl/vrt_stv_var.h"
#undef VRTSTVTYPE

extern storage_allocobj_f stv_default_allocobj;

extern const struct storeobj_methods default_oc_methods;

/*--------------------------------------------------------------------*/

struct stevedore {
	unsigned		magic;
#define STEVEDORE_MAGIC		0x4baf43db
	const char		*name;
	unsigned		transient;
	storage_init_f		*init;		/* called by mgt process */
	storage_open_f		*open;		/* called by cache process */
	storage_alloc_f		*alloc;		/* --//-- */
	storage_trim_f		*trim;		/* --//-- */
	storage_free_f		*free;		/* --//-- */
	storage_close_f		*close;		/* --//-- */
	storage_allocobj_f	*allocobj;	/* --//-- */
	storage_signal_close_f	*signal_close;	/* --//-- */

	const struct storeobj_methods
				*methods;

	struct lru_chain	*lru_chain;

#define VRTSTVVAR(nm, vtype, ctype, dval) storage_var_##ctype *var_##nm;
#include "tbl/vrt_stv_var.h"
#undef VRTSTVVAR

	/* private fields */
	void			*priv;

	VTAILQ_ENTRY(stevedore)	list;
	char			ident[16];	/* XXX: match VSM_chunk.ident */
};

VTAILQ_HEAD(stevedore_head, stevedore);

extern struct stevedore_head stv_stevedores;
extern struct stevedore *stv_transient;

/*--------------------------------------------------------------------*/
int STV_GetFile(const char *fn, int *fdp, const char **fnp, const char *ctx);
uintmax_t STV_FileSize(int fd, const char *size, unsigned *granularity,
    const char *ctx);
struct object *STV_MkObject(const struct stevedore *, struct objcore *,
    void *ptr);

/*--------------------------------------------------------------------*/
extern const struct stevedore sma_stevedore;
extern const struct stevedore smf_stevedore;
extern const struct stevedore smp_stevedore;
#ifdef HAVE_LIBUMEM
extern const struct stevedore smu_stevedore;
#endif
extern const struct stevedore mse_stevedore;
