diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index cb47b950be..bb659cfc76 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "os" + "sort" "strings" "time" @@ -746,6 +747,11 @@ func (d *Datastore) MarkHostsSeen(ctx context.Context, hostIDs []uint, t time.Ti return nil } + // Sort by host id to prevent deadlocks: + // https://percona.community/blog/2018/09/24/minimize-mysql-deadlocks-3-steps/ + // https://dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks-handling.html + sort.Slice(hostIDs, func(i, j int) bool { return hostIDs[i] < hostIDs[j] }) + if err := d.withRetryTxx(ctx, func(tx sqlx.ExtContext) error { var insertArgs []interface{} for _, hostID := range hostIDs { diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index b74a9fb2bf..a921301ccd 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -653,7 +653,7 @@ func testHostsListStatus(t *testing.T, ds *Datastore) { DetailUpdatedAt: time.Now(), LabelUpdatedAt: time.Now(), PolicyUpdatedAt: time.Now(), - SeenTime: time.Now().Add(-time.Duration(i) * time.Minute), + SeenTime: time.Now().Add(-time.Duration(i) * time.Minute * 2), OsqueryHostID: strconv.Itoa(i), NodeKey: fmt.Sprintf("%d", i), UUID: fmt.Sprintf("%d", i),