@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.cjs
CHANGED
|
@@ -766,11 +766,166 @@ var import_path2 = __toESM(require("path"));
|
|
|
766
766
|
var import_module2 = require("module");
|
|
767
767
|
var net = __toESM(require("net"));
|
|
768
768
|
var import_child_process2 = require("child_process");
|
|
769
|
+
var MAX_CONNECTIONS_PER_DB = 10;
|
|
770
|
+
var MAX_CACHE_ENTRIES = 1e3;
|
|
771
|
+
var CACHE_CLEANUP_THRESHOLD = 0.9;
|
|
772
|
+
var CONNECTION_IDLE_TIMEOUT = 3e5;
|
|
773
|
+
var CONNECTION_MAX_AGE = 36e5;
|
|
774
|
+
var LRUCache = class {
|
|
775
|
+
cache;
|
|
776
|
+
maxSize;
|
|
777
|
+
cleanupThreshold;
|
|
778
|
+
constructor(maxSize, cleanupThreshold = 0.9) {
|
|
779
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
780
|
+
this.maxSize = maxSize;
|
|
781
|
+
this.cleanupThreshold = cleanupThreshold;
|
|
782
|
+
}
|
|
783
|
+
get(key) {
|
|
784
|
+
const entry = this.cache.get(key);
|
|
785
|
+
if (!entry) return void 0;
|
|
786
|
+
entry.lastAccessed = Date.now();
|
|
787
|
+
entry.accessCount++;
|
|
788
|
+
return entry.value;
|
|
789
|
+
}
|
|
790
|
+
set(key, value) {
|
|
791
|
+
if (this.cache.size >= this.maxSize * this.cleanupThreshold) {
|
|
792
|
+
this.evictLRU();
|
|
793
|
+
}
|
|
794
|
+
this.cache.set(key, {
|
|
795
|
+
value,
|
|
796
|
+
lastAccessed: Date.now(),
|
|
797
|
+
accessCount: 1
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
evictLRU() {
|
|
801
|
+
const entries = Array.from(this.cache.entries()).sort((a, b) => {
|
|
802
|
+
const scoreDiff = this.calculateScore(a[1]) - this.calculateScore(b[1]);
|
|
803
|
+
if (scoreDiff !== 0) return scoreDiff;
|
|
804
|
+
return a[1].lastAccessed - b[1].lastAccessed;
|
|
805
|
+
});
|
|
806
|
+
const toRemove = Math.floor(this.maxSize * 0.2);
|
|
807
|
+
for (let i = 0; i < toRemove && i < entries.length; i++) {
|
|
808
|
+
this.cache.delete(entries[i][0]);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
calculateScore(entry) {
|
|
812
|
+
const now = Date.now();
|
|
813
|
+
const age = now - entry.lastAccessed;
|
|
814
|
+
const recencyScore = 1 / (age + 1);
|
|
815
|
+
const frequencyScore = entry.accessCount;
|
|
816
|
+
return recencyScore * 0.3 + frequencyScore * 0.7;
|
|
817
|
+
}
|
|
818
|
+
clear() {
|
|
819
|
+
this.cache.clear();
|
|
820
|
+
}
|
|
821
|
+
size() {
|
|
822
|
+
return this.cache.size;
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
var ConnectionPool = class {
|
|
826
|
+
pools;
|
|
827
|
+
maxConnectionsPerDb;
|
|
828
|
+
constructor(maxConnectionsPerDb = MAX_CONNECTIONS_PER_DB) {
|
|
829
|
+
this.pools = /* @__PURE__ */ new Map();
|
|
830
|
+
this.maxConnectionsPerDb = maxConnectionsPerDb;
|
|
831
|
+
setInterval(() => this.cleanupIdleConnections(), 6e4);
|
|
832
|
+
}
|
|
833
|
+
getConnection(connectionId) {
|
|
834
|
+
const pool = this.pools.get(connectionId);
|
|
835
|
+
if (!pool || pool.length === 0) return null;
|
|
836
|
+
for (let i = 0; i < pool.length; i++) {
|
|
837
|
+
const conn = pool[i];
|
|
838
|
+
if (this.isConnectionValid(conn)) {
|
|
839
|
+
conn.lastUsed = Date.now();
|
|
840
|
+
conn.requestCount++;
|
|
841
|
+
return conn.socket;
|
|
842
|
+
} else {
|
|
843
|
+
conn.socket.destroy();
|
|
844
|
+
pool.splice(i, 1);
|
|
845
|
+
i--;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
addConnection(connectionId, socket) {
|
|
851
|
+
if (!this.pools.has(connectionId)) {
|
|
852
|
+
this.pools.set(connectionId, []);
|
|
853
|
+
}
|
|
854
|
+
const pool = this.pools.get(connectionId);
|
|
855
|
+
if (pool.length >= this.maxConnectionsPerDb) {
|
|
856
|
+
const oldest = pool.shift();
|
|
857
|
+
if (oldest) {
|
|
858
|
+
oldest.socket.destroy();
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
pool.push({
|
|
862
|
+
socket,
|
|
863
|
+
lastUsed: Date.now(),
|
|
864
|
+
createdAt: Date.now(),
|
|
865
|
+
requestCount: 0
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
removeConnection(connectionId, socket) {
|
|
869
|
+
const pool = this.pools.get(connectionId);
|
|
870
|
+
if (!pool) return;
|
|
871
|
+
const index = pool.findIndex((c) => c.socket === socket);
|
|
872
|
+
if (index !== -1) {
|
|
873
|
+
pool[index].socket.destroy();
|
|
874
|
+
pool.splice(index, 1);
|
|
875
|
+
}
|
|
876
|
+
if (pool.length === 0) {
|
|
877
|
+
this.pools.delete(connectionId);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
closeAll(connectionId) {
|
|
881
|
+
if (connectionId) {
|
|
882
|
+
const pool = this.pools.get(connectionId);
|
|
883
|
+
if (pool) {
|
|
884
|
+
pool.forEach((conn) => conn.socket.destroy());
|
|
885
|
+
this.pools.delete(connectionId);
|
|
886
|
+
}
|
|
887
|
+
} else {
|
|
888
|
+
this.pools.forEach((pool) => {
|
|
889
|
+
pool.forEach((conn) => conn.socket.destroy());
|
|
890
|
+
});
|
|
891
|
+
this.pools.clear();
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
isConnectionValid(conn) {
|
|
895
|
+
const now = Date.now();
|
|
896
|
+
const age = now - conn.createdAt;
|
|
897
|
+
return conn.socket.readyState === "open" && age < CONNECTION_MAX_AGE;
|
|
898
|
+
}
|
|
899
|
+
cleanupIdleConnections() {
|
|
900
|
+
const now = Date.now();
|
|
901
|
+
this.pools.forEach((pool, connectionId) => {
|
|
902
|
+
for (let i = pool.length - 1; i >= 0; i--) {
|
|
903
|
+
const conn = pool[i];
|
|
904
|
+
const idleTime = now - conn.lastUsed;
|
|
905
|
+
if (idleTime > CONNECTION_IDLE_TIMEOUT || !this.isConnectionValid(conn)) {
|
|
906
|
+
conn.socket.destroy();
|
|
907
|
+
pool.splice(i, 1);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
if (pool.length === 0) {
|
|
911
|
+
this.pools.delete(connectionId);
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
getStats() {
|
|
916
|
+
const stats = {};
|
|
917
|
+
this.pools.forEach((pool, id) => {
|
|
918
|
+
stats[id] = {
|
|
919
|
+
activeConnections: pool.length,
|
|
920
|
+
totalRequests: pool.reduce((sum, c) => sum + c.requestCount, 0)
|
|
921
|
+
};
|
|
922
|
+
});
|
|
923
|
+
return stats;
|
|
924
|
+
}
|
|
925
|
+
};
|
|
769
926
|
var globalTcpServers = /* @__PURE__ */ new Map();
|
|
770
|
-
var
|
|
771
|
-
var queryCache =
|
|
772
|
-
var cacheSize = 0;
|
|
773
|
-
var MAX_CACHE_SIZE = 500;
|
|
927
|
+
var connectionPool = new ConnectionPool(MAX_CONNECTIONS_PER_DB);
|
|
928
|
+
var queryCache = new LRUCache(MAX_CACHE_ENTRIES, CACHE_CLEANUP_THRESHOLD);
|
|
774
929
|
var QueryEngine = class {
|
|
775
930
|
name;
|
|
776
931
|
config;
|
|
@@ -925,14 +1080,12 @@ var QueryEngine = class {
|
|
|
925
1080
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
926
1081
|
}
|
|
927
1082
|
getCachedDML(dmlJson) {
|
|
928
|
-
|
|
929
|
-
|
|
1083
|
+
const cached = queryCache.get(dmlJson);
|
|
1084
|
+
if (cached !== void 0) {
|
|
1085
|
+
return cached;
|
|
930
1086
|
}
|
|
931
1087
|
const parsed = JSON.parse(dmlJson);
|
|
932
|
-
|
|
933
|
-
queryCache.set(dmlJson, parsed);
|
|
934
|
-
cacheSize++;
|
|
935
|
-
}
|
|
1088
|
+
queryCache.set(dmlJson, parsed);
|
|
936
1089
|
return parsed;
|
|
937
1090
|
}
|
|
938
1091
|
async startTcpServer() {
|
|
@@ -1046,13 +1199,12 @@ var QueryEngine = class {
|
|
|
1046
1199
|
});
|
|
1047
1200
|
}
|
|
1048
1201
|
async sendTcpRequestFast(args) {
|
|
1049
|
-
const existingConnection =
|
|
1202
|
+
const existingConnection = connectionPool.getConnection(this.connectionId);
|
|
1050
1203
|
if (existingConnection && existingConnection.readyState === "open") {
|
|
1051
1204
|
try {
|
|
1052
1205
|
return await this.sendOnExistingConnection(existingConnection, args);
|
|
1053
1206
|
} catch (error) {
|
|
1054
|
-
|
|
1055
|
-
existingConnection.destroy();
|
|
1207
|
+
connectionPool.removeConnection(this.connectionId, existingConnection);
|
|
1056
1208
|
}
|
|
1057
1209
|
}
|
|
1058
1210
|
return await this.createPersistentConnection(args);
|
|
@@ -1137,7 +1289,7 @@ var QueryEngine = class {
|
|
|
1137
1289
|
}
|
|
1138
1290
|
return;
|
|
1139
1291
|
}
|
|
1140
|
-
|
|
1292
|
+
connectionPool.addConnection(this.connectionId, client);
|
|
1141
1293
|
const command = {
|
|
1142
1294
|
action: "execute",
|
|
1143
1295
|
dml: dmlJson
|
|
@@ -1164,12 +1316,12 @@ var QueryEngine = class {
|
|
|
1164
1316
|
client.on("error", (error) => {
|
|
1165
1317
|
if (!isResolved) {
|
|
1166
1318
|
isResolved = true;
|
|
1167
|
-
|
|
1319
|
+
connectionPool.removeConnection(this.connectionId, client);
|
|
1168
1320
|
reject(error);
|
|
1169
1321
|
}
|
|
1170
1322
|
});
|
|
1171
1323
|
client.on("close", () => {
|
|
1172
|
-
|
|
1324
|
+
connectionPool.removeConnection(this.connectionId, client);
|
|
1173
1325
|
if (!isResolved && !responseBuffer.includes("PROCESS_RESPONSE:")) {
|
|
1174
1326
|
reject(new Error("Connection closed without valid response"));
|
|
1175
1327
|
}
|
|
@@ -1264,12 +1416,7 @@ var QueryEngine = class {
|
|
|
1264
1416
|
});
|
|
1265
1417
|
}
|
|
1266
1418
|
async disconnect() {
|
|
1267
|
-
|
|
1268
|
-
if (connection && connection.readyState === "open") {
|
|
1269
|
-
connection.write(JSON.stringify({ action: "disconnect" }));
|
|
1270
|
-
connection.destroy();
|
|
1271
|
-
globalTcpConnections.delete(this.connectionId);
|
|
1272
|
-
}
|
|
1419
|
+
connectionPool.closeAll(this.connectionId);
|
|
1273
1420
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1274
1421
|
if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
|
|
1275
1422
|
serverInfo.process.kill();
|
|
@@ -1286,6 +1433,21 @@ var QueryEngine = class {
|
|
|
1286
1433
|
data: null
|
|
1287
1434
|
};
|
|
1288
1435
|
}
|
|
1436
|
+
// Método para obtener estadísticas del pool y cache
|
|
1437
|
+
static getStats() {
|
|
1438
|
+
return {
|
|
1439
|
+
connectionPool: connectionPool.getStats(),
|
|
1440
|
+
cache: {
|
|
1441
|
+
size: queryCache.size(),
|
|
1442
|
+
maxSize: MAX_CACHE_ENTRIES
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
// Método para limpiar todo el cache y conexiones
|
|
1447
|
+
static clearAll() {
|
|
1448
|
+
queryCache.clear();
|
|
1449
|
+
connectionPool.closeAll();
|
|
1450
|
+
}
|
|
1289
1451
|
};
|
|
1290
1452
|
|
|
1291
1453
|
// src/lib/SqliteExecutor.ts
|