Commit 883a6d61 authored by Geoff Simmons's avatar Geoff Simmons

VMOD uses quadbit tries and perfect hashes instead of patricia tries.

This adds the .compile() method to set objects, required for the
use of .match().

Docs for the .compile() method are currently incomplete.
parent c74275e2
......@@ -379,6 +379,13 @@ Example::
regex="^/quux/([^/]+)/");
}
.. _xset.compile():
VOID xset.compile()
-------------------
Compile the set, to prepare for the ``.match()`` operation.
.. _xset.create_stats():
VOID xset.create_stats()
......
......@@ -18,6 +18,7 @@ varnish v1 -vcl {
s.add("baz", backend=b3);
s.add("quux", backend=b4);
s.add("foobar", backend=b5);
s.compile();
}
sub vcl_recv {
......@@ -255,6 +256,7 @@ varnish v1 -vcl {
s.add("foo", backend=b);
s.add("bar");
s.add("bazz", backend=b0);
s.compile();
}
sub vcl_recv {
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
t.add("baz");
t.add("quux");
t.add("foobar");
t.compile();
}
sub vcl_recv {
......@@ -157,6 +158,7 @@ varnish v1 -vcl {
s.add("Millie");
s.add("mil's");
s.add("dethrones");
s.compile();
}
sub vcl_recv {
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
s.add("baz");
s.add("quux");
s.add("foobar");
s.compile();
}
sub vcl_recv {
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
s.add("baz", integer=2);
s.add("quux", integer=-1);
s.add("foobar", integer=-2);
s.compile();
}
sub vcl_recv {
......@@ -341,6 +342,7 @@ varnish v1 -vcl {
new s = selector.set();
s.add("foo", integer=0);
s.add("bar");
s.compile();
}
sub vcl_recv {
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
t.add("baz");
t.add("quux");
t.add("foobar");
t.compile();
}
sub vcl_recv {
......@@ -59,6 +60,7 @@ varnish v1 -vcl {
t.add("études");
t.add("étude's");
t.add("étude");
t.compile();
}
sub vcl_recv {
......@@ -192,6 +194,7 @@ varnish v1 -vcl {
s.add("electrode's");
s.add("disposition");
s.add("Rena's");
s.compile();
}
sub vcl_recv {
......@@ -850,6 +853,10 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * = End
} -run
logexpect l1 -v v1 -d 0 -g raw -q "vxid == 0 and VCL_Error" {
expect 0 0 VCL_Error {^VCL \S+ vmod selector n\.compile\(\): no entries were added, nothing to compile, n\.match\(\) will always fail}
} -start
varnish v1 -vcl {
import ${vmod_selector};
backend b { .host = "${bad_ip}"; }
......@@ -857,8 +864,13 @@ varnish v1 -vcl {
sub vcl_init {
new t = selector.set();
t.add("foo");
t.compile();
new n = selector.set();
n.compile();
new s = selector.set();
s.add("foo");
}
sub vcl_recv {
......@@ -868,14 +880,18 @@ varnish v1 -vcl {
sub vcl_synth {
set resp.http.Undef = t.match(req.http.No-Such-Header);
set resp.http.Nil = n.match("foo");
set resp.http.Not-Compiled = s.match("foo");
return (deliver);
}
}
logexpect l1 -wait
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector error: t\.match\(\): subject string is NULL$}
expect * = VCL_Error {^vmod selector error: n\.match\(\): no entries were added$}
expect * = VCL_Error {^vmod selector error: s\.match\(\): set was not compiled$}
expect * = End
} -start
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
s.add("baz", regex="zab");
s.add("quux", regex="xuuq");
s.add("foobar", regex="raboof");
s.compile();
}
sub vcl_recv {
......@@ -334,6 +335,7 @@ varnish v1 -vcl {
new s = selector.set();
s.add("foo", regex="foo");
s.add("bar");
s.compile();
}
sub vcl_recv {
......
......@@ -13,6 +13,7 @@ varnish v1 -vcl {
s.add("baz", string="zab");
s.add("quux", string="xuuq");
s.add("foobar", string="raboof");
s.compile();
}
sub vcl_recv {
......@@ -245,6 +246,7 @@ varnish v1 -vcl {
new s = selector.set();
s.add("foo", string="foo");
s.add("bar");
s.compile();
}
sub vcl_recv {
......
......@@ -50,7 +50,8 @@
#define ZERO_OBJ(to, sz) (void)memset(to, 0, sz)
#include "vcc_if.h"
#include "patricia.h"
#include "ph.h"
#include "qp.h"
#include "VSC_selector.h"
#define VFAIL(ctx, fmt, ...) \
......@@ -92,7 +93,8 @@ struct vmod_selector_set {
struct entry **table;
char **members;
char **lomembers;
struct pt_y *origo;
struct qp_y *origo;
struct ph *hash;
char *vcl_name;
struct bitmaps *bitmaps;
unsigned nmembers;
......@@ -130,10 +132,6 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
vsc_head = priv->priv;
switch(e) {
case VCL_EVENT_LOAD:
if (!PT_Inited())
PT_Init();
break;
case VCL_EVENT_DISCARD:
while (!VSLIST_EMPTY(vsc_head)) {
vsc_entry = VSLIST_FIRST(vsc_head);
......@@ -157,7 +155,7 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
}
break;
default:
WRONG("illegal event enum");
assert(e == VCL_EVENT_LOAD);
}
return 0;
}
......@@ -192,6 +190,7 @@ vmod_set__init(VRT_CTX, struct vmod_selector_set **setp, const char *vcl_name,
AZ(set->table);
AZ(set->members);
AZ(set->origo);
AZ(set->hash);
}
static inline void
......@@ -225,7 +224,8 @@ vmod_set__fini(struct vmod_selector_set **setp)
CHECK_OBJ(*setp, VMOD_SELECTOR_SET_MAGIC);
set = *setp;
*setp = NULL;
PT_Free(set->origo);
QP_Free(set->origo);
PH_Free(set->hash);
for (unsigned i = 0; i < set->nmembers; i++) {
free(set->members[i]);
for (int j = 0; j < __MAX_BITMAP; j++)
......@@ -298,7 +298,7 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set,
}
errno = 0;
if (PT_Insert(&set->origo, n - 1, members) != 0) {
if (QP_Insert(&set->origo, n - 1, members) != 0) {
if (errno == EINVAL)
VFAIL(ctx, "%s.add(): \"%s\" added more than once",
set->vcl_name, args->arg1);
......@@ -347,6 +347,44 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set,
set->table[n - 1] = entry;
}
VCL_VOID
vmod_set_compile(VRT_CTX, struct VPFX(selector_set) *set)
{
char **members;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if ((ctx->method & VCL_MET_INIT) == 0) {
VFAIL(ctx, "%s.compile() may only be called in vcl_init",
set->vcl_name);
return;
}
members = set->members;
if (!set->case_sensitive)
members = set->lomembers;
if (members == NULL || set->nmembers == 0) {
CHECK_OBJ_NOTNULL(ctx->msg, VSB_MAGIC);
VSL(SLT_VCL_Error, 0, "VCL %s vmod selector %s.compile(): "
"no entries were added, nothing to compile, "
"%s.match() will always fail\n", VCL_Name(ctx->vcl),
set->vcl_name, set->vcl_name);
return;
}
errno = 0;
if ((set->hash = PH_Generate(members, set->nmembers)) == NULL) {
if (errno == ERANGE)
VFAIL(ctx, "%s.compile(): perfect hash cannot be "
"generated for this set", set->vcl_name);
else
VFAIL(ctx, "%s.compile() failed: %s", set->vcl_name,
strerror(errno));
}
return;
}
static struct match_data *
get_match_data(VRT_CTX, struct vmod_selector_set *set, const char *method)
{
......@@ -388,8 +426,10 @@ vmod_set_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
VERR(ctx, "%s.match(): no entries were added", set->vcl_name);
return (0);
}
AN(set->origo);
if (set->hash == NULL) {
VERR(ctx, "%s.match(): set was not compiled", set->vcl_name);
return (0);
}
if (subject == NULL) {
VERR(ctx, "%s.match(): subject string is NULL", set->vcl_name);
return (0);
......@@ -413,7 +453,7 @@ vmod_set_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
AN(members);
match = get_match_data(ctx, set, "match");
if ((idx = PT_Lookup(set->origo, members, subj)) == UINT_MAX) {
if ((idx = PH_Lookup(set->hash, members, subj)) == UINT_MAX) {
match->n = 0;
return (0);
}
......@@ -478,7 +518,7 @@ vmod_set_hasprefix(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
}
match->indices = (unsigned *)WS_Reservation(ctx->ws);
if (PT_Prefixes(set->origo, members, subj, match) != 0) {
if (QP_Prefixes(set->origo, members, subj, match) != 0) {
VERRNOMEM(ctx, "Adding indices in %s.hasprefix(\"%.40s\")",
set->vcl_name, subject);
WS_Release(ctx->ws, 0);
......@@ -772,7 +812,7 @@ vmod_set_debug(VRT_CTX, struct vmod_selector_set *set)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
sb = PT_Dump(set->origo, set->members);
sb = QP_Dump(set->origo, set->members);
CHECK_OBJ_NOTNULL(sb, VSB_MAGIC);
output = WS_Copy(ctx->ws, VSB_data(sb), -1);
VSB_destroy(&sb);
......@@ -785,7 +825,7 @@ VCL_VOID
vmod_set_create_stats(VRT_CTX, struct vmod_selector_set *set,
struct vmod_priv *priv)
{
struct pt_stats stats = { .magic = PT_STATS_MAGIC };
struct qp_stats stats = { .magic = QP_STATS_MAGIC };
struct VSC_selector *vsc;
struct vsc_seg *vsc_seg;
struct vsc_head *vsc_head;
......@@ -810,7 +850,7 @@ vmod_set_create_stats(VRT_CTX, struct vmod_selector_set *set,
if (!set->case_sensitive)
members = set->lomembers;
AN(members);
PT_Stats(set->origo, members, &stats);
QP_Stats(set->origo, members, &stats);
assert(stats.terms == set->nmembers);
assert(stats.leaves <= stats.terms);
assert(stats.terms <= stats.nodes);
......
......@@ -360,6 +360,10 @@ Example::
regex="^/quux/([^/]+)/");
}
$Method VOID .compile()
Compile the set, to prepare for the ``.match()`` operation.
$Method VOID .create_stats(PRIV_VCL)
Creates statistics counters for this object that are displayed by
......
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