mirror of
https://github.com/KeymonSoft/jRDC-Multi.git
synced 2026-04-17 21:06:24 +00:00
- VERSION 5.09.19
- feat(sqlite): Implementa optimización de SQLite (WAL e Índices) - fix(manager): Extiende el comando 'test' para verificar todos los pools de conexión configurados. - Mejoras al subsistema de logs y diagnóstico del servidor jRDC2-Multi. - Cambios principales: 1. Optimización del Rendimiento de SQLite (users.db): * Habilitación de WAL: Se implementó PRAGMA journal_mode=WAL y PRAGMA synchronous=NORMAL en `InitializeSQLiteDatabase`. Esto reduce la contención de disco y mejora el rendimiento de I/O en las escrituras transaccionales de logs por lotes. * Índices de logs: Se agregaron índices a las columnas `timestamp` y `duration_ms` en `query_logs`, y a `timestamp` en `errores`. Esto acelera drásticamente las operaciones de limpieza periódica (`borraArribaDe15000Logs`) y la generación de reportes de consultas lentas (`slowqueries`). 2. Mejora del Comando de Diagnóstico 'test': * Se corrigió el comando `manager?command=test` para que no solo pruebe la conexión de `DB1`, sino que itere sobre `Main.listaDeCP` y fuerce la adquisición y liberación de una conexión (`GetConnection`) en *todos* los `RDCConnector` configurados (DB1, DB2, DB3, etc.). * La nueva lógica garantiza una prueba de vida rigurosa de cada pool C3P0, devolviendo un mensaje detallado del estado de conectividad y registrando un error crítico vía `LogServerError` si algún pool no responde.
This commit is contained in:
134
jRDC_Multi.b4j
134
jRDC_Multi.b4j
@@ -1,19 +1,15 @@
|
||||
AppType=StandardJava
|
||||
Build1=Default,b4j.JRDCMulti
|
||||
File1=config.DB2.properties
|
||||
File10=start2.bat
|
||||
File11=stop.bat
|
||||
File2=config.DB3.properties
|
||||
File3=config.DB4.properties
|
||||
File4=config.properties
|
||||
File5=login.html
|
||||
File6=manager.html
|
||||
File7=reiniciaProcesoBow.bat
|
||||
File8=reiniciaProcesoPM2.bat
|
||||
File9=start.bat
|
||||
File5=reiniciaProcesoBow.bat
|
||||
File6=reiniciaProcesoPM2.bat
|
||||
File7=start.bat
|
||||
File8=start2.bat
|
||||
File9=stop.bat
|
||||
FileGroup1=Default Group
|
||||
FileGroup10=Default Group
|
||||
FileGroup11=Default Group
|
||||
FileGroup2=Default Group
|
||||
FileGroup3=Default Group
|
||||
FileGroup4=Default Group
|
||||
@@ -23,15 +19,15 @@ FileGroup7=Default Group
|
||||
FileGroup8=Default Group
|
||||
FileGroup9=Default Group
|
||||
Group=Default Group
|
||||
Library1=byteconverter
|
||||
Library2=javaobject
|
||||
Library3=jcore
|
||||
Library4=jrandomaccessfile
|
||||
Library5=jserver
|
||||
Library6=jshell
|
||||
Library7=json
|
||||
Library8=jsql
|
||||
Library9=bcrypt
|
||||
Library1=bcrypt
|
||||
Library2=byteconverter
|
||||
Library3=javaobject
|
||||
Library4=jcore
|
||||
Library5=jrandomaccessfile
|
||||
Library6=jserver
|
||||
Library7=jshell
|
||||
Library8=json
|
||||
Library9=jsql
|
||||
Module1=Cambios
|
||||
Module10=Manager
|
||||
Module11=Manager0
|
||||
@@ -49,7 +45,7 @@ Module6=faviconHandler
|
||||
Module7=GlobalParameters
|
||||
Module8=LoginHandler
|
||||
Module9=LogoutHandler
|
||||
NumberOfFiles=11
|
||||
NumberOfFiles=9
|
||||
NumberOfLibraries=9
|
||||
NumberOfModules=17
|
||||
Version=10.3
|
||||
@@ -60,7 +56,7 @@ Version=10.3
|
||||
|
||||
#CommandLineArgs:
|
||||
#MergeLibraries: True
|
||||
' VERSION 5.09.18
|
||||
' VERSION 5.09.19
|
||||
'###########################################################################################################
|
||||
'###################### PULL #############################################################
|
||||
'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
|
||||
@@ -148,7 +144,22 @@ Sub AppStart (Args() As String)
|
||||
#End If
|
||||
' --- Subrutina principal que se ejecuta al iniciar la aplicación ---
|
||||
|
||||
' SSE.Initialize
|
||||
' La subcarpeta es "www"
|
||||
CopiarRecursoSiNoExiste("manager.html", "www")
|
||||
CopiarRecursoSiNoExiste("login.html", "www")
|
||||
|
||||
' --- Copiar los archivos .bat de la raíz ---
|
||||
' La subcarpeta es "" (vacía) porque están en la raíz de "Files"
|
||||
CopiarRecursoSiNoExiste("config.properties", "")
|
||||
CopiarRecursoSiNoExiste("config.DB2.properties", "")
|
||||
CopiarRecursoSiNoExiste("config.DB3.properties", "")
|
||||
CopiarRecursoSiNoExiste("start.bat", "")
|
||||
CopiarRecursoSiNoExiste("start2.bat", "")
|
||||
CopiarRecursoSiNoExiste("stop.bat", "")
|
||||
CopiarRecursoSiNoExiste("reiniciaProcesoBow.bat", "")
|
||||
CopiarRecursoSiNoExiste("reiniciaProcesoPM2.bat", "")
|
||||
'
|
||||
' Log("Verificación de archivos completada.")
|
||||
|
||||
bc.Initialize("BC")
|
||||
QueryLogCache.Initialize
|
||||
@@ -343,7 +354,6 @@ Sub InitializeSQLiteDatabase
|
||||
If File.Exists(File.DirApp, dbFileName) = False Then
|
||||
Log("Creando nueva base de datos de usuarios: " & dbFileName)
|
||||
SQL1.InitializeSQLite(File.DirApp, dbFileName, True)
|
||||
|
||||
' Crear tabla 'users'
|
||||
Dim createUserTable As String = "CREATE TABLE users (username TEXT PRIMARY KEY, password_hash TEXT NOT NULL)"
|
||||
SQL1.ExecNonQuery(createUserTable)
|
||||
@@ -353,6 +363,9 @@ Sub InitializeSQLiteDatabase
|
||||
Dim createQueryLogsTable As String = "CREATE TABLE query_logs (id INTEGER PRIMARY KEY AUTOINCREMENT, query_name TEXT, duration_ms INTEGER, timestamp INTEGER, db_key TEXT, client_ip TEXT, busy_connections INTEGER, handler_active_requests INTEGER)"
|
||||
SQL1.ExecNonQuery(createQueryLogsTable)
|
||||
|
||||
SQL1.ExecNonQuery("PRAGMA journal_mode=WAL;")
|
||||
SQL1.ExecNonQuery("PRAGMA synchronous=NORMAL;")
|
||||
|
||||
' Insertar usuario por defecto
|
||||
Dim defaultUser As String = "admin"
|
||||
Dim defaultPass As String = "12345"
|
||||
@@ -364,10 +377,23 @@ Sub InitializeSQLiteDatabase
|
||||
Log("Creando tabla 'errores' para registrar eventos.")
|
||||
Dim createErrorsTable As String = "CREATE TABLE errores (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, type TEXT, source TEXT, message TEXT, db_key TEXT, command_name TEXT, client_ip TEXT)"
|
||||
SQL1.ExecNonQuery(createErrorsTable)
|
||||
|
||||
If logger Then Log("Creando índices de rendimiento en tablas de logs.")
|
||||
|
||||
' Índice en timestamp para limpieza rápida (DELETE/ORDER BY) en query_logs
|
||||
SQL1.ExecNonQuery("CREATE INDEX idx_query_timestamp ON query_logs(timestamp)")
|
||||
|
||||
' Índice en duration_ms para la consulta 'slowqueries' (ORDER BY)
|
||||
SQL1.ExecNonQuery("CREATE INDEX idx_query_duration ON query_logs(duration_ms)")
|
||||
|
||||
' Índice en timestamp para limpieza rápida de la tabla de errores
|
||||
SQL1.ExecNonQuery("CREATE INDEX idx_error_timestamp ON errores(timestamp)")
|
||||
|
||||
Else
|
||||
SQL1.InitializeSQLite(File.DirApp, dbFileName, True)
|
||||
Log("Base de datos de usuarios cargada.")
|
||||
SQL1.ExecNonQuery("PRAGMA journal_mode=WAL;")
|
||||
SQL1.ExecNonQuery("PRAGMA synchronous=NORMAL;")
|
||||
|
||||
' >>> INICIO: Lógica de migración (ALTER TABLE) si la DB ya existía <<<
|
||||
If logger Then Log("Verificando y migrando tabla 'query_logs' si es necesario.")
|
||||
@@ -671,7 +697,6 @@ Public Sub WriteErrorLogsBatch
|
||||
End Sub
|
||||
|
||||
' --- Borra los registros más antiguos de la tabla 'query_logs' y hace VACUUM. ---
|
||||
' ¡MODIFICADA PARA USAR FILTRADO GLOBAL!
|
||||
Sub borraArribaDe15000Logs 'ignore
|
||||
|
||||
If IsAnySQLiteLoggingEnabled Then ' Solo ejecutar si al menos una DB requiere logs.
|
||||
@@ -690,4 +715,65 @@ Sub borraArribaDe15000Logs 'ignore
|
||||
' Si IsAnySQLiteLoggingEnabled es False, el Timer no debería estar activo.
|
||||
If logger Then Log("AVISO: Tarea de limpieza de logs omitida. El logging global de SQLite está deshabilitado.")
|
||||
End If
|
||||
End Sub
|
||||
End Sub
|
||||
|
||||
'Copiamos recursos del jar al directorio de la app
|
||||
Sub CopiarRecursoSiNoExiste(NombreArchivo As String, SubCarpeta As String)
|
||||
Dim DirDestino As String = File.Combine(File.DirApp, SubCarpeta)
|
||||
|
||||
If SubCarpeta <> "" And File.Exists(DirDestino, "") = False Then
|
||||
File.MakeDir(DirDestino, "")
|
||||
End If
|
||||
|
||||
Dim ArchivoDestino As String = File.Combine(DirDestino, NombreArchivo)
|
||||
|
||||
If File.Exists(DirDestino, NombreArchivo) = False Then
|
||||
|
||||
Dim RutaRecurso As String
|
||||
If SubCarpeta <> "" Then
|
||||
RutaRecurso = "Files/" & SubCarpeta & "/" & NombreArchivo
|
||||
Else
|
||||
RutaRecurso = "Files/" & NombreArchivo
|
||||
End If
|
||||
|
||||
Dim classLoader As JavaObject = GetThreadContextClassLoader
|
||||
Dim InStream As InputStream = classLoader.RunMethod("getResourceAsStream", Array(RutaRecurso))
|
||||
|
||||
If InStream.IsInitialized Then
|
||||
Log($"Copiando recurso: '${RutaRecurso}'..."$)
|
||||
|
||||
' Llamamos a nuestra propia función de copiado manual
|
||||
Dim OutStream As OutputStream = File.OpenOutput(DirDestino, NombreArchivo, False)
|
||||
CopiarStreamManualmente(InStream, OutStream)
|
||||
|
||||
Log($"'${ArchivoDestino}' copiado correctamente."$)
|
||||
Else
|
||||
Log($"ERROR: No se pudo encontrar el recurso con la ruta interna: '${RutaRecurso}'"$)
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
' No depende de ninguna librería extraña.
|
||||
Sub CopiarStreamManualmente (InStream As InputStream, OutStream As OutputStream)
|
||||
Try
|
||||
Dim buffer(1024) As Byte
|
||||
Dim len As Int
|
||||
len = InStream.ReadBytes(buffer, 0, buffer.Length)
|
||||
Do While len > 0
|
||||
OutStream.WriteBytes(buffer, 0, len)
|
||||
len = InStream.ReadBytes(buffer, 0, buffer.Length)
|
||||
Loop
|
||||
Catch
|
||||
LogError(LastException)
|
||||
End Try
|
||||
|
||||
InStream.Close
|
||||
OutStream.Close
|
||||
End Sub
|
||||
|
||||
' Función ayudante para obtener el Class Loader correcto.
|
||||
Sub GetThreadContextClassLoader As JavaObject
|
||||
Dim thread As JavaObject
|
||||
thread = thread.InitializeStatic("java.lang.Thread").RunMethod("currentThread", Null)
|
||||
Return thread.RunMethod("getContextClassLoader", Null)
|
||||
End Sub
|
||||
|
||||
Reference in New Issue
Block a user