Repository navigation
Conversation
Прочитанные сущности хранилище запоминает в пуле своего потока исполнения (в данных потока), а не в одном пуле на все потоки. Внутри потока на идентификатор по-прежнему один экземпляр, а разные потоки получают разные экземпляры одной строки: чтение в одном потоке больше не стирает несохраненные правки другого и не смешивает снимки строки, прочитанные в разное время. ХранилищеСущностей.Закрыть() отбрасывает экземпляры всех потоков: пул своего потока освобождается сразу, пулы других - при их следующем обращении к хранилищу (по номеру очистки). Потерянное обновление при двух сохранениях одной строки это не лечит: остается сохраненное последним, это описано в документации. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughПул сущностей теперь хранится отдельно для каждого потока. Хранилище заменяет пул после очистки. Создание активных записей использует зарегистрированные типы. Добавлены тесты создания экземпляров, повторного чтения и очистки пулов. ChangesЭкземпляры сущностей и пулы потоков
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant Поток
participant ХранилищеСущностей
participant ДанныеПотока
participant РаботаСКоннекторами
Поток->>ХранилищеСущностей: ПолучитьПулСущностей
ХранилищеСущностей->>ДанныеПотока: Получить пул и проверить номер очистки
ДанныеПотока-->>ХранилищеСущностей: Пул текущего потока
ХранилищеСущностей-->>РаботаСКоннекторами: Передать пул
РаботаСКоннекторами->>РаботаСКоннекторами: Получить экземпляр по идентификатору
РаботаСКоннекторами->>РаботаСКоннекторами: При отсутствии создать и вставить экземпляр
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The reviewed changes preserve the documented entity-instance and pool-cleanup behavior. No actionable merge-blocking issue was established. Architecture SummaryArchitecture risk: 🔵 Low · up to The change affects 4 systems. Changed systems: Architecture concerns Review details
Pre-merge checks |
|
…го один раз Пул сущностей на поток исполнения создает экземпляры заново в каждом потоке, а АктивнаяЗапись строила декоратор компиляцией модуля на каждый экземпляр (около 1,8 мс). Теперь тип активной записи регистрируется через ЗарегистрироватьВСистемеТипов один раз на класс сущности, и экземпляр создается из него через Новый (около 0,14 мс). Чтение 200 сущностей в новом потоке - 31-57 мс вместо 285-359. Тип общий у всех менеджеров процесса, поэтому хранилище и модель экземпляр получает после создания: значения по умолчанию остались бы в реестре типов decorator навсегда и держали бы хранилище первого менеджера. Тип сущности экземпляра определяется через ОбработкаДекоратора.ИсходныйТип: ТипЗнч у него теперь зарегистрированный тип, а не Сценарий. Нужна decorator 3.1.1 с потокобезопасной регистрацией типов (nixel2007/decorator#34). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Рефлектор - встроенный тип движка, библиотека reflector дает только РефлекторОбъекта и ИнтерфейсОбъекта. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| ТипСущности = ОбработкаДекоратора.ИсходныйТип(Сущность); | ||
| КонецЕсли; | ||
| // Соответствие - Тип сущности: имя зарегистрированного типа ее активной записи. | ||
| Перем ТипыЗаписей; |
There was a problem hiding this comment.
CoW-карта из collectionos 0.9.0?
There was a problem hiding this comment.
Да, перевёл в 784bf15. ТипыЗаписей — КартаКопированиеПриЗаписи, своя БлокировкаРесурса и ТипЗаписи ушли: Создать берёт тип через ВычислитьЕслиОтсутствует. Тип читается из снимка без блокировки, а регистрируется ровно один раз, даже если первые экземпляры класса создают несколько потоков сразу. ВставитьЕслиОтсутствует здесь не подошёл бы: проигравшая регистрация оставила бы лишний тип в системе типов.
Регистрацию вызывает Действие, а оно видит только экспортные методы, поэтому ЗарегистрироватьТипЗаписи стала экспортной (модуль в src/internal).
Влил master (collectionos 0.9.0 из #155). Без PostgreSQL на 2.2.0 и 2.3.0-next — 312 из 312. Пробник: 8 фоновых заданий одновременно впервые создают экземпляр нового класса — во всех один тип (5 запусков на 2.2.0, 5 на next); мутант «прочитать, зарегистрировать, вставить» без атомарности даёт 8 разных типов.
…риЗаписи Тип записи класса берется из снимка карты без блокировки, а при первом обращении регистрируется через ВычислитьЕслиОтсутствует ровно один раз, даже если первые экземпляры создают несколько потоков сразу. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Требует decorator 3.1.1 (nixel2007/decorator#34, «Потокобезопасная регистрация типов») и collectionos 0.9.0 — обе версии уже в
master, он влит в ветку.Что чинит
Экземпляры прочитанных сущностей. Пул сущностей хранилища был один на все потоки: потоки получали один и тот же экземпляр строки и без согласования заполняли его поля. Для каждого дефекта сначала написан тест, красный на
master, потом исправление.masterКак теперь
СоответствиевТекущийПоток().Данныепод ключом хранилища. Пишет и читает его только свой поток, поэтому блокировки нет.ХранилищеСущностей.Закрыть()иМенеджерСущностей.Закрыть()отбрасывают экземпляры всех потоков. Пул своего потока освобождается сразу, пулы других — при их следующем обращении к хранилищу (по номеру очистки,АтомарноеЧисло) или по завершении потока.Цена экземпляров в новом потоке
Общий пул на
masterкешировал не данные — каждое чтение и так идёт в БД, — а собранные экземпляры.АктивнаяЗаписьстроила декоратор компиляцией модуля (ЗагрузитьСценарийИзСтроки) на каждый экземпляр, около 1,8 мс. С пулом на поток каждый новый поток (фоновое задание, запрос веб-сервера) платил бы эту цену заново за каждую прочитанную сущность.Поэтому второй коммит переводит
АктивнаяЗаписьна тип декоратора, зарегистрированный один раз на класс сущности (ЗарегистрироватьВСистемеТипов). Экземпляр создаётся из него черезНовый.КартаКопированиеПриЗаписи:ВычислитьЕслиОтсутствуетчитает снимок без блокировки, а тип класса регистрирует один раз, даже если первые экземпляры создают несколько потоков сразу._ХранилищеСущностейи_ОбъектМоделипроставляются экземпляру после создания. Значения по умолчанию остались бы в реестре типов decorator навсегда и держали бы хранилище первого менеджера.АктивнаяЗапись.ТипСущности— черезОбработкаДекоратора.ИсходныйТип:ТипЗнчэкземпляра теперь зарегистрированный тип, а неСценарий.Замер, InMemory,
Получить200 авторов:Создание экземпляра: 1,7–1,9 мс → 0,13–0,145 мс; регистрация типа — 10–20 мс один раз на класс.
Что меняется снаружи
ПолучитьПулСущностей()отдаётСоответствиетекущего потока вместо общейСинхронизированнаяКарта.ТипЗнчэкземпляра активной записи — зарегистрированный типАктивнаяЗапись_<uuid>, а неСценарий. Исходный класс по-прежнему отдаётОбработкаДекоратора.ИсходныйТип.docs/ПотокобезопаснаяРаботаСБД.md.Тесты
Новый набор
ЭкземплярыСущностейВПотоках(InMemory):ЧтениеВДругомПотокеНеЗатираетПравкуЭкземпляра;ПотокиПолучаютРазныеЭкземплярыОднойСтроки;ЧтениеПосредиСборкиВДругомПотокеНеСмешиваетСнимки— новая фикстураНаблюдательЗадержкиЧтениядержит задание на вложенном чтении ссылки;ОчисткаХранилищаОтбрасываетЭкземплярыДругихПотоков: зелёный и наmaster, мутант «без номера очистки» тест поймал.Первые три на
masterкрасные.В
ХранилищеСущностей:ЭкземплярыСоздаютсяИзЗарегистрированногоТипа— красный до второго коммита;ЭкземплярДругогоМенеджераСохраняетсяЧерезСвоеХранилище: тип общий у менеджеров, а экземпляр сохраняется через своё хранилище. Мутант «служебные поля — значения по умолчанию первой регистрации» тест поймал, а с ним ещё пять тестов набора.Полный прогон:
c2ff803, вместе сosparser0.1.0): 2.2.0 — 321 из 321 (дважды), 2.3.0-next+a02323a1 — 321 из 321 (дважды), 2.2.0 только PostgreSQL — 304 из 304;master, без PostgreSQL: 2.2.0 — 305 из 305, 2.3.0-next+a02323a1 — 305 из 305;КартаКопированиеПриЗаписи, после слияния сmaster(collectionos 0.9.0), без PostgreSQL: 2.2.0 — 312 из 312, 2.3.0-next+a02323a1 — 312 из 312.На 2.2.0 остаётся гонка движка, которая была и на
master: первое параллельноеНовыйодного типа портит кэш фабрик типов (EvilBeaver/OneScript#1762, в 2.3.0-next исправлено). Этот PR её не чинит.🤖 Generated with Claude Code
Summary by CodeRabbit