Skip to content

Commit d1ac37d

Browse files
authored
Merge pull request #197 from jumpserver/pr@dev@fix_gson_issues
fix: make large SQL chunk transfer reliable
2 parents 4ce1532 + ecf0582 commit d1ac37d

5 files changed

Lines changed: 428 additions & 77 deletions

File tree

backend/framework/src/main/java/org/jumpserver/chen/framework/console/QueryConsole.java

Lines changed: 19 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@
3737
import java.util.LinkedHashMap;
3838
import java.util.List;
3939
import java.util.Map;
40-
import java.util.concurrent.ConcurrentHashMap;
40+
import java.util.Optional;
4141
import java.util.concurrent.CountDownLatch;
42-
import java.util.concurrent.TimeUnit;
4342
import java.util.concurrent.atomic.AtomicBoolean;
4443

4544
@Slf4j
@@ -51,6 +50,7 @@ public class QueryConsole extends AbstractConsole {
5150
private StateManager<QueryConsoleState> stateManager;
5251
private final Map<String, DataView> dataViews = new HashMap<>();
5352
private volatile Map<String, String> allowedContexts = Map.of();
53+
private final SQLChunkTransferManager sqlChunkTransfers = new SQLChunkTransferManager();
5454

5555
private static final Gson GSON = new Gson();
5656

@@ -168,7 +168,7 @@ private void onAction(QueryConsoleAction action) {
168168
this.handleSQLChunk(action);
169169
}
170170
case QueryConsoleAction.ACTION_RUN_SQL_COMPLETE -> {
171-
this.handleSQLComplete();
171+
this.handleSQLComplete(action);
172172
}
173173

174174
case QueryConsoleAction.ACTION_RUN_SQL_FILE -> {
@@ -184,6 +184,7 @@ private void onAction(QueryConsoleAction action) {
184184

185185

186186
case QueryConsoleAction.ACTION_CANCEL -> {
187+
this.sqlChunkTransfers.cancelAll();
187188
this.onCancel();
188189
this.getState().setInQuery(false);
189190
this.stateManager.commit();
@@ -195,65 +196,26 @@ private void onAction(QueryConsoleAction action) {
195196
}
196197
}
197198

198-
private final ConcurrentHashMap<Integer, String> sqlChunks = new ConcurrentHashMap<>();
199-
private CountDownLatch latch;
200-
private int expectedChunks = -1;
201-
202199
private void handleSQLChunk(QueryConsoleAction action) {
203-
var data = (Map<String, Object>) action.getData();
204-
var chunk = (String) data.get("chunk");
205-
var index = (Integer) data.get("index");
206-
var total = (Integer) data.get("total");
207-
208-
synchronized (this) {
209-
if (expectedChunks == -1) {
210-
expectedChunks = total;
211-
latch = new CountDownLatch(total);
212-
}
213-
}
214-
215-
if (sqlChunks.putIfAbsent(index, chunk) == null) {
216-
latch.countDown();
200+
Optional<String> sql;
201+
try {
202+
sql = this.sqlChunkTransfers.receiveChunk(action.getData());
203+
} catch (IllegalArgumentException | IllegalStateException e) {
204+
this.getConsoleLogger().error("Invalid SQL chunk transfer: %s", e.getMessage());
205+
return;
217206
}
207+
sql.ifPresent(this::onSQL);
218208
}
219209

220-
/**
221-
* 处理分段 SQL 接收完成
222-
*/
223-
private void handleSQLComplete() {
210+
private void handleSQLComplete(QueryConsoleAction action) {
211+
Optional<String> sql;
224212
try {
225-
226-
// 等待所有分段接收完成
227-
boolean completed = latch.await(10, TimeUnit.SECONDS); // 超时10秒
228-
229-
if (!completed) {
230-
this.getConsoleLogger().error("read sql message timeout!!");
231-
return;
232-
}
233-
234-
// 按照索引顺序合并所有分段
235-
StringBuilder sqlBuilder = new StringBuilder();
236-
for (int i = 0; i < expectedChunks; i++) {
237-
sqlBuilder.append(sqlChunks.get(i));
238-
}
239-
240-
// 合并完成后清理缓存
241-
var sql = sqlBuilder.toString();
242-
sqlChunks.clear();
243-
expectedChunks = -1;
244-
245-
// 执行完整 SQL
246-
this.getState().setInQuery(true);
247-
this.stateManager.commit();
248-
249-
this.onSQL(sql);
250-
251-
} catch (InterruptedException e) {
252-
Thread.currentThread().interrupt();
253-
} finally {
254-
this.getState().setInQuery(false);
255-
this.stateManager.commit();
213+
sql = this.sqlChunkTransfers.receiveComplete(action.getData());
214+
} catch (IllegalArgumentException | IllegalStateException e) {
215+
this.getConsoleLogger().error("Invalid SQL chunk transfer: %s", e.getMessage());
216+
return;
256217
}
218+
sql.ifPresent(this::onSQL);
257219
}
258220

259221
private void onDataViewAction(DataViewAction action) {
@@ -538,6 +500,7 @@ private void sendDataView(DataView dataView, boolean clearOthers) {
538500

539501
@Override
540502
public void close() {
503+
this.sqlChunkTransfers.close();
541504
if (this.currentPlan != null) {
542505
// flush
543506
var session = SessionManager.getCurrentSession();

0 commit comments

Comments
 (0)