{"record":{"id":"213f0341234df2ae","repo":"vitessio/vitess","slug":"lock-already-acquired","errorCode":null,"errorMessage":"lock already acquired","messagePattern":"lock already acquired","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/query.go","lineNumber":323,"sourceCode":"\tquery := fmt.Sprintf(\"SHOW STATUS LIKE '%s'\", pattern)\n\tqr, err := mysqld.FetchSuperQuery(ctx, query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(qr.Fields) != 2 {\n\t\treturn nil, fmt.Errorf(\"query %#v returned %d columns, expected 2\", query, len(qr.Fields))\n\t}\n\tvarMap := make(map[string]string, len(qr.Rows))\n\tfor _, row := range qr.Rows {\n\t\tvarMap[row[0].ToString()] = row[1].ToString()\n\t}\n\treturn varMap, nil\n}\n\n// ExecuteSuperQuery allows the user to execute a query as a super user.\nfunc (mysqld *Mysqld) AcquireGlobalReadLock(ctx context.Context) error {\n\tif mysqld.lockConn != nil {\n\t\treturn errors.New(\"lock already acquired\")\n\t}\n\n\tconn, err := getPoolReconnect(ctx, mysqld.dbaPool)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = mysqld.executeSuperQueryListConn(ctx, conn, []string{\"FLUSH TABLES WITH READ LOCK\"})\n\tif err != nil {\n\t\tconn.Recycle()\n\t\treturn err\n\t}\n\n\tmysqld.lockConn = conn\n\treturn nil\n}\n\nfunc (mysqld *Mysqld) ReleaseGlobalReadLock(ctx context.Context) error {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/query.go#L305-L341","documentation":"AcquireGlobalReadLock enforces a single lock connection per Mysqld instance: mysqld.lockConn must be nil. If a read lock was already acquired (and not yet released), calling AcquireGlobalReadLock again returns this error, because two concurrent lock holders on the same connection state are not supported. Acquiring the lock twice would overwrite the remembered connection and leak the first lock.","triggerScenarios":"Calling AcquireGlobalReadLock twice without an intervening ReleaseGlobalReadLock; concurrent goroutines both acquiring the lock on the same Mysqld; a previous owner failing to release due to an error path skipping ReleaseGlobalReadLock.","commonSituations":"Refactored backup/health-check code that forgot a matching release; concurrent tasks sharing one Mysqld instance; leaked lockConn after a partial failure between acquire and release.","solutions":["Ensure every AcquireGlobalReadLock has a matching ReleaseGlobalReadLock (defer or finally-style cleanup)","Check and serialize lock acquisition — do not call AcquireGlobalReadLock concurrently on the same Mysqld","If the lock is stuck because of a leaked connection, restart the owning component or recreate the Mysqld instance so lockConn resets"],"exampleFix":"// before\nmysqld.AcquireGlobalReadLock(ctx)\n// ... forgot release ...\nmysqld.AcquireGlobalReadLock(ctx) // error: lock already acquired\n// after\nif err := mysqld.AcquireGlobalReadLock(ctx); err == nil {\n    defer mysqld.ReleaseGlobalReadLock(ctx)\n}","handlingStrategy":"try-catch","validationCode":"if mysqld.HasGlobalReadLock() { // if such an accessor exists; otherwise track locally\n    return errors.New(\"global read lock already held by this process\")\n}\nerr := mysqld.AcquireGlobalReadLock(ctx)","typeGuard":null,"tryCatchPattern":"if err := mysqld.AcquireGlobalReadLock(ctx); err != nil {\n    if strings.Contains(err.Error(), \"lock already acquired\") {\n        // either skip (lock already held) or wait and retry\n        return nil\n    }\n    return err\n}\ndefer mysqld.ReleaseGlobalReadLock(ctx)","preventionTips":["Always pair acquire with a deferred release","Serialize lock acquisition with a local mutex around the Mysqld","Avoid sharing one Mysqld instance across components that each need the read lock"],"tags":["go","mysqlctl","locking","global-read-lock","api-misuse"],"backgroundTag":"lock-already-held","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}