merged from gramsrv upstream
This commit is contained in:
parent
79c64ee916
commit
21a0856587
651 changed files with 54774 additions and 4590 deletions
|
|
@ -0,0 +1,245 @@
|
|||
-- Advance one explicit invokeWithLayer observation without paying one client
|
||||
-- round trip for every lock, comparison and projection update. The caller
|
||||
-- still owns the surrounding transaction/savepoint so identity_changed can
|
||||
-- roll the complete attempt back and retry with a fresh READ COMMITTED view.
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.telesrv_advance_auth_session_layer(
|
||||
p_raw_auth_key_id bigint,
|
||||
p_session_id bigint,
|
||||
p_layer integer,
|
||||
p_msg_id bigint,
|
||||
p_expires_at timestamptz
|
||||
)
|
||||
RETURNS TABLE (
|
||||
advance_status text,
|
||||
current_layer integer,
|
||||
current_msg_id bigint,
|
||||
current_observation_id bigint,
|
||||
current_expires_at timestamptz,
|
||||
shared_default boolean,
|
||||
applied boolean
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_now timestamptz := now();
|
||||
v_hint_expiry integer;
|
||||
v_hint_perm_id bigint;
|
||||
v_hint_bound boolean := false;
|
||||
v_hint_has_identity boolean := false;
|
||||
v_hint_identity_id bigint;
|
||||
v_raw_expiry integer;
|
||||
v_actual_perm_id bigint;
|
||||
v_actual_bound boolean := false;
|
||||
v_actual_has_identity boolean := false;
|
||||
v_actual_identity_id bigint;
|
||||
v_perm_expiry integer;
|
||||
v_current_found boolean := false;
|
||||
v_current_layer integer := 0;
|
||||
v_current_msg_id bigint := 0;
|
||||
v_current_observation_id bigint := 0;
|
||||
v_current_expires_at timestamptz := p_expires_at;
|
||||
v_shared_default boolean := false;
|
||||
v_observation_id bigint;
|
||||
v_key_ids bigint[];
|
||||
v_updated integer;
|
||||
BEGIN
|
||||
IF p_layer <= 0
|
||||
OR p_msg_id <= 0
|
||||
OR p_msg_id % 4 <> 0
|
||||
OR (p_msg_id & 4294967295) = 0
|
||||
OR p_expires_at IS NULL
|
||||
OR NOT v_now < p_expires_at
|
||||
OR p_expires_at - interval '301 seconds' > v_now + interval '30 seconds'
|
||||
THEN
|
||||
RETURN QUERY SELECT
|
||||
'evidence_invalid'::text, 0, 0::bigint, 0::bigint,
|
||||
COALESCE(p_expires_at, v_now), false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- Lock-free identity hint. It is deliberately revalidated after the raw
|
||||
-- row lock; a newly committed first bind returns identity_changed rather
|
||||
-- than taking a permanent identity lock in raw->identity order.
|
||||
SELECT key.expires_at, binding.perm_auth_key_id
|
||||
INTO v_hint_expiry, v_hint_perm_id
|
||||
FROM public.auth_keys AS key
|
||||
LEFT JOIN public.temp_auth_key_bindings AS binding
|
||||
ON binding.temp_auth_key_id = key.auth_key_id
|
||||
WHERE key.auth_key_id = p_raw_auth_key_id;
|
||||
IF NOT FOUND THEN
|
||||
RETURN QUERY SELECT
|
||||
'auth_key_not_found'::text, 0, 0::bigint, 0::bigint,
|
||||
p_expires_at, false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
v_hint_bound := v_hint_perm_id IS NOT NULL;
|
||||
v_hint_has_identity := v_hint_bound OR v_hint_expiry = 0;
|
||||
IF v_hint_has_identity THEN
|
||||
v_hint_identity_id := CASE
|
||||
WHEN v_hint_bound THEN v_hint_perm_id
|
||||
ELSE p_raw_auth_key_id
|
||||
END;
|
||||
PERFORM pg_advisory_xact_lock(
|
||||
1096111176::integer,
|
||||
hashint8(v_hint_identity_id)::integer
|
||||
);
|
||||
END IF;
|
||||
|
||||
SELECT key.expires_at
|
||||
INTO v_raw_expiry
|
||||
FROM public.auth_keys AS key
|
||||
WHERE key.auth_key_id = p_raw_auth_key_id
|
||||
FOR UPDATE;
|
||||
IF NOT FOUND THEN
|
||||
RETURN QUERY SELECT
|
||||
'auth_key_not_found'::text, 0, 0::bigint, 0::bigint,
|
||||
p_expires_at, false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
v_actual_perm_id := NULL;
|
||||
SELECT binding.perm_auth_key_id
|
||||
INTO v_actual_perm_id
|
||||
FROM public.temp_auth_key_bindings AS binding
|
||||
WHERE binding.temp_auth_key_id = p_raw_auth_key_id;
|
||||
v_actual_bound := FOUND;
|
||||
IF NOT v_actual_bound THEN
|
||||
v_actual_perm_id := p_raw_auth_key_id;
|
||||
END IF;
|
||||
v_actual_has_identity := v_actual_bound OR v_raw_expiry = 0;
|
||||
v_actual_identity_id := v_actual_perm_id;
|
||||
|
||||
IF v_actual_has_identity <> v_hint_has_identity
|
||||
OR (v_actual_has_identity AND v_actual_identity_id <> v_hint_identity_id)
|
||||
OR v_actual_bound <> v_hint_bound
|
||||
OR v_raw_expiry <> v_hint_expiry
|
||||
THEN
|
||||
RETURN QUERY SELECT
|
||||
'identity_changed'::text, 0, 0::bigint, 0::bigint,
|
||||
p_expires_at, false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF v_actual_bound THEN
|
||||
SELECT key.expires_at
|
||||
INTO v_perm_expiry
|
||||
FROM public.auth_keys AS key
|
||||
WHERE key.auth_key_id = v_actual_perm_id
|
||||
FOR UPDATE;
|
||||
IF NOT FOUND OR v_raw_expiry <= 0 OR v_perm_expiry <> 0 THEN
|
||||
RETURN QUERY SELECT
|
||||
'binding_invalid'::text, 0, 0::bigint, 0::bigint,
|
||||
p_expires_at, false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
SELECT evidence.layer,
|
||||
evidence.msg_id,
|
||||
evidence.observation_id,
|
||||
evidence.expires_at
|
||||
INTO v_current_layer,
|
||||
v_current_msg_id,
|
||||
v_current_observation_id,
|
||||
v_current_expires_at
|
||||
FROM public.auth_key_session_layers AS evidence
|
||||
WHERE evidence.raw_auth_key_id = p_raw_auth_key_id
|
||||
AND evidence.session_id = p_session_id
|
||||
FOR UPDATE;
|
||||
v_current_found := FOUND;
|
||||
|
||||
IF v_current_found AND v_now < v_current_expires_at THEN
|
||||
IF p_msg_id < v_current_msg_id THEN
|
||||
SELECT key.layer = v_current_layer
|
||||
AND key.layer_observation_id = v_current_observation_id
|
||||
INTO v_shared_default
|
||||
FROM public.auth_keys AS key
|
||||
WHERE key.auth_key_id = v_actual_perm_id;
|
||||
RETURN QUERY SELECT
|
||||
'ok'::text, v_current_layer, v_current_msg_id,
|
||||
v_current_observation_id, v_current_expires_at,
|
||||
v_shared_default, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
IF p_msg_id = v_current_msg_id THEN
|
||||
IF p_layer <> v_current_layer THEN
|
||||
RETURN QUERY SELECT
|
||||
'conflict'::text, v_current_layer, v_current_msg_id,
|
||||
v_current_observation_id, v_current_expires_at,
|
||||
false, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
SELECT key.layer = v_current_layer
|
||||
AND key.layer_observation_id = v_current_observation_id
|
||||
INTO v_shared_default
|
||||
FROM public.auth_keys AS key
|
||||
WHERE key.auth_key_id = v_actual_perm_id;
|
||||
RETURN QUERY SELECT
|
||||
'ok'::text, v_current_layer, v_current_msg_id,
|
||||
v_current_observation_id, v_current_expires_at,
|
||||
v_shared_default, false;
|
||||
RETURN;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
v_observation_id := nextval('public.auth_key_layer_observation_seq');
|
||||
INSERT INTO public.auth_key_session_layers (
|
||||
raw_auth_key_id,
|
||||
session_id,
|
||||
layer,
|
||||
msg_id,
|
||||
observation_id,
|
||||
expires_at
|
||||
) VALUES (
|
||||
p_raw_auth_key_id,
|
||||
p_session_id,
|
||||
p_layer,
|
||||
p_msg_id,
|
||||
v_observation_id,
|
||||
p_expires_at
|
||||
)
|
||||
ON CONFLICT (raw_auth_key_id, session_id) DO UPDATE SET
|
||||
layer = EXCLUDED.layer,
|
||||
msg_id = EXCLUDED.msg_id,
|
||||
observation_id = EXCLUDED.observation_id,
|
||||
expires_at = EXCLUDED.expires_at
|
||||
RETURNING layer, msg_id, observation_id, expires_at
|
||||
INTO v_current_layer,
|
||||
v_current_msg_id,
|
||||
v_current_observation_id,
|
||||
v_current_expires_at;
|
||||
|
||||
v_key_ids := ARRAY[p_raw_auth_key_id];
|
||||
IF v_actual_perm_id <> p_raw_auth_key_id THEN
|
||||
v_key_ids := array_append(v_key_ids, v_actual_perm_id);
|
||||
END IF;
|
||||
UPDATE public.auth_keys AS key
|
||||
SET layer = p_layer,
|
||||
layer_observation_id = v_observation_id
|
||||
WHERE key.auth_key_id = ANY(v_key_ids)
|
||||
AND key.layer_observation_id < v_observation_id;
|
||||
GET DIAGNOSTICS v_updated = ROW_COUNT;
|
||||
IF v_updated <> cardinality(v_key_ids) THEN
|
||||
RAISE EXCEPTION
|
||||
'publish auth session Layer defaults updated % of % locked keys',
|
||||
v_updated,
|
||||
cardinality(v_key_ids)
|
||||
USING ERRCODE = '23000';
|
||||
END IF;
|
||||
|
||||
UPDATE public.authorizations AS authz
|
||||
SET layer = p_layer
|
||||
WHERE authz.auth_key_id = ANY(v_key_ids);
|
||||
|
||||
RETURN QUERY SELECT
|
||||
'ok'::text, v_current_layer, v_current_msg_id,
|
||||
v_current_observation_id, v_current_expires_at,
|
||||
true, true;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION public.telesrv_advance_auth_session_layer(
|
||||
bigint, bigint, integer, bigint, timestamptz
|
||||
) IS 'Atomically advances durable invokeWithLayer evidence while preserving auth identity lock order';
|
||||
Loading…
Add table
Add a link
Reference in a new issue