Commit d73f4f61 authored by Julian Wiesener's avatar Julian Wiesener

Initial import

parents
*.o
*.so
*.la
*.lo
.deps/
.libs/
vcc_if.c
vcc_if.h
Makefile
README.html
aclocal.m4
autom4te.cache
config.*
configure
depcomp
install-sh
libtool
ltmain.sh
m4
missing
Makefile.in
stamp-h1
compile
vmod_vtstor.3
src/*.rst
Copyright (c) 2009-2013 UPLEX - Nils Goroll Systemoptimierung
...
See LICENSE for details.
You're free to use and distribute this under terms in the
LICENSE. Please add your relevant copyright statements.
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.
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
EXTRA_DIST = README.rst
dist_man_MANS = vmod_vtstor.3
MAINTAINERCLEANFILES = $(dist_man_MANS)
vmod_vtstor.3: README.rst
if HAVE_RST2MAN
${RST2MAN} README.rst $@
else
@echo "========================================"
@echo "You need rst2man installed to make dist"
@echo "========================================"
@false
endif
===========
vmod_vtstor
===========
#!/bin/sh
#
# $Id$
#
warn() {
echo "WARNING: $@" 1>&2
}
case `uname -s` in
Darwin)
LIBTOOLIZE=glibtoolize
;;
FreeBSD)
LIBTOOLIZE=libtoolize
;;
Linux)
LIBTOOLIZE=libtoolize
;;
SunOS)
LIBTOOLIZE=libtoolize
;;
*)
warn "unrecognized platform:" `uname -s`
LIBTOOLIZE=libtoolize
esac
automake_version=`automake --version | tr ' ' '\n' | egrep '^[0-9]\.[0-9a-z.-]+'`
if [ -z "$automake_version" ] ; then
warn "unable to determine automake version"
else
case $automake_version in
0.*|1.[0-8]|1.[0-8][.-]*)
warn "automake ($automake_version) detected; 1.9 or newer recommended"
;;
*)
;;
esac
fi
set -ex
aclocal
$LIBTOOLIZE --copy --force
autoheader
automake --add-missing --copy --foreign
autoconf
AC_PREREQ(2.59)
AC_COPYRIGHT([Copyright (c) 2013-2015 UPLEX - Nils Goroll Systemoptimierung, 2011 Varnish Software AS])
AC_INIT([libvmod-vtstor], [master])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/vmod_vtstor.vcc)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_SYSTEM
AC_LANG(C)
AM_INIT_AUTOMAKE([foreign])
AC_GNU_SOURCE
AC_PROG_CC
AC_PROG_CC_STDC
if test "x$ac_cv_prog_cc_c99" = xno; then
AC_MSG_ERROR([Could not find a C99 compatible compiler])
fi
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_LIBTOOL
AC_PROG_MAKE_SET
# Check for rst utilities
AC_CHECK_PROGS(RST2MAN, [rst2man rst2man.py], "no")
if test "x$RST2MAN" = "xno"; then
AC_MSG_WARN([rst2man not found - not building man pages])
fi
AM_CONDITIONAL(HAVE_RST2MAN, [test "x$RST2MAN" != "xno"])
# Check for pkg-config
PKG_PROG_PKG_CONFIG
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([sys/stdlib.h])
# Check for python
AC_CHECK_PROGS(PYTHON, [python3 python3.1 python3.2 python2.7 python2.6 python2.5 python2 python], [AC_MSG_ERROR([Python is needed to build this vmod, please install python.])])
# Varnish source tree
AC_ARG_VAR([VARNISHSRC], [path to Varnish source tree (mandatory)])
if test "x$VARNISHSRC" = x; then
AC_MSG_ERROR([No Varnish source tree specified])
fi
VARNISHSRC=`cd $VARNISHSRC && pwd`
AC_CHECK_FILE([$VARNISHSRC/include/vrt.h],
[],
[AC_MSG_FAILURE(["$VARNISHSRC" is not a Varnish source directory])]
)
# Check that varnishtest is built in the varnish source directory
AC_CHECK_FILE([$VARNISHSRC/bin/varnishtest/varnishtest],
[],
[AC_MSG_FAILURE([Can't find "$VARNISHSRC/bin/varnishtest/varnishtest". Please build your varnish source directory])]
)
# vmod installation dir
AC_ARG_VAR([VMODDIR], [vmod installation directory @<:@LIBDIR/varnish/vmods@:>@])
if test "x$VMODDIR" = x; then
VMODDIR=`pkg-config --variable=vmoddir varnishapi`
if test "x$VMODDIR" = x; then
AC_MSG_FAILURE([Can't determine vmod installation directory])
fi
fi
# This corresponds to FreeBSD's WARNS level 6
DEVELOPER_CFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wcast-align -Wunused-parameter -Wchar-subscripts -Winline -Wnested-externs -Wredundant-decls -Wformat"
# Additional flags for GCC 4
EXTRA_DEVELOPER_CFLAGS="-Wextra -Wno-missing-field-initializers -Wno-sign-compare"
# --enable-developer-warnings
AC_ARG_ENABLE(developer-warnings,
AS_HELP_STRING([--enable-developer-warnings],[enable strict warnings (default is NO)]),
CFLAGS="${CFLAGS} ${DEVELOPER_CFLAGS}")
# --enable-debugging-symbols
AC_ARG_ENABLE(debugging-symbols,
AS_HELP_STRING([--enable-debugging-symbols],[enable debugging symbols (default is NO)]),
CFLAGS="${CFLAGS} -O0 -g -fno-inline")
# --enable-diagnostics
AC_ARG_ENABLE(diagnostics,
AS_HELP_STRING([--enable-diagnostics],[enable run-time diagnostics (default is NO)]),
CFLAGS="${CFLAGS} -DDIAGNOSTICS")
# --enable-extra-developer-warnings
AC_ARG_ENABLE(extra-developer-warnings,
AS_HELP_STRING([--enable-extra-developer-warnings],[enable even stricter warnings (default is NO)]),
[],
[enable_extra_developer_warnings=no])
if test "x$enable_stack_protector" != "xno"; then
save_CFLAGS="$CFLAGS"
CFLAGS="${CFLAGS} ${EXTRA_DEVELOPER_CFLAGS}"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([],[],[])],
[],
[AC_MSG_WARN([All of ${EXTRA_DEVELOPER_CFLAGS} not supported, disabling])
CFLAGS="$save_CFLAGS"])
fi
# --enable-stack-protector
AC_ARG_ENABLE(stack-protector,
AS_HELP_STRING([--enable-stack-protector],[enable stack protector (default is NO)]),
[],
[enable_stack_protector=no])
if test "x$enable_stack_protector" != "xno"; then
save_CFLAGS="$CFLAGS"
CFLAGS="${CFLAGS} -fstack-protector-all"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([],[],[])],
[],
[AC_MSG_WARN([-fstack-protector not supported, disabling])
CFLAGS="$save_CFLAGS"])
fi
# --enable-tests
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[build test programs (default is NO)]))
AM_CONDITIONAL([ENABLE_TESTS], [test x$enable_tests = xyes])
# --enable-werror
AC_ARG_ENABLE(werror,
AS_HELP_STRING([--enable-werror],[use -Werror (default is NO)]),
CFLAGS="${CFLAGS} -Werror")
AC_CONFIG_FILES([
Makefile
src/Makefile
])
AC_OUTPUT
AM_CPPFLAGS = \
-I$(VARNISHSRC)/include \
-I$(VARNISHSRC)/bin/varnishd \
-I$(VARNISHSRC)/lib/libvgz
AM_LDFLAGS = $(AM_LT_LDFLAGS)
vmoddir = $(VMODDIR)
vmod_LTLIBRARIES = libvmod_vtstor.la
vmod_srcdir = $(top_srcdir)/src
vmodtool = $(VARNISHSRC)/lib/libvcc/vmodtool.py
libvmod_vtstor_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version -shared
libvmod_vtstor_la_SOURCES = \
vmod_vtstor.c \
vtstor.c
nodist_libvmod_vtstor_la_SOURCES = \
vcc_if.c \
vcc_if.h
# BUILT_SOURCES is only a hack and dependency tracking does not help for the first build
vmod_vtstor.lo: vcc_if.h
vcc_if.c vcc_if.h: $(vmodtool) $(vmod_srcdir)/vmod_vtstor.vcc
@PYTHON@ $(vmodtool) $(vmod_srcdir)/vmod_vtstor.vcc
VMOD_TESTS = tests/*.vtc
check: $(VARNISHSRC)/bin/varnishtest/varnishtest
$(VARNISHSRC)/bin/varnishtest/varnishtest \
-Dvarnishd=$(VARNISHSRC)/bin/varnishd/varnishd \
-Dvmod_topbuild=$(abs_top_builddir) \
tests/*.vtc
EXTRA_DIST = \
vmod_vtstor.vcc \
$(VMOD_TESTS)
CLEANFILES = $(builddir)/vcc_if.c $(builddir)/vcc_if.h
/*-
* Copyright (c) 2015 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Julian Wiesener <jw@uplex.de>
*
* 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.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "vtstor.h"
VCL_VOID __match_proto__(td_vmod_vtstor__init)
vmod_vtstor__init(VRT_CTX,
struct vmod_vtstor_vtstor **vmip, const char *vcl_name)
{
struct vmod_vtstor_vtstor *vmi;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
(void)vcl_name;
AN(vmip);
AZ(*vmip);
ALLOC_OBJ(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(vmi);
vmi->hash = vtstor_hash_crc32;
vmi->alloc = vtstor_alloc;
vmi->dealloc = vtstor_dealloc;
vmi->buckets = 1024;
vmi->timeout = 60;
vmi->key_max = 64;
vmi->value_max = 4096;
vmi->map = vtstor_init(vmi);
*vmip = vmi;
CHECK_OBJ_NOTNULL(*vmip, VMOD_VTSTOR_VTSTOR_MAGIC);
}
VCL_VOID __match_proto__(td_vmod_vtstor__fini)
vmod_vtstor__fini(struct vmod_vtstor_vtstor **vmip)
{
AN(vmip);
CHECK_OBJ_NOTNULL(*vmip, VMOD_VTSTOR_VTSTOR_MAGIC);
vtstor_deleteall(*vmip);
FREE_OBJ(*vmip);
*vmip = NULL;
}
VCL_VOID __match_proto__(td_vmod_vtstor_store)
vmod_vtstor_store(VRT_CTX, struct vmod_vtstor_vtstor *vmi,
VCL_STRING s, VCL_HEADER hdr)
{
struct http *hp;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(hdr);
AN(hdr->what);
hp = VRT_selecthttp(ctx, hdr->where);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
unsigned u, l = hdr->what[0];
assert(l == strlen(hdr->what + 1));
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
if(!strncasecmp(hp->hd[u].b, (hdr->what + 1), l))
vtstor_store(vmi, (hp->hd[u].b + ++l), s);
}
}
VCL_STRING __match_proto__(td_vmod_vtstor_get)
vmod_vtstor_get(VRT_CTX, struct vmod_vtstor_vtstor *vmi, VCL_HEADER hdr)
{
struct http *hp;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(hdr);
AN(hdr->what);
hp = VRT_selecthttp(ctx, hdr->where);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
unsigned u, l = hdr->what[0];
assert(l == strlen(hdr->what + 1));
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
if(!strncasecmp(hp->hd[u].b, (hdr->what + 1), l))
return(vtstor_get(vmi, (hp->hd[u].b + ++l)));
}
return(NULL);
}
VCL_VOID __match_proto__(td_vmod_vtstor_delete)
vmod_vtstor_delete(VRT_CTX, struct vmod_vtstor_vtstor *vmi, VCL_HEADER hdr)
{
struct http *hp;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(hdr);
AN(hdr->what);
hp = VRT_selecthttp(ctx, hdr->where);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
unsigned u, l = hdr->what[0];
assert(l == strlen(hdr->what + 1));
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
if(!strncasecmp(hp->hd[u].b, (hdr->what + 1), l))
vtstor_delete(vmi, (hp->hd[u].b + ++l));
}
}
VCL_STRING __match_proto__(td_vmod_vxid)
vmod_vxid(VRT_CTX, struct vmod_priv *priv)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
if(priv->priv == NULL) {
priv->priv = malloc(sizeof(char) * 11);
snprintf(priv->priv, 11, "%u", ctx->req->sp->vxid);
priv->free = free;
}
return(priv->priv);
}
#-
# Copyright (c) 2015 UPLEX - Nils Goroll Systemoptimierung
# All rights reserved.
#
# Author: Julian Wiesener <jw@uplex.de>
#
# 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.
$Module vtstor 3
$Object vtstor()
$Method VOID .store(STRING, HEADER)
$Method STRING .get(HEADER)
$Method VOID .delete(HEADER)
$Function STRING vxid(PRIV_TASK)
/*-
* Copyright (c) 2015 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Julian Wiesener <jw@uplex.de>
*
* 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.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include "vtstor.h"
#include "vgz.h"
struct vtstor_node {
unsigned magic;
#define VMOD_VTSTOR_NODE_MAGIC 0x8625cfc7
char* key;
char* value;
size_t key_capacity;
size_t value_capacity;
time_t ctime;
struct vtstor_node *next;
pthread_rwlock_t lock;
};
struct vtstor_map {
struct vtstor_node *node;
};
static struct vtstor_node* create_node(struct vmod_vtstor_vtstor *vmi)
{
(void) vmi;
struct vtstor_node* node = malloc(sizeof(struct vtstor_node));
if(!node)
return NULL;
memset(node, 0, sizeof(struct vtstor_node));
node->magic = 0x8625cfc7;
pthread_rwlock_init(&node->lock, NULL);
return node;
}
static struct vtstor_node* delete_node_r(struct vmod_vtstor_vtstor *vmi, struct vtstor_node *node)
{
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
if(node->next)
node->next = delete_node_r(vmi, node->next);
if(node->key)
vmi->dealloc(vmi, &node->key);
if(node->value)
vmi->dealloc(vmi, &node->value);
pthread_rwlock_destroy(&node->lock);
free(node);
return 0;
}
static inline struct vtstor_node* find_bucket(struct vmod_vtstor_vtstor *vmi, uint32_t hash)
{
return (vmi->map[hash % vmi->buckets].node);
}
/* By: Nils Goroll <slink@uplex.de> */
#define SMU_PWR_MIN 6 /* 64 b */
#define SMU_PWR_MAX 21 /* 2 M */
static inline int
szpwr(size_t size, size_t *space) {
int pwr;
if(size < (1 << SMU_PWR_MIN)) {
pwr = SMU_PWR_MIN;
*space = (1 << SMU_PWR_MIN);
} else if (size > (1 << SMU_PWR_MAX)) {
return -1;
} else {
size_t s;
pwr = log2(size);
s = (1 << pwr);
if((s < size) && (pwr < SMU_PWR_MAX)) {
pwr++;
*space = (s << 1);
} else {
*space = s;
}
}
return pwr;
}
static struct vtstor_node* find_node(struct vtstor_node *node, VCL_STRING key)
{
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
AN(key);
pthread_rwlock_rdlock(&node->lock);
if(node->key && !strcmp(node->key, key))
return node;
pthread_rwlock_unlock(&node->lock);
if(node->next == NULL)
return NULL;
return find_node(node->next, key);
}
static struct vtstor_node* new_node(struct vmod_vtstor_vtstor *vmi, struct vtstor_node *node)
{
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
time_t now = time(NULL);
pthread_rwlock_wrlock(&node->lock);
if(node->ctime + vmi->timeout < now)
return node;
if(node->next == NULL) {
struct vtstor_node* newnode = create_node(vmi);
if(!newnode) {
pthread_rwlock_unlock(&node->lock);
WRONG("Could not allocate new node");
}
pthread_rwlock_wrlock(&newnode->lock);
node->next = newnode;
pthread_rwlock_unlock(&node->lock);
return node->next;
}
pthread_rwlock_unlock(&node->lock);
return new_node(vmi, node->next);
}
static int vtstor_set_key(struct vmod_vtstor_vtstor *vmi, struct vtstor_node *node, VCL_STRING s)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
size_t size = strlen(s);
if(size > vmi->key_max)
return 0;
if(node->key) {
if(node->key_capacity >= size) {
snprintf(node->key, node->key_capacity, s);
return node->key_capacity;
}
vmi->dealloc(vmi, &node->key);
}
node->key_capacity = vmi->alloc(vmi, size, &node->key);
if(node->key_capacity)
snprintf(node->key, node->key_capacity, s);
return node->key_capacity;
}
static int vtstor_set_value(struct vmod_vtstor_vtstor *vmi, struct vtstor_node *node, VCL_STRING s)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
size_t size = strlen(s);
if(size > vmi->value_max)
return 0;
if(node->value) {
if(node->value_capacity >= size) {
snprintf(node->value, node->value_capacity, s);
return node->value_capacity;
}
vmi->dealloc(vmi, &node->value);
}
node->value_capacity = vmi->alloc(vmi, size, &node->value);
if(node->value_capacity)
snprintf(node->value, node->value_capacity, s);
return node->value_capacity;
}
uint32_t vtstor_hash_crc32(VCL_STRING s)
{
uint32_t crc;
crc = crc32(~0U, (const unsigned char*)s, strlen(s));
crc ^= ~0U;
crc++;
return (crc ? crc : 1);
}
size_t vtstor_alloc(struct vmod_vtstor_vtstor *vmi, size_t size, char** ptrp)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(ptrp);
AZ(*ptrp);
size_t space;
if(szpwr(size, &space) < 1)
return 0;
char *ptr = malloc(space);
if(ptr) {
*ptrp = ptr;
return space;
}
return 0;
}
void vtstor_dealloc(struct vmod_vtstor_vtstor *vmi, char **ptr)
{
(void) vmi;
if(*ptr) {
free(*ptr);
*ptr = NULL;
}
}
struct vtstor_map* vtstor_init(struct vmod_vtstor_vtstor *vmi)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
struct vtstor_map* map = malloc(sizeof(struct vtstor_map) * vmi->buckets);
if(!map)
WRONG("Could not allocate map");
unsigned u;
for(u = 0; u < vmi->buckets; u++) {
map[u].node = create_node(vmi);
if(!map[u].node)
WRONG("Could not allocate node");
}
return map;
}
void vtstor_deleteall(struct vmod_vtstor_vtstor *vmi)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(vmi->map);
unsigned u;
for(u = 0; u < vmi->buckets; u++)
vmi->map[u].node = delete_node_r(vmi, vmi->map[u].node);
free(vmi->map);
vmi->map = NULL;
}
void vtstor_store(struct vmod_vtstor_vtstor *vmi, VCL_STRING key, VCL_STRING value)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(vmi->map);
struct vtstor_node *headnode = find_bucket(vmi, vmi->hash(key));
AN(headnode);
struct vtstor_node *node = find_node(headnode, key);
if(node) {
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
pthread_rwlock_unlock(&node->lock);
pthread_rwlock_wrlock(&node->lock);
/* need recheck key, node might got recycled */
if(node->key && !strcmp(node->key, key)) {
if(vtstor_set_value(vmi, node, value)) {
node->ctime = time(NULL);
pthread_rwlock_unlock(&node->lock);
return;
}
pthread_rwlock_unlock(&node->lock);
WRONG("could not store value");
}
pthread_rwlock_unlock(&node->lock);
}
/* if someone had created a node for that key in the meantime, the
* keys are not uniq, that should not happen, i don't care for now */
node = new_node(vmi, headnode);
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
if(!vtstor_set_key(vmi, node, key)) {
pthread_rwlock_unlock(&node->lock);
WRONG("could not store key");
}
if(!vtstor_set_value(vmi, node, value)) {
pthread_rwlock_unlock(&node->lock);
node->key[0] = '\0';
WRONG("could not store value");
}
node->ctime = time(NULL);
pthread_rwlock_unlock(&node->lock);
}
VCL_STRING vtstor_get(struct vmod_vtstor_vtstor *vmi, VCL_STRING key)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(vmi->map);
struct vtstor_node *node = find_bucket(vmi, vmi->hash(key));
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
node = find_node(node, key);
if(node == NULL)
return NULL;
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
pthread_rwlock_unlock(&node->lock);
/* returning a pointer here is racy, would need to copy into priv */
return(node->value);
}
void vtstor_delete(struct vmod_vtstor_vtstor *vmi, VCL_STRING key)
{
CHECK_OBJ_NOTNULL(vmi, VMOD_VTSTOR_VTSTOR_MAGIC);
AN(vmi->map);
struct vtstor_node *node = find_bucket(vmi, vmi->hash(key));
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
node = find_node(node, key);
if(node == NULL)
return;
CHECK_OBJ_NOTNULL(node, VMOD_VTSTOR_NODE_MAGIC);
pthread_rwlock_unlock(&node->lock);
pthread_rwlock_wrlock(&node->lock);
/* need recheck key, node might got recycled */
if(node->key && !strcmp(node->key, key)) {
node->key[0] = '\0';
node->ctime = 0;
}
pthread_rwlock_unlock(&node->lock);
return;
}
/*-
* Copyright (c) 2015 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Julian Wiesener <jw@uplex.de>
*
* 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.
*/
#include "config.h"
#include "cache/cache.h"
#include "vrt.h"
#include "vcc_if.h"
struct vmod_vtstor_vtstor;
typedef size_t (*malloc_func)(struct vmod_vtstor_vtstor *, size_t, char **);
typedef void (*dealloc_func)(struct vmod_vtstor_vtstor *, char **);
typedef uint32_t (*hash_func)(VCL_STRING);
struct vtstor_map;
struct vmod_vtstor_vtstor {
unsigned magic;
#define VMOD_VTSTOR_VTSTOR_MAGIC 0x5881bc28
hash_func hash;
malloc_func alloc;
dealloc_func dealloc;
size_t key_max;
size_t value_max;
unsigned buckets;
unsigned timeout;
struct vtstor_map *map;
};
uint32_t vtstor_hash_crc32(VCL_STRING);
size_t vtstor_alloc(struct vmod_vtstor_vtstor *, size_t, char **);
void vtstor_dealloc(struct vmod_vtstor_vtstor *, char **);
struct vtstor_map* vtstor_init(struct vmod_vtstor_vtstor *);
void vtstor_deleteall(struct vmod_vtstor_vtstor *);
void vtstor_store(struct vmod_vtstor_vtstor *,VCL_STRING, VCL_STRING);
VCL_STRING vtstor_get(struct vmod_vtstor_vtstor *, VCL_STRING);
void vtstor_delete(struct vmod_vtstor_vtstor *,VCL_STRING);
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