Ühel kenal päeval, E, 2007-03-26 kell 11:30, kirjutas Andrew Dunstan:
> This feature (ability to add a message payload to a NOTIFY) is on the 
> TODO list and I had undertaken to implement it. However, pressure of 
> other work has conspired to make that difficult, and Abhijit Menon-Sen 
> recently very kindly offered to help out.
> 
> Therer was some discussion of implementation late last year here: 
> http://groups.google.com/group/pgsql.hackers/browse_frm/thread/e63a5ac43e2508ce/ce47016235bd5a62?tvc=1&q=notify+payload&hl=en#ce47016235bd5a62
> 
> However, in various pieces of off-list discussion it appears that there 
> is some opposition either to the design or to the feature itself. What 
> is more, there will clearly be vigorous opposition to any implementation 
> which does NOT remove the use of pg_listener (which I understand and I 
> think largely agree with).
> 
> So, before an investment of any more time is made by either Abhijit or 
> myself, I would like to get confirmation that a) there is broad 
> agreement on the desirability of the feature and b) that there is broad 
> agreement on the general design (i.e. to use a circular buffer in shared 
> memory, of configurable size, to hold the outstanding message queue). 
> Please speak up or forever ....

I find the feature very useful, and have even done some preliminary
design work for shared memory implementation, where each listener is
required to copy data to its own privat memory ASAP and notifier waits
in case there is not enough room in shared memory buffer.

Alas, I have lost my design 3 a4 pages of design notes for organising
things in fixed-size buffer, but the basic operation data-wise sould be
as in attached sql file.

-- 
----------------
Hannu Krosing
Database Architect
Skype Technologies OÜ
Akadeemia tee 21 F, Tallinn, 12618, Estonia

Skype me:  callto:hkrosing
Get Skype for free:  http://www.skype.com

CREATE TABLE listen_name (
    message_id serial PRIMARY KEY,
    message_name text UNIQUE
);

CREATE TABLE listener (
    listener_pid int,
    message_id int REFERENCES listen_name,
    CONSTRAINT pk_listener PRIMARY KEY (message_id, listener_pid)
);

CREATE TABLE message (
    message_nr serial PRIMARY KEY,
    message_id int REFERENCES listen_name,
    notifier_pid int,
    message_text text,
    listener_count int
);

CREATE TABLE message_listener (
    message_nr int REFERENCES message,
    listener_pid int,
    CONSTRAINT pk_message_listener PRIMARY KEY (listener_pid, message_nr)
);

CREATE LANGUAGE plpgsql;

CREATE FUNCTION add_listener (i_listener_pid int, i_message_name text) RETURNS VOID
LANGUAGE plpgsql AS
$$
/*
More error checking needed, what to do, when there is no room for adding a listener ?
*/
DECLARE
    v_message_id int;
BEGIN
    BEGIN
        INSERT INTO listen_name(message_name) VALUES (i_message_name);
    EXCEPTION WHEN unique_violation THEN
        -- name already present, do nothing
    END;
    SELECT message_id INTO v_message_id FROM listen_name WHERE message_name = i_message_name;
    INSERT INTO listener (listener_pid, message_id) VALUES (i_listener_pid, v_message_id);
END
$$
;

CREATE OR REPLACE FUNCTION add_message (i_notifier_pid int, i_message_name text, i_message_text text) RETURNS VOID
LANGUAGE plpgsql AS
$$
DECLARE
    v_message_id int;
BEGIN
    SELECT message_id INTO v_message_id FROM listen_name WHERE message_name = i_message_name;
    IF NOT FOUND THEN 
        RETURN; -- nobody is listening, no need to post
    END IF;
--    LOOP   -- pseudocode for shared memory commented out
--        BEGIN
            INSERT INTO message(message_id,notifier_pid,message_text,listener_count)
                         VALUES(v_message_id, i_notifier_pid, i_message_text, (SELECT count(*) FROM listener WHERE message_id = v_message_id));
            INSERT INTO message_listener
            SELECT currval('message_message_nr_seq'), listener_pid FROM listener WHERE message_id = v_message_id;
--        EXCEPTION WHEN not_enough_room_in_shared_mem THEN
--            -- wait for room to appear in shared mem, maybe try some cleanup
--        END;
--    END LOOP;
END
$$
;

CREATE OR REPLACE FUNCTION fetch_message (i_listener_pid int, i_message_name text,  out o_notifier_pid int,  out o_message_name text, out o_message_text text) RETURNS SETOF RECORD
LANGUAGE plpgsql AS
$$
DECLARE
    v_message_id int;
    v_message_nr int;
BEGIN
    FOR v_message_nr, o_notifier_pid, o_message_name, o_message_text IN
        SELECT ml.message_nr, notifier_pid,message_name,message_text
          FROM message_listener ml, listen_name ln, message m
         WHERE ml.listener_pid = i_listener_pid
           AND m.message_id = ln.message_id
           AND ml.message_nr = m.message_nr
        ORDER BY message_nr
    LOOP
        UPDATE message SET listener_count = listener_count - 1 WHERE message_nr = v_message_nr;
        DELETE FROM message WHERE message_nr = v_message_nr AND listener_count = 0; -- cleanup by the last listener
        DELETE FROM message_listener WHERE (listener_pid, message_nr) = (i_listener_pid, v_message_nr);
        RETURN NEXT;
    END LOOP;
END
$$
;

CREATE FUNCTION drop_listener (i_listener_pid int) RETURNS VOID
LANGUAGE plpgsql AS
$$
UPDATE message SET listener_count = listener_count - 1 WHERE message_nr IN (SELECT message_nr FROM message_listener WHERE listener_pid = i_listener_pid);
DELETE FROM listener WHERE listener_pid = i_listener_pid; -- drop listeners of this pid
DELETE FROM listen_name WHERE message_id NOT IN (SELECT message_id FROM listener); -- drop message names with no registered listeners
DELETE FROM message_listener WHERE  listener_pid = i_listener_pid; -- drop message listenings
DELETE FROM message WHERE listener_count = 0; -- clean up messages with no remaining listeners
$$
;



---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at

                http://www.postgresql.org/about/donate

Reply via email to