BUG #16610: server process was terminated by signal 11: Segmentation fault

Поиск
Список
Период
Сортировка
От PG Bug reporting form
Тема BUG #16610: server process was terminated by signal 11: Segmentation fault
Дата
Msg-id 16610-efef65179bab385d@postgresql.org
обсуждение исходный текст
Список pgsql-bugs
The following bug has been logged on the website:

Bug reference:      16610
Logged by:          Sylwester Kogowski
Email address:      s.kogowski@netfactory.pl
PostgreSQL version: 12.2
Operating system:   Debian 8
Description:

Hi,
I had a following error on our development server (luckily):
server process (PID 7748) was terminated by signal 11: Segmentation fault
This was always after the same statement: DELETE FROM "blockades" WHERE
"saas_user_id" = 92
However, DELETE FROM "blockades" WHERE id=.... worked ok.
Column saas_user_id is an indexed non-unique column. There are triggers on
this table that where executed and those triggers use pg_notify to
communicate with external processes (don't know if that had influence). The
statement was not executed in a transaction. No replication is used or
anything like that. The table is not partitioned, though a trigger modifies
'blockades_optimized' table which is partitioned and uses a btree_gist
indexing (don't know if that matters, because clearing blockades table was
enough to remove the error, so I don't think that blockades_optimized or
pg_notify had any influence on it).

None other statements were affected in this error.
The error was fixed by TRUNCATE TABLE blockades CASCADE;
This was a dev server, so we could've just clear that table without
repercussions, but it would've been a bigger problem on the production
server (though I don't imagine a scenario where we would remove multiple
blockades at the same time on production server).
I will provide more info if I will encounter the error again, just reply to
this with list of information that you will need (or an advice if this error
can be circumvented somehow).

Logs from postgresql:
2020-09-09 10:19:56.413 CEST [3512] LOG:  server process (PID 7748) was
terminated by signal 11: Segmentation fault
2020-09-09 10:19:56.413 CEST [3512] DETAIL:  Failed process was running:
DELETE FROM "blockades" WHERE "saas_user_id" = 92
2020-09-09 10:19:56.413 CEST [3512] LOG:  terminating any other active
server processes
2020-09-09 10:19:56.413 CEST [7809] root@nfhotel WARNING:  terminating
connection because of crash of another server process
2020-09-09 10:19:56.413 CEST [7809] root@nfhotel DETAIL:  The postmaster has
commanded this server process to roll back the current transaction and exit,
because another server process exited abnormally and poss
ibly corrupted shared memory.
2020-09-09 10:19:56.413 CEST [7809] root@nfhotel HINT:  In a moment you
should be able to reconnect to the database and repeat your command.
2020-09-09 10:19:56.414 CEST [7722] root@nfhotel WARNING:  terminating
connection because of crash of another server process
2020-09-09 10:19:56.414 CEST [7722] root@nfhotel DETAIL:  The postmaster has
commanded this server process to roll back the current transaction and exit,
because another server process exited abnormally and possibly corrupted
shared memory.
(... and all other connections were also disconnected)

Logs from messages
Sep  9 10:19:56 NFhotel-dev kernel: [97212.380440] postgres[7748]: segfault
at 0 ip 0000559032e2c5d8 sp 00007fffa3243750 error 4 in
postgres[559032d5f000+77b000]


The 'blockades' table has following construction:
-- Table: nfhotel.blockades

-- DROP TABLE nfhotel.blockades;

CREATE TABLE nfhotel.blockades
(
    id integer NOT NULL DEFAULT nextval('blockades_id_seq'::regclass),
    saas_user_id integer NOT NULL,
    bl_name character varying(400) COLLATE pg_catalog."default" NOT NULL,
    bl_deleted integer DEFAULT 0,
    bl_type_id integer NOT NULL DEFAULT 1,
    b_created timestamp without time zone NOT NULL DEFAULT
CURRENT_TIMESTAMP,
    b_modified timestamp without time zone,
    CONSTRAINT "idx_16863_PRIMARY" PRIMARY KEY (id),
    CONSTRAINT "FK_blockades_blockade_types" FOREIGN KEY (bl_type_id)
        REFERENCES nfhotel.blockade_types (id) MATCH SIMPLE
        ON UPDATE CASCADE
        ON DELETE CASCADE
)

TABLESPACE pg_default;


-- Index: idx_16863_FK_blockades_blockade_types

-- DROP INDEX nfhotel."idx_16863_FK_blockades_blockade_types";

CREATE INDEX "idx_16863_FK_blockades_blockade_types"
    ON nfhotel.blockades USING btree
    (bl_type_id ASC NULLS LAST)
    TABLESPACE pg_default;
-- Index: idx_16863_idx_saas_user_id

-- DROP INDEX nfhotel.idx_16863_idx_saas_user_id;

CREATE INDEX idx_16863_idx_saas_user_id
    ON nfhotel.blockades USING btree
    (saas_user_id ASC NULLS LAST)
    TABLESPACE pg_default;

-- Trigger: blockades_optimized_on_delete

-- DROP TRIGGER blockades_optimized_on_delete ON nfhotel.blockades;

CREATE TRIGGER blockades_optimized_on_delete
    AFTER DELETE
    ON nfhotel.blockades
    REFERENCING OLD TABLE AS old_blockades
    FOR EACH STATEMENT
    EXECUTE PROCEDURE nfhotel.on_blockades_changed();

-- Trigger: blockades_optimized_on_insert

-- DROP TRIGGER blockades_optimized_on_insert ON nfhotel.blockades;

CREATE TRIGGER blockades_optimized_on_insert
    AFTER INSERT
    ON nfhotel.blockades
    REFERENCING NEW TABLE AS new_blockades
    FOR EACH STATEMENT
    EXECUTE PROCEDURE nfhotel.on_blockades_changed();

-- Trigger: blockades_optimized_on_update

-- DROP TRIGGER blockades_optimized_on_update ON nfhotel.blockades;

CREATE TRIGGER blockades_optimized_on_update
    AFTER UPDATE 
    ON nfhotel.blockades
    REFERENCING NEW TABLE AS new_blockades OLD TABLE AS old_blockades
    FOR EACH STATEMENT
    EXECUTE PROCEDURE nfhotel.on_blockades_changed();


CREATE FUNCTION nfhotel.on_blockades_changed()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
RAISE NOTICE 'on_blockades_changed, op:%', TG_OP;
  IF TG_OP = 'DELETE' THEN
    
    
      
RAISE NOTICE 'on_blockades_changed, op:DELETE, bo count:%', (SELECT COUNT(*)

                                                             FROM old_blockades oldb
        INNER JOIN blockades_optimized AS bo ON oldb.id = bo.blockade_id AND
bo.saas_user_id = oldb.saas_user_id);
      
    PERFORM send_availability_synchronization(oldb.saas_user_id::int,
array_agg((range_begin_to_date(bo.date_range),range_end_to_date(bo.date_range),bo.room_id)::availability_change))
  
      FROM old_blockades oldb
        INNER JOIN blockades_optimized AS bo ON oldb.id = bo.blockade_id AND
bo.saas_user_id = oldb.saas_user_id
          INNER JOIN rooms r ON r.id = bo.room_id AND r.ro_enabled = 1 AND
r.ro_type=1
      GROUP BY oldb.saas_user_id,bo.room_id;
      
    DELETE FROM blockades_optimized AS bo 
        USING old_blockades oldb
          WHERE oldb.id = bo.blockade_id AND bo.saas_user_id =
oldb.saas_user_id;
          
  ELSIF TG_OP = 'UPDATE' THEN
    
    PERFORM send_availability_synchronization(oldb.saas_user_id::int,
array_agg((range_begin_to_date(bo.date_range),range_end_to_date(bo.date_range),bo.room_id)::availability_change))
  
      FROM old_blockades oldb
        INNER JOIN blockades_optimized AS bo ON oldb.id = bo.blockade_id AND
bo.saas_user_id = oldb.saas_user_id
        INNER JOIN rooms r ON r.id = bo.room_id AND r.ro_enabled = 1 AND
r.ro_type=1
      GROUP BY oldb.saas_user_id,bo.room_id;
      
    DELETE FROM blockades_optimized AS bo 
        USING old_blockades oldb
          WHERE oldb.id = bo.blockade_id AND bo.saas_user_id =
oldb.saas_user_id;
          
    
    INSERT INTO blockades_optimized
(blockade_id,room_id,term_id,room_standard_id,date_range,saas_user_id)    
        (SELECT
newb.id,br.room_id,bt.id,r.room_standard_id,int4range(date_to_number(bt.bl_from),
date_to_number(bt.bl_to)),newb.saas_user_id 
            FROM new_blockades newb
        INNER JOIN blockades_terms bt ON bt.blockade_id = newb.id
        INNER JOIN blockades_rooms br on br.term_id = bt.id
        INNER JOIN rooms r ON r.id = br.room_id
            where newb.bl_deleted = 0 AND bt.bl_to > current_date)
      ON CONFLICT DO NOTHING;
          
      
    PERFORM 1 FROM (
        WITH requires_sync AS (
              SELECT newb.saas_user_id,br.room_id,
(bt.bl_from,bt.bl_to,br.room_id)::availability_change AS change
                FROM new_blockades newb
                    INNER JOIN blockades_terms bt ON bt.blockade_id = newb.id AND bt.bl_to
> current_date
                    INNER JOIN blockades_rooms br on br.term_id = bt.id
                    INNER JOIN rooms r ON r.id = br.room_id and
r.ro_enabled=1 and r.ro_type=1
                WHERE newb.bl_deleted = 0
        )
        SELECT send_availability_synchronization(saas_user_id::int,
array_agg(change))
          FROM requires_sync 
            GROUP BY saas_user_id, room_id) AS smth;
      
      
  ELSIF TG_OP = 'INSERT' THEN
    
    INSERT INTO blockades_optimized
(blockade_id,room_id,term_id,room_standard_id,date_range,saas_user_id)    
        (SELECT
newb.id,br.room_id,bt.id,r.room_standard_id,int4range(date_to_number(bt.bl_from),
date_to_number(bt.bl_to)),newb.saas_user_id 
            FROM new_blockades newb
        INNER JOIN blockades_terms bt ON bt.blockade_id = newb.id
        INNER JOIN blockades_rooms br on br.term_id = bt.id
        INNER JOIN rooms r ON r.id = br.room_id
            where newb.bl_deleted = 0 AND bt.bl_to > current_date)
      ON CONFLICT DO NOTHING;
      
  
      PERFORM send_availability_synchronization(newb.saas_user_id::int,
array_agg((bt.bl_from,bt.bl_to,br.room_id)::availability_change))
        FROM new_blockades newb
            INNER JOIN blockades_terms bt ON bt.blockade_id = newb.id AND
bt.bl_to > current_date
            INNER JOIN blockades_rooms br on br.term_id = bt.id
            INNER JOIN rooms r ON r.id = br.room_id AND r.ro_enabled = 1 AND
r.ro_type=1
        WHERE newb.bl_deleted = 0
        GROUP BY newb.saas_user_id,br.room_id;
  end if;
  return NULL;
END
$BODY$;


CREATE OR REPLACE FUNCTION nfhotel.send_availability_synchronization(
    saas_user_id integer,
    changes availability_change[])
    RETURNS void
    LANGUAGE 'plpgsql'

    COST 100
    VOLATILE 
    
AS $BODY$
DECLARE
    lower_range int;
    upper_range int;
    change_range int4range;
    change availability_change;
BEGIN
FOREACH change in ARRAY changes LOOP
        change_range :=
int4range(date_to_number(change._from),date_to_number(change._to),'[]');
        PERFORM 1 FROM pending_availability_changes pac  WHERE
pac.saas_user_id = send_availability_synchronization.saas_user_id AND
pac.room_id  = change.room_id 
                AND pac.date_range && change_range FOR UPDATE;
        lower_range := LEAST((SELECT MIN(lower(pac.date_range)) FROM
pending_availability_changes pac
            WHERE  pac.saas_user_id =
send_availability_synchronization.saas_user_id AND pac.room_id  =
change.room_id 
                AND pac.date_range @> lower(change_range) ),
date_to_number(change._from));
        upper_range := GREATEST((SELECT MAX(upper(pac.date_range)) FROM
pending_availability_changes pac
            WHERE  pac.saas_user_id =
send_availability_synchronization.saas_user_id AND pac.room_id  =
change.room_id 
                AND pac.date_range @> upper(change_range) ),
date_to_number(change._to));
        change_range := int4range(lower_range,upper_range,'[]');
        DELETE FROM pending_availability_changes WHERE
pending_availability_changes.saas_user_id =
send_availability_synchronization.saas_user_id AND room_id  = change.room_id

            AND date_range && change_range;
        INSERT INTO pending_availability_changes(saas_user_id, room_id,
date_range) VALUES(send_availability_synchronization.saas_user_id,
change.room_id,

              change_range);

end loop;
RAISE NOTICE 'send_availability_synchronization for saas:%, json:%',
saas_user_id,json_build_object('command_type','changes_detected','node_based_prices',1,
    'saas_user_id',saas_user_id, 'changes_array',changes)::text; 
PERFORM pg_notify('nfhotel_availability_sync',
json_build_object('command_type','changes_detected','node_based_prices',1,
    'saas_user_id',saas_user_id, 'changes_array',changes)::text);
END
$BODY$;

As you can see, saas_user_id is not a unique column. 
Server configuration is default, except for adding btree_gist and pgcrypto
extensions (not used in this particular table).
Postgresql version is "PostgreSQL 12.2 (Debian 12.2-2.pgdg80+1) on
x86_64-pc-linux-gnu, compiled by gcc (Debian 4.9.2-10+deb8u2) 4.9.2,
64-bit"

I will update postgresql to a newer version and see if it helps, but in case
that the error will come up again, please instruct me if you need more
information.


В списке pgsql-bugs по дате отправления:

Предыдущее
От: Tomas Vondra
Дата:
Сообщение: Re: BUG #16577: Segfault on altering a table located in a dropped tablespace
Следующее
От: Jehan-Guillaume de Rorthais
Дата:
Сообщение: Re: [BUG v13] Crash with event trigger in extension