From 6dc4998802abfd4517a76e8f8e1ae927dbba0058 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 Jun 2023 15:13:40 +0200 Subject: [PATCH] Support Percona XtraDB Cluster by not using SERIALIZABLE transactions directly The RDBMS rejects them by default. But it doesn't rejects their equivalent: Append "LOCK IN SHARE MODE" to every SELECT in a REPEATABLE READ transaction. Now we do the latter with MySQL. --- pkg/icingadb/ha.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/icingadb/ha.go b/pkg/icingadb/ha.go index 0a81bb5b5..4242c1eb6 100644 --- a/pkg/icingadb/ha.go +++ b/pkg/icingadb/ha.go @@ -9,6 +9,7 @@ import ( "github.com/icinga/icingadb/internal" "github.com/icinga/icingadb/pkg/backoff" "github.com/icinga/icingadb/pkg/com" + "github.com/icinga/icingadb/pkg/driver" v1 "github.com/icinga/icingadb/pkg/icingadb/v1" "github.com/icinga/icingadb/pkg/icingaredis" icingaredisv1 "github.com/icinga/icingadb/pkg/icingaredis/v1" @@ -247,14 +248,23 @@ func (h *HA) realize(ctx context.Context, s *icingaredisv1.IcingaStatus, t *type func(ctx context.Context) error { takeover = false otherResponsible = false + isoLvl := sql.LevelSerializable + selectLock := "" + + if h.db.DriverName() == driver.MySQL { + // The RDBMS may actually be a Percona XtraDB Cluster which doesn't + // support serializable transactions, but only their following equivalent: + isoLvl = sql.LevelRepeatableRead + selectLock = " LOCK IN SHARE MODE" + } - tx, errBegin := h.db.BeginTxx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) + tx, errBegin := h.db.BeginTxx(ctx, &sql.TxOptions{Isolation: isoLvl}) if errBegin != nil { return errors.Wrap(errBegin, "can't start transaction") } - query := h.db.Rebind("SELECT id, heartbeat FROM icingadb_instance " + - "WHERE environment_id = ? AND responsible = ? AND id <> ? AND heartbeat > ?") + query := h.db.Rebind("SELECT id, heartbeat FROM icingadb_instance "+ + "WHERE environment_id = ? AND responsible = ? AND id <> ? AND heartbeat > ?") + selectLock instance := &v1.IcingadbInstance{}