-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically. CREATE TABLE OrleansMembershipVersionTable ( DeploymentId varchar(150) NOT NULL, Timestamp timestamptz(3) NOT NULL DEFAULT now(), Version integer NOT NULL DEFAULT 0, CONSTRAINT PK_OrleansMembershipVersionTable_DeploymentId PRIMARY KEY(DeploymentId) ); -- Every silo instance has a row in the membership table. CREATE TABLE OrleansMembershipTable ( DeploymentId varchar(150) NOT NULL, Address varchar(45) NOT NULL, Port integer NOT NULL, Generation integer NOT NULL, SiloName varchar(150) NOT NULL, HostName varchar(150) NOT NULL, Status integer NOT NULL, ProxyPort integer NULL, SuspectTimes varchar(8000) NULL, StartTime timestamptz(3) NOT NULL, IAmAliveTime timestamptz(3) NOT NULL, CONSTRAINT PK_MembershipTable_DeploymentId PRIMARY KEY(DeploymentId, Address, Port, Generation), CONSTRAINT FK_MembershipTable_MembershipVersionTable_DeploymentId FOREIGN KEY (DeploymentId) REFERENCES OrleansMembershipVersionTable (DeploymentId) ); CREATE 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; INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'UpdateIAmAlivetimeKey',' -- This is expected to never fail by Orleans, so return value -- is not needed nor is it checked. SELECT * from update_i_am_alive_time( @DeploymentId, @Address, @Port, @Generation, @IAmAliveTime ); '); CREATE FUNCTION insert_membership_version( DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE ) RETURNS TABLE(row_count integer) AS $func$ DECLARE RowCountVar int := 0; BEGIN BEGIN INSERT INTO OrleansMembershipVersionTable ( DeploymentId ) SELECT DeploymentIdArg ON CONFLICT (DeploymentId) DO NOTHING; 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; INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'InsertMembershipVersionKey',' SELECT * FROM insert_membership_version( @DeploymentId ); '); CREATE 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; INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'InsertMembershipKey',' SELECT * FROM insert_membership( @DeploymentId, @Address, @Port, @Generation, @SiloName, @HostName, @Status, @ProxyPort, @StartTime, @IAmAliveTime, @Version ); '); CREATE 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; INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'UpdateMembershipKey',' SELECT * FROM update_membership( @DeploymentId, @Address, @Port, @Generation, @Status, @SuspectTimes, @IAmAliveTime, @Version ); '); INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'MembershipReadRowKey',' SELECT v.DeploymentId, m.Address, m.Port, m.Generation, m.SiloName, m.HostName, m.Status, m.ProxyPort, m.SuspectTimes, m.StartTime, m.IAmAliveTime, v.Version FROM OrleansMembershipVersionTable v -- This ensures the version table will returned even if there is no matching membership row. LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId AND Address = @Address AND @Address IS NOT NULL AND Port = @Port AND @Port IS NOT NULL AND Generation = @Generation AND @Generation IS NOT NULL WHERE v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL; '); INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'MembershipReadAllKey',' SELECT v.DeploymentId, m.Address, m.Port, m.Generation, m.SiloName, m.HostName, m.Status, m.ProxyPort, m.SuspectTimes, m.StartTime, m.IAmAliveTime, v.Version FROM OrleansMembershipVersionTable v LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId WHERE v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL; '); INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'DeleteMembershipTableEntriesKey',' DELETE FROM OrleansMembershipTable WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL; DELETE FROM OrleansMembershipVersionTable WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL; '); INSERT INTO OrleansQuery(QueryKey, QueryText) VALUES ( 'GatewaysQueryKey',' SELECT Address, ProxyPort, Generation FROM OrleansMembershipTable WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL AND Status = @Status AND @Status IS NOT NULL AND ProxyPort > 0; ');