Exemplo n.º 1
0
static void throttle_wait(size_t total_bytes_processed TSRMLS_DC)
{
	struct timeval tv;
	double time;
	double min_time;
	size_t bytes_processed;
	
	bytes_processed = total_bytes_processed - THROTTLE_G(post_bytes_processed);

	throttle_debug("throttle: bytes processed: %zd (total: %zd)\n", bytes_processed, total_bytes_processed);

	min_time = (double) bytes_processed / (double) THROTTLE_G(speed);

	gettimeofday(&tv, NULL);
	time = (double) tv.tv_sec + tv.tv_usec / 1000000.0;

	if (time < THROTTLE_G(lasttime) + min_time) {

		useconds_t usec;

		throttle_debug("throttle: waiting for %f seconds (until %f)\n", THROTTLE_G(lasttime) + min_time - time, THROTTLE_G(lasttime) + min_time);

		usec = (THROTTLE_G(lasttime) + min_time - time) * 1000000.0;
		usleep(usec);

		gettimeofday(&tv, NULL);
		time = (double) tv.tv_sec + tv.tv_usec / 1000000.0;
	}

	THROTTLE_G(post_bytes_processed) = total_bytes_processed;
	THROTTLE_G(lasttime) = time;
}
Exemplo n.º 2
0
static void S_throttle_pool_rearm_workers(liThrottlePool *pool, guint worker_count, guint time_diff) {
	guint i;
	gint64 connections = 0;
	gint64 wrk_connections[worker_count];
	gint64 fill;

	for (i = 0; i < worker_count; ++i) {
		wrk_connections[i] = g_atomic_int_get((gint*) &pool->workers[i].connections);
		connections += wrk_connections[i];
	}

	if (0 == connections) return;

	time_diff = MIN(time_diff, 1000);

	fill = MIN((guint64) pool->burst, ((guint64) pool->rate * time_diff) / 1000u);

	throttle_debug("rearm workers: refill %i after %u (or more) msecs (rate %u, burst %u)\n",
		(guint) fill, (guint) time_diff, pool->rate, pool->burst);

	for (i = 0; i < worker_count; ++i) {
		gint wrk_fill;
		if (0 == wrk_connections[i]) continue;
		wrk_fill = (fill * wrk_connections[i]) / connections;
		throttle_debug("rearm worker %u: refill %u\n", i, wrk_fill);
		g_atomic_int_add(&pool->workers[i].magazine, wrk_fill);
	}
}
Exemplo n.º 3
0
void li_throttle_waitqueue_cb(liWaitQueue *wq, gpointer data) {
	liWaitQueueElem *wqe;
	UNUSED(data); /* should contain worker */

	throttle_debug("li_throttle_waitqueue_cb\n");

	while (NULL != (wqe = li_waitqueue_pop(wq))) {
		liThrottleState *state = LI_CONTAINER_OF(wqe, liThrottleState, wqueue_elem);
		liThrottleNotifyCB notify_callback = state->notify_callback;
		gpointer notify_data = wqe->data;

		if (NULL == notify_data || NULL == notify_callback || 0 == state->interested) continue;

		notify_callback(state, notify_data);
	}
	li_waitqueue_update(wq);
}
Exemplo n.º 4
0
static void throttle_pool_rearm(liWorker *wrk, liThrottlePool *pool, guint now) {
	liThrottlePoolWorkerState *wpool = &pool->workers[wrk->ndx];
	guint last = g_atomic_int_get((gint*) &pool->last_rearm);
	guint time_diff = now - last;

	if (G_UNLIKELY(time_diff >= LI_THROTTLE_GRANULARITY)) {
		g_mutex_lock(pool->rearm_mutex);
			/* check again */
			last = g_atomic_int_get((gint*) &pool->last_rearm);
			time_diff = now - last;
			if (G_LIKELY(time_diff >= LI_THROTTLE_GRANULARITY)) {
				S_throttle_pool_rearm_workers(pool, wrk->srv->worker_count, time_diff);
				g_atomic_int_set((gint*) &pool->last_rearm, now);
			}
		g_mutex_unlock(pool->rearm_mutex);
	}

	if (G_UNLIKELY(wpool->last_rearm < last)) {
		/* distribute wpool->magazine */
		GList *lnk;
		guint connections = wpool->connections;
		gint magazine = g_atomic_int_get(&wpool->magazine);
		gint supply = magazine / connections;
		g_atomic_int_add(&wpool->magazine, -supply * connections);
		wpool->last_rearm = now;

		throttle_debug("throttle_pool_rearm: distribute supply %i on each of %i connections\n",
			supply, connections);

		if (0 == supply) return;

		g_atomic_int_set((gint*) &wpool->connections, 0);
		while (NULL != (lnk = g_queue_pop_head_link(&wpool->waiting))) {
			liThrottlePoolState *pstate = LI_CONTAINER_OF(lnk, liThrottlePoolState, pool_link);
			pstate->magazine += supply;
			lnk->data = NULL;
		}
	}
}
Exemplo n.º 5
0
guint li_throttle_query(liWorker *wrk, liThrottleState *state, guint interested, liThrottleNotifyCB notify_callback, gpointer data) {
	guint now = msec_timestamp(li_cur_ts(wrk));
	gint fill, pool_fill;
	guint i, len;

	if (NULL == state) return interested;

	state->notify_callback = NULL;
	state->wqueue_elem.data = NULL;

	throttle_debug("li_throttle_query[%u]: interested %i, magazine %i\n", now, interested, state->magazine);

	if (interested > THROTTLE_MAX_STEP) interested = THROTTLE_MAX_STEP;

	if ((gint) interested <= state->magazine + THROTTLE_OVERLOAD) return interested;

	/* also try to balance negative magazine */
	fill = interested - state->magazine;
	if (state->single_rate != 0) {
		if (now - state->single_last_rearm >= LI_THROTTLE_GRANULARITY) {
			guint single_fill = (((guint64) state->single_rate) * (now - state->single_last_rearm)) / 1000u;
			state->single_last_rearm = now;
			if (state->single_burst - state->single_magazine < single_fill) {
				state->single_magazine = state->single_burst;
			} else {
				state->single_magazine += single_fill;
			}
		}
		if (fill > state->single_magazine) fill = state->single_magazine;
		throttle_debug("single_magazine: %i\n", state->single_magazine);
	}

	/* pool_fill <= fill in the loop */
	pool_fill = fill;
	for (i = 0, len = state->pools->len; i < len; ++i) {
		liThrottlePoolState *pstate = g_ptr_array_index(state->pools, i);
		liThrottlePool *pool = pstate->pool;
		liThrottlePoolWorkerState *pwstate = &pool->workers[wrk->ndx];
		if (fill > pstate->magazine) {
			throttle_register(pwstate, pstate);
			throttle_pool_rearm(wrk, pool, now);
			if (fill > pstate->magazine) {
				throttle_register(pwstate, pstate);
				if (pool_fill > pstate->magazine) {
					pool_fill = pstate->magazine;
				}
			}
		}
		throttle_debug("pool %i magazine: %i\n", i, state->single_magazine);
	}

	throttle_debug("query refill: %i\n", pool_fill);

	if (pool_fill > 0) {
		if (state->single_rate != 0) {
			state->single_magazine -= pool_fill;
		}
		for (i = 0, len = state->pools->len; i < len; ++i) {
			liThrottlePoolState *pstate = g_ptr_array_index(state->pools, i);
			pstate->magazine -= pool_fill;
		}
		state->magazine += pool_fill;
	}

	if (state->magazine + THROTTLE_OVERLOAD <= 0) {
		throttle_debug("query queueing\n");
		state->wqueue_elem.data = data;
		state->notify_callback = notify_callback;
		state->interested = interested;
		if (!state->wqueue_elem.queued) {
			li_waitqueue_push(&wrk->throttle_queue, &state->wqueue_elem);
		}
		return 0;
	}

	throttle_debug("query success: %i\n", state->magazine + THROTTLE_OVERLOAD);

	if ((gint) interested <= state->magazine + THROTTLE_OVERLOAD) return interested;
	return state->magazine + THROTTLE_OVERLOAD;
}