- VERSION 5.10.27

- feat(arquitectura): Consolidación de estabilidad y diagnóstico.
- refactor: Arquitectura de base de datos local y políticas de logs.
- arch(sqlite): Aislamiento total de las conexiones SQLite en SQL_Auth y SQL_Logs. Esto protege las operaciones de autenticación críticas de la alta carga de I/O generada por el subsistema de logs.
- feat(logs): Implementación de modo de almacenamiento flexible para logs (disco o en memoria), mejorando la capacidad de testing.
- refactor(logs): Se estandariza el límite de retención de registros a 10,000 para todas las tablas de logs, y se renombra la subrutina de limpieza a borraArribaDe10000Logs.
This commit is contained in:
jaguerrau
2025-10-29 05:25:49 -06:00
parent 4c7639f867
commit 9c9e2975e9
12 changed files with 1390 additions and 1374 deletions

View File

@@ -4,171 +4,167 @@ ModulesStructureVersion=1
Type=Class
Version=4.19
@EndOfDesignText@
' Módulo de clase: RDCConnector
' Esta clase gestiona el pool de conexiones a una base de datos específica.
' REFRACTORIZADO: Usa ConnectionPoolManager y delega a HikariCP.
' Class module: RDCConnector
' This class manages the connection pool for a specific database.
' Uses ConnectionPoolManager and delegates to HikariCP.
Sub Class_Globals
' --- Variables globales de la clase ---
Private pool As ConnectionPoolManager ' Usa el Manager para la modularidad
Private MyHikariPool As HikariConnectionPool ' <-- NUEVO: Pool dedicado a esta DBKey.
Private DebugQueries As Boolean = False ' Bandera para activar/desactivar el modo de depuración
Public commands As Map ' Comandos SQL cargados
' --- Class global variables ---
Private MyHikariPool As HikariConnectionPool ' Dedicated pool for this DBKey.
Private DebugQueries As Boolean = False ' Flag to enable/disable debug mode
Public commands As Map ' Loaded SQL commands
Public serverPort As Int
Public usePool As Boolean = True
Public config As Map ' Configuración completa (JdbcUrl, User, Password, etc.)
Public IsParameterToleranceEnabled As Boolean ' Tolerancia a parámetros de más
Dim driverProperties As Map ' CRÍTICO: Propiedades específicas del driver (MySQL statement caching)
Private configLocation As String ' Ubicación del archivo de configuración
Public config As Map ' Complete configuration (JdbcUrl, User, Password, etc.)
Public IsParameterToleranceEnabled As Boolean ' Tolerance for extra parameters
Dim driverProperties As Map ' Specific driver properties (MySQL statement caching)
Private configLocation As String ' Configuration file location
Private poolProperties As Map
End Sub
' Subrutina de inicialización para el conector de una base de datos específica.
' Initialization subroutine for a specific database connector.
Public Sub Initialize(DB As String)
' Nota: Este código asume que MyHikariPool ya está declarado en Class_Globals
Dim dbKey As String = DB ' Usaremos DB como la llave
' Note: This code assumes MyHikariPool is already declared in Class_Globals
Dim dbKey As String = DB ' We will use DB as the key
If DB.EqualsIgnoreCase("DB1") Then dbKey = ""
poolProperties.Initialize
driverProperties.Initialize
' PASO 1: Cargar la configuración desde el archivo .properties correspondiente.
config = LoadConfigMap(dbKey) ' Aseguramos la carga en la variable de clase [1]
' Load the configuration from the corresponding .properties file.
config = LoadConfigMap(dbKey) ' Ensure it's loaded into the class variable
' Lectura de la configuración de tolerancia de parámetros
' Read the parameter tolerance configuration
Dim toleranceSetting As Int = config.GetDefault("parameterTolerance", 0).As(Int)
IsParameterToleranceEnabled = (toleranceSetting = 1)
If IsParameterToleranceEnabled Then
Log($"RDCConnector.Initialize para ${dbKey}: Tolerancia a parámetros extras, HABILITADA."$)
Log($"RDCConnector.Initialize for ${dbKey}: Extra parameter tolerance ENABLED."$)
Else
Log($"RDCConnector.Initialize para ${dbKey}: Tolerancia a parámetros extras, DESHABILITADA (modo estricto)."$)
Log($"RDCConnector.Initialize for ${dbKey}: Extra parameter tolerance DISABLED (strict mode)."$)
End If
' Bloque Try-Catch para la inicialización y configuración del pool.
' Try-Catch block for pool initialization and configuration.
Try
Dim driverClass As String = config.Get("DriverClass")
Dim jdbcUrl As String = config.Get("JdbcUrl")
Dim aUser As String = config.Get("User")
Dim aPassword As String = config.Get("Password")
Dim poolType As String = "Hikari" ' Forzamos Hikari
Dim poolType As String = "Hikari" ' Force Hikari
' *** INICIO DE LA LÓGICA DE PRECEDENCIA DE TAMAÑO (HIKARI) ***
' --- Size precedence logic (HIKARI) ---
Dim maxSizeKey As String = $"pool.${poolType.ToLowerCase}.maximumpoolsize"$
Dim poolSizeString As String
Dim poolSize As Int
' Intentamos leer el valor específico (pool.hikari.maximumpoolsize).
' Attempt to read the specific value (pool.hikari.maximumpoolsize).
If config.ContainsKey(maxSizeKey) Then
poolSizeString = config.Get(maxSizeKey)
poolSize = poolSizeString.As(Int)
Else
' Si no está definido, usamos el default recomendado por Hikari (10). [2]
' If not defined, use the recommended Hikari default (10).
poolSize = 10
End If
If poolSize < 1 Then poolSize = 10 ' Mantenemos la sensatez
Log($"RDCConnector: Usando MaximumPoolSize para ${poolType} calculado: ${poolSize}"$)
If poolSize < 1 Then poolSize = 10 ' Keep it sensible
Log($"RDCConnector: Using MaximumPoolSize for ${poolType} calculated: ${poolSize}"$)
' *** PASO 2: INICIALIZA/CREA EL POOL LOCALMENTE (Decoupling CRÍTICO) ***
If MyHikariPool.IsInitialized = False Then MyHikariPool.Initialize ' Inicializa el wrapper local
' Crea el pool subyacente (DataSource) en esta instancia dedicada. [3]
' Initialize/Create the pool locally
If MyHikariPool.IsInitialized = False Then MyHikariPool.Initialize ' Initialize the local wrapper
' Create the underlying pool (DataSource) in this dedicated instance.
MyHikariPool.CreatePool2(driverClass, jdbcUrl, aUser, aPassword, poolSize)
' PASO 3a: Cargar y filtrar SOLO las propiedades del Pool (ej. las que comienzan con 'pool.hikari.')
' Load and filter ONLY the Pool properties (e.g., those starting with 'pool.hikari.')
LoadPoolProperties(poolType, config)
' PASO 3b: Aplicar propiedades de ESTABILIDAD (Pool Properties)
' Apply STABILITY properties (Pool Properties)
If poolProperties.Size > 0 Then
' Aplicación directa al pool local. [4]
' Direct application to the local pool.
CallSub2(MyHikariPool, "SetProperties", poolProperties)
End If
' PASO 4: Cargar propiedades específicas del Driver (ej. Statement Caching)
' Load specific Driver properties (e.g., Statement Caching)
If config.ContainsKey("DriverShortName") Then
LoadDriverProperties(config.Get("DriverShortName"), config)
End If
' PASO 5: Aplicar propiedades de RENDIMIENTO (Driver Properties)
' Apply PERFORMANCE properties (Driver Properties)
If driverProperties.Size > 0 Then
' Aplicación directa al pool local. [5]
' Direct application to the local pool.
CallSub2(MyHikariPool, "SetDriverProperties", driverProperties)
Log($"RDCConnector.Initialize para ${DB}: {driverProperties.Size} propiedades del Driver aplicadas a HikariCP."$)
Log($"RDCConnector.Initialize for ${DB}: {driverProperties.Size} Driver properties applied to HikariCP."$)
End If
' PASO 6 (Prueba de vida): Forzar la creación de conexiones iniciales y verificar el estado.
' Esto garantiza el fail-fast. [6]
' Force initial connection creation and check status.
' This ensures fail-fast.
Dim tempCon As SQL = MyHikariPool.GetConnection
If tempCon.IsInitialized Then
tempCon.Close
End If
' Cargar configuración estática en el cache global
' Load static configuration into the global cache
Dim dbKeyToStore As String = DB
If dbKeyToStore = "" Then dbKeyToStore = "DB1"
' Almacenamos el mapa completo (configuración estática + métricas dinámicas iniciales) en el cache global.
' GetPoolStats ahora usa MyHikariPool.
' Store the complete map (static config + initial dynamic metrics) in the global cache.
' GetPoolStats now uses MyHikariPool.
Dim initialPoolStats As Map = GetPoolStats
Main.LatestPoolStats.Put(dbKeyToStore, initialPoolStats)
Catch
' Si ocurre un error durante la inicialización del pool o al forzar la conexión.
Dim ErrorMsg As String = $"RDCConnector.Initialize para ${DB}: ERROR CRÍTICO al inicializar/forzar conexión: ${LastException.Message}"$
' If an error occurs during pool initialization or when forcing the connection.
Dim ErrorMsg As String = $"RDCConnector.Initialize for ${DB}: CRITICAL ERROR initializing/forcing connection: ${LastException.Message}"$
Log(ErrorMsg)
Main.LogServerError("ERROR", "RDCConnector.Initialize", ErrorMsg, DB, Null, Null)
' Si falla la inicialización, la instancia local MyHikariPool se queda inutilizada.
' Aquí podríamos considerar la opción de llamar a MyHikariPool.ClosePool para asegurar
' que no queden recursos parciales, aunque HikariCP debería manejarse con fail-fast.
' If initialization fails, the local MyHikariPool instance remains unusable.
' We could consider calling MyHikariPool.ClosePool here to ensure
' that no partial resources are left, although HikariCP should handle fail-fast.
End Try
' Carga los comandos SQL predefinidos de esta base de datos en el mapa global 'commandsMap' de Main.
' Load predefined SQL commands for this database into Main's global 'commandsMap'.
If dbKey = "" Then dbKey = "DB1"
LoadSQLCommands(config, dbKey)
serverPort = config.Get("ServerPort")
End Sub
' Carga el mapa de configuración
' Load the configuration map
Private Sub LoadConfigMap(DB As String) As Map
Private DBX As String = ""
If DB <> "" Then DBX = "." & DB
Log($"RDCConnector.LoadConfigMap: Leemos el config${DBX}.properties"$)
Log($"RDCConnector.LoadConfigMap: Reading config${DBX}.properties"$)
Return File.ReadMap("./", "config" & DBX & ".properties")
End Sub
' Obtiene la sentencia SQL completa para un comando dado.
' Get the complete SQL statement for a given command.
Public Sub GetCommand(DB As String, Key As String) As String
commands = Main.commandsMap.Get(DB).As(Map)
If commands.ContainsKey("sql." & Key) = False Then
Dim ErrorMsg As String = $"RDCConnector.GetCommand: *** Comando no encontrado: '${Key}' para DB: '${DB}' ***"$
Dim ErrorMsg As String = $"RDCConnector.GetCommand: *** Command not found: '${Key}' for DB: '${DB}' ***"$
Log(ErrorMsg)
Main.LogServerError("ERROR", "RDCConnector.GetCommand", ErrorMsg, DB, Key, Null)
End If
Return commands.Get("sql." & Key)
End Sub
' Obtiene una conexión SQL funcional del pool de conexiones.
' Get a functional SQL connection from the connection pool.
Public Sub GetConnection(DB As String) As SQL
' If DB.EqualsIgnoreCase("DB1") Then DB = ""
' If DebugQueries Then LoadSQLCommands(LoadConfigMap(DB), DB) ' Deshabilitado por defecto. [13]
' Devolvemos la conexión del pool local, si está inicializado.
' El ConnectionPoolManager ha sido removido. La delegación debe ir directamente
' al pool dedicado de HikariCP. Esto simplifica la ruta crítica.
If MyHikariPool.IsInitialized Then
Return MyHikariPool.GetConnection
Else
Log($"ERROR: Intento de obtener conexión de DBKey ${DB}, pero MyHikariPool no está inicializado."$)
' Devolver Null o lanzar excepción, dependiendo del manejo de errores deseado.
Log($"ERROR: Attempt to get connection for DBKey ${DB}, but MyHikariPool is not initialized."$)
' Es crucial retornar Null si no está inicializado para que el handler capture el error.
Return Null
End If
' ANTES: Return Main.ConnectionPoolManager1.GetConnection
End Sub
' Carga todos los comandos SQL del mapa de configuración en el mapa global 'commandsMap' de Main.
' Load all SQL commands from the config map into Main's global 'commandsMap'.
Private Sub LoadSQLCommands(config2 As Map, DB As String)
Dim newCommands As Map
newCommands.Initialize
@@ -181,48 +177,45 @@ Private Sub LoadSQLCommands(config2 As Map, DB As String)
Main.commandsMap.Put(DB, commands)
End Sub
' ** Delegación de estasticas de C3P0 a HikariCP **
' Delegation of statistics from C3P0 to HikariCP
Public Sub GetPoolStats As Map
Dim stats As Map
stats.Initialize
If MyHikariPool.IsInitialized Then
Try
' 2. Llamamos al método delegado GetStats en el wrapper de HikariCP.
' 2. Call the delegated GetStats method in the HikariCP wrapper.
Dim hikariStats As Map = MyHikariPool.GetStats
Return hikariStats
Catch
' Fallo en el método GetStats del wrapper.
Dim ErrorMsg As String = $"RDCConnector.GetPoolStats: ERROR CRÍTICO al obtener estadísticas de HikariCP: ${LastException.Message}"$
' Failure in the wrapper's GetStats method.
Dim ErrorMsg As String = $"RDCConnector.GetPoolStats: CRITICAL ERROR getting stats from HikariCP: ${LastException.Message}"$
Log(ErrorMsg)
stats.Put("Error", LastException.Message)
End Try
Else
stats.Put("Error", "Pool local MyHikariPool no inicializado.")
stats.Put("Error", "Local pool MyHikariPool not initialized.")
End If
Return stats
End Sub
' *** NUEVA SUBRUTINA: Cierra el pool de conexiones de forma ordenada ***
' Close the connection pool cleanly
Public Sub Close
If MyHikariPool.IsInitialized Then
' Cierre limpio del pool subyacente.
' Clean closure of the underlying pool.
MyHikariPool.ClosePool
Log($"RDCConnector.Close: Pool Hikari cerrado limpiamente para este conector."$)
Log($"RDCConnector.Close: Hikari pool closed cleanly for this connector."$)
End If
' Ya NO delegamos el cierre al Manager.
' ANTES: Main.ConnectionPoolManager1.ClosePoolByType(poolType) [15]
' La línea de delegación a Main.ConnectionPoolManager1.ClosePoolByType(poolType) ha sido eliminada.
End Sub
' --- SUBRUTINAS DE UTILIDAD PARA CARGA DE PROPIEDADES ---
' --- UTILITY SUBROUTINES FOR LOADING PROPERTIES ---
' [2]
Private Sub LoadDriverProperties(driverShortName As String, config_ As Map)
driverProperties = ExtractProperties($"driver.${driverShortName.trim}."$, config_, Null, Null)
End Sub
' [3]
Private Sub ExtractProperties(prefix As String, input As Map, newPrefix As String, output As Map) As Map
Dim properties As Map
If output = Null Or output.IsInitialized = False Then
@@ -232,7 +225,7 @@ Private Sub ExtractProperties(prefix As String, input As Map, newPrefix As Strin
End If
If newPrefix.EqualsIgnoreCase(Null) Then newPrefix = ""
Dim prefixLength As Int = prefix.Length
' Log($"Prefijo=${prefix}, ${newPrefix}"$)
For Each k As String In input.Keys
' Log(k)
@@ -243,11 +236,11 @@ Private Sub ExtractProperties(prefix As String, input As Map, newPrefix As Strin
properties.Put($"${newPrefix}${standardizedKey}"$, input.Get(k))
End If
Next
Return properties
End Sub
Private Sub LoadPoolProperties(poolType As String, config_ As Map)
' Busca entradas como 'pool.hikari.<propiedad>' y las extrae.
' Find entries like 'pool.hikari.<property>' and extract them.
poolProperties = ExtractProperties($"pool.${poolType.ToLowerCase}."$, config_, Null, Null)
End Sub
End Sub