Skip to content

Commit 6d615c7

Browse files
authored
Merge pull request #64 from seanwevans/codex/revise-allocate_memory-in-pg_os-1.0.sql
Ensure allocate_memory locks segments safely
2 parents 926eaaa + b3d6662 commit 6d615c7

1 file changed

Lines changed: 51 additions & 20 deletions

File tree

pg_os--1.0.sql

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -706,37 +706,68 @@ $$ LANGUAGE plpgsql;
706706
-- Similarly, for memory allocation, use transactions and more verbose errors
707707
CREATE OR REPLACE FUNCTION allocate_memory(user_id INTEGER, process_id INTEGER, segment_size INTEGER) RETURNS VOID AS $$
708708
DECLARE
709-
mem_seg RECORD;
709+
mem_seg memory_segments%ROWTYPE;
710+
updated_seg memory_segments%ROWTYPE;
711+
locked BOOLEAN := FALSE;
710712
BEGIN
711713
IF NOT check_permission(user_id, 'memory', 'allocate') THEN
712714
RAISE EXCEPTION 'User % does not have permission to allocate memory', user_id;
713715
END IF;
714716

715717
BEGIN
716-
SELECT * INTO mem_seg FROM memory_segments
717-
WHERE allocated = FALSE AND size >= segment_size
718-
ORDER BY size
719-
LIMIT 1;
720-
721-
IF NOT FOUND THEN
722-
RAISE EXCEPTION 'No suitable memory segment available of size %', segment_size;
723-
END IF;
724-
725-
-- Transaction block for atomic allocation
726-
BEGIN
727-
PERFORM pg_advisory_lock(1); -- simulate locking, ensure no other transaction interferes
728-
UPDATE memory_segments SET allocated = TRUE, allocated_to = process_id WHERE id = mem_seg.id;
729-
INSERT INTO process_memory (process_id, segment_id) VALUES (process_id, mem_seg.id);
718+
PERFORM pg_advisory_lock(1); -- simulate locking, ensure no other transaction interferes
719+
locked := TRUE;
720+
721+
LOOP
722+
SELECT *
723+
INTO mem_seg
724+
FROM memory_segments
725+
WHERE allocated = FALSE AND size >= segment_size
726+
ORDER BY size
727+
LIMIT 1
728+
FOR UPDATE SKIP LOCKED;
729+
730+
IF NOT FOUND THEN
731+
IF locked THEN
732+
PERFORM pg_advisory_unlock(1);
733+
locked := FALSE;
734+
END IF;
735+
RAISE EXCEPTION 'No suitable memory segment available of size %', segment_size;
736+
END IF;
737+
738+
UPDATE memory_segments
739+
SET allocated = TRUE,
740+
allocated_to = process_id
741+
WHERE id = mem_seg.id
742+
AND allocated = FALSE
743+
RETURNING * INTO updated_seg;
744+
745+
IF FOUND THEN
746+
EXIT;
747+
END IF;
748+
749+
IF locked THEN
750+
PERFORM pg_advisory_unlock(1);
751+
locked := FALSE;
752+
END IF;
753+
RAISE EXCEPTION 'Memory segment % was allocated concurrently', mem_seg.id;
754+
END LOOP;
755+
756+
INSERT INTO process_memory (process_id, segment_id) VALUES (process_id, updated_seg.id);
757+
758+
IF locked THEN
730759
PERFORM pg_advisory_unlock(1);
731-
EXCEPTION WHEN others THEN
732-
PERFORM pg_advisory_unlock(1);
733-
RAISE;
734-
END;
760+
locked := FALSE;
761+
END IF;
735762

736763
-- Log the allocation
737-
PERFORM log_memory_action(process_id, 'Memory allocated: segment ' || mem_seg.id, user_id, mem_seg.id);
764+
PERFORM log_memory_action(process_id, 'Memory allocated: segment ' || updated_seg.id, user_id, updated_seg.id);
738765

739766
EXCEPTION WHEN others THEN
767+
IF locked THEN
768+
PERFORM pg_advisory_unlock(1);
769+
locked := FALSE;
770+
END IF;
740771
RAISE EXCEPTION 'Error allocating memory: %', SQLERRM;
741772
END;
742773
END;

0 commit comments

Comments
 (0)