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