/* * iterate backends and update * - healthy bitmap * - number of healthy backends * - total_weight * - last change time of the VCL_BACKEND * * must be called under the vdir lock (read or write). * * A write lock is required if consistency between the individual attributes is * a must, e.g. when total_weight is required to be the exact sum of the weights * * The read lock is safe because add_backend expands the healthy bitmap and all * other members are atomic and may be used if consistency is not required. */ void vdir_update_health(VRT_CTX, struct vdir *vd) { VCL_TIME c, changed = 0; VCL_BOOL h; VCL_BACKEND be; unsigned u, nh = 0; double tw = 0.0; struct vbitmap *healthy; CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC); healthy = vd->healthy; for (u = 0; u < vd->n_backend; u++) { be = vd->backend[u]; CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC); c = 0; h = VRT_Healthy(ctx, vd->backend[u], &c); if (h) { nh++; tw += vd->weight[u]; } if (c > changed) changed = c; if (h != vbit_test(healthy, u)) { if (h) vbit_set(healthy, u); else vbit_clr(healthy, u); } } VRT_SetChanged(vd->dir, changed); vd->total_weight = tw; vd->n_healthy = nh; }
int VSL_Dispatch(struct VSL_data *vd, vsl_handler *func, void *priv) { int i; unsigned u, l, s; unsigned char *p; CHECK_OBJ_NOTNULL(vd, VSL_MAGIC); while (1) { i = VSL_NextLog(vd, &p); if (i <= 0) return (i); u = SHMLOG_ID(p); l = SHMLOG_LEN(p); s = 0; if (vbit_test(vd->vbm_backend, u)) s |= VSL_S_BACKEND; if (vbit_test(vd->vbm_client, u)) s |= VSL_S_CLIENT; if (func(priv, p[SHMLOG_TAG], u, l, s, (char *)p + SHMLOG_DATA)) return (1); } }
static unsigned vdir_pick_by_weight(const struct vdir *vd, double w) { const struct vbitmap *healthy = vd->healthy; double a = 0.0; unsigned u; AN(healthy); for (u = 0; u < vd->n_backend; u++) { if (! vbit_test(healthy, u)) continue; a += vd->weight[u]; if (w < a) return (u); } WRONG(""); }
static void vex_print_tags(const struct vbitmap *vbm) { int i; int first = 1; for (i = 0; i < SLT__MAX; i++) { if (VSL_tags[i] == NULL) continue; if (!vbit_test(vbm, i)) continue; if (first) first = 0; else fprintf(stderr, ","); fprintf(stderr, "%s", VSL_tags[i]); } }
static unsigned vdir_pick_by_weight(const struct vdir *vd, double w, const struct vbitmap *blacklist) { double a = 0.0; VCL_BACKEND be = NULL; unsigned u; for (u = 0; u < vd->n_backend; u++) { be = vd->backend[u]; CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC); if (blacklist != NULL && vbit_test(blacklist, u)) continue; a += vd->weight[u]; if (w < a) return (u); } WRONG(""); }
static int vsl_match_IX(struct VSL_data *vsl, const vslf_list *list, const struct VSL_cursor *c) { enum VSL_tag_e tag; const char *cdata; int len; const struct vslf *vslf; (void)vsl; tag = VSL_TAG(c->rec.ptr); cdata = VSL_CDATA(c->rec.ptr); len = VSL_LEN(c->rec.ptr); VTAILQ_FOREACH(vslf, list, list) { CHECK_OBJ_NOTNULL(vslf, VSLF_MAGIC); if (vslf->tags != NULL && !vbit_test(vslf->tags, tag)) continue; if (VRE_exec(vslf->vre, cdata, len, 0, 0, NULL, 0, NULL) >= 0) return (1); }
static int shard_next(struct shard_state *state, VCL_INT skip, VCL_BOOL healthy) { int c, chosen = -1; uint32_t ringsz; VCL_BACKEND be; double changed; struct shard_be_info *sbe; AN(state); assert(state->idx >= 0); CHECK_OBJ_NOTNULL(state->shardd, SHARDDIR_MAGIC); if (state->pickcount >= state->shardd->n_backend) return -1; ringsz = state->shardd->n_backend * state->shardd->replicas; while (state->pickcount < state->shardd->n_backend && skip >= 0) { c = state->shardd->hashcircle[state->idx].host; if (! vbit_test(state->picklist, c)) { vbit_set(state->picklist, c); state->pickcount++; sbe = NULL; be = state->shardd->backend[c].backend; AN(be); if (be->healthy(be, state->ctx->bo, &changed)) { if (skip-- == 0) { chosen = c; sbe = &state->last; } else { sbe = &state->previous; } } else if (!healthy && skip-- == 0) { chosen = c; sbe = &state->last; } if (sbe == &state->last && state->last.hostid != -1) memcpy(&state->previous, &state->last, sizeof(state->previous)); if (sbe) { sbe->hostid = c; sbe->healthy = 1; sbe->changed = changed; } if (chosen != -1) break; } if (++(state->idx) == ringsz) state->idx = 0; } return chosen; }
void vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag, int weight) { VCL_BACKEND be; VCL_BOOL h; unsigned u, nh; double w; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC); if (pflag) { if (jflag) { VSB_cat(vsb, "{\n"); VSB_indent(vsb, 2); if (weight) VSB_printf(vsb, "\"total_weight\": %f,\n", vd->total_weight); VSB_cat(vsb, "\"backends\": {\n"); VSB_indent(vsb, 2); } else { VSB_cat(vsb, "\n\n\tBackend\tWeight\tHealth\n"); } } vdir_rdlock(vd); vdir_update_health(ctx, vd); for (u = 0; pflag && u < vd->n_backend; u++) { be = vd->backend[u]; CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC); h = vbit_test(vd->healthy, u); w = h ? vd->weight[u] : 0.0; if (jflag) { if (u) VSB_cat(vsb, ",\n"); VSB_printf(vsb, "\"%s\": {\n", be->vcl_name); VSB_indent(vsb, 2); if (weight) VSB_printf(vsb, "\"weight\": %f,\n", w); if (h) VSB_cat(vsb, "\"health\": \"healthy\"\n"); else VSB_cat(vsb, "\"health\": \"sick\"\n"); VSB_indent(vsb, -2); VSB_cat(vsb, "}"); } else { VSB_cat(vsb, "\t"); VSB_cat(vsb, be->vcl_name); if (weight) VSB_printf(vsb, "\t%6.2f%%\t", 100 * w / vd->total_weight); else VSB_cat(vsb, "\t-\t"); VSB_cat(vsb, h ? "healthy" : "sick"); VSB_cat(vsb, "\n"); } } nh = vd->n_healthy; u = vd->n_backend; vdir_unlock(vd); if (jflag && (pflag)) { VSB_cat(vsb, "\n"); VSB_indent(vsb, -2); VSB_cat(vsb, "}\n"); VSB_indent(vsb, -2); VSB_cat(vsb, "},\n"); } if (pflag) return; if (jflag) VSB_printf(vsb, "[%u, %u, \"%s\"]", nh, u, nh ? "healthy" : "sick"); else VSB_printf(vsb, "%u/%u\t%s", nh, u, nh ? "healthy" : "sick"); }
int VSL_NextLog(struct VSL_data *vd, unsigned char **pp) { unsigned char *p, t; unsigned u, l; int i; CHECK_OBJ_NOTNULL(vd, VSL_MAGIC); while (1) { i = vsl_nextlog(vd, &p); if (i != 1) return (i); u = SHMLOG_ID(p); l = SHMLOG_LEN(p); (void)l; switch(p[SHMLOG_TAG]) { case SLT_SessionOpen: case SLT_ReqStart: vbit_set(vd->vbm_client, u); vbit_clr(vd->vbm_backend, u); break; case SLT_BackendOpen: case SLT_BackendXID: vbit_clr(vd->vbm_client, u); vbit_set(vd->vbm_backend, u); break; default: break; } if (vd->skip) { --vd->skip; continue; } else if (vd->keep) { if (--vd->keep == 0) return (-1); } t = p[SHMLOG_TAG]; if (vbit_test(vd->vbm_select, t)) { *pp = p; return (1); } if (vbit_test(vd->vbm_supress, t)) continue; if (vd->b_opt && !vbit_test(vd->vbm_backend, u)) continue; if (vd->c_opt && !vbit_test(vd->vbm_client, u)) continue; if (vd->regincl != NULL) { i = VRE_exec(vd->regincl, (char *)p + SHMLOG_DATA, SHMLOG_LEN(p), /* Length */ 0, 0, NULL, 0); if (i == VRE_ERROR_NOMATCH) continue; } if (vd->regexcl != NULL) { i = VRE_exec(vd->regexcl, (char *)p + SHMLOG_DATA, SHMLOG_LEN(p), /* Length */ 0, 0, NULL, 0); if (i != VRE_ERROR_NOMATCH) continue; } *pp = p; return (1); } }
static void mgt_launch_child(struct cli *cli) { pid_t pid; unsigned u; char *p; struct vev *e; int i, j, k, cp[2]; struct sigaction sa; if (child_state != CH_STOPPED && child_state != CH_DIED) return; if (!MAC_sockets_ready(cli)) { child_state = CH_STOPPED; if (cli != NULL) { VCLI_SetResult(cli, CLIS_CANT); return; } MGT_complain(C_ERR, "Child start failed: could not open sockets"); return; } child_state = CH_STARTING; /* Open pipe for mgr->child CLI */ AZ(pipe(cp)); heritage.cli_in = cp[0]; mgt_child_inherit(heritage.cli_in, "cli_in"); child_cli_out = cp[1]; /* Open pipe for child->mgr CLI */ AZ(pipe(cp)); heritage.cli_out = cp[1]; mgt_child_inherit(heritage.cli_out, "cli_out"); child_cli_in = cp[0]; /* * Open pipe for child stdout/err * NB: not inherited, because we dup2() it to stdout/stderr in child */ AZ(pipe(cp)); heritage.std_fd = cp[1]; child_output = cp[0]; AN(heritage.vsm); mgt_SHM_Size_Adjust(); AN(heritage.vsm); AN(heritage.param); if ((pid = fork()) < 0) { /* XXX */ perror("Could not fork child"); exit(1); } if (pid == 0) { /* Redirect stdin/out/err */ AZ(close(STDIN_FILENO)); assert(open("/dev/null", O_RDONLY) == STDIN_FILENO); assert(dup2(heritage.std_fd, STDOUT_FILENO) == STDOUT_FILENO); assert(dup2(heritage.std_fd, STDERR_FILENO) == STDERR_FILENO); /* * Close all FDs the child shouldn't know about * * We cannot just close these filedescriptors, some random * library routine might miss it later on and wantonly close * a FD we use at that point in time. (See bug #1841). * We close the FD and replace it with /dev/null instead, * That prevents security leakage, and gives the library * code a valid FD to close when it discovers the changed * circumstances. */ closelog(); for (i = STDERR_FILENO + 1; i < CLOSE_FD_UP_TO; i++) { if (vbit_test(fd_map, i)) continue; if (close(i) == 0) { k = open("/dev/null", O_RDONLY); assert(k >= 0); j = dup2(k, i); assert(j == i); AZ(close(k)); } } #ifdef HAVE_SETPROCTITLE setproctitle("Varnish-Chld %s", heritage.name); #endif if (mgt_param.sigsegv_handler) { memset(&sa, 0, sizeof sa); sa.sa_sigaction = child_sigsegv_handler; sa.sa_flags = SA_SIGINFO; (void)sigaction(SIGSEGV, &sa, NULL); (void)sigaction(SIGBUS, &sa, NULL); (void)sigaction(SIGABRT, &sa, NULL); } (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); VJ_subproc(JAIL_SUBPROC_WORKER); child_main(); exit(0); } assert(pid > 1); MGT_complain(C_DEBUG, "Child (%jd) Started", (intmax_t)pid); VSC_C_mgt->child_start = ++static_VSC_C_mgt.child_start; /* Close stuff the child got */ closex(&heritage.std_fd); mgt_child_inherit(heritage.cli_in, NULL); closex(&heritage.cli_in); mgt_child_inherit(heritage.cli_out, NULL); closex(&heritage.cli_out); child_std_vlu = VLU_New(NULL, child_line, 0); AN(child_std_vlu); AZ(ev_listen); e = vev_new(); XXXAN(e); e->fd = child_output; e->fd_flags = EV_RD; e->name = "Child listener"; e->callback = child_listener; AZ(vev_add(mgt_evb, e)); ev_listen = e; AZ(ev_poker); if (mgt_param.ping_interval > 0) { e = vev_new(); XXXAN(e); e->timeout = mgt_param.ping_interval; e->callback = child_poker; e->name = "child poker"; AZ(vev_add(mgt_evb, e)); ev_poker = e; } mgt_cli_start_child(child_cli_in, child_cli_out); child_pid = pid; if (mgt_push_vcls_and_start(cli, &u, &p)) { VCLI_SetResult(cli, u); MGT_complain(C_ERR, "Child (%jd) Pushing vcls failed:\n%s", (intmax_t)child_pid, p); free(p); child_state = CH_RUNNING; mgt_stop_child(); } else child_state = CH_RUNNING; }