Tenho duas tabelas PostgreSQL: objects
e metadata
. Cada objeto tem uma size
propriedade que representa seu tamanho em bytes e pode ser armazenado em um local exclusivo com storage_id
. Nos metadados, a total_size
propriedade de todos os objetos de cada armazenamento com um dado storage_id
é mantida. Tabelas simplificadas:
CREATE TABLE IF NOT EXISTS objects (
object_id UUID PRIMARY KEY,
storage_id UUID NOT NULL,
size BIGINT NOT NULL,
FOREIGN KEY (storage_id) REFERENCES metadata(storage_id)
);
CREATE TABLE IF NOT EXISTS metadata (
storage_id UUID PRIMARY KEY,
total_size BIGINT DEFAULT 0
);
Para manter o total_size
na metadata
tabela, tenho gatilhos que sempre que um objeto é inserido ou excluído, ele total_size
é atualizado, ou seja, aqui está o gatilho para inserção:
CREATE OR REPLACE FUNCTION update_size_on_insert() RETURNS TRIGGER AS $$
BEGIN
UPDATE metadata
SET total_size = total_size + NEW.size
WHERE storage_id = NEW.storage_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER trg_update_size_on_insert
AFTER INSERT ON objects
FOR EACH ROW
EXECUTE FUNCTION update_size_on_insert();
O problema é que inserções/exclusões simultâneas podem sobrescrever o comando, o total_size
que leva a dados inválidos. Como posso alterar o gatilho para que ele contenha um bloqueio em nível de linhaSET total_size = total_size + NEW.size
quando o comando for executado? Eu estava pensando na FOR UPDATE
instrução, mas isso requer um comando SELECT
. Posso usar PERFORM ... FOR UPDATE;
para bloquear a linha?