@dbcube/core 3.0.10 → 3.0.14

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 CHANGED
@@ -768,9 +768,39 @@ var net = __toESM(require("net"));
768
768
  var import_child_process2 = require("child_process");
769
769
  var globalTcpServers = /* @__PURE__ */ new Map();
770
770
  var globalTcpConnections = /* @__PURE__ */ new Map();
771
- var queryCache = /* @__PURE__ */ new Map();
772
- var cacheSize = 0;
773
- var MAX_CACHE_SIZE = 500;
771
+ var connectionPools = /* @__PURE__ */ new Map();
772
+ var MAX_POOL_SIZE = 3;
773
+ var LRUCache = class {
774
+ cache = /* @__PURE__ */ new Map();
775
+ maxSize;
776
+ constructor(maxSize) {
777
+ this.maxSize = maxSize;
778
+ }
779
+ get(key) {
780
+ if (this.cache.has(key)) {
781
+ const value = this.cache.get(key);
782
+ this.cache.delete(key);
783
+ this.cache.set(key, value);
784
+ return value;
785
+ }
786
+ return void 0;
787
+ }
788
+ set(key, value) {
789
+ if (this.cache.has(key)) {
790
+ this.cache.delete(key);
791
+ } else if (this.cache.size >= this.maxSize) {
792
+ const firstKey = this.cache.keys().next().value;
793
+ if (firstKey !== void 0) {
794
+ this.cache.delete(firstKey);
795
+ }
796
+ }
797
+ this.cache.set(key, value);
798
+ }
799
+ size() {
800
+ return this.cache.size;
801
+ }
802
+ };
803
+ var queryCache = new LRUCache(500);
774
804
  var QueryEngine = class {
775
805
  name;
776
806
  config;
@@ -889,6 +919,7 @@ var QueryEngine = class {
889
919
  if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
890
920
  await this.startTcpServer();
891
921
  await this.waitForServerReady();
922
+ await this.initializeConnectionPool();
892
923
  }
893
924
  return this.sendTcpRequestFast(args);
894
925
  }
@@ -924,15 +955,30 @@ var QueryEngine = class {
924
955
  sleep(ms) {
925
956
  return new Promise((resolve5) => setTimeout(resolve5, ms));
926
957
  }
958
+ async initializeConnectionPool() {
959
+ console.log("\u{1F3CA} Initializing connection pool...");
960
+ if (!connectionPools.has(this.connectionId)) {
961
+ connectionPools.set(this.connectionId, []);
962
+ }
963
+ const pool = connectionPools.get(this.connectionId);
964
+ for (let i = 0; i < MAX_POOL_SIZE; i++) {
965
+ try {
966
+ const connection = await this.createPooledConnection();
967
+ pool.push(connection);
968
+ console.log(`\u2705 Pool connection ${i + 1}/${MAX_POOL_SIZE} created`);
969
+ } catch (error) {
970
+ console.error(`\u274C Failed to create pool connection ${i + 1}:`, error);
971
+ }
972
+ }
973
+ console.log(`\u{1F680} Connection pool ready with ${pool.length} connections`);
974
+ }
927
975
  getCachedDML(dmlJson) {
928
- if (queryCache.has(dmlJson)) {
929
- return queryCache.get(dmlJson);
976
+ const cached = queryCache.get(dmlJson);
977
+ if (cached) {
978
+ return cached;
930
979
  }
931
980
  const parsed = JSON.parse(dmlJson);
932
- if (cacheSize < MAX_CACHE_SIZE) {
933
- queryCache.set(dmlJson, parsed);
934
- cacheSize++;
935
- }
981
+ queryCache.set(dmlJson, parsed);
936
982
  return parsed;
937
983
  }
938
984
  async startTcpServer() {
@@ -956,7 +1002,6 @@ var QueryEngine = class {
956
1002
  if (output.includes("TCP Server listening on")) {
957
1003
  if (!started) {
958
1004
  started = true;
959
- clearTimeout(timeout);
960
1005
  globalTcpServers.set(this.connectionId, {
961
1006
  port: this.tcpPort,
962
1007
  process: serverProcess
@@ -973,7 +1018,6 @@ var QueryEngine = class {
973
1018
  });
974
1019
  serverProcess.on("error", (error) => {
975
1020
  if (!started) {
976
- clearTimeout(timeout);
977
1021
  reject(error);
978
1022
  }
979
1023
  });
@@ -997,7 +1041,6 @@ var QueryEngine = class {
997
1041
  if (!dmlJson) {
998
1042
  if (!isResolved) {
999
1043
  isResolved = true;
1000
- clearTimeout(timeout);
1001
1044
  client.destroy();
1002
1045
  reject(new Error("No DML found in arguments"));
1003
1046
  }
@@ -1014,7 +1057,6 @@ var QueryEngine = class {
1014
1057
  const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
1015
1058
  if (match && !isResolved) {
1016
1059
  isResolved = true;
1017
- clearTimeout(timeout);
1018
1060
  client.destroy();
1019
1061
  try {
1020
1062
  const response = JSON.parse(match[1]);
@@ -1031,13 +1073,11 @@ var QueryEngine = class {
1031
1073
  client.on("error", (error) => {
1032
1074
  if (!isResolved) {
1033
1075
  isResolved = true;
1034
- clearTimeout(timeout);
1035
1076
  reject(error);
1036
1077
  }
1037
1078
  });
1038
1079
  client.on("close", () => {
1039
1080
  if (!isResolved) {
1040
- clearTimeout(timeout);
1041
1081
  if (!responseBuffer.includes("PROCESS_RESPONSE:")) {
1042
1082
  reject(new Error("Connection closed without valid response"));
1043
1083
  }
@@ -1046,18 +1086,24 @@ var QueryEngine = class {
1046
1086
  });
1047
1087
  }
1048
1088
  async sendTcpRequestFast(args) {
1049
- const existingConnection = globalTcpConnections.get(this.connectionId);
1050
- if (existingConnection && existingConnection.readyState === "open") {
1089
+ if (!connectionPools.has(this.connectionId)) {
1090
+ return await this.createAndPoolConnection(args);
1091
+ }
1092
+ const pool = connectionPools.get(this.connectionId);
1093
+ if (pool.length > 0) {
1094
+ const connection = pool.pop();
1051
1095
  try {
1052
- return await this.sendOnExistingConnection(existingConnection, args);
1096
+ const result = await this.sendUltraFast(connection, args);
1097
+ pool.push(connection);
1098
+ return result;
1053
1099
  } catch (error) {
1054
- globalTcpConnections.delete(this.connectionId);
1055
- existingConnection.destroy();
1100
+ connection.destroy();
1101
+ return await this.createAndPoolConnection(args);
1056
1102
  }
1057
1103
  }
1058
- return await this.createPersistentConnection(args);
1104
+ return await this.createAndPoolConnection(args);
1059
1105
  }
1060
- async sendOnExistingConnection(connection, args) {
1106
+ async sendUltraFast(connection, args) {
1061
1107
  return new Promise((resolve5, reject) => {
1062
1108
  const dmlIndex = args.findIndex((arg) => arg === "--dml");
1063
1109
  const dmlJson = dmlIndex !== -1 ? args[dmlIndex + 1] : null;
@@ -1067,20 +1113,96 @@ var QueryEngine = class {
1067
1113
  }
1068
1114
  let responseBuffer = "";
1069
1115
  let isResolved = false;
1070
- const timeout = setTimeout(() => {
1116
+ const onData = (data) => {
1117
+ responseBuffer += data.toString();
1118
+ const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
1119
+ if (match && !isResolved) {
1120
+ isResolved = true;
1121
+ connection.off("data", onData);
1122
+ connection.off("error", onError);
1123
+ connection.off("close", onClose);
1124
+ try {
1125
+ const response = JSON.parse(match[1]);
1126
+ resolve5({
1127
+ status: response.status,
1128
+ message: response.message,
1129
+ data: response.data
1130
+ });
1131
+ } catch (error) {
1132
+ reject(new Error("Failed to parse TCP response"));
1133
+ }
1134
+ }
1135
+ };
1136
+ const onError = (error) => {
1071
1137
  if (!isResolved) {
1072
1138
  isResolved = true;
1073
- reject(new Error("TCP request timeout"));
1139
+ connection.off("data", onData);
1140
+ connection.off("error", onError);
1141
+ connection.off("close", onClose);
1142
+ reject(error);
1074
1143
  }
1075
- }, 100);
1144
+ };
1145
+ const onClose = () => {
1146
+ if (!isResolved) {
1147
+ isResolved = true;
1148
+ connection.off("data", onData);
1149
+ connection.off("error", onError);
1150
+ connection.off("close", onClose);
1151
+ connection.off("close", onClose);
1152
+ reject(new Error("Connection closed unexpectedly"));
1153
+ }
1154
+ };
1155
+ connection.on("data", onData);
1156
+ connection.on("error", onError);
1157
+ connection.on("close", onClose);
1158
+ const command = `{"action":"execute","dml":${dmlJson}}`;
1159
+ connection.write(command);
1160
+ });
1161
+ }
1162
+ async createAndPoolConnection(args) {
1163
+ const connection = await this.createPooledConnection();
1164
+ if (!connectionPools.has(this.connectionId)) {
1165
+ connectionPools.set(this.connectionId, []);
1166
+ }
1167
+ const result = await this.sendUltraFast(connection, args);
1168
+ const pool = connectionPools.get(this.connectionId);
1169
+ if (pool.length < MAX_POOL_SIZE) {
1170
+ pool.push(connection);
1171
+ } else {
1172
+ connection.destroy();
1173
+ }
1174
+ return result;
1175
+ }
1176
+ async createPooledConnection() {
1177
+ return new Promise((resolve5, reject) => {
1178
+ const client = new net.Socket();
1179
+ client.setNoDelay(true);
1180
+ client.setKeepAlive(true, 0);
1181
+ client.connect(this.tcpPort, "127.0.0.1", () => {
1182
+ resolve5(client);
1183
+ });
1184
+ client.on("error", reject);
1185
+ });
1186
+ }
1187
+ async sendOnExistingConnection(connection, args) {
1188
+ return new Promise((resolve5, reject) => {
1189
+ const dmlIndex = args.findIndex((arg) => arg === "--dml");
1190
+ const dmlJson = dmlIndex !== -1 ? args[dmlIndex + 1] : null;
1191
+ if (!dmlJson) {
1192
+ reject(new Error("No DML found in arguments"));
1193
+ return;
1194
+ }
1195
+ const dmlParsed = this.getCachedDML(dmlJson);
1196
+ let responseBuffer = "";
1197
+ let isResolved = false;
1076
1198
  const onData = (data) => {
1077
1199
  responseBuffer += data.toString();
1078
1200
  const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
1079
1201
  if (match && !isResolved) {
1080
1202
  isResolved = true;
1081
- clearTimeout(timeout);
1082
1203
  connection.off("data", onData);
1083
1204
  connection.off("error", onError);
1205
+ connection.off("close", onClose);
1084
1206
  try {
1085
1207
  const response = JSON.parse(match[1]);
1086
1208
  resolve5({
@@ -1096,14 +1218,24 @@ var QueryEngine = class {
1096
1218
  const onError = (error) => {
1097
1219
  if (!isResolved) {
1098
1220
  isResolved = true;
1099
- clearTimeout(timeout);
1100
1221
  connection.off("data", onData);
1101
1222
  connection.off("error", onError);
1223
+ connection.off("close", onClose);
1102
1224
  reject(error);
1103
1225
  }
1104
1226
  };
1227
+ const onClose = () => {
1228
+ if (!isResolved) {
1229
+ isResolved = true;
1230
+ connection.off("data", onData);
1231
+ connection.off("error", onError);
1232
+ connection.off("close", onClose);
1233
+ reject(new Error("Connection closed unexpectedly"));
1234
+ }
1235
+ };
1105
1236
  connection.on("data", onData);
1106
1237
  connection.on("error", onError);
1238
+ connection.on("close", onClose);
1107
1239
  const command = {
1108
1240
  action: "execute",
1109
1241
  dml: dmlJson