/* * 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; }
/* * 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); } } } }