MAJOR: server: use states instead of flags to store the server state

Servers used to have 3 flags to store a state, now they have 4 states
instead. This avoids lots of confusion for the 4 remaining undefined
states.

The encoding from the previous to the new states can be represented
this way :

  SRV_STF_RUNNING
   |  SRV_STF_GOINGDOWN
   |   |  SRV_STF_WARMINGUP
   |   |   |
   0   x   x     SRV_ST_STOPPED
   1   0   0     SRV_ST_RUNNING
   1   0   1     SRV_ST_STARTING
   1   1   x     SRV_ST_STOPPING

Note that the case where all bits were set used to exist and was randomly
dealt with. For example, the task was not stopped, the throttle value was
still updated and reported in the stats and in the http_server_state header.
It was the same if the server was stopped by the agent or for maintenance.

It's worth noting that the internal function names are still quite confusing.
This commit is contained in:
Willy Tarreau 2014-05-13 23:41:20 +02:00
parent 2012521d7b
commit 892337c8e1
12 changed files with 84 additions and 69 deletions

View File

@ -63,11 +63,15 @@ static inline int srv_is_usable(const struct server *srv)
return 0;
if (srv->admin & SRV_ADMF_MAINT)
return 0;
if (state & SRV_STF_GOINGDOWN)
switch (state) {
case SRV_ST_STARTING:
case SRV_ST_RUNNING:
return 1;
case SRV_ST_STOPPING:
case SRV_ST_STOPPED:
return 0;
if (!(state & SRV_STF_RUNNING))
return 0;
return 1;
}
return 0;
}
/* This function returns non-zero if the designated server was usable for LB
@ -81,11 +85,15 @@ static inline int srv_was_usable(const struct server *srv)
return 0;
if (srv->prev_admin & SRV_ADMF_MAINT)
return 0;
if (state & SRV_STF_GOINGDOWN)
switch (state) {
case SRV_ST_STARTING:
case SRV_ST_RUNNING:
return 1;
case SRV_ST_STOPPING:
case SRV_ST_STOPPED:
return 0;
if (!(state & SRV_STF_RUNNING))
return 0;
return 1;
}
return 0;
}
/* This function commits the current server state and weight onto the previous

View File

@ -43,11 +43,12 @@
#include <types/checks.h>
/* server states, still used as cumulative flags */
/* server states. Only SRV_ST_DOWN indicates a down server. */
enum srv_state {
SRV_STF_RUNNING = 0x1, /* the server is UP */
SRV_STF_GOINGDOWN = 0x2, /* the server is going down (eg: 404) */
SRV_STF_WARMINGUP = 0x4, /* the server is warming up after a failure */
SRV_ST_STOPPED = 0, /* the server is down. Please keep set to zero. */
SRV_ST_STARTING, /* the server is warming up (up but throttled) */
SRV_ST_RUNNING, /* the server is fully up */
SRV_ST_STOPPING, /* the server is up but soft-stopping (eg: 404) */
};
/* Maintenance mode : each server may be in maintenance by itself or may inherit
@ -113,7 +114,7 @@ struct tree_occ {
struct server {
enum obj_type obj_type; /* object type == OBJ_TYPE_SERVER */
enum srv_state state, prev_state; /* server state among SRV_STF_* */
enum srv_state state, prev_state; /* server state among SRV_ST_* */
enum srv_admin admin, prev_admin; /* server maintenance status : SRV_ADMF_* */
unsigned char flags; /* server flags (SRV_F_*) */
struct server *next;

View File

@ -1242,7 +1242,7 @@ int tcp_persist_rdp_cookie(struct session *s, struct channel *req, int an_bit)
while (srv) {
if (srv->addr.ss_family == AF_INET &&
memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
if ((srv->state & SRV_STF_RUNNING) || (px->options & PR_O_PERSIST)) {
if ((srv->state != SRV_ST_STOPPED) || (px->options & PR_O_PERSIST)) {
/* we found the server and it is usable */
s->flags |= SN_DIRECT | SN_ASSIGNED;
s->target = &srv->obj_type;
@ -1490,7 +1490,7 @@ smp_fetch_srv_is_up(struct proxy *px, struct session *l4, void *l7, unsigned int
smp->flags = SMP_F_VOL_TEST;
smp->type = SMP_T_BOOL;
if (!(srv->admin & SRV_ADMF_MAINT) &&
(!(srv->check.state & CHK_ST_CONFIGURED) || (srv->state & SRV_STF_RUNNING)))
(!(srv->check.state & CHK_ST_CONFIGURED) || (srv->state != SRV_ST_STOPPED)))
smp->data.uint = 1;
else
smp->data.uint = 0;
@ -1512,7 +1512,7 @@ smp_fetch_connslots(struct proxy *px, struct session *l4, void *l7, unsigned int
smp->data.uint = 0;
for (iterator = args->data.prx->srv; iterator; iterator = iterator->next) {
if ((iterator->state & SRV_STF_RUNNING) == 0)
if (iterator->state == SRV_ST_STOPPED)
continue;
if (iterator->maxconn == 0 || iterator->maxqueue == 0) {

View File

@ -6618,7 +6618,7 @@ int check_config_validity()
/* if the other server is forced disabled, we have to do the same here */
if (srv->admin & SRV_ADMF_MAINT) {
newsrv->state &= ~SRV_STF_RUNNING;
newsrv->state = SRV_ST_STOPPED;
newsrv->check.health = 0;
newsrv->agent.health = 0;
}

View File

@ -182,7 +182,7 @@ static void server_status_printf(struct chunk *msg, struct server *s, struct che
}
if (xferred >= 0) {
if (!(s->state & SRV_STF_RUNNING))
if (s->state == SRV_ST_STOPPED)
chunk_appendf(msg, ". %d active and %d backup servers left.%s"
" %d sessions active, %d requeued, %d remaining in queue",
s->proxy->srv_act, s->proxy->srv_bck,
@ -264,7 +264,7 @@ static void set_server_check_status(struct check *check, short status, const cha
health--; /* still good */
} else {
if (health == rise)
state &= ~(SRV_STF_RUNNING | SRV_STF_GOINGDOWN);
state = SRV_ST_STOPPED;
health = 0;
}
@ -276,7 +276,7 @@ static void set_server_check_status(struct check *check, short status, const cha
health++; /* was bad, stays for a while */
if (health == rise)
state |= SRV_STF_RUNNING;
state = SRV_ST_RUNNING;
if (health >= rise)
health = rise + fall - 1; /* OK now */
@ -300,9 +300,9 @@ static void set_server_check_status(struct check *check, short status, const cha
server_status_printf(&trash, s, check, -1);
chunk_appendf(&trash, ", status: %d/%d %s",
(state & SRV_STF_RUNNING) ? (health - rise + 1) : (health),
(state & SRV_STF_RUNNING) ? (fall) : (rise),
(state & SRV_STF_RUNNING) ? (s->uweight?"UP":"DRAIN"):"DOWN");
(state != SRV_ST_STOPPED) ? (health - rise + 1) : (health),
(state != SRV_ST_STOPPED) ? (fall) : (rise),
(state != SRV_ST_STOPPED) ? (s->uweight?"UP":"DRAIN"):"DOWN");
Warning("%s.\n", trash.str);
send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
@ -416,12 +416,12 @@ void set_server_down(struct check *check)
check->health = check->rise;
}
if ((s->state & SRV_STF_RUNNING && check->health == check->rise) || s->track) {
int srv_was_paused = s->state & SRV_STF_GOINGDOWN;
if ((s->state != SRV_ST_STOPPED && check->health == check->rise) || s->track) {
int srv_was_stopping = (s->state == SRV_ST_STOPPING);
int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
s->last_change = now.tv_sec;
s->state &= ~(SRV_STF_RUNNING | SRV_STF_GOINGDOWN);
s->state = SRV_ST_STOPPED;
if (s->proxy->lbprm.set_server_status_down)
s->proxy->lbprm.set_server_status_down(s);
@ -452,7 +452,7 @@ void set_server_down(struct check *check)
Warning("%s.\n", trash.str);
/* we don't send an alert if the server was previously paused */
if (srv_was_paused)
if (srv_was_stopping)
send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
else
send_log(s->proxy, LOG_ALERT, "%s.\n", trash.str);
@ -498,14 +498,14 @@ void set_server_up(struct check *check) {
s->down_time += now.tv_sec - s->last_change;
s->last_change = now.tv_sec;
s->state |= SRV_STF_RUNNING;
s->admin &= ~SRV_ADMF_FMAINT;
s->check.state &= ~CHK_ST_PAUSED;
if (s->slowstart > 0) {
s->state |= SRV_STF_WARMINGUP;
s->state = SRV_ST_STARTING;
if (s->slowstart > 0)
task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
}
else
s->state = SRV_ST_RUNNING;
server_recalc_eweight(s);
@ -559,7 +559,7 @@ static void set_server_disabled(struct check *check) {
struct server *srv;
int xferred;
s->state |= SRV_STF_GOINGDOWN;
s->state = SRV_ST_STOPPING;
if (s->proxy->lbprm.set_server_status_down)
s->proxy->lbprm.set_server_status_down(s);
@ -596,7 +596,11 @@ static void set_server_enabled(struct check *check) {
struct server *srv;
int xferred;
s->state &= ~SRV_STF_GOINGDOWN;
if (s->slowstart)
s->state = SRV_ST_STARTING;
else
s->state = SRV_ST_RUNNING;
if (s->proxy->lbprm.set_server_status_up)
s->proxy->lbprm.set_server_status_up(s);
@ -745,13 +749,13 @@ static int httpchk_build_status_header(struct server *s, char *buffer, int size)
if (!(s->check.state & CHK_ST_ENABLED))
sv_state = 6;
else if (s->state & SRV_STF_RUNNING) {
else if (s->state != SRV_ST_STOPPED) {
if (s->check.health == s->check.rise + s->check.fall - 1)
sv_state = 3; /* UP */
else
sv_state = 2; /* going down */
if (s->state & SRV_STF_GOINGDOWN)
if (s->state == SRV_ST_STOPPING)
sv_state += 2;
} else {
if (s->check.health)
@ -762,8 +766,8 @@ static int httpchk_build_status_header(struct server *s, char *buffer, int size)
hlen += snprintf(buffer + hlen, size - hlen,
srv_hlt_st[sv_state],
(s->state & SRV_STF_RUNNING) ? (s->check.health - s->check.rise + 1) : (s->check.health),
(s->state & SRV_STF_RUNNING) ? (s->check.fall) : (s->check.rise));
(s->state != SRV_ST_STOPPED) ? (s->check.health - s->check.rise + 1) : (s->check.health),
(s->state != SRV_ST_STOPPED) ? (s->check.fall) : (s->check.rise));
hlen += snprintf(buffer + hlen, size - hlen, "; name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
s->proxy->id, s->id,
@ -773,7 +777,7 @@ static int httpchk_build_status_header(struct server *s, char *buffer, int size)
s->cur_sess, s->proxy->beconn - s->proxy->nbpend,
s->nbpend);
if ((s->state & SRV_STF_WARMINGUP) &&
if ((s->state == SRV_ST_STARTING) &&
now.tv_sec < s->last_change + s->slowstart &&
now.tv_sec >= s->last_change) {
ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart);
@ -1084,7 +1088,7 @@ static void event_srv_chk_r(struct connection *conn)
desc = ltrim(check->bi->data + 12, ' ');
if ((s->proxy->options & PR_O_DISABLE404) &&
(s->state & SRV_STF_RUNNING) && (check->code == 404)) {
(s->state != SRV_ST_STOPPED) && (check->code == 404)) {
/* 404 may be accepted as "stopping" only if the server was up */
cut_crlf(desc);
set_server_check_status(check, HCHK_STATUS_L7OKCD, desc);
@ -1481,9 +1485,10 @@ static struct task *server_warmup(struct task *t)
/* by default, plan on stopping the task */
t->expire = TICK_ETERNITY;
if ((s->admin & SRV_ADMF_MAINT) ||
(s->state & (SRV_STF_RUNNING|SRV_STF_WARMINGUP)) != (SRV_STF_RUNNING|SRV_STF_WARMINGUP))
(s->state != SRV_ST_STARTING))
return t;
/* recalculate the weights and update the state */
server_recalc_eweight(s);
/* probably that we can refill this server with a bit more connections */
@ -1492,7 +1497,7 @@ static struct task *server_warmup(struct task *t)
/* get back there in 1 second or 1/20th of the slowstart interval,
* whichever is greater, resulting in small 5% steps.
*/
if (s->state & SRV_STF_WARMINGUP)
if (s->state == SRV_ST_STARTING)
t->expire = tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20)));
return t;
}
@ -1701,10 +1706,10 @@ static struct task *process_chk(struct task *t)
check_failed(check);
else { /* check was OK */
/* we may have to add/remove this server from the LB group */
if ((s->state & SRV_STF_RUNNING) && (s->proxy->options & PR_O_DISABLE404)) {
if ((s->state & SRV_STF_GOINGDOWN) && (check->result != CHK_RES_CONDPASS))
if ((s->state != SRV_ST_STOPPED) && (s->proxy->options & PR_O_DISABLE404)) {
if ((s->state == SRV_ST_STOPPING) && (check->result != CHK_RES_CONDPASS))
set_server_enabled(check);
else if (!(s->state & SRV_STF_GOINGDOWN) && (check->result == CHK_RES_CONDPASS))
else if ((s->state != SRV_ST_STOPPING) && (check->result == CHK_RES_CONDPASS))
set_server_disabled(check);
}

View File

@ -1716,7 +1716,7 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
/* If this server tracks the status of another one,
* we must restore the good status.
*/
if (sv->track->state & SRV_STF_RUNNING) {
if (sv->track->state != SRV_ST_STOPPED) {
set_server_up(&sv->check);
sv->check.health = sv->check.rise; /* up, but will fall down at first failure */
} else {
@ -2923,8 +2923,8 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1));
chunk_appendf(&trash,
srv_hlt_st[state],
(ref->state & SRV_STF_RUNNING) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
(ref->state & SRV_STF_RUNNING) ? (ref->check.fall) : (ref->check.rise));
(ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
(ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
}
if (sv->check.state & CHK_ST_ENABLED) {
@ -2987,7 +2987,7 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
chunk_appendf(&trash, "<td colspan=3></td>");
/* throttle */
if ((sv->state & SRV_STF_WARMINGUP) && !server_is_draining(sv))
if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
chunk_appendf(&trash, "<td class=ac>%d %%</td></tr>\n", server_throttle_rate(sv));
else
chunk_appendf(&trash, "<td class=ac>-</td></tr>\n");
@ -3037,8 +3037,8 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
else
chunk_appendf(&trash,
srv_hlt_st[state],
(ref->state & SRV_STF_RUNNING) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
(ref->state & SRV_STF_RUNNING) ? (ref->check.fall) : (ref->check.rise));
(ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
(ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
chunk_appendf(&trash,
/* weight, active, backup */
@ -3065,7 +3065,7 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
relative_pid, px->uuid, sv->puid);
/* throttle */
if ((sv->state & SRV_STF_WARMINGUP) && !server_is_draining(sv))
if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
chunk_appendf(&trash, "%d", server_throttle_rate(sv));
/* sessions: lbtot */
@ -3621,7 +3621,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy
/* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
if (!(svs->check.state & CHK_ST_ENABLED))
sv_state = 8;
else if (svs->state & SRV_STF_RUNNING) {
else if (svs->state != SRV_ST_STOPPED) {
if (svs->check.health == svs->check.rise + svs->check.fall - 1)
sv_state = 3; /* UP */
else
@ -3629,7 +3629,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy
if (server_is_draining(sv))
sv_state += 4;
else if (svs->state & SRV_STF_GOINGDOWN)
else if (svs->state == SRV_ST_STOPPING)
sv_state += 2;
}
else
@ -4264,7 +4264,7 @@ static int stats_process_http_post(struct stream_interface *si)
* If this server tracks the status of another one,
* we must restore the good status.
*/
if (!sv->track || (sv->track->state & SRV_STF_RUNNING)) {
if (!sv->track || (sv->track->state != SRV_ST_STOPPED)) {
set_server_up(&sv->check);
sv->check.health = sv->check.rise; /* up, but will fall down at first failure */
}

View File

@ -449,7 +449,7 @@ void sig_dump_state(struct sig_handler *sh)
chunk_printf(&trash,
"SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
p->id, s->id,
(s->state & SRV_STF_RUNNING) ? "UP" : "DOWN",
(s->state != SRV_ST_STOPPED) ? "UP" : "DOWN",
s->cur_sess, s->nbpend, s->counters.cum_sess);
Warning("%s\n", trash.str);
send_log(p, LOG_NOTICE, "%s\n", trash.str);

View File

@ -101,7 +101,7 @@ void recalc_server_map(struct proxy *px)
for (cur = px->srv; cur; cur = cur->next) {
if (cur->eweight &&
(cur->flags & SRV_F_BACKUP) == flag &&
(cur->state & (SRV_STF_RUNNING | SRV_STF_GOINGDOWN)) == SRV_STF_RUNNING) {
(cur->state == SRV_ST_STARTING || cur->state == SRV_ST_RUNNING)) {
int v;
/* If we are forced to return only one server, we don't want to

View File

@ -7069,12 +7069,12 @@ void manage_client_side_appsession(struct session *s, const char *buf, int len)
while (srv) {
if (strcmp(srv->id, asession->serverid) == 0) {
if ((srv->state & SRV_STF_RUNNING) ||
if ((srv->state != SRV_ST_STOPPED) ||
(s->be->options & PR_O_PERSIST) ||
(s->flags & SN_FORCE_PRST)) {
/* we found the server and it's usable */
txn->flags &= ~TX_CK_MASK;
txn->flags |= (srv->state & SRV_STF_RUNNING) ? TX_CK_VALID : TX_CK_DOWN;
txn->flags |= (srv->state != SRV_ST_STOPPED) ? TX_CK_VALID : TX_CK_DOWN;
s->flags |= SN_DIRECT | SN_ASSIGNED;
s->target = &srv->obj_type;
@ -7479,12 +7479,12 @@ void manage_client_side_cookies(struct session *s, struct channel *req)
while (srv) {
if (srv->cookie && (srv->cklen == delim - val_beg) &&
!memcmp(val_beg, srv->cookie, delim - val_beg)) {
if ((srv->state & SRV_STF_RUNNING) ||
if ((srv->state != SRV_ST_STOPPED) ||
(s->be->options & PR_O_PERSIST) ||
(s->flags & SN_FORCE_PRST)) {
/* we found the server and we can use it */
txn->flags &= ~TX_CK_MASK;
txn->flags |= (srv->state & SRV_STF_RUNNING) ? TX_CK_VALID : TX_CK_DOWN;
txn->flags |= (srv->state != SRV_ST_STOPPED) ? TX_CK_VALID : TX_CK_DOWN;
s->flags |= SN_DIRECT | SN_ASSIGNED;
s->target = &srv->obj_type;
break;

View File

@ -50,7 +50,7 @@ unsigned int srv_dynamic_maxconn(const struct server *s)
else max = MAX(s->minconn,
s->proxy->beconn * s->maxconn / s->proxy->fullconn);
if ((s->state & SRV_STF_WARMINGUP) &&
if ((s->state == SRV_ST_STARTING) &&
now.tv_sec < s->last_change + s->slowstart &&
now.tv_sec >= s->last_change) {
unsigned int ratio;

View File

@ -32,7 +32,7 @@ static struct srv_kw_list srv_keywords = {
int srv_downtime(const struct server *s)
{
if ((s->state & SRV_STF_RUNNING) && s->last_change < now.tv_sec) // ignore negative time
if ((s->state != SRV_ST_STOPPED) && s->last_change < now.tv_sec) // ignore negative time
return s->down_time;
return now.tv_sec - s->last_change + s->down_time;
@ -53,7 +53,7 @@ int srv_getinter(const struct check *check)
if ((check->state & CHK_ST_CONFIGURED) && (check->health == check->rise + check->fall - 1))
return check->inter;
if (!(s->state & SRV_STF_RUNNING) && check->health == 0)
if ((s->state == SRV_ST_STOPPED) && check->health == 0)
return (check->downinter)?(check->downinter):(check->inter);
return (check->fastinter)?(check->fastinter):(check->inter);
@ -185,13 +185,14 @@ void server_recalc_eweight(struct server *sv)
if (now.tv_sec < sv->last_change || now.tv_sec >= sv->last_change + sv->slowstart) {
/* go to full throttle if the slowstart interval is reached */
sv->state &= ~SRV_STF_WARMINGUP;
if (sv->state == SRV_ST_STARTING)
sv->state = SRV_ST_RUNNING;
}
/* We must take care of not pushing the server to full throttle during slow starts.
* It must also start immediately, at least at the minimal step when leaving maintenance.
*/
if ((sv->state & SRV_STF_WARMINGUP) && (px->lbprm.algo & BE_LB_PROP_DYN))
if ((sv->state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN))
w = (px->lbprm.wdiv * (now.tv_sec - sv->last_change) + sv->slowstart) / sv->slowstart;
else
w = px->lbprm.wdiv;
@ -347,7 +348,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
do_agent = 0;
newsrv->flags = 0;
newsrv->admin = 0;
newsrv->state = SRV_STF_RUNNING; /* early server setup */
newsrv->state = SRV_ST_RUNNING; /* early server setup */
newsrv->last_change = now.tv_sec;
newsrv->id = strdup(args[1]);
@ -682,7 +683,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
}
else if (!defsrv && !strcmp(args[cur_arg], "disabled")) {
newsrv->admin |= SRV_ADMF_FMAINT;
newsrv->state &= ~SRV_STF_RUNNING;
newsrv->state = SRV_ST_STOPPED;
newsrv->check.state |= CHK_ST_PAUSED;
newsrv->check.health = 0;
newsrv->agent.health = 0;

View File

@ -1375,7 +1375,7 @@ static int process_server_rules(struct session *s, struct channel *req, int an_b
if (ret) {
struct server *srv = rule->srv.ptr;
if ((srv->state & SRV_STF_RUNNING) ||
if ((srv->state != SRV_ST_STOPPED) ||
(px->options & PR_O_PERSIST) ||
(s->flags & SN_FORCE_PRST)) {
s->flags |= SN_DIRECT | SN_ASSIGNED;
@ -1460,7 +1460,7 @@ static int process_sticking_rules(struct session *s, struct channel *req, int an
struct server *srv;
srv = container_of(node, struct server, conf.id);
if ((srv->state & SRV_STF_RUNNING) ||
if ((srv->state != SRV_ST_STOPPED) ||
(px->options & PR_O_PERSIST) ||
(s->flags & SN_FORCE_PRST)) {
s->flags |= SN_DIRECT | SN_ASSIGNED;