Commit 79668197 authored by Geoff Simmons's avatar Geoff Simmons

Add the allow_overlaps flag.

parent 11ac404d
......@@ -321,8 +321,15 @@ or the longest match, and so on::
.. _selector.set():
new xset = selector.set(BOOL case_sensitive=1)
----------------------------------------------
new xset = selector.set(BOOL case_sensitive, BOOL allow_overlaps)
-----------------------------------------------------------------
::
new xset = selector.set(
BOOL case_sensitive=1,
BOOL allow_overlaps=1
)
Create a set object. When ``case_sensitive`` is ``false``, matches
using the ``.match()`` and ``.hasprefix()`` methods are
......
......@@ -159,7 +159,8 @@ getidx(const struct qp_y * const restrict y, uint16_t bitmap)
int
QP_Insert(struct qp_y * * restrict root, unsigned idx,
char * const restrict * const restrict strings)
char * const restrict * const restrict strings,
unsigned allow_overlaps)
{
struct qp_y *y;
unsigned char *c, *b;
......@@ -205,6 +206,16 @@ QP_Insert(struct qp_y * * restrict root, unsigned idx,
return (-1);
}
if (!allow_overlaps && i == y->len && y->term) {
/*
* The current node is terminating and has a
* prefix in common with the current string,
* reject if overlaps are not permitted.
*/
errno = EPERM;
return (-1);
}
if (i == y->len && y->branch != NULL) {
/*
* The string to be inserted has a prefix that is
......
......@@ -61,7 +61,8 @@ struct qp_stats {
};
int QP_Insert(struct qp_y * * restrict root, unsigned idx,
char * const restrict * const restrict strings);
char * const restrict * const restrict strings,
unsigned allow_overlaps);
unsigned QP_Lookup(const struct qp_y * const restrict root,
char * const restrict * const restrict strings,
const char * const restrict subject);
......
......@@ -98,7 +98,7 @@ void
usage(const char *argv, int status)
{
fprintf(stderr,
"Usage: %s [-hs] [-c csvfile] [-d dumpfile] [-i inputfile]\n"
"Usage: %s [-hos] [-c csvfile] [-d dumpfile] [-i inputfile]\n"
" [-m m|p] [-n iterations] [file]\n", argv);
exit(status);
}
......@@ -121,10 +121,11 @@ main(int argc, char *argv[])
struct timespec before, after, start, finish;
uint64_t ns = 0, iters, matches, exacts, misses;
struct qp_stats stats = { .magic = QP_STATS_MAGIC };
int opt, do_shuf = 0, do_iters = ITERATIONS, do_match = 1, do_prefix = 1;
int opt, do_shuf = 0, do_iters = ITERATIONS, do_match = 1
, do_prefix = 1, allow_overlaps = 1;
struct rusage rusage;
while ((opt = getopt(argc, argv, "hsc:d:i:m:n:")) != -1) {
while ((opt = getopt(argc, argv, "hosc:d:i:m:n:")) != -1) {
switch (opt) {
case 'c':
csvf = optarg;
......@@ -152,6 +153,9 @@ main(int argc, char *argv[])
case 's':
do_shuf = 1;
break;
case 'o':
allow_overlaps = 0;
break;
default:
usage(argv[0], EXIT_FAILURE);
}
......@@ -272,7 +276,7 @@ main(int argc, char *argv[])
errno = 0;
(void)clock_gettime(CLOCK, &before);
ret = QP_Insert(&origo, i, strings);
ret = QP_Insert(&origo, i, strings, allow_overlaps);
(void)clock_gettime(CLOCK, &after);
if (ret != 0) {
......
# looks like -*- vcl -*-
varnishtest "allow_overlaps flag"
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foo");
s.add("bar");
s.add("baz");
s.add("quux");
s.compile();
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
set resp.http.Match = s.hasprefix(req.http.Word);
set resp.http.N = s.nmatches();
set resp.http.Which = s.which();
set resp.http.Which-Unique = s.which(select=UNIQUE);
return (deliver);
}
} -start
client c1 {
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 200
expect resp.http.Match == "true"
expect resp.http.N == "1"
expect resp.http.Which == "1"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: barbaz"
rxresp
expect resp.status == 200
expect resp.http.Match == "true"
expect resp.http.N == "1"
expect resp.http.Which == "2"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: bazquux"
rxresp
expect resp.status == 200
expect resp.http.Match == "true"
expect resp.http.N == "1"
expect resp.http.Which == "3"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: quuxxyzzy"
rxresp
expect resp.status == 200
expect resp.http.Match == "true"
expect resp.http.N == "1"
expect resp.http.Which == "4"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: oof"
rxresp
expect resp.status == 200
expect resp.http.Match == "false"
expect resp.http.N == "0"
expect resp.http.Which == "0"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: rab"
rxresp
expect resp.status == 200
expect resp.http.Match == "false"
expect resp.http.N == "0"
expect resp.http.Which == "0"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: zab"
rxresp
expect resp.status == 200
expect resp.http.Match == "false"
expect resp.http.N == "0"
expect resp.http.Which == "0"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: xuuq"
rxresp
expect resp.status == 200
expect resp.http.Match == "false"
expect resp.http.N == "0"
expect resp.http.Which == "0"
expect resp.http.Which-Unique == resp.http.Which
txreq -hdr "Word: raboof"
rxresp
expect resp.status == 200
expect resp.http.Match == "false"
expect resp.http.N == "0"
expect resp.http.Which == "0"
expect resp.http.Which-Unique == resp.http.Which
} -run
varnish v1 -errvcl {vmod selector failure: s.compile(): allow_overlaps is false but strings with common prefixes were added} {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set(allow_overlaps=false);
s.add("foobar");
s.add("foo");
s.compile();
}
}
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set(allow_overlaps=false);
s.add("foofighters");
s.add("foodfight");
s.add("foobar");
s.compile();
}
}
......@@ -82,6 +82,7 @@ struct bitmaps {
struct vmod_selector_set {
unsigned magic;
#define VMOD_SELECTOR_SET_MAGIC 0x838979ef
unsigned nmembers;
struct entry **table;
char **members;
char **lomembers;
......@@ -89,8 +90,8 @@ struct vmod_selector_set {
struct ph *hash;
char *vcl_name;
struct bitmaps *bitmaps;
unsigned nmembers;
VCL_BOOL case_sensitive;
unsigned int case_sensitive:1;
unsigned int allow_overlaps:1;
};
struct vsc_entry {
......@@ -161,7 +162,7 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
VCL_VOID
vmod_set__init(VRT_CTX, struct vmod_selector_set **setp, const char *vcl_name,
VCL_BOOL case_sensitive)
VCL_BOOL case_sensitive, VCL_BOOL allow_overlaps)
{
struct vmod_selector_set *set;
......@@ -175,7 +176,8 @@ vmod_set__init(VRT_CTX, struct vmod_selector_set **setp, const char *vcl_name,
*setp = set;
set->vcl_name = strdup(vcl_name);
AN(set->vcl_name);
set->case_sensitive = case_sensitive;
set->case_sensitive = (case_sensitive != 0);
set->allow_overlaps = (allow_overlaps != 0);
ALLOC_OBJ(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps);
......@@ -381,10 +383,15 @@ vmod_set_compile(VRT_CTX, struct VPFX(selector_set) *set)
qsort(idx, set->nmembers, sizeof(*idx), cmp);
for (unsigned i = 0; i < set->nmembers; i++) {
errno = 0;
if (QP_Insert(&set->origo, idx[i].n, members) != 0) {
if (QP_Insert(&set->origo, idx[i].n, members,
set->allow_overlaps) != 0) {
if (errno == EINVAL)
VFAIL(ctx, "%s.compile(): \"%s\" added more "
"than once", set->vcl_name, members[i]);
else if (errno == EPERM)
VFAIL(ctx, "%s.compile(): allow_overlaps is "
"false but strings with common prefixes "
"were added", set->vcl_name);
else
VFAIL(ctx, "%s.compile(\"%s\") failed: %s",
set->vcl_name, members[i],
......
......@@ -315,7 +315,7 @@ or the longest match, and so on::
# bar_backend for /foo/bar/quux
# foo_backend for /foo/quux
$Object set(BOOL case_sensitive=1)
$Object set(BOOL case_sensitive=1, BOOL allow_overlaps=1)
Create a set object. When ``case_sensitive`` is ``false``, matches
using the ``.match()`` and ``.hasprefix()`` methods are
......
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