#define PEER_F_LEARN_NOTUP2DATE 0x00000200 /* Learn from peer finished but peer is not up to date */
#define PEER_F_LEARN_PROCESS 0x00000400 /* Learn from peer was started */
#define PEER_F_LEARN_FINISHED 0x00000800 /* Learn from peer fully finished */
-/* unused : 0x00001000 */
-#define PEER_F_ST_CONNECTED 0x00002000 /* Used to set a peer in connected state. */
-/* unused : 0x00004000 */
-#define PEER_F_ST_RELEASED 0x00008000 /* Used to set a peer in released state. */
+/* unused : 0x00001000..0x00008000 */
#define PEER_F_RESYNC_REQUESTED 0x00010000 /* A resnyc was explicitly requested */
#define PEER_F_WAIT_SYNCTASK_ACK 0x00020000 /* Stop all processing waiting for the sync task acknowledgement when the applet state changes */
#define PEER_TEACH_RESET ~(PEER_F_TEACH_PROCESS|PEER_F_TEACH_FINISHED) /* PEER_F_TEACH_COMPLETE should never be reset */
#define PEER_LEARN_RESET ~(PEER_F_LEARN_ASSIGN|PEER_F_LEARN_PROCESS|PEER_F_LEARN_FINISHED|PEER_F_LEARN_NOTUP2DATE)
-#define PEER_STATE_RESET ~(PEER_F_ST_CONNECTED|PEER_F_ST_RELEASED)
#define PEER_RESYNC_TIMEOUT 5000 /* 5 seconds */
}
}
+static const char *peer_app_state_str(enum peer_app_state appstate)
+{
+ switch (appstate) {
+ case PEER_APP_ST_STOPPED:
+ return "STOPPED";
+ case PEER_APP_ST_STARTING:
+ return "STARTING";
+ case PEER_APP_ST_RUNNING:
+ return "RUNNING";
+ case PEER_APP_ST_STOPPING:
+ return "STOPPING";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/* This function encode an uint64 to 'dynamic' length format.
The encoded value is written at address *str, and the
caller must assure that size after *str is large enough.
/* reset teaching flags to 0 */
peer->flags &= PEER_TEACH_RESET;
- /* Mark peer as released */
- peer->flags &= PEER_STATE_RESET;
- peer->flags |= (PEER_F_ST_RELEASED|PEER_F_WAIT_SYNCTASK_ACK);
+ /* Mark the peer as stopping and wait for the sync task */
+ peer->flags |= PEER_F_WAIT_SYNCTASK_ACK;
+ peer->appstate = PEER_APP_ST_STOPPING;
task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
}
peer->flags |= PEER_F_TEACH_PROCESS;
}
- peer->flags &= PEER_STATE_RESET;
- peer->flags |= (PEER_F_ST_CONNECTED|PEER_F_WAIT_SYNCTASK_ACK);
+ /* Mark the peer as starting and wait the sync task */
+ peer->flags |= PEER_F_WAIT_SYNCTASK_ACK;
+ peer->appstate = PEER_APP_ST_STARTING;
}
/*
return NULL;
}
+/* Clear LEARN flags to a given peer, dealing with aborts if it was assigned for
+ * learning. In this case, the resync timeout is re-armed.
+ */
+static void clear_peer_learning_status(struct peer *peer)
+{
+ if (peer->flags & PEER_F_LEARN_ASSIGN) {
+ /* unassign current peer for learning */
+ peer->peers->flags &= ~PEERS_F_RESYNC_ASSIGN;
+ peer->peers->flags |= (peer->local ? PEERS_F_RESYNC_LOCALABORT : PEERS_F_RESYNC_REMOTEABORT);
+ /* reschedule a resync */
+ peer->peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
+ }
+ peer->flags &= PEER_LEARN_RESET;
+}
+
static void __process_peer_learn_status(struct peers *peers, struct peer *peer)
{
struct peer *ps;
appctx_wakeup(peer->appctx);
}
-static void __process_peer_state(struct peers *peers, struct peer *peer)
+/* Synchronise the peer applet state with its associated peers section. This
+ * function handles STARTING->RUNNING and STOPPING->STOPPED transitions.
+ */
+static void sync_peer_app_state(struct peers *peers, struct peer *peer)
{
- /* Check peer state. Order is important */
- if (peer->flags & (PEER_F_ST_RELEASED|PEER_F_ST_CONNECTED)) {
- if (peer->flags & PEER_F_LEARN_ASSIGN) {
- /* unassign current peer for learning */
- peers->flags &= ~PEERS_F_RESYNC_ASSIGN;
- peers->flags |= (peer->local ? PEERS_F_RESYNC_LOCALABORT : PEERS_F_RESYNC_REMOTEABORT);
- /* reschedule a resync */
- peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
- }
- peer->flags &= PEER_LEARN_RESET;
+ if (peer->appstate == PEER_APP_ST_STOPPING) {
+ clear_peer_learning_status(peer);
+ peer->appstate = PEER_APP_ST_STOPPED;
}
- if (peer->flags & PEER_F_ST_CONNECTED) {
- peer->flags &= PEER_LEARN_RESET;
-
+ else if (peer->appstate == PEER_APP_ST_STARTING) {
+ clear_peer_learning_status(peer);
if (peer->local & appctx_is_back(peer->appctx)) {
/* if local peer has accepted the connection (appctx is
* on the backend side), flag it to learn a lesson and
peers->flags |= PEERS_F_RESYNC_REMOTEASSIGN;
}
}
+ peer->appstate = PEER_APP_ST_RUNNING;
appctx_wakeup(peer->appctx);
}
-
- peer->flags &= PEER_STATE_RESET;
}
static void __process_running_peer_sync(struct task *task, struct peers *peers, unsigned int state)
HA_SPIN_LOCK(PEER_LOCK, &ps->lock);
__process_peer_learn_status(peers, ps);
- __process_peer_state(peers, ps);
+ sync_peer_app_state(peers, ps);
/* Peer changes, if any, were now ack by the sync task. Unblock
* the peer (any wakeup should already be performed, no need to
ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + ha_random() % 2000));
ps->heartbeat = TICK_ETERNITY;
peer_session_forceshutdown(ps);
- __process_peer_state(peers, ps);
+ sync_peer_app_state(peers, ps);
ps->no_hbt++;
}
}
HA_SPIN_LOCK(PEER_LOCK, &ps->lock);
__process_peer_learn_status(peers, ps);
- __process_peer_state(peers, ps);
+ sync_peer_app_state(peers, ps);
/* Peer changes, if any, were now ack by the sync task. Unblock
* the peer (any wakeup should already be performed, no need to
ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + ha_random() % 2000));
if (ps->appctx) {
peer_session_forceshutdown(ps);
- __process_peer_state(peers, ps);
+ sync_peer_app_state(peers, ps);
}
}
struct shared_table *st;
addr_to_str(&peer->srv->addr, pn, sizeof pn);
- chunk_appendf(msg, " %p: id=%s(%s,%s) addr=%s:%d last_status=%s",
+ chunk_appendf(msg, " %p: id=%s(%s,%s) addr=%s:%d app_state=%s last_status=%s",
peer, peer->id,
peer->local ? "local" : "remote",
peer->appctx ? "active" : "inactive",
pn, peer->srv->svc_port,
+ peer_app_state_str(peer->appstate),
statuscode_str(peer->statuscode));
chunk_appendf(msg, " last_hdshk=%s\n",