mirror of
https://github.com/KeymonSoft/jRDC-MultiDB-Hikari.git
synced 2026-04-17 12:56:23 +00:00
- 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.
334 lines
12 KiB
QBasic
334 lines
12 KiB
QBasic
B4J=true
|
|
Group=Default Group
|
|
ModulesStructureVersion=1
|
|
Type=Class
|
|
Version=6.01
|
|
@EndOfDesignText@
|
|
'Class module : HikariConnectionPool
|
|
'Author: Oliver Ackermann
|
|
'Created on: 2018/05/07
|
|
'Based on: https://github.com/AnywhereSoftware/B4J_Server/blob/master/src/anywheresoftware/b4j/object/ConnectionPool.java
|
|
'Resources:
|
|
' https://github.com/brettwooldridge/HikariCP
|
|
' addDataSourceProperty - individual driver property
|
|
' setDataSourceProperties - Java Property values
|
|
|
|
Sub Class_Globals
|
|
Private poolJO As JavaObject
|
|
Private poolProperties As Map
|
|
Private PoolSizeConfig As Int
|
|
Private MinIdleConfig As Int
|
|
Private MaxLifeConfig As Long
|
|
Private ConnTimeoutConfig As Long
|
|
Private LeakDetectionThresholdConfig As Long
|
|
Private KeepAliveTimeConfig As Long
|
|
End Sub
|
|
|
|
Public Sub Initialize
|
|
Dim properties As Map
|
|
properties.Initialize
|
|
|
|
'Frequently used
|
|
properties.Put("autocommit", "boolean")
|
|
properties.Put("connectiontimeout", "int")
|
|
properties.Put("idletimeout", "int")
|
|
properties.Put("maxlifetime", "int")
|
|
properties.Put("connectiontestquery", "string")
|
|
properties.Put("minimumidle", "int")
|
|
properties.Put("maximumpoolsize", "int")
|
|
properties.Put("poolname", "string")
|
|
properties.Put("keepalivetime", "int")
|
|
|
|
'Infrequently used
|
|
properties.Put("initializationfailtimeout", "int")
|
|
properties.Put("isolateinternalqueries", "boolean")
|
|
properties.Put("allowpoolsuspension", "boolean")
|
|
properties.Put("readonly", "boolean")
|
|
properties.Put("registermbeans", "boolean")
|
|
properties.Put("connectioninitsql", "string")
|
|
properties.Put("validationtimeout", "int")
|
|
properties.Put("leakdetectionthreshold", "int")
|
|
|
|
poolProperties = properties
|
|
End Sub
|
|
|
|
'Creates the pool.
|
|
' driverClass - The JDBC driver class.
|
|
' jdbcUrl - JDBC connection url.
|
|
' aUser / aPassword - Connection credentials.
|
|
Public Sub CreatePool(driverClass As String, jdbcUrl As String, aUser As String, aPassword As String)
|
|
CreatePool2(driverClass, jdbcUrl, aUser, aPassword, 0)
|
|
End Sub
|
|
|
|
'Creates the pool.
|
|
' driverClass - The JDBC driver class.
|
|
' jdbcUrl - JDBC connection url.
|
|
' aUser / aPassword - Connection credentials.
|
|
' poolSize - Maximum size of connection pool. Pool's default used when < 1.
|
|
Public Sub CreatePool2(driverClass As String, jdbcUrl As String, aUser As String, aPassword As String, poolSize As Int)
|
|
Dim jo As JavaObject
|
|
poolJO = jo.InitializeNewInstance("com.zaxxer.hikari.HikariDataSource", Null)
|
|
poolJO.RunMethod("setDriverClassName",Array As Object(driverClass))
|
|
poolJO.RunMethod("setJdbcUrl", Array As Object(jdbcUrl))
|
|
poolJO.RunMethod("setUsername", Array As Object(aUser))
|
|
poolJO.RunMethod("setPassword", Array As Object(aPassword))
|
|
If poolSize > 0 Then poolJO.RunMethod("setMaximumPoolSize", Array As Object(poolSize))
|
|
End Sub
|
|
|
|
Public Sub CreatePool3(options As Map)
|
|
CreatePool2(options.Get("driver"), options.Get("url"), options.Get("user"), options.Get("password"), options.Get("poolsize"))
|
|
End Sub
|
|
|
|
'https://github.com/openbouquet/HikariCP/blob/master/src/main/java/com/zaxxer/hikari/HikariConfig.java
|
|
'HikariConfig can use Properties object. But this must be done before creating the pool. The pool than is created using
|
|
'that HikariConfig object.
|
|
Public Sub SetProperties(properties As Map)
|
|
|
|
' Optimal default values for HikariCP (in milliseconds)
|
|
Private const DEFAULT_MAX_LIFE As Long = 1750000
|
|
Private const DEFAULT_CONN_TIMEOUT As Long = 30000
|
|
Private const DEFAULT_LEAK_THR As Long = 35000
|
|
Private const DEFAULT_REG_MBEANS As Boolean = True
|
|
Private const DEFAULT_MIN_IDLE As Int = 10
|
|
Private const DEFAULT_MAX_SIZE As Int = 10
|
|
Private const DEFAULT_KEEP_ALIVE_TIME As Long = 300000
|
|
|
|
Dim rawValue As String
|
|
Dim processedKeys As List
|
|
processedKeys.Initialize
|
|
|
|
Dim maxSize As Int ' Temporary variable for the calculated maximum size
|
|
|
|
' 1. MaxLifetime (Long) - Key: maxlifetime
|
|
Dim maxLife As Long
|
|
If properties.ContainsKey("maxlifetime") Then
|
|
rawValue = properties.Get("maxlifetime").As(String).Trim
|
|
maxLife = rawValue
|
|
poolJO.RunMethod("setMaxLifetime", Array As Object(maxLife))
|
|
Log($"Ponemos MaxLifetime: ${maxLife}"$)
|
|
Else
|
|
maxLife = DEFAULT_MAX_LIFE
|
|
poolJO.RunMethod("setMaxLifetime", Array As Object(maxLife))
|
|
Log($"Ponemos (LONG, Default): MaxLifetime, ${DEFAULT_MAX_LIFE}"$)
|
|
End If
|
|
processedKeys.Add("maxlifetime")
|
|
MaxLifeConfig = maxLife ' Store the config value
|
|
|
|
' 2. ConnectionTimeout (Long) - Key: connectiontimeout
|
|
Dim connTimeout As Long
|
|
If properties.ContainsKey("connectiontimeout") Then
|
|
rawValue = properties.Get("connectiontimeout").As(String).Trim
|
|
connTimeout = rawValue
|
|
poolJO.RunMethod("setConnectionTimeout", Array As Object(connTimeout))
|
|
Log($"Ponemos ConnectionTimeout: ${connTimeout}"$)
|
|
Else
|
|
connTimeout = DEFAULT_CONN_TIMEOUT
|
|
poolJO.RunMethod("setConnectionTimeout", Array As Object(connTimeout))
|
|
Log($"Ponemos ConnectionTimeout: ${DEFAULT_CONN_TIMEOUT}"$)
|
|
End If
|
|
processedKeys.Add("connectiontimeout")
|
|
ConnTimeoutConfig = connTimeout ' Store the config value
|
|
|
|
' 3. LeakDetectionThreshold (Long) - Key: leakdetectionthreshold
|
|
Dim leakThr As Long
|
|
If properties.ContainsKey("leakdetectionthreshold") Then
|
|
rawValue = properties.Get("leakdetectionthreshold").As(String).Trim
|
|
leakThr = rawValue
|
|
poolJO.RunMethod("setLeakDetectionThreshold", Array As Object(leakThr))
|
|
Log($"Ponemos LeakDetectionThreshold: ${leakThr}"$)
|
|
Else
|
|
leakThr = DEFAULT_LEAK_THR
|
|
poolJO.RunMethod("setLeakDetectionThreshold", Array As Object(leakThr))
|
|
Log($"Ponemos (LONG, Default): LeakDetectionThreshold, ${DEFAULT_LEAK_THR}"$)
|
|
End If
|
|
processedKeys.Add("leakdetectionthreshold")
|
|
LeakDetectionThresholdConfig = leakThr ' Store the config value
|
|
|
|
' 4. MaximumPoolSize (Int) - Key: maximumpoolsize
|
|
If properties.ContainsKey("maximumpoolsize") Then
|
|
rawValue = properties.Get("maximumpoolsize").As(String).Trim
|
|
maxSize = rawValue.As(Int)
|
|
poolJO.RunMethod("setMaximumPoolSize", Array As Object(maxSize))
|
|
Log($"Ponemos MaximumPoolSize: ${maxSize}"$)
|
|
Else
|
|
maxSize = DEFAULT_MAX_SIZE
|
|
poolJO.RunMethod("setMaximumPoolSize", Array As Object(DEFAULT_MAX_SIZE))
|
|
Log($"Ponemos MaximumPoolSize: ${DEFAULT_MAX_SIZE}"$)
|
|
End If
|
|
processedKeys.Add("maximumpoolsize")
|
|
PoolSizeConfig = maxSize ' Store the config value
|
|
|
|
' 5. MinimumIdle (Int) - Key: minimumidle
|
|
Dim minIdleFinal As Int
|
|
If properties.ContainsKey("minimumidle") Then
|
|
rawValue = properties.Get("minimumidle").As(String).Trim
|
|
minIdleFinal = rawValue.As(Int)
|
|
poolJO.RunMethod("setMinimumIdle", Array As Object(minIdleFinal))
|
|
Log($"Ponemos MinimumIdle: ${minIdleFinal}"$)
|
|
Else
|
|
' APPLY FIXED POOL AXIOM: MinimumIdle = MaximumPoolSize (maxSize)
|
|
minIdleFinal = maxSize
|
|
poolJO.RunMethod("setMinimumIdle", Array As Object(minIdleFinal))
|
|
Log($"Ponemos MinimumIdle: ${minIdleFinal} (Igual a MaximumPoolSize)"$)
|
|
End If
|
|
processedKeys.Add("minimumidle")
|
|
MinIdleConfig = minIdleFinal ' Store the config value
|
|
|
|
' 6. RegisterMbeans (Boolean) - Key: registermbeans
|
|
If properties.ContainsKey("registermbeans") Then
|
|
Dim regMbeans As Boolean = properties.Get("registermbeans")
|
|
poolJO.RunMethod("setRegisterMbeans", Array As Object(regMbeans))
|
|
Log($"Ponemos RegisterMbeans: ${regMbeans}"$)
|
|
Else
|
|
poolJO.RunMethod("setRegisterMbeans", Array As Object(DEFAULT_REG_MBEANS))
|
|
Log($"Ponemos RegisterMbeans: ${DEFAULT_REG_MBEANS}"$)
|
|
End If
|
|
processedKeys.Add("registermbeans")
|
|
|
|
' 7. KeepaliveTime (Long) - Key: keepalivetime
|
|
Dim keepAlive As Long
|
|
If properties.ContainsKey("keepalivetime") Then
|
|
rawValue = properties.Get("keepalivetime").As(String).Trim
|
|
keepAlive = rawValue
|
|
' The minimum accepted value is 30,000 ms [4].
|
|
If keepAlive < 30000 Then keepAlive = 30000
|
|
|
|
poolJO.RunMethod("setKeepaliveTime", Array As Object(keepAlive))
|
|
Log($"Ponemos (LONG, Config): KeepaliveTime, ${keepAlive}"$)
|
|
Else
|
|
keepAlive = DEFAULT_KEEP_ALIVE_TIME
|
|
poolJO.RunMethod("setKeepaliveTime", Array As Object(keepAlive))
|
|
Log($"Ponemos KeepaliveTime: ${DEFAULT_KEEP_ALIVE_TIME} (50 minutes)"$)
|
|
End If
|
|
processedKeys.Add("keepalivetime")
|
|
KeepAliveTimeConfig = keepAlive ' Store the config value
|
|
|
|
' Process remaining properties
|
|
Dim intValue As Int
|
|
Dim booleanValue As Boolean
|
|
Dim variableType As String
|
|
For Each k As String In properties.Keys
|
|
If processedKeys.IndexOf(k) = -1 Then
|
|
If poolProperties.ContainsKey(k) Then
|
|
variableType = poolProperties.Get(k)
|
|
Dim valueToUse As String = properties.Get(k)
|
|
If variableType = "string" Then
|
|
valueToUse = valueToUse.Trim
|
|
End If
|
|
|
|
Dim dynamicMethodName As String = $"set${k}"$
|
|
Try
|
|
If variableType = "int" Then
|
|
intValue = valueToUse
|
|
poolJO.RunMethod(dynamicMethodName, Array As Object(intValue))
|
|
Else If variableType = "string" Then
|
|
poolJO.RunMethod(dynamicMethodName, Array As Object(valueToUse))
|
|
Else If variableType = "boolean" Then
|
|
booleanValue = valueToUse
|
|
GetPoolJO.RunMethod(dynamicMethodName, Array As Object(booleanValue))
|
|
Else
|
|
Log($"Connection pool property ${k} has unsupported variable type of ${variableType}"$)
|
|
End If
|
|
Log($"Ponemos (Remaining): ${k}, ${properties.Get(k)}"$)
|
|
Catch
|
|
Log($"Warning (Remaining): Method: ${dynamicMethodName} not matched or type mismatch for property ${k}. Error: ${LastException.Message}"$)
|
|
End Try
|
|
Else
|
|
Log($"Warning: Property ${k} not supported"$)
|
|
End If
|
|
End If
|
|
Next
|
|
End Sub
|
|
|
|
' Applies specific JDBC Driver properties (e.g., MySQL caching)
|
|
' These properties are applied using addDataSourceProperty, which is not supported in standard SetProperties.
|
|
Public Sub SetDriverProperties(properties As Map)
|
|
' properties is the map extracted by RDCConnector.LoadDriverProperties (e.g., driver.mysql.*).
|
|
Dim value As Object
|
|
For Each k As String In properties.Keys
|
|
value = properties.Get(k)
|
|
' Use addDataSourceProperty to configure the Driver, not the Pool.
|
|
poolJO.RunMethod("addDataSourceProperty", Array As Object(k, value))
|
|
Log($"HikariCP: Driver Property [${k}] added with value: ${value}"$)
|
|
Next
|
|
End Sub
|
|
|
|
'Check if JDBC URL is supported
|
|
Public Sub SupportUrl(jdbcUrl As String) As Boolean
|
|
If jdbcUrl.StartsWith("jdbc:sqlite") Then
|
|
Log("Error: Hikari connection pool does not support SQLite")
|
|
Return False
|
|
End If
|
|
Return True
|
|
End Sub
|
|
|
|
'See if pool's java object supports standard getConnection method
|
|
Public Sub IsStandardConnection As Boolean
|
|
Return True
|
|
End Sub
|
|
|
|
'Get pool's underlying java object. Used if IsStandardConnection is True
|
|
Public Sub GetPoolJO As JavaObject
|
|
Return poolJO
|
|
End Sub
|
|
|
|
'Retrieves a connection from the pool. Make sure to close the connection when you are done with it.
|
|
Public Sub GetConnection As SQL
|
|
Dim newSQL As SQL
|
|
Dim jo As JavaObject = newSQL
|
|
jo.SetField("connection", poolJO.RunMethod("getConnection", Null))
|
|
Return newSQL
|
|
End Sub
|
|
|
|
'Closes all unused pooled connections.
|
|
Public Sub ClosePool
|
|
If poolJO.IsInitialized Then
|
|
poolJO.RunMethod("close", Null)
|
|
End If
|
|
End Sub
|
|
|
|
' WARNING: This subroutine translates internal HikariCP method names
|
|
' to the generic keys (e.g., BusyConnections) that RDCConnector expects.
|
|
' It now includes the STATIC CONFIGURATION saved in the class variables.
|
|
Public Sub GetStats As Map
|
|
Dim stats As Map
|
|
stats.Initialize
|
|
|
|
' 1. ADD STATIC PROPERTIES (STORED CONFIGURATION)
|
|
stats.Put("MaxPoolSize", PoolSizeConfig)
|
|
stats.Put("MinPoolSize", MinIdleConfig)
|
|
stats.Put("MaxLifetime", MaxLifeConfig)
|
|
stats.Put("ConnectionTimeout", ConnTimeoutConfig)
|
|
stats.Put("LeakDetectionThreshold", LeakDetectionThresholdConfig)
|
|
stats.Put("KeepaliveTime", KeepAliveTimeConfig)
|
|
' Note: You can add other relevant static properties here.
|
|
|
|
' 2. GET RUNTIME METRICS (JMX/MBean)
|
|
If poolJO.IsInitialized Then
|
|
Try
|
|
Dim poolMBean As JavaObject = poolJO.RunMethod("getHikariPoolMXBean", Null)
|
|
|
|
Dim busyConn As Object = poolMBean.RunMethod("getActiveConnections", Null)
|
|
stats.Put("BusyConnections", busyConn)
|
|
|
|
Dim idleConn As Object = poolMBean.RunMethod("getIdleConnections", Null)
|
|
stats.Put("IdleConnections", idleConn)
|
|
|
|
Dim activeCount As Int = busyConn
|
|
Dim idleCount As Int = idleConn
|
|
stats.Put("TotalConnections", activeCount + idleCount)
|
|
|
|
Dim awaitingConn As Object = poolMBean.RunMethod("getThreadsAwaitingConnection", Null)
|
|
stats.Put("ThreadsAwaitingConnection", awaitingConn)
|
|
Catch
|
|
Dim ErrorMsg As String = "HikariCP.GetStats: Error getting dynamic metrics from MBean: " & LastException.Message
|
|
Log(ErrorMsg)
|
|
stats.Put("Error_Runtime", ErrorMsg)
|
|
End Try
|
|
Else
|
|
stats.Put("Error", "Pool JO not initialized")
|
|
End If
|
|
|
|
Return stats
|
|
End Sub
|