Commit 7e2f8c69 authored by Geoff Simmons's avatar Geoff Simmons

Add the .backend() method.

set objects now have bitmaps internally to keep track of which data
types have been added for each element.
parent f3293c2a
......@@ -25,6 +25,7 @@ CONTENTS
* :ref:`obj_set`
* :ref:`func_set.add`
* :ref:`func_set.backend`
* :ref:`func_set.debug`
* :ref:`func_set.element`
* :ref:`func_set.hasprefix`
......@@ -195,6 +196,27 @@ Example::
}
.. _func_set.backend:
BACKEND xset.backend(INT n, ENUM select)
----------------------------------------
::
BACKEND xset.backend(
INT n=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE
)
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
.. _func_set.debug:
STRING xset.debug()
......
# looks like -*- vcl -*-
varnishtest "element() method"
varnish v1 -vcl {
import ${vmod_selector};
backend b1 { .host = "${bad_ip}"; }
backend b2 { .host = "${bad_ip}"; }
backend b3 { .host = "${bad_ip}"; }
backend b4 { .host = "${bad_ip}"; }
backend b5 { .host = "${bad_ip}"; }
sub vcl_init {
new s = selector.set();
s.add("foo", backend=b1);
s.add("bar", backend=b2);
s.add("baz", backend=b3);
s.add("quux", backend=b4);
s.add("foobar", backend=b5);
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
set resp.http.N-1 = s.backend(1);
set resp.http.N-2 = s.backend(2);
set resp.http.N-3 = s.backend(3);
set resp.http.N-4 = s.backend(4);
set resp.http.N-5 = s.backend(5);
set resp.http.N--1 = s.backend(-1);
set resp.http.N-0 = s.backend(0);
set resp.http.N-6 = s.backend(6);
if (s.match(req.http.Word)) {
set resp.http.Backend = s.backend();
set resp.http.Backend-Unique = s.backend(select=UNIQUE);
set resp.http.Backend-Exact = s.backend(select=EXACT);
set resp.http.Backend-First = s.backend(select=FIRST);
set resp.http.Backend-Last = s.backend(select=LAST);
set resp.http.Backend-Shortest
= s.backend(select=SHORTEST);
set resp.http.Backend-Longest
= s.backend(select=LONGEST);
}
return (deliver);
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.N-1 == "b1"
expect resp.http.N-2 == "b2"
expect resp.http.N-3 == "b3"
expect resp.http.N-4 == "b4"
expect resp.http.N-5 == "b5"
expect resp.http.N--1 == ""
expect resp.http.N-0 == ""
expect resp.http.N-6 == ""
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b1"
expect resp.http.Backend-Unique == resp.http.Backend
expect resp.http.Backend-Exact == resp.http.Backend
expect resp.http.Backend-First == "b1"
expect resp.http.Backend-Last == "b1"
expect resp.http.Backend-Shortest == "b1"
expect resp.http.Backend-Longest == "b1"
txreq -hdr "Word: bar"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b2"
expect resp.http.Backend-Unique == resp.http.Backend
expect resp.http.Backend-Exact == resp.http.Backend
expect resp.http.Backend-First == "b2"
expect resp.http.Backend-Last == "b2"
expect resp.http.Backend-Shortest == "b2"
expect resp.http.Backend-Longest == "b2"
txreq -hdr "Word: baz"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b3"
expect resp.http.Backend-Unique == resp.http.Backend
expect resp.http.Backend-Exact == resp.http.Backend
expect resp.http.Backend-First == "b3"
expect resp.http.Backend-Last == "b3"
expect resp.http.Backend-Shortest == "b3"
expect resp.http.Backend-Longest == "b3"
txreq -hdr "Word: quux"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b4"
expect resp.http.Backend-Unique == resp.http.Backend
expect resp.http.Backend-Exact == resp.http.Backend
expect resp.http.Backend-First == "b4"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b4"
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b5"
expect resp.http.Backend-Unique == resp.http.Backend
expect resp.http.Backend-Exact == resp.http.Backend
expect resp.http.Backend-First == "b5"
expect resp.http.Backend-Last == "b5"
expect resp.http.Backend-Shortest == "b5"
expect resp.http.Backend-Longest == "b5"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(\) called without prior match$}
expect * = VCL_Error {^vmod selector error: s\.backend\(\) called without prior match$}
expect * = VCL_Error {^vmod selector error: s\.backend\(6\): set has 5 elements$}
expect * = End
} -run
varnish v1 -vcl {
import ${vmod_selector};
backend b1 { .host = "${bad_ip}"; }
backend b2 { .host = "${bad_ip}"; }
backend b3 { .host = "${bad_ip}"; }
backend b4 { .host = "${bad_ip}"; }
sub vcl_init {
new s = selector.set();
s.add("foobarbazquux", backend=b1);
s.add("foobarbaz", backend=b2);
s.add("foobar", backend=b3);
s.add("foo", backend=b4);
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
if (s.hasprefix(req.http.Word)) {
set resp.http.Backend = s.backend();
set resp.http.Backend-Unique = s.backend(select=UNIQUE);
set resp.http.Backend-Exact = s.backend(select=EXACT);
set resp.http.Backend-First = s.backend(select=FIRST);
set resp.http.Backend-Last = s.backend(select=LAST);
set resp.http.Backend-Shortest
= s.backend(select=SHORTEST);
set resp.http.Backend-Longest
= s.backend(select=LONGEST);
}
return (deliver);
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * 1009 Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 2 elements were matched$}
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 2 elements were matched$}
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 3 elements were matched$}
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 3 elements were matched$}
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 4 elements were matched$}
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 4 elements were matched$}
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 2 elements were matched$}
expect * = VCL_Error {^vmod selector error: s\.backend\(select=UNIQUE\): 2 elements were matched$}
expect * = VCL_Error {^vmod selector error: s\.backend\(select=EXACT\): no element matched exactly$}
expect * = End
} -start
client c1 {
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b4"
expect resp.http.Backend-Unique == "b4"
expect resp.http.Backend-Exact == "b4"
expect resp.http.Backend-First == "b4"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b4"
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 200
expect resp.http.Backend == ""
expect resp.http.Backend-Unique == ""
expect resp.http.Backend-Exact == "b3"
expect resp.http.Backend-First == "b3"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b3"
txreq -hdr "Word: foobarbaz"
rxresp
expect resp.status == 200
expect resp.http.Backend == ""
expect resp.http.Backend-Unique == ""
expect resp.http.Backend-Exact == "b2"
expect resp.http.Backend-First == "b2"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b2"
txreq -hdr "Word: foobarbazquux"
rxresp
expect resp.status == 200
expect resp.http.Backend == ""
expect resp.http.Backend-Unique == ""
expect resp.http.Backend-Exact == "b1"
expect resp.http.Backend-First == "b1"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b1"
txreq -hdr "Word: foobarb"
rxresp
expect resp.status == 200
expect resp.http.Backend == ""
expect resp.http.Backend-Unique == ""
expect resp.http.Backend-Exact == ""
expect resp.http.Backend-First == "b3"
expect resp.http.Backend-Last == "b4"
expect resp.http.Backend-Shortest == "b4"
expect resp.http.Backend-Longest == "b3"
} -run
logexpect l1 -wait
varnish v1 -vcl {
import ${vmod_selector};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = selector.set();
s.add("foo", backend=b);
s.add("bar");
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
if (s.match(req.http.Word)) {
set resp.http.Backend = s.backend();
}
return (deliver);
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: s\.backend\(\): backend not added for element 2$}
expect * = End
} -start
client c1 {
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Backend == "b"
txreq -hdr "Word: bar"
rxresp
expect resp.status == 200
expect resp.http.Backend == ""
} -run
logexpect l1 -wait
......@@ -38,6 +38,7 @@
#include "cache/cache.h"
#include "vcl.h"
#include "vre.h"
#include "vbm.h"
#include "cache/cache_director.h"
#include "vcc_if.h"
......@@ -61,6 +62,19 @@ struct entry {
vre_t *re;
};
enum bitmap_e {
STRING = 0,
BACKEND,
REGEX,
__MAX_BITMAP,
};
struct bitmaps {
unsigned magic;
#define VMOD_SELECTOR_BITMAPS_MAGIC 0x5b17093f
struct vbitmap *bitmaps[__MAX_BITMAP];
};
struct vmod_selector_set {
unsigned magic;
#define VMOD_SELECTOR_SET_MAGIC 0x838979ef
......@@ -69,6 +83,7 @@ struct vmod_selector_set {
char **lomembers;
struct pt_y *origo;
char *vcl_name;
struct bitmaps *bitmaps;
unsigned nmembers;
unsigned nentries;
VCL_BOOL case_sensitive;
......@@ -106,6 +121,14 @@ vmod_set__init(VRT_CTX, struct vmod_selector_set **setp, const char *vcl_name,
set->vcl_name = strdup(vcl_name);
AN(set->vcl_name);
set->case_sensitive = case_sensitive;
ALLOC_OBJ(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps);
for (int i = 0; i < __MAX_BITMAP; i++) {
set->bitmaps->bitmaps[i] = vbit_new(0);
AN(set->bitmaps->bitmaps[i]);
}
AZ(set->table);
AZ(set->members);
AZ(set->origo);
......@@ -133,12 +156,37 @@ vmod_set__fini(struct vmod_selector_set **setp)
VRE_free(&entry->re);
FREE_OBJ(entry);
}
for (int i = 0; i < __MAX_BITMAP; i++)
vbit_destroy(set->bitmaps->bitmaps[i]);
FREE_OBJ(set->bitmaps);
free(set->members);
free(set->table);
free(set->vcl_name);
FREE_OBJ(set);
}
static inline void
set_added(struct vmod_selector_set *set, unsigned idx, enum bitmap_e bitmap)
{
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
CHECK_OBJ_NOTNULL(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps->bitmaps[bitmap]);
vbit_set(set->bitmaps->bitmaps[bitmap], idx);
}
static inline int
is_added(const struct vmod_selector_set *set, unsigned idx,
enum bitmap_e bitmap)
{
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
CHECK_OBJ_NOTNULL(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps->bitmaps[bitmap]);
return (vbit_test(set->bitmaps->bitmaps[bitmap], idx));
}
VCL_VOID
vmod_set_add(VRT_CTX, struct vmod_selector_set *set, VCL_STRING member,
VCL_STRING string, VCL_STRING regex, VCL_BACKEND backend)
......@@ -214,12 +262,18 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set, VCL_STRING member,
AN(set->table);
ALLOC_OBJ(entry, VMOD_SELECTOR_ENTRY_MAGIC);
AN(entry);
if (string != NULL)
if (string != NULL) {
entry->string = strdup(string);
if (re != NULL)
set_added(set, n - 1, STRING);
}
if (re != NULL) {
entry->re = re;
if (backend != NULL)
set_added(set, n - 1, REGEX);
}
if (backend != NULL) {
entry->backend = backend;
set_added(set, n - 1, BACKEND);
}
set->table[n - 1] = entry;
}
......@@ -506,6 +560,41 @@ vmod_set_element(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
return (set->members[idx]);
}
static inline int
check_added(VRT_CTX, const struct vmod_selector_set * const restrict set,
unsigned idx, enum bitmap_e bitmap,
const char * const restrict method,
const char * const restrict type)
{
if (!is_added(set, idx, bitmap)) {
VERR(ctx, "%s.%s(): %s not added for element %u", set->vcl_name,
method, type, idx + 1);
return (0);
}
return (1);
}
VCL_BACKEND
vmod_set_backend(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
VCL_ENUM selects)
{
unsigned idx;
VCL_BACKEND b;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "backend", selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, BACKEND, "backend", "backend"))
return (NULL);
b = set->table[idx]->backend;
CHECK_OBJ_NOTNULL(b, DIRECTOR_MAGIC);
return (b);
}
VCL_STRING
vmod_set_debug(VRT_CTX, struct vmod_selector_set *set)
{
......
......@@ -111,6 +111,18 @@ $Method STRING .element(INT n=0,
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
$Method BACKEND .backend(INT n=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE)
Returns ...
Example::
if (myset.hasprefix(req.url)) {
......
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