mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Redesign interrupt/cancel API for regex engine.
Previously, a PostgreSQL-specific callback checked by the regex engine had a way to trigger a special error code REG_CANCEL if it detected that the next call to CHECK_FOR_INTERRUPTS() would certainly throw via ereport(). A later proposed bugfix aims to move some complex logic out of signal handlers, so that it won't run until the next CHECK_FOR_INTERRUPTS(), which makes the above design impossible unless we split CHECK_FOR_INTERRUPTS() into two phases, one to run logic and another to ereport(). We may develop such a system in the future, but for the regex code it is no longer necessary. An earlier commit moved regex memory management over to our MemoryContext system. Given that the purpose of the two-phase interrupt checking was to free memory before throwing, something we don't need to worry about anymore, it seems simpler to inject CHECK_FOR_INTERRUPTS() directly into cancelation points, and just let it throw. Since the plan is to keep PostgreSQL-specific concerns separate from the main regex engine code (with a view to bein able to stay in sync with other projects), do this with a new macro INTERRUPT(), customizable in regcustom.h and defaulting to nothing. Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/CA%2BhUKGK3PGKwcKqzoosamn36YW-fsuTdOPPF1i_rtEO%3DnEYKSg%40mail.gmail.com
This commit is contained in:
@ -475,11 +475,7 @@ range(struct vars *v, /* context */
|
||||
}
|
||||
addchr(cv, cc);
|
||||
}
|
||||
if (CANCEL_REQUESTED(v->re))
|
||||
{
|
||||
ERR(REG_CANCEL);
|
||||
return NULL;
|
||||
}
|
||||
INTERRUPT(v->re);
|
||||
}
|
||||
|
||||
return cv;
|
||||
|
@ -143,11 +143,7 @@ newstate(struct nfa *nfa)
|
||||
* compilation, since no code path will go very long without making a new
|
||||
* state or arc.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return NULL;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
/* first, recycle anything that's on the freelist */
|
||||
if (nfa->freestates != NULL)
|
||||
@ -297,11 +293,7 @@ newarc(struct nfa *nfa,
|
||||
* compilation, since no code path will go very long without making a new
|
||||
* state or arc.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
/* check for duplicate arc, using whichever chain is shorter */
|
||||
if (from->nouts <= to->nins)
|
||||
@ -825,11 +817,7 @@ moveins(struct nfa *nfa,
|
||||
* Because we bypass newarc() in this code path, we'd better include a
|
||||
* cancel check.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
sortins(nfa, oldState);
|
||||
sortins(nfa, newState);
|
||||
@ -929,11 +917,7 @@ copyins(struct nfa *nfa,
|
||||
* Because we bypass newarc() in this code path, we'd better include a
|
||||
* cancel check.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
sortins(nfa, oldState);
|
||||
sortins(nfa, newState);
|
||||
@ -1000,11 +984,7 @@ mergeins(struct nfa *nfa,
|
||||
* Because we bypass newarc() in this code path, we'd better include a
|
||||
* cancel check.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
/* Sort existing inarcs as well as proposed new ones */
|
||||
sortins(nfa, s);
|
||||
@ -1125,11 +1105,7 @@ moveouts(struct nfa *nfa,
|
||||
* Because we bypass newarc() in this code path, we'd better include a
|
||||
* cancel check.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
sortouts(nfa, oldState);
|
||||
sortouts(nfa, newState);
|
||||
@ -1226,11 +1202,7 @@ copyouts(struct nfa *nfa,
|
||||
* Because we bypass newarc() in this code path, we'd better include a
|
||||
* cancel check.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
sortouts(nfa, oldState);
|
||||
sortouts(nfa, newState);
|
||||
@ -3282,11 +3254,7 @@ checkmatchall_recurse(struct nfa *nfa, struct state *s, bool **haspaths)
|
||||
return false;
|
||||
|
||||
/* In case the search takes a long time, check for cancel */
|
||||
if (CANCEL_REQUESTED(nfa->v->re))
|
||||
{
|
||||
NERR(REG_CANCEL);
|
||||
return false;
|
||||
}
|
||||
INTERRUPT(nfa->v->re);
|
||||
|
||||
/* Create a haspath array for this state */
|
||||
haspath = (bool *) MALLOC((DUPINF + 2) * sizeof(bool));
|
||||
|
@ -86,7 +86,6 @@ static int newlacon(struct vars *v, struct state *begin, struct state *end,
|
||||
int latype);
|
||||
static void freelacons(struct subre *subs, int n);
|
||||
static void rfree(regex_t *re);
|
||||
static int rcancelrequested(void);
|
||||
static int rstacktoodeep(void);
|
||||
|
||||
#ifdef REG_DEBUG
|
||||
@ -356,7 +355,6 @@ struct vars
|
||||
/* static function list */
|
||||
static const struct fns functions = {
|
||||
rfree, /* regfree insides */
|
||||
rcancelrequested, /* check for cancel request */
|
||||
rstacktoodeep /* check for stack getting dangerously deep */
|
||||
};
|
||||
|
||||
@ -2468,22 +2466,6 @@ rfree(regex_t *re)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rcancelrequested - check for external request to cancel regex operation
|
||||
*
|
||||
* Return nonzero to fail the operation with error code REG_CANCEL,
|
||||
* zero to keep going
|
||||
*
|
||||
* The current implementation is Postgres-specific. If we ever get around
|
||||
* to splitting the regex code out as a standalone library, there will need
|
||||
* to be some API to let applications define a callback function for this.
|
||||
*/
|
||||
static int
|
||||
rcancelrequested(void)
|
||||
{
|
||||
return InterruptPending && (QueryCancelPending || ProcDiePending);
|
||||
}
|
||||
|
||||
/*
|
||||
* rstacktoodeep - check for stack getting dangerously deep
|
||||
*
|
||||
|
@ -805,11 +805,7 @@ miss(struct vars *v,
|
||||
* Checking for operation cancel in the inner text search loop seems
|
||||
* unduly expensive. As a compromise, check during cache misses.
|
||||
*/
|
||||
if (CANCEL_REQUESTED(v->re))
|
||||
{
|
||||
ERR(REG_CANCEL);
|
||||
return NULL;
|
||||
}
|
||||
INTERRUPT(v->re);
|
||||
|
||||
/*
|
||||
* What set of states would we end up in after consuming the co character?
|
||||
|
@ -764,8 +764,7 @@ cdissect(struct vars *v,
|
||||
MDEBUG(("%d: cdissect %c %ld-%ld\n", t->id, t->op, LOFF(begin), LOFF(end)));
|
||||
|
||||
/* handy place to check for operation cancel */
|
||||
if (CANCEL_REQUESTED(v->re))
|
||||
return REG_CANCEL;
|
||||
INTERRUPT(v->re);
|
||||
/* ... and stack overrun */
|
||||
if (STACK_TOO_DEEP(v->re))
|
||||
return REG_ETOOBIG;
|
||||
|
Reference in New Issue
Block a user