Commit c3f66757 authored by Geoff Simmons's avatar Geoff Simmons

Set compilation is now done by vcl_init PRIV_TASK fini.

.compile() is still legal, but unnecessary and will be deprecated.
parent 3fc87c74
......@@ -81,6 +81,15 @@ struct task_set_match {
size_t nmatches;
};
struct task_set_init {
unsigned magic;
#define SET_INIT_TASK_MAGIC 0xe24e2945
VSLIST_ENTRY(task_set_init) list;
struct vmod_re2_set *set;
};
VSLIST_HEAD(set_init_head, task_set_init);
typedef
VCL_STRING regex_rewrite_f(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
VCL_STRING text, VCL_STRING rewrite,
......@@ -105,23 +114,78 @@ decimal_digits(int n)
return digits;
}
static int
compile(VRT_CTX, struct vmod_re2_set *set, const char *method)
{
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
AZ(set->compiled);
if (set->npatterns == 0) {
VFAIL(ctx, "%s%s: no patterns were added", set->vcl_name,
method);
return (-1);
}
if ((err = vre2set_compile(set->set)) != NULL) {
VFAIL(ctx, "%s%s: possibly insufficient memory", set->vcl_name,
method);
return (-1);
}
set->compiled = 1;
return (0);
}
static void
set_complete_init(VRT_CTX, void *priv_task)
{
struct set_init_head *head;
struct task_set_init *task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(priv_task);
head = priv_task;
AZ(VSLIST_EMPTY(head));
VSLIST_FOREACH(task, head, list) {
CHECK_OBJ_NOTNULL(task, SET_INIT_TASK_MAGIC);
CHECK_OBJ_NOTNULL(task->set, VMOD_RE2_SET_MAGIC);
if (!task->set->compiled)
if (compile(ctx, task->set, " set initialization") != 0)
return;
}
}
static const struct vmod_priv_methods set_init[1] = {{
.magic = VMOD_PRIV_METHODS_MAGIC,
.type = "vmod_re2_set_init",
.fini = set_complete_init,
}};
/* Object set */
VCL_VOID
vmod_set__init(VRT_CTX, struct vmod_re2_set **setp, const char *vcl_name,
VCL_ENUM anchor_a, VCL_BOOL utf8, VCL_BOOL posix_syntax,
VCL_BOOL longest_match, VCL_INT max_mem, VCL_BOOL literal,
VCL_BOOL never_nl, VCL_BOOL dot_nl, VCL_BOOL case_sensitive,
VCL_BOOL perl_classes, VCL_BOOL word_boundary, VCL_BOOL one_line)
struct vmod_priv *priv_task, VCL_ENUM anchor_a, VCL_BOOL utf8,
VCL_BOOL posix_syntax, VCL_BOOL longest_match, VCL_INT max_mem,
VCL_BOOL literal, VCL_BOOL never_nl, VCL_BOOL dot_nl,
VCL_BOOL case_sensitive, VCL_BOOL perl_classes,
VCL_BOOL word_boundary, VCL_BOOL one_line)
{
struct vmod_re2_set *set;
struct set_init_head *head;
struct task_set_init *task;
anchor_e anchor;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
AN(setp);
AZ(*setp);
AN(vcl_name);
AN(priv_task);
ALLOC_OBJ(set, VMOD_RE2_SET_MAGIC);
AN(set);
*setp = set;
......@@ -144,6 +208,30 @@ vmod_set__init(VRT_CTX, struct vmod_re2_set **setp, const char *vcl_name,
return;
}
if (priv_task->priv == NULL) {
if ((head = WS_Alloc(ctx->ws, sizeof(*head))) == NULL) {
VERRNOMEM(ctx, "insufficient workspace for task head "
"initializing %s", vcl_name);
return;
}
VSLIST_INIT(head);
priv_task->priv = head;
priv_task->len = sizeof(*task);
priv_task->methods = set_init;
}
else {
AN(priv_task->methods);
head = priv_task->priv;
}
if ((task = WS_Alloc(ctx->ws, sizeof(*task))) == NULL) {
VERRNOMEM(ctx, "insufficient workspace to initialize %s",
vcl_name);
return;
}
task->magic = SET_INIT_TASK_MAGIC;
task->set = set;
VSLIST_INSERT_HEAD(head, task, list);
for (unsigned i = 0; i < NELEMS(set->added); i++) {
set->added[i] = vbit_new(0);
AN(set->added[i]);
......@@ -303,40 +391,24 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, struct VARGS(set_add) *args)
#undef ERR_PREFIX
#define ERR_PREFIX "%s.compile(): "
VCL_VOID
vmod_set_compile(VRT_CTX, struct vmod_re2_set *set)
{
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (!INIT(ctx)) {
VFAIL(ctx, ERR_PREFIX ".compile() may only be called in "
VFAIL(ctx, "%s.compile(): .compile() may only be called in "
"vcl_init", set->vcl_name);
return;
}
if (set->npatterns == 0) {
VFAIL(ctx, ERR_PREFIX "no patterns were added", set->vcl_name);
return;
}
if (set->compiled) {
VFAIL(ctx, ERR_PREFIX "%s has already been compiled",
VFAIL(ctx, "%s.compile(): %s has already been compiled",
set->vcl_name, set->vcl_name);
return;
}
if ((err = vre2set_compile(set->set)) != NULL) {
VFAIL(ctx, ERR_PREFIX "failed, possibly insufficient memory",
set->vcl_name);
return;
}
set->compiled = 1;
compile(ctx, set, ".compile()");
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.match(\"%.40s\"): "
VCL_BOOL
......
......@@ -107,7 +107,7 @@ client c1 {
expect resp.http.rep == "match"
} -run
varnish v1 -errvcl {vmod re2 failure: rep.compile(): failed, possibly insufficient memory} {
varnish v1 -errvcl {vmod re2 failure: rep.compile(): possibly insufficient memory} {
import ${vmod_re2};
backend b None;
......
......@@ -33,6 +33,7 @@ server s1 {
txresp
} -start
# .compile() is no longer required.
varnish v1 -vcl+backend {
import ${vmod_re2};
......@@ -51,16 +52,8 @@ varnish v1 -vcl+backend {
client c1 {
txreq
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.foo == <undef>
expect_close
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod re2 failure: s\.match\("foo"\): s was not compiled$}
expect * = End
expect resp.status == 200
expect resp.http.foo == "match"
} -run
# Safe to call .match() in vcl_init
......@@ -102,16 +95,17 @@ varnish v1 -vcl+backend {
sub vcl_init {
new s = re2.set();
s.add("foo");
}
sub vcl_deliver {
s.add("foo");
s.add("bar");
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod re2 failure: s\.add\("foo"\): \.add\(\) may only be called in vcl_init$}
expect * = VCL_Error {^vmod re2 failure: s\.add\("bar"\): \.add\(\) may only be called in vcl_init$}
expect 0 = VCL_return fail
expect * = End
} -start
......@@ -131,6 +125,7 @@ varnish v1 -vcl+backend {
sub vcl_init {
new s = re2.set();
s.add("foo");
}
sub vcl_deliver {
......@@ -155,33 +150,11 @@ client c1 {
logexpect l1 -wait
varnish v1 -vcl+backend {
varnish v1 -errvcl {s set initialization: no patterns were added} {
import ${vmod_re2};
backend b None;
sub vcl_init {
new s = re2.set();
}
sub vcl_deliver {
if (s.match("foo")) {
set resp.http.foo = "match";
}
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod re2 failure: s\.match\("foo"\): s was not compiled$}
expect 0 = VCL_return fail
expect * = End
} -start
client c1 {
txreq
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
logexpect l1 -wait
......@@ -723,9 +723,9 @@ Example::
std.log("simple cost=" + re2.cost("simple")
+ " complex cost=" + re2.cost("complex{1,128}"));
$Object set(ENUM { none, start, both } anchor="none", BOOL utf8=0,
BOOL posix_syntax=0, BOOL longest_match=0, INT max_mem=8388608,
BOOL literal=0, BOOL never_nl=0, BOOL dot_nl=0,
$Object set(PRIV_TASK, ENUM { none, start, both } anchor="none",
BOOL utf8=0, BOOL posix_syntax=0, BOOL longest_match=0,
INT max_mem=8388608, BOOL literal=0, BOOL never_nl=0, BOOL dot_nl=0,
BOOL case_sensitive=1, BOOL perl_classes=0, BOOL word_boundary=0,
BOOL one_line=0)
......
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