Skip to content

Commit

Permalink
Create a _sum_log_stat_group() function to directly compute the sum o…
Browse files Browse the repository at this point in the history
…f log rows. This avoids calls to the emaj_log_stat_group() function by the _set_mark_groups(), _delete_intermediate_mark_group() and emaj_get_consolidable_rollbacks() functions. Adjust the 3 functions accordingly. Also improve the coding of the emaj_log_stat_group() function.
  • Loading branch information
beaud76 committed Sep 18, 2017
1 parent 3f319fb commit 69353b0
Show file tree
Hide file tree
Showing 20 changed files with 202 additions and 149 deletions.
87 changes: 67 additions & 20 deletions sql/emaj--2.1.0--next_version.sql
Expand Up @@ -951,8 +951,8 @@ $_delete_log_tbl$
EXECUTE 'DELETE FROM ' || quote_ident(r_rel.rel_log_schema) || '.' || quote_ident(r_rel.rel_log_table) || ' WHERE emaj_gid > ' || v_lastGlobalSeq;
GET DIAGNOSTICS v_nbRows = ROW_COUNT;
-- record the sequence holes generated by the delete operation
-- this is due to the fact that log sequences are not rolled back, this information will be used by the emaj_log_stat_group
-- function (and indirectly by emaj_estimate_rollback_group() and emaj_estimate_rollback_groups())
-- this is due to the fact that log sequences are not rolled back, this information will be used by the emaj_log_stat_group() function
-- (and indirectly by emaj_estimate_rollback_group() and emaj_estimate_rollback_groups())
-- first delete, if exist, sequence holes that have disappeared with the rollback
DELETE FROM emaj.emaj_seq_hole
WHERE sqhl_schema = r_rel.rel_schema AND sqhl_table = r_rel.rel_tblseq
Expand Down Expand Up @@ -2287,9 +2287,9 @@ $_set_mark_groups$
v_nbTb = v_nbTb + 1;
END LOOP;
-- record the number of log rows for the old last mark of each group
-- the statement returns no row in case of emaj_start_group(s)
-- the statement updates no row in case of emaj_start_group(s)
UPDATE emaj.emaj_mark m SET mark_log_rows_before_next =
coalesce( (SELECT sum(stat_rows) FROM emaj.emaj_log_stat_group(m.mark_group,'EMAJ_LAST_MARK',NULL)) ,0)
coalesce(emaj._sum_log_stat_group(m.mark_group,emaj._get_mark_time_id(m.mark_group,'EMAJ_LAST_MARK'),NULL),0)
WHERE mark_group = ANY (v_groupNames)
AND (mark_group, mark_id) IN -- select only the last non deleted mark of each concerned group
(SELECT mark_group, MAX(mark_id) FROM emaj.emaj_mark
Expand Down Expand Up @@ -2546,6 +2546,8 @@ $_delete_intermediate_mark_group$
DECLARE
v_previousMark TEXT;
v_nextMark TEXT;
v_previousMarkTimeId BIGINT;
v_nextMarkTimeId BIGINT;
BEGIN
-- delete the sequences related to the mark to delete
-- delete first data related to the application sequences currently belonging to the group
Expand All @@ -2564,19 +2566,18 @@ $_delete_intermediate_mark_group$
DELETE FROM emaj.emaj_mark WHERE mark_group = v_groupName AND mark_name = v_markName;
-- adjust the mark_log_rows_before_next column of the previous mark
-- get the name of the mark immediately preceeding the mark to delete
SELECT mark_name INTO v_previousMark FROM emaj.emaj_mark
SELECT mark_name, mark_time_id INTO v_previousMark, v_previousMarkTimeId FROM emaj.emaj_mark
WHERE mark_group = v_groupName AND mark_id < v_markId ORDER BY mark_id DESC LIMIT 1;
-- get the name of the first mark succeeding the mark to delete
SELECT mark_name INTO v_nextMark FROM emaj.emaj_mark
SELECT mark_name, mark_time_id INTO v_nextMark, v_nextMarkTimeId FROM emaj.emaj_mark
WHERE mark_group = v_groupName AND mark_id > v_markId ORDER BY mark_id LIMIT 1;
IF NOT FOUND THEN
-- no next mark, so update the previous mark with NULL
UPDATE emaj.emaj_mark SET mark_log_rows_before_next = NULL
WHERE mark_group = v_groupName AND mark_name = v_previousMark;
ELSE
-- update the previous mark with the emaj_log_stat_group() call's result
UPDATE emaj.emaj_mark SET mark_log_rows_before_next =
(SELECT sum(stat_rows) FROM emaj.emaj_log_stat_group(v_groupName, v_previousMark, v_nextMark))
-- update the previous mark with the _sum_log_stat_group() call's result
UPDATE emaj.emaj_mark SET mark_log_rows_before_next = emaj._sum_log_stat_group(v_groupName, v_previousMarkTimeId, v_nextMarkTimeId)
WHERE mark_group = v_groupName AND mark_name = v_previousMark;
END IF;
-- reset the mark_logged_rlbk_target_mark column to null for other marks of the group
Expand Down Expand Up @@ -3653,6 +3654,31 @@ $_delete_between_marks_group$
END;
$_delete_between_marks_group$;

CREATE OR REPLACE FUNCTION emaj.emaj_get_consolidable_rollbacks()
RETURNS SETOF emaj.emaj_consolidable_rollback_type LANGUAGE plpgsql AS
$emaj_get_consolidable_rollbacks$
-- This function returns the list of logged rollback operations that can be consolidated, defined as a marks range for a group.
-- It doesn't need input parameter.
-- It returns a set of emaj_consolidable_rollback_type records, sorted by ascending rollback time.
-- The cons_group and cons_end_rlbk_mark_name returned columns can be used as input parameters for the emaj_consolidate_rollback_group() function.
BEGIN
-- search and return all marks range corresponding to any logged rollback operation
RETURN QUERY
SELECT m1.mark_group AS cons_group,
m2.mark_name AS cons_target_rlbk_mark_name, m2.mark_id AS cons_target_rlbk_mark_id,
m1.mark_name AS cons_end_rlbk_mark_name, m1.mark_id AS cons_end_rlbk_mark_id,
cast(coalesce(emaj._sum_log_stat_group(m1.mark_group, m2.mark_time_id, m1.mark_time_id),0) AS BIGINT) AS cons_rows,
cast((SELECT count(*) FROM emaj.emaj_mark m3
WHERE m3.mark_group = m1.mark_group AND m3.mark_id > m2.mark_id AND m3.mark_id < m1.mark_id) AS INT) AS cons_marks
FROM emaj.emaj_mark m1
JOIN emaj.emaj_mark m2 ON (m2.mark_name = m1.mark_logged_rlbk_target_mark AND m2.mark_group = m1.mark_group)
WHERE m1.mark_logged_rlbk_target_mark IS NOT NULL
ORDER BY m1.mark_id;
END;
$emaj_get_consolidable_rollbacks$;
COMMENT ON FUNCTION emaj.emaj_get_consolidable_rollbacks() IS
$$Returns the list of logged rollback operations that can be consolidated.$$;

CREATE OR REPLACE FUNCTION emaj._reset_groups(v_groupNames TEXT[])
RETURNS INT LANGUAGE plpgsql SECURITY DEFINER AS
$_reset_groups$
Expand Down Expand Up @@ -3716,19 +3742,16 @@ RETURNS SETOF emaj.emaj_log_stat_type LANGUAGE plpgsql AS
$emaj_log_stat_group$
-- This function returns statistics on row updates executed between 2 marks or between a mark and the current situation.
-- It is used to quickly get simple statistics of updates logged between 2 marks (i.e. for one or several processing)
-- It is also used to estimate the cost of a rollback to a specified mark
-- These statistics are computed using the serial id of log tables and holes is sequences recorded into emaj_seq_hole at rollback time
-- Input: group name, the 2 mark names defining a range
-- a NULL value or an empty string as first_mark indicates the first recorded mark
-- a NULL value or an empty string as last_mark indicates the current situation
-- Use a NULL or an empty string as last_mark to know the number of rows to rollback to reach the mark specified by the first_mark parameter.
-- The keyword 'EMAJ_LAST_MARK' can be used as first or last mark to specify the last set mark.
-- Output: table of log rows by table (including tables with 0 rows to rollback)
-- Output: set of log rows by table (including tables with 0 rows to rollback)
DECLARE
v_realFirstMark TEXT;
v_realLastMark TEXT;
v_firstMarkId BIGINT;
v_lastMarkId BIGINT;
v_firstMarkTimeId BIGINT;
v_lastMarkTimeId BIGINT;
v_firstMarkTs TIMESTAMPTZ;
Expand All @@ -3743,30 +3766,30 @@ $emaj_log_stat_group$
IF v_firstMark IS NULL OR v_firstMark = '' THEN
-- if no mark exists for the group (just after emaj_create_group() or emaj_reset_group() functions call),
-- v_realFirstMark remains NULL
SELECT mark_name, mark_id, mark_time_id, time_clock_timestamp INTO v_realFirstMark, v_firstMarkId, v_firstMarkTimeId, v_firstMarkTs
SELECT mark_name, mark_time_id, time_clock_timestamp INTO v_realFirstMark, v_firstMarkTimeId, v_firstMarkTs
FROM emaj.emaj_mark, emaj.emaj_time_stamp
WHERE time_id = mark_time_id AND mark_group = v_groupName
ORDER BY mark_id LIMIT 1;
ELSE
-- else, check and retrieve the name, timestamp and last sequ_hole id of the supplied first mark for the group
-- else, check and retrieve the name and the timestamp id of the supplied first mark for the group
SELECT emaj._get_mark_name(v_groupName,v_firstMark) INTO v_realFirstMark;
IF v_realFirstMark IS NULL THEN
RAISE EXCEPTION 'emaj_log_stat_group: The start mark "%" is unknown for the group "%".', v_firstMark, v_groupName;
END IF;
SELECT mark_id, mark_time_id, time_clock_timestamp INTO v_firstMarkId, v_firstMarkTimeId, v_firstMarkTs
SELECT mark_time_id, time_clock_timestamp INTO v_firstMarkTimeId, v_firstMarkTs
FROM emaj.emaj_mark, emaj.emaj_time_stamp
WHERE time_id = mark_time_id AND mark_group = v_groupName AND mark_name = v_realFirstMark;
END IF;
-- if a last mark name is supplied, check and retrieve the name, timestamp and last sequ_hole id of the supplied end mark for the group
-- if a last mark name is supplied, check and retrieve the name, and the timestamp id of the supplied end mark for the group
IF v_lastMark IS NOT NULL AND v_lastMark <> '' THEN
SELECT emaj._get_mark_name(v_groupName,v_lastMark) INTO v_realLastMark;
IF v_realLastMark IS NULL THEN
RAISE EXCEPTION 'emaj_log_stat_group: The end mark "%" is unknown for the group "%".', v_lastMark, v_groupName;
END IF;
SELECT mark_id, mark_time_id, time_clock_timestamp INTO v_lastMarkId, v_lastMarkTimeId, v_lastMarkTs
SELECT mark_time_id, time_clock_timestamp INTO v_lastMarkTimeId, v_lastMarkTs
FROM emaj.emaj_mark, emaj.emaj_time_stamp
WHERE time_id = mark_time_id AND mark_group = v_groupName AND mark_name = v_realLastMark;
-- if last mark is null or empty, v_realLastMark, v_lastMarkTimeId, v_lastMarkTs and v_lastLastSeqHoleId remain NULL
-- if last mark is null or empty, v_realLastMark, v_lastMarkTimeId and v_lastMarkTs remain NULL
END IF;
-- check that the first_mark < end_mark
IF v_lastMarkTimeId IS NOT NULL AND v_firstMarkTimeId > v_lastMarkTimeId THEN
Expand All @@ -3781,11 +3804,34 @@ $emaj_log_stat_group$
FROM emaj.emaj_relation
WHERE rel_group = v_groupName AND rel_kind = 'r' AND upper_inf(rel_time_range)
ORDER BY rel_priority, rel_schema, rel_tblseq;
END;
END;
$emaj_log_stat_group$;
COMMENT ON FUNCTION emaj.emaj_log_stat_group(TEXT,TEXT,TEXT) IS
$$Returns global statistics about logged events for an E-Maj group between 2 marks.$$;

CREATE OR REPLACE FUNCTION emaj._sum_log_stat_group(v_groupName TEXT, v_firstMarkTimeId BIGINT, v_lastMarkTimeId BIGINT)
RETURNS BIGINT LANGUAGE plpgsql AS
$_sum_log_stat_group$
-- This function the sum of row updates executed between 2 marks or between a mark and the current situation for a tables group.
-- It is used by several functions to set the mark_log_rows_before_next column of the emaj_mark table.
-- The sum is computed for each table of the group by calling the _log_stat_tbl() function.
-- Input: group name, the time id of both marks defining a time range
-- a NULL value as last_mark_time_id indicates the current situation
-- Checks on input values are performed in calling functions.
-- Output: sum of log rows for the group between both marks
BEGIN
-- Directly return 0 if the firstMarkTimeId is set to NULL (ie no mark exists for the group - just after emaj_create_group() or emaj_reset_group() functions call)
IF v_firstMarkTimeId IS NULL THEN
RETURN 0;
END IF;
-- for each table currently belonging to the group, add the number of log rows and return the sum
--TODO ok ?
RETURN sum(emaj._log_stat_tbl(emaj_relation, v_firstMarkTimeId, v_lastMarkTimeId))
FROM emaj.emaj_relation
WHERE rel_group = v_groupName AND rel_kind = 'r' AND upper_inf(rel_time_range);
END;
$_sum_log_stat_group$;

CREATE OR REPLACE FUNCTION emaj.emaj_detailed_log_stat_group(v_groupName TEXT, v_firstMark TEXT, v_lastMark TEXT)
RETURNS SETOF emaj.emaj_detailed_log_stat_type LANGUAGE plpgsql AS
$emaj_detailed_log_stat_group$
Expand Down Expand Up @@ -4766,6 +4812,7 @@ REVOKE SELECT ON TABLE emaj.emaj_param FROM emaj_viewer;
GRANT EXECUTE ON FUNCTION emaj._get_mark_name(v_groupName TEXT, v_mark TEXT) TO emaj_viewer;
GRANT EXECUTE ON FUNCTION emaj._get_mark_time_id(v_groupName TEXT, v_mark TEXT) TO emaj_viewer;
GRANT EXECUTE ON FUNCTION emaj._log_stat_tbl(r_rel emaj.emaj_relation, v_firstMarkTimeId BIGINT, v_lastMarkTimeId BIGINT) TO emaj_viewer;
GRANT EXECUTE ON FUNCTION emaj._sum_log_stat_group(v_groupName TEXT, v_firstMarkTimeId BIGINT, v_lastMarkTimeId BIGINT) TO emaj_viewer;

------------------------------------
-- --
Expand Down

0 comments on commit 69353b0

Please sign in to comment.