CVS User Account cvsuser
Wed Mar 1 12:18:47 PST 2006
Log Message:
-----------
Automatically switch log tables every Sunday at 2am, if the admin
did not set up logtable switching via crontab.

Jan

Modified Files:
--------------
    slony1-engine/src/backend:
        slony1_base.sql (r1.29 -> r1.30)
        slony1_funcs.c (r1.39 -> r1.40)
        slony1_funcs.sql (r1.77 -> r1.78)
    slony1-engine/src/parsestatements:
        Makefile (r1.2 -> r1.3)
    slony1-engine/src/slon:
        cleanup_thread.c (r1.30 -> r1.31)

-------------- next part --------------
Index: slony1_base.sql
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_base.sql,v
retrieving revision 1.29
retrieving revision 1.30
diff -Lsrc/backend/slony1_base.sql -Lsrc/backend/slony1_base.sql -u -w -r1.29 -r1.30
--- src/backend/slony1_base.sql
+++ src/backend/slony1_base.sql
@@ -442,6 +442,22 @@
 	(log_xid @NAMESPACE at .xxid_ops);
 
 
+-- ----------------------------------------------------------------------
+-- TABLE sl_registry
+-- ----------------------------------------------------------------------
+create table @NAMESPACE at .sl_registry (
+	reg_key				text primary key,
+	reg_int4			int4,
+	reg_text			text,
+	reg_timestamp		timestamp
+);
+comment on table @NAMESPACE at .sl_registry is 'Stores miscellaneous runtime data';
+comment on column @NAMESPACE at .sl_registry.reg_key is 'Unique key of the runtime option';
+comment on column @NAMESPACE at .sl_registry.reg_int4 is 'Option value if type int4';
+comment on column @NAMESPACE at .sl_registry.reg_text is 'Option value if type text';
+comment on column @NAMESPACE at .sl_registry.reg_timestamp is 'Option value if type timestamp';
+
+
 -- **********************************************************************
 -- * Views
 -- **********************************************************************
Index: slony1_funcs.sql
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_funcs.sql,v
retrieving revision 1.77
retrieving revision 1.78
diff -Lsrc/backend/slony1_funcs.sql -Lsrc/backend/slony1_funcs.sql -u -w -r1.77 -r1.78
--- src/backend/slony1_funcs.sql
+++ src/backend/slony1_funcs.sql
@@ -451,6 +451,182 @@
 
 
 -- ----------------------------------------------------------------------
+-- FUNCTION registry_set_int4(key, value);
+-- FUNCTION registry_get_int4(key, default);
+-- FUNCTION registry_set_text(key, value);
+-- FUNCTION registry_get_text(key, default);
+-- FUNCTION registry_set_timestamp(key, value);
+-- FUNCTION registry_get_timestamp(key, default);
+--
+--	Functions for accessing sl_registry
+-- ----------------------------------------------------------------------
+create or replace function @NAMESPACE at .registry_set_int4(text, int4)
+returns int4 as '
+DECLARE
+	p_key		alias for $1;
+	p_value		alias for $2;
+BEGIN
+	if p_value is null then
+		delete from @NAMESPACE at .sl_registry
+				where reg_key = p_key;
+	else
+		lock table @NAMESPACE at .sl_registry;
+		update @NAMESPACE at .sl_registry
+				set reg_int4 = p_value
+				where reg_key = p_key;
+		if not found then
+			insert into @NAMESPACE at .sl_registry (reg_key, reg_int4)
+					values (p_key, p_value);
+		end if;
+	end if;
+	return p_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_set_int4(text, int4) is
+'registry_set_int4(key, value)
+
+Set or delete a registry value';
+
+create or replace function @NAMESPACE at .registry_get_int4(text, int4)
+returns int4 as '
+DECLARE
+	p_key		alias for $1;
+	p_default	alias for $2;
+	v_value		int4;
+BEGIN
+	select reg_int4 into v_value from @NAMESPACE at .sl_registry
+			where reg_key = p_key;
+	if not found then 
+		v_value = p_default;
+		if p_default notnull then
+			perform @NAMESPACE at .registry_set_int4(p_key, p_default);
+		end if;
+	else
+		if v_value is null then
+			raise exception ''Slony-I: registry key % is not an int4 value'',
+					p_key;
+		end if;
+	end if;
+	return v_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_get_int4(text, int4) is
+'registry_get_int4(key, value)
+
+Get a registry value. If not present, set and return the default.';
+
+create or replace function @NAMESPACE at .registry_set_text(text, text)
+returns text as '
+DECLARE
+	p_key		alias for $1;
+	p_value		alias for $2;
+BEGIN
+	if p_value is null then
+		delete from @NAMESPACE at .sl_registry
+				where reg_key = p_key;
+	else
+		lock table @NAMESPACE at .sl_registry;
+		update @NAMESPACE at .sl_registry
+				set reg_text = p_value
+				where reg_key = p_key;
+		if not found then
+			insert into @NAMESPACE at .sl_registry (reg_key, reg_text)
+					values (p_key, p_value);
+		end if;
+	end if;
+	return p_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_set_text(text, text) is
+'registry_set_text(key, value)
+
+Set or delete a registry value';
+
+create or replace function @NAMESPACE at .registry_get_text(text, text)
+returns text as '
+DECLARE
+	p_key		alias for $1;
+	p_default	alias for $2;
+	v_value		text;
+BEGIN
+	select reg_text into v_value from @NAMESPACE at .sl_registry
+			where reg_key = p_key;
+	if not found then 
+		v_value = p_default;
+		if p_default notnull then
+			perform @NAMESPACE at .registry_set_text(p_key, p_default);
+		end if;
+	else
+		if v_value is null then
+			raise exception ''Slony-I: registry key % is not an text value'',
+					p_key;
+		end if;
+	end if;
+	return v_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_get_text(text, text) is
+'registry_get_text(key, value)
+
+Get a registry value. If not present, set and return the default.';
+
+create or replace function @NAMESPACE at .registry_set_timestamp(text, timestamp)
+returns timestamp as '
+DECLARE
+	p_key		alias for $1;
+	p_value		alias for $2;
+BEGIN
+	if p_value is null then
+		delete from @NAMESPACE at .sl_registry
+				where reg_key = p_key;
+	else
+		lock table @NAMESPACE at .sl_registry;
+		update @NAMESPACE at .sl_registry
+				set reg_timestamp = p_value
+				where reg_key = p_key;
+		if not found then
+			insert into @NAMESPACE at .sl_registry (reg_key, reg_timestamp)
+					values (p_key, p_value);
+		end if;
+	end if;
+	return p_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_set_timestamp(text, timestamp) is
+'registry_set_timestamp(key, value)
+
+Set or delete a registry value';
+
+create or replace function @NAMESPACE at .registry_get_timestamp(text, timestamp)
+returns timestamp as '
+DECLARE
+	p_key		alias for $1;
+	p_default	alias for $2;
+	v_value		timestamp;
+BEGIN
+	select reg_timestamp into v_value from @NAMESPACE at .sl_registry
+			where reg_key = p_key;
+	if not found then 
+		v_value = p_default;
+		if p_default notnull then
+			perform @NAMESPACE at .registry_set_timestamp(p_key, p_default);
+		end if;
+	else
+		if v_value is null then
+			raise exception ''Slony-I: registry key % is not an timestamp value'',
+					p_key;
+		end if;
+	end if;
+	return v_value;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .registry_get_timestamp(text, timestamp) is
+'registry_get_timestamp(key, value)
+
+Get a registry value. If not present, set and return the default.';
+
+
+-- ----------------------------------------------------------------------
 -- FUNCTION cleanupNodelock ()
 --
 --	Remove old entries from the nodelock table
@@ -5119,6 +5295,8 @@
 	-- ----
 	if v_current_status = 0 then
 		perform "pg_catalog".setval(''@NAMESPACE at .sl_log_status'', 3);
+		perform @NAMESPACE at .registry_set_timestamp(
+				''logswitch.laststart'', now()::timestamp);
 		raise notice ''Logswitch to sl_log_2 initiated'';
 		return 2;
 	end if;
@@ -5129,6 +5307,8 @@
 	-- ----
 	if v_current_status = 1 then
 		perform "pg_catalog".setval(''@NAMESPACE at .sl_log_status'', 2);
+		perform @NAMESPACE at .registry_set_timestamp(
+				''logswitch.laststart'', now()::timestamp);
 		raise notice ''Logswitch to sl_log_1 initiated'';
 		return 1;
 	end if;
@@ -5136,6 +5316,84 @@
 	raise exception ''Previous logswitch still in progress'';
 END;
 ' language plpgsql;
+comment on function @NAMESPACE at .logswitch_start() is
+'logswitch_start()
+
+Initiate a log table switch if none is in progress';
+
+
+-- ----------------------------------------------------------------------
+-- FUNCTION logswitch_weekly()
+--
+--	Called by slonik to ensure that a logswitch is done at least
+--  once a week. The default time is Sunday 2am.
+-- ----------------------------------------------------------------------
+create or replace function @NAMESPACE at .logswitch_weekly()
+returns int4 as '
+DECLARE
+	v_now			timestamp;
+	v_now_dow		int4;
+	v_auto_dow		int4;
+	v_auto_time		time;
+	v_auto_ts		timestamp;
+	v_lastrun		timestamp;
+	v_laststart		timestamp;
+	v_days_since	int4;
+BEGIN
+	-- ----
+	-- Check that today is the day to run at all
+	-- ----
+	v_auto_dow := @NAMESPACE at .registry_get_int4(
+			''logswitch_weekly.dow'', 0);
+	v_now := "pg_catalog".now();
+	v_now_dow := extract (DOW from v_now);
+	if v_now_dow <> v_auto_dow then
+		perform @NAMESPACE at .registry_set_timestamp(
+				''logswitch_weekly.lastrun'', v_now);
+		return 0;
+	end if;
+
+	-- ----
+	-- Check that the last run of this procedure was before and now is
+	-- after the time we should automatically switch logs.
+	-- ----
+	v_auto_time := @NAMESPACE at .registry_get_text(
+			''logswitch_weekly.time'', ''02:00'');
+	v_auto_ts := current_date + v_auto_time;
+	v_lastrun := @NAMESPACE at .registry_get_timestamp(
+			''logswitch_weekly.lastrun'', ''epoch'');
+	if v_lastrun >= v_auto_ts or v_now < v_auto_ts then
+		perform @NAMESPACE at .registry_set_timestamp(
+				''logswitch_weekly.lastrun'', v_now);
+		return 0;
+	end if;
+
+	-- ----
+	-- This is the moment configured in dow+time. Check that the
+	-- last logswitch was done more than 2 days ago.
+	-- ----
+	v_laststart := @NAMESPACE at .registry_get_timestamp(
+			''logswitch.laststart'', ''epoch'');
+	v_days_since := extract (days from (v_now - v_laststart));
+	if v_days_since < 2 then
+		perform @NAMESPACE at .registry_set_timestamp(
+				''logswitch_weekly.lastrun'', v_now);
+		return 0;
+	end if;
+
+	-- ----
+	-- Fire off an automatic logswitch
+	-- ----
+	perform @NAMESPACE at .logswitch_start();
+	perform @NAMESPACE at .registry_set_timestamp(
+			''logswitch_weekly.lastrun'', v_now);
+	return 1;
+END;
+' language plpgsql;
+comment on function @NAMESPACE at .logswitch_weekly() is
+'logswitch_weekly()
+
+Ensure a logswitch is done at least weekly';
 
 
 -- ----------------------------------------------------------------------
@@ -5215,6 +5473,10 @@
 	end if;
 END;
 ' language plpgsql;
+comment on function @NAMESPACE at .logswitch_finish() is
+'logswitch_finish()
+
+Attempt to finalize a log table switch in progress';
 
 
 -- ----------------------------------------------------------------------
@@ -5324,6 +5586,19 @@
 		execute ''drop function @NAMESPACE at .truncateTable(text)'';
 	end if;
 
+	-- ----
+	-- Changes for 1.2
+	-- ----
+	if p_old IN (''1.0.2'', ''1.0.5'', ''1.0.6'', ''1.1.0'', ''1.1.1'', ''1.1.2'', ''1.1.3'') then
+		-- Add new table sl_registry
+		execute ''create table @NAMESPACE at .sl_registry (
+						reg_key			text primay key,
+						reg_int4		int4,
+						reg_text		text,
+						reg_timestamp	timestamp
+					)'';
+	end if;
+
 	return p_old;
 end;
 ' language plpgsql;
Index: slony1_funcs.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_funcs.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -Lsrc/backend/slony1_funcs.c -Lsrc/backend/slony1_funcs.c -u -w -r1.39 -r1.40
--- src/backend/slony1_funcs.c
+++ src/backend/slony1_funcs.c
@@ -1449,6 +1449,9 @@
 		VARATT_SIZEP(cs->cmdtype_D) = VARHDRSZ + 1;
 		*VARDATA(cs->cmdtype_D) = 'D';
 
+		/*
+		 * And the plan to read the current log_status.
+		 */
 		sprintf(query, "SELECT last_value::int4 FROM %s.sl_log_status",
 				cs->clusterident);
 		cs->plan_get_logstatus = SPI_saveplan(SPI_prepare(query, 0, NULL));
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/parsestatements/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lsrc/parsestatements/Makefile -Lsrc/parsestatements/Makefile -u -w -r1.2 -r1.3
--- src/parsestatements/Makefile
+++ src/parsestatements/Makefile
@@ -17,3 +17,7 @@
 	cmp ./test_sql.log ./test_sql.expected
 
 install:
+
+clean:
+	rm -f scanner.o test-scanner test-scanner.o
+	rm -f *.log
Index: cleanup_thread.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/cleanup_thread.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -Lsrc/slon/cleanup_thread.c -Lsrc/slon/cleanup_thread.c -u -w -r1.30 -r1.31
--- src/slon/cleanup_thread.c
+++ src/slon/cleanup_thread.c
@@ -123,8 +123,7 @@
 	 * cluster will run into conflicts due to trying to vacuum pg_listener
 	 * concurrently
 	 */
-	// while (sched_wait_time(conn, SCHED_WAIT_SOCK_READ, SLON_CLEANUP_SLEEP * 1000 + vac_bias + (rand() % (SLON_CLEANUP_SLEEP * 166))) == SCHED_STATUS_OK)
-	while (sched_wait_time(conn, SCHED_WAIT_SOCK_READ, 300 * 1000) == SCHED_STATUS_OK)
+	while (sched_wait_time(conn, SCHED_WAIT_SOCK_READ, SLON_CLEANUP_SLEEP * 1000 + vac_bias + (rand() % (SLON_CLEANUP_SLEEP * 166))) == SCHED_STATUS_OK)
 	{
 		/*
 		 * Call the stored procedure cleanupEvent()
@@ -202,6 +201,23 @@
 				break;
 			}
 			PQclear(res2);
+
+			/*
+			 * Eventually kick off a logswitch. This might fail,
+			 * but this is not really slon's problem, so we just
+			 * shrug and move on if it does.
+			 */
+			slon_mkquery(&query2,
+						 "select %s.logswitch_weekly(); ",
+						 rtcfg_namespace);
+			res2 = PQexec(dbconn, dstring_data(&query2));
+			if (PQresultStatus(res2) != PGRES_TUPLES_OK)
+			{
+				slon_log(SLON_WARN,
+						 "cleanupThread: \"%s\" - %s",
+						 dstring_data(&query2), PQresultErrorMessage(res2));
+			}
+			PQclear(res2);
 		}
 		PQclear(res);
 		gettimeofday(&tv_end, NULL);



More information about the Slony1-commit mailing list