示例#1
0
/*
 * 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;
}
示例#2
0
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);
	}
}
示例#3
0
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("");
}
示例#4
0
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]);
	}
}
示例#5
0
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("");
}
示例#6
0
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);
	}
示例#7
0
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;
}
示例#8
0
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");
}
示例#9
0
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;
}