Arquitectura de Almacenamiento del Grabador
Audience: Engineers changing persistence logic, query semantics, schema, Audiencia: Ingenieros que cambian la lógica de persistencia, la semántica de consultas, el esquema o los backends de almacenamiento.
Tabla de Contenidos
- Resumen Ejecutivo
- Contratos de Rasgos de Almacenamiento
- Backend en memoria
- Backend de SQLite
- Esquema de SQLite e Indexación
- Cumplimiento de la Continuidad de la Cadena
- Semántica de Consulta y Paginación
- Corrupción y Manejo de Errores
- Referencia Cruzada Archivo por Archivo
Resumen Ejecutivo
recorder-store proporciona la abstracción de persistencia y dos backends concretos:
InMemoryStorepara pruebas deterministas y ejecución local,SqliteStorepara operación duradera con WAL y verificaciones transaccionales.
Ambos implementan contratos de rasgos compartidos para operaciones de sobre, adjunto y segmento. F:crates/recorder-store/src/lib.rs L11-L37 F:crates/recorder-store/src/lib.rs L49-L71
Contratos de Rasgos de Almacén
El contrato de almacenamiento se expresa como tres rasgos asíncronos:
EnvelopeStore: agregar/obtener/consultar/cabeza de cadena/segmentar sobres,AttachmentStore: poner/obtener/existe para blobs dirigidos por contenido,SegmentStore: crear/sellar/listar/obtener metadatos y génesis.
Las invariantes centrales incluyen un comportamiento de solo anexar, verificaciones de continuidad de la cadena y la inmutabilidad de segmentos sellados. La creación de segmentos se cierra en caso de fallo: las tiendas rechazan un nuevo segmento cuando ya existe otro segmento abierto o cuando ya existe el ID del segmento. F:crates/recorder-store/src/traits.rs L43-L101 F:crates/recorder-store/src/traits.rs L107-L138 F:crates/recorder-store/src/traits.rs L144-L206
Matiz actual de ingestión de sidecar:
- sidecar mutating ingest uses writer-owned SQLite transaction logic over
streams+segmentsstream identity columns to maintain one open segment por clave de transmisión, - this stream-scoped segment lifecycle is intentionally decoupled from legacy trait-level single-active-segment assumptions used by recorder-era APIs. F:crates/recorder-store/src/traits.rs L43-L101 F:crates/recorder-sidecar/src/ingest.rs
Backend en memoria
InMemoryStore utiliza mapas y vectores protegidos por bloqueo, preservando las verificaciones de invariante pero sin garantías de consistencia ante fallos. F:crates/recorder-store/src/memory.rs L12-L16
Destacados del comportamiento:
- valida el estado del segmento y la continuidad de la cadena al agregar,
- mantiene las actualizaciones de los IDs de sobre primero/último y de la cadena principal,
- aplica reglas de creación de segmento único abierto y sin ID de segmento duplicado,
- admite la enumeración de segmentos deterministas por
created_at, - impone un orden de consulta de sobreenvoltura determinista por
segment_idy luego por secuencia.
F:crates/recorder-store/src/memory.rs L124-L180 F:crates/recorder-store/src/memory.rs L317-L407
SQLite Backend
SqliteStore dirige todas las operaciones de la base de datos a través de un hilo de conexión dedicado (SqliteConnection) para preservar de manera segura la semántica de un solo escritor entre los llamadores asíncronos. F:crates/recorder-store/src/sqlite/mod.rs L12-L22 F:crates/recorder-store/src/sqlite/connection.rs L12-L21
SqliteConnection::execute utiliza sync_channel acotado + canales oneshot para conectar código asíncrono con operaciones síncronas de rusqlite. La admisión en la cola es explícita: la saturación de la cola falla cerrada con StoreError::ConcurrencyConflict en lugar de permitir un crecimiento ilimitado del trabajo en memoria. F:crates/recorder-store/src/sqlite/connection.rs L42-L136 F:crates/recorder-store/src/sqlite/connection.rs L167-L222
La detección de segmentos activos (get_active_segment) ahora falla de manera segura cuando el estado persistido está dañado y contiene múltiples segmentos abiertos. Esto previene un comportamiento de recuperación ambiguo al seleccionar un segmento abierto arbitrario. F:crates/recorder-store/src/sqlite/segment_ops.rs
SqliteStore además expone ayudantes de metadatos tipados sobre store_meta (get_meta, set_meta, set_meta_batch) para el estado de tiempo de ejecución determinista, como los marcadores de idempotencia de rotación de clave de firmante. F:crates/recorder-store/src/sqlite/mod.rs
SQLite open tuning ahora admite controles de tiempo de ejecución explícitos y validados:
- modo de durabilidad sincrónica (
FULLpor defecto), - Páginas de autocheckpoint WAL (predeterminado explícito),
- optional busy-timeout. F:crates/recorder-store/src/sqlite/mod.rs F:crates/recorder-store/src/sqlite/schema.rs F:crates/recorder-store/src/sqlite/mod.rs
Esquema de SQLite e Indexación
La inicialización habilita:
- modo WAL,
- claves foráneas,
- tabla de metadatos del esquema con puerta de versión de esquema de cierre en caso de fallo (
schema_version=2), - segmentos normalizados, sobres, adjuntos y tablas de unión,
- writer/projection tables:
streams,idempotency_entries,query_projection_envelopes, - stream identity columns on
segmentsandenvelopesused by sidecar ordenamiento por flujo y invariantes de rollo en writer-runtime, - índices para patrones de sobreenvoltura/segmento/proyección de consulta deterministas.
F:crates/recorder-store/src/sqlite/schema.rs L111-L144 F:crates/recorder-store/src/sqlite/schema.rs L43-L105
Cumplimiento de la Continuidad de la Cadena
Ambos backends imponen la validación de cadenas en el tiempo de anexado utilizando la recomputación de la cabeza de cadena esperada y la comparación en tiempo constante.
Validación de anexos en memoria: F:crates/recorder-store/src/memory.rs L140-L158
La validación de anexos de SQLite está limitada al ámbito de la transacción:
- verificar que el segmento exista y esté abierto,
- recalcular el hash de cadena esperado,
- rechazar desajuste,
- insertar filas de sobre + adjunto de sobre,
- actualizar los metadatos del segmento de forma atómica.
F:crates/recorder-store/src/sqlite/envelope_ops.rs L42-L141
Semántica de Consulta y Paginación
Las consultas de sobreenvoltura admiten filtrado de múltiples campos, además de continuación de cursor y límite. Las consultas de ámbito de flujo de Sidecar utilizan query_projection_envelopes y ORDER BY stream_sequence ASC dentro del ámbito de (tenant_id, recorder_id). Las consultas de sobreenvoltura de segmento continúan ordenándose por sequence ASC.
F:crates/recorder-store/src/sqlite/envelope_ops.rs L167-L280 F:crates/recorder-store/src/sqlite/envelope_ops.rs L306-L347
La lista de segmentos admite filtros de estado/tiempo/id y ordena por created_at ASC, segment_id ASC para preservar un orden determinista bajo marcas de tiempo iguales en diferentes backend. F:crates/recorder-store/src/sqlite/segment_ops.rs L148-L245
Corrupción y Manejo de Errores
StoreError diferencia explícitamente las rupturas de integridad, los casos no encontrados, los conflictos de concurrencia, las fallas del backend y la detección de corrupción. F:crates/recorder-store/src/error.rs L36-L103
El análisis de segmentos de SQLite trata los valores de DB inválidos como corrupción (uuid inválido, estado desconocido, algoritmo de hash desconocido, marcas de tiempo inválidas). F:crates/recorder-store/src/sqlite/segment_ops.rs L336-L416
Las pruebas del sistema ahora validan el comportamiento de cierre en caso de fallo cuando las filas de SQLite persistidas son manipuladas con datos de UUID/genesis de segmento inválidos entre operaciones de CLI. F:system-tests/tests/suites/persistence.rs L375-L468
Referencia Cruzada Archivo por Archivo
| Área | Archivo | Notas |
|---|---|---|
| Contratos de almacenamiento | crates/recorder-store/src/traits.rs | Invariantes del rasgo de almacenamiento canónico. |
| Tipos de segmento | crates/recorder-store/src/types.rs | Metadatos de segmento y formas de filtro. |
| Backend en memoria | crates/recorder-store/src/memory.rs | Implementación determinista basada en mapas. |
| Fachada de SQLite | crates/recorder-store/src/sqlite/mod.rs | Construcción de almacenamiento y composición de backend. |
| Ayudantes de metadatos de SQLite | crates/recorder-store/src/sqlite/mod.rs | Ayudantes de lectura/escritura store_meta para la persistencia del estado en tiempo de ejecución. |
| Puente de SQLite | crates/recorder-store/src/sqlite/connection.rs | Puente asíncrono de hilo dedicado. |
| Esquema de SQLite | crates/recorder-store/src/sqlite/schema.rs | DDL, índices, versionado de esquema. |
| Operaciones SQL de sobre | crates/recorder-store/src/sqlite/envelope_ops.rs | Lógica de consulta de anexado transaccional y filtro. |
| Operaciones SQL de segmento | crates/recorder-store/src/sqlite/segment_ops.rs | Ciclo de vida del segmento y decodificación de metadatos. |
| Operaciones SQL de adjunto | crates/recorder-store/src/sqlite/attachment_ops.rs | Semántica de poner/obtener/existe dirigida por contenido. |
| Taxonomía de errores | crates/recorder-store/src/error.rs | Modelo de fallo de almacenamiento tipado. |