Files
jRDC-MultiDB-Hikari/RDCConnector.bas
jaguerrau 9c9e2975e9 - 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.
2025-10-29 05:25:56 -06:00

247 lines
8.9 KiB
QBasic

B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=4.19
@EndOfDesignText@
' Class module: RDCConnector
' This class manages the connection pool for a specific database.
' Uses ConnectionPoolManager and delegates to HikariCP.
Sub Class_Globals
' --- 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 ' 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
' Initialization subroutine for a specific database connector.
Public Sub Initialize(DB As String)
' 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
' Load the configuration from the corresponding .properties file.
config = LoadConfigMap(dbKey) ' Ensure it's loaded into the class variable
' Read the parameter tolerance configuration
Dim toleranceSetting As Int = config.GetDefault("parameterTolerance", 0).As(Int)
IsParameterToleranceEnabled = (toleranceSetting = 1)
If IsParameterToleranceEnabled Then
Log($"RDCConnector.Initialize for ${dbKey}: Extra parameter tolerance ENABLED."$)
Else
Log($"RDCConnector.Initialize for ${dbKey}: Extra parameter tolerance DISABLED (strict mode)."$)
End If
' 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" ' Force Hikari
' --- Size precedence logic (HIKARI) ---
Dim maxSizeKey As String = $"pool.${poolType.ToLowerCase}.maximumpoolsize"$
Dim poolSizeString As String
Dim poolSize As Int
' Attempt to read the specific value (pool.hikari.maximumpoolsize).
If config.ContainsKey(maxSizeKey) Then
poolSizeString = config.Get(maxSizeKey)
poolSize = poolSizeString.As(Int)
Else
' If not defined, use the recommended Hikari default (10).
poolSize = 10
End If
If poolSize < 1 Then poolSize = 10 ' Keep it sensible
Log($"RDCConnector: Using MaximumPoolSize for ${poolType} calculated: ${poolSize}"$)
' 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)
' Load and filter ONLY the Pool properties (e.g., those starting with 'pool.hikari.')
LoadPoolProperties(poolType, config)
' Apply STABILITY properties (Pool Properties)
If poolProperties.Size > 0 Then
' Direct application to the local pool.
CallSub2(MyHikariPool, "SetProperties", poolProperties)
End If
' Load specific Driver properties (e.g., Statement Caching)
If config.ContainsKey("DriverShortName") Then
LoadDriverProperties(config.Get("DriverShortName"), config)
End If
' Apply PERFORMANCE properties (Driver Properties)
If driverProperties.Size > 0 Then
' Direct application to the local pool.
CallSub2(MyHikariPool, "SetDriverProperties", driverProperties)
Log($"RDCConnector.Initialize for ${DB}: {driverProperties.Size} Driver properties applied to HikariCP."$)
End If
' 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
' Load static configuration into the global cache
Dim dbKeyToStore As String = DB
If dbKeyToStore = "" Then dbKeyToStore = "DB1"
' 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
' 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)
' 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
' 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
' Load the configuration map
Private Sub LoadConfigMap(DB As String) As Map
Private DBX As String = ""
If DB <> "" Then DBX = "." & DB
Log($"RDCConnector.LoadConfigMap: Reading config${DBX}.properties"$)
Return File.ReadMap("./", "config" & DBX & ".properties")
End Sub
' 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: *** 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
' Get a functional SQL connection from the connection pool.
Public Sub GetConnection(DB As String) As SQL
' 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: 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
End Sub
' 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
For Each k As String In config2.Keys
If k.StartsWith("sql.") Then
newCommands.Put(k, config2.Get(k))
End If
Next
commands = newCommands
Main.commandsMap.Put(DB, commands)
End Sub
' Delegation of statistics from C3P0 to HikariCP
Public Sub GetPoolStats As Map
Dim stats As Map
stats.Initialize
If MyHikariPool.IsInitialized Then
Try
' 2. Call the delegated GetStats method in the HikariCP wrapper.
Dim hikariStats As Map = MyHikariPool.GetStats
Return hikariStats
Catch
' 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", "Local pool MyHikariPool not initialized.")
End If
Return stats
End Sub
' Close the connection pool cleanly
Public Sub Close
If MyHikariPool.IsInitialized Then
' Clean closure of the underlying pool.
MyHikariPool.ClosePool
Log($"RDCConnector.Close: Hikari pool closed cleanly for this connector."$)
End If
' La línea de delegación a Main.ConnectionPoolManager1.ClosePoolByType(poolType) ha sido eliminada.
End Sub
' --- UTILITY SUBROUTINES FOR LOADING PROPERTIES ---
Private Sub LoadDriverProperties(driverShortName As String, config_ As Map)
driverProperties = ExtractProperties($"driver.${driverShortName.trim}."$, config_, Null, Null)
End Sub
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
properties.Initialize
Else
properties = output
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)
If k.ToLowerCase.StartsWith(prefix) Then
' Log($"found ${prefix}"$)
Dim standardizedKey As String = k.SubString(prefixLength).ToLowerCase
' Log("Ponemos: " & $"${newPrefix}${k.SubString(prefixLength)}, ${input.Get(k)}"$)
properties.Put($"${newPrefix}${standardizedKey}"$, input.Get(k))
End If
Next
Return properties
End Sub
Private Sub LoadPoolProperties(poolType As String, config_ As Map)
' Find entries like 'pool.hikari.<property>' and extract them.
poolProperties = ExtractProperties($"pool.${poolType.ToLowerCase}."$, config_, Null, Null)
End Sub