pgpool2.git / summary / log / commit / refs
commit 4d58bfbe2adf631fb4cb9d55cf890d6e501c773a
Author: Toshihiro Kitagawa <kitagawa at sraoss.co.jp>
Date: Wed Aug 17 12:15:55 2011 +0000
Allow to issue SELECT to unlogged tables in master/slave mode.
pool_query_context.c | 9 ++++
pool_select_walker.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
pool_select_walker.h | 1 +
3 files changed, 147 insertions(+)
diff --git a/pool_query_context.c b/pool_query_context.c
index 8ec3f7244..7305dc252 100644
--- a/pool_query_context.c
+++ b/pool_query_context.c
@@ -417,6 +417,15 @@ void pool_where_to_send(POOL_QUERY_CONTEXT *query_context, char *query, Node *no
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
}
+ /*
+ * If unlogged table is used in the SELECT,
+ * we prefer to send to the primary.
+ */
+ else if (pool_has_unlogged_table(node))
+ {
+ pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
+ }
+
else
{
pool_set_node_to_be_sent(query_context,
diff --git a/pool_select_walker.c b/pool_select_walker.c
index 92bb64329..ea846c5fb 100644
--- a/pool_select_walker.c
+++ b/pool_select_walker.c
@@ -32,6 +32,7 @@
typedef struct {
bool has_system_catalog; /* True if system catalog table is used */
bool has_temp_table; /* True if temporary table is used */
+ bool has_unlogged_table; /* True if unlogged table is used */
bool has_function_call; /* True if write function call is used */
} SelectContext;
@@ -39,7 +40,9 @@ static bool function_call_walker(Node *node, void *context);
static bool system_catalog_walker(Node *node, void *context);
static bool is_system_catalog(char *table_name);
static bool temp_table_walker(Node *node, void *context);
+static bool unlogged_table_walker(Node *node, void *context);
static bool is_temp_table(char *table_name);
+static bool is_unlogged_table(char *table_name);
/*
* Return true if this SELECT has function calls *and* supposed to
@@ -96,6 +99,24 @@ bool pool_has_temp_table(Node *node)
return ctx.has_temp_table;
}
+/*
+ * Return true if this SELECT has unlogged table.
+ */
+bool pool_has_unlogged_table(Node *node)
+{
+
+ SelectContext ctx;
+
+ if (!IsA(node, SelectStmt))
+ return false;
+
+ ctx.has_unlogged_table = false;
+
+ raw_expression_tree_walker(node, unlogged_table_walker, &ctx);
+
+ return ctx.has_unlogged_table;
+}
+
/*
* Search function name in whilelist or blacklist regex array
* Return 1 on success (found in list)
@@ -249,6 +270,32 @@ temp_table_walker(Node *node, void *context)
return raw_expression_tree_walker(node, temp_table_walker, context);
}
+/*
+ * Walker function to find a unlogged table
+ */
+static bool
+unlogged_table_walker(Node *node, void *context)
+{
+ SelectContext *ctx = (SelectContext *) context;
+
+ if (node == NULL)
+ return false;
+
+ if (IsA(node, RangeVar))
+ {
+ RangeVar *rgv = (RangeVar *)node;
+
+ pool_debug("unlogged_table_walker: relname: %s", rgv->relname);
+
+ if (is_unlogged_table(rgv->relname))
+ {
+ ctx->has_unlogged_table = true;
+ return false;
+ }
+ }
+ return raw_expression_tree_walker(node, unlogged_table_walker, context);
+}
+
/*
* Judge the table used in a query represented by node is a system
* catalog or not.
@@ -423,6 +470,96 @@ static bool is_temp_table(char *table_name)
return result;
}
+/*
+ * Judge the table used in a query represented by node is a unlogged
+ * table or not.
+ */
+static bool is_unlogged_table(char *table_name)
+{
+/*
+ * Query to know if pg_class has relpersistence column or not.
+ * PostgreSQL 9.1 or later has this.
+ */
+#define HASRELPERSISTENCEQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c, pg_catalog.pg_attribute AS a WHERE c.relname = 'pg_class' AND a.attrelid = c.oid AND a.attname = 'relpersistence'"
+
+/*
+ * Query to know if the target table is a unlogged one. This query
+ * is valid in PostgreSQL 9.1 or later.
+ */
+#define ISUNLOGGEDQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.relname = '%s' AND c.relpersistence = 'u'"
+
+#define ISUNLOGGEDQUERY2 "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.oid = pgpool_regclass('%s') AND c.relpersistence = 'u'"
+
+ int hasrelpersistence;
+ static POOL_RELCACHE *hasrelpersistence_cache;
+ static POOL_RELCACHE *relcache;
+ POOL_CONNECTION_POOL *backend;
+
+ if (table_name == NULL)
+ {
+ return false;
+ }
+
+ backend = pool_get_session_context()->backend;
+
+ /*
+ * Check backend version
+ */
+ if (!hasrelpersistence_cache)
+ {
+ hasrelpersistence_cache = pool_create_relcache(128, HASRELPERSISTENCEQUERY,
+ int_register_func, int_unregister_func,
+ false);
+ if (hasrelpersistence_cache == NULL)
+ {
+ pool_error("is_unlogged_table: pool_create_relcache error");
+ return false;
+ }
+ }
+
+ hasrelpersistence = pool_search_relcache(hasrelpersistence_cache, backend, "pg_class")==0?0:1;
+ if (hasrelpersistence)
+ {
+ bool result;
+ char *query;
+
+ /* pgpool_regclass has been installed */
+ if (pool_has_pgpool_regclass())
+ {
+ query = ISUNLOGGEDQUERY2;
+ }
+ else
+ {
+ query = ISUNLOGGEDQUERY;
+ }
+
+ /*
+ * If relcache does not exist, create it.
+ */
+ if (!relcache)
+ {
+ relcache = pool_create_relcache(128, query,
+ int_register_func, int_unregister_func,
+ true);
+ if (relcache == NULL)
+ {
+ pool_error("is_unlogged_table: pool_create_relcache error");
+ return false;
+ }
+ }
+
+ /*
+ * Search relcache.
+ */
+ result = pool_search_relcache(relcache, backend, table_name)==0?false:true;
+ return result;
+ }
+ else
+ {
+ return false;
+ }
+}
+
/*
* Judge if we have pgpool_regclass or not.
*/
diff --git a/pool_select_walker.h b/pool_select_walker.h
index 66acf65fc..24ff6070a 100644
--- a/pool_select_walker.h
+++ b/pool_select_walker.h
@@ -32,6 +32,7 @@
extern bool pool_has_function_call(Node *node);
extern bool pool_has_system_catalog(Node *node);
extern bool pool_has_temp_table(Node *node);
+extern bool pool_has_unlogged_table(Node *node);
extern bool pool_has_pgpool_regclass(void);
extern bool raw_expression_tree_walker(Node *node, bool (*walker) (), void *context);
[parent: d47b37050d46]