# Критический Контекст ## Статус И Источники - Здесь находится исходный Beanstalkd 1.13 на C99. Многопроцессная архитектура ниже принята как направление доработки, но ещё не реализована. - Постановка: [epics/00-overview.md](epics/00-overview.md). Открытые решения перечислены в [epics/01-contract.md](epics/01-contract.md); не считать их уже утверждёнными. - Исходные контракты: `README.md`, `doc/protocol.txt`, `doc/beanstalkd.ronn`, `doc/beanstalkd.1`. Каталог называется `doc`, не `docs`. - `doc/beanstalkd.1` и HTML генерируются из `doc/beanstalkd.ronn`. При изменении CLI обновлять исходник руководства и производные документы штатным способом. - Сохранять приоритеты проекта: стабильность, исправление ошибок, ясность, затем производительность; см. `CONTRIBUTING.md`. ## Принятое Решение - Архитектура: процессы-владельцы групп tubes на одном хосте, frontend для TCP/протокола, IPC между frontend и владельцами, supervisor для управления процессами. - Каждая tube имеет одного владельца; один владелец обслуживает несколько tubes. Все изменения её заданий и планирование выполняются последовательно в event loop владельца. - У каждого owner slot отдельные состояние в памяти и WAL. Owner slot является стабильным логическим идентификатором, а не PID. - На первом этапе consumers не резервируют задания одновременно из нескольких наблюдаемых tubes. Допускается временный watch list из нескольких tubes при настройке, например `watch target`, `ignore default`. На момент `reserve` / `reserve-with-timeout` наблюдаемая tube должна быть одна. - Реакция на неподдерживаемый multi-watch reserve требует явного протокольного решения. Нельзя молча выбрать одну tube или выдать выдуманный стандартный ответ. - Одна наблюдаемая tube не означает один job, одну резервацию или одного владельца на всё время TCP-сессии. Переключение watch list и `reserve-job` могут оставить у сессии резервации разных владельцев. Не вводить дополнительные ограничения без согласования. - Одна горячая tube остаётся последовательной. Масштабируется совокупность независимых tubes, а не выполнение пользовательских задач внешними consumers. ## Владение Динамическими Tubes - Постоянный дескриптор каждой tube не нужен. Объект появляется при `use`, `watch`, инициализации `default` или восстановлении заданий и удаляется после исчезновения удерживающих ссылок. - Задание в любом живом состоянии, включая reserved, удерживает tube. Ссылки от удалённых сессий должны учитываться у владельца; авария frontend должна их освобождать. - Владение определяется до создания объекта: `partition = stable_hash(tube_name) % PARTITION_COUNT`, затем `owner_slot = partition_map[partition]`. - Алгоритм hash, параметры, число разделов и карта одинаковы у всех процессов и стабильны между перезапусками с данными. Их точный формат задаётся в эпиках 01 и 02. - Конкурентный claim отдельной tube не нужен: все обращения с одним именем попадают одному владельцу; он локально выполняет find-or-create. - Маршрутизация сама по себе ничего не создаёт. Например, `stats-tube` и `pause-tube` неизвестного имени должны сохранить `NOT_FOUND`. - Жизненный цикл объекта tube не меняет принадлежность имени. Повторное создание использует того же владельца. - Одновременно активен не более одного процесса на owner slot. При падении перезапускается тот же slot; нельзя направлять его имена к другому живому владельцу как обычный failover. - Карта распределения фиксирована на первом этапе. `hash(name) % live_process_count`, автоматический rebalance и переназначение при сбое запрещены. Миграция требует отдельной процедуры. ## Инварианты Реализации - Не передавать `Job*`, `Tube*`, `Conn*`, `File*` через IPC. Использовать сериализуемые ID, поколения процессов/сессий и явное владение данными. - Сохранять последовательность команд и ответов на TCP-соединении, текущие проверки владения резервацией, priority/FIFO внутри tube, delay, TTR, timeout, `DEADLINE_SOON` и освобождение резерваций при disconnect. - У задания не может быть двух действующих резерваций; один запрос reserve даёт не более одного результата. Повторное выполнение внешним consumer после TTR допустимо: exactly-once не обещается. - ID должны быть уникальны в логическом сервере, маршрутизируемы и безопасны при частичном перезапуске. `job_pri_less()` использует ID для FIFO; новый формат ID не должен нарушать порядок внутри tube. - IPC обязан иметь framing, лимиты памяти, backpressure, отмену ожиданий и защиту от устаревших сообщений. Не повторять автоматически `put` или другую мутацию с неизвестным результатом. - Смерть владельца, frontend и supervisor является частью контракта, а не только эксплуатационной деталью. Недоступность владельца не равна `NOT_FOUND`. - Не делить существующий WAL между независимыми writers и не снимать блокировку каталога ради многопроцессности. Изменение `Jobrec` требует следовать правилам `Walver` в `dat.h`. - Не обещать более сильную durability, чем реализует выбранный режим `-b`, `-f`, `-F`. Успешный IPC-ответ сам по себе не означает fsync. - Политика сохранения отдельного legacy-режима, включения новой архитектуры и переноса старого WAL согласуется в эпике 01 до изменения запуска и форматов. Не считать поддержку двух режимов уже утверждённым объёмом и не ломать существующее поведение/данные без явного решения. ## Карта Кода | Область | Файлы и точки | | --- | --- | | Запуск и event loop | `main.c`, `serv.c:srvserve`, платформенные `linux.c`, `darwin.c`, `freebsd.c`, `sunos.c` | | Протокол, scheduler, timers | `prot.c:dispatch_cmd`, `process_queue`, `prottick`, `conn_timeout` | | Сессии и резервации | `conn.c:conn_reserve_job`, `connclose`, `dat.h:Conn` | | ID и jobs | `job.c:next_id`, `all_jobs`, `job_pri_less`; `dat.h:Job`, `Jobrec` | | Динамические tubes | `tube.c:tube_find_or_make`, `tube_iref`, `tube_dref` | | WAL и восстановление | `walg.c`, `file.c`, `serv.c:srv_acquire_wal`, `prot.c:prot_replay` | | Тесты | `testserv.c`, `testjobs.c`, `testheap.c`, `testms.c`, `testutil.c`, `ct/` | ## Проверки - Сборка: `make`; регрессии: `make check`; существующие микробенчмарки: `make bench`. - Команды требуют поддерживаемого Unix-окружения и toolchain. Нативный Windows не заявлен как поддерживаемая платформа; наличие WSL/контейнеров проверять, а не предполагать. - `make bench` не заменяет end-to-end нагрузочный тест многопроцессного сервера. - Для каждой реализации проверять один и несколько owner slots, ошибки IPC, disconnect, TTR, аварии и восстановление WAL. Критерии: `epics/07-validation.md`. - Не выдавать статический анализ за измеренный выигрыш и не отмечать эпики завершёнными без проверок.