Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create PostgreSQL migrations for version 3.5.2 #7490

Merged
merged 5 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
-- Run this migration for upgrading the PostgreSQL clustering table and routines for deployments created before 3.6.0

BEGIN;

-- Change date type

ALTER TABLE OrleansMembershipVersionTable
ALTER COLUMN Timestamp TYPE TIMESTAMPTZ(3) USING Timestamp AT TIME ZONE 'UTC';

ALTER TABLE OrleansMembershipTable
ALTER COLUMN StartTime TYPE TIMESTAMPTZ(3) USING StartTime AT TIME ZONE 'UTC',
ALTER COLUMN IAmAliveTime TYPE TIMESTAMPTZ(3) USING IAmAliveTime AT TIME ZONE 'UTC';

-- Recreate routines

CREATE OR REPLACE FUNCTION update_i_am_alive_time(
deployment_id OrleansMembershipTable.DeploymentId%TYPE,
address_arg OrleansMembershipTable.Address%TYPE,
port_arg OrleansMembershipTable.Port%TYPE,
generation_arg OrleansMembershipTable.Generation%TYPE,
i_am_alive_time OrleansMembershipTable.IAmAliveTime%TYPE)
RETURNS void AS
$func$
BEGIN
-- This is expected to never fail by Orleans, so return value
-- is not needed nor is it checked.
UPDATE OrleansMembershipTable as d
SET
IAmAliveTime = i_am_alive_time
WHERE
d.DeploymentId = deployment_id AND deployment_id IS NOT NULL
AND d.Address = address_arg AND address_arg IS NOT NULL
AND d.Port = port_arg AND port_arg IS NOT NULL
AND d.Generation = generation_arg AND generation_arg IS NOT NULL;
END
$func$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION insert_membership(
DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,
AddressArg OrleansMembershipTable.Address%TYPE,
PortArg OrleansMembershipTable.Port%TYPE,
GenerationArg OrleansMembershipTable.Generation%TYPE,
SiloNameArg OrleansMembershipTable.SiloName%TYPE,
HostNameArg OrleansMembershipTable.HostName%TYPE,
StatusArg OrleansMembershipTable.Status%TYPE,
ProxyPortArg OrleansMembershipTable.ProxyPort%TYPE,
StartTimeArg OrleansMembershipTable.StartTime%TYPE,
IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,
VersionArg OrleansMembershipVersionTable.Version%TYPE)
RETURNS TABLE(row_count integer) AS
$func$
DECLARE
RowCountVar int := 0;
BEGIN

BEGIN
INSERT INTO OrleansMembershipTable
(
DeploymentId,
Address,
Port,
Generation,
SiloName,
HostName,
Status,
ProxyPort,
StartTime,
IAmAliveTime
)
SELECT
DeploymentIdArg,
AddressArg,
PortArg,
GenerationArg,
SiloNameArg,
HostNameArg,
StatusArg,
ProxyPortArg,
StartTimeArg,
IAmAliveTimeArg
ON CONFLICT (DeploymentId, Address, Port, Generation) DO
NOTHING;


GET DIAGNOSTICS RowCountVar = ROW_COUNT;

UPDATE OrleansMembershipVersionTable
SET
Timestamp = now(),
Version = Version + 1
WHERE
DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL
AND Version = VersionArg AND VersionArg IS NOT NULL
AND RowCountVar > 0;

GET DIAGNOSTICS RowCountVar = ROW_COUNT;

ASSERT RowCountVar <> 0, 'no rows affected, rollback';


RETURN QUERY SELECT RowCountVar;
EXCEPTION
WHEN assert_failure THEN
RETURN QUERY SELECT RowCountVar;
END;

END
$func$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION update_membership(
DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,
AddressArg OrleansMembershipTable.Address%TYPE,
PortArg OrleansMembershipTable.Port%TYPE,
GenerationArg OrleansMembershipTable.Generation%TYPE,
StatusArg OrleansMembershipTable.Status%TYPE,
SuspectTimesArg OrleansMembershipTable.SuspectTimes%TYPE,
IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,
VersionArg OrleansMembershipVersionTable.Version%TYPE
)
RETURNS TABLE(row_count integer) AS
$func$
DECLARE
RowCountVar int := 0;
BEGIN

BEGIN

UPDATE OrleansMembershipVersionTable
SET
Timestamp = now(),
Version = Version + 1
WHERE
DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL
AND Version = VersionArg AND VersionArg IS NOT NULL;


GET DIAGNOSTICS RowCountVar = ROW_COUNT;

UPDATE OrleansMembershipTable
SET
Status = StatusArg,
SuspectTimes = SuspectTimesArg,
IAmAliveTime = IAmAliveTimeArg
WHERE
DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL
AND Address = AddressArg AND AddressArg IS NOT NULL
AND Port = PortArg AND PortArg IS NOT NULL
AND Generation = GenerationArg AND GenerationArg IS NOT NULL
AND RowCountVar > 0;


GET DIAGNOSTICS RowCountVar = ROW_COUNT;

ASSERT RowCountVar <> 0, 'no rows affected, rollback';


RETURN QUERY SELECT RowCountVar;
EXCEPTION
WHEN assert_failure THEN
RETURN QUERY SELECT RowCountVar;
END;

END
$func$ LANGUAGE plpgsql;

COMMIT;
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
-- Run this migration for upgrading the PostgreSQL persistence table and routines for deployments created before 3.6.0

BEGIN;

-- Change date type

ALTER TABLE OrleansStorage
ALTER COLUMN modifiedon TYPE TIMESTAMPTZ USING modifiedon AT TIME ZONE 'UTC';

-- Recreate routines

CREATE OR REPLACE FUNCTION writetostorage(
_grainidhash integer,
_grainidn0 bigint,
_grainidn1 bigint,
_graintypehash integer,
_graintypestring character varying,
_grainidextensionstring character varying,
_serviceid character varying,
_grainstateversion integer,
_payloadbinary bytea,
_payloadjson text,
_payloadxml xml)
RETURNS TABLE(newgrainstateversion integer)
LANGUAGE 'plpgsql'
AS $function$
DECLARE
_newGrainStateVersion integer := _GrainStateVersion;
RowCountVar integer := 0;

BEGIN

-- Grain state is not null, so the state must have been read from the storage before.
-- Let's try to update it.
--
-- When Orleans is running in normal, non-split state, there will
-- be only one grain with the given ID and type combination only. This
-- grain saves states mostly serially if Orleans guarantees are upheld. Even
-- if not, the updates should work correctly due to version number.
--
-- In split brain situations there can be a situation where there are two or more
-- grains with the given ID and type combination. When they try to INSERT
-- concurrently, the table needs to be locked pessimistically before one of
-- the grains gets @GrainStateVersion = 1 in return and the other grains will fail
-- to update storage. The following arrangement is made to reduce locking in normal operation.
--
-- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed
-- and throws an InconsistentStateException.
--
-- See further information at https://dotnet.github.io/orleans/Documentation/Core-Features/Grain-Persistence.html.
IF _GrainStateVersion IS NOT NULL
THEN
UPDATE OrleansStorage
SET
PayloadBinary = _PayloadBinary,
PayloadJson = _PayloadJson,
PayloadXml = _PayloadXml,
ModifiedOn = (now() at time zone 'utc'),
Version = Version + 1

WHERE
GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL
AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL
AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL
AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL
AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL
AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)
AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL
AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL;

GET DIAGNOSTICS RowCountVar = ROW_COUNT;
IF RowCountVar > 0
THEN
_newGrainStateVersion := _GrainStateVersion + 1;
END IF;
END IF;

-- The grain state has not been read. The following locks rather pessimistically
-- to ensure only one INSERT succeeds.
IF _GrainStateVersion IS NULL
THEN
INSERT INTO OrleansStorage
(
GrainIdHash,
GrainIdN0,
GrainIdN1,
GrainTypeHash,
GrainTypeString,
GrainIdExtensionString,
ServiceId,
PayloadBinary,
PayloadJson,
PayloadXml,
ModifiedOn,
Version
)
SELECT
_GrainIdHash,
_GrainIdN0,
_GrainIdN1,
_GrainTypeHash,
_GrainTypeString,
_GrainIdExtensionString,
_ServiceId,
_PayloadBinary,
_PayloadJson,
_PayloadXml,
now(),
1
WHERE NOT EXISTS
(
-- There should not be any version of this grain state.
SELECT 1
FROM OrleansStorage
WHERE
GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL
AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL
AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL
AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL
AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL
AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)
AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL
);

GET DIAGNOSTICS RowCountVar = ROW_COUNT;
IF RowCountVar > 0
THEN
_newGrainStateVersion := 1;
END IF;
END IF;

RETURN QUERY SELECT _newGrainStateVersion AS NewGrainStateVersion;
END

$function$;

COMMIT;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
-- Run this migration for upgrading the PostgreSQL reminder table and routines for deployments created before 3.6.0

BEGIN;

-- Change date type

ALTER TABLE OrleansRemindersTable
ALTER COLUMN StartTime TYPE TIMESTAMPTZ(3) USING StartTime AT TIME ZONE 'UTC';

-- Recreate routines

CREATE OR REPLACE FUNCTION upsert_reminder_row(
ServiceIdArg OrleansRemindersTable.ServiceId%TYPE,
GrainIdArg OrleansRemindersTable.GrainId%TYPE,
ReminderNameArg OrleansRemindersTable.ReminderName%TYPE,
StartTimeArg OrleansRemindersTable.StartTime%TYPE,
PeriodArg OrleansRemindersTable.Period%TYPE,
GrainHashArg OrleansRemindersTable.GrainHash%TYPE
)
RETURNS TABLE(version integer) AS
$func$
DECLARE
VersionVar int := 0;
BEGIN

INSERT INTO OrleansRemindersTable
(
ServiceId,
GrainId,
ReminderName,
StartTime,
Period,
GrainHash,
Version
)
SELECT
ServiceIdArg,
GrainIdArg,
ReminderNameArg,
StartTimeArg,
PeriodArg,
GrainHashArg,
0
ON CONFLICT (ServiceId, GrainId, ReminderName)
DO UPDATE SET
StartTime = excluded.StartTime,
Period = excluded.Period,
GrainHash = excluded.GrainHash,
Version = OrleansRemindersTable.Version + 1
RETURNING
OrleansRemindersTable.Version INTO STRICT VersionVar;

RETURN QUERY SELECT VersionVar AS versionr;

END
$func$ LANGUAGE plpgsql;

COMMIT;