Skip to content

open-sdbl 0.8.0

Latest

Choose a tag to compare

@dobpilot dobpilot released this 22 Sep 11:35

Релиз после 0.7.0: open-sdbl-db научился отдавать не только имена, которые нужны компилятору, но и саму конфигурацию — одним чтением, из той же read-only транзакции, что и метаданные. Изменение оформлено спецификацией OpenSpec (crate-architecture, onec-metadata, access-rights).

Зачем

Потребителю, которому нужны ресурсы конфигурации, приходилось читать Config второй раз — уже после закрытия сеанса, против базы, о которой он больше ничего не знает. Между двумя чтениями конфигурацию могли обновить, расширение включить, ресурс переписать, и ничто в результате об этом бы не сказало.

Согласованное получение конфигурации

use open_sdbl_db::{DatabaseSession, Limits, NoProgress};

let mut session =
    DatabaseSession::connect(&connection, &credentials, Limits::default()).await?;
let configuration = session.configuration(&mut NoProgress).await?;

// Снимок и отчёт — те же, что вернул бы `metadata()`.
let snapshot = &configuration.metadata;
// Каждый ресурс таблицы `Config`, собранный из всех `PartNo`, байтами как
// их хранит база: сырой DEFLATE, без распаковки и перекодирования.
for resource in &configuration.config_resources {
    let _ = (&resource.file_name, &resource.compressed);
}
// Расширения в порядке применения платформой, каждое со своими ресурсами.
for extension in &configuration.extensions {
    if extension.active == Some(false) {
        continue;
    }
    let _ = (&extension.identity, &extension.name, extension.order, &extension.resources);
}

AcquiredConfiguration несёт metadata, report, layout, config_resources и extensions; AcquiredExtension — identity, name, active, order, resources. Операция есть и на DatabaseSession, и на обеих сессиях провайдеров, и как свободная acquire_configuration над MetadataSource.

Что операция обещает и чего не обещает

Второго конвейера метаданных и второго пути к СУБД нет: acquire_metadata стала обёрткой над одним внутренним получением, план различается ровно одним шагом. Возвращаются те самые ресурсы, из которых разрешён снимок, — конфигурация читается один раз, а не дважды.

Это не атомарный снимок базы. Транзакция идёт на READ COMMITTED: каждый оператор видит зафиксированное на момент своего начала, и запись в базу во время чтения может развести соседние операторы. Поднять изоляцию бесплатно нельзя — у SQL Server нет MVCC-уровня без ALLOW_SNAPSHOT_ISOLATION, настройки базы, которой библиотека не вправе требовать, а блокирующие уровни заставили бы read-only инструмент блокировать писателей. Поэтому сужен контракт, а не поднята изоляция: операция убирает второе чтение после закрытия сеанса, а узнать, сдвинулась ли конфигурация, можно сравнением CONFIG_FINGERPRINT до и после. Результат публикуется только после успешного завершения всего чтения; любая ошибка откатывает транзакцию и не отдаёт частичный результат.

Расширения

Ресурсы группируются по корневому индексу каждого расширения, а не по имени в content-addressed ConfigCAS, поэтому одинаковые имена в двух расширениях не сливаются. Идентичность — _IDRRef в hex, переживает переименование; порядок — _ExtensionOrder.

Признак применяемости измерен, а не угадан: на базе с двумя расширениями, одинаковыми во всём, кроме того, что платформа применяет одно и не применяет другое, записи по 177 байт различаются в корневом ключе, одном символе синонима и байте на три от конца — 0x82 у применяемого, 0x81 у остального. Оба блоба легли фикстурами.

active — Option<bool>. Разбор _ExtensionZippedInfo знает свои теги и останавливается на любом другом, а флаг принимается, только если разбор дошёл до терминатора и прошёл этот байт именно как односложный тег, а не как payload неизвестного счётного поля. Иначе активность неизвестна: сообщить false про расширение, которое база применяет, значило бы заставить потребителя пропустить живой код.

Пределы и расход памяти

ConfigResource::compressed — Arc<[u8]>: общая строка хранилища и партии декодера стоят ссылку, а не копию конфигурации. В Limits добавлены config_resource_limit (1 000 000) и config_retained_byte_limit (2 ГиБ). Потолки применяются к каждому собираемому хранилищу по отдельности — сначала Config, затем самостоятельно ConfigCAS, — и оба набора удерживаются одновременно, поэтому пик равен потолку столько раз, сколько хранилищ собирается. Totals проверяются до первой строки ресурсов, а потолок повторно — по фактически пришедшему, поскольку totals это отдельный оператор и может устареть. При превышении возвращается типизированная DbError, а не OOM.

Прочее

  • DatabaseSession::metadata не изменился: та же сигнатура, тот же результат, та же цена — по-прежнему поток с фильтром, ничего не удерживающий.
  • Новые SELECT-only выражения CONFIG_ALL, CONFIG_ALL_LEGACY, CONFIG_ALL_TOTALS у обоих провайдеров, в обоих вариантах раскладки; EXTENSIONS теперь отдаёт идентичность и порядок рядом с именем.
  • open_sdbl::metadata::is_config_metadata_resource задаёт фильтр имён ресурсов один раз — тот же, что кодируют выражения обоих провайдеров.
  • InfoBaseUser::can_authenticate() — владелец правила «есть ли у пользователя способ войти»: стандартная аутентификация или непустой логин ОС. Ни список выбора, ни AdmRole, ни роли на ответ не влияют; AdmRole — право, а не способ входа.

Новых production-зависимостей не добавлено. cargo tree -p open-sdbl -e normal по-прежнему пуст: ядро остаётся без зависимостей и без I/O.