From ad8461491b35c739683971deff32a3203d0d7e5d Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 13 Mar 2020 11:29:03 +0100 Subject: [PATCH] Avoid occasionnal deadlocks (1 in 256) --- account.go | 9 ++++----- server.go | 3 ++- util.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/account.go b/account.go index b0313a4..0b480d6 100644 --- a/account.go +++ b/account.go @@ -453,17 +453,16 @@ func (a *Account) eventInternal(event *Event) error { var cache_key string if event.Id != "" { + // Use mx_room_id as a lock slot key, because this section is + // concurrent with the part that sends events out in server.go, + // and at that point we don't know the event's ID yet + // since it will be attributed by the backend during the call to send dbLockSlot(mx_room_id) defer dbUnlockSlot(mx_room_id) // If the event has an ID, make sure it is processed only once cache_key = fmt.Sprintf("%s/event_seen/%s/%s", a.Protocol, mx_room_id, event.Id) - slot_key := dbKvSlotKey(cache_key) - - dbLockSlot(slot_key) - defer dbUnlockSlot(slot_key) - if dbKvGet(cache_key) == "yes" { // false: cache key was not modified, meaning we // already saw the event diff --git a/server.go b/server.go index 1654971..1868078 100644 --- a/server.go +++ b/server.go @@ -166,6 +166,7 @@ func handleTxnEvent(e *mxlib.Event) error { ev.Author = acct.Conn.User() ev.Room = room.RoomID + // use room id as lock slot key, see account.go in eventInternal dbLockSlot(e.RoomId) defer dbUnlockSlot(e.RoomId) @@ -173,7 +174,7 @@ func handleTxnEvent(e *mxlib.Event) error { if err == nil && created_ev_id != "" { cache_key := fmt.Sprintf("%s/event_seen/%s/%s", room.Protocol, e.RoomId, created_ev_id) - dbKvPut(cache_key, "yes") + dbKvPutLocked(cache_key, "yes") } return err } else { diff --git a/util.go b/util.go index 4e23bb1..cd16a59 100644 --- a/util.go +++ b/util.go @@ -27,15 +27,15 @@ func ezbrSystemRoom(user_mx_id string) (string, error) { } widget_kv_key := "ezbr_widget_on:" + mx_room_id - if config.WebURL != "" && dbKvTestAndSet(widget_kv_key, "yes") { + if config.WebURL != "" && dbKvGet(widget_kv_key) != "yes" { widget := map[string]interface{}{ "type": "m.easybridge", "url": config.WebURL, "name": "Easybridge account configuration dashboard", } err = mx.PutStateAs(mx_room_id, "im.vector.modular.widgets", "ezbr_widget", widget, ezbrMxId()) - if err != nil { - dbKvPut(widget_kv_key, "") + if err == nil { + dbKvPut(widget_kv_key, "yes") } }