Hello Everyone,

I've run into a strange error on the PostgreSQL 9.5.4 DB we use for our Zabbix 
Server.  I implemented auto-partitioning based on the design from this wiki 
article: 
https://www.zabbix.org/wiki/Docs/howto/zabbix2_postgresql_autopartitioning

I implemented auto-partitioning for the history_uint table using the following 
trigger function:

CREATE FUNCTION zbx_part_trigger_func() RETURNS trigger
    LANGUAGE plpgsql
    AS $_$
      DECLARE
        prefix     text := 'partitions';
        timeformat text;
        selector   text;
        _interval  interval;
        tablename  text;
        startdate  text;
        enddate    text;
        create_table_part text;
        create_index_part text;

      BEGIN
        selector = TG_ARGV[0];

        IF selector = 'hour' THEN
          timeformat := 'YYYY_MM_DD_HH24';
        ELSIF selector = 'day' THEN
          timeformat := 'YYYY_MM_DD';
        ELSIF selector = 'month' THEN
          timeformat := 'YYYY_MM';
        ELSE
          RAISE EXCEPTION 'zbx_part_trigger_func: Specify "hour", "day", or 
"month" for interval selector instead of "%"', selector;
        END IF;

        _interval := '1 ' || selector;
        tablename :=  TG_TABLE_NAME || '_p' || to_char(to_timestamp(NEW.clock), 
timeformat);

        EXECUTE 'INSERT INTO ' || quote_ident(prefix) || '.' || 
quote_ident(tablename) || ' SELECT ($1).*' USING NEW;
        RETURN NULL;

        EXCEPTION
          WHEN undefined_table THEN
            startdate := extract(epoch FROM date_trunc(selector, 
to_timestamp(NEW.clock)));
            enddate := extract(epoch FROM date_trunc(selector, 
to_timestamp(NEW.clock) + _interval ));
            create_table_part := 'CREATE TABLE IF NOT EXISTS ' || 
quote_ident(prefix) || '.' || quote_ident(tablename)
                              || ' (CHECK ((clock >= ' || 
quote_literal(startdate)
                              || ' AND clock < ' || quote_literal(enddate)
                              || '))) INHERITS (' || TG_TABLE_NAME || ')';
            create_index_part := 'CREATE INDEX ' || quote_ident(tablename)
                              || '_1 on ' || quote_ident(prefix) || '.' || 
quote_ident(tablename) || '(itemid,clock)';
            EXECUTE create_table_part;
            EXECUTE create_index_part;
            --insert it again
            EXECUTE 'INSERT INTO ' || quote_ident(prefix) || '.' || 
quote_ident(tablename) || ' SELECT ($1).*' USING NEW;
            RETURN NULL;
      END;
    $_$;


With this trigger (no other triggers defined):
zbx_partition_trg BEFORE INSERT ON history_uint FOR EACH ROW EXECUTE PROCEDURE 
zbx_part_trigger_func('day');


I had fully expected race conditions to occur on a very busy system and throw 
errors trying to create the table, but instead I got the following index 
creation error:

ERROR:  relation "history_uint_p2017_05_17_1" already exists
CONTEXT:  SQL statement "CREATE INDEX history_uint_p2017_05_17_1 on 
partitions.history_uint_p2017_05_17(itemid,clock)"
                PL/pgSQL function zbx_part_trigger_func() line 43 at EXECUTE
STATEMENT:  insert into history_uint (itemid,clock,ns,value) values 
(73800,1494979201,11841804,99382669312),(30061,1494979201,17605067,0);


I am unable to figure out how the trigger was able to successfully create the 
table, but then fail creating the index.  I would have expected one thread to 
"win" and create both the table and index, but other threads would fail when 
creating the table… but NOT when creating the index.

The only other function defined in the system is the "cleanup" function which 
was not running at the time.

The target table and index were still created.

Can anyone shed any light on how this could have occurred?  Is this a bug or am 
I missing something?


Pertinent details:
·         PostgreSQL 9.5.4 installed from PGDG packages on Centos 7.3.1611
·         Zabbix 3.2 server


Thanks,
Rob Brucks

Reply via email to