Venta de entradas concurrente en Rust

Introducción

Vas a trabajar con un sistema de ticketing que simula una cola de usuarios intentando comprar entradas en un recinto con varios sectores (numerados y de admisión general). El problema es intrínsecamente concurrente: múltiples usuarios consultan disponibilidad, seleccionan asientos y realizan el pago casi al mismo tiempo, lo que puede provocar condiciones de carrera (doble venta, estados inconsistentes) si no se controla correctamente. Partimos de un flujo de compra por sesión fijo (no modificable) y una cola de usuarios que, en la versión base, es secuencial. Tu tarea será acelerar el sistema orquestando compras en paralelo sin romper la corretitud.

Objetivo

Tu objetivo es mejorar el rendimiento del sistema diseñando una estrategia concurrente que mantenga las garantías de corretitud (no vender dos veces el mismo asiento, no dejar recursos “bloqueados”, etc.). Para ello:

  • Se proporciona un código base con la siguiente estructura:

    • main.rs — punto de entrada de la aplicación (no modificable).
    • config.rs — parámetros de ejecución y utilidades de configuración (no modificable).
    • simulation.rsflujo de compra por sesión, orquestación realista de una compra individual (no modificable).
    • booking.rs — define el trait Booker (API del motor de reservas) y una implementación base.
    • venue.rs — modelo de recinto, sectores y asientos.
    • queue_manager.rsgestión de la cola (implementación inicial o esqueleto).
  • Debes implementar una cola concurrente llamada ConcurrentQueueManager (en queue_manager.rs), responsable de:

    • Gestionar la cola “infinita” de usuarios/sesiones.
    • Lanzar y coordinar hilos (o el mecanismo de concurrencia que elijas) para ejecutar el flujo de compra definido en simulation.rs.
    • Asegurar corretitud (sin doble venta, sin deadlocks, cierre limpio) y mejora de rendimiento respecto a la ejecución secuencial.
  • Puedes crear nuevas implementaciones de Booker (se recomienda p. ej. bloqueo fino por sector/asiento) siempre que respeten el trait Booker expuesto en booking.rs.

    Ej.: FineGrainedBooker, ShardedBooker, etc.

  • Puedes modificar otras partes del código si lo consideras necesario, salvo:

    • No se puede modificar el contenido de main.rs, simulation.rs y config.rs.

En resumen: no toques el flujo de compra por sesión ni la configuración; diseña e implementa tu ConcurrentQueueManager (y si quieres, un Booker más eficiente) para paralelizar la cola de usuarios, manteniendo la consistencia del sistema y acelerando la venta.

Proceso de compra (flujo por sesión)

  1. Entrada desde la cola
    El usuario obtiene turno desde la cola de espera y comienza su sesión de compra.

  2. Vista de sectores disponibles
    El sistema muestra solo los sectores que aún tienen disponibilidad (sin listar butacas).

  3. Selección de sector
    El usuario elige un sector para consultar su detalle.

  4. Vista de asientos disponibles del sector
    Se listan los asientos disponibles (o si hay tickets disponibles si es admisión general).

  5. Selección de asientos
    El usuario selecciona una o varias localidades que desea comprar.

    En la versión concurrente, la selección debe bloquear temporalmente esas localidades para evitar carreras.

  6. Compra (checkout)
    El usuario confirma la compra; los asientos pasan a vendidos de forma atómica para esa sesión.

A tener en cuenta

  • Cambio de criterio del usuario
    El usuario puede deseleccionar asientos o cambiar de sector en cualquier momento antes del checkout. La API del Booker permite liberar selecciones previas.

  • Contención y carreras entre usuarios
    Mientras un usuario decide, otro puede seleccionar los mismos asientos. Esto genera errores (reintentos) y aumenta el tiempo de compra.
    Tu implementación debe minimizar estas situaciones:

    • Reduciendo el tiempo entre listar y seleccionar (evita trabajo innecesario bajo lock).
    • Usando bloqueos finos (p. ej., por sector o por asiento) o particionando el Venue para bajar la contención.
    • Diseñando una estrategia de reintentos que no cause inanición ni livelock.
  • Admisión general En la implementación básica no se tiene en cuenta la admisión general (sin asientos numerados). Puedes aprovechar esta característica para optimizar la distribución de tickets.

Criterios de corrección y evaluación

1. Corretitud (obligatoria)

Se verificará automáticamente que:

  • No hay ventas duplicadas: ninguna localidad (butaca numerada o cupo de GA) se vende más de una vez.
  • Se venden todas las localidades: al finalizar, el total de vendidas coincide con la capacidad total del recinto (o el objetivo de la prueba).
  • Termina correctamente: el programa finaliza sin deadlocks y sin hilos colgados.
  • Contrato respetado: no se modifican main.rs, simulation.rs ni config.rs.
  • API respetada: existe e integra ConcurrentQueueManager; si se implementa otro Booker, cumple el trait Booker.

Cualquier incumplimiento en este bloque invalida la entrega (0 puntos en la prueba correspondiente).

2. Rendimiento (nota principal)

La nota se calculará a partir del tiempo de ejecución en un conjunto de pruebas cronometradas. Para ello, se lanzará una batería de pruebas de varios recintos con combinaciones de sectores numerados y de admisión general diferentes. La nota se calculará a partir del tiempo total de venta de entradas.

Entrega

  • Se realiza en pracdlsi en las fechas allí indicadas. Puedes entregar tantas veces como quieras, solo se corrige la ultima entrega.
  • Crea una carpeta llamada p6 y dentro de ella estarán el código y archivos de texto o PDF donde contestas a las preguntas. Esta carpeta la comprimes en un archivo llamado p6.tgz p.e. así usando el terminal: tar cfz p6.tgz p6