@dbcube/core 3.0.19 → 3.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +184 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +184 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -728,11 +728,166 @@ import path4 from "path";
|
|
|
728
728
|
import { createRequire as createRequire2 } from "module";
|
|
729
729
|
import * as net from "net";
|
|
730
730
|
import { spawn as spawn2 } from "child_process";
|
|
731
|
+
var MAX_CONNECTIONS_PER_DB = 10;
|
|
732
|
+
var MAX_CACHE_ENTRIES = 1e3;
|
|
733
|
+
var CACHE_CLEANUP_THRESHOLD = 0.9;
|
|
734
|
+
var CONNECTION_IDLE_TIMEOUT = 3e5;
|
|
735
|
+
var CONNECTION_MAX_AGE = 36e5;
|
|
736
|
+
var LRUCache = class {
|
|
737
|
+
cache;
|
|
738
|
+
maxSize;
|
|
739
|
+
cleanupThreshold;
|
|
740
|
+
constructor(maxSize, cleanupThreshold = 0.9) {
|
|
741
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
742
|
+
this.maxSize = maxSize;
|
|
743
|
+
this.cleanupThreshold = cleanupThreshold;
|
|
744
|
+
}
|
|
745
|
+
get(key) {
|
|
746
|
+
const entry = this.cache.get(key);
|
|
747
|
+
if (!entry) return void 0;
|
|
748
|
+
entry.lastAccessed = Date.now();
|
|
749
|
+
entry.accessCount++;
|
|
750
|
+
return entry.value;
|
|
751
|
+
}
|
|
752
|
+
set(key, value) {
|
|
753
|
+
if (this.cache.size >= this.maxSize * this.cleanupThreshold) {
|
|
754
|
+
this.evictLRU();
|
|
755
|
+
}
|
|
756
|
+
this.cache.set(key, {
|
|
757
|
+
value,
|
|
758
|
+
lastAccessed: Date.now(),
|
|
759
|
+
accessCount: 1
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
evictLRU() {
|
|
763
|
+
const entries = Array.from(this.cache.entries()).sort((a, b) => {
|
|
764
|
+
const scoreDiff = this.calculateScore(a[1]) - this.calculateScore(b[1]);
|
|
765
|
+
if (scoreDiff !== 0) return scoreDiff;
|
|
766
|
+
return a[1].lastAccessed - b[1].lastAccessed;
|
|
767
|
+
});
|
|
768
|
+
const toRemove = Math.floor(this.maxSize * 0.2);
|
|
769
|
+
for (let i = 0; i < toRemove && i < entries.length; i++) {
|
|
770
|
+
this.cache.delete(entries[i][0]);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
calculateScore(entry) {
|
|
774
|
+
const now = Date.now();
|
|
775
|
+
const age = now - entry.lastAccessed;
|
|
776
|
+
const recencyScore = 1 / (age + 1);
|
|
777
|
+
const frequencyScore = entry.accessCount;
|
|
778
|
+
return recencyScore * 0.3 + frequencyScore * 0.7;
|
|
779
|
+
}
|
|
780
|
+
clear() {
|
|
781
|
+
this.cache.clear();
|
|
782
|
+
}
|
|
783
|
+
size() {
|
|
784
|
+
return this.cache.size;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
var ConnectionPool = class {
|
|
788
|
+
pools;
|
|
789
|
+
maxConnectionsPerDb;
|
|
790
|
+
constructor(maxConnectionsPerDb = MAX_CONNECTIONS_PER_DB) {
|
|
791
|
+
this.pools = /* @__PURE__ */ new Map();
|
|
792
|
+
this.maxConnectionsPerDb = maxConnectionsPerDb;
|
|
793
|
+
setInterval(() => this.cleanupIdleConnections(), 6e4);
|
|
794
|
+
}
|
|
795
|
+
getConnection(connectionId) {
|
|
796
|
+
const pool = this.pools.get(connectionId);
|
|
797
|
+
if (!pool || pool.length === 0) return null;
|
|
798
|
+
for (let i = 0; i < pool.length; i++) {
|
|
799
|
+
const conn = pool[i];
|
|
800
|
+
if (this.isConnectionValid(conn)) {
|
|
801
|
+
conn.lastUsed = Date.now();
|
|
802
|
+
conn.requestCount++;
|
|
803
|
+
return conn.socket;
|
|
804
|
+
} else {
|
|
805
|
+
conn.socket.destroy();
|
|
806
|
+
pool.splice(i, 1);
|
|
807
|
+
i--;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
addConnection(connectionId, socket) {
|
|
813
|
+
if (!this.pools.has(connectionId)) {
|
|
814
|
+
this.pools.set(connectionId, []);
|
|
815
|
+
}
|
|
816
|
+
const pool = this.pools.get(connectionId);
|
|
817
|
+
if (pool.length >= this.maxConnectionsPerDb) {
|
|
818
|
+
const oldest = pool.shift();
|
|
819
|
+
if (oldest) {
|
|
820
|
+
oldest.socket.destroy();
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
pool.push({
|
|
824
|
+
socket,
|
|
825
|
+
lastUsed: Date.now(),
|
|
826
|
+
createdAt: Date.now(),
|
|
827
|
+
requestCount: 0
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
removeConnection(connectionId, socket) {
|
|
831
|
+
const pool = this.pools.get(connectionId);
|
|
832
|
+
if (!pool) return;
|
|
833
|
+
const index = pool.findIndex((c) => c.socket === socket);
|
|
834
|
+
if (index !== -1) {
|
|
835
|
+
pool[index].socket.destroy();
|
|
836
|
+
pool.splice(index, 1);
|
|
837
|
+
}
|
|
838
|
+
if (pool.length === 0) {
|
|
839
|
+
this.pools.delete(connectionId);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
closeAll(connectionId) {
|
|
843
|
+
if (connectionId) {
|
|
844
|
+
const pool = this.pools.get(connectionId);
|
|
845
|
+
if (pool) {
|
|
846
|
+
pool.forEach((conn) => conn.socket.destroy());
|
|
847
|
+
this.pools.delete(connectionId);
|
|
848
|
+
}
|
|
849
|
+
} else {
|
|
850
|
+
this.pools.forEach((pool) => {
|
|
851
|
+
pool.forEach((conn) => conn.socket.destroy());
|
|
852
|
+
});
|
|
853
|
+
this.pools.clear();
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
isConnectionValid(conn) {
|
|
857
|
+
const now = Date.now();
|
|
858
|
+
const age = now - conn.createdAt;
|
|
859
|
+
return conn.socket.readyState === "open" && age < CONNECTION_MAX_AGE;
|
|
860
|
+
}
|
|
861
|
+
cleanupIdleConnections() {
|
|
862
|
+
const now = Date.now();
|
|
863
|
+
this.pools.forEach((pool, connectionId) => {
|
|
864
|
+
for (let i = pool.length - 1; i >= 0; i--) {
|
|
865
|
+
const conn = pool[i];
|
|
866
|
+
const idleTime = now - conn.lastUsed;
|
|
867
|
+
if (idleTime > CONNECTION_IDLE_TIMEOUT || !this.isConnectionValid(conn)) {
|
|
868
|
+
conn.socket.destroy();
|
|
869
|
+
pool.splice(i, 1);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
if (pool.length === 0) {
|
|
873
|
+
this.pools.delete(connectionId);
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
getStats() {
|
|
878
|
+
const stats = {};
|
|
879
|
+
this.pools.forEach((pool, id) => {
|
|
880
|
+
stats[id] = {
|
|
881
|
+
activeConnections: pool.length,
|
|
882
|
+
totalRequests: pool.reduce((sum, c) => sum + c.requestCount, 0)
|
|
883
|
+
};
|
|
884
|
+
});
|
|
885
|
+
return stats;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
731
888
|
var globalTcpServers = /* @__PURE__ */ new Map();
|
|
732
|
-
var
|
|
733
|
-
var queryCache =
|
|
734
|
-
var cacheSize = 0;
|
|
735
|
-
var MAX_CACHE_SIZE = 500;
|
|
889
|
+
var connectionPool = new ConnectionPool(MAX_CONNECTIONS_PER_DB);
|
|
890
|
+
var queryCache = new LRUCache(MAX_CACHE_ENTRIES, CACHE_CLEANUP_THRESHOLD);
|
|
736
891
|
var QueryEngine = class {
|
|
737
892
|
name;
|
|
738
893
|
config;
|
|
@@ -887,14 +1042,12 @@ var QueryEngine = class {
|
|
|
887
1042
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
888
1043
|
}
|
|
889
1044
|
getCachedDML(dmlJson) {
|
|
890
|
-
|
|
891
|
-
|
|
1045
|
+
const cached = queryCache.get(dmlJson);
|
|
1046
|
+
if (cached !== void 0) {
|
|
1047
|
+
return cached;
|
|
892
1048
|
}
|
|
893
1049
|
const parsed = JSON.parse(dmlJson);
|
|
894
|
-
|
|
895
|
-
queryCache.set(dmlJson, parsed);
|
|
896
|
-
cacheSize++;
|
|
897
|
-
}
|
|
1050
|
+
queryCache.set(dmlJson, parsed);
|
|
898
1051
|
return parsed;
|
|
899
1052
|
}
|
|
900
1053
|
async startTcpServer() {
|
|
@@ -1008,13 +1161,12 @@ var QueryEngine = class {
|
|
|
1008
1161
|
});
|
|
1009
1162
|
}
|
|
1010
1163
|
async sendTcpRequestFast(args) {
|
|
1011
|
-
const existingConnection =
|
|
1164
|
+
const existingConnection = connectionPool.getConnection(this.connectionId);
|
|
1012
1165
|
if (existingConnection && existingConnection.readyState === "open") {
|
|
1013
1166
|
try {
|
|
1014
1167
|
return await this.sendOnExistingConnection(existingConnection, args);
|
|
1015
1168
|
} catch (error) {
|
|
1016
|
-
|
|
1017
|
-
existingConnection.destroy();
|
|
1169
|
+
connectionPool.removeConnection(this.connectionId, existingConnection);
|
|
1018
1170
|
}
|
|
1019
1171
|
}
|
|
1020
1172
|
return await this.createPersistentConnection(args);
|
|
@@ -1099,7 +1251,7 @@ var QueryEngine = class {
|
|
|
1099
1251
|
}
|
|
1100
1252
|
return;
|
|
1101
1253
|
}
|
|
1102
|
-
|
|
1254
|
+
connectionPool.addConnection(this.connectionId, client);
|
|
1103
1255
|
const command = {
|
|
1104
1256
|
action: "execute",
|
|
1105
1257
|
dml: dmlJson
|
|
@@ -1126,12 +1278,12 @@ var QueryEngine = class {
|
|
|
1126
1278
|
client.on("error", (error) => {
|
|
1127
1279
|
if (!isResolved) {
|
|
1128
1280
|
isResolved = true;
|
|
1129
|
-
|
|
1281
|
+
connectionPool.removeConnection(this.connectionId, client);
|
|
1130
1282
|
reject(error);
|
|
1131
1283
|
}
|
|
1132
1284
|
});
|
|
1133
1285
|
client.on("close", () => {
|
|
1134
|
-
|
|
1286
|
+
connectionPool.removeConnection(this.connectionId, client);
|
|
1135
1287
|
if (!isResolved && !responseBuffer.includes("PROCESS_RESPONSE:")) {
|
|
1136
1288
|
reject(new Error("Connection closed without valid response"));
|
|
1137
1289
|
}
|
|
@@ -1226,12 +1378,7 @@ var QueryEngine = class {
|
|
|
1226
1378
|
});
|
|
1227
1379
|
}
|
|
1228
1380
|
async disconnect() {
|
|
1229
|
-
|
|
1230
|
-
if (connection && connection.readyState === "open") {
|
|
1231
|
-
connection.write(JSON.stringify({ action: "disconnect" }));
|
|
1232
|
-
connection.destroy();
|
|
1233
|
-
globalTcpConnections.delete(this.connectionId);
|
|
1234
|
-
}
|
|
1381
|
+
connectionPool.closeAll(this.connectionId);
|
|
1235
1382
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1236
1383
|
if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
|
|
1237
1384
|
serverInfo.process.kill();
|
|
@@ -1248,6 +1395,21 @@ var QueryEngine = class {
|
|
|
1248
1395
|
data: null
|
|
1249
1396
|
};
|
|
1250
1397
|
}
|
|
1398
|
+
// Método para obtener estadísticas del pool y cache
|
|
1399
|
+
static getStats() {
|
|
1400
|
+
return {
|
|
1401
|
+
connectionPool: connectionPool.getStats(),
|
|
1402
|
+
cache: {
|
|
1403
|
+
size: queryCache.size(),
|
|
1404
|
+
maxSize: MAX_CACHE_ENTRIES
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
// Método para limpiar todo el cache y conexiones
|
|
1409
|
+
static clearAll() {
|
|
1410
|
+
queryCache.clear();
|
|
1411
|
+
connectionPool.closeAll();
|
|
1412
|
+
}
|
|
1251
1413
|
};
|
|
1252
1414
|
|
|
1253
1415
|
// src/lib/SqliteExecutor.ts
|