Hauk & Tharnell
Hauk Hauk
Привет, я тут смотрел логи с кластера, оказалось, незаметная ошибка в многопоточности проскочила. У тебя, с твоим старым кодом, сталкивался с чем-то похожим?
Tharnell Tharnell
Да, видел я эту схему. Захватывается мьютекс, а тот же поток пытается снова войти в него, не освободив сначала. Появляется только при очень удачном переплетении потоков, поэтому ускользает от обычных тестов. Проверь, не используешь ли ты реентерабельные мьютексы там, где можно обойтись обычным, или не вызывает ли какой-то поток функцию, которая в итоге захватывает мьютекс, который он уже держит. Ещё убедись, что с блокировками чтения-записи не происходит несанкционированное повышение прав. В таких микроскопических гонках и прячутся странные ошибки. Если выложишь трассировку стека, я смогу точно указать цепочку вызовов.
Hauk Hauk
Спасибо за разбор. Сейчас посмотрю последнюю информацию об ошибках и отправлю тебе. Это поможет точно определить, что произошло. Спасибо за помощь.
Tharnell Tharnell
Конечно, сними отслеживание, как только сможешь. Я прогоню это через отладчик и посмотрю, где загвоздка. Только будь готов к тому, что придется долго копаться в стеке, если ошибка серьезная.
Hauk Hauk
Понял. Сейчас перешлю трассировку. Ожидай подробный дамп стека – готов разбираться с ним по порядку. Спасибо.
Tharnell Tharnell
Понял, отправляй. Разберу и скажу, где затык. Мы всё сделали, как надо. Понял, отправляй. Разберу и скажу, где затык.
Hauk Hauk
Вот трассировка стека последней аварии. Она довольно длинная, но должна дать тебе наглядное представление о том, где происходит борьба за блокировку. Посмотри на вызовы `ReentrantLock.lock()` в `ConnectionPool.acquireConnection`. Похоже, заблокированный поток пытается захватить блокировку ресурса, который он уже косвенно удерживает, что приводит к сценарию тупика, о котором ты говорил. Если тебе нужны дополнительные подробности по каким-либо из этих кадров, дай знать.
Tharnell Tharnell
Похоже, тут классическая взаимная блокировка – один и тот же поток пытается захватить мьютекс, который он уже держит, через цепочку вызовов. В идеале эту цепочку нужно упростить: либо отпускай мьютекс перед вызовом другого метода, либо перестрой пул, чтобы все запросы и освобождения происходили под одним мьютексом. Если хочешь, пришли код конкретного метода, который вызывает проблемы. А так я покопаюсь в логике пула и посмотрю, можно ли оптимизировать порядок захвата мьютексов.
Hauk Hauk
Понял, сейчас гляну в ConnectionPool.acquireConnection. А пока следи за порядком захвата блокировок – наверняка это и решит проблему.