Skip to content

Latest commit

 

History

History
85 lines (54 loc) · 5.29 KB

File metadata and controls

85 lines (54 loc) · 5.29 KB

Changelog

20.12.2026 race condition в методе acquireUrlLock()

В методе acquireUrlLock() присутствует race condition (состояние гонки):

Сценарий deadlock:

  1. Вкладка A читает URL со статусом pending
  2. Вкладка B читает тот же URL со статусом pending (до того, как A успела записать)
  3. Обе вкладки устанавливают статус processing и свой tabId
  4. Последняя запись побеждает, но обе вкладки считают, что захватили блокировку

Решение

Используем версионность с оптимистичной блокировкой (как в updateHeartbeat):

Объяснение решения

Почему это работает?

  1. Оптимистичная блокировка через версионность:

    • Каждая запись имеет поле version
    • При изменении версия инкрементируется
    • После записи проверяется, что версия соответствует ожидаемой
  2. Атомарность на уровне транзакции:

    • IndexedDB гарантирует, что put() атомарен
    • Если две вкладки попытаются записать одновременно, одна из них перезапишет другую
    • Проверка версии после записи выявляет конфликт
  3. Retry механизм:

    • При конфликте делается до 3 попыток с экспоненциальной задержкой
    • Это увеличивает шансы на успешный захват при высокой конкуренции

Оптимистичная блокировка через версионность - это лучший компромисс для IndexedDB, так как:

  • ✅ Работает во всех браузерах
  • ✅ Не блокирует UI
  • ✅ Простая реализация
  • ✅ Хорошая производительность

20.12.2026 sabberworm/php-css-parser версии 9.x

Проблема в том, что библиотека sabberworm/php-css-parser версии 9.x изменила возвращаемый тип методов селекторов. В версии 9.x метод getSelectors() возвращает массив объектов Selector, которые нельзя напрямую привести к строке через (string).

Суть проблемы:

В версии 8.x: объект Selector можно было привести к строке через (string)$selectorObject

В версии 9.x: нужно явно вызывать метод getSelector(), который возвращает строковое представление селектора.

Update добавляет проверку наличия метода getSelector() и использует его, обеспечивая обратную совместимость с версией 8.x.


18.12.2026 Исправленная версия класса TabSyncManager

Объяснение исправления

Метод updateHeartbeat() в классе TabSyncManager не защищен от параллельной записи. При мультивкладочной работе несколько вкладок могут одновременно читать и записывать данные в TAB_STORE_NAME, что приводит к перезаписи данных других вкладок.

Ключевые изменения:

  1. Версионность записей: Каждая запись в TAB_STORE_NAME теперь содержит поле version, которое инкрементируется при каждом обновлении.

  2. Оптимистичная блокировка:

    • Читаем текущую версию
    • Инкрементируем версию
    • Записываем с новой версией
    • Проверяем, что версия не изменилась после записи
  3. Retry механизм: При обнаружении конфликта версии делаем до 3 попыток с экспоненциальной задержкой (50ms, 100ms, 200ms).

  4. Безопасная очистка: Метод cleanupDeadTabs() также проверяет версию перед удалением, чтобы не удалить запись, которая была только что обновлена другой вкладкой.

Преимущества решения:

  • ✅ Нет блокировок - работает быстро
  • ✅ Обнаруживает конфликты записи
  • ✅ Автоматически повторяет попытку при конфликте
  • ✅ Не требует изменений в схеме IndexedDB (добавляется только поле version)
  • ✅ Совместимо с существующим кодом