Repository navigation
Conversation
|
I reviewed commit
Validation was performed in an isolated checkout: the PR's existing 21 targeted tests passed, and two additional regression tests reproduced the issues above. The tests used the locally cached TsFile |
CritasWang
left a comment
There was a problem hiding this comment.
Thanks for working on this. I went through the full diff at e5db31f together with the surrounding code. The tree multi-device SQL export, the per-query output files and destination-table derivation, literal escaping and NULL handling, the typed CSV headers, and the archival target fix all look correct to me. The 21 tests in DataToolRegressionTest, ImportTsFileOperationTest and WriteDataFileTest pass locally, and I reproduced the import-side issues below with small unit probes.
I'd like the first inline comment addressed before merging: a failed CSV batch now ends the whole worker thread, so the files queued behind it are skipped and never reported. The second is about the exit-code coverage that is still incomplete. The rest is minor.
Follow-ups outside this diff
import-tsfilestill has the archival bug this PR fixes forimport-data.ImportTsFileBase#processingFilestill computesisSuccess ? successDir : failDir + File.separator + ..., so every successfully loaded file is archived to the success directory path itself. With-os mvand a fresh (empty) success directory, this deletes source files. The first loaded TsFile replaces the empty directory, and each later one replaces the previous file (REPLACE_EXISTING). All of them have already been moved out of the source directory, so only the last one survives on disk. It is the same logic, so it could reuse the newprocessingFile, either here or in a quick follow-up.export-tsfile.bat,schema/export-schema.batandschema/import-schema.batstill haveENDLOCALandEXIT /B %ret_code%on separate lines. That is the same exit-code problem fixed here forexport-data.bat/import-data.bat.
Nits
- The three new
CliMessagesconstants sit between the private constructor and the "Additional auto-collected messages" separator. Their names and hashes are correct; only the placement looks accidental. - In the tree non-aligned SQL export,
processedRowsnow counts INSERT statements rather than result rows, so the progress number means something slightly different.
Checked, no action needed
''escaping is valid for both the tree and the relational lexer; neither treats\as an escape.- Unquoted
NULLis accepted by the treeINSERTgrammar and becomes a real null on the server (CommonUtils.parseValue). identifierValuelower-cases names the same way the server canonicalizes them (QualifiedName).iotdb-relational-grammarwas already on the CLI classpath throughnode-commons, so the packaged CLI does not change.
| } catch (Exception e) { | ||
| importFailed.set(true); | ||
| loadFileFailedNum.increment(); | ||
| ioTPrinter.println( | ||
| String.format("[%s] - Unexpected error occurred: %s", file.getName(), e.getMessage())); | ||
| String.format( | ||
| CliMessages.MESSAGE_ARG_UNEXPECTED_ERROR_OCCURRED_ARG_E7255EE6, | ||
| file == null ? filePath : file.getName(), | ||
| e.getMessage())); | ||
| } |
There was a problem hiding this comment.
This catch wraps the whole while (... pollFromQueue() != null) loop. executeWithRetry now throws IllegalStateException, but importFromCsvFile only catches IOException (plus IllegalPathException in the tree variant). As a result, a single failed batch ends this worker thread.
The files still in the queue are then not imported, not counted in loadFileFailedNum, and not mentioned in the output:
- With
-tn 1, or once every thread has hit a failure, all remaining files are skipped. - With the default 8 threads, which files get imported depends on how many threads have already exited.
For the tree align-by-device path this is also a behaviour change, because it used to log the StatementExecutionException and continue.
Repro: set threadNum = 1 and queue a_bad.csv (its batch throws), then b_good.csv. init() returns false, but b_good.csv is still in ImportDataScanTool's queue afterwards and was never inserted.
Suggestion: move the try/catch inside the loop body, for both the TsFile loop and the CSV/SQL loop. Each failure is then handled per file: mark the import as failed, increment loadFileFailedNum, print the file name, and continue with the next file.
Probe test (fits into DataToolRegressionTest; fails today)
@Test
public void testFailedCsvDoesNotSkipRemainingFiles() throws Exception {
Path bad = directory.resolve("a_bad.csv");
Path good = directory.resolve("b_good.csv");
Files.writeString(bad, "Time,root.a.d1.s1(INT32)\n1,11\n");
Files.writeString(good, "Time,root.a.d2.s1(INT32)\n1,22\n");
SessionPool pool = mock(SessionPool.class);
set(ImportDataTree.class, "sessionPool", pool);
doAnswer(
invocation -> {
if (((List<?>) invocation.getArgument(0)).contains("root.a.d1")) {
throw new StatementExecutionException("type mismatch");
}
return null;
})
.when(pool)
.insertRecords(any(), any(), any(), any(), any());
ImportDataScanTool.putToQueue(bad.toString());
ImportDataScanTool.putToQueue(good.toString());
assertFalse(AbstractImportData.init(new ImportDataTree())); // threadNum = 1 in setUp()
assertNull(ImportDataScanTool.pollFromQueue()); // fails today: b_good.csv is still queued
}There was a problem hiding this comment.
Addressed in 240cfd502cce. Both worker loops now catch exceptions per file, record that file's failure, and continue draining the queue. Added single-worker regressions for tree align-by-time, tree align-by-device, and table CSV imports: the first batch fails while the next file is still inserted.
| public abstract class AbstractImportData extends AbstractDataTool implements Runnable { | ||
|
|
||
| private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out); | ||
| private static final AtomicBoolean importFailed = new AtomicBoolean(); |
There was a problem hiding this comment.
importFailed is private and is only set inside AbstractImportData: on worker exceptions, archival failures and failed TsFile loads. These paths still print "Import completely!" and exit with 0:
.sqlinput. Failed statements inImportDataTree#importFromSqlFile/ImportDataTable#importFromSqlFileare only written to the.failedfile. In a probe where every statement throwsStatementExecutionException,init()still returnstrue.- CSV files rejected as a whole. This covers an empty file, a first column that is not
Time, a wrong extension, and anIOExceptionwhile reading, i.e. the early returns and thecatchin bothimportFromCsvFileimplementations. A probe with the headerts,root.a.d1.s1returnstrue.
Could we add something like protected static void markImportFailed() and call it from those branches? If that is out of scope on purpose, it would help to state in the description which failure modes now produce a non-zero exit code.
Whether row-level conversion failures that only go to .failed should also fail the run is a separate product decision, so I'm not suggesting that here.
There was a problem hiding this comment.
Addressed in 240cfd502cce. Shared failure markers now cover failed SQL statements, table SQL database mismatches, SQL read errors, and CSV files rejected for an empty file, invalid time header, unsupported extension, or read/path errors. Failed SQL files are counted once as failures instead of successes. Added coverage in both models. The existing row-level conversion/.failed policy is unchanged.
| throw new StatementExecutionException(message); | ||
| } | ||
| // Multiple source relations do not have an unambiguous destination table. | ||
| if (sources.size() != 1) { |
There was a problem hiding this comment.
Minor / FYI: because this counts tableName nodes, it also rejects single-table queries that mention the table more than once, for example select * from t where v in (select v from t) or a CTE over t. Both fail with "requires a query from a single table". Failing closed seems right here, since simple de-duplication would also let self-joins through. It may be worth spelling out the limitation in the docs or help text, e.g. that joins, subqueries and CTEs are not supported for -ft sql/tsfile custom queries.
There was a problem hiding this comment.
Updated the -q help in 240cfd502cce for both English and Chinese: table SQL/TsFile custom queries require one table without joins, subqueries, or CTEs. The help also now reflects that -q supports SQL/TsFile export, replacing the obsolete CSV-only description.
|
Applied both findings in
Added regression coverage for the colliding paths under copy/hard-link/move operations, existing main-file and sidecar conflicts without source-file loss, and typed/untyped CSV export-import round trips with a column containing spaces and parentheses. Validation: Spotless and CLI Checkstyle passed. Full-reactor checks remain incomplete due to local memory limits: the English build failed with a JVM native-memory allocation error in Thrift compilation; the Chinese retry was stopped during DataNode Checkstyle with its capped 512 MB heap full. No live-cluster integration tests were run. |
|
Applied the remaining review feedback in
Validation: Spotless and CLI Checkstyle passed. Full-reactor No live-cluster integration tests were run. Review threads are left open for re-review. |
Description
import-dataandexport-datacan silently produce incorrect output or report success after an import fails. For example, a tree query containing interleaved columns from two devices currently exports only the first device and assigns it a value from the other device. Multiple custom table queries also overwrite the same output file and can use the wrong destination table.This change fixes the data tools by:
NULLfor missing values..resourceand.modssidecars, and reporting file-operation failures accurately.Validation
mvn -o test -pl iotdb-client/cli -Dtest=DataToolRegressionTest,ImportTsFileOperationTest,WriteDataFileTest -Ddevelocity.off=true: 21 tests passed, including 18 new regression tests.mvn -o test-compile -DskipTests -Ddevelocity.off=true: full 53-module reactor passed.mvn -o test-compile -P with-zh-locale -DskipTests -Ddevelocity.off=true: full 53-module Chinese-locale reactor passed.ret_codeunset, 0, and 23.git diff --checkpassed.No live-cluster integration tests were run.
This PR has: