Example #1
0
/*
 * Search relcache. If found, return user data. Otherwise return 0.
 * If not found in cache, do the query and store the result into cache and return it.
 */
void *pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, char *table)
{
	char *rel;
	char *dbname;
	int i;
	int maxrefcnt = INT_MAX;
	char query[1024];
	POOL_SELECT_RESULT *res = NULL;
	int index = 0;

	/* Eliminate double quotes */
	rel = malloc(strlen(table)+1);
	if (!rel)
	{
		pool_error("pool_search_relcache: malloc failed");
		return NULL;
	}
	for(i=0;*table;table++)
	{
		if (*table != '"')
			rel[i++] = *table;
	}
	rel[i] = '\0';

	/* Obtain database name */
	dbname = MASTER_CONNECTION(backend)->sp->database;

	/* Look for cache first */
	for (i=0;i<relcache->num;i++)
	{
		/*
		 * If cache is session local, we need to check session id
		 */
		if (relcache->cache_is_session_local)
		{
			if (relcache->cache[i].session_id != LocalSessionId)
				continue;
		}

		if (strcasecmp(relcache->cache[i].dbname, dbname) == 0 &&
			strcasecmp(relcache->cache[i].relname, rel) == 0)
		{
			/* Found */
			if (relcache->cache[i].refcnt < INT_MAX)
				relcache->cache[i].refcnt++;
			free(rel);
			return relcache->cache[i].data;
		}
	}

	/* Not in cache. Check the system catalog */
	snprintf(query, sizeof(query), relcache->sql, rel);

	per_node_statement_log(backend, MASTER_NODE_ID, query);

	if (do_query(MASTER(backend), query, &res) != POOL_CONTINUE)
	{
		pool_error("pool_search_relcache: do_query failed");
		if (res)
			free_select_result(res);
		free(rel);
		return NULL;
	}

	/*
	 * Look for replacement in cache
	 */
	for (i=0;i<relcache->num;i++)
	{
		/*
		 * If cache is session local, we can discard old cache immediately
		 */
		if (relcache->cache_is_session_local)
		{
			if (relcache->cache[i].session_id != LocalSessionId)
			{
				index = i;
				break;
			}
		}

		if (relcache->cache[i].refcnt == 0)
		{
			/* Found empty slot */
			index = i;
			break;
		}
		else if (relcache->cache[i].refcnt < maxrefcnt)
		{
			maxrefcnt = relcache->cache[i].refcnt;
			index = i;
		}
	}

	/* Register cache */
	strncpy(relcache->cache[index].dbname, dbname, MAX_ITEM_LENGTH);
	strncpy(relcache->cache[index].relname, rel, MAX_ITEM_LENGTH);
	relcache->cache[index].refcnt = 1;
	relcache->cache[index].session_id = LocalSessionId;
	free(rel);

	/*
	 * Call user defined unregister/register fuction.
	 */
	(*relcache->unregister_func)(relcache->cache[index].data);
	relcache->cache[index].data = (*relcache->register_func)(res);
	free_select_result(res);

	return 	relcache->cache[index].data;
}
/*
 * Get or return cached transaction isolation mode
 */
POOL_TRANSACTION_ISOLATION pool_get_transaction_isolation(void)
{
	POOL_STATUS status;
	POOL_SELECT_RESULT *res;
	POOL_TRANSACTION_ISOLATION ret;

	if (!session_context)
	{
		pool_error("pool_get_transaction_isolation: session context is not initialized");
		return POOL_UNKNOWN;
	}

	/* It seems cached result is usable. Return it. */
	if (session_context->transaction_isolation != POOL_UNKNOWN)
		return session_context->transaction_isolation;

	/* No cached data is available. Ask backend. */
	status = do_query(MASTER(session_context->backend),
					  "SELECT current_setting('transaction_isolation')", &res, MAJOR(session_context->backend));

	if (res->numrows <= 0)
	{
		pool_error("pool_get_transaction_isolation: do_query returns no rows");
		free_select_result(res);
		return POOL_UNKNOWN;
	}
	if (res->data[0] == NULL)
	{
		pool_error("pool_get_transaction_isolation: do_query returns no data");
		free_select_result(res);
		return POOL_UNKNOWN;
	}
	if (res->nullflags[0] == -1)
	{
		pool_error("pool_get_transaction_isolation: do_query returns NULL");
		free_select_result(res);
		return POOL_UNKNOWN;
	}

	if (!strcmp(res->data[0], "read uncommitted"))
		ret = POOL_READ_UNCOMMITTED;
	else if (!strcmp(res->data[0], "read committed"))
		ret = POOL_READ_COMMITTED;
	else if (!strcmp(res->data[0], "repeatable read"))
		ret = POOL_REPEATABLE_READ;
	else if (!strcmp(res->data[0], "serializable"))
		ret = POOL_SERIALIZABLE;
	else
	{
		pool_error("pool_get_transaction_isolation: unknown transaction isolation level:%s",
				   res->data[0]);
		ret = POOL_UNKNOWN;
	}   

	free_select_result(res);

	if (ret != POOL_UNKNOWN)
		session_context->transaction_isolation = ret;

	return ret;
}
Example #3
0
/*
 * Check replicaton time lag
 */
static void check_replication_time_lag(void)
{
	int i;
	int active_nodes = 0;
	POOL_STATUS sts;
	POOL_SELECT_RESULT *res;
	unsigned long long int lsn[MAX_NUM_BACKENDS];
	char *query;
	BackendInfo *bkinfo;
	unsigned long long int lag;

	if (NUM_BACKENDS <= 1)
	{
		/* If there's only one node, there's no point to do checking */
		return;
	}

	/* Count healthy nodes */
	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
			active_nodes++;
	}

	if (active_nodes <= 1)
	{
		/* If there's only one or less active node, there's no point
		 * to do checking */
		return;
	}

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (!VALID_BACKEND(i))
			continue;

		if (!slots[i])
		{
			pool_debug("check_replication_time_lag: DB node is valid but no persistent connection");
			pool_error("check_replication_time_lag: could not connect to DB node %d, check sr_check_user and sr_check_password", i);

			return;
		}

		if (PRIMARY_NODE_ID == i)
		{
			query = "SELECT pg_current_xlog_location()";
		}
		else
		{
			query = "SELECT pg_last_xlog_replay_location()";
		}

		sts = do_query(slots[i]->con, query, &res, PROTO_MAJOR_V3);
		if (sts != POOL_CONTINUE)
		{
			pool_error("check_replication_time_lag: %s failed", query);
			return;
		}
		if (!res)
		{
			pool_error("check_replication_time_lag: %s result is null", query);
			return;
		}
		if (res->numrows <= 0)
		{
			pool_error("check_replication_time_lag: %s returns no rows", query);
			free_select_result(res);
			return;
		}
		if (res->data[0] == NULL)
		{
			pool_error("check_replication_time_lag: %s returns no data", query);
			free_select_result(res);
			return;
		}

		if (res->nullflags[0] == -1)
		{
			pool_log("check_replication_time_lag: %s returns NULL", query);
			free_select_result(res);
			lsn[i] = 0;
		}
		else
		{
			lsn[i] = text_to_lsn(res->data[0]);
			free_select_result(res);
		}
	}

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (!VALID_BACKEND(i))
			continue;

		/* Set standby delay value */
		bkinfo = pool_get_node_info(i);
		lag = (lsn[PRIMARY_NODE_ID] > lsn[i]) ? lsn[PRIMARY_NODE_ID] - lsn[i] : 0;

		if (PRIMARY_NODE_ID == i)
		{
			bkinfo->standby_delay = 0;
		}
		else
		{
			bkinfo->standby_delay = lag;

			/* Log delay if necessary */
			if ((!strcmp(pool_config->log_standby_delay, "always") && lag > 0) ||
				(pool_config->delay_threshold &&
				 !strcmp(pool_config->log_standby_delay, "if_over_threshold") &&
				 lag > pool_config->delay_threshold))
			{
				pool_log("Replication of node:%d is behind %llu bytes from the primary server (node:%d)",
				         i, lsn[PRIMARY_NODE_ID] - lsn[i], PRIMARY_NODE_ID);
			}
		}
	}
}