From 37cea6f19a04ed62073e31f364b94cc2ab5178fc Mon Sep 17 00:00:00 2001 From: "tianjin.lp" Date: Fri, 25 Dec 2015 08:22:29 +0800 Subject: [PATCH 001/114] add all code --- README | 0 README.md | 100 +- adswriter/adswriter.iml | 72 ++ adswriter/doc/adswriter.md | 298 +++++ adswriter/pom.xml | 113 ++ adswriter/src/main/assembly/package.xml | 36 + .../plugin/writer/adswriter/AdsException.java | 40 + .../plugin/writer/adswriter/AdsWriter.java | 328 +++++ .../writer/adswriter/AdsWriterErrorCode.java | 54 + .../writer/adswriter/ads/ColumnDataType.java | 414 +++++++ .../writer/adswriter/ads/ColumnInfo.java | 72 ++ .../writer/adswriter/ads/TableInfo.java | 69 ++ .../writer/adswriter/ads/package-info.java | 6 + .../adswriter/insert/AdsInsertProxy.java | 286 +++++ .../adswriter/insert/AdsInsertUtil.java | 134 ++ .../writer/adswriter/load/AdsHelper.java | 388 ++++++ .../adswriter/load/TableMetaHelper.java | 87 ++ .../adswriter/load/TransferProjectConf.java | 65 + .../writer/adswriter/odps/DataType.java | 77 ++ .../writer/adswriter/odps/FieldSchema.java | 63 + .../writer/adswriter/odps/TableMeta.java | 114 ++ .../writer/adswriter/odps/package-info.java | 6 + .../plugin/writer/adswriter/package-info.java | 6 + .../plugin/writer/adswriter/util/AdsUtil.java | 134 ++ .../writer/adswriter/util/Constant.java | 13 + .../plugin/writer/adswriter/util/Key.java | 48 + adswriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 13 + common/datax-common.iml | 30 + common/pom.xml | 81 ++ .../alibaba/datax/common/base/BaseObject.java | 25 + .../datax/common/constant/CommonConstant.java | 9 + .../datax/common/constant/PluginType.java | 20 + .../datax/common/element/BoolColumn.java | 115 ++ .../datax/common/element/BytesColumn.java | 84 ++ .../alibaba/datax/common/element/Column.java | 75 ++ .../datax/common/element/ColumnCast.java | 199 +++ .../datax/common/element/DateColumn.java | 130 ++ .../datax/common/element/DoubleColumn.java | 161 +++ .../datax/common/element/LongColumn.java | 135 +++ .../datax/common/element/OverFlowUtil.java | 62 + .../alibaba/datax/common/element/Record.java | 23 + .../datax/common/element/StringColumn.java | 163 +++ .../common/exception/CommonErrorCode.java | 45 + .../common/exception/DataXException.java | 60 + .../common/exception/ExceptionTracker.java | 15 + .../common/plugin/AbstractJobPlugin.java | 25 + .../datax/common/plugin/AbstractPlugin.java | 87 ++ .../common/plugin/AbstractTaskPlugin.java | 37 + .../common/plugin/JobPluginCollector.java | 22 + .../datax/common/plugin/PluginCollector.java | 9 + .../datax/common/plugin/Pluginable.java | 30 + .../datax/common/plugin/RecordReceiver.java | 26 + .../datax/common/plugin/RecordSender.java | 32 + .../common/plugin/TaskPluginCollector.java | 57 + .../alibaba/datax/common/spi/ErrorCode.java | 33 + .../com/alibaba/datax/common/spi/Hook.java | 27 + .../com/alibaba/datax/common/spi/Reader.java | 52 + .../com/alibaba/datax/common/spi/Writer.java | 40 + .../datax/common/statistics/PerfRecord.java | 246 ++++ .../datax/common/statistics/PerfTrace.java | 422 +++++++ .../datax/common/statistics/VMInfo.java | 412 +++++++ .../datax/common/util/Configuration.java | 1078 +++++++++++++++++ .../alibaba/datax/common/util/FilterUtil.java | 52 + .../alibaba/datax/common/util/HostUtils.java | 50 + .../alibaba/datax/common/util/ListUtil.java | 139 +++ .../datax/common/util/RangeSplitUtil.java | 209 ++++ .../alibaba/datax/common/util/RetryUtil.java | 171 +++ .../alibaba/datax/common/util/StrUtil.java | 85 ++ .../alibaba/datax/common/base/BaseTest.java | 30 + .../datax/common/element/BoolColumnTest.java | 79 ++ .../datax/common/element/ColumnCastTest.java | 95 ++ .../datax/common/element/DateColumnTest.java | 109 ++ .../common/element/DoubleColumnTest.java | 250 ++++ .../datax/common/element/LongColumnTest.java | 217 ++++ .../common/element/ScientificTester.java | 12 + .../common/element/StringColumnTest.java | 216 ++++ .../common/exception/DataXExceptionTest.java | 29 + .../datax/common/exception/FakeErrorCode.java | 37 + .../common/statistics/PerfRecordTest.java | 471 +++++++ .../datax/common/statistics/VMInfoTest.java | 109 ++ .../datax/common/util/ConfigurationTest.java | 699 +++++++++++ .../datax/common/util/FilterUtilTest.java | 169 +++ .../datax/common/util/ListUtilTest.java | 90 ++ .../datax/common/util/RangeSplitUtilTest.java | 185 +++ .../datax/common/util/RetryUtilTest.java | 259 ++++ .../datax/common/util/StrUtilTest.java | 59 + common/src/test/resources/all.json | 151 +++ common/src/test/resources/logback-test.xml | 18 + common/src/test/resources/logback.xml | 18 + core/datax-core.iml | 47 + core/pom.xml | 145 +++ core/src/main/assembly/package.xml | 98 ++ core/src/main/bin/datax.py | 216 ++++ core/src/main/bin/dxprof.py | 191 +++ core/src/main/conf/.secret.properties | 3 + core/src/main/conf/core.json | 61 + core/src/main/conf/logback.xml | 150 +++ .../alibaba/datax/core/AbstractContainer.java | 35 + .../java/com/alibaba/datax/core/Engine.java | 217 ++++ .../core/container/util/HookInvoker.java | 91 ++ .../core/container/util/JobAssignUtil.java | 177 +++ .../alibaba/datax/core/job/JobContainer.java | 923 ++++++++++++++ .../datax/core/job/meta/ExecuteMode.java | 22 + .../alibaba/datax/core/job/meta/State.java | 32 + .../core/job/scheduler/AbstractScheduler.java | 135 +++ .../processinner/ProcessInnerScheduler.java | 60 + .../processinner/StandAloneScheduler.java | 19 + .../communication/Communication.java | 281 +++++ .../communication/CommunicationTool.java | 261 ++++ .../LocalTGCommunicationManager.java | 62 + .../collector/AbstractCollector.java | 69 ++ .../collector/ProcessInnerCollector.java | 17 + .../AbstractContainerCommunicator.java | 88 ++ .../StandAloneJobContainerCommunicator.java | 63 + .../AbstractTGContainerCommunicator.java | 74 ++ .../StandaloneTGContainerCommunicator.java | 19 + .../container/report/AbstractReporter.java | 11 + .../report/ProcessInnerReporter.java | 17 + .../plugin/DefaultJobPluginCollector.java | 31 + .../task/AbstractTaskPluginCollector.java | 77 ++ .../plugin/task/HttpPluginCollector.java | 23 + .../plugin/task/StdoutPluginCollector.java | 74 ++ .../plugin/task/util/DirtyRecord.java | 151 +++ .../core/taskgroup/TaskGroupContainer.java | 540 +++++++++ .../datax/core/taskgroup/TaskMonitor.java | 113 ++ .../core/taskgroup/runner/AbstractRunner.java | 113 ++ .../core/taskgroup/runner/ReaderRunner.java | 88 ++ .../runner/TaskGroupContainerRunner.java | 44 + .../core/taskgroup/runner/WriterRunner.java | 90 ++ .../datax/core/transport/channel/Channel.java | 247 ++++ .../channel/memory/MemoryChannel.java | 146 +++ .../exchanger/BufferedRecordExchanger.java | 156 +++ .../transport/exchanger/RecordExchanger.java | 99 ++ .../core/transport/record/DefaultRecord.java | 119 ++ .../transport/record/TerminateRecord.java | 48 + .../alibaba/datax/core/util/ClassSize.java | 42 + .../alibaba/datax/core/util/ClassUtil.java | 40 + .../alibaba/datax/core/util/ConfigParser.java | 181 +++ .../core/util/ConfigurationValidate.java | 33 + .../datax/core/util/ErrorRecordChecker.java | 82 ++ .../datax/core/util/ExceptionTracker.java | 15 + .../datax/core/util/FrameworkErrorCode.java | 68 ++ .../datax/core/util/HttpClientUtil.java | 169 +++ .../alibaba/datax/core/util/SecretUtil.java | 440 +++++++ .../util/container/ClassLoaderSwapper.java | 41 + .../core/util/container/CoreConstant.java | 168 +++ .../datax/core/util/container/JarLoader.java | 97 ++ .../datax/core/util/container/LoadUtil.java | 202 +++ core/src/main/job/job.json | 52 + core/src/main/log/datax.log | 0 core/src/main/script/Readme.md | 1 + core/src/main/tmp/readme.txt | 4 + .../com/alibaba/datax/core/EngineTest.java | 62 + .../datax/core/constant/CoreConstantTest.java | 12 + .../container/ClassLoaderSwapperTest.java | 23 + .../core/container/JobAssignUtilTest.java | 56 + .../core/container/JobContainerTest.java | 369 ++++++ .../datax/core/container/LoadUtilTest.java | 31 + .../container/TaskGroupContainerTest.java | 129 ++ .../datax/core/faker/FakeExceptionReader.java | 75 ++ .../datax/core/faker/FakeExceptionWriter.java | 76 ++ .../datax/core/faker/FakeJobContainer.java | 18 + .../datax/core/faker/FakeLongTimeWriter.java | 86 ++ .../datax/core/faker/FakeOneReader.java | 82 ++ .../alibaba/datax/core/faker/FakeReader.java | 116 ++ .../alibaba/datax/core/faker/FakeWriter.java | 100 ++ .../datax/core/scaffold/ColumnProducer.java | 30 + .../core/scaffold/ConfigurationProducer.java | 15 + .../datax/core/scaffold/RecordProducer.java | 25 + .../core/scaffold/base/CaseInitializer.java | 39 + .../core/scheduler/ErrorRecordLimitTest.java | 57 + .../standalone/StandAloneSchedulerTest.java | 64 + .../StandAloneTestJobCollector.java | 45 + .../StandAloneTestTaskGroupContainer.java | 23 + .../collector/ProcessInnerCollectorTest.java | 36 + .../CommunicationJsonifyTest.java | 31 + .../communication/CommunicationTest.java | 122 ++ .../LocalTaskGroupCommunicationTest.java | 48 + .../reporter/ProcessInnerReporterTest.java | 43 + .../datax/core/taskgroup/TaskMonitorTest.java | 192 +++ .../channel/memory/MemoryChannelTest.java | 174 +++ .../exchanger/RecordExchangerTest.java | 293 +++++ .../core/transport/record/RecordTest.java | 20 + .../datax/core/util/ClassUtilTest.java | 53 + .../datax/core/util/ConfigParserTest.java | 162 +++ .../datax/core/util/HttpClientUtilTest.java | 175 +++ .../alibaba/datax/core/util/ReflectUtil.java | 43 + .../datax/core/util/SecretUtilTest.java | 107 ++ core/src/test/resources/all.json | 163 +++ .../test/resources/conf/.secret.properties | 11 + core/src/test/resources/conf/core.json | 51 + core/src/test/resources/conf/logback.xml | 148 +++ core/src/test/resources/dryRunAll.json | 157 +++ core/src/test/resources/job/job.json | 27 + .../plugin/reader/fakereader/FakePluginer.jar | Bin 0 -> 19608 bytes .../plugin/reader/fakereader/plugin.json | 10 + .../plugin/writer/fakewriter/FakePluginer.jar | Bin 0 -> 19608 bytes .../plugin/writer/fakewriter/plugin.json | 10 + datax-all.iml | 13 + drdsreader/doc/drdsreader.md | 348 ++++++ drdsreader/drdsreader.iml | 46 + drdsreader/pom.xml | 82 ++ drdsreader/src/main/assembly/package.xml | 35 + .../plugin/reader/drdsreader/DrdsReader.java | 150 +++ .../drdsreader/DrdsReaderErrorCode.java | 31 + .../drdsreader/DrdsReaderSplitUtil.java | 121 ++ drdsreader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 11 + drdswriter/doc/drdswriter.md | 386 ++++++ drdswriter/drdswriter.iml | 46 + drdswriter/pom.xml | 83 ++ drdswriter/src/main/assembly/package.xml | 35 + .../plugin/writer/drdswriter/DrdsWriter.java | 97 ++ drdswriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 13 + ftpreader/doc/ftpreader.md | 292 +++++ ftpreader/ftpreader.iml | 32 + ftpreader/pom.xml | 92 ++ ftpreader/src/main/assembly/package.xml | 35 + .../plugin/reader/ftpreader/Constant.java | 14 + .../plugin/reader/ftpreader/FtpHelper.java | 107 ++ .../plugin/reader/ftpreader/FtpReader.java | 244 ++++ .../reader/ftpreader/FtpReaderErrorCode.java | 52 + .../datax/plugin/reader/ftpreader/Key.java | 13 + .../plugin/reader/ftpreader/SftpHelper.java | 247 ++++ .../reader/ftpreader/StandardFtpHelper.java | 229 ++++ .../src/main/resources/plugin-template.json | 38 + ftpreader/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 19 + hbasereader/doc/hbasereader.md | 347 ++++++ hbasereader/hbasereader.iml | 83 ++ hbasereader/pom.xml | 89 ++ hbasereader/src/main/assembly/package.xml | 35 + .../plugin/reader/hbasereader/ColumnType.java | 43 + .../plugin/reader/hbasereader/Constant.java | 10 + .../reader/hbasereader/HTableManager.java | 27 + .../reader/hbasereader/HbaseColumnCell.java | 124 ++ .../reader/hbasereader/HbaseColumnConfig.java | 21 + .../reader/hbasereader/HbaseReader.java | 130 ++ .../hbasereader/HbaseReaderErrorCode.java | 37 + .../datax/plugin/reader/hbasereader/Key.java | 50 + .../plugin/reader/hbasereader/ModeType.java | 28 + .../hbasereader/util/HbaseAbstractTask.java | 89 ++ .../hbasereader/util/HbaseSplitUtil.java | 149 +++ .../reader/hbasereader/util/HbaseUtil.java | 362 ++++++ .../util/MultiVersionDynamicColumnTask.java | 27 + .../util/MultiVersionFixedColumnTask.java | 27 + .../hbasereader/util/MultiVersionTask.java | 141 +++ .../reader/hbasereader/util/NormalTask.java | 160 +++ hbasereader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 15 + hdfsreader/doc/hdfsreader.md | 257 ++++ hdfsreader/hdfsreader.iml | 170 +++ hdfsreader/pom.xml | 123 ++ hdfsreader/src/main/assembly/package.xml | 49 + .../plugin/reader/hdfsreader/Constant.java | 10 + .../plugin/reader/hdfsreader/DFSUtil.java | 523 ++++++++ .../reader/hdfsreader/HdfsFileType.java | 8 + .../plugin/reader/hdfsreader/HdfsReader.java | 298 +++++ .../hdfsreader/HdfsReaderErrorCode.java | 44 + .../datax/plugin/reader/hdfsreader/Key.java | 18 + hdfsreader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 11 + hdfswriter/doc/hdfswriter.md | 355 ++++++ hdfswriter/hdfswriter.iml | 163 +++ hdfswriter/pom.xml | 135 +++ hdfswriter/src/main/assembly/package.xml | 35 + .../plugin/writer/hdfswriter/Constant.java | 7 + .../plugin/writer/hdfswriter/HdfsHelper.java | 515 ++++++++ .../plugin/writer/hdfswriter/HdfsWriter.java | 373 ++++++ .../hdfswriter/HdfsWriterErrorCode.java | 44 + .../datax/plugin/writer/hdfswriter/Key.java | 32 + .../hdfswriter/SupportHiveDataType.java | 19 + hdfswriter/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 13 + mongodbreader/doc/mongodbreader.md | 149 +++ mongodbreader/mongodbreader.iml | 31 + mongodbreader/pom.xml | 88 ++ mongodbreader/src/main/assembly/package.xml | 36 + .../reader/mongodbreader/KeyConstant.java | 67 + .../reader/mongodbreader/MongoDBReader.java | 173 +++ .../mongodbreader/MongoDBReaderErrorCode.java | 33 + .../util/CollectionSplitUtil.java | 77 ++ .../reader/mongodbreader/util/MongoUtil.java | 99 ++ mongodbreader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 11 + mongodbwriter/doc/mongodbwriter.md | 157 +++ mongodbwriter/mongodbwriter.iml | 52 + mongodbwriter/pom.xml | 92 ++ mongodbwriter/src/main/assembly/package.xml | 36 + .../writer/mongodbwriter/KeyConstant.java | 79 ++ .../writer/mongodbwriter/MongoDBWriter.java | 309 +++++ .../mongodbwriter/MongoDBWriterErrorCode.java | 33 + .../writer/mongodbwriter/util/MongoUtil.java | 103 ++ mongodbwriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 15 + mysqlreader/doc/mysqlreader.md | 377 ++++++ mysqlreader/mysqlreader.iml | 46 + mysqlreader/pom.xml | 79 ++ mysqlreader/src/main/assembly/package.xml | 35 + .../reader/mysqlreader/MysqlReader.java | 97 ++ .../mysqlreader/MysqlReaderErrorCode.java | 31 + mysqlreader/src/main/resources/TODO.txt | 3 + mysqlreader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 15 + mysqlwriter/doc/mysqlwriter.md | 359 ++++++ mysqlwriter/mysqlwriter.iml | 46 + mysqlwriter/pom.xml | 78 ++ mysqlwriter/src/main/assembly/package.xml | 35 + .../writer/mysqlwriter/MysqlWriter.java | 101 ++ .../mysqlwriter/MysqlWriterErrorCode.java | 31 + mysqlwriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 17 + ocswriter/doc/ocswriter.md | 168 +++ ocswriter/ocswriter.iml | 64 + ocswriter/pom.xml | 94 ++ ocswriter/src/main/assembly/package.xml | 35 + .../datax/plugin/writer/ocswriter/Key.java | 26 + .../plugin/writer/ocswriter/OcsWriter.java | 321 +++++ .../writer/ocswriter/utils/CommonUtils.java | 15 + .../ocswriter/utils/ConfigurationChecker.java | 147 +++ .../ocswriter/utils/OcsWriterErrorCode.java | 34 + ocswriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 15 + odpsreader/doc/odpsreader.md | 349 ++++++ odpsreader/odpsreader.iml | 50 + odpsreader/pom.xml | 118 ++ odpsreader/src/main/assembly/package.xml | 35 + .../plugin/reader/odpsreader/ColumnType.java | 31 + .../plugin/reader/odpsreader/Constant.java | 35 + .../datax/plugin/reader/odpsreader/Key.java | 34 + .../plugin/reader/odpsreader/OdpsReader.java | 390 ++++++ .../odpsreader/OdpsReaderErrorCode.java | 60 + .../plugin/reader/odpsreader/ReaderProxy.java | 281 +++++ .../reader/odpsreader/util/DESCipher.java | 355 ++++++ .../reader/odpsreader/util/IdAndKeyUtil.java | 85 ++ .../odpsreader/util/OdpsExceptionMsg.java | 18 + .../reader/odpsreader/util/OdpsSplitUtil.java | 168 +++ .../reader/odpsreader/util/OdpsUtil.java | 377 ++++++ odpsreader/src/main/resources/TODO.txt | 6 + odpsreader/src/main/resources/plugin.json | 10 + .../main/resources/plugin_job_template.json | 14 + odpswriter/doc/odpswriter.md | 338 ++++++ odpswriter/odpswriter.iml | 51 + odpswriter/pom.xml | 100 ++ odpswriter/src/main/assembly/package.xml | 35 + .../plugin/writer/odpswriter/Constant.java | 15 + .../datax/plugin/writer/odpswriter/Key.java | 34 + .../plugin/writer/odpswriter/OdpsWriter.java | 356 ++++++ .../odpswriter/OdpsWriterErrorCode.java | 66 + .../writer/odpswriter/OdpsWriterProxy.java | 190 +++ .../writer/odpswriter/util/DESCipher.java | 355 ++++++ .../writer/odpswriter/util/IdAndKeyUtil.java | 85 ++ .../odpswriter/util/OdpsExceptionMsg.java | 18 + .../writer/odpswriter/util/OdpsUtil.java | 585 +++++++++ odpswriter/src/main/resources/TODO.txt | 3 + odpswriter/src/main/resources/plugin.json | 10 + .../main/resources/plugin_job_template.json | 14 + oraclereader/doc/oraclereader.md | 347 ++++++ oraclereader/oraclereader.iml | 54 + oraclereader/pom.xml | 86 ++ oraclereader/src/main/assembly/package.xml | 35 + .../plugin/reader/oraclereader/Constant.java | 7 + .../reader/oraclereader/OracleReader.java | 126 ++ .../oraclereader/OracleReaderErrorCode.java | 33 + oraclereader/src/main/lib/ojdbc6-11.2.0.3.jar | Bin 0 -> 2714189 bytes oraclereader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 14 + oraclewriter/doc/oraclewriter.md | 416 +++++++ oraclewriter/oraclewriter.iml | 54 + oraclewriter/pom.xml | 82 ++ oraclewriter/src/main/assembly/package.xml | 35 + .../writer/oraclewriter/OracleWriter.java | 104 ++ .../oraclewriter/OracleWriterErrorCode.java | 31 + oraclewriter/src/main/lib/ojdbc6-11.2.0.3.jar | Bin 0 -> 2714189 bytes oraclewriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 15 + ossreader/doc/ossreader.md | 244 ++++ ossreader/ossreader.iml | 35 + ossreader/pom.xml | 82 ++ ossreader/src/main/assembly/package.xml | 34 + .../plugin/reader/ossreader/Constants.java | 10 + .../datax/plugin/reader/ossreader/Key.java | 19 + .../plugin/reader/ossreader/OssReader.java | 317 +++++ .../reader/ossreader/OssReaderErrorCode.java | 45 + .../plugin/reader/ossreader/util/OssUtil.java | 32 + ossreader/src/main/resources/basic0.json | 55 + ossreader/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 14 + osswriter/doc/osswriter.md | 214 ++++ osswriter/osswriter.iml | 35 + osswriter/pom.xml | 80 ++ osswriter/src/main/assembly/package.xml | 34 + .../plugin/writer/osswriter/Constant.java | 9 + .../datax/plugin/writer/osswriter/Key.java | 17 + .../plugin/writer/osswriter/OssWriter.java | 436 +++++++ .../writer/osswriter/OssWriterErrorCode.java | 41 + .../plugin/writer/osswriter/util/OssUtil.java | 29 + osswriter/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 13 + otsreader/doc/otsreader.md | 340 ++++++ otsreader/otsreader.iml | 38 + otsreader/pom.xml | 91 ++ otsreader/src/main/assembly/package.xml | 35 + .../datax/plugin/reader/otsreader/Key.java | 50 + .../plugin/reader/otsreader/OtsReader.java | 124 ++ .../reader/otsreader/OtsReaderError.java | 42 + .../otsreader/OtsReaderMasterProxy.java | 221 ++++ .../reader/otsreader/OtsReaderSlaveProxy.java | 135 +++ .../otsreader/adaptor/OTSColumnAdaptor.java | 117 ++ .../adaptor/PrimaryKeyValueAdaptor.java | 91 ++ .../GetFirstRowPrimaryKeyCallable.java | 55 + .../otsreader/callable/GetRangeCallable.java | 35 + .../callable/GetTableMetaCallable.java | 29 + .../reader/otsreader/model/OTSColumn.java | 76 ++ .../reader/otsreader/model/OTSConf.java | 90 ++ .../reader/otsreader/model/OTSConst.java | 25 + .../otsreader/model/OTSPrimaryKeyColumn.java | 22 + .../reader/otsreader/model/OTSRange.java | 29 + .../plugin/reader/otsreader/utils/Common.java | 161 +++ .../otsreader/utils/DefaultNoRetry.java | 17 + .../reader/otsreader/utils/GsonParser.java | 63 + .../reader/otsreader/utils/ParamChecker.java | 245 ++++ .../reader/otsreader/utils/RangeSplit.java | 379 ++++++ .../otsreader/utils/ReaderModelParser.java | 175 +++ .../reader/otsreader/utils/RetryHelper.java | 83 ++ otsreader/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 14 + otswriter/doc/otswriter.md | 234 ++++ otswriter/otswriter.iml | 38 + otswriter/pom.xml | 89 ++ otswriter/src/main/assembly/package.xml | 35 + .../datax/plugin/writer/otswriter/Key.java | 36 + .../plugin/writer/otswriter/OtsWriter.java | 92 ++ .../writer/otswriter/OtsWriterError.java | 46 + .../otswriter/OtsWriterMasterProxy.java | 106 ++ .../writer/otswriter/OtsWriterSlaveProxy.java | 86 ++ .../callable/BatchWriteRowCallable.java | 25 + .../callable/GetTableMetaCallable.java | 29 + .../callable/PutRowChangeCallable.java | 24 + .../callable/UpdateRowChangeCallable.java | 24 + .../otswriter/model/LogExceptionManager.java | 58 + .../writer/otswriter/model/OTSAttrColumn.java | 21 + .../model/OTSBatchWriteRowTaskManager.java | 46 + .../model/OTSBatchWriterRowTask.java | 226 ++++ .../otswriter/model/OTSBlockingExecutor.java | 52 + .../writer/otswriter/model/OTSConf.java | 136 +++ .../writer/otswriter/model/OTSConst.java | 32 + .../otswriter/model/OTSErrorMessage.java | 66 + .../writer/otswriter/model/OTSLine.java | 42 + .../writer/otswriter/model/OTSOpType.java | 6 + .../writer/otswriter/model/OTSPKColumn.java | 22 + .../otswriter/model/OTSRowPrimaryKey.java | 61 + .../writer/otswriter/model/OTSSendBuffer.java | 58 + .../plugin/writer/otswriter/model/Pair.java | 24 + .../otswriter/utils/ColumnConversion.java | 61 + .../plugin/writer/otswriter/utils/Common.java | 134 ++ .../otswriter/utils/DefaultNoRetry.java | 17 + .../writer/otswriter/utils/GsonParser.java | 46 + .../writer/otswriter/utils/ParamChecker.java | 153 +++ .../writer/otswriter/utils/RetryHelper.java | 76 ++ .../otswriter/utils/SizeCalculateHelper.java | 67 + .../otswriter/utils/WriterModelParser.java | 137 +++ otswriter/src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 13 + package.xml | 298 +++++ plugin-rdbms-util/plugin-rdbms-util.iml | 46 + plugin-rdbms-util/pom.xml | 66 + .../rdbms/reader/CommonRdbmsReader.java | 206 ++++ .../datax/plugin/rdbms/reader/Constant.java | 24 + .../datax/plugin/rdbms/reader/Key.java | 44 + .../rdbms/reader/ResultSetReadProxy.java | 139 +++ .../plugin/rdbms/reader/util/HintUtil.java | 67 + .../util/OriginalConfPretreatmentUtil.java | 271 +++++ .../rdbms/reader/util/PreCheckTask.java | 100 ++ .../rdbms/reader/util/ReaderSplitUtil.java | 158 +++ .../reader/util/SingleTableSplitUtil.java | 277 +++++ .../plugin/rdbms/util/ConnectionFactory.java | 16 + .../datax/plugin/rdbms/util/Constant.java | 27 + .../datax/plugin/rdbms/util/DBUtil.java | 764 ++++++++++++ .../plugin/rdbms/util/DBUtilErrorCode.java | 95 ++ .../datax/plugin/rdbms/util/DataBaseType.java | 195 +++ .../rdbms/util/JdbcConnectionFactory.java | 39 + .../plugin/rdbms/util/RdbmsException.java | 190 +++ .../rdbms/util/RdbmsRangeSplitWrap.java | 86 ++ .../plugin/rdbms/util/TableExpandUtil.java | 83 ++ .../rdbms/writer/CommonRdbmsWriter.java | 547 +++++++++ .../datax/plugin/rdbms/writer/Constant.java | 19 + .../datax/plugin/rdbms/writer/Key.java | 40 + .../rdbms/writer/MysqlWriterErrorCode.java | 32 + .../util/OriginalConfPretreatmentUtil.java | 160 +++ .../plugin/rdbms/writer/util/WriterUtil.java | 176 +++ .../plugin-unstructured-storage-util.iml | 29 + plugin-unstructured-storage-util/pom.xml | 59 + .../unstructuredstorage/reader/Constant.java | 11 + .../unstructuredstorage/reader/Key.java | 28 + .../UnstructuredStorageReaderErrorCode.java | 45 + .../reader/UnstructuredStorageReaderUtil.java | 620 ++++++++++ .../unstructuredstorage/writer/Constant.java | 17 + .../unstructuredstorage/writer/Key.java | 35 + .../UnstructuredStorageWriterErrorCode.java | 36 + .../writer/UnstructuredStorageWriterUtil.java | 381 ++++++ pom.xml | 200 +++ postgresqlreader/doc/postgresqlreader.md | 297 +++++ postgresqlreader/pom.xml | 86 ++ postgresqlreader/postgresqlreader.iml | 46 + .../src/main/assembly/package.xml | 35 + .../reader/postgresqlreader/Constant.java | 7 + .../postgresqlreader/PostgresqlReader.java | 86 ++ .../src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 13 + postgresqlwriter/doc/postgresqlwriter.md | 267 ++++ postgresqlwriter/pom.xml | 82 ++ postgresqlwriter/postgresqlwriter.iml | 46 + .../src/main/assembly/package.xml | 35 + .../postgresqlwriter/PostgresqlWriter.java | 100 ++ .../src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 17 + sqlserverreader/doc/sqlserverreader.md | 279 +++++ sqlserverreader/pom.xml | 78 ++ sqlserverreader/sqlserverreader.iml | 54 + sqlserverreader/src/main/assembly/package.xml | 35 + .../reader/sqlserverreader/Constant.java | 7 + .../plugin/reader/sqlserverreader/Key.java | 6 + .../sqlserverreader/SqlServerReader.java | 95 ++ .../SqlServerReaderErrorCode.java | 26 + sqlserverreader/src/main/lib/sqljdbc4-4.0.jar | Bin 0 -> 584207 bytes .../src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 13 + sqlserverwriter/doc/sqlserverwriter.md | 248 ++++ sqlserverwriter/pom.xml | 79 ++ sqlserverwriter/sqlserverwriter.iml | 54 + sqlserverwriter/src/main/assembly/package.xml | 35 + .../sqlserverwriter/SqlServerWriter.java | 97 ++ .../SqlServerWriterErrorCode.java | 31 + sqlserverwriter/src/main/lib/sqljdbc4-4.0.jar | Bin 0 -> 584207 bytes .../src/main/resources/plugin.json | 6 + .../main/resources/plugin_job_template.json | 17 + streamreader/pom.xml | 74 ++ streamreader/src/main/assembly/package.xml | 35 + .../plugin/reader/streamreader/Constant.java | 12 + .../datax/plugin/reader/streamreader/Key.java | 12 + .../reader/streamreader/StreamReader.java | 215 ++++ .../streamreader/StreamReaderErrorCode.java | 34 + streamreader/src/main/resources/plugin.json | 10 + .../main/resources/plugin_job_template.json | 7 + streamreader/streamreader.iml | 24 + streamwriter/pom.xml | 68 ++ streamwriter/src/main/assembly/package.xml | 34 + .../datax/plugin/writer/streamwriter/Key.java | 16 + .../writer/streamwriter/StreamWriter.java | 255 ++++ .../streamwriter/StreamWriterErrorCode.java | 36 + streamwriter/src/main/resources/plugin.json | 10 + .../main/resources/plugin_job_template.json | 7 + streamwriter/streamwriter.iml | 24 + txtfilereader/doc/txtfielreader.md | 223 ++++ txtfilereader/pom.xml | 78 ++ txtfilereader/src/main/assembly/package.xml | 35 + .../plugin/reader/txtfilereader/Constant.java | 9 + .../plugin/reader/txtfilereader/Key.java | 8 + .../reader/txtfilereader/TxtFileReader.java | 420 +++++++ .../txtfilereader/TxtFileReaderErrorCode.java | 45 + txtfilereader/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 9 + txtfilereader/txtfilereader.iml | 30 + txtfilewriter/doc/txtfilewriter.md | 216 ++++ txtfilewriter/pom.xml | 78 ++ txtfilewriter/src/main/assembly/package.xml | 35 + .../plugin/writer/txtfilewriter/Key.java | 9 + .../writer/txtfilewriter/TxtFileWriter.java | 342 ++++++ .../txtfilewriter/TxtFileWriterErrorCode.java | 41 + txtfilewriter/src/main/resources/plugin.json | 7 + .../main/resources/plugin_job_template.json | 10 + txtfilewriter/txtfilewriter.iml | 30 + userGuid.md | 254 ++++ 576 files changed, 58011 insertions(+), 1 deletion(-) create mode 100755 README create mode 100644 adswriter/adswriter.iml create mode 100644 adswriter/doc/adswriter.md create mode 100644 adswriter/pom.xml create mode 100644 adswriter/src/main/assembly/package.xml create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsException.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriter.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriterErrorCode.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnDataType.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnInfo.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/TableInfo.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/package-info.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertProxy.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertUtil.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/AdsHelper.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TableMetaHelper.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TransferProjectConf.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/DataType.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/FieldSchema.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/TableMeta.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/package-info.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/package-info.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/AdsUtil.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Constant.java create mode 100644 adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Key.java create mode 100644 adswriter/src/main/resources/plugin.json create mode 100644 adswriter/src/main/resources/plugin_job_template.json create mode 100644 common/datax-common.iml create mode 100755 common/pom.xml create mode 100755 common/src/main/java/com/alibaba/datax/common/base/BaseObject.java create mode 100755 common/src/main/java/com/alibaba/datax/common/constant/CommonConstant.java create mode 100755 common/src/main/java/com/alibaba/datax/common/constant/PluginType.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/BoolColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/BytesColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/Column.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/ColumnCast.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/DateColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/DoubleColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/LongColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/OverFlowUtil.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/Record.java create mode 100755 common/src/main/java/com/alibaba/datax/common/element/StringColumn.java create mode 100755 common/src/main/java/com/alibaba/datax/common/exception/CommonErrorCode.java create mode 100755 common/src/main/java/com/alibaba/datax/common/exception/DataXException.java create mode 100644 common/src/main/java/com/alibaba/datax/common/exception/ExceptionTracker.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/AbstractJobPlugin.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/AbstractPlugin.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/AbstractTaskPlugin.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/JobPluginCollector.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/PluginCollector.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/Pluginable.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/RecordReceiver.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/RecordSender.java create mode 100755 common/src/main/java/com/alibaba/datax/common/plugin/TaskPluginCollector.java create mode 100755 common/src/main/java/com/alibaba/datax/common/spi/ErrorCode.java create mode 100755 common/src/main/java/com/alibaba/datax/common/spi/Hook.java create mode 100755 common/src/main/java/com/alibaba/datax/common/spi/Reader.java create mode 100755 common/src/main/java/com/alibaba/datax/common/spi/Writer.java create mode 100644 common/src/main/java/com/alibaba/datax/common/statistics/PerfRecord.java create mode 100644 common/src/main/java/com/alibaba/datax/common/statistics/PerfTrace.java create mode 100644 common/src/main/java/com/alibaba/datax/common/statistics/VMInfo.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/Configuration.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/FilterUtil.java create mode 100644 common/src/main/java/com/alibaba/datax/common/util/HostUtils.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/ListUtil.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/RangeSplitUtil.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/RetryUtil.java create mode 100755 common/src/main/java/com/alibaba/datax/common/util/StrUtil.java create mode 100755 common/src/test/java/com/alibaba/datax/common/base/BaseTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/BoolColumnTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/ColumnCastTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/DateColumnTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/DoubleColumnTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/LongColumnTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/ScientificTester.java create mode 100755 common/src/test/java/com/alibaba/datax/common/element/StringColumnTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/exception/DataXExceptionTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/exception/FakeErrorCode.java create mode 100644 common/src/test/java/com/alibaba/datax/common/statistics/PerfRecordTest.java create mode 100644 common/src/test/java/com/alibaba/datax/common/statistics/VMInfoTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/util/ConfigurationTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/util/FilterUtilTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/util/ListUtilTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/util/RangeSplitUtilTest.java create mode 100755 common/src/test/java/com/alibaba/datax/common/util/RetryUtilTest.java create mode 100644 common/src/test/java/com/alibaba/datax/common/util/StrUtilTest.java create mode 100755 common/src/test/resources/all.json create mode 100644 common/src/test/resources/logback-test.xml create mode 100644 common/src/test/resources/logback.xml create mode 100644 core/datax-core.iml create mode 100755 core/pom.xml create mode 100755 core/src/main/assembly/package.xml create mode 100755 core/src/main/bin/datax.py create mode 100644 core/src/main/bin/dxprof.py create mode 100755 core/src/main/conf/.secret.properties create mode 100755 core/src/main/conf/core.json create mode 100755 core/src/main/conf/logback.xml create mode 100755 core/src/main/java/com/alibaba/datax/core/AbstractContainer.java create mode 100755 core/src/main/java/com/alibaba/datax/core/Engine.java create mode 100755 core/src/main/java/com/alibaba/datax/core/container/util/HookInvoker.java create mode 100755 core/src/main/java/com/alibaba/datax/core/container/util/JobAssignUtil.java create mode 100755 core/src/main/java/com/alibaba/datax/core/job/JobContainer.java create mode 100644 core/src/main/java/com/alibaba/datax/core/job/meta/ExecuteMode.java create mode 100644 core/src/main/java/com/alibaba/datax/core/job/meta/State.java create mode 100755 core/src/main/java/com/alibaba/datax/core/job/scheduler/AbstractScheduler.java create mode 100755 core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/ProcessInnerScheduler.java create mode 100755 core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/StandAloneScheduler.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/communication/Communication.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/communication/CommunicationTool.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/communication/LocalTGCommunicationManager.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/collector/AbstractCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/collector/ProcessInnerCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/AbstractContainerCommunicator.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/job/StandAloneJobContainerCommunicator.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/AbstractTGContainerCommunicator.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/StandaloneTGContainerCommunicator.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/report/AbstractReporter.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/container/report/ProcessInnerReporter.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/plugin/DefaultJobPluginCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/AbstractTaskPluginCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/HttpPluginCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/StdoutPluginCollector.java create mode 100755 core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/util/DirtyRecord.java create mode 100755 core/src/main/java/com/alibaba/datax/core/taskgroup/TaskGroupContainer.java create mode 100644 core/src/main/java/com/alibaba/datax/core/taskgroup/TaskMonitor.java create mode 100755 core/src/main/java/com/alibaba/datax/core/taskgroup/runner/AbstractRunner.java create mode 100755 core/src/main/java/com/alibaba/datax/core/taskgroup/runner/ReaderRunner.java create mode 100755 core/src/main/java/com/alibaba/datax/core/taskgroup/runner/TaskGroupContainerRunner.java create mode 100755 core/src/main/java/com/alibaba/datax/core/taskgroup/runner/WriterRunner.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/channel/Channel.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannel.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/exchanger/BufferedRecordExchanger.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/exchanger/RecordExchanger.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/record/DefaultRecord.java create mode 100755 core/src/main/java/com/alibaba/datax/core/transport/record/TerminateRecord.java create mode 100644 core/src/main/java/com/alibaba/datax/core/util/ClassSize.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/ClassUtil.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/ConfigParser.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/ConfigurationValidate.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/ErrorRecordChecker.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/ExceptionTracker.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/FrameworkErrorCode.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/HttpClientUtil.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/SecretUtil.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/container/ClassLoaderSwapper.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/container/CoreConstant.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/container/JarLoader.java create mode 100755 core/src/main/java/com/alibaba/datax/core/util/container/LoadUtil.java create mode 100755 core/src/main/job/job.json create mode 100755 core/src/main/log/datax.log create mode 100755 core/src/main/script/Readme.md create mode 100755 core/src/main/tmp/readme.txt create mode 100755 core/src/test/java/com/alibaba/datax/core/EngineTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/constant/CoreConstantTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/container/ClassLoaderSwapperTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/container/JobAssignUtilTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/container/JobContainerTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/container/LoadUtilTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/container/TaskGroupContainerTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionReader.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionWriter.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeJobContainer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeLongTimeWriter.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeOneReader.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeReader.java create mode 100755 core/src/test/java/com/alibaba/datax/core/faker/FakeWriter.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scaffold/ColumnProducer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scaffold/ConfigurationProducer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scaffold/RecordProducer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scaffold/base/CaseInitializer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scheduler/ErrorRecordLimitTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneSchedulerTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestJobCollector.java create mode 100755 core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestTaskGroupContainer.java create mode 100755 core/src/test/java/com/alibaba/datax/core/statistics/collector/ProcessInnerCollectorTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationJsonifyTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/statistics/communication/LocalTaskGroupCommunicationTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/statistics/reporter/ProcessInnerReporterTest.java create mode 100644 core/src/test/java/com/alibaba/datax/core/taskgroup/TaskMonitorTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannelTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/transport/exchanger/RecordExchangerTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/transport/record/RecordTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/util/ClassUtilTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/util/ConfigParserTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/util/HttpClientUtilTest.java create mode 100755 core/src/test/java/com/alibaba/datax/core/util/ReflectUtil.java create mode 100755 core/src/test/java/com/alibaba/datax/core/util/SecretUtilTest.java create mode 100755 core/src/test/resources/all.json create mode 100755 core/src/test/resources/conf/.secret.properties create mode 100755 core/src/test/resources/conf/core.json create mode 100755 core/src/test/resources/conf/logback.xml create mode 100644 core/src/test/resources/dryRunAll.json create mode 100755 core/src/test/resources/job/job.json create mode 100755 core/src/test/resources/plugin/reader/fakereader/FakePluginer.jar create mode 100755 core/src/test/resources/plugin/reader/fakereader/plugin.json create mode 100755 core/src/test/resources/plugin/writer/fakewriter/FakePluginer.jar create mode 100755 core/src/test/resources/plugin/writer/fakewriter/plugin.json create mode 100644 datax-all.iml create mode 100644 drdsreader/doc/drdsreader.md create mode 100644 drdsreader/drdsreader.iml create mode 100755 drdsreader/pom.xml create mode 100755 drdsreader/src/main/assembly/package.xml create mode 100755 drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReader.java create mode 100755 drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderErrorCode.java create mode 100755 drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderSplitUtil.java create mode 100755 drdsreader/src/main/resources/plugin.json create mode 100644 drdsreader/src/main/resources/plugin_job_template.json create mode 100644 drdswriter/doc/drdswriter.md create mode 100644 drdswriter/drdswriter.iml create mode 100755 drdswriter/pom.xml create mode 100755 drdswriter/src/main/assembly/package.xml create mode 100755 drdswriter/src/main/java/com/alibaba/datax/plugin/writer/drdswriter/DrdsWriter.java create mode 100755 drdswriter/src/main/resources/plugin.json create mode 100644 drdswriter/src/main/resources/plugin_job_template.json create mode 100644 ftpreader/doc/ftpreader.md create mode 100644 ftpreader/ftpreader.iml create mode 100755 ftpreader/pom.xml create mode 100755 ftpreader/src/main/assembly/package.xml create mode 100755 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Constant.java create mode 100644 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpHelper.java create mode 100644 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReader.java create mode 100755 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReaderErrorCode.java create mode 100755 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Key.java create mode 100644 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/SftpHelper.java create mode 100644 ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/StandardFtpHelper.java create mode 100755 ftpreader/src/main/resources/plugin-template.json create mode 100755 ftpreader/src/main/resources/plugin.json create mode 100644 ftpreader/src/main/resources/plugin_job_template.json create mode 100644 hbasereader/doc/hbasereader.md create mode 100644 hbasereader/hbasereader.iml create mode 100755 hbasereader/pom.xml create mode 100755 hbasereader/src/main/assembly/package.xml create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ColumnType.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Constant.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HTableManager.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnCell.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnConfig.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReader.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReaderErrorCode.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Key.java create mode 100644 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ModeType.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseAbstractTask.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseSplitUtil.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseUtil.java create mode 100644 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionDynamicColumnTask.java create mode 100644 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionFixedColumnTask.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionTask.java create mode 100755 hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/NormalTask.java create mode 100755 hbasereader/src/main/resources/plugin.json create mode 100644 hbasereader/src/main/resources/plugin_job_template.json create mode 100644 hdfsreader/doc/hdfsreader.md create mode 100644 hdfsreader/hdfsreader.iml create mode 100644 hdfsreader/pom.xml create mode 100644 hdfsreader/src/main/assembly/package.xml create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Constant.java create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/DFSUtil.java create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsFileType.java create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReader.java create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReaderErrorCode.java create mode 100644 hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Key.java create mode 100644 hdfsreader/src/main/resources/plugin.json create mode 100644 hdfsreader/src/main/resources/plugin_job_template.json create mode 100644 hdfswriter/doc/hdfswriter.md create mode 100644 hdfswriter/hdfswriter.iml create mode 100644 hdfswriter/pom.xml create mode 100755 hdfswriter/src/main/assembly/package.xml create mode 100755 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Constant.java create mode 100644 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsHelper.java create mode 100644 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriter.java create mode 100644 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriterErrorCode.java create mode 100644 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Key.java create mode 100644 hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/SupportHiveDataType.java create mode 100755 hdfswriter/src/main/resources/plugin.json create mode 100644 hdfswriter/src/main/resources/plugin_job_template.json create mode 100644 mongodbreader/doc/mongodbreader.md create mode 100644 mongodbreader/mongodbreader.iml create mode 100644 mongodbreader/pom.xml create mode 100644 mongodbreader/src/main/assembly/package.xml create mode 100644 mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/KeyConstant.java create mode 100644 mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReader.java create mode 100644 mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReaderErrorCode.java create mode 100644 mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/CollectionSplitUtil.java create mode 100644 mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/MongoUtil.java create mode 100644 mongodbreader/src/main/resources/plugin.json create mode 100644 mongodbreader/src/main/resources/plugin_job_template.json create mode 100644 mongodbwriter/doc/mongodbwriter.md create mode 100644 mongodbwriter/mongodbwriter.iml create mode 100644 mongodbwriter/pom.xml create mode 100644 mongodbwriter/src/main/assembly/package.xml create mode 100644 mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/KeyConstant.java create mode 100644 mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriter.java create mode 100644 mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriterErrorCode.java create mode 100644 mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/util/MongoUtil.java create mode 100644 mongodbwriter/src/main/resources/plugin.json create mode 100644 mongodbwriter/src/main/resources/plugin_job_template.json create mode 100644 mysqlreader/doc/mysqlreader.md create mode 100644 mysqlreader/mysqlreader.iml create mode 100755 mysqlreader/pom.xml create mode 100755 mysqlreader/src/main/assembly/package.xml create mode 100755 mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReader.java create mode 100755 mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReaderErrorCode.java create mode 100755 mysqlreader/src/main/resources/TODO.txt create mode 100755 mysqlreader/src/main/resources/plugin.json create mode 100644 mysqlreader/src/main/resources/plugin_job_template.json create mode 100644 mysqlwriter/doc/mysqlwriter.md create mode 100644 mysqlwriter/mysqlwriter.iml create mode 100755 mysqlwriter/pom.xml create mode 100755 mysqlwriter/src/main/assembly/package.xml create mode 100755 mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriter.java create mode 100755 mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriterErrorCode.java create mode 100755 mysqlwriter/src/main/resources/plugin.json create mode 100644 mysqlwriter/src/main/resources/plugin_job_template.json create mode 100644 ocswriter/doc/ocswriter.md create mode 100644 ocswriter/ocswriter.iml create mode 100644 ocswriter/pom.xml create mode 100644 ocswriter/src/main/assembly/package.xml create mode 100644 ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/Key.java create mode 100644 ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/OcsWriter.java create mode 100644 ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/CommonUtils.java create mode 100644 ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/ConfigurationChecker.java create mode 100644 ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/OcsWriterErrorCode.java create mode 100644 ocswriter/src/main/resources/plugin.json create mode 100644 ocswriter/src/main/resources/plugin_job_template.json create mode 100644 odpsreader/doc/odpsreader.md create mode 100644 odpsreader/odpsreader.iml create mode 100755 odpsreader/pom.xml create mode 100755 odpsreader/src/main/assembly/package.xml create mode 100644 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ColumnType.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Constant.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Key.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReader.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReaderErrorCode.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ReaderProxy.java create mode 100644 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/DESCipher.java create mode 100644 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/IdAndKeyUtil.java create mode 100644 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsExceptionMsg.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsSplitUtil.java create mode 100755 odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsUtil.java create mode 100755 odpsreader/src/main/resources/TODO.txt create mode 100755 odpsreader/src/main/resources/plugin.json create mode 100644 odpsreader/src/main/resources/plugin_job_template.json create mode 100644 odpswriter/doc/odpswriter.md create mode 100644 odpswriter/odpswriter.iml create mode 100755 odpswriter/pom.xml create mode 100755 odpswriter/src/main/assembly/package.xml create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Constant.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Key.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriter.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterErrorCode.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterProxy.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/DESCipher.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/IdAndKeyUtil.java create mode 100644 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsExceptionMsg.java create mode 100755 odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsUtil.java create mode 100755 odpswriter/src/main/resources/TODO.txt create mode 100755 odpswriter/src/main/resources/plugin.json create mode 100644 odpswriter/src/main/resources/plugin_job_template.json create mode 100644 oraclereader/doc/oraclereader.md create mode 100644 oraclereader/oraclereader.iml create mode 100755 oraclereader/pom.xml create mode 100755 oraclereader/src/main/assembly/package.xml create mode 100755 oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/Constant.java create mode 100755 oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReader.java create mode 100755 oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReaderErrorCode.java create mode 100644 oraclereader/src/main/lib/ojdbc6-11.2.0.3.jar create mode 100755 oraclereader/src/main/resources/plugin.json create mode 100644 oraclereader/src/main/resources/plugin_job_template.json create mode 100644 oraclewriter/doc/oraclewriter.md create mode 100644 oraclewriter/oraclewriter.iml create mode 100755 oraclewriter/pom.xml create mode 100755 oraclewriter/src/main/assembly/package.xml create mode 100755 oraclewriter/src/main/java/com/alibaba/datax/plugin/writer/oraclewriter/OracleWriter.java create mode 100755 oraclewriter/src/main/java/com/alibaba/datax/plugin/writer/oraclewriter/OracleWriterErrorCode.java create mode 100644 oraclewriter/src/main/lib/ojdbc6-11.2.0.3.jar create mode 100755 oraclewriter/src/main/resources/plugin.json create mode 100644 oraclewriter/src/main/resources/plugin_job_template.json create mode 100644 ossreader/doc/ossreader.md create mode 100644 ossreader/ossreader.iml create mode 100755 ossreader/pom.xml create mode 100755 ossreader/src/main/assembly/package.xml create mode 100755 ossreader/src/main/java/com/alibaba/datax/plugin/reader/ossreader/Constants.java create mode 100755 ossreader/src/main/java/com/alibaba/datax/plugin/reader/ossreader/Key.java create mode 100755 ossreader/src/main/java/com/alibaba/datax/plugin/reader/ossreader/OssReader.java create mode 100755 ossreader/src/main/java/com/alibaba/datax/plugin/reader/ossreader/OssReaderErrorCode.java create mode 100755 ossreader/src/main/java/com/alibaba/datax/plugin/reader/ossreader/util/OssUtil.java create mode 100755 ossreader/src/main/resources/basic0.json create mode 100755 ossreader/src/main/resources/plugin.json create mode 100644 ossreader/src/main/resources/plugin_job_template.json create mode 100644 osswriter/doc/osswriter.md create mode 100644 osswriter/osswriter.iml create mode 100644 osswriter/pom.xml create mode 100644 osswriter/src/main/assembly/package.xml create mode 100644 osswriter/src/main/java/com/alibaba/datax/plugin/writer/osswriter/Constant.java create mode 100644 osswriter/src/main/java/com/alibaba/datax/plugin/writer/osswriter/Key.java create mode 100644 osswriter/src/main/java/com/alibaba/datax/plugin/writer/osswriter/OssWriter.java create mode 100644 osswriter/src/main/java/com/alibaba/datax/plugin/writer/osswriter/OssWriterErrorCode.java create mode 100644 osswriter/src/main/java/com/alibaba/datax/plugin/writer/osswriter/util/OssUtil.java create mode 100644 osswriter/src/main/resources/plugin.json create mode 100644 osswriter/src/main/resources/plugin_job_template.json create mode 100644 otsreader/doc/otsreader.md create mode 100644 otsreader/otsreader.iml create mode 100644 otsreader/pom.xml create mode 100644 otsreader/src/main/assembly/package.xml create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/Key.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/OtsReader.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/OtsReaderError.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/OtsReaderMasterProxy.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/OtsReaderSlaveProxy.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/adaptor/OTSColumnAdaptor.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/adaptor/PrimaryKeyValueAdaptor.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/callable/GetFirstRowPrimaryKeyCallable.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/callable/GetRangeCallable.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/callable/GetTableMetaCallable.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/model/OTSColumn.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/model/OTSConf.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/model/OTSConst.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/model/OTSPrimaryKeyColumn.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/model/OTSRange.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/Common.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/DefaultNoRetry.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/GsonParser.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/ParamChecker.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/RangeSplit.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/ReaderModelParser.java create mode 100644 otsreader/src/main/java/com/alibaba/datax/plugin/reader/otsreader/utils/RetryHelper.java create mode 100644 otsreader/src/main/resources/plugin.json create mode 100644 otsreader/src/main/resources/plugin_job_template.json create mode 100644 otswriter/doc/otswriter.md create mode 100644 otswriter/otswriter.iml create mode 100644 otswriter/pom.xml create mode 100644 otswriter/src/main/assembly/package.xml create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/Key.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/OtsWriter.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/OtsWriterError.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/OtsWriterMasterProxy.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/OtsWriterSlaveProxy.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/callable/BatchWriteRowCallable.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/callable/GetTableMetaCallable.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/callable/PutRowChangeCallable.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/callable/UpdateRowChangeCallable.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/LogExceptionManager.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSAttrColumn.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSBatchWriteRowTaskManager.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSBatchWriterRowTask.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSBlockingExecutor.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSConf.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSConst.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSErrorMessage.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSLine.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSOpType.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSPKColumn.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSRowPrimaryKey.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/OTSSendBuffer.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/model/Pair.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/ColumnConversion.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/Common.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/DefaultNoRetry.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/GsonParser.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/ParamChecker.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/RetryHelper.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/SizeCalculateHelper.java create mode 100644 otswriter/src/main/java/com/alibaba/datax/plugin/writer/otswriter/utils/WriterModelParser.java create mode 100644 otswriter/src/main/resources/plugin.json create mode 100644 otswriter/src/main/resources/plugin_job_template.json create mode 100755 package.xml create mode 100644 plugin-rdbms-util/plugin-rdbms-util.iml create mode 100755 plugin-rdbms-util/pom.xml create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/CommonRdbmsReader.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/Constant.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/Key.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/ResultSetReadProxy.java create mode 100644 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/util/HintUtil.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/util/OriginalConfPretreatmentUtil.java create mode 100644 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/util/PreCheckTask.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/util/ReaderSplitUtil.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/reader/util/SingleTableSplitUtil.java create mode 100644 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/ConnectionFactory.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/Constant.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DBUtil.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DBUtilErrorCode.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DataBaseType.java create mode 100644 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/JdbcConnectionFactory.java create mode 100644 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/RdbmsException.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/RdbmsRangeSplitWrap.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/TableExpandUtil.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/CommonRdbmsWriter.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/Constant.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/Key.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/MysqlWriterErrorCode.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/util/OriginalConfPretreatmentUtil.java create mode 100755 plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/writer/util/WriterUtil.java create mode 100644 plugin-unstructured-storage-util/plugin-unstructured-storage-util.iml create mode 100755 plugin-unstructured-storage-util/pom.xml create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/reader/Constant.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/reader/Key.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/reader/UnstructuredStorageReaderErrorCode.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/reader/UnstructuredStorageReaderUtil.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/writer/Constant.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/writer/Key.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/writer/UnstructuredStorageWriterErrorCode.java create mode 100755 plugin-unstructured-storage-util/src/main/java/com/alibaba/datax/plugin/unstructuredstorage/writer/UnstructuredStorageWriterUtil.java create mode 100755 pom.xml create mode 100644 postgresqlreader/doc/postgresqlreader.md create mode 100755 postgresqlreader/pom.xml create mode 100644 postgresqlreader/postgresqlreader.iml create mode 100755 postgresqlreader/src/main/assembly/package.xml create mode 100755 postgresqlreader/src/main/java/com/alibaba/datax/plugin/reader/postgresqlreader/Constant.java create mode 100755 postgresqlreader/src/main/java/com/alibaba/datax/plugin/reader/postgresqlreader/PostgresqlReader.java create mode 100755 postgresqlreader/src/main/resources/plugin.json create mode 100644 postgresqlreader/src/main/resources/plugin_job_template.json create mode 100644 postgresqlwriter/doc/postgresqlwriter.md create mode 100755 postgresqlwriter/pom.xml create mode 100644 postgresqlwriter/postgresqlwriter.iml create mode 100755 postgresqlwriter/src/main/assembly/package.xml create mode 100755 postgresqlwriter/src/main/java/com/alibaba/datax/plugin/writer/postgresqlwriter/PostgresqlWriter.java create mode 100755 postgresqlwriter/src/main/resources/plugin.json create mode 100644 postgresqlwriter/src/main/resources/plugin_job_template.json create mode 100644 sqlserverreader/doc/sqlserverreader.md create mode 100755 sqlserverreader/pom.xml create mode 100644 sqlserverreader/sqlserverreader.iml create mode 100755 sqlserverreader/src/main/assembly/package.xml create mode 100755 sqlserverreader/src/main/java/com/alibaba/datax/plugin/reader/sqlserverreader/Constant.java create mode 100755 sqlserverreader/src/main/java/com/alibaba/datax/plugin/reader/sqlserverreader/Key.java create mode 100755 sqlserverreader/src/main/java/com/alibaba/datax/plugin/reader/sqlserverreader/SqlServerReader.java create mode 100755 sqlserverreader/src/main/java/com/alibaba/datax/plugin/reader/sqlserverreader/SqlServerReaderErrorCode.java create mode 100644 sqlserverreader/src/main/lib/sqljdbc4-4.0.jar create mode 100755 sqlserverreader/src/main/resources/plugin.json create mode 100644 sqlserverreader/src/main/resources/plugin_job_template.json create mode 100644 sqlserverwriter/doc/sqlserverwriter.md create mode 100644 sqlserverwriter/pom.xml create mode 100644 sqlserverwriter/sqlserverwriter.iml create mode 100755 sqlserverwriter/src/main/assembly/package.xml create mode 100644 sqlserverwriter/src/main/java/com/alibaba/datax/plugin/writer/sqlserverwriter/SqlServerWriter.java create mode 100644 sqlserverwriter/src/main/java/com/alibaba/datax/plugin/writer/sqlserverwriter/SqlServerWriterErrorCode.java create mode 100644 sqlserverwriter/src/main/lib/sqljdbc4-4.0.jar create mode 100755 sqlserverwriter/src/main/resources/plugin.json create mode 100644 sqlserverwriter/src/main/resources/plugin_job_template.json create mode 100755 streamreader/pom.xml create mode 100755 streamreader/src/main/assembly/package.xml create mode 100755 streamreader/src/main/java/com/alibaba/datax/plugin/reader/streamreader/Constant.java create mode 100755 streamreader/src/main/java/com/alibaba/datax/plugin/reader/streamreader/Key.java create mode 100755 streamreader/src/main/java/com/alibaba/datax/plugin/reader/streamreader/StreamReader.java create mode 100755 streamreader/src/main/java/com/alibaba/datax/plugin/reader/streamreader/StreamReaderErrorCode.java create mode 100755 streamreader/src/main/resources/plugin.json create mode 100644 streamreader/src/main/resources/plugin_job_template.json create mode 100644 streamreader/streamreader.iml create mode 100755 streamwriter/pom.xml create mode 100755 streamwriter/src/main/assembly/package.xml create mode 100755 streamwriter/src/main/java/com/alibaba/datax/plugin/writer/streamwriter/Key.java create mode 100755 streamwriter/src/main/java/com/alibaba/datax/plugin/writer/streamwriter/StreamWriter.java create mode 100755 streamwriter/src/main/java/com/alibaba/datax/plugin/writer/streamwriter/StreamWriterErrorCode.java create mode 100755 streamwriter/src/main/resources/plugin.json create mode 100644 streamwriter/src/main/resources/plugin_job_template.json create mode 100644 streamwriter/streamwriter.iml create mode 100644 txtfilereader/doc/txtfielreader.md create mode 100755 txtfilereader/pom.xml create mode 100755 txtfilereader/src/main/assembly/package.xml create mode 100755 txtfilereader/src/main/java/com/alibaba/datax/plugin/reader/txtfilereader/Constant.java create mode 100755 txtfilereader/src/main/java/com/alibaba/datax/plugin/reader/txtfilereader/Key.java create mode 100755 txtfilereader/src/main/java/com/alibaba/datax/plugin/reader/txtfilereader/TxtFileReader.java create mode 100755 txtfilereader/src/main/java/com/alibaba/datax/plugin/reader/txtfilereader/TxtFileReaderErrorCode.java create mode 100755 txtfilereader/src/main/resources/plugin.json create mode 100644 txtfilereader/src/main/resources/plugin_job_template.json create mode 100644 txtfilereader/txtfilereader.iml create mode 100644 txtfilewriter/doc/txtfilewriter.md create mode 100755 txtfilewriter/pom.xml create mode 100755 txtfilewriter/src/main/assembly/package.xml create mode 100755 txtfilewriter/src/main/java/com/alibaba/datax/plugin/writer/txtfilewriter/Key.java create mode 100755 txtfilewriter/src/main/java/com/alibaba/datax/plugin/writer/txtfilewriter/TxtFileWriter.java create mode 100755 txtfilewriter/src/main/java/com/alibaba/datax/plugin/writer/txtfilewriter/TxtFileWriterErrorCode.java create mode 100755 txtfilewriter/src/main/resources/plugin.json create mode 100644 txtfilewriter/src/main/resources/plugin_job_template.json create mode 100644 txtfilewriter/txtfilewriter.iml create mode 100644 userGuid.md diff --git a/README b/README new file mode 100755 index 000000000..e69de29bb diff --git a/README.md b/README.md index e6cde27b5..e5b5dd41f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,101 @@ # DataX + DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、SqlServer、Postgre、HDFS、Hive、ADS、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。 -代码近期会上传,敬请期待。 + + + +# Features + +DataX本身作为数据同步框架,将不同数据源的同步抽象为从源头数据源读取数据的Reader插件,以及向目标端写入数据的Writer插件,理论上DataX框架可以支持任意数据源类型的数据同步工作。同时DataX插件体系作为一套生态系统, 每接入一套新数据源该新加入的数据源即可实现和现有的数据源互通。 + + + +# DataX详细介绍 + +请参考: + +# System Requirements + +- Linux +- [JDK(1.6以上,推荐1.6) ](http://www.oracle.com/technetwork/cn/java/javase/downloads/index.html) +- [Python(推荐Python2.6.X) ](https://www.python.org/downloads/) +- [Apache Maven 3.x](https://maven.apache.org/download.cgi) (Compile DataX) + +# Quick Start + +请点击:[Quick Start](https://github.com/alibaba/DataX/wiki/Quick-Start) + +# Support Data Channels + +目前DataX支持的数据源有: + +### Reader + +> **Reader实现了从数据存储系统批量抽取数据,并转换为DataX标准数据交换协议,DataX任意Reader能与DataX任意Writer实现无缝对接,达到任意异构数据互通之目的。** + +**RDBMS 关系型数据库** + +- [MysqlReader](https://github.com/alibaba/DataX/blob/master/mysqlreader/doc/mysqlreader.md): 使用JDBC批量抽取Mysql数据集。 +- [OracleReader](https://github.com/alibaba/DataX/blob/master/oraclereader/doc/oraclereader.md): 使用JDBC批量抽取Oracle数据集。 +- [SqlServerReader](https://github.com/alibaba/DataX/blob/master/sqlserverreader/doc/sqlserverreader.md): 使用JDBC批量抽取SqlServer数据集 +- [PostgresqlReader](https://github.com/alibaba/DataX/blob/master/postgresqlreader/doc/postgresqlreader.md): 使用JDBC批量抽取PostgreSQL数据集 +- [DrdsReader](https://github.com/alibaba/DataX/blob/master/drdsreader/doc/drdsreader.md): 针对公有云上DRDS的批量数据抽取工具。 + +**数仓数据存储** + +- [ODPSReader](https://github.com/alibaba/DataX/blob/master/odpsreader/doc/odpsreader.md): 使用ODPS Tunnel SDK批量抽取ODPS数据。 + +**NoSQL数据存储** + +- [OTSReader](https://github.com/alibaba/DataX/blob/master/otsreader/doc/otsreader.md): 针对公有云上OTS的批量数据抽取工具。 +- [HBaseReader](https://github.com/alibaba/DataX/blob/master/hbasereader/doc/hbasereader.md): 针对 HBase 0.94版本的在线数据抽取工具 +- [MongoDBReader](https://github.com/alibaba/DataX/blob/master/mongodbreader/doc/mongodbreader.md):MongoDBReader + +**无结构化数据存储** + +- [TxtFileReader](https://github.com/alibaba/DataX/blob/master/txtfilereader/doc/txtfilereader.md): 读取(递归/过滤)本地文件。 +- [FtpReader](https://github.com/alibaba/DataX/blob/master/ftpreader/doc/ftpreader.md): 读取(递归/过滤)远程ftp文件。 +- [HdfsReader](https://github.com/alibaba/DataX/blob/master/hdfsreader/doc/hdfsreader.md): 针对Hdfs文件系统中textfile和orcfile文件批量数据抽取工具。 +- [OssReader](https://github.com/alibaba/DataX/blob/master/ossreader/doc/ossreader.md): 针对公有云OSS产品的批量数据抽取工具。 +- StreamReader + +### Writer + +------ + +> **Writer实现了从DataX标准数据交换协议,翻译为具体的数据存储类型并写入目的数据存储。DataX任意Writer能与DataX任意Reader实现无缝对接,达到任意异构数据互通之目的。** + +------ + +**RDBMS 关系型数据库** + +- [MysqlWriter](https://github.com/alibaba/DataX/blob/master/mysqlwriter/doc/mysqlwriter.md): 使用JDBC(Insert,Replace方式)写入Mysql数据库 +- [OracleWriter](https://github.com/alibaba/DataX/blob/master/oraclewriter/doc/oraclewriter.md): 使用JDBC(Insert方式)写入Oracle数据库 +- [PostgresqlWriter](https://github.com/alibaba/DataX/blob/master/postgresqlwriter/doc/postgresqlwriter.md): 使用JDBC(Insert方式)写入PostgreSQL数据库 +- [SqlServerWriter](https://github.com/alibaba/DataX/blob/master/sqlserverwriter/doc/sqlserverwriter.md): 使用JDBC(Insert方式)写入sqlserver数据库 +- [DrdsWriter](https://github.com/alibaba/DataX/blob/master/drdswriter/doc/drdswriter.md): 使用JDBC(Replace方式)写入Drds数据库 + +**数仓数据存储** + +- [ODPSWriter](https://github.com/alibaba/DataX/blob/master/odpswriter/doc/odpswriter.md): 使用ODPS Tunnel SDK向ODPS写入数据。 +- [ADSWriter](https://github.com/alibaba/DataX/blob/master/adswriter/doc/adswriter.md): 使用ODPS中转将数据导入ADS。 + +**NoSQL数据存储** + +- [OTSWriter](https://github.com/alibaba/DataX/blob/master/otswriter/doc/otswriter.md): 使用OTS SDK向OTS Public模型的表中导入数据。 +- [OCSWriter](https://github.com/alibaba/DataX/blob/master/ocswriter/doc/ocswriter.md) +- [MongoDBWriter](https://github.com/alibaba/DataX/blob/master/mongodbwriter/doc/mongodbwriter.md):MongoDBWriter + +**无结构化数据存储** + +- [TxtFileWriter](https://github.com/alibaba/DataX/blob/master/txtfilewriter/doc/txtfilewriter.md): 提供写入本地文件功能。 +- [OssWriter](https://github.com/alibaba/DataX/blob/master/osswriter/doc/osswriter.md): 使用OSS SDK写入OSS数据。 +- [HdfsWriter](https://github.com/alibaba/DataX/blob/master/hdfswriter/doc/hdfswriter.md): 提供向Hdfs文件系统中写入textfile文件和orcfile文件功能。 +- StreamWriter + + + +# Contact us + +请及时提出issue给我们。请前往:[DataxIssue](https://github.com/alibaba/DataX/issues) + diff --git a/adswriter/adswriter.iml b/adswriter/adswriter.iml new file mode 100644 index 000000000..7a7f2115e --- /dev/null +++ b/adswriter/adswriter.iml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/adswriter/doc/adswriter.md b/adswriter/doc/adswriter.md new file mode 100644 index 000000000..bdfdf8ded --- /dev/null +++ b/adswriter/doc/adswriter.md @@ -0,0 +1,298 @@ +# DataX ADS写入 + + +--- + + +## 1 快速介绍 + +
+ +欢迎ADS加入DataX生态圈!ADSWriter插件实现了其他数据源向ADS写入功能,现有DataX所有的数据源均可以无缝接入ADS,实现数据快速导入ADS。 + +ADS写入预计支持两种实现方式: + +* ADSWriter 支持向ODPS中转落地导入ADS方式,优点在于当数据量较大时(>1KW),可以以较快速度进行导入,缺点引入了ODPS作为落地中转,因此牵涉三方系统(DataX、ADS、ODPS)鉴权认证。 + +* ADSWriter 同时支持向ADS直接写入的方式,优点在于小批量数据写入能够较快完成(<1KW),缺点在于大数据导入较慢。 + + +注意: + +> 如果从ODPS导入数据到ADS,请用户提前在源ODPS的Project中授权ADS Build账号具有读取你源表ODPS的权限,同时,ODPS源表创建人和ADS写入属于同一个阿里云账号。 + +- + +> 如果从非ODPS导入数据到ADS,请用户提前在目的端ADS空间授权ADS Build账号具备Load data权限。 + +以上涉及ADS Build账号请联系ADS管理员提供。 + + +## 2 实现原理 + +ADS写入预计支持两种实现方式: + +### 2.1 Load模式 + +DataX 将数据导入ADS为当前导入任务分配的ADS项目表,随后DataX通知ADS完成数据加载。该类数据导入方式实际上是写ADS完成数据同步,由于ADS是分布式存储集群,因此该通道吞吐量较大,可以支持TB级别数据导入。 + +![中转导入](http://aligitlab.oss-cn-hangzhou-zmf.aliyuncs.com/uploads/cdp/cdp/f805dea46b/_____2015-04-10___12.06.21.png) + +1. CDP底层得到明文的 jdbc://host:port/dbname + username + password + table, 以此连接ADS, 执行show grants; 前置检查该用户是否有ADS中目标表的Load Data或者更高的权限。注意,此时ADSWriter使用用户填写的ADS用户名+密码信息完成登录鉴权工作。 + +2. 检查通过后,通过ADS中目标表的元数据反向生成ODPS DDL,在ODPS中间project中,以ADSWriter的账户建立ODPS表(非分区表,生命周期设为1-2Day), 并调用ODPSWriter把数据源的数据写入该ODPS表中。 + + 注意,这里需要使用中转ODPS的账号AK向中转ODPS写入数据。 + +3. 写入完成后,以中转ODPS账号连接ADS,发起Load Data From ‘odps://中转project/中转table/' [overwrite] into adsdb.adstable [partition (xx,xx=xx)]; 这个命令返回一个Job ID需要记录。 + + 注意,此时ADS使用自己的Build账号访问中转ODPS,因此需要中转ODPS对这个Build账号提前开放读取权限。 + +4. 连接ADS一分钟一次轮询执行 select state from information_schema.job_instances where job_id like ‘$Job ID’,查询状态,注意这个第一个一分钟可能查不到状态记录。 + +5. Success或者Fail后返回给用户,然后删除中转ODPS表,任务结束。 + +上述流程是从其他非ODPS数据源导入ADS流程,对于ODPS导入ADS流程使用如下流程: + +![直接导入](http://aligitlab.oss-cn-hangzhou-zmf.aliyuncs.com/uploads/cdp/cdp/b3a76459d1/_____2015-04-10___12.06.25.png) + +### 2.2 Insert模式 + +DataX 将数据直连ADS接口,利用ADS暴露的INSERT接口直写到ADS。该类数据导入方式写入吞吐量较小,不适合大批量数据写入。有如下注意点: + +* ADSWriter使用JDBC连接直连ADS,并只使用了JDBC Statement进行数据插入。ADS不支持PreparedStatement,故ADSWriter只能单行多线程进行写入。 + +* ADSWriter支持筛选部分列,列换序等功能,即用户可以填写列。 + +* 考虑到ADS负载问题,建议ADSWriter Insert模式建议用户使用TPS限流,最高在1W TPS。 + +* ADSWriter在所有Task完成写入任务后,Job Post单例执行flush工作,保证数据在ADS整体更新。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 这里使用一份从内存产生到ADS,使用Load模式进行导入的数据。 + +``` +{ + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column": [ + { + "value": "DataX", + "type": "string" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 100000 + } + }, + "writer": { + "name": "adswriter", + "parameter": { + "odps": { + "accessId": "xasdfkladslfjsaifw224ysgsa5", + "accessKey": "asfjkljfp0w4624twfswe56346212341adsfa3", + "account": "xxx@aliyun.com", + "odpsServer": "http://service.odpsstg.aliyun-inc.com/stgnew", + "tunnelServer": "http://tunnel.odpsstg.aliyun-inc.com/", + "accountType": "aliyun", + "project": "transfer_project" + }, + "writeMode": "load", + "url": "127.0.0.1:3306", + "schema": "schema", + "table": "table", + "username": "username", + "password": "password", + "partition": "", + "lifeCycle": 2, + "overWrite": true, + } + } + } + ] + } +} +``` + +* 这里使用一份从内存产生到ADS,使用Insert模式进行导入的数据。 + +``` +{ + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column": [ + { + "value": "DataX", + "type": "string" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 100000 + } + }, + "writer": { + "name": "adswriter", + "parameter": { + "writeMode": "insert", + "url": "127.0.0.1:3306", + "schema": "schema", + "table": "table", + "column": ["*"], + "username": "username", + "password": "password", + "partition": "id,ds=2015" + } + } + } + ] + } +} +``` + + + +### 3.2 参数说明 (用户配置规格) + +* **url** + + * 描述:ADS连接信息,格式为"ip:port"。 + + * 必选:是
+ + * 默认值:无
+ +* **schema** + + * 描述:ADS的schema名称。 + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:ADS对应的username,目前就是accessId
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:ADS对应的password,目前就是accessKey
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:目的表的表名称。 + + * 必选:是
+ + * 默认值:无
+ + +* **partition** + + * 描述:目标表的分区名称,当目标表为分区表,需要指定该字段。 + + * 必选:否
+ + * 默认值:无
+ +* **writeMode** + + * 描述:支持Load和Insert两种写入模式 + + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:目的表字段列表,可以为["*"],或者具体的字段列表,例如["a", "b", "c"] + + * 必选:是
+ + * 默认值:无
+ +* **overWrite** + + * 描述:ADS写入是否覆盖当前写入的表,true为覆盖写入,false为不覆盖(追加)写入。当writeMode为Load,该值才会生效。 + + * 必选:是
+ + * 默认值:无
+ + +* **lifeCycle** + + * 描述:ADS 临时表生命周期。当writeMode为Load时,该值才会生效。 + + * 必选:是
+ + * 默认值:无
+ + +### 3.3 类型转换 + +| DataX 内部类型| ADS 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, int, bigint| +| Double |float, double, decimal| +| String |varchar | +| Date |date | +| Boolean |bool | +| Bytes |无 | + + 注意: + +* multivalue ADS支持multivalue类型,DataX对于该类型支持待定? + + +## 4 插件约束 + +如果Reader为ODPS,且ADSWriter写入模式为Load模式时,ODPS的partition只支持如下三种配置方式(以两级分区为例): +``` +"partition":["pt=*,ds=*"] (读取test表所有分区的数据) +"partition":["pt=1,ds=*"] (读取test表下面,一级分区pt=1下面的所有二级分区) +"partition":["pt=1,ds=hangzhou"] (读取test表下面,一级分区pt=1下面,二级分区ds=hz的数据) +``` + +## 5 性能报告(线上环境实测) + +### 5.1 环境准备 + +### 5.2 测试报告 + +## 6 FAQ diff --git a/adswriter/pom.xml b/adswriter/pom.xml new file mode 100644 index 000000000..5e6a12849 --- /dev/null +++ b/adswriter/pom.xml @@ -0,0 +1,113 @@ + + + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + 4.0.0 + + adswriter + adswriter + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + com.alibaba.datax + datax-core + ${datax-project-version} + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + + org.slf4j + slf4j-api + + + org.apache.commons + commons-exec + 1.3 + + + com.alibaba.datax + odpswriter + ${datax-project-version} + + + ch.qos.logback + logback-classic + + + mysql + mysql-connector-java + 5.1.26 + + + commons-configuration + commons-configuration + 1.9 + + + commons-configuration + commons-configuration + 1.10 + + + commons-configuration + commons-configuration + 1.10 + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/adswriter/src/main/assembly/package.xml b/adswriter/src/main/assembly/package.xml new file mode 100644 index 000000000..c1fb64bb8 --- /dev/null +++ b/adswriter/src/main/assembly/package.xml @@ -0,0 +1,36 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + config.properties + plugin_job_template.json + + plugin/writer/adswriter + + + target/ + + adswriter-0.0.1-SNAPSHOT.jar + + plugin/writer/adswriter + + + + + + false + plugin/writer/adswriter/libs + runtime + + + diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsException.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsException.java new file mode 100644 index 000000000..f0d6f9289 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsException.java @@ -0,0 +1,40 @@ +package com.alibaba.datax.plugin.writer.adswriter; + +public class AdsException extends Exception { + + private static final long serialVersionUID = 1080618043484079794L; + + public final static int ADS_CONN_URL_NOT_SET = -100; + public final static int ADS_CONN_USERNAME_NOT_SET = -101; + public final static int ADS_CONN_PASSWORD_NOT_SET = -102; + public final static int ADS_CONN_SCHEMA_NOT_SET = -103; + + public final static int JOB_NOT_EXIST = -200; + public final static int JOB_FAILED = -201; + + public final static int ADS_LOADDATA_SCHEMA_NULL = -300; + public final static int ADS_LOADDATA_TABLE_NULL = -301; + public final static int ADS_LOADDATA_SOURCEPATH_NULL = -302; + public final static int ADS_LOADDATA_JOBID_NOT_AVAIL = -303; + public final static int ADS_LOADDATA_FAILED = -304; + + public final static int ADS_TABLEMETA_SCHEMA_NULL = -404; + public final static int ADS_TABLEMETA_TABLE_NULL = -405; + + public final static int OTHER = -999; + + private int code = OTHER; + private String message; + + public AdsException(int code, String message, Throwable e) { + super(message, e); + this.code = code; + this.message = message; + } + + @Override + public String getMessage() { + return "Code=" + this.code + " Message=" + this.message; + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriter.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriter.java new file mode 100644 index 000000000..f44a6b18b --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriter.java @@ -0,0 +1,328 @@ +package com.alibaba.datax.plugin.writer.adswriter; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.writer.adswriter.ads.TableInfo; +import com.alibaba.datax.plugin.writer.adswriter.insert.AdsInsertProxy; +import com.alibaba.datax.plugin.writer.adswriter.insert.AdsInsertUtil; +import com.alibaba.datax.plugin.writer.adswriter.load.AdsHelper; +import com.alibaba.datax.plugin.writer.adswriter.load.TableMetaHelper; +import com.alibaba.datax.plugin.writer.adswriter.load.TransferProjectConf; +import com.alibaba.datax.plugin.writer.adswriter.odps.TableMeta; +import com.alibaba.datax.plugin.writer.adswriter.util.AdsUtil; +import com.alibaba.datax.plugin.writer.adswriter.util.Constant; +import com.alibaba.datax.plugin.writer.adswriter.util.Key; +import com.alibaba.datax.plugin.writer.odpswriter.OdpsWriter; +import com.aliyun.odps.Instance; +import com.aliyun.odps.Odps; +import com.aliyun.odps.OdpsException; +import com.aliyun.odps.account.Account; +import com.aliyun.odps.account.AliyunAccount; +import com.aliyun.odps.task.SQLTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AdsWriter extends Writer { + + public static class Job extends Writer.Job { + private static final Logger LOG = LoggerFactory.getLogger(Writer.Job.class); + public final static String ODPS_READER = "odpsreader"; + + private OdpsWriter.Job odpsWriterJobProxy = new OdpsWriter.Job(); + private Configuration originalConfig; + private Configuration readerConfig; + + /** + * 持有ads账号的ads helper + */ + private AdsHelper adsHelper; + /** + * 持有odps账号的ads helper + */ + private AdsHelper odpsAdsHelper; + /** + * 中转odps的配置,对应到writer配置的parameter.odps部分 + */ + private TransferProjectConf transProjConf; + private final int ODPSOVERTIME = 120000; + private String odpsTransTableName; + + private String writeMode; + private long startTime; + + @Override + public void init() { + startTime = System.currentTimeMillis(); + this.originalConfig = super.getPluginJobConf(); + this.writeMode = this.originalConfig.getString(Key.WRITE_MODE); + if(null == this.writeMode) { + LOG.warn("您未指定[writeMode]参数, 默认采用load模式, load模式只能用于离线表"); + this.writeMode = Constant.LOADMODE; + this.originalConfig.set(Key.WRITE_MODE, "load"); + } + + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + AdsUtil.checkNecessaryConfig(this.originalConfig, this.writeMode); + loadModeInit(); + } else if(Constant.INSERTMODE.equalsIgnoreCase(this.writeMode)) { + AdsUtil.checkNecessaryConfig(this.originalConfig, this.writeMode); + List allColumns = AdsInsertUtil.getAdsTableColumnNames(originalConfig); + AdsInsertUtil.dealColumnConf(originalConfig, allColumns); + + LOG.debug("After job init(), originalConfig now is:[\n{}\n]", + originalConfig.toJSON()); + } else { + throw DataXException.asDataXException(AdsWriterErrorCode.INVALID_CONFIG_VALUE, "writeMode 必须为 'load' 或者 'insert'"); + } + } + + private void loadModeInit() { + this.adsHelper = AdsUtil.createAdsHelper(this.originalConfig); + this.odpsAdsHelper = AdsUtil.createAdsHelperWithOdpsAccount(this.originalConfig); + this.transProjConf = TransferProjectConf.create(this.originalConfig); + + /** + * 如果是从odps导入到ads,直接load data然后System.exit() + */ + if (super.getPeerPluginName().equals(ODPS_READER)) { + transferFromOdpsAndExit(); + } + + + Account odpsAccount; + odpsAccount = new AliyunAccount(transProjConf.getAccessId(), transProjConf.getAccessKey()); + + Odps odps = new Odps(odpsAccount); + odps.setEndpoint(transProjConf.getOdpsServer()); + odps.setDefaultProject(transProjConf.getProject()); + + TableMeta tableMeta; + try { + String adsTable = this.originalConfig.getString(Key.ADS_TABLE); + TableInfo tableInfo = adsHelper.getTableInfo(adsTable); + int lifeCycle = this.originalConfig.getInt(Key.Life_CYCLE); + tableMeta = TableMetaHelper.createTempODPSTable(tableInfo, lifeCycle); + this.odpsTransTableName = tableMeta.getTableName(); + String sql = tableMeta.toDDL(); + LOG.info("正在创建ODPS临时表: "+sql); + Instance instance = SQLTask.run(odps, transProjConf.getProject(), sql, null, null); + boolean terminated = false; + int time = 0; + while (!terminated && time < ODPSOVERTIME) { + Thread.sleep(1000); + terminated = instance.isTerminated(); + time += 1000; + } + LOG.info("正在创建ODPS临时表成功"); + } catch (AdsException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_CREATETABLE_FAILED, e); + }catch (OdpsException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_CREATETABLE_FAILED,e); + } catch (InterruptedException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_CREATETABLE_FAILED,e); + } + + Configuration newConf = AdsUtil.generateConf(this.originalConfig, this.odpsTransTableName, + tableMeta, this.transProjConf); + odpsWriterJobProxy.setPluginJobConf(newConf); + odpsWriterJobProxy.init(); + } + + /** + * 当reader是odps的时候,直接call ads的load接口,完成后退出。 + * 这种情况下,用户在odps reader里头填写的参数只有部分有效。 + * 其中accessId、accessKey是忽略掉iao的。 + */ + private void transferFromOdpsAndExit() { + this.readerConfig = super.getPeerPluginJobConf(); + String odpsTableName = this.readerConfig.getString(Key.ODPSTABLENAME); + List userConfiguredPartitions = this.readerConfig.getList(Key.PARTITION, String.class); + + if (userConfiguredPartitions == null) { + userConfiguredPartitions = Collections.emptyList(); + } + + if(userConfiguredPartitions.size() > 1) + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_PARTITION_FAILED, ""); + + if(userConfiguredPartitions.size() == 0) { + loadAdsData(adsHelper, odpsTableName,null); + }else { + loadAdsData(adsHelper, odpsTableName,userConfiguredPartitions.get(0)); + } + System.exit(0); + } + + // 一般来说,是需要推迟到 task 中进行pre 的执行(单表情况例外) + @Override + public void prepare() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + //导数据到odps表中 + this.odpsWriterJobProxy.prepare(); + } else { + //todo 目前insert模式不支持presql + } + } + + @Override + public List split(int mandatoryNumber) { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + return this.odpsWriterJobProxy.split(mandatoryNumber); + } else { + List splitResult = new ArrayList(); + for(int i = 0; i < mandatoryNumber; i++) { + splitResult.add(this.originalConfig.clone()); + } + return splitResult; + } + } + + // 一般来说,是需要推迟到 task 中进行post 的执行(单表情况例外) + @Override + public void post() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + loadAdsData(odpsAdsHelper, this.odpsTransTableName, null); + this.odpsWriterJobProxy.post(); + } else { + //insert mode do noting + } + } + + @Override + public void destroy() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + this.odpsWriterJobProxy.destroy(); + } else { + //insert mode do noting + } + } + + private void loadAdsData(AdsHelper helper, String odpsTableName, String odpsPartition) { + + String table = this.originalConfig.getString(Key.ADS_TABLE); + String project; + if (super.getPeerPluginName().equals(ODPS_READER)) { + project = this.readerConfig.getString(Key.PROJECT); + } else { + project = this.transProjConf.getProject(); + } + String partition = this.originalConfig.getString(Key.PARTITION); + String sourcePath = AdsUtil.generateSourcePath(project,odpsTableName,odpsPartition); + /** + * 因为之前检查过,所以不用担心unbox的时候NPE + */ + boolean overwrite = this.originalConfig.getBool(Key.OVER_WRITE); + try { + String id = helper.loadData(table,partition,sourcePath,overwrite); + LOG.info("ADS Load Data任务已经提交,job id: " + id); + boolean terminated = false; + int time = 0; + while(!terminated) { + Thread.sleep(120000); + terminated = helper.checkLoadDataJobStatus(id); + time += 2; + LOG.info("ADS 正在导数据中,整个过程需要20分钟以上,请耐心等待,目前已执行 "+ time+" 分钟"); + } + LOG.info("ADS 导数据已成功"); + } catch (AdsException e) { + if (super.getPeerPluginName().equals(ODPS_READER)) { + // TODO 使用云账号 + AdsWriterErrorCode.ADS_LOAD_ODPS_FAILED.setAdsAccount(helper.getUserName()); + throw DataXException.asDataXException(AdsWriterErrorCode.ADS_LOAD_ODPS_FAILED,e); + } else { + throw DataXException.asDataXException(AdsWriterErrorCode.ADS_LOAD_TEMP_ODPS_FAILED,e); + } + } catch (InterruptedException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_CREATETABLE_FAILED,e); + } + } + } + + public static class Task extends Writer.Task { + private Configuration writerSliceConfig; + private OdpsWriter.Task odpsWriterTaskProxy = new OdpsWriter.Task(); + + + private String writeMode; + private int columnNumber; + + @Override + public void init() { + writerSliceConfig = super.getPluginJobConf(); + this.writeMode = this.writerSliceConfig.getString(Key.WRITE_MODE); + + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + odpsWriterTaskProxy.setPluginJobConf(writerSliceConfig); + odpsWriterTaskProxy.init(); + } else if(Constant.INSERTMODE.equalsIgnoreCase(this.writeMode)) { + List allColumns = AdsInsertUtil.getAdsTableColumnNames(writerSliceConfig); + AdsInsertUtil.dealColumnConf(writerSliceConfig, allColumns); + List userColumns = writerSliceConfig.getList(Key.COLUMN, String.class); + this.columnNumber = userColumns.size(); + } else { + throw DataXException.asDataXException(AdsWriterErrorCode.INVALID_CONFIG_VALUE, "writeMode 必须为 'load' 或者 'insert'"); + } + + } + + @Override + public void prepare() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + odpsWriterTaskProxy.prepare(); + } else { + //do nothing + } + } + + //TODO 改用连接池,确保每次获取的连接都是可用的(注意:连接可能需要每次都初始化其 session) + public void startWrite(RecordReceiver recordReceiver) { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + odpsWriterTaskProxy.setTaskPluginCollector(super.getTaskPluginCollector()); + odpsWriterTaskProxy.startWrite(recordReceiver); + } else { + //todo insert 模式 + String username = writerSliceConfig.getString(Key.USERNAME); + String password = writerSliceConfig.getString(Key.PASSWORD); + String adsURL = writerSliceConfig.getString(Key.ADS_URL); + String schema = writerSliceConfig.getString(Key.SCHEMA); + String table = writerSliceConfig.getString(Key.ADS_TABLE); + List columns = writerSliceConfig.getList(Key.COLUMN, String.class); + String jdbcUrl = "jdbc:mysql://" + adsURL + "/" + schema + "?useUnicode=true&characterEncoding=UTF-8"; + Connection connection = DBUtil.getConnection(DataBaseType.ADS, + jdbcUrl, username, password); + TaskPluginCollector taskPluginCollector = super.getTaskPluginCollector(); + AdsInsertProxy proxy = new AdsInsertProxy(schema + "." + table, columns, writerSliceConfig, taskPluginCollector); + proxy.startWriteWithConnection(recordReceiver, connection, columnNumber); + } + } + + @Override + public void post() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + odpsWriterTaskProxy.post(); + } else { + //do noting until now + } + } + + @Override + public void destroy() { + if(Constant.LOADMODE.equalsIgnoreCase(this.writeMode)) { + odpsWriterTaskProxy.destroy(); + } else { + //do noting until now + } + } + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriterErrorCode.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriterErrorCode.java new file mode 100644 index 000000000..a1ac3c107 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/AdsWriterErrorCode.java @@ -0,0 +1,54 @@ +package com.alibaba.datax.plugin.writer.adswriter; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum AdsWriterErrorCode implements ErrorCode { + REQUIRED_VALUE("AdsWriter-00", "您缺失了必须填写的参数值."), + NO_ADS_TABLE("AdsWriter-01", "ADS表不存在."), + ODPS_CREATETABLE_FAILED("AdsWriter-02", "创建ODPS临时表失败,请联系ADS 技术支持"), + ADS_LOAD_TEMP_ODPS_FAILED("AdsWriter-03", "ADS从ODPS临时表导数据失败,请联系ADS 技术支持"), + TABLE_TRUNCATE_ERROR("AdsWriter-04", "清空 ODPS 目的表时出错."), + CREATE_ADS_HELPER_FAILED("AdsWriter-05", "创建ADSHelper对象出错,请联系ADS 技术支持"), + ODPS_PARTITION_FAILED("AdsWriter-06", "ODPS Reader不允许配置多个partition,目前只支持三种配置方式,\"partition\":[\"pt=*,ds=*\"](读取test表所有分区的数据); \n" + + "\"partition\":[\"pt=1,ds=*\"](读取test表下面,一级分区pt=1下面的所有二级分区); \n" + + "\"partition\":[\"pt=1,ds=hangzhou\"](读取test表下面,一级分区pt=1下面,二级分区ds=hz的数据)"), + ADS_LOAD_ODPS_FAILED("AdsWriter-07", "ADS从ODPS导数据失败,请联系ADS 技术支持,先检查ADS账号是否已加到该ODPS Project中。ADS账号为:"), + INVALID_CONFIG_VALUE("AdsWriter-08", "不合法的配置值."), + + GET_ADS_TABLE_MEATA_FAILED("AdsWriter-11", "获取ADS table原信息失败"); + + private final String code; + private final String description; + private String adsAccount; + + + private AdsWriterErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + public void setAdsAccount(String adsAccount) { + this.adsAccount = adsAccount; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + if (this.code.equals("AdsWriter-07")){ + return String.format("Code:[%s], Description:[%s][%s]. ", this.code, + this.description,adsAccount); + }else{ + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } + } +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnDataType.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnDataType.java new file mode 100644 index 000000000..9062d0fd7 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnDataType.java @@ -0,0 +1,414 @@ +package com.alibaba.datax.plugin.writer.adswriter.ads; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * ADS column data type. + * + * @since 0.0.1 + */ +public class ColumnDataType { + + // public static final int NULL = 0; + public static final int BOOLEAN = 1; + public static final int BYTE = 2; + public static final int SHORT = 3; + public static final int INT = 4; + public static final int LONG = 5; + public static final int DECIMAL = 6; + public static final int DOUBLE = 7; + public static final int FLOAT = 8; + public static final int TIME = 9; + public static final int DATE = 10; + public static final int TIMESTAMP = 11; + public static final int STRING = 13; + // public static final int STRING_IGNORECASE = 14; + // public static final int STRING_FIXED = 21; + + public static final int MULTI_VALUE = 22; + + public static final int TYPE_COUNT = MULTI_VALUE + 1; + + /** + * The list of types. An ArrayList so that Tomcat doesn't set it to null when clearing references. + */ + private static final ArrayList TYPES = new ArrayList(); + private static final HashMap TYPES_BY_NAME = new HashMap(); + private static final ArrayList TYPES_BY_VALUE_TYPE = new ArrayList(); + + /** + * @param dataTypes + * @return + */ + public static String getNames(int[] dataTypes) { + List names = new ArrayList(dataTypes.length); + for (final int dataType : dataTypes) { + names.add(ColumnDataType.getDataType(dataType).name); + } + return names.toString(); + } + + public int type; + public String name; + public int sqlType; + public String jdbc; + + /** + * How closely the data type maps to the corresponding JDBC SQL type (low is best). + */ + public int sqlTypePos; + + static { + for (int i = 0; i < TYPE_COUNT; i++) { + TYPES_BY_VALUE_TYPE.add(null); + } + // add(NULL, Types.NULL, "Null", new String[] { "NULL" }); + add(STRING, Types.VARCHAR, "String", new String[] { "VARCHAR", "VARCHAR2", "NVARCHAR", "NVARCHAR2", + "VARCHAR_CASESENSITIVE", "CHARACTER VARYING", "TID" }); + add(STRING, Types.LONGVARCHAR, "String", new String[] { "LONGVARCHAR", "LONGNVARCHAR" }); + // add(STRING_FIXED, Types.CHAR, "String", new String[] { "CHAR", "CHARACTER", "NCHAR" }); + // add(STRING_IGNORECASE, Types.VARCHAR, "String", new String[] { "VARCHAR_IGNORECASE" }); + add(BOOLEAN, Types.BOOLEAN, "Boolean", new String[] { "BOOLEAN", "BIT", "BOOL" }); + add(BYTE, Types.TINYINT, "Byte", new String[] { "TINYINT" }); + add(SHORT, Types.SMALLINT, "Short", new String[] { "SMALLINT", "YEAR", "INT2" }); + add(INT, Types.INTEGER, "Int", new String[] { "INTEGER", "INT", "MEDIUMINT", "INT4", "SIGNED" }); + add(INT, Types.INTEGER, "Int", new String[] { "SERIAL" }); + add(LONG, Types.BIGINT, "Long", new String[] { "BIGINT", "INT8", "LONG" }); + add(LONG, Types.BIGINT, "Long", new String[] { "IDENTITY", "BIGSERIAL" }); + add(DECIMAL, Types.DECIMAL, "BigDecimal", new String[] { "DECIMAL", "DEC" }); + add(DECIMAL, Types.NUMERIC, "BigDecimal", new String[] { "NUMERIC", "NUMBER" }); + add(FLOAT, Types.REAL, "Float", new String[] { "REAL", "FLOAT4" }); + add(DOUBLE, Types.DOUBLE, "Double", new String[] { "DOUBLE", "DOUBLE PRECISION" }); + add(DOUBLE, Types.FLOAT, "Double", new String[] { "FLOAT", "FLOAT8" }); + add(TIME, Types.TIME, "Time", new String[] { "TIME" }); + add(DATE, Types.DATE, "Date", new String[] { "DATE" }); + add(TIMESTAMP, Types.TIMESTAMP, "Timestamp", new String[] { "TIMESTAMP", "DATETIME", "SMALLDATETIME" }); + add(MULTI_VALUE, Types.VARCHAR, "String", new String[] { "MULTIVALUE" }); + } + + private static void add(int type, int sqlType, String jdbc, String[] names) { + for (int i = 0; i < names.length; i++) { + ColumnDataType dt = new ColumnDataType(); + dt.type = type; + dt.sqlType = sqlType; + dt.jdbc = jdbc; + dt.name = names[i]; + for (ColumnDataType t2 : TYPES) { + if (t2.sqlType == dt.sqlType) { + dt.sqlTypePos++; + } + } + TYPES_BY_NAME.put(dt.name, dt); + if (TYPES_BY_VALUE_TYPE.get(type) == null) { + TYPES_BY_VALUE_TYPE.set(type, dt); + } + TYPES.add(dt); + } + } + +// /** +// * Get the list of ads data types. +// * +// * @return the ads data types +// */ +// public static ArrayList getTypes() { +// return TYPES; +// } + +// /** +// * Get the name of the Java class for the given value type. +// * +// * @param type the value type +// * @return the class name +// */ +// public static String getTypeClassName(int type) { +// switch (type) { +// case BOOLEAN: +// // "java.lang.Boolean"; +// return Boolean.class.getName(); +// case BYTE: +// // "java.lang.Byte"; +// return Byte.class.getName(); +// case SHORT: +// // "java.lang.Short"; +// return Short.class.getName(); +// case INT: +// // "java.lang.Integer"; +// return Integer.class.getName(); +// case LONG: +// // "java.lang.Long"; +// return Long.class.getName(); +// case DECIMAL: +// // "java.math.BigDecimal"; +// return BigDecimal.class.getName(); +// case TIME: +// // "java.sql.Time"; +// return Time.class.getName(); +// case DATE: +// // "java.sql.Date"; +// return Date.class.getName(); +// case TIMESTAMP: +// // "java.sql.Timestamp"; +// return Timestamp.class.getName(); +// case STRING: +// // case STRING_IGNORECASE: +// // case STRING_FIXED: +// case MULTI_VALUE: +// // "java.lang.String"; +// return String.class.getName(); +// case DOUBLE: +// // "java.lang.Double"; +// return Double.class.getName(); +// case FLOAT: +// // "java.lang.Float"; +// return Float.class.getName(); +// // case NULL: +// // return null; +// default: +// throw new IllegalArgumentException("type=" + type); +// } +// } + + /** + * Get the data type object for the given value type. + * + * @param type the value type + * @return the data type object + */ + public static ColumnDataType getDataType(int type) { + if (type < 0 || type >= TYPE_COUNT) { + throw new IllegalArgumentException("type=" + type); + } + ColumnDataType dt = TYPES_BY_VALUE_TYPE.get(type); + // if (dt == null) { + // dt = TYPES_BY_VALUE_TYPE.get(NULL); + // } + return dt; + } + + /** + * Convert a value type to a SQL type. + * + * @param type the value type + * @return the SQL type + */ + public static int convertTypeToSQLType(int type) { + return getDataType(type).sqlType; + } + + /** + * Convert a SQL type to a value type. + * + * @param sqlType the SQL type + * @return the value type + */ + public static int convertSQLTypeToValueType(int sqlType) { + switch (sqlType) { + // case Types.CHAR: + // case Types.NCHAR: + // return STRING_FIXED; + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.NVARCHAR: + case Types.LONGNVARCHAR: + return STRING; + case Types.NUMERIC: + case Types.DECIMAL: + return DECIMAL; + case Types.BIT: + case Types.BOOLEAN: + return BOOLEAN; + case Types.INTEGER: + return INT; + case Types.SMALLINT: + return SHORT; + case Types.TINYINT: + return BYTE; + case Types.BIGINT: + return LONG; + case Types.REAL: + return FLOAT; + case Types.DOUBLE: + case Types.FLOAT: + return DOUBLE; + case Types.DATE: + return DATE; + case Types.TIME: + return TIME; + case Types.TIMESTAMP: + return TIMESTAMP; + // case Types.NULL: + // return NULL; + default: + throw new IllegalArgumentException("JDBC Type: " + sqlType); + } + } + + /** + * Get the value type for the given Java class. + * + * @param x the Java class + * @return the value type + */ + public static int getTypeFromClass(Class x) { + // if (x == null || Void.TYPE == x) { + // return NULL; + // } + if (x.isPrimitive()) { + x = getNonPrimitiveClass(x); + } + if (String.class == x) { + return STRING; + } else if (Integer.class == x) { + return INT; + } else if (Long.class == x) { + return LONG; + } else if (Boolean.class == x) { + return BOOLEAN; + } else if (Double.class == x) { + return DOUBLE; + } else if (Byte.class == x) { + return BYTE; + } else if (Short.class == x) { + return SHORT; + } else if (Float.class == x) { + return FLOAT; + // } else if (Void.class == x) { + // return NULL; + } else if (BigDecimal.class.isAssignableFrom(x)) { + return DECIMAL; + } else if (Date.class.isAssignableFrom(x)) { + return DATE; + } else if (Time.class.isAssignableFrom(x)) { + return TIME; + } else if (Timestamp.class.isAssignableFrom(x)) { + return TIMESTAMP; + } else if (java.util.Date.class.isAssignableFrom(x)) { + return TIMESTAMP; + } else { + throw new IllegalArgumentException("class=" + x); + } + } + + /** + * ads getNonPrimitiveClass + * @param clazz + * @return + */ + public static Class getNonPrimitiveClass(Class clazz) { + if (!clazz.isPrimitive()) { + return clazz; + } else if (clazz == boolean.class) { + // ads return "java.lang.Boolean"; + return Boolean.class; + } else if (clazz == char.class) { + // ads return "java.lang.Character"; + return Character.class; + } else if (clazz == byte.class) { + // ads return "java.lang.Byte"; + return Byte.class; + } else if (clazz == double.class) { + // ads return "java.lang.Double"; + return Double.class; + } else if (clazz == float.class) { + // ads return "java.lang.Float"; + return Float.class; + } else if (clazz == int.class) { + // ads return "java.lang.Integer"; + return Integer.class; + } else if (clazz == short.class) { + // ads return "java.lang.Short"; + return Short.class; + } else if (clazz == long.class) { + // ads return "java.lang.Long"; + return Long.class; + } else if (clazz == void.class) { + // ads return "java.lang.Void"; + return Void.class; + } + return clazz; + } + + /** + * Get a data type object from a type name. + * + * @param s the type name + * @return the data type object + */ + public static ColumnDataType getTypeByName(String s) { + return TYPES_BY_NAME.get(s); + } + + /** + * Check if the given value type is a String (VARCHAR,...). + * + * @param type the value type + * @return true if the value type is a String type + */ + public static boolean isStringType(int type) { + if (type == STRING /* || type == STRING_FIXED || type == STRING_IGNORECASE */ + || type == MULTI_VALUE) { + return true; + } + return false; + } + + /** + * @return + */ + public boolean supportsAdd() { + return supportsAdd(type); + } + + /** + * Check if the given value type supports the add operation. + * + * @param type the value type + * @return true if add is supported + */ + public static boolean supportsAdd(int type) { + switch (type) { + case BYTE: + case DECIMAL: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + return true; + default: + return false; + } + } + + /** + * Get the data type that will not overflow when calling 'add' 2 billion times. + * + * @param type the value type + * @return the data type that supports adding + */ + public static int getAddProofType(int type) { + switch (type) { + case BYTE: + return LONG; + case FLOAT: + return DOUBLE; + case INT: + return LONG; + case LONG: + return DECIMAL; + case SHORT: + return LONG; + default: + return type; + } + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnInfo.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnInfo.java new file mode 100644 index 000000000..030ce35d1 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/ColumnInfo.java @@ -0,0 +1,72 @@ +package com.alibaba.datax.plugin.writer.adswriter.ads; + +/** + * ADS column meta.
+ *

+ * select ordinal_position,column_name,data_type,type_name,column_comment
+ * from information_schema.columns
+ * where table_schema='db_name' and table_name='table_name'
+ * and is_deleted=0
+ * order by ordinal_position limit 1000
+ *

+ * + * @since 0.0.1 + */ +public class ColumnInfo { + + private int ordinal; + private String name; + private ColumnDataType dataType; + private boolean isDeleted; + private String comment; + + public int getOrdinal() { + return ordinal; + } + + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ColumnDataType getDataType() { + return dataType; + } + + public void setDataType(ColumnDataType dataType) { + this.dataType = dataType; + } + + public boolean isDeleted() { + return isDeleted; + } + + public void setDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ColumnInfo [ordinal=").append(ordinal).append(", name=").append(name).append(", dataType=") + .append(dataType).append(", isDeleted=").append(isDeleted).append(", comment=").append(comment) + .append("]"); + return builder.toString(); + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/TableInfo.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/TableInfo.java new file mode 100644 index 000000000..f2395d6b7 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/TableInfo.java @@ -0,0 +1,69 @@ +package com.alibaba.datax.plugin.writer.adswriter.ads; + +import java.util.List; + +/** + * ADS table meta.
+ *

+ * select table_schema, table_name,comments
+ * from information_schema.tables
+ * where table_schema='alimama' and table_name='click_af' limit 1
+ *

+ *

+ * select ordinal_position,column_name,data_type,type_name,column_comment
+ * from information_schema.columns
+ * where table_schema='db_name' and table_name='table_name'
+ * and is_deleted=0
+ * order by ordinal_position limit 1000
+ *

+ * + * @since 0.0.1 + */ +public class TableInfo { + + private String tableSchema; + private String tableName; + private List columns; + private String comments; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TableInfo [tableSchema=").append(tableSchema).append(", tableName=").append(tableName) + .append(", columns=").append(columns).append(", comments=").append(comments).append("]"); + return builder.toString(); + } + + public String getTableSchema() { + return tableSchema; + } + + public void setTableSchema(String tableSchema) { + this.tableSchema = tableSchema; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + } + + public String getComments() { + return comments; + } + + public void setComments(String comments) { + this.comments = comments; + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/package-info.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/package-info.java new file mode 100644 index 000000000..b396c49ff --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/ads/package-info.java @@ -0,0 +1,6 @@ +/** + * ADS meta and service. + * + * @since 0.0.1 + */ +package com.alibaba.datax.plugin.writer.adswriter.ads; \ No newline at end of file diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertProxy.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertProxy.java new file mode 100644 index 000000000..bd01a1553 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertProxy.java @@ -0,0 +1,286 @@ +package com.alibaba.datax.plugin.writer.adswriter.insert; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.writer.adswriter.util.Constant; +import com.alibaba.datax.plugin.writer.adswriter.util.Key; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + + +public class AdsInsertProxy { + + private static final Logger LOG = LoggerFactory + .getLogger(AdsInsertProxy.class); + + private String table; + private List columns; + private TaskPluginCollector taskPluginCollector; + private Configuration configuration; + private Boolean emptyAsNull; + + private Triple, List, List> resultSetMetaData; + + public AdsInsertProxy(String table, List columns, Configuration configuration, TaskPluginCollector taskPluginCollector) { + this.table = table; + this.columns = columns; + this.configuration = configuration; + this.taskPluginCollector = taskPluginCollector; + this.emptyAsNull = configuration.getBool(Key.EMPTY_AS_NULL, false); + } + + public void startWriteWithConnection(RecordReceiver recordReceiver, + Connection connection, + int columnNumber) { + //目前 ads 新建的表 如果未插入数据 不能通过select colums from table where 1=2,获取列信息。 +// this.resultSetMetaData = DBUtil.getColumnMetaData(connection, +// this.table, StringUtils.join(this.columns, ",")); + + this.resultSetMetaData = AdsInsertUtil.getColumnMetaData(configuration, columns); + + int batchSize = this.configuration.getInt(Key.BATCH_SIZE, Constant.DEFAULT_BATCH_SIZE); + List writeBuffer = new ArrayList(batchSize); + try { + Record record; + while ((record = recordReceiver.getFromReader()) != null) { + if (record.getColumnNumber() != columnNumber) { + // 源头读取字段列数与目的表字段写入列数不相等,直接报错 + throw DataXException + .asDataXException( + DBUtilErrorCode.CONF_ERROR, + String.format( + "列配置信息有错误. 因为您配置的任务中,源头读取字段数:%s 与 目的表要写入的字段数:%s 不相等. 请检查您的配置并作出修改.", + record.getColumnNumber(), + columnNumber)); + } + + writeBuffer.add(record); + + if (writeBuffer.size() >= batchSize) { + doOneInsert(connection, writeBuffer); + writeBuffer.clear(); + } + } + if (!writeBuffer.isEmpty()) { + doOneInsert(connection, writeBuffer); + writeBuffer.clear(); + } + } catch (Exception e) { + throw DataXException.asDataXException( + DBUtilErrorCode.WRITE_DATA_ERROR, e); + } finally { + writeBuffer.clear(); + DBUtil.closeDBResources(null, null, connection); + } + } + + protected void doBatchInsert(Connection connection, List buffer) throws SQLException { + Statement statement = null; + try { + connection.setAutoCommit(false); + statement = connection.createStatement(); + + for (Record record : buffer) { + String sql = generateInsertSql(record); + statement.addBatch(sql); + } + statement.executeBatch(); + connection.commit(); + } catch (SQLException e) { + LOG.warn("回滚此次写入, 采用每次写入一行方式提交. 因为:" + e.getMessage()); + connection.rollback(); + doOneInsert(connection, buffer); + } catch (Exception e) { + throw DataXException.asDataXException( + DBUtilErrorCode.WRITE_DATA_ERROR, e); + } finally { + DBUtil.closeDBResources(statement, null); + } + } + + protected void doOneInsert(Connection connection, List buffer) { + Statement statement = null; + String sql = null; + try { + connection.setAutoCommit(true); + statement = connection.createStatement(); + + for (Record record : buffer) { + try { + sql = generateInsertSql(record); + int status = statement.executeUpdate(sql); + sql = null; + } catch (SQLException e) { + LOG.error("sql: " + sql, e.getMessage()); + this.taskPluginCollector.collectDirtyRecord(record, e); + } + } + } catch (Exception e) { + LOG.error("插入异常, sql: " + sql); + throw DataXException.asDataXException( + DBUtilErrorCode.WRITE_DATA_ERROR, e); + } finally { + DBUtil.closeDBResources(statement, null); + } + } + + private String generateInsertSql(Record record) throws SQLException { + StringBuilder sqlSb = new StringBuilder("insert into " + this.table + "(" + + StringUtils.join(columns, ",") + ") values("); + for (int i = 0; i < columns.size(); i++) { + int columnSqltype = this.resultSetMetaData.getMiddle().get(i); + checkColumnType(columnSqltype, sqlSb, record.getColumn(i), i); + if((i+1) != columns.size()) { + sqlSb.append(","); + } + } + sqlSb.append(")"); + return sqlSb.toString(); + } + + private void checkColumnType(int columnSqltype, StringBuilder sqlSb, Column column, int columnIndex) throws SQLException { + java.util.Date utilDate; + switch (columnSqltype) { + case Types.CHAR: + case Types.NCHAR: + case Types.CLOB: + case Types.NCLOB: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.NVARCHAR: + case Types.LONGNVARCHAR: + String strValue = column.asString(); + if(null == strValue) { + sqlSb.append("null"); + } else { + String optStr = column.asString().replace("\\","\\\\"); + sqlSb.append("'").append(optStr).append("'"); + } + break; + + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.NUMERIC: + case Types.DECIMAL: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + String numValue = column.asString(); + if(emptyAsNull && "".equals(numValue) || numValue == null){ + sqlSb.append("null"); + } else{ + sqlSb.append(numValue); + } + break; + + //tinyint is a little special in some database like mysql {boolean->tinyint(1)} + case Types.TINYINT: + Long longValue = column.asLong(); + if (null == longValue) { + sqlSb.append("null"); + } else { + sqlSb.append(longValue); + } + break; + + case Types.DATE: + java.sql.Date sqlDate = null; + try { + if("".equals(column.getRawData())) { + utilDate = null; + } else { + utilDate = column.asDate(); + } + } catch (DataXException e) { + throw new SQLException(String.format( + "Date 类型转换错误:[%s]", column)); + } + + if (null != utilDate) { + sqlDate = new java.sql.Date(utilDate.getTime()); + sqlSb.append("'").append(sqlDate).append("'"); + } else { + sqlSb.append("null"); + } + break; + + case Types.TIME: + java.sql.Time sqlTime = null; + try { + if("".equals(column.getRawData())) { + utilDate = null; + } else { + utilDate = column.asDate(); + } + } catch (DataXException e) { + throw new SQLException(String.format( + "TIME 类型转换错误:[%s]", column)); + } + + if (null != utilDate) { + sqlTime = new java.sql.Time(utilDate.getTime()); + sqlSb.append("'").append(sqlTime).append("'"); + } else { + sqlSb.append("null"); + } + break; + + case Types.TIMESTAMP: + java.sql.Timestamp sqlTimestamp = null; + try { + if("".equals(column.getRawData())) { + utilDate = null; + } else { + utilDate = column.asDate(); + } + } catch (DataXException e) { + throw new SQLException(String.format( + "TIMESTAMP 类型转换错误:[%s]", column)); + } + + if (null != utilDate) { + sqlTimestamp = new java.sql.Timestamp( + utilDate.getTime()); + sqlSb.append("'").append(sqlTimestamp).append("'"); + } else { + sqlSb.append("null"); + } + break; + + case Types.BOOLEAN: + case Types.BIT: + String bitValue = column.asString(); + if(bitValue == null) { + sqlSb.append("null"); + } else { + sqlSb.append(bitValue); + } + break; + default: + throw DataXException + .asDataXException( + DBUtilErrorCode.UNSUPPORTED_TYPE, + String.format( + "您的配置文件中的列配置信息有误. 因为DataX 不支持数据库写入这种字段类型. 字段名:[%s], 字段类型:[%d], 字段Java类型:[%s]. 请修改表中该字段的类型或者不同步该字段.", + this.resultSetMetaData.getLeft() + .get(columnIndex), + this.resultSetMetaData.getMiddle() + .get(columnIndex), + this.resultSetMetaData.getRight() + .get(columnIndex))); + } + } +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertUtil.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertUtil.java new file mode 100644 index 000000000..11550b979 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/insert/AdsInsertUtil.java @@ -0,0 +1,134 @@ +package com.alibaba.datax.plugin.writer.adswriter.insert; + +import com.alibaba.datax.common.exception.DataXException; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.ListUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.writer.adswriter.AdsException; +import com.alibaba.datax.plugin.writer.adswriter.AdsWriterErrorCode; +import com.alibaba.datax.plugin.writer.adswriter.ads.ColumnInfo; +import com.alibaba.datax.plugin.writer.adswriter.ads.TableInfo; +import com.alibaba.datax.plugin.writer.adswriter.load.AdsHelper; +import com.alibaba.datax.plugin.writer.adswriter.util.Key; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + + +public class AdsInsertUtil { + + private static final Logger LOG = LoggerFactory + .getLogger(AdsInsertUtil.class); + + public Connection getAdsConnect(Configuration conf) { + String userName = conf.getString(Key.USERNAME); + String passWord = conf.getString(Key.PASSWORD); + String adsURL = conf.getString(Key.ADS_URL); + String schema = conf.getString(Key.SCHEMA); + String jdbcUrl = "jdbc:mysql://" + adsURL + "/" + schema + "?useUnicode=true&characterEncoding=UTF-8"; + + Connection connection = DBUtil.getConnection(DataBaseType.ADS, userName, passWord, jdbcUrl); + return connection; + } + + + public static List getAdsTableColumnNames(Configuration conf) { + List tableColumns = new ArrayList(); + String userName = conf.getString(Key.USERNAME); + String passWord = conf.getString(Key.PASSWORD); + String adsUrl = conf.getString(Key.ADS_URL); + String schema = conf.getString(Key.SCHEMA); + String tableName = conf.getString(Key.ADS_TABLE); + AdsHelper adsHelper = new AdsHelper(adsUrl, userName, passWord, schema); + TableInfo tableInfo= null; + try { + tableInfo = adsHelper.getTableInfo(tableName); + } catch (AdsException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.GET_ADS_TABLE_MEATA_FAILED, e); + } + + List columnInfos = tableInfo.getColumns(); + for(ColumnInfo columnInfo: columnInfos) { + tableColumns.add(columnInfo.getName()); + } + + LOG.info("table:[{}] all columns:[\n{}\n].", tableName, + StringUtils.join(tableColumns, ",")); + return tableColumns; + } + + public static Triple, List, List> getColumnMetaData + (Configuration configuration, List userColumns) { + Triple, List, List> columnMetaData = new ImmutableTriple, List, List>( + new ArrayList(), new ArrayList(), + new ArrayList()); + + List columnInfoList = getAdsTableColumns(configuration); + for(String column : userColumns) { + for (ColumnInfo columnInfo : columnInfoList) { + if(column.equals(columnInfo.getName())) { + columnMetaData.getLeft().add(columnInfo.getName()); + columnMetaData.getMiddle().add(columnInfo.getDataType().sqlType); + columnMetaData.getRight().add( + columnInfo.getDataType().name); + } + } + } + return columnMetaData; + } + + public static List getAdsTableColumns(Configuration conf) { + String userName = conf.getString(Key.USERNAME); + String passWord = conf.getString(Key.PASSWORD); + String adsUrl = conf.getString(Key.ADS_URL); + String schema = conf.getString(Key.SCHEMA); + String tableName = conf.getString(Key.ADS_TABLE); + AdsHelper adsHelper = new AdsHelper(adsUrl, userName, passWord, schema); + TableInfo tableInfo= null; + try { + tableInfo = adsHelper.getTableInfo(tableName); + } catch (AdsException e) { + throw DataXException.asDataXException(AdsWriterErrorCode.GET_ADS_TABLE_MEATA_FAILED, e); + } + + List columnInfos = tableInfo.getColumns(); + + return columnInfos; + } + + public static void dealColumnConf(Configuration originalConfig, List tableColumns) { + List userConfiguredColumns = originalConfig.getList(Key.COLUMN, String.class); + if (null == userConfiguredColumns || userConfiguredColumns.isEmpty()) { + throw DataXException.asDataXException(DBUtilErrorCode.ILLEGAL_VALUE, + "您的配置文件中的列配置信息有误. 因为您未配置写入数据库表的列名称,DataX获取不到列信息. 请检查您的配置并作出修改."); + } else { + if (1 == userConfiguredColumns.size() && "*".equals(userConfiguredColumns.get(0))) { + LOG.warn("您的配置文件中的列配置信息存在风险. 因为您配置的写入数据库表的列为*,当您的表字段个数、类型有变动时,可能影响任务正确性甚至会运行出错。请检查您的配置并作出修改."); + + // 回填其值,需要以 String 的方式转交后续处理 + originalConfig.set(Key.COLUMN, tableColumns); + } else if (userConfiguredColumns.size() > tableColumns.size()) { + throw DataXException.asDataXException(DBUtilErrorCode.ILLEGAL_VALUE, + String.format("您的配置文件中的列配置信息有误. 因为您所配置的写入数据库表的字段个数:%s 大于目的表的总字段总个数:%s. 请检查您的配置并作出修改.", + userConfiguredColumns.size(), tableColumns.size())); + } else { + // 确保用户配置的 column 不重复 + ListUtil.makeSureNoValueDuplicate(userConfiguredColumns, false); + + // 检查列是否都为数据库表中正确的列(通过执行一次 select column from table 进行判断) + ListUtil.makeSureBInA(tableColumns, userConfiguredColumns, true); + } + } + } + + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/AdsHelper.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/AdsHelper.java new file mode 100644 index 000000000..5f429294c --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/AdsHelper.java @@ -0,0 +1,388 @@ +/** + * + */ +package com.alibaba.datax.plugin.writer.adswriter.load; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.writer.adswriter.AdsException; +import com.alibaba.datax.plugin.writer.adswriter.AdsWriterErrorCode; +import com.alibaba.datax.plugin.writer.adswriter.ads.ColumnDataType; +import com.alibaba.datax.plugin.writer.adswriter.ads.ColumnInfo; +import com.alibaba.datax.plugin.writer.adswriter.ads.TableInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class AdsHelper { + private static final Logger LOG = LoggerFactory + .getLogger(AdsHelper.class); + + private String adsURL; + private String userName; + private String password; + private String schema; + + public AdsHelper(String adsUrl, String userName, String password, String schema) { + this.adsURL = adsUrl; + this.userName = userName; + this.password = password; + this.schema = schema; + } + + public String getAdsURL() { + return adsURL; + } + + public void setAdsURL(String adsURL) { + this.adsURL = adsURL; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + /** + * Obtain the table meta information. + * + * @param table The table + * @return The table meta information + * @throws com.alibaba.datax.plugin.writer.adswriter.AdsException + */ + public TableInfo getTableInfo(String table) throws AdsException { + + if (table == null) { + throw new AdsException(AdsException.ADS_TABLEMETA_TABLE_NULL, "Table is null.", null); + } + + if (adsURL == null) { + throw new AdsException(AdsException.ADS_CONN_URL_NOT_SET, "ADS JDBC connection URL was not set.", null); + } + + if (userName == null) { + throw new AdsException(AdsException.ADS_CONN_USERNAME_NOT_SET, + "ADS JDBC connection user name was not set.", null); + } + + if (password == null) { + throw new AdsException(AdsException.ADS_CONN_PASSWORD_NOT_SET, "ADS JDBC connection password was not set.", + null); + } + + if (schema == null) { + throw new AdsException(AdsException.ADS_CONN_SCHEMA_NOT_SET, "ADS JDBC connection schema was not set.", + null); + } + + String sql = "select ordinal_position,column_name,data_type,type_name,column_comment from information_schema.columns where table_schema='" + + schema + "' and table_name='" + table + "' order by ordinal_position"; + + Connection connection = null; + Statement statement = null; + ResultSet rs = null; + try { + Class.forName("com.mysql.jdbc.Driver"); + String url = "jdbc:mysql://" + adsURL + "/" + schema + "?useUnicode=true&characterEncoding=UTF-8&socketTimeout=3600000"; + + Properties connectionProps = new Properties(); + connectionProps.put("user", userName); + connectionProps.put("password", password); + connection = DriverManager.getConnection(url, connectionProps); + statement = connection.createStatement(); + + rs = statement.executeQuery(sql); + + TableInfo tableInfo = new TableInfo(); + List columnInfoList = new ArrayList(); + while (DBUtil.asyncResultSetNext(rs)) { + ColumnInfo columnInfo = new ColumnInfo(); + columnInfo.setOrdinal(rs.getInt(1)); + columnInfo.setName(rs.getString(2)); + //columnInfo.setDataType(ColumnDataType.getDataType(rs.getInt(3))); //for ads version < 0.7 + //columnInfo.setDataType(ColumnDataType.getTypeByName(rs.getString(3).toUpperCase())); //for ads version 0.8 + columnInfo.setDataType(ColumnDataType.getTypeByName(rs.getString(4).toUpperCase())); //for ads version 0.8 & 0.7 + columnInfo.setComment(rs.getString(5)); + columnInfoList.add(columnInfo); + } + if (columnInfoList.isEmpty()) { + throw DataXException.asDataXException(AdsWriterErrorCode.NO_ADS_TABLE, table + "不存在或者查询不到列信息. "); + } + + tableInfo.setColumns(columnInfoList); + tableInfo.setTableSchema(schema); + tableInfo.setTableName(table); + + return tableInfo; + + } catch (ClassNotFoundException e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } catch (SQLException e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } catch ( DataXException e) { + throw e; + } catch (Exception e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore exception + } + } + } + + } + + /** + * Submit LOAD DATA command. + * + * @param table The target ADS table + * @param partition The partition option in the form of "(partition_name,...)" + * @param sourcePath The source path + * @param overwrite + * @return + * @throws AdsException + */ + public String loadData(String table, String partition, String sourcePath, boolean overwrite) throws AdsException { + + if (table == null) { + throw new AdsException(AdsException.ADS_LOADDATA_TABLE_NULL, "ADS LOAD DATA table is null.", null); + } + + if (sourcePath == null) { + throw new AdsException(AdsException.ADS_LOADDATA_SOURCEPATH_NULL, "ADS LOAD DATA source path is null.", + null); + } + + if (adsURL == null) { + throw new AdsException(AdsException.ADS_CONN_URL_NOT_SET, "ADS JDBC connection URL was not set.", null); + } + + if (userName == null) { + throw new AdsException(AdsException.ADS_CONN_USERNAME_NOT_SET, + "ADS JDBC connection user name was not set.", null); + } + + if (password == null) { + throw new AdsException(AdsException.ADS_CONN_PASSWORD_NOT_SET, "ADS JDBC connection password was not set.", + null); + } + + if (schema == null) { + throw new AdsException(AdsException.ADS_CONN_SCHEMA_NOT_SET, "ADS JDBC connection schema was not set.", + null); + } + + StringBuilder sb = new StringBuilder(); + sb.append("LOAD DATA FROM "); + if (sourcePath.startsWith("'") && sourcePath.endsWith("'")) { + sb.append(sourcePath); + } else { + sb.append("'" + sourcePath + "'"); + } + if (overwrite) { + sb.append(" OVERWRITE"); + } + sb.append(" INTO TABLE "); + sb.append(schema + "." + table); + if (partition != null && !partition.trim().equals("")) { + String partitionTrim = partition.trim(); + if(partitionTrim.startsWith("(") && partitionTrim.endsWith(")")) { + sb.append(" PARTITION " + partition); + } else { + sb.append(" PARTITION " + "(" + partition + ")"); + } + } + + Connection connection = null; + Statement statement = null; + ResultSet rs = null; + try { + Class.forName("com.mysql.jdbc.Driver"); + String url = "jdbc:mysql://" + adsURL + "/" + schema + "?useUnicode=true&characterEncoding=UTF-8&socketTimeout=3600000"; + + Properties connectionProps = new Properties(); + connectionProps.put("user", userName); + connectionProps.put("password", password); + connection = DriverManager.getConnection(url, connectionProps); + statement = connection.createStatement(); + LOG.info("正在从ODPS数据库导数据到ADS中: "+sb.toString()); + LOG.info("由于ADS的限制,ADS导数据最少需要20分钟,请耐心等待"); + rs = statement.executeQuery(sb.toString()); + + String jobId = null; + while (DBUtil.asyncResultSetNext(rs)) { + jobId = rs.getString(1); + } + + if (jobId == null) { + throw new AdsException(AdsException.ADS_LOADDATA_JOBID_NOT_AVAIL, + "Job id is not available for the submitted LOAD DATA." + jobId, null); + } + + return jobId; + + } catch (ClassNotFoundException e) { + throw new AdsException(AdsException.ADS_LOADDATA_FAILED, e.getMessage(), e); + } catch (SQLException e) { + throw new AdsException(AdsException.ADS_LOADDATA_FAILED, e.getMessage(), e); + } catch (Exception e) { + throw new AdsException(AdsException.ADS_LOADDATA_FAILED, e.getMessage(), e); + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore exception + } + } + } + + } + + /** + * Check the load data job status. + * + * @param jobId The job id to + * @return true if load data job succeeded, false if load data job failed. + * @throws AdsException + */ + public boolean checkLoadDataJobStatus(String jobId) throws AdsException { + + if (adsURL == null) { + throw new AdsException(AdsException.ADS_CONN_URL_NOT_SET, "ADS JDBC connection URL was not set.", null); + } + + if (userName == null) { + throw new AdsException(AdsException.ADS_CONN_USERNAME_NOT_SET, + "ADS JDBC connection user name was not set.", null); + } + + if (password == null) { + throw new AdsException(AdsException.ADS_CONN_PASSWORD_NOT_SET, "ADS JDBC connection password was not set.", + null); + } + + if (schema == null) { + throw new AdsException(AdsException.ADS_CONN_SCHEMA_NOT_SET, "ADS JDBC connection schema was not set.", + null); + } + + Connection connection = null; + Statement statement = null; + ResultSet rs = null; + try { + Class.forName("com.mysql.jdbc.Driver"); + String url = "jdbc:mysql://" + adsURL + "/" + schema + "?useUnicode=true&characterEncoding=UTF-8&socketTimeout=3600000"; + + Properties connectionProps = new Properties(); + connectionProps.put("user", userName); + connectionProps.put("password", password); + connection = DriverManager.getConnection(url, connectionProps); + statement = connection.createStatement(); + + String sql = "select state from information_schema.job_instances where job_id like '" + jobId + "'"; + rs = statement.executeQuery(sql); + + String state = null; + while (DBUtil.asyncResultSetNext(rs)) { + state = rs.getString(1); + } + + if (state == null) { + throw new AdsException(AdsException.JOB_NOT_EXIST, "Target job does not exist for id: " + jobId, null); + } + + if (state.equals("SUCCEEDED")) { + return true; + } else if (state.equals("FAILED")) { + throw new AdsException(AdsException.JOB_FAILED, "Target job failed for id: " + jobId, null); + } else { + return false; + } + + } catch (ClassNotFoundException e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } catch (SQLException e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } catch (Exception e) { + throw new AdsException(AdsException.OTHER, e.getMessage(), e); + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore exception + } + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore exception + } + } + } + + } +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TableMetaHelper.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TableMetaHelper.java new file mode 100644 index 000000000..1ecad7561 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TableMetaHelper.java @@ -0,0 +1,87 @@ +package com.alibaba.datax.plugin.writer.adswriter.load; + +import com.alibaba.datax.plugin.writer.adswriter.ads.ColumnDataType; +import com.alibaba.datax.plugin.writer.adswriter.ads.ColumnInfo; +import com.alibaba.datax.plugin.writer.adswriter.ads.TableInfo; +import com.alibaba.datax.plugin.writer.adswriter.odps.DataType; +import com.alibaba.datax.plugin.writer.adswriter.odps.FieldSchema; +import com.alibaba.datax.plugin.writer.adswriter.odps.TableMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Table meta helper for ADS writer. + * + * @since 0.0.1 + */ +public class TableMetaHelper { + + private TableMetaHelper() { + } + + /** + * Create temporary ODPS table. + * + * @param tableMeta table meta + * @param lifeCycle for temporary table + * @return ODPS temporary table meta + */ + public static TableMeta createTempODPSTable(TableInfo tableMeta, int lifeCycle) { + TableMeta tempTable = new TableMeta(); + tempTable.setComment(tableMeta.getComments()); + tempTable.setLifeCycle(lifeCycle); + String tableSchema = tableMeta.getTableSchema(); + String tableName = tableMeta.getTableName(); + tempTable.setTableName(generateTempTableName(tableSchema, tableName)); + List tempColumns = new ArrayList(); + List columns = tableMeta.getColumns(); + for (ColumnInfo column : columns) { + FieldSchema tempColumn = new FieldSchema(); + tempColumn.setName(column.getName()); + tempColumn.setType(toODPSDataType(column.getDataType())); + tempColumn.setComment(column.getComment()); + tempColumns.add(tempColumn); + } + tempTable.setCols(tempColumns); + tempTable.setPartitionKeys(null); + return tempTable; + } + + private static String toODPSDataType(ColumnDataType columnDataType) { + int type; + switch (columnDataType.type) { + case ColumnDataType.BOOLEAN: + type = DataType.STRING; + break; + case ColumnDataType.BYTE: + case ColumnDataType.SHORT: + case ColumnDataType.INT: + case ColumnDataType.LONG: + type = DataType.INTEGER; + break; + case ColumnDataType.DECIMAL: + case ColumnDataType.DOUBLE: + case ColumnDataType.FLOAT: + type = DataType.DOUBLE; + break; + case ColumnDataType.DATE: + case ColumnDataType.TIME: + case ColumnDataType.TIMESTAMP: + case ColumnDataType.STRING: + case ColumnDataType.MULTI_VALUE: + type = DataType.STRING; + break; + default: + throw new IllegalArgumentException("columnDataType=" + columnDataType); + } + return DataType.toString(type); + } + + private static String generateTempTableName(String tableSchema, String tableName) { + int randNum = 1000 + new Random(System.currentTimeMillis()).nextInt(1000); + return tableSchema + "__" + tableName + "_" + System.currentTimeMillis() + randNum; + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TransferProjectConf.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TransferProjectConf.java new file mode 100644 index 000000000..bff4b7b90 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/TransferProjectConf.java @@ -0,0 +1,65 @@ +package com.alibaba.datax.plugin.writer.adswriter.load; + +import com.alibaba.datax.common.util.Configuration; + +/** + * Created by xiafei.qiuxf on 15/4/13. + */ +public class TransferProjectConf { + + public final static String KEY_ACCESS_ID = "odps.accessId"; + public final static String KEY_ACCESS_KEY = "odps.accessKey"; + public final static String KEY_ACCOUNT = "odps.account"; + public final static String KEY_ODPS_SERVER = "odps.odpsServer"; + public final static String KEY_ODPS_TUNNEL = "odps.tunnelServer"; + public final static String KEY_ACCOUNT_TYPE = "odps.accountType"; + public final static String KEY_PROJECT = "odps.project"; + + private String accessId; + private String accessKey; + private String account; + private String odpsServer; + private String odpsTunnel; + private String accountType; + private String project; + + public static TransferProjectConf create(Configuration adsWriterConf) { + TransferProjectConf res = new TransferProjectConf(); + res.accessId = adsWriterConf.getString(KEY_ACCESS_ID); + res.accessKey = adsWriterConf.getString(KEY_ACCESS_KEY); + res.account = adsWriterConf.getString(KEY_ACCOUNT); + res.odpsServer = adsWriterConf.getString(KEY_ODPS_SERVER); + res.odpsTunnel = adsWriterConf.getString(KEY_ODPS_TUNNEL); + res.accountType = adsWriterConf.getString(KEY_ACCOUNT_TYPE, "aliyun"); + res.project = adsWriterConf.getString(KEY_PROJECT); + return res; + } + + public String getAccessId() { + return accessId; + } + + public String getAccessKey() { + return accessKey; + } + + public String getAccount() { + return account; + } + + public String getOdpsServer() { + return odpsServer; + } + + public String getOdpsTunnel() { + return odpsTunnel; + } + + public String getAccountType() { + return accountType; + } + + public String getProject() { + return project; + } +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/DataType.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/DataType.java new file mode 100644 index 000000000..595b1dfd2 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/DataType.java @@ -0,0 +1,77 @@ +package com.alibaba.datax.plugin.writer.adswriter.odps; + +/** + * ODPS 数据类型. + *

+ * 当前定义了如下类型: + *

    + *
  • INTEGER + *
  • DOUBLE + *
  • BOOLEAN + *
  • STRING + *
  • DATETIME + *
+ *

+ * + * @since 0.0.1 + */ +public class DataType { + + public final static byte INTEGER = 0; + public final static byte DOUBLE = 1; + public final static byte BOOLEAN = 2; + public final static byte STRING = 3; + public final static byte DATETIME = 4; + + public static String toString(int type) { + switch (type) { + case INTEGER: + return "bigint"; + case DOUBLE: + return "double"; + case BOOLEAN: + return "boolean"; + case STRING: + return "string"; + case DATETIME: + return "datetime"; + default: + throw new IllegalArgumentException("type=" + type); + } + } + + /** + * 字符串的数据类型转换为byte常量定义的数据类型. + *

+ * 转换规则: + *

    + *
  • tinyint, int, bigint, long - {@link #INTEGER} + *
  • double, float - {@link #DOUBLE} + *
  • string - {@link #STRING} + *
  • boolean, bool - {@link #BOOLEAN} + *
  • datetime - {@link #DATETIME} + *
+ *

+ * + * @param type 字符串的数据类型 + * @return byte常量定义的数据类型 + * @throws IllegalArgumentException + */ + public static byte convertToDataType(String type) throws IllegalArgumentException { + type = type.toLowerCase().trim(); + if ("string".equals(type)) { + return STRING; + } else if ("bigint".equals(type) || "int".equals(type) || "tinyint".equals(type) || "long".equals(type)) { + return INTEGER; + } else if ("boolean".equals(type) || "bool".equals(type)) { + return BOOLEAN; + } else if ("double".equals(type) || "float".equals(type)) { + return DOUBLE; + } else if ("datetime".equals(type)) { + return DATETIME; + } else { + throw new IllegalArgumentException("unkown type: " + type); + } + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/FieldSchema.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/FieldSchema.java new file mode 100644 index 000000000..701ee261c --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/FieldSchema.java @@ -0,0 +1,63 @@ +package com.alibaba.datax.plugin.writer.adswriter.odps; + +/** + * ODPS列属性,包含列名和类型 列名和类型与SQL的DESC表或分区显示的列名和类型一致 + * + * @since 0.0.1 + */ +public class FieldSchema { + + /** 列名 */ + private String name; + + /** 列类型,如:string, bigint, boolean, datetime等等 */ + private String type; + + private String comment; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("FieldSchema [name=").append(name).append(", type=").append(type).append(", comment=") + .append(comment).append("]"); + return builder.toString(); + } + + /** + * @return "col_name data_type [COMMENT col_comment]" + */ + public String toDDL() { + StringBuilder builder = new StringBuilder(); + builder.append(name).append(" ").append(type); + String comment = this.comment; + if (comment != null && comment.length() > 0) { + builder.append(" ").append("COMMENT \"" + comment + "\""); + } + return builder.toString(); + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/TableMeta.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/TableMeta.java new file mode 100644 index 000000000..d0adc4eae --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/TableMeta.java @@ -0,0 +1,114 @@ +package com.alibaba.datax.plugin.writer.adswriter.odps; + +import java.util.Iterator; +import java.util.List; + +/** + * ODPS table meta. + * + * @since 0.0.1 + */ +public class TableMeta { + + private String tableName; + + private List cols; + + private List partitionKeys; + + private int lifeCycle; + + private String comment; + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public List getCols() { + return cols; + } + + public void setCols(List cols) { + this.cols = cols; + } + + public List getPartitionKeys() { + return partitionKeys; + } + + public void setPartitionKeys(List partitionKeys) { + this.partitionKeys = partitionKeys; + } + + public int getLifeCycle() { + return lifeCycle; + } + + public void setLifeCycle(int lifeCycle) { + this.lifeCycle = lifeCycle; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TableMeta [tableName=").append(tableName).append(", cols=").append(cols) + .append(", partitionKeys=").append(partitionKeys).append(", lifeCycle=").append(lifeCycle) + .append(", comment=").append(comment).append("]"); + return builder.toString(); + } + + /** + * @return
+ * "CREATE TABLE [IF NOT EXISTS] table_name
+ * [(col_name data_type [COMMENT col_comment], ...)]
+ * [COMMENT table_comment]
+ * [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
+ * [LIFECYCLE days]
+ * [AS select_statement] "
+ */ + public String toDDL() { + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE " + tableName).append(" "); + List cols = this.cols; + if (cols != null && cols.size() > 0) { + builder.append("(").append(toDDL(cols)).append(")").append(" "); + } + String comment = this.comment; + if (comment != null && comment.length() > 0) { + builder.append("COMMENT \"" + comment + "\" "); + } + List partitionKeys = this.partitionKeys; + if (partitionKeys != null && partitionKeys.size() > 0) { + builder.append("PARTITIONED BY "); + builder.append("(").append(toDDL(partitionKeys)).append(")").append(" "); + } + if (lifeCycle > 0) { + builder.append("LIFECYCLE " + lifeCycle).append(" "); + } + builder.append(";"); + return builder.toString(); + } + + private String toDDL(List cols) { + StringBuilder builder = new StringBuilder(); + Iterator iter = cols.iterator(); + builder.append(iter.next().toDDL()); + while (iter.hasNext()) { + builder.append(", ").append(iter.next().toDDL()); + } + return builder.toString(); + } + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/package-info.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/package-info.java new file mode 100644 index 000000000..92dfd09da --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/odps/package-info.java @@ -0,0 +1,6 @@ +/** + * ODPS meta. + * + * @since 0.0.1 + */ +package com.alibaba.datax.plugin.writer.adswriter.odps; \ No newline at end of file diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/package-info.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/package-info.java new file mode 100644 index 000000000..139a39106 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/package-info.java @@ -0,0 +1,6 @@ +/** + * ADS Writer. + * + * @since 0.0.1 + */ +package com.alibaba.datax.plugin.writer.adswriter; \ No newline at end of file diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/AdsUtil.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/AdsUtil.java new file mode 100644 index 000000000..778ce5eb8 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/AdsUtil.java @@ -0,0 +1,134 @@ +package com.alibaba.datax.plugin.writer.adswriter.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.writer.adswriter.load.AdsHelper; +import com.alibaba.datax.plugin.writer.adswriter.AdsWriterErrorCode; +import com.alibaba.datax.plugin.writer.adswriter.load.TransferProjectConf; +import com.alibaba.datax.plugin.writer.adswriter.odps.FieldSchema; +import com.alibaba.datax.plugin.writer.adswriter.odps.TableMeta; +import com.alibaba.datax.plugin.writer.odpswriter.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by judy.lt on 2015/1/30. + */ +public class AdsUtil { + private static final Logger LOG = LoggerFactory.getLogger(AdsUtil.class); + + /*检查配置文件中必填的配置项是否都已填 + * */ + public static void checkNecessaryConfig(Configuration originalConfig, String writeMode) { + //检查ADS必要参数 + originalConfig.getNecessaryValue(Key.ADS_URL, + AdsWriterErrorCode.REQUIRED_VALUE); + originalConfig.getNecessaryValue(Key.USERNAME, + AdsWriterErrorCode.REQUIRED_VALUE); + originalConfig.getNecessaryValue(Key.PASSWORD, + AdsWriterErrorCode.REQUIRED_VALUE); + originalConfig.getNecessaryValue(Key.SCHEMA, + AdsWriterErrorCode.REQUIRED_VALUE); + if(Constant.LOADMODE.equals(writeMode)) { + originalConfig.getNecessaryValue(Key.Life_CYCLE, + AdsWriterErrorCode.REQUIRED_VALUE); + Integer lifeCycle = originalConfig.getInt(Key.Life_CYCLE); + if (lifeCycle <= 0) { + throw DataXException.asDataXException(AdsWriterErrorCode.INVALID_CONFIG_VALUE, "配置项[lifeCycle]的值必须大于零."); + } + originalConfig.getNecessaryValue(Key.ADS_TABLE, + AdsWriterErrorCode.REQUIRED_VALUE); + Boolean overwrite = originalConfig.getBool(Key.OVER_WRITE); + if (overwrite == null) { + throw DataXException.asDataXException(AdsWriterErrorCode.REQUIRED_VALUE, "配置项[overWrite]是必填项."); + } + } + } + + /*生成AdsHelp实例 + * */ + public static AdsHelper createAdsHelper(Configuration originalConfig){ + //Get adsUrl,userName,password,schema等参数,创建AdsHelp实例 + String adsUrl = originalConfig.getString(Key.ADS_URL); + String userName = originalConfig.getString(Key.USERNAME); + String password = originalConfig.getString(Key.PASSWORD); + String schema = originalConfig.getString(Key.SCHEMA); + return new AdsHelper(adsUrl,userName,password,schema); + } + + public static AdsHelper createAdsHelperWithOdpsAccount(Configuration originalConfig) { + String adsUrl = originalConfig.getString(Key.ADS_URL); + String userName = originalConfig.getString(TransferProjectConf.KEY_ACCESS_ID); + String password = originalConfig.getString(TransferProjectConf.KEY_ACCESS_KEY); + String schema = originalConfig.getString(Key.SCHEMA); + return new AdsHelper(adsUrl, userName, password, schema); + } + + /*生成ODPSWriter Plugin所需要的配置文件 + * */ + public static Configuration generateConf(Configuration originalConfig, String odpsTableName, TableMeta tableMeta, TransferProjectConf transConf){ + Configuration newConfig = originalConfig.clone(); + newConfig.set(Key.ODPSTABLENAME, odpsTableName); + newConfig.set(Key.ODPS_SERVER, transConf.getOdpsServer()); + newConfig.set(Key.TUNNEL_SERVER,transConf.getOdpsTunnel()); + newConfig.set(Key.ACCESS_ID,transConf.getAccessId()); + newConfig.set(Key.ACCESS_KEY,transConf.getAccessKey()); + newConfig.set(Key.PROJECT,transConf.getProject()); + newConfig.set(Key.TRUNCATE, true); + newConfig.set(Key.PARTITION,null); +// newConfig.remove(Key.PARTITION); + List cols = tableMeta.getCols(); + List allColumns = new ArrayList(); + if(cols != null && !cols.isEmpty()){ + for(FieldSchema col:cols){ + allColumns.add(col.getName()); + } + } + newConfig.set(Key.COLUMN,allColumns); + return newConfig; + } + + /*生成ADS数据导入时的source_path + * */ + public static String generateSourcePath(String project, String tmpOdpsTableName, String odpsPartition){ + StringBuilder builder = new StringBuilder(); + String partition = transferOdpsPartitionToAds(odpsPartition); + builder.append("odps://").append(project).append("/").append(tmpOdpsTableName); + if(odpsPartition != null && !odpsPartition.isEmpty()){ + builder.append("/").append(partition); + } + return builder.toString(); + } + + public static String transferOdpsPartitionToAds(String odpsPartition){ + if(odpsPartition == null || odpsPartition.isEmpty()) + return null; + String adsPartition = formatPartition(odpsPartition);; + String[] partitions = adsPartition.split("/"); + for(int last = partitions.length; last > 0; last--){ + + String partitionPart = partitions[last-1]; + String newPart = partitionPart.replace(".*", "*").replace("*", ".*"); + if(newPart.split("=")[1].equals(".*")){ + adsPartition = adsPartition.substring(0,adsPartition.length()-partitionPart.length()); + }else{ + break; + } + if(adsPartition.endsWith("/")){ + adsPartition = adsPartition.substring(0,adsPartition.length()-1); + } + } + if (adsPartition.contains("*")) + throw DataXException.asDataXException(AdsWriterErrorCode.ODPS_PARTITION_FAILED, ""); + return adsPartition; + } + + public static String formatPartition(String partition) { + return partition.trim().replaceAll(" *= *", "=") + .replaceAll(" */ *", ",").replaceAll(" *, *", ",") + .replaceAll("'", "").replaceAll(",", "/"); + } +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Constant.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Constant.java new file mode 100644 index 000000000..3842cd011 --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Constant.java @@ -0,0 +1,13 @@ +package com.alibaba.datax.plugin.writer.adswriter.util; + +public class Constant { + + public static final String LOADMODE = "load"; + + public static final String INSERTMODE = "insert"; + + public static final String REPLACEMODE = "replace"; + + public static final int DEFAULT_BATCH_SIZE = 32; + +} diff --git a/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Key.java b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Key.java new file mode 100644 index 000000000..e0822878b --- /dev/null +++ b/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/util/Key.java @@ -0,0 +1,48 @@ +package com.alibaba.datax.plugin.writer.adswriter.util; + + +public final class Key { + + public final static String ADS_URL = "url"; + + public final static String USERNAME = "username"; + + public final static String PASSWORD = "password"; + + public final static String SCHEMA = "schema"; + + public final static String ADS_TABLE = "table"; + + public final static String Life_CYCLE = "lifeCycle"; + + public final static String OVER_WRITE = "overWrite"; + + public final static String WRITE_MODE = "writeMode"; + + + public final static String COLUMN = "column"; + + public final static String EMPTY_AS_NULL = "emptyAsNull"; + + public final static String BATCH_SIZE = "batchSize"; + + /** + * 以下是odps writer的key + */ + public final static String PARTITION = "partition"; + + public final static String ODPSTABLENAME = "table"; + + public final static String ODPS_SERVER = "odpsServer"; + + public final static String TUNNEL_SERVER = "tunnelServer"; + + public final static String ACCESS_ID = "accessId"; + + public final static String ACCESS_KEY = "accessKey"; + + public final static String PROJECT = "project"; + + public final static String TRUNCATE = "truncate"; + +} \ No newline at end of file diff --git a/adswriter/src/main/resources/plugin.json b/adswriter/src/main/resources/plugin.json new file mode 100644 index 000000000..a70fb3646 --- /dev/null +++ b/adswriter/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "adswriter", + "class": "com.alibaba.datax.plugin.writer.adswriter.AdsWriter", + "description": "", + "developer": "alibaba" +} \ No newline at end of file diff --git a/adswriter/src/main/resources/plugin_job_template.json b/adswriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..0753a226e --- /dev/null +++ b/adswriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,13 @@ +{ + "name": "adswriter", + "parameter": { + "url": "", + "username": "", + "password": "", + "schema": "", + "table": "", + "partition": "", + "overWrite": "", + "lifeCycle": 2 + } +} \ No newline at end of file diff --git a/common/datax-common.iml b/common/datax-common.iml new file mode 100644 index 000000000..87f7dace6 --- /dev/null +++ b/common/datax-common.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml new file mode 100755 index 000000000..86c0a22dd --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + + datax-common + datax-common + jar + + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + 18.0 + + + com.alibaba + fastjson + + + commons-io + commons-io + + + + junit + junit + test + + + + org.slf4j + slf4j-api + + + + ch.qos.logback + logback-classic + + + + org.apache.httpcomponents + httpclient + 4.4 + test + + + org.apache.httpcomponents + fluent-hc + 4.4 + test + + + org.apache.commons + commons-math3 + 3.1.1 + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + \ No newline at end of file diff --git a/common/src/main/java/com/alibaba/datax/common/base/BaseObject.java b/common/src/main/java/com/alibaba/datax/common/base/BaseObject.java new file mode 100755 index 000000000..e7d06a950 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/base/BaseObject.java @@ -0,0 +1,25 @@ +package com.alibaba.datax.common.base; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class BaseObject { + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this, false); + } + + @Override + public boolean equals(Object object) { + return EqualsBuilder.reflectionEquals(this, object, false); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, + ToStringStyle.MULTI_LINE_STYLE); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/constant/CommonConstant.java b/common/src/main/java/com/alibaba/datax/common/constant/CommonConstant.java new file mode 100755 index 000000000..423e16f92 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/constant/CommonConstant.java @@ -0,0 +1,9 @@ +package com.alibaba.datax.common.constant; + +public final class CommonConstant { + /** + * 用于插件对自身 split 的每个 task 标识其使用的资源,以告知core 对 reader/writer split 之后的 task 进行拼接时需要根据资源标签进行更有意义的 shuffle 操作 + */ + public static String LOAD_BALANCE_RESOURCE_MARK = "loadBalanceResourceMark"; + +} diff --git a/common/src/main/java/com/alibaba/datax/common/constant/PluginType.java b/common/src/main/java/com/alibaba/datax/common/constant/PluginType.java new file mode 100755 index 000000000..ceee089e9 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/constant/PluginType.java @@ -0,0 +1,20 @@ +package com.alibaba.datax.common.constant; + +/** + * Created by jingxing on 14-8-31. + */ +public enum PluginType { + //pluginType还代表了资源目录,很难扩展,或者说需要足够必要才扩展。先mark Handler(其实和transformer一样),再讨论 + READER("reader"), TRANSFORMER("transformer"), WRITER("writer"), HANDLER("handler"); + + private String pluginType; + + private PluginType(String pluginType) { + this.pluginType = pluginType; + } + + @Override + public String toString() { + return this.pluginType; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/BoolColumn.java b/common/src/main/java/com/alibaba/datax/common/element/BoolColumn.java new file mode 100755 index 000000000..7699e152a --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/BoolColumn.java @@ -0,0 +1,115 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Created by jingxing on 14-8-24. + */ +public class BoolColumn extends Column { + + public BoolColumn(Boolean bool) { + super(bool, Column.Type.BOOL, 1); + } + + public BoolColumn(final String data) { + this(true); + this.validate(data); + if (null == data) { + this.setRawData(null); + this.setByteSize(0); + } else { + this.setRawData(Boolean.valueOf(data)); + this.setByteSize(1); + } + return; + } + + public BoolColumn() { + super(null, Column.Type.BOOL, 1); + } + + @Override + public Boolean asBoolean() { + if (null == super.getRawData()) { + return null; + } + + return (Boolean) super.getRawData(); + } + + @Override + public Long asLong() { + if (null == this.getRawData()) { + return null; + } + + return this.asBoolean() ? 1L : 0L; + } + + @Override + public Double asDouble() { + if (null == this.getRawData()) { + return null; + } + + return this.asBoolean() ? 1.0d : 0.0d; + } + + @Override + public String asString() { + if (null == super.getRawData()) { + return null; + } + + return this.asBoolean() ? "true" : "false"; + } + + @Override + public BigInteger asBigInteger() { + if (null == this.getRawData()) { + return null; + } + + return BigInteger.valueOf(this.asLong()); + } + + @Override + public BigDecimal asBigDecimal() { + if (null == this.getRawData()) { + return null; + } + + return BigDecimal.valueOf(this.asLong()); + } + + @Override + public Date asDate() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bool类型不能转为Date ."); + } + + @Override + public byte[] asBytes() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Boolean类型不能转为Bytes ."); + } + + private void validate(final String data) { + if (null == data) { + return; + } + + if ("true".equalsIgnoreCase(data) || "false".equalsIgnoreCase(data)) { + return; + } + + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[%s]不能转为Bool .", data)); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/BytesColumn.java b/common/src/main/java/com/alibaba/datax/common/element/BytesColumn.java new file mode 100755 index 000000000..d3cc59936 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/BytesColumn.java @@ -0,0 +1,84 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import org.apache.commons.lang3.ArrayUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Created by jingxing on 14-8-24. + */ +public class BytesColumn extends Column { + + public BytesColumn() { + this(null); + } + + public BytesColumn(byte[] bytes) { + super(ArrayUtils.clone(bytes), Column.Type.BYTES, null == bytes ? 0 + : bytes.length); + } + + @Override + public byte[] asBytes() { + if (null == this.getRawData()) { + return null; + } + + return (byte[]) this.getRawData(); + } + + @Override + public String asString() { + if (null == this.getRawData()) { + return null; + } + + try { + return ColumnCast.bytes2String(this); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("Bytes[%s]不能转为String .", this.toString())); + } + } + + @Override + public Long asLong() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为Long ."); + } + + @Override + public BigDecimal asBigDecimal() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为BigDecimal ."); + } + + @Override + public BigInteger asBigInteger() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为BigInteger ."); + } + + @Override + public Double asDouble() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为Long ."); + } + + @Override + public Date asDate() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为Date ."); + } + + @Override + public Boolean asBoolean() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Bytes类型不能转为Boolean ."); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/Column.java b/common/src/main/java/com/alibaba/datax/common/element/Column.java new file mode 100755 index 000000000..ed68e88d6 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/Column.java @@ -0,0 +1,75 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.fastjson.JSON; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Created by jingxing on 14-8-24. + *

+ */ +public abstract class Column { + + private Type type; + + private Object rawData; + + private int byteSize; + + public Column(final Object object, final Type type, int byteSize) { + this.rawData = object; + this.type = type; + this.byteSize = byteSize; + } + + public Object getRawData() { + return this.rawData; + } + + public Type getType() { + return this.type; + } + + public int getByteSize() { + return this.byteSize; + } + + protected void setType(Type type) { + this.type = type; + } + + protected void setRawData(Object rawData) { + this.rawData = rawData; + } + + protected void setByteSize(int byteSize) { + this.byteSize = byteSize; + } + + public abstract Long asLong(); + + public abstract Double asDouble(); + + public abstract String asString(); + + public abstract Date asDate(); + + public abstract byte[] asBytes(); + + public abstract Boolean asBoolean(); + + public abstract BigDecimal asBigDecimal(); + + public abstract BigInteger asBigInteger(); + + @Override + public String toString() { + return JSON.toJSONString(this); + } + + public enum Type { + BAD, NULL, INT, LONG, DOUBLE, STRING, BOOL, DATE, BYTES + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/ColumnCast.java b/common/src/main/java/com/alibaba/datax/common/element/ColumnCast.java new file mode 100755 index 000000000..89d0a7c62 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/ColumnCast.java @@ -0,0 +1,199 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.commons.lang3.time.FastDateFormat; + +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +import java.util.*; + +public final class ColumnCast { + + public static void bind(final Configuration configuration) { + StringCast.init(configuration); + DateCast.init(configuration); + BytesCast.init(configuration); + } + + public static Date string2Date(final StringColumn column) + throws ParseException { + return StringCast.asDate(column); + } + + public static byte[] string2Bytes(final StringColumn column) + throws UnsupportedEncodingException { + return StringCast.asBytes(column); + } + + public static String date2String(final DateColumn column) { + return DateCast.asString(column); + } + + public static String bytes2String(final BytesColumn column) + throws UnsupportedEncodingException { + return BytesCast.asString(column); + } +} + +class StringCast { + static String datetimeFormat = "yyyy-MM-dd HH:mm:ss"; + + static String dateFormat = "yyyy-MM-dd"; + + static String timeFormat = "HH:mm:ss"; + + static List extraFormats = Collections.emptyList(); + + static String timeZone = "GMT+8"; + + static FastDateFormat dateFormatter; + + static FastDateFormat timeFormatter; + + static FastDateFormat datetimeFormatter; + + static TimeZone timeZoner; + + static String encoding = "UTF-8"; + + static void init(final Configuration configuration) { + StringCast.datetimeFormat = configuration.getString( + "common.column.datetimeFormat", StringCast.datetimeFormat); + StringCast.dateFormat = configuration.getString( + "common.column.dateFormat", StringCast.dateFormat); + StringCast.timeFormat = configuration.getString( + "common.column.timeFormat", StringCast.timeFormat); + StringCast.extraFormats = configuration.getList( + "common.column.extraFormats", Collections.emptyList(), String.class); + + StringCast.timeZone = configuration.getString("common.column.timeZone", + StringCast.timeZone); + StringCast.timeZoner = TimeZone.getTimeZone(StringCast.timeZone); + + StringCast.datetimeFormatter = FastDateFormat.getInstance( + StringCast.datetimeFormat, StringCast.timeZoner); + StringCast.dateFormatter = FastDateFormat.getInstance( + StringCast.dateFormat, StringCast.timeZoner); + StringCast.timeFormatter = FastDateFormat.getInstance( + StringCast.timeFormat, StringCast.timeZoner); + + StringCast.encoding = configuration.getString("common.column.encoding", + StringCast.encoding); + } + + static Date asDate(final StringColumn column) throws ParseException { + if (null == column.asString()) { + return null; + } + + try { + return StringCast.datetimeFormatter.parse(column.asString()); + } catch (ParseException ignored) { + } + + try { + return StringCast.dateFormatter.parse(column.asString()); + } catch (ParseException ignored) { + } + + ParseException e; + try { + return StringCast.timeFormatter.parse(column.asString()); + } catch (ParseException ignored) { + e = ignored; + } + + for (String format : StringCast.extraFormats) { + try{ + return FastDateFormat.getInstance(format, StringCast.timeZoner).parse(column.asString()); + } catch (ParseException ignored){ + e = ignored; + } + } + throw e; + } + + static byte[] asBytes(final StringColumn column) + throws UnsupportedEncodingException { + if (null == column.asString()) { + return null; + } + + return column.asString().getBytes(StringCast.encoding); + } +} + +/** + * 后续为了可维护性,可以考虑直接使用 apache 的DateFormatUtils. + * + * 迟南已经修复了该问题,但是为了维护性,还是直接使用apache的内置函数 + */ +class DateCast { + + static String datetimeFormat = "yyyy-MM-dd HH:mm:ss"; + + static String dateFormat = "yyyy-MM-dd"; + + static String timeFormat = "HH:mm:ss"; + + static String timeZone = "GMT+8"; + + static TimeZone timeZoner = TimeZone.getTimeZone(DateCast.timeZone); + + static void init(final Configuration configuration) { + DateCast.datetimeFormat = configuration.getString( + "common.column.datetimeFormat", datetimeFormat); + DateCast.timeFormat = configuration.getString( + "common.column.timeFormat", timeFormat); + DateCast.dateFormat = configuration.getString( + "common.column.dateFormat", dateFormat); + DateCast.timeZone = configuration.getString("common.column.timeZone", + DateCast.timeZone); + DateCast.timeZoner = TimeZone.getTimeZone(DateCast.timeZone); + return; + } + + static String asString(final DateColumn column) { + if (null == column.asDate()) { + return null; + } + + switch (column.getSubType()) { + case DATE: + return DateFormatUtils.format(column.asDate(), DateCast.dateFormat, + DateCast.timeZoner); + case TIME: + return DateFormatUtils.format(column.asDate(), DateCast.timeFormat, + DateCast.timeZoner); + case DATETIME: + return DateFormatUtils.format(column.asDate(), + DateCast.datetimeFormat, DateCast.timeZoner); + default: + throw DataXException + .asDataXException(CommonErrorCode.CONVERT_NOT_SUPPORT, + "时间类型出现不支持类型,目前仅支持DATE/TIME/DATETIME。该类型属于编程错误,请反馈给DataX开发团队 ."); + } + } +} + +class BytesCast { + static String encoding = "utf-8"; + + static void init(final Configuration configuration) { + BytesCast.encoding = configuration.getString("common.column.encoding", + BytesCast.encoding); + return; + } + + static String asString(final BytesColumn column) + throws UnsupportedEncodingException { + if (null == column.asBytes()) { + return null; + } + + return new String(column.asBytes(), encoding); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/alibaba/datax/common/element/DateColumn.java b/common/src/main/java/com/alibaba/datax/common/element/DateColumn.java new file mode 100755 index 000000000..6626a6fbd --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/DateColumn.java @@ -0,0 +1,130 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Created by jingxing on 14-8-24. + */ +public class DateColumn extends Column { + + private DateType subType = DateType.DATETIME; + + public static enum DateType { + DATE, TIME, DATETIME + } + + /** + * 构建值为null的DateColumn,使用Date子类型为DATETIME + * */ + public DateColumn() { + this((Long)null); + } + + /** + * 构建值为stamp(Unix时间戳)的DateColumn,使用Date子类型为DATETIME + * 实际存储有date改为long的ms,节省存储 + * */ + public DateColumn(final Long stamp) { + super(stamp, Column.Type.DATE, (null == stamp ? 0 : 8)); + } + + /** + * 构建值为date(java.util.Date)的DateColumn,使用Date子类型为DATETIME + * */ + public DateColumn(final Date date) { + this(date == null ? null : date.getTime()); + } + + /** + * 构建值为date(java.sql.Date)的DateColumn,使用Date子类型为DATE,只有日期,没有时间 + * */ + public DateColumn(final java.sql.Date date) { + this(date == null ? null : date.getTime()); + this.setSubType(DateType.DATE); + } + + /** + * 构建值为time(java.sql.Time)的DateColumn,使用Date子类型为TIME,只有时间,没有日期 + * */ + public DateColumn(final java.sql.Time time) { + this(time == null ? null : time.getTime()); + this.setSubType(DateType.TIME); + } + + /** + * 构建值为ts(java.sql.Timestamp)的DateColumn,使用Date子类型为DATETIME + * */ + public DateColumn(final java.sql.Timestamp ts) { + this(ts == null ? null : ts.getTime()); + this.setSubType(DateType.DATETIME); + } + + @Override + public Long asLong() { + + return (Long)this.getRawData(); + } + + @Override + public String asString() { + try { + return ColumnCast.date2String(this); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("Date[%s]类型不能转为String .", this.toString())); + } + } + + @Override + public Date asDate() { + if (null == this.getRawData()) { + return null; + } + + return new Date((Long)this.getRawData()); + } + + @Override + public byte[] asBytes() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Date类型不能转为Bytes ."); + } + + @Override + public Boolean asBoolean() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Date类型不能转为Boolean ."); + } + + @Override + public Double asDouble() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Date类型不能转为Double ."); + } + + @Override + public BigInteger asBigInteger() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Date类型不能转为BigInteger ."); + } + + @Override + public BigDecimal asBigDecimal() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Date类型不能转为BigDecimal ."); + } + + public DateType getSubType() { + return subType; + } + + public void setSubType(DateType subType) { + this.subType = subType; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/alibaba/datax/common/element/DoubleColumn.java b/common/src/main/java/com/alibaba/datax/common/element/DoubleColumn.java new file mode 100755 index 000000000..17170ea6c --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/DoubleColumn.java @@ -0,0 +1,161 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +public class DoubleColumn extends Column { + + public DoubleColumn(final String data) { + this(data, null == data ? 0 : data.length()); + this.validate(data); + } + + public DoubleColumn(Long data) { + this(data == null ? (String) null : String.valueOf(data)); + } + + public DoubleColumn(Integer data) { + this(data == null ? (String) null : String.valueOf(data)); + } + + /** + * Double无法表示准确的小数数据,我们不推荐使用该方法保存Double数据,建议使用String作为构造入参 + * + * */ + public DoubleColumn(final Double data) { + this(data == null ? (String) null + : new BigDecimal(String.valueOf(data)).toPlainString()); + } + + /** + * Float无法表示准确的小数数据,我们不推荐使用该方法保存Float数据,建议使用String作为构造入参 + * + * */ + public DoubleColumn(final Float data) { + this(data == null ? (String) null + : new BigDecimal(String.valueOf(data)).toPlainString()); + } + + public DoubleColumn(final BigDecimal data) { + this(null == data ? (String) null : data.toPlainString()); + } + + public DoubleColumn(final BigInteger data) { + this(null == data ? (String) null : data.toString()); + } + + public DoubleColumn() { + this((String) null); + } + + private DoubleColumn(final String data, int byteSize) { + super(data, Column.Type.DOUBLE, byteSize); + } + + @Override + public BigDecimal asBigDecimal() { + if (null == this.getRawData()) { + return null; + } + + try { + return new BigDecimal((String) this.getRawData()); + } catch (NumberFormatException e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[%s] 无法转换为Double类型 .", + (String) this.getRawData())); + } + } + + @Override + public Double asDouble() { + if (null == this.getRawData()) { + return null; + } + + String string = (String) this.getRawData(); + + boolean isDoubleSpecific = string.equals("NaN") + || string.equals("-Infinity") || string.equals("+Infinity"); + if (isDoubleSpecific) { + return Double.valueOf(string); + } + + BigDecimal result = this.asBigDecimal(); + OverFlowUtil.validateDoubleNotOverFlow(result); + + return result.doubleValue(); + } + + @Override + public Long asLong() { + if (null == this.getRawData()) { + return null; + } + + BigDecimal result = this.asBigDecimal(); + OverFlowUtil.validateLongNotOverFlow(result.toBigInteger()); + + return result.longValue(); + } + + @Override + public BigInteger asBigInteger() { + if (null == this.getRawData()) { + return null; + } + + return this.asBigDecimal().toBigInteger(); + } + + @Override + public String asString() { + if (null == this.getRawData()) { + return null; + } + return (String) this.getRawData(); + } + + @Override + public Boolean asBoolean() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Double类型无法转为Bool ."); + } + + @Override + public Date asDate() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Double类型无法转为Date类型 ."); + } + + @Override + public byte[] asBytes() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Double类型无法转为Bytes类型 ."); + } + + private void validate(final String data) { + if (null == data) { + return; + } + + if (data.equalsIgnoreCase("NaN") || data.equalsIgnoreCase("-Infinity") + || data.equalsIgnoreCase("Infinity")) { + return; + } + + try { + new BigDecimal(data); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[%s]无法转为Double类型 .", data)); + } + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/alibaba/datax/common/element/LongColumn.java b/common/src/main/java/com/alibaba/datax/common/element/LongColumn.java new file mode 100755 index 000000000..d8113f7c0 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/LongColumn.java @@ -0,0 +1,135 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import org.apache.commons.lang3.math.NumberUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +public class LongColumn extends Column { + + /** + * 从整形字符串表示转为LongColumn,支持Java科学计数法 + * + * NOTE:
+ * 如果data为浮点类型的字符串表示,数据将会失真,请使用DoubleColumn对接浮点字符串 + * + * */ + public LongColumn(final String data) { + super(null, Column.Type.LONG, 0); + if (null == data) { + return; + } + + try { + BigInteger rawData = NumberUtils.createBigDecimal(data) + .toBigInteger(); + super.setRawData(rawData); + + // 当 rawData 为[0-127]时,rawData.bitLength() < 8,导致其 byteSize = 0,简单起见,直接认为其长度为 data.length() + // super.setByteSize(rawData.bitLength() / 8); + super.setByteSize(data.length()); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[%s]不能转为Long .", data)); + } + } + + public LongColumn(Long data) { + this(null == data ? (BigInteger) null : BigInteger.valueOf(data)); + } + + public LongColumn(Integer data) { + this(null == data ? (BigInteger) null : BigInteger.valueOf(data)); + } + + public LongColumn(BigInteger data) { + this(data, null == data ? 0 : 8); + } + + private LongColumn(BigInteger data, int byteSize) { + super(data, Column.Type.LONG, byteSize); + } + + public LongColumn() { + this((BigInteger) null); + } + + @Override + public BigInteger asBigInteger() { + if (null == this.getRawData()) { + return null; + } + + return (BigInteger) this.getRawData(); + } + + @Override + public Long asLong() { + BigInteger rawData = (BigInteger) this.getRawData(); + if (null == rawData) { + return null; + } + + OverFlowUtil.validateLongNotOverFlow(rawData); + + return rawData.longValue(); + } + + @Override + public Double asDouble() { + if (null == this.getRawData()) { + return null; + } + + BigDecimal decimal = this.asBigDecimal(); + OverFlowUtil.validateDoubleNotOverFlow(decimal); + + return decimal.doubleValue(); + } + + @Override + public Boolean asBoolean() { + if (null == this.getRawData()) { + return null; + } + + return this.asBigInteger().compareTo(BigInteger.ZERO) != 0 ? true + : false; + } + + @Override + public BigDecimal asBigDecimal() { + if (null == this.getRawData()) { + return null; + } + + return new BigDecimal(this.asBigInteger()); + } + + @Override + public String asString() { + if (null == this.getRawData()) { + return null; + } + return ((BigInteger) this.getRawData()).toString(); + } + + @Override + public Date asDate() { + if (null == this.getRawData()) { + return null; + } + return new Date(this.asLong()); + } + + @Override + public byte[] asBytes() { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, "Long类型不能转为Bytes ."); + } + +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/OverFlowUtil.java b/common/src/main/java/com/alibaba/datax/common/element/OverFlowUtil.java new file mode 100755 index 000000000..39460c7eb --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/OverFlowUtil.java @@ -0,0 +1,62 @@ +package com.alibaba.datax.common.element; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; + +public final class OverFlowUtil { + public static final BigInteger MAX_LONG = BigInteger + .valueOf(Long.MAX_VALUE); + + public static final BigInteger MIN_LONG = BigInteger + .valueOf(Long.MIN_VALUE); + + public static final BigDecimal MIN_DOUBLE_POSITIVE = new BigDecimal( + String.valueOf(Double.MIN_VALUE)); + + public static final BigDecimal MAX_DOUBLE_POSITIVE = new BigDecimal( + String.valueOf(Double.MAX_VALUE)); + + public static boolean isLongOverflow(final BigInteger integer) { + return (integer.compareTo(OverFlowUtil.MAX_LONG) > 0 || integer + .compareTo(OverFlowUtil.MIN_LONG) < 0); + + } + + public static void validateLongNotOverFlow(final BigInteger integer) { + boolean isOverFlow = OverFlowUtil.isLongOverflow(integer); + + if (isOverFlow) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_OVER_FLOW, + String.format("[%s] 转为Long类型出现溢出 .", integer.toString())); + } + } + + public static boolean isDoubleOverFlow(final BigDecimal decimal) { + if (decimal.signum() == 0) { + return false; + } + + BigDecimal newDecimal = decimal; + boolean isPositive = decimal.signum() == 1; + if (!isPositive) { + newDecimal = decimal.negate(); + } + + return (newDecimal.compareTo(MIN_DOUBLE_POSITIVE) < 0 || newDecimal + .compareTo(MAX_DOUBLE_POSITIVE) > 0); + } + + public static void validateDoubleNotOverFlow(final BigDecimal decimal) { + boolean isOverFlow = OverFlowUtil.isDoubleOverFlow(decimal); + if (isOverFlow) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_OVER_FLOW, + String.format("[%s]转为Double类型出现溢出 .", + decimal.toPlainString())); + } + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/Record.java b/common/src/main/java/com/alibaba/datax/common/element/Record.java new file mode 100755 index 000000000..d06d80aaf --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/Record.java @@ -0,0 +1,23 @@ +package com.alibaba.datax.common.element; + +/** + * Created by jingxing on 14-8-24. + */ + +public interface Record { + + public void addColumn(Column column); + + public void setColumn(int i, final Column column); + + public Column getColumn(int i); + + public String toString(); + + public int getColumnNumber(); + + public int getByteSize(); + + public int getMemorySize(); + +} diff --git a/common/src/main/java/com/alibaba/datax/common/element/StringColumn.java b/common/src/main/java/com/alibaba/datax/common/element/StringColumn.java new file mode 100755 index 000000000..11209f468 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/element/StringColumn.java @@ -0,0 +1,163 @@ +package com.alibaba.datax.common.element; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; + +/** + * Created by jingxing on 14-8-24. + */ + +public class StringColumn extends Column { + + public StringColumn() { + this((String) null); + } + + public StringColumn(final String rawData) { + super(rawData, Column.Type.STRING, (null == rawData ? 0 : rawData + .length())); + } + + @Override + public String asString() { + if (null == this.getRawData()) { + return null; + } + + return (String) this.getRawData(); + } + + private void validateDoubleSpecific(final String data) { + if ("NaN".equals(data) || "Infinity".equals(data) + || "-Infinity".equals(data)) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[\"%s\"]属于Double特殊类型,不能转为其他类型 .", data)); + } + + return; + } + + @Override + public BigInteger asBigInteger() { + if (null == this.getRawData()) { + return null; + } + + this.validateDoubleSpecific((String) this.getRawData()); + + try { + return this.asBigDecimal().toBigInteger(); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, String.format( + "String[\"%s\"]不能转为BigInteger .", this.asString())); + } + } + + @Override + public Long asLong() { + if (null == this.getRawData()) { + return null; + } + + this.validateDoubleSpecific((String) this.getRawData()); + + try { + BigInteger integer = this.asBigInteger(); + OverFlowUtil.validateLongNotOverFlow(integer); + return integer.longValue(); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[\"%s\"]不能转为Long .", this.asString())); + } + } + + @Override + public BigDecimal asBigDecimal() { + if (null == this.getRawData()) { + return null; + } + + this.validateDoubleSpecific((String) this.getRawData()); + + try { + return new BigDecimal(this.asString()); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, String.format( + "String [\"%s\"] 不能转为BigDecimal .", this.asString())); + } + } + + @Override + public Double asDouble() { + if (null == this.getRawData()) { + return null; + } + + String data = (String) this.getRawData(); + if ("NaN".equals(data)) { + return Double.NaN; + } + + if ("Infinity".equals(data)) { + return Double.POSITIVE_INFINITY; + } + + if ("-Infinity".equals(data)) { + return Double.NEGATIVE_INFINITY; + } + + BigDecimal decimal = this.asBigDecimal(); + OverFlowUtil.validateDoubleNotOverFlow(decimal); + + return decimal.doubleValue(); + } + + @Override + public Boolean asBoolean() { + if (null == this.getRawData()) { + return null; + } + + if ("true".equalsIgnoreCase(this.asString())) { + return true; + } + + if ("false".equalsIgnoreCase(this.asString())) { + return false; + } + + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[\"%s\"]不能转为Bool .", this.asString())); + } + + @Override + public Date asDate() { + try { + return ColumnCast.string2Date(this); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[\"%s\"]不能转为Date .", this.asString())); + } + } + + @Override + public byte[] asBytes() { + try { + return ColumnCast.string2Bytes(this); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONVERT_NOT_SUPPORT, + String.format("String[\"%s\"]不能转为Bytes .", this.asString())); + } + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/exception/CommonErrorCode.java b/common/src/main/java/com/alibaba/datax/common/exception/CommonErrorCode.java new file mode 100755 index 000000000..8679ffb47 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/exception/CommonErrorCode.java @@ -0,0 +1,45 @@ +package com.alibaba.datax.common.exception; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * + */ +public enum CommonErrorCode implements ErrorCode { + + CONFIG_ERROR("Common-00", "您提供的配置文件存在错误信息,请检查您的作业配置 ."), + CONVERT_NOT_SUPPORT("Common-01", "同步数据出现业务脏数据情况,数据类型转换错误 ."), + CONVERT_OVER_FLOW("Common-02", "同步数据出现业务脏数据情况,数据类型转换溢出 ."), + RETRY_FAIL("Common-10", "方法调用多次仍旧失败 ."), + RUNTIME_ERROR("Common-11", "运行时内部调用错误 ."), + HOOK_INTERNAL_ERROR("Common-12", "Hook运行错误 ."), + SHUT_DOWN_TASK("Common-20", "Task收到了shutdown指令,为failover做准备"), + WAIT_TIME_EXCEED("Common-21", "等待时间超出范围"), + TASK_HUNG_EXPIRED("Common-22", "任务hung住,Expired"); + + private final String code; + + private final String describe; + + private CommonErrorCode(String code, String describe) { + this.code = code; + this.describe = describe; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.describe; + } + + @Override + public String toString() { + return String.format("Code:[%s], Describe:[%s]", this.code, + this.describe); + } + +} diff --git a/common/src/main/java/com/alibaba/datax/common/exception/DataXException.java b/common/src/main/java/com/alibaba/datax/common/exception/DataXException.java new file mode 100755 index 000000000..9def28de7 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/exception/DataXException.java @@ -0,0 +1,60 @@ +package com.alibaba.datax.common.exception; + +import com.alibaba.datax.common.spi.ErrorCode; + +public class DataXException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private ErrorCode errorCode; + + public DataXException(ErrorCode errorCode, String errorMessage) { + super(errorCode.toString() + " - " + errorMessage); + this.errorCode = errorCode; + } + + private DataXException(ErrorCode errorCode, String errorMessage, + Throwable cause) { + super(errorCode.toString() + " - " + getMessage(errorMessage) + + " - " + getMessage(cause), cause); + + this.errorCode = errorCode; + } + + public static DataXException asDataXException(ErrorCode errorCode, String message) { + return new DataXException(errorCode, message); + } + + public static DataXException asDataXException(ErrorCode errorCode, String message, + Throwable cause) { + if (cause instanceof DataXException) { + return (DataXException) cause; + } + return new DataXException(errorCode, message, cause); + } + + public static DataXException asDataXException(ErrorCode errorCode, + Throwable cause) { + if (cause instanceof DataXException) { + return (DataXException) cause; + } + return new DataXException(errorCode, getMessage(cause), cause); + } + + public ErrorCode getErrorCode() { + return this.errorCode; + } + + + private static String getMessage(Object obj) { + if (obj == null) { + return ""; + } + + if (obj instanceof Throwable) { + return ((Throwable) obj).getMessage(); + } else { + return obj.toString(); + } + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/exception/ExceptionTracker.java b/common/src/main/java/com/alibaba/datax/common/exception/ExceptionTracker.java new file mode 100644 index 000000000..f6d3732e2 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/exception/ExceptionTracker.java @@ -0,0 +1,15 @@ +package com.alibaba.datax.common.exception; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public final class ExceptionTracker { + public static final int STRING_BUFFER = 1024; + + public static String trace(Throwable ex) { + StringWriter sw = new StringWriter(STRING_BUFFER); + PrintWriter pw = new PrintWriter(sw); + ex.printStackTrace(pw); + return sw.toString(); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/AbstractJobPlugin.java b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractJobPlugin.java new file mode 100755 index 000000000..946adfd0e --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractJobPlugin.java @@ -0,0 +1,25 @@ +package com.alibaba.datax.common.plugin; + +/** + * Created by jingxing on 14-8-24. + */ +public abstract class AbstractJobPlugin extends AbstractPlugin { + /** + * @return the jobPluginCollector + */ + public JobPluginCollector getJobPluginCollector() { + return jobPluginCollector; + } + + /** + * @param jobPluginCollector + * the jobPluginCollector to set + */ + public void setJobPluginCollector( + JobPluginCollector jobPluginCollector) { + this.jobPluginCollector = jobPluginCollector; + } + + private JobPluginCollector jobPluginCollector; + +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/AbstractPlugin.java b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractPlugin.java new file mode 100755 index 000000000..184ee89ec --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractPlugin.java @@ -0,0 +1,87 @@ +package com.alibaba.datax.common.plugin; + +import com.alibaba.datax.common.base.BaseObject; +import com.alibaba.datax.common.util.Configuration; + +public abstract class AbstractPlugin extends BaseObject implements Pluginable { + //作业的config + private Configuration pluginJobConf; + + //插件本身的plugin + private Configuration pluginConf; + + // by qiangsi.lq。 修改为对端的作业configuration + private Configuration peerPluginJobConf; + + private String peerPluginName; + + @Override + public String getPluginName() { + assert null != this.pluginConf; + return this.pluginConf.getString("name"); + } + + @Override + public String getDeveloper() { + assert null != this.pluginConf; + return this.pluginConf.getString("developer"); + } + + @Override + public String getDescription() { + assert null != this.pluginConf; + return this.pluginConf.getString("description"); + } + + @Override + public Configuration getPluginJobConf() { + return pluginJobConf; + } + + @Override + public void setPluginJobConf(Configuration pluginJobConf) { + this.pluginJobConf = pluginJobConf; + } + + @Override + public void setPluginConf(Configuration pluginConf) { + this.pluginConf = pluginConf; + } + + @Override + public Configuration getPeerPluginJobConf() { + return peerPluginJobConf; + } + + @Override + public void setPeerPluginJobConf(Configuration peerPluginJobConf) { + this.peerPluginJobConf = peerPluginJobConf; + } + + @Override + public String getPeerPluginName() { + return peerPluginName; + } + + @Override + public void setPeerPluginName(String peerPluginName) { + this.peerPluginName = peerPluginName; + } + + public void preCheck() { + } + + public void prepare() { + } + + public void post() { + } + + public void preHandler(Configuration jobConfiguration){ + + } + + public void postHandler(Configuration jobConfiguration){ + + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/AbstractTaskPlugin.java b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractTaskPlugin.java new file mode 100755 index 000000000..39fbbe9b5 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/AbstractTaskPlugin.java @@ -0,0 +1,37 @@ +package com.alibaba.datax.common.plugin; + +/** + * Created by jingxing on 14-8-24. + */ +public abstract class AbstractTaskPlugin extends AbstractPlugin { + + //TaskPlugin 应该具备taskId + private int taskGroupId; + private int taskId; + private TaskPluginCollector taskPluginCollector; + + public TaskPluginCollector getTaskPluginCollector() { + return taskPluginCollector; + } + + public void setTaskPluginCollector( + TaskPluginCollector taskPluginCollector) { + this.taskPluginCollector = taskPluginCollector; + } + + public int getTaskId() { + return taskId; + } + + public void setTaskId(int taskId) { + this.taskId = taskId; + } + + public int getTaskGroupId() { + return taskGroupId; + } + + public void setTaskGroupId(int taskGroupId) { + this.taskGroupId = taskGroupId; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/JobPluginCollector.java b/common/src/main/java/com/alibaba/datax/common/plugin/JobPluginCollector.java new file mode 100755 index 000000000..6eb02ab4e --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/JobPluginCollector.java @@ -0,0 +1,22 @@ +package com.alibaba.datax.common.plugin; + +import java.util.List; +import java.util.Map; + +/** + * Created by jingxing on 14-9-9. + */ +public interface JobPluginCollector extends PluginCollector { + + /** + * 从Task获取自定义收集信息 + * + * */ + Map> getMessage(); + + /** + * 从Task获取自定义收集信息 + * + * */ + List getMessage(String key); +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/PluginCollector.java b/common/src/main/java/com/alibaba/datax/common/plugin/PluginCollector.java new file mode 100755 index 000000000..f2af398dd --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/PluginCollector.java @@ -0,0 +1,9 @@ +package com.alibaba.datax.common.plugin; + + +/** + * 这里只是一个标示类 + * */ +public interface PluginCollector { + +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/Pluginable.java b/common/src/main/java/com/alibaba/datax/common/plugin/Pluginable.java new file mode 100755 index 000000000..ac28f6a29 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/Pluginable.java @@ -0,0 +1,30 @@ +package com.alibaba.datax.common.plugin; + +import com.alibaba.datax.common.util.Configuration; + +public interface Pluginable { + String getDeveloper(); + + String getDescription(); + + void setPluginConf(Configuration pluginConf); + + void init(); + + void destroy(); + + String getPluginName(); + + Configuration getPluginJobConf(); + + Configuration getPeerPluginJobConf(); + + public String getPeerPluginName(); + + void setPluginJobConf(Configuration jobConf); + + void setPeerPluginJobConf(Configuration peerPluginJobConf); + + public void setPeerPluginName(String peerPluginName); + +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/RecordReceiver.java b/common/src/main/java/com/alibaba/datax/common/plugin/RecordReceiver.java new file mode 100755 index 000000000..74f236f37 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/RecordReceiver.java @@ -0,0 +1,26 @@ +/** + * (C) 2010-2013 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.common.plugin; + +import com.alibaba.datax.common.element.Record; + +public interface RecordReceiver { + + public Record getFromReader(); + + public void shutdown(); +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/RecordSender.java b/common/src/main/java/com/alibaba/datax/common/plugin/RecordSender.java new file mode 100755 index 000000000..0d6926098 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/RecordSender.java @@ -0,0 +1,32 @@ +/** + * (C) 2010-2013 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.common.plugin; + +import com.alibaba.datax.common.element.Record; + +public interface RecordSender { + + public Record createRecord(); + + public void sendToWriter(Record record); + + public void flush(); + + public void terminate(); + + public void shutdown(); +} diff --git a/common/src/main/java/com/alibaba/datax/common/plugin/TaskPluginCollector.java b/common/src/main/java/com/alibaba/datax/common/plugin/TaskPluginCollector.java new file mode 100755 index 000000000..f0c85fe6c --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/plugin/TaskPluginCollector.java @@ -0,0 +1,57 @@ +package com.alibaba.datax.common.plugin; + +import com.alibaba.datax.common.element.Record; + +/** + * + * 该接口提供给Task Plugin用来记录脏数据和自定义信息。
+ * + * 1. 脏数据记录,TaskPluginCollector提供多种脏数据记录的适配,包括本地输出、集中式汇报等等
+ * 2. 自定义信息,所有的task插件运行过程中可以通过TaskPluginCollector收集信息,
+ * Job的插件在POST过程中通过getMessage()接口获取信息 + */ +public abstract class TaskPluginCollector implements PluginCollector { + /** + * 收集脏数据 + * + * @param dirtyRecord + * 脏数据信息 + * @param t + * 异常信息 + * @param errorMessage + * 错误的提示信息 + */ + public abstract void collectDirtyRecord(final Record dirtyRecord, + final Throwable t, final String errorMessage); + + /** + * 收集脏数据 + * + * @param dirtyRecord + * 脏数据信息 + * @param errorMessage + * 错误的提示信息 + */ + public void collectDirtyRecord(final Record dirtyRecord, + final String errorMessage) { + this.collectDirtyRecord(dirtyRecord, null, errorMessage); + } + + /** + * 收集脏数据 + * + * @param dirtyRecord + * 脏数据信息 + * @param t + * 异常信息 + */ + public void collectDirtyRecord(final Record dirtyRecord, final Throwable t) { + this.collectDirtyRecord(dirtyRecord, t, ""); + } + + /** + * 收集自定义信息,Job插件可以通过getMessage获取该信息
+ * 如果多个key冲突,内部使用List记录同一个key,多个value情况。
+ * */ + public abstract void collectMessage(final String key, final String value); +} diff --git a/common/src/main/java/com/alibaba/datax/common/spi/ErrorCode.java b/common/src/main/java/com/alibaba/datax/common/spi/ErrorCode.java new file mode 100755 index 000000000..053f99a47 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/spi/ErrorCode.java @@ -0,0 +1,33 @@ +package com.alibaba.datax.common.spi; + +/** + * 尤其注意:最好提供toString()实现。例如: + * + *

+ * 
+ * @Override
+ * public String toString() {
+ * 	return String.format("Code:[%s], Description:[%s]. ", this.code, this.describe);
+ * }
+ * 
+ * + */ +public interface ErrorCode { + // 错误码编号 + String getCode(); + + // 错误码描述 + String getDescription(); + + /** 必须提供toString的实现 + * + *
+	 * @Override
+	 * public String toString() {
+	 * 	return String.format("Code:[%s], Description:[%s]. ", this.code, this.describe);
+	 * }
+	 * 
+ * + */ + String toString(); +} diff --git a/common/src/main/java/com/alibaba/datax/common/spi/Hook.java b/common/src/main/java/com/alibaba/datax/common/spi/Hook.java new file mode 100755 index 000000000..d510f57c1 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/spi/Hook.java @@ -0,0 +1,27 @@ +package com.alibaba.datax.common.spi; + +import com.alibaba.datax.common.util.Configuration; + +import java.util.Map; + +/** + * Created by xiafei.qiuxf on 14/12/17. + */ +public interface Hook { + + /** + * 返回名字 + * + * @return + */ + public String getName(); + + /** + * TODO 文档 + * + * @param jobConf + * @param msg + */ + public void invoke(Configuration jobConf, Map msg); + +} diff --git a/common/src/main/java/com/alibaba/datax/common/spi/Reader.java b/common/src/main/java/com/alibaba/datax/common/spi/Reader.java new file mode 100755 index 000000000..fec41a9f0 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/spi/Reader.java @@ -0,0 +1,52 @@ +package com.alibaba.datax.common.spi; + +import java.util.List; + +import com.alibaba.datax.common.base.BaseObject; +import com.alibaba.datax.common.plugin.AbstractJobPlugin; +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.plugin.RecordSender; + +/** + * 每个Reader插件在其内部内部实现Job、Task两个内部类。 + * + * + * */ +public abstract class Reader extends BaseObject { + + /** + * 每个Reader插件必须实现Job内部类。 + * + * */ + public static abstract class Job extends AbstractJobPlugin { + + /** + * 切分任务 + * + * @param adviceNumber + * + * 着重说明下,adviceNumber是框架建议插件切分的任务数,插件开发人员最好切分出来的任务数>= + * adviceNumber。
+ *
+ * 之所以采取这个建议是为了给用户最好的实现,例如框架根据计算认为用户数据存储可以支持100个并发连接, + * 并且用户认为需要100个并发。 此时,插件开发人员如果能够根据上述切分规则进行切分并做到>=100连接信息, + * DataX就可以同时启动100个Channel,这样给用户最好的吞吐量
+ * 例如用户同步一张Mysql单表,但是认为可以到10并发吞吐量,插件开发人员最好对该表进行切分,比如使用主键范围切分, + * 并且如果最终切分任务数到>=10,我们就可以提供给用户最大的吞吐量。
+ *
+ * 当然,我们这里只是提供一个建议值,Reader插件可以按照自己规则切分。但是我们更建议按照框架提供的建议值来切分。
+ *
+ * 对于ODPS写入OTS而言,如果存在预排序预切分问题,这样就可能只能按照分区信息切分,无法更细粒度切分, + * 这类情况只能按照源头物理信息切分规则切分。
+ *
+ * + * + * */ + public abstract List split(int adviceNumber); + } + + public static abstract class Task extends AbstractTaskPlugin { + public abstract void startRead(RecordSender recordSender); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/spi/Writer.java b/common/src/main/java/com/alibaba/datax/common/spi/Writer.java new file mode 100755 index 000000000..457eb6860 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/spi/Writer.java @@ -0,0 +1,40 @@ +package com.alibaba.datax.common.spi; + +import com.alibaba.datax.common.base.BaseObject; +import com.alibaba.datax.common.plugin.AbstractJobPlugin; +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.plugin.RecordReceiver; + +import java.util.List; + +/** + * 每个Writer插件需要实现Writer类,并在其内部实现Job、Task两个内部类。 + * + * + * */ +public abstract class Writer extends BaseObject { + /** + * 每个Writer插件必须实现Job内部类 + */ + public abstract static class Job extends AbstractJobPlugin { + /** + * 切分任务。
+ * + * @param mandatoryNumber + * 为了做到Reader、Writer任务数对等,这里要求Writer插件必须按照源端的切分数进行切分。否则框架报错! + * + * */ + public abstract List split(int mandatoryNumber); + } + + /** + * 每个Writer插件必须实现Task内部类 + */ + public abstract static class Task extends AbstractTaskPlugin { + + public abstract void startWrite(RecordReceiver lineReceiver); + + public boolean supportFailOver(){return false;} + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/statistics/PerfRecord.java b/common/src/main/java/com/alibaba/datax/common/statistics/PerfRecord.java new file mode 100644 index 000000000..5174fcad2 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/statistics/PerfRecord.java @@ -0,0 +1,246 @@ +package com.alibaba.datax.common.statistics; + +import com.alibaba.datax.common.util.HostUtils; +import com.google.common.base.Objects; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +/** + * Created by liqiang on 15/8/23. + */ +public class PerfRecord implements Comparable { + private static Logger perf = LoggerFactory.getLogger(PerfRecord.class); + private static String datetimeFormat = "yyyy-MM-dd HH:mm:ss"; + + + public enum PHASE { + /** + * task total运行的时间,前10为框架统计,后面为部分插件的个性统计 + */ + TASK_TOTAL(0), + + READ_TASK_INIT(1), + READ_TASK_PREPARE(2), + READ_TASK_DATA(3), + READ_TASK_POST(4), + READ_TASK_DESTROY(5), + + WRITE_TASK_INIT(6), + WRITE_TASK_PREPARE(7), + WRITE_TASK_DATA(8), + WRITE_TASK_POST(9), + WRITE_TASK_DESTROY(10), + + /** + * SQL_QUERY: sql query阶段, 部分reader的个性统计 + */ + SQL_QUERY(100), + /** + * 数据从sql全部读出来 + */ + RESULT_NEXT_ALL(101), + + /** + * only odps block close + */ + ODPS_BLOCK_CLOSE(102), + + WAIT_READ_TIME(103), + + WAIT_WRITE_TIME(104); + + private int val; + + PHASE(int val) { + this.val = val; + } + + public int toInt(){ + return val; + } + } + + public enum ACTION{ + start, + end + } + + private final int taskGroupId; + private final int taskId; + private final PHASE phase; + private volatile ACTION action; + private volatile Date startTime; + private volatile long elapsedTimeInNs = -1; + private volatile long count = 0; + private volatile long size = 0; + + private volatile long startTimeInNs; + private volatile boolean isReport = false; + + public PerfRecord(int taskGroupId, int taskId, PHASE phase) { + this.taskGroupId = taskGroupId; + this.taskId = taskId; + this.phase = phase; + } + + public static void addPerfRecord(int taskGroupId, int taskId, PHASE phase, long startTime,long elapsedTimeInNs) { + if(PerfTrace.getInstance().isEnable()) { + PerfRecord perfRecord = new PerfRecord(taskGroupId, taskId, phase); + perfRecord.elapsedTimeInNs = elapsedTimeInNs; + perfRecord.action = ACTION.end; + perfRecord.startTime = new Date(startTime); + //在PerfTrace里注册 + PerfTrace.getInstance().tracePerfRecord(perfRecord); + perf.info(perfRecord.toString()); + } + } + + public void start() { + if(PerfTrace.getInstance().isEnable()) { + this.startTime = new Date(); + this.startTimeInNs = System.nanoTime(); + this.action = ACTION.start; + //在PerfTrace里注册 + PerfTrace.getInstance().tracePerfRecord(this); + perf.info(toString()); + } + } + + public void addCount(long count) { + this.count += count; + } + + public void addSize(long size) { + this.size += size; + } + + public void end() { + if(PerfTrace.getInstance().isEnable()) { + this.elapsedTimeInNs = System.nanoTime() - startTimeInNs; + this.action = ACTION.end; + PerfTrace.getInstance().tracePerfRecord(this); + perf.info(toString()); + } + } + + public void end(long elapsedTimeInNs) { + if(PerfTrace.getInstance().isEnable()) { + this.elapsedTimeInNs = elapsedTimeInNs; + this.action = ACTION.end; + perf.info(toString()); + } + } + + public String toString() { + return String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" + , getJobId(), taskGroupId, taskId, phase, action, + DateFormatUtils.format(startTime, datetimeFormat), elapsedTimeInNs, count, size,getHostIP()); + } + + + @Override + public int compareTo(PerfRecord o) { + if (o == null) { + return 1; + } + return this.elapsedTimeInNs > o.elapsedTimeInNs ? 1 : this.elapsedTimeInNs == o.elapsedTimeInNs ? 0 : -1; + } + + @Override + public int hashCode() { + return Objects.hashCode(getJobId(),taskGroupId,taskId,phase,startTime); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if(!(o instanceof PerfRecord)){ + return false; + } + + PerfRecord dst = (PerfRecord)o; + + if(!Objects.equal(this.getJobId(),dst.getJobId())) return false; + if(!Objects.equal(this.taskGroupId,dst.taskGroupId)) return false; + if(!Objects.equal(this.taskId,dst.taskId)) return false; + if(!Objects.equal(this.phase,dst.phase)) return false; + if(!Objects.equal(this.startTime,dst.startTime)) return false; + + return true; + } + + public PerfRecord copy() { + PerfRecord copy = new PerfRecord(this.taskGroupId, this.getTaskId(), this.phase); + copy.action = this.action; + copy.startTime = this.startTime; + copy.elapsedTimeInNs = this.elapsedTimeInNs; + copy.count = this.count; + copy.size = this.size; + return copy; + } + public int getTaskGroupId() { + return taskGroupId; + } + + public int getTaskId() { + return taskId; + } + + public PHASE getPhase() { + return phase; + } + + public ACTION getAction() { + return action; + } + + public long getElapsedTimeInNs() { + return elapsedTimeInNs; + } + + public long getCount() { + return count; + } + + public long getSize() { + return size; + } + + public long getJobId(){ + return PerfTrace.getInstance().getJobId(); + } + + public String getHostIP(){ + return HostUtils.IP; + } + + public String getHostName(){ + return HostUtils.HOSTNAME; + } + + public Date getStartTime() { + return startTime; + } + + public long getStartTimeInNs() { + return startTimeInNs; + } + + public String getDatetime(){ + if(startTime == null){ + return "null time"; + } + return DateFormatUtils.format(startTime, datetimeFormat); + } + + public boolean isReport() { + return isReport; + } + + public void setIsReport(boolean isReport) { + this.isReport = isReport; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/statistics/PerfTrace.java b/common/src/main/java/com/alibaba/datax/common/statistics/PerfTrace.java new file mode 100644 index 000000000..eb0706079 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/statistics/PerfTrace.java @@ -0,0 +1,422 @@ +package com.alibaba.datax.common.statistics; + +import com.alibaba.datax.common.util.Configuration; +import com.google.common.base.Optional; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * PerfTrace 记录 job(local模式),taskGroup(distribute模式),因为这2种都是jvm,即一个jvm里只需要有1个PerfTrace。 + */ + +public class PerfTrace { + + private static Logger LOG = LoggerFactory.getLogger(PerfTrace.class); + private static PerfTrace instance; + private static final Object lock = new Object(); + private String perfTraceId; + private volatile boolean enable; + private volatile boolean isJob; + private long jobId; + private int priority; + private int batchSize = 500; + private volatile boolean perfReportEnalbe = true; + + //jobid_jobversion,instanceid,taskid, src_mark, dst_mark, + private Map taskDetails = new ConcurrentHashMap(); + //PHASE => PerfRecord + private ConcurrentHashMap perfRecordMaps = new ConcurrentHashMap(); + private Configuration jobInfo; + private final List startReportPool = new ArrayList(); + private final List endReportPool = new ArrayList(); + private final List totalEndReport = new ArrayList(); + private final Set waitingReportSet = new HashSet(); + + + /** + * 单实例 + * + * @param isJob + * @param jobId + * @param taskGroupId + * @return + */ + public static PerfTrace getInstance(boolean isJob, long jobId, int taskGroupId,int priority, boolean enable) { + + if (instance == null) { + synchronized (lock) { + if (instance == null) { + instance = new PerfTrace(isJob, jobId, taskGroupId,priority, enable); + } + } + } + return instance; + } + + /** + * 因为一个JVM只有一个,因此在getInstance(isJob,jobId,taskGroupId)调用完成实例化后,方便后续调用,直接返回该实例 + * + * @return + */ + public static PerfTrace getInstance() { + if (instance == null) { + LOG.error("PerfTrace instance not be init! must have some error! "); + synchronized (lock) { + if (instance == null) { + instance = new PerfTrace(false, -1111, -1111, 0, false); + } + } + } + return instance; + } + + private PerfTrace(boolean isJob, long jobId, int taskGroupId, int priority, boolean enable) { + this.perfTraceId = isJob ? "job_" + jobId : String.format("taskGroup_%s_%s", jobId, taskGroupId); + this.enable = enable; + this.isJob = isJob; + this.jobId = jobId; + this.priority = priority; + LOG.info(String.format("PerfTrace traceId=%s, isEnable=%s, priority=%s", this.perfTraceId, this.enable, this.priority)); + + } + + public void addTaskDetails(int taskId, String detail) { + if (enable) { + String before = ""; + int index = detail.indexOf("?"); + String current = detail.substring(0, index == -1 ? detail.length() : index); + if(current.indexOf("[")>=0){ + current+="]"; + } + if (taskDetails.containsKey(taskId)) { + before = taskDetails.get(taskId).trim(); + } + if (StringUtils.isEmpty(before)) { + before = ""; + } else { + before += ","; + } + this.taskDetails.put(taskId, before + current); + } + } + + public void tracePerfRecord(PerfRecord perfRecord) { + if (enable) { + //ArrayList非线程安全 + switch (perfRecord.getAction()) { + case start: + synchronized (startReportPool) { + startReportPool.add(perfRecord); + } + break; + case end: + synchronized (endReportPool) { + endReportPool.add(perfRecord); + } + break; + } + } + } + + public String summarizeNoException(){ + String res; + try { + res = summarize(); + } catch (Exception e) { + res = "PerfTrace summarize has Exception "+e.getMessage(); + } + return res; + } + + //任务结束时,对当前的perf总汇总统计 + private synchronized String summarize() { + if (!enable) { + return "PerfTrace not enable!"; + } + + if (totalEndReport.size() > 0) { + sumEndPerfRecords(totalEndReport); + } + + StringBuilder info = new StringBuilder(); + info.append("\n === total summarize info === \n"); + info.append("\n 1. all phase average time info and max time task info: \n\n"); + info.append(String.format("%-20s | %18s | %18s | %18s | %18s | %-100s\n", "PHASE", "AVERAGE USED TIME", "ALL TASK NUM", "MAX USED TIME", "MAX TASK ID", "MAX TASK INFO")); + + List keys = new ArrayList(perfRecordMaps.keySet()); + Collections.sort(keys, new Comparator() { + @Override + public int compare(PerfRecord.PHASE o1, PerfRecord.PHASE o2) { + return o1.toInt() - o2.toInt(); + } + }); + for (PerfRecord.PHASE phase : keys) { + SumPerfRecord sumPerfRecord = perfRecordMaps.get(phase); + if (sumPerfRecord == null) { + continue; + } + long averageTime = sumPerfRecord.getAverageTime(); + long maxTime = sumPerfRecord.getMaxTime(); + int maxTaskId = sumPerfRecord.maxTaskId; + int maxTaskGroupId = sumPerfRecord.getMaxTaskGroupId(); + info.append(String.format("%-20s | %18s | %18s | %18s | %18s | %-100s\n", + phase, unitTime(averageTime), sumPerfRecord.totalCount, unitTime(maxTime), jobId + "-" + maxTaskGroupId + "-" + maxTaskId, taskDetails.get(maxTaskId))); + } + + SumPerfRecord countSumPerf = Optional.fromNullable(perfRecordMaps.get(PerfRecord.PHASE.READ_TASK_DATA)).or(new SumPerfRecord()); + + long averageRecords = countSumPerf.getAverageRecords(); + long averageBytes = countSumPerf.getAverageBytes(); + long maxRecord = countSumPerf.getMaxRecord(); + long maxByte = countSumPerf.getMaxByte(); + int maxTaskId4Records = countSumPerf.getMaxTaskId4Records(); + int maxTGID4Records = countSumPerf.getMaxTGID4Records(); + + info.append("\n\n 2. record average count and max count task info :\n\n"); + info.append(String.format("%-20s | %18s | %18s | %18s | %18s | %18s | %-100s\n", "PHASE", "AVERAGE RECORDS", "AVERAGE BYTES", "MAX RECORDS", "MAX RECORD`S BYTES", "MAX TASK ID", "MAX TASK INFO")); + if (maxTaskId4Records > -1) { + info.append(String.format("%-20s | %18s | %18s | %18s | %18s | %18s | %-100s\n" + , PerfRecord.PHASE.READ_TASK_DATA, averageRecords, unitSize(averageBytes), maxRecord, unitSize(maxByte), jobId + "-" + maxTGID4Records + "-" + maxTaskId4Records, taskDetails.get(maxTaskId4Records))); + + } + return info.toString(); + } + + //缺省传入的时间是nano + public static String unitTime(long time) { + return unitTime(time, TimeUnit.NANOSECONDS); + } + + public static String unitTime(long time, TimeUnit timeUnit) { + return String.format("%,.3fs", ((float) timeUnit.toNanos(time)) / 1000000000); + } + + public static String unitSize(long size) { + if (size > 1000000000) { + return String.format("%,.2fG", (float) size / 1000000000); + } else if (size > 1000000) { + return String.format("%,.2fM", (float) size / 1000000); + } else if (size > 1000) { + return String.format("%,.2fK", (float) size / 1000); + } else { + return size + "B"; + } + } + + + public synchronized ConcurrentHashMap getPerfRecordMaps() { + synchronized (endReportPool) { + // perfRecordMaps.get(perfRecord.getPhase()).add(perfRecord); + waitingReportSet.addAll(endReportPool); + totalEndReport.addAll(endReportPool); + endReportPool.clear(); + } + if(totalEndReport.size() > 0 ){ + sumEndPerfRecords(totalEndReport); + } + return perfRecordMaps; + } + + public List getWaitingReportList() { + return new ArrayList(waitingReportSet); + } + + public List getStartReportPool() { + return startReportPool; + } + + public List getEndReportPool() { + return endReportPool; + } + + public List getTotalEndReport() { + return totalEndReport; + } + + public Map getTaskDetails() { + return taskDetails; + } + + public boolean isEnable() { + return enable; + } + + public boolean isJob() { + return isJob; + } + + public long getJobId() { + return jobId; + } + + private String cluster; + private String jobDomain; + private String srcType; + private String dstType; + private String srcGuid; + private String dstGuid; + private String dataxType; + + public void setJobInfo(Configuration jobInfo) { + this.jobInfo = jobInfo; + if (jobInfo != null) { + cluster = jobInfo.getString("cluster"); + + String srcDomain = jobInfo.getString("srcDomain", "null"); + String dstDomain = jobInfo.getString("dstDomain", "null"); + jobDomain = srcDomain + "|" + dstDomain; + srcType = jobInfo.getString("srcType"); + dstType = jobInfo.getString("dstType"); + srcGuid = jobInfo.getString("srcGuid"); + dstGuid = jobInfo.getString("dstGuid"); + long jobId = jobInfo.getLong("jobId"); + if (jobId > 0) { + //同步中心任务 + dataxType = "dsc"; + } else { + dataxType = "datax3"; + } + } else { + dataxType = "datax3"; + } + } + + public Configuration getJobInfo() { + return jobInfo; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + public void setPerfReportEnalbe(boolean perfReportEnalbe) { + this.perfReportEnalbe = perfReportEnalbe; + } + + + private void sumEndPerfRecords(List totalEndReport) { + if (!enable || totalEndReport == null) { + return; + } + + for (PerfRecord perfRecord : totalEndReport) { + perfRecordMaps.putIfAbsent(perfRecord.getPhase(), new SumPerfRecord()); + perfRecordMaps.get(perfRecord.getPhase()).add(perfRecord); + } + + totalEndReport.clear(); + } + + + + public static class SumPerfRecord { + private long perfTimeTotal = 0; + private long averageTime = 0; + private long maxTime = 0; + private int maxTaskId = -1; + private int maxTaskGroupId = -1; + private int totalCount = 0; + + private long recordsTotal = 0; + private long sizesTotal = 0; + private long averageRecords = 0; + private long averageBytes = 0; + private long maxRecord = 0; + private long maxByte = 0; + private int maxTaskId4Records = -1; + private int maxTGID4Records = -1; + + synchronized void add(PerfRecord perfRecord) { + if (perfRecord == null) { + return; + } + perfTimeTotal += perfRecord.getElapsedTimeInNs(); + if (perfRecord.getElapsedTimeInNs() > maxTime) { + maxTime = perfRecord.getElapsedTimeInNs(); + maxTaskId = perfRecord.getTaskId(); + maxTaskGroupId = perfRecord.getTaskGroupId(); + } + + recordsTotal += perfRecord.getCount(); + sizesTotal += perfRecord.getSize(); + if (perfRecord.getCount() > maxRecord) { + maxRecord = perfRecord.getCount(); + maxByte = perfRecord.getSize(); + maxTaskId4Records = perfRecord.getTaskId(); + maxTGID4Records = perfRecord.getTaskGroupId(); + } + + totalCount++; + } + + public long getPerfTimeTotal() { + return perfTimeTotal; + } + + public long getAverageTime() { + if (totalCount > 0) { + averageTime = perfTimeTotal / totalCount; + } + return averageTime; + } + + public long getMaxTime() { + return maxTime; + } + + public int getMaxTaskId() { + return maxTaskId; + } + + public int getMaxTaskGroupId() { + return maxTaskGroupId; + } + + public long getRecordsTotal() { + return recordsTotal; + } + + public long getSizesTotal() { + return sizesTotal; + } + + public long getAverageRecords() { + if (totalCount > 0) { + averageRecords = recordsTotal / totalCount; + } + return averageRecords; + } + + public long getAverageBytes() { + if (totalCount > 0) { + averageBytes = sizesTotal / totalCount; + } + return averageBytes; + } + + public long getMaxRecord() { + return maxRecord; + } + + public long getMaxByte() { + return maxByte; + } + + public int getMaxTaskId4Records() { + return maxTaskId4Records; + } + + public int getMaxTGID4Records() { + return maxTGID4Records; + } + + public int getTotalCount() { + return totalCount; + } + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/statistics/VMInfo.java b/common/src/main/java/com/alibaba/datax/common/statistics/VMInfo.java new file mode 100644 index 000000000..85535fddd --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/statistics/VMInfo.java @@ -0,0 +1,412 @@ +package com.alibaba.datax.common.statistics; + +import com.google.common.collect.Maps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +/** + * Created by liqiang on 15/11/12. + */ +public class VMInfo { + private static final Logger LOG = LoggerFactory.getLogger(VMInfo.class); + static final long MB = 1024 * 1024; + static final long GB = 1024 * 1024 * 1024; + public static Object lock = new Object(); + private static VMInfo vmInfo; + + /** + * @return null or vmInfo. null is something error, job no care it. + */ + public static VMInfo getVmInfo() { + if (vmInfo == null) { + synchronized (lock) { + if (vmInfo == null) { + try { + vmInfo = new VMInfo(); + } catch (Exception e) { + LOG.warn("no need care, the fail is ignored : vmInfo init failed " + e.getMessage(), e); + } + } + } + + } + return vmInfo; + } + + // 数据的MxBean + private final OperatingSystemMXBean osMXBean; + private final RuntimeMXBean runtimeMXBean; + private final List garbageCollectorMXBeanList; + private final List memoryPoolMXBeanList; + /** + * 静态信息 + */ + private final String osInfo; + private final String jvmInfo; + + /** + * cpu个数 + */ + private final int totalProcessorCount; + + /** + * 机器的各个状态,用于中间打印和统计上报 + */ + private final PhyOSStatus startPhyOSStatus; + private final ProcessCpuStatus processCpuStatus = new ProcessCpuStatus(); + private final ProcessGCStatus processGCStatus = new ProcessGCStatus(); + private final ProcessMemoryStatus processMomoryStatus = new ProcessMemoryStatus(); + //ms + private long lastUpTime = 0; + //nano + private long lastProcessCpuTime = 0; + + + private VMInfo() { + //初始化静态信息 + osMXBean = java.lang.management.ManagementFactory.getOperatingSystemMXBean(); + runtimeMXBean = java.lang.management.ManagementFactory.getRuntimeMXBean(); + garbageCollectorMXBeanList = java.lang.management.ManagementFactory.getGarbageCollectorMXBeans(); + memoryPoolMXBeanList = java.lang.management.ManagementFactory.getMemoryPoolMXBeans(); + + osInfo = runtimeMXBean.getVmVendor() + " " + runtimeMXBean.getSpecVersion() + " " + runtimeMXBean.getVmVersion(); + jvmInfo = osMXBean.getName() + " " + osMXBean.getArch() + " " + osMXBean.getVersion(); + totalProcessorCount = osMXBean.getAvailableProcessors(); + + //构建startPhyOSStatus + startPhyOSStatus = new PhyOSStatus(); + LOG.info("VMInfo# operatingSystem class => " + osMXBean.getClass().getName()); + if (VMInfo.isSunOsMBean(osMXBean)) { + { + startPhyOSStatus.totalPhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getTotalPhysicalMemorySize"); + startPhyOSStatus.freePhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getFreePhysicalMemorySize"); + startPhyOSStatus.maxFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getMaxFileDescriptorCount"); + startPhyOSStatus.currentOpenFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getOpenFileDescriptorCount"); + } + } + + //初始化processGCStatus; + for (GarbageCollectorMXBean garbage : garbageCollectorMXBeanList) { + GCStatus gcStatus = new GCStatus(); + gcStatus.name = garbage.getName(); + processGCStatus.gcStatusMap.put(garbage.getName(), gcStatus); + } + + //初始化processMemoryStatus + if (memoryPoolMXBeanList != null && !memoryPoolMXBeanList.isEmpty()) { + for (MemoryPoolMXBean pool : memoryPoolMXBeanList) { + MemoryStatus memoryStatus = new MemoryStatus(); + memoryStatus.name = pool.getName(); + memoryStatus.initSize = pool.getUsage().getInit(); + memoryStatus.maxSize = pool.getUsage().getMax(); + processMomoryStatus.memoryStatusMap.put(pool.getName(), memoryStatus); + } + } + } + + public String toString() { + return "the machine info => \n\n" + + "\tosInfo:\t" + osInfo + "\n" + + "\tjvmInfo:\t" + jvmInfo + "\n" + + "\tcpu num:\t" + totalProcessorCount + "\n\n" + + startPhyOSStatus.toString() + "\n" + + processGCStatus.toString() + "\n" + + processMomoryStatus.toString() + "\n"; + } + + public String totalString() { + return (processCpuStatus.getTotalString() + processGCStatus.getTotalString()); + } + + public void getDelta() { + getDelta(true); + } + + public synchronized void getDelta(boolean print) { + + try { + if (VMInfo.isSunOsMBean(osMXBean)) { + long curUptime = runtimeMXBean.getUptime(); + long curProcessTime = getLongFromOperatingSystem(osMXBean, "getProcessCpuTime"); + //百分比, uptime是ms,processTime是nano + if ((curUptime > lastUpTime) && (curProcessTime >= lastProcessCpuTime)) { + float curDeltaCpu = (float) (curProcessTime - lastProcessCpuTime) / ((curUptime - lastUpTime) * totalProcessorCount * 10000); + processCpuStatus.setMaxMinCpu(curDeltaCpu); + processCpuStatus.averageCpu = (float) curProcessTime / (curUptime * totalProcessorCount * 10000); + + lastUpTime = curUptime; + lastProcessCpuTime = curProcessTime; + } + } + + for (GarbageCollectorMXBean garbage : garbageCollectorMXBeanList) { + + GCStatus gcStatus = processGCStatus.gcStatusMap.get(garbage.getName()); + if (gcStatus == null) { + gcStatus = new GCStatus(); + gcStatus.name = garbage.getName(); + processGCStatus.gcStatusMap.put(garbage.getName(), gcStatus); + } + + long curTotalGcCount = garbage.getCollectionCount(); + gcStatus.setCurTotalGcCount(curTotalGcCount); + + long curtotalGcTime = garbage.getCollectionTime(); + gcStatus.setCurTotalGcTime(curtotalGcTime); + } + + if (memoryPoolMXBeanList != null && !memoryPoolMXBeanList.isEmpty()) { + for (MemoryPoolMXBean pool : memoryPoolMXBeanList) { + + MemoryStatus memoryStatus = processMomoryStatus.memoryStatusMap.get(pool.getName()); + if (memoryStatus == null) { + memoryStatus = new MemoryStatus(); + memoryStatus.name = pool.getName(); + processMomoryStatus.memoryStatusMap.put(pool.getName(), memoryStatus); + } + memoryStatus.commitedSize = pool.getUsage().getCommitted(); + memoryStatus.setMaxMinUsedSize(pool.getUsage().getUsed()); + long maxMemory = memoryStatus.commitedSize > 0 ? memoryStatus.commitedSize : memoryStatus.maxSize; + memoryStatus.setMaxMinPercent(maxMemory > 0 ? (float) 100 * memoryStatus.usedSize / maxMemory : -1); + } + } + + if (print) { + LOG.info(processCpuStatus.getDeltaString() + processMomoryStatus.getDeltaString() + processGCStatus.getDeltaString()); + } + + } catch (Exception e) { + LOG.warn("no need care, the fail is ignored : vmInfo getDelta failed " + e.getMessage(), e); + } + } + + public static boolean isSunOsMBean(OperatingSystemMXBean operatingSystem) { + final String className = operatingSystem.getClass().getName(); + + return "com.sun.management.UnixOperatingSystem".equals(className); + } + + public static long getLongFromOperatingSystem(OperatingSystemMXBean operatingSystem, String methodName) { + try { + final Method method = operatingSystem.getClass().getMethod(methodName, (Class[]) null); + method.setAccessible(true); + return (Long) method.invoke(operatingSystem, (Object[]) null); + } catch (final Exception e) { + LOG.info(String.format("OperatingSystemMXBean %s failed, Exception = %s ", methodName, e.getMessage())); + } + + return -1; + } + + private class PhyOSStatus { + long totalPhysicalMemory = -1; + long freePhysicalMemory = -1; + long maxFileDescriptorCount = -1; + long currentOpenFileDescriptorCount = -1; + + public String toString() { + return String.format("\ttotalPhysicalMemory:\t%,.2fG\n" + + "\tfreePhysicalMemory:\t%,.2fG\n" + + "\tmaxFileDescriptorCount:\t%s\n" + + "\tcurrentOpenFileDescriptorCount:\t%s\n", + (float) totalPhysicalMemory / GB, (float) freePhysicalMemory / GB, maxFileDescriptorCount, currentOpenFileDescriptorCount); + } + } + + private class ProcessCpuStatus { + // 百分比的值 比如30.0 表示30.0% + float maxDeltaCpu = -1; + float minDeltaCpu = -1; + float curDeltaCpu = -1; + float averageCpu = -1; + + public void setMaxMinCpu(float curCpu) { + this.curDeltaCpu = curCpu; + if (maxDeltaCpu < curCpu) { + maxDeltaCpu = curCpu; + } + + if (minDeltaCpu == -1 || minDeltaCpu > curCpu) { + minDeltaCpu = curCpu; + } + } + + public String getDeltaString() { + StringBuilder sb = new StringBuilder(); + sb.append("\n\t [delta cpu info] => \n"); + sb.append("\t\t"); + sb.append(String.format("%-30s | %-30s | %-30s | %-30s \n", "curDeltaCpu", "averageCpu", "maxDeltaCpu", "minDeltaCpu")); + sb.append("\t\t"); + sb.append(String.format("%-30s | %-30s | %-30s | %-30s \n", + String.format("%,.2f%%", processCpuStatus.curDeltaCpu), + String.format("%,.2f%%", processCpuStatus.averageCpu), + String.format("%,.2f%%", processCpuStatus.maxDeltaCpu), + String.format("%,.2f%%\n", processCpuStatus.minDeltaCpu))); + + return sb.toString(); + } + + public String getTotalString() { + StringBuilder sb = new StringBuilder(); + sb.append("\n\t [total cpu info] => \n"); + sb.append("\t\t"); + sb.append(String.format("%-30s | %-30s | %-30s \n", "averageCpu", "maxDeltaCpu", "minDeltaCpu")); + sb.append("\t\t"); + sb.append(String.format("%-30s | %-30s | %-30s \n", + String.format("%,.2f%%", processCpuStatus.averageCpu), + String.format("%,.2f%%", processCpuStatus.maxDeltaCpu), + String.format("%,.2f%%\n", processCpuStatus.minDeltaCpu))); + + return sb.toString(); + } + + } + + private class ProcessGCStatus { + final Map gcStatusMap = Maps.newHashMap(); + + public String toString() { + return "\tGC Names\t" + gcStatusMap.keySet() + "\n"; + } + + public String getDeltaString() { + StringBuilder sb = new StringBuilder(); + sb.append("\n\t [delta gc info] => \n"); + sb.append("\t\t "); + sb.append(String.format("%-20s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s \n", "NAME", "curDeltaGCCount", "totalGCCount", "maxDeltaGCCount", "minDeltaGCCount", "curDeltaGCTime", "totalGCTime", "maxDeltaGCTime", "minDeltaGCTime")); + for (GCStatus gc : gcStatusMap.values()) { + sb.append("\t\t "); + sb.append(String.format("%-20s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s \n", + gc.name, gc.curDeltaGCCount, gc.totalGCCount, gc.maxDeltaGCCount, gc.minDeltaGCCount, + String.format("%,.3fs",(float)gc.curDeltaGCTime/1000), + String.format("%,.3fs",(float)gc.totalGCTime/1000), + String.format("%,.3fs",(float)gc.maxDeltaGCTime/1000), + String.format("%,.3fs",(float)gc.minDeltaGCTime/1000))); + + } + return sb.toString(); + } + + public String getTotalString() { + StringBuilder sb = new StringBuilder(); + sb.append("\n\t [total gc info] => \n"); + sb.append("\t\t "); + sb.append(String.format("%-20s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s \n", "NAME", "totalGCCount", "maxDeltaGCCount", "minDeltaGCCount", "totalGCTime", "maxDeltaGCTime", "minDeltaGCTime")); + for (GCStatus gc : gcStatusMap.values()) { + sb.append("\t\t "); + sb.append(String.format("%-20s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s \n", + gc.name, gc.totalGCCount, gc.maxDeltaGCCount, gc.minDeltaGCCount, + String.format("%,.3fs",(float)gc.totalGCTime/1000), + String.format("%,.3fs",(float)gc.maxDeltaGCTime/1000), + String.format("%,.3fs",(float)gc.minDeltaGCTime/1000))); + + } + return sb.toString(); + } + } + + private class ProcessMemoryStatus { + final Map memoryStatusMap = Maps.newHashMap(); + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("\t"); + sb.append(String.format("%-30s | %-30s | %-30s \n", "MEMORY_NAME", "allocation_size", "init_size")); + for (MemoryStatus ms : memoryStatusMap.values()) { + sb.append("\t"); + sb.append(String.format("%-30s | %-30s | %-30s \n", + ms.name, String.format("%,.2fMB", (float) ms.maxSize / MB), String.format("%,.2fMB", (float) ms.initSize / MB))); + } + return sb.toString(); + } + + public String getDeltaString() { + StringBuilder sb = new StringBuilder(); + sb.append("\n\t [delta memory info] => \n"); + sb.append("\t\t "); + sb.append(String.format("%-30s | %-30s | %-30s | %-30s | %-30s \n", "NAME", "used_size", "used_percent", "max_used_size", "max_percent")); + for (MemoryStatus ms : memoryStatusMap.values()) { + sb.append("\t\t "); + sb.append(String.format("%-30s | %-30s | %-30s | %-30s | %-30s \n", + ms.name, String.format("%,.2f", (float) ms.usedSize / MB) + "MB", + String.format("%,.2f", (float) ms.percent) + "%", + String.format("%,.2f", (float) ms.maxUsedSize / MB) + "MB", + String.format("%,.2f", (float) ms.maxpercent) + "%")); + + } + return sb.toString(); + } + } + + private class GCStatus { + String name; + long maxDeltaGCCount = -1; + long minDeltaGCCount = -1; + long curDeltaGCCount; + long totalGCCount = 0; + long maxDeltaGCTime = -1; + long minDeltaGCTime = -1; + long curDeltaGCTime; + long totalGCTime = 0; + + public void setCurTotalGcCount(long curTotalGcCount) { + this.curDeltaGCCount = curTotalGcCount - totalGCCount; + this.totalGCCount = curTotalGcCount; + + if (maxDeltaGCCount < curDeltaGCCount) { + maxDeltaGCCount = curDeltaGCCount; + } + + if (minDeltaGCCount == -1 || minDeltaGCCount > curDeltaGCCount) { + minDeltaGCCount = curDeltaGCCount; + } + } + + public void setCurTotalGcTime(long curTotalGcTime) { + this.curDeltaGCTime = curTotalGcTime - totalGCTime; + this.totalGCTime = curTotalGcTime; + + if (maxDeltaGCTime < curDeltaGCTime) { + maxDeltaGCTime = curDeltaGCTime; + } + + if (minDeltaGCTime == -1 || minDeltaGCTime > curDeltaGCTime) { + minDeltaGCTime = curDeltaGCTime; + } + } + } + + private class MemoryStatus { + String name; + long initSize; + long maxSize; + long commitedSize; + long usedSize; + float percent; + long maxUsedSize = -1; + float maxpercent = 0; + + void setMaxMinUsedSize(long curUsedSize) { + if (maxUsedSize < curUsedSize) { + maxUsedSize = curUsedSize; + } + this.usedSize = curUsedSize; + } + + void setMaxMinPercent(float curPercent) { + if (maxpercent < curPercent) { + maxpercent = curPercent; + } + this.percent = curPercent; + } + } + +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/Configuration.java b/common/src/main/java/com/alibaba/datax/common/util/Configuration.java new file mode 100755 index 000000000..456920805 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/Configuration.java @@ -0,0 +1,1078 @@ +package com.alibaba.datax.common.util; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.spi.ErrorCode; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.io.*; +import java.util.*; + +/** + * Configuration 提供多级JSON配置信息无损存储
+ *
+ *

+ * 实例代码:
+ *

+ * 获取job的配置信息
+ * Configuration configuration = Configuration.from(new File("Config.json"));
+ * String jobContainerClass = + * configuration.getString("core.container.job.class");
+ *

+ *
+ * 设置多级List
+ * configuration.set("job.reader.parameter.jdbcUrl", Arrays.asList(new String[] + * {"jdbc", "jdbc"})); + *

+ *

+ *
+ *
+ * 合并Configuration:
+ * configuration.merge(another); + *

+ *

+ *
+ *
+ *
+ *

+ * Configuration 存在两种较好地实现方式
+ * 第一种是将JSON配置信息中所有的Key全部打平,用a.b.c的级联方式作为Map的Key,内部使用一个Map保存信息
+ * 第二种是将JSON的对象直接使用结构化树形结构保存
+ *

+ * 目前使用的第二种实现方式,使用第一种的问题在于:
+ * 1. 插入新对象,比较难处理,例如a.b.c="bazhen",此时如果需要插入a="bazhen",也即是根目录下第一层所有类型全部要废弃 + * ,使用"bazhen"作为value,第一种方式使用字符串表示key,难以处理这类问题。
+ * 2. 返回树形结构,例如 a.b.c.d = "bazhen",如果返回"a"下的所有元素,实际上是一个Map,需要合并处理
+ * 3. 输出JSON,将上述对象转为JSON,要把上述Map的多级key转为树形结构,并输出为JSON
+ */ +public class Configuration { + + /** + * 对于加密的keyPath,需要记录下来 + * 为的是后面分布式情况下将该值加密后抛到DataXServer中 + */ + private Set secretKeyPathSet = + new HashSet(); + + private Object root = null; + + /** + * 初始化空白的Configuration + */ + public static Configuration newDefault() { + return Configuration.from("{}"); + } + + /** + * 从JSON字符串加载Configuration + */ + public static Configuration from(String json) { + json = StrUtil.replaceVariable(json); + checkJSON(json); + + try { + return new Configuration(json); + } catch (Exception e) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + e); + } + + } + + /** + * 从包括json的File对象加载Configuration + */ + public static Configuration from(File file) { + try { + return Configuration.from(IOUtils + .toString(new FileInputStream(file))); + } catch (FileNotFoundException e) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + String.format("配置信息错误,您提供的配置文件[%s]不存在. 请检查您的配置文件.", file.getAbsolutePath())); + } catch (IOException e) { + throw DataXException.asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format("配置信息错误. 您提供配置文件[%s]读取失败,错误原因: %s. 请检查您的配置文件的权限设置.", + file.getAbsolutePath(), e)); + } + } + + /** + * 从包括json的InputStream对象加载Configuration + */ + public static Configuration from(InputStream is) { + try { + return Configuration.from(IOUtils.toString(is)); + } catch (IOException e) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + String.format("请检查您的配置文件. 您提供的配置文件读取失败,错误原因: %s. 请检查您的配置文件的权限设置.", e)); + } + } + + /** + * 从Map对象加载Configuration + */ + public static Configuration from(final Map object) { + return Configuration.from(Configuration.toJSONString(object)); + } + + /** + * 从List对象加载Configuration + */ + public static Configuration from(final List object) { + return Configuration.from(Configuration.toJSONString(object)); + } + + public String getNecessaryValue(String key, ErrorCode errorCode) { + String value = this.getString(key, null); + if (StringUtils.isBlank(value)) { + throw DataXException.asDataXException(errorCode, + String.format("您提供配置文件有误,[%s]是必填参数,不允许为空或者留白 .", key)); + } + + return value; + } + + public String getUnnecessaryValue(String key,String defaultValue,ErrorCode errorCode) { + String value = this.getString(key, defaultValue); + if (StringUtils.isBlank(value)) { + value = defaultValue; + } + return value; + } + + public Boolean getNecessaryBool(String key, ErrorCode errorCode) { + Boolean value = this.getBool(key); + if (value == null) { + throw DataXException.asDataXException(errorCode, + String.format("您提供配置文件有误,[%s]是必填参数,不允许为空或者留白 .", key)); + } + + return value; + } + + /** + * 根据用户提供的json path,寻址具体的对象。 + *

+ *
+ *

+ * NOTE: 目前仅支持Map以及List下标寻址, 例如: + *

+ *
+ *

+ * 对于如下JSON + *

+ * {"a": {"b": {"c": [0,1,2,3]}}} + *

+ * config.get("") 返回整个Map
+ * config.get("a") 返回a下属整个Map
+ * config.get("a.b.c") 返回c对应的数组List
+ * config.get("a.b.c[0]") 返回数字0 + * + * @return Java表示的JSON对象,如果path不存在或者对象不存在,均返回null。 + */ + public Object get(final String path) { + this.checkPath(path); + try { + return this.findObject(path); + } catch (Exception e) { + return null; + } + } + + /** + * 用户指定部分path,获取Configuration的子集 + *

+ *
+ * 如果path获取的路径或者对象不存在,返回null + */ + public Configuration getConfiguration(final String path) { + Object object = this.get(path); + if (null == object) { + return null; + } + + return Configuration.from(Configuration.toJSONString(object)); + } + + /** + * 根据用户提供的json path,寻址String对象 + * + * @return String对象,如果path不存在或者String不存在,返回null + */ + public String getString(final String path) { + Object string = this.get(path); + if (null == string) { + return null; + } + return String.valueOf(string); + } + + /** + * 根据用户提供的json path,寻址String对象,如果对象不存在,返回默认字符串 + * + * @return String对象,如果path不存在或者String不存在,返回默认字符串 + */ + public String getString(final String path, final String defaultValue) { + String result = this.getString(path); + + if (null == result) { + return defaultValue; + } + + return result; + } + + /** + * 根据用户提供的json path,寻址Character对象 + * + * @return Character对象,如果path不存在或者Character不存在,返回null + */ + public Character getChar(final String path) { + String result = this.getString(path); + if (null == result) { + return null; + } + + try { + return CharUtils.toChar(result); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format("任务读取配置文件出错. 因为配置文件路径[%s] 值非法,期望是字符类型: %s. 请检查您的配置并作出修改.", path, + e.getMessage())); + } + } + + /** + * 根据用户提供的json path,寻址Boolean对象,如果对象不存在,返回默认Character对象 + * + * @return Character对象,如果path不存在或者Character不存在,返回默认Character对象 + */ + public Character getChar(final String path, char defaultValue) { + Character result = this.getChar(path); + if (null == result) { + return defaultValue; + } + return result; + } + + /** + * 根据用户提供的json path,寻址Boolean对象 + * + * @return Boolean对象,如果path值非true,false ,将报错.特别注意:当 path 不存在时,会返回:null. + */ + public Boolean getBool(final String path) { + String result = this.getString(path); + + if (null == result) { + return null; + } else if ("true".equalsIgnoreCase(result)) { + return Boolean.TRUE; + } else if ("false".equalsIgnoreCase(result)) { + return Boolean.FALSE; + } else { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + String.format("您提供的配置信息有误,因为从[%s]获取的值[%s]无法转换为bool类型. 请检查源表的配置并且做出相应的修改.", + path, result)); + } + + } + + /** + * 根据用户提供的json path,寻址Boolean对象,如果对象不存在,返回默认Boolean对象 + * + * @return Boolean对象,如果path不存在或者Boolean不存在,返回默认Boolean对象 + */ + public Boolean getBool(final String path, boolean defaultValue) { + Boolean result = this.getBool(path); + if (null == result) { + return defaultValue; + } + return result; + } + + /** + * 根据用户提供的json path,寻址Integer对象 + * + * @return Integer对象,如果path不存在或者Integer不存在,返回null + */ + public Integer getInt(final String path) { + String result = this.getString(path); + if (null == result) { + return null; + } + + try { + return Integer.valueOf(result); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是整数类型: %s. 请检查您的配置并作出修改.", path, + e.getMessage())); + } + } + + /** + * 根据用户提供的json path,寻址Integer对象,如果对象不存在,返回默认Integer对象 + * + * @return Integer对象,如果path不存在或者Integer不存在,返回默认Integer对象 + */ + public Integer getInt(final String path, int defaultValue) { + Integer object = this.getInt(path); + if (null == object) { + return defaultValue; + } + return object; + } + + /** + * 根据用户提供的json path,寻址Long对象 + * + * @return Long对象,如果path不存在或者Long不存在,返回null + */ + public Long getLong(final String path) { + String result = this.getString(path); + if (null == result) { + return null; + } + + try { + return Long.valueOf(result); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是整数类型: %s. 请检查您的配置并作出修改.", path, + e.getMessage())); + } + } + + /** + * 根据用户提供的json path,寻址Long对象,如果对象不存在,返回默认Long对象 + * + * @return Long对象,如果path不存在或者Integer不存在,返回默认Long对象 + */ + public Long getLong(final String path, long defaultValue) { + Long result = this.getLong(path); + if (null == result) { + return defaultValue; + } + return result; + } + + /** + * 根据用户提供的json path,寻址Double对象 + * + * @return Double对象,如果path不存在或者Double不存在,返回null + */ + public Double getDouble(final String path) { + String result = this.getString(path); + if (null == result) { + return null; + } + + try { + return Double.valueOf(result); + } catch (Exception e) { + throw DataXException.asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是浮点类型: %s. 请检查您的配置并作出修改.", path, + e.getMessage())); + } + } + + /** + * 根据用户提供的json path,寻址Double对象,如果对象不存在,返回默认Double对象 + * + * @return Double对象,如果path不存在或者Double不存在,返回默认Double对象 + */ + public Double getDouble(final String path, double defaultValue) { + Double result = this.getDouble(path); + if (null == result) { + return defaultValue; + } + return result; + } + + /** + * 根据用户提供的json path,寻址List对象,如果对象不存在,返回null + */ + @SuppressWarnings("unchecked") + public List getList(final String path) { + List list = this.get(path, List.class); + if (null == list) { + return null; + } + return list; + } + + /** + * 根据用户提供的json path,寻址List对象,如果对象不存在,返回null + */ + @SuppressWarnings("unchecked") + public List getList(final String path, Class t) { + Object object = this.get(path, List.class); + if (null == object) { + return null; + } + + List result = new ArrayList(); + + List origin = (List) object; + for (final Object each : origin) { + result.add((T) each); + } + + return result; + } + + /** + * 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List + */ + @SuppressWarnings("unchecked") + public List getList(final String path, + final List defaultList) { + Object object = this.getList(path); + if (null == object) { + return defaultList; + } + return (List) object; + } + + /** + * 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List + */ + public List getList(final String path, final List defaultList, + Class t) { + List list = this.getList(path, t); + if (null == list) { + return defaultList; + } + return list; + } + + /** + * 根据用户提供的json path,寻址包含Configuration的List,如果对象不存在,返回默认null + */ + public List getListConfiguration(final String path) { + List lists = getList(path); + if (lists == null) { + return null; + } + + List result = new ArrayList(); + for (final Object object : lists) { + result.add(Configuration.from(Configuration.toJSONString(object))); + } + return result; + } + + /** + * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回null + */ + @SuppressWarnings("unchecked") + public Map getMap(final String path) { + Map result = this.get(path, Map.class); + if (null == result) { + return null; + } + return result; + } + + /** + * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回null; + */ + @SuppressWarnings("unchecked") + public Map getMap(final String path, Class t) { + Map map = this.get(path, Map.class); + if (null == map) { + return null; + } + + Map result = new HashMap(); + for (final String key : map.keySet()) { + result.put(key, (T) map.get(key)); + } + + return result; + } + + /** + * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回默认map + */ + @SuppressWarnings("unchecked") + public Map getMap(final String path, + final Map defaultMap) { + Object object = this.getMap(path); + if (null == object) { + return defaultMap; + } + return (Map) object; + } + + /** + * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回默认map + */ + public Map getMap(final String path, + final Map defaultMap, Class t) { + Map result = getMap(path, t); + if (null == result) { + return defaultMap; + } + return result; + } + + /** + * 根据用户提供的json path,寻址包含Configuration的Map,如果对象不存在,返回默认null + */ + @SuppressWarnings("unchecked") + public Map getMapConfiguration(final String path) { + Map map = this.get(path, Map.class); + if (null == map) { + return null; + } + + Map result = new HashMap(); + for (final String key : map.keySet()) { + result.put(key, Configuration.from(Configuration.toJSONString(map + .get(key)))); + } + + return result; + } + + /** + * 根据用户提供的json path,寻址具体的对象,并转为用户提供的类型 + *

+ *
+ *

+ * NOTE: 目前仅支持Map以及List下标寻址, 例如: + *

+ *
+ *

+ * 对于如下JSON + *

+ * {"a": {"b": {"c": [0,1,2,3]}}} + *

+ * config.get("") 返回整个Map
+ * config.get("a") 返回a下属整个Map
+ * config.get("a.b.c") 返回c对应的数组List
+ * config.get("a.b.c[0]") 返回数字0 + * + * @return Java表示的JSON对象,如果转型失败,将抛出异常 + */ + @SuppressWarnings("unchecked") + public T get(final String path, Class clazz) { + this.checkPath(path); + return (T) this.get(path); + } + + /** + * 格式化Configuration输出 + */ + public String beautify() { + return JSON.toJSONString(this.getInternal(), + SerializerFeature.PrettyFormat); + } + + /** + * 根据用户提供的json path,插入指定对象,并返回之前存在的对象(如果存在) + *

+ *
+ *

+ * 目前仅支持.以及数组下标寻址, 例如: + *

+ *
+ *

+ * config.set("a.b.c[3]", object); + *

+ *
+ * 对于插入对象,Configuration不做任何限制,但是请务必保证该对象是简单对象(包括Map、List),不要使用自定义对象,否则后续对于JSON序列化等情况会出现未定义行为。 + * + * @param path + * JSON path对象 + * @param object + * 需要插入的对象 + * @return Java表示的JSON对象 + */ + public Object set(final String path, final Object object) { + checkPath(path); + + Object result = this.get(path); + + setObject(path, extractConfiguration(object)); + + return result; + } + + /** + * 获取Configuration下所有叶子节点的key + *

+ *
+ *

+ * 对于
+ *

+ * {"a": {"b": {"c": [0,1,2,3]}}, "x": "y"} + *

+ * 下属的key包括: a.b.c[0],a.b.c[1],a.b.c[2],a.b.c[3],x + */ + public Set getKeys() { + Set collect = new HashSet(); + this.getKeysRecursive(this.getInternal(), "", collect); + return collect; + } + + /** + * 删除path对应的值,如果path不存在,将抛出异常。 + */ + public Object remove(final String path) { + final Object result = this.get(path); + if (null == result) { + throw DataXException.asDataXException( + CommonErrorCode.RUNTIME_ERROR, + String.format("配置文件对应Key[%s]并不存在,该情况是代码编程错误. 请联系DataX团队的同学.", path)); + } + + this.set(path, null); + return result; + } + + /** + * 合并其他Configuration,并修改两者冲突的KV配置 + * + * @param another + * 合并加入的第三方Configuration + * @param updateWhenConflict + * 当合并双方出现KV冲突时候,选择更新当前KV,或者忽略该KV + * @return 返回合并后对象 + */ + public Configuration merge(final Configuration another, + boolean updateWhenConflict) { + Set keys = another.getKeys(); + + for (final String key : keys) { + // 如果使用更新策略,凡是another存在的key,均需要更新 + if (updateWhenConflict) { + this.set(key, another.get(key)); + continue; + } + + // 使用忽略策略,只有another Configuration存在但是当前Configuration不存在的key,才需要更新 + boolean isCurrentExists = this.get(key) != null; + if (isCurrentExists) { + continue; + } + + this.set(key, another.get(key)); + } + return this; + } + + @Override + public String toString() { + return this.toJSON(); + } + + /** + * 将Configuration作为JSON输出 + */ + public String toJSON() { + return Configuration.toJSONString(this.getInternal()); + } + + /** + * 拷贝当前Configuration,注意,这里使用了深拷贝,避免冲突 + */ + public Configuration clone() { + Configuration config = Configuration + .from(Configuration.toJSONString(this.getInternal())); + config.addSecretKeyPath(this.secretKeyPathSet); + return config; + } + + /** + * 按照configuration要求格式的path + * 比如: + * a.b.c + * a.b[2].c + * @param path + */ + public void addSecretKeyPath(String path) { + if(StringUtils.isNotBlank(path)) { + this.secretKeyPathSet.add(path); + } + } + + public void addSecretKeyPath(Set pathSet) { + if(pathSet != null) { + this.secretKeyPathSet.addAll(pathSet); + } + } + + public void setSecretKeyPathSet(Set keyPathSet) { + if(keyPathSet != null) { + this.secretKeyPathSet = keyPathSet; + } + } + + public boolean isSecretPath(String path) { + return this.secretKeyPathSet.contains(path); + } + + @SuppressWarnings("unchecked") + void getKeysRecursive(final Object current, String path, Set collect) { + boolean isRegularElement = !(current instanceof Map || current instanceof List); + if (isRegularElement) { + collect.add(path); + return; + } + + boolean isMap = current instanceof Map; + if (isMap) { + Map mapping = ((Map) current); + for (final String key : mapping.keySet()) { + if (StringUtils.isBlank(path)) { + getKeysRecursive(mapping.get(key), key.trim(), collect); + } else { + getKeysRecursive(mapping.get(key), path + "." + key.trim(), + collect); + } + } + return; + } + + boolean isList = current instanceof List; + if (isList) { + List lists = (List) current; + for (int i = 0; i < lists.size(); i++) { + getKeysRecursive(lists.get(i), path + String.format("[%d]", i), + collect); + } + return; + } + + return; + } + + public Object getInternal() { + return this.root; + } + + private void setObject(final String path, final Object object) { + Object newRoot = setObjectRecursive(this.root, split2List(path), 0, + object); + + if (isSuitForRoot(newRoot)) { + this.root = newRoot; + return; + } + + throw DataXException.asDataXException(CommonErrorCode.RUNTIME_ERROR, + String.format("值[%s]无法适配您提供[%s], 该异常代表系统编程错误, 请联系DataX开发团队!", + ToStringBuilder.reflectionToString(object), path)); + } + + @SuppressWarnings("unchecked") + private Object extractConfiguration(final Object object) { + if (object instanceof Configuration) { + return extractFromConfiguration(object); + } + + if (object instanceof List) { + List result = new ArrayList(); + for (final Object each : (List) object) { + result.add(extractFromConfiguration(each)); + } + return result; + } + + if (object instanceof Map) { + Map result = new HashMap(); + for (final String key : ((Map) object).keySet()) { + result.put(key, + extractFromConfiguration(((Map) object) + .get(key))); + } + return result; + } + + return object; + } + + private Object extractFromConfiguration(final Object object) { + if (object instanceof Configuration) { + return ((Configuration) object).getInternal(); + } + + return object; + } + + Object buildObject(final List paths, final Object object) { + if (null == paths) { + throw DataXException.asDataXException( + CommonErrorCode.RUNTIME_ERROR, + "Path不能为null,该异常代表系统编程错误, 请联系DataX开发团队 !"); + } + + if (1 == paths.size() && StringUtils.isBlank(paths.get(0))) { + return object; + } + + Object child = object; + for (int i = paths.size() - 1; i >= 0; i--) { + String path = paths.get(i); + + if (isPathMap(path)) { + Map mapping = new HashMap(); + mapping.put(path, child); + child = mapping; + continue; + } + + if (isPathList(path)) { + List lists = new ArrayList( + this.getIndex(path) + 1); + expand(lists, this.getIndex(path) + 1); + lists.set(this.getIndex(path), child); + child = lists; + continue; + } + + throw DataXException.asDataXException( + CommonErrorCode.RUNTIME_ERROR, String.format( + "路径[%s]出现非法值类型[%s],该异常代表系统编程错误, 请联系DataX开发团队! .", + StringUtils.join(paths, "."), path)); + } + + return child; + } + + @SuppressWarnings("unchecked") + Object setObjectRecursive(Object current, final List paths, + int index, final Object value) { + + // 如果是已经超出path,我们就返回value即可,作为最底层叶子节点 + boolean isLastIndex = index == paths.size(); + if (isLastIndex) { + return value; + } + + String path = paths.get(index).trim(); + boolean isNeedMap = isPathMap(path); + if (isNeedMap) { + Map mapping; + + // 当前不是map,因此全部替换为map,并返回新建的map对象 + boolean isCurrentMap = current instanceof Map; + if (!isCurrentMap) { + mapping = new HashMap(); + mapping.put( + path, + buildObject(paths.subList(index + 1, paths.size()), + value)); + return mapping; + } + + // 当前是map,但是没有对应的key,也就是我们需要新建对象插入该map,并返回该map + mapping = ((Map) current); + boolean hasSameKey = mapping.containsKey(path); + if (!hasSameKey) { + mapping.put( + path, + buildObject(paths.subList(index + 1, paths.size()), + value)); + return mapping; + } + + // 当前是map,而且还竟然存在这个值,好吧,继续递归遍历 + current = mapping.get(path); + mapping.put(path, + setObjectRecursive(current, paths, index + 1, value)); + return mapping; + } + + boolean isNeedList = isPathList(path); + if (isNeedList) { + List lists; + int listIndexer = getIndex(path); + + // 当前是list,直接新建并返回即可 + boolean isCurrentList = current instanceof List; + if (!isCurrentList) { + lists = expand(new ArrayList(), listIndexer + 1); + lists.set( + listIndexer, + buildObject(paths.subList(index + 1, paths.size()), + value)); + return lists; + } + + // 当前是list,但是对应的indexer是没有具体的值,也就是我们新建对象然后插入到该list,并返回该List + lists = (List) current; + lists = expand(lists, listIndexer + 1); + + boolean hasSameIndex = lists.get(listIndexer) != null; + if (!hasSameIndex) { + lists.set( + listIndexer, + buildObject(paths.subList(index + 1, paths.size()), + value)); + return lists; + } + + // 当前是list,并且存在对应的index,没有办法继续递归寻找 + current = lists.get(listIndexer); + lists.set(listIndexer, + setObjectRecursive(current, paths, index + 1, value)); + return lists; + } + + throw DataXException.asDataXException(CommonErrorCode.RUNTIME_ERROR, + "该异常代表系统编程错误, 请联系DataX开发团队 !"); + } + + private Object findObject(final String path) { + boolean isRootQuery = StringUtils.isBlank(path); + if (isRootQuery) { + return this.root; + } + + Object target = this.root; + + for (final String each : split2List(path)) { + if (isPathMap(each)) { + target = findObjectInMap(target, each); + continue; + } else { + target = findObjectInList(target, each); + continue; + } + } + + return target; + } + + @SuppressWarnings("unchecked") + private Object findObjectInMap(final Object target, final String index) { + boolean isMap = (target instanceof Map); + if (!isMap) { + throw new IllegalArgumentException(String.format( + "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.", + index, target.getClass().toString())); + } + + Object result = ((Map) target).get(index); + if (null == result) { + throw new IllegalArgumentException(String.format( + "您提供的配置文件有误. 路径[%s]值为null,datax无法识别该配置. 请检查您的配置并作出修改.", index)); + } + + return result; + } + + @SuppressWarnings({ "unchecked" }) + private Object findObjectInList(final Object target, final String each) { + boolean isList = (target instanceof List); + if (!isList) { + throw new IllegalArgumentException(String.format( + "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.", + each, target.getClass().toString())); + } + + String index = each.replace("[", "").replace("]", ""); + if (!StringUtils.isNumeric(index)) { + throw new IllegalArgumentException( + String.format( + "系统编程错误,列表下标必须为数字类型,但该节点发现实际类型是[%s] ,该异常代表系统编程错误, 请联系DataX开发团队 !", + index)); + } + + return ((List) target).get(Integer.valueOf(index)); + } + + private List expand(List list, int size) { + int expand = size - list.size(); + while (expand-- > 0) { + list.add(null); + } + return list; + } + + private boolean isPathList(final String path) { + return path.contains("[") && path.contains("]"); + } + + private boolean isPathMap(final String path) { + return StringUtils.isNotBlank(path) && !isPathList(path); + } + + private int getIndex(final String index) { + return Integer.valueOf(index.replace("[", "").replace("]", "")); + } + + private boolean isSuitForRoot(final Object object) { + if (null != object && (object instanceof List || object instanceof Map)) { + return true; + } + + return false; + } + + private String split(final String path) { + return StringUtils.replace(path, "[", ".["); + } + + private List split2List(final String path) { + return Arrays.asList(StringUtils.split(split(path), ".")); + } + + private void checkPath(final String path) { + if (null == path) { + throw new IllegalArgumentException( + "系统编程错误, 该异常代表系统编程错误, 请联系DataX开发团队!."); + } + + for (final String each : StringUtils.split(".")) { + if (StringUtils.isBlank(each)) { + throw new IllegalArgumentException(String.format( + "系统编程错误, 路径[%s]不合法, 路径层次之间不能出现空白字符 .", path)); + } + } + } + + @SuppressWarnings("unused") + private String toJSONPath(final String path) { + return (StringUtils.isBlank(path) ? "$" : "$." + path).replace("$.[", + "$["); + } + + private static void checkJSON(final String json) { + if (StringUtils.isBlank(json)) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + "配置信息错误. 因为您提供的配置信息不是合法的JSON格式, JSON不能为空白. 请按照标准json格式提供配置信息. "); + } + } + + private Configuration(final String json) { + try { + this.root = JSON.parse(json); + } catch (Exception e) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + String.format("配置信息错误. 您提供的配置信息不是合法的JSON格式: %s . 请按照标准json格式提供配置信息. ", e.getMessage())); + } + } + + private static String toJSONString(final Object object) { + return JSON.toJSONString(object); + } + + public Set getSecretKeyPathSet() { + return secretKeyPathSet; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/FilterUtil.java b/common/src/main/java/com/alibaba/datax/common/util/FilterUtil.java new file mode 100755 index 000000000..37b319a19 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/FilterUtil.java @@ -0,0 +1,52 @@ +package com.alibaba.datax.common.util; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 提供从 List 中根据 regular 过滤的通用工具(返回值已经去重). 使用场景,比如:odpsreader + * 的分区筛选,hdfsreader/txtfilereader的路径筛选等 + */ +public final class FilterUtil { + + //已经去重 + public static List filterByRegular(List allStrs, + String regular) { + List matchedValues = new ArrayList(); + + // 语法习惯上的兼容处理(pt=* 实际正则应该是:pt=.*) + String newReqular = regular.replace(".*", "*").replace("*", ".*"); + + Pattern p = Pattern.compile(newReqular); + + for (String partition : allStrs) { + if (p.matcher(partition).matches()) { + if (!matchedValues.contains(partition)) { + matchedValues.add(partition); + } + } + } + + return matchedValues; + } + + //已经去重 + public static List filterByRegulars(List allStrs, + List regulars) { + List matchedValues = new ArrayList(); + + List tempMatched = null; + for (String regular : regulars) { + tempMatched = filterByRegular(allStrs, regular); + if (null != tempMatched && !tempMatched.isEmpty()) { + for (String temp : tempMatched) { + if (!matchedValues.contains(temp)) { + matchedValues.add(temp); + } + } + } + } + + return matchedValues; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/HostUtils.java b/common/src/main/java/com/alibaba/datax/common/util/HostUtils.java new file mode 100644 index 000000000..3980076c6 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/HostUtils.java @@ -0,0 +1,50 @@ +package com.alibaba.datax.common.util; + +import com.google.common.base.CharMatcher; +import com.google.common.io.ByteStreams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Created by liqiang on 15/8/25. + */ +public class HostUtils { + + public static final String IP; + public static final String HOSTNAME; + private static final Logger log = LoggerFactory.getLogger(HostUtils.class); + + static { + String ip; + String hostname; + try { + InetAddress addr = InetAddress.getLocalHost(); + ip = addr.getHostAddress(); + hostname = addr.getHostName(); + } catch (UnknownHostException e) { + log.error("Can't find out address: " + e.getMessage(), e); + ip = "UNKNOWN"; + hostname = "UNKNOWN"; + } + if (ip.equals("127.0.0.1") || ip.equals("::1") || ip.equals("UNKNOWN")) { + try { + Process process = Runtime.getRuntime().exec("hostname -i"); + if (process.waitFor() == 0) { + ip = new String(ByteStreams.toByteArray(process.getInputStream()), "UTF8"); + } + process = Runtime.getRuntime().exec("hostname"); + if (process.waitFor() == 0) { + hostname = CharMatcher.BREAKING_WHITESPACE.trimFrom(new String(ByteStreams.toByteArray(process.getInputStream()), "UTF8")); + } + } catch (Exception e) { + log.warn("get hostname failed {}", e.getMessage()); + } + } + IP = ip; + HOSTNAME = hostname; + log.info("IP {} HOSTNAME {}", IP, HOSTNAME); + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/ListUtil.java b/common/src/main/java/com/alibaba/datax/common/util/ListUtil.java new file mode 100755 index 000000000..d7a5b7646 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/ListUtil.java @@ -0,0 +1,139 @@ +package com.alibaba.datax.common.util; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 提供针对 DataX中使用的 List 较为常见的一些封装。 比如:checkIfValueDuplicate 可以用于检查用户配置的 writer + * 的列不能重复。makeSureNoValueDuplicate亦然,只是会严格报错。 + */ +public final class ListUtil { + + public static boolean checkIfValueDuplicate(List aList, + boolean caseSensitive) { + if (null == aList || aList.isEmpty()) { + throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, + "您提供的作业配置有误,List不能为空."); + } + + try { + makeSureNoValueDuplicate(aList, caseSensitive); + } catch (Exception e) { + return true; + } + return false; + } + + public static void makeSureNoValueDuplicate(List aList, + boolean caseSensitive) { + if (null == aList || aList.isEmpty()) { + throw new IllegalArgumentException("您提供的作业配置有误, List不能为空."); + } + + if (1 == aList.size()) { + return; + } else { + List list = null; + if (!caseSensitive) { + list = valueToLowerCase(aList); + } else { + list = new ArrayList(aList); + } + + Collections.sort(list); + + for (int i = 0, len = list.size() - 1; i < len; i++) { + if (list.get(i).equals(list.get(i + 1))) { + throw DataXException + .asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format( + "您提供的作业配置信息有误, String:[%s] 不允许重复出现在列表中: [%s].", + list.get(i), + StringUtils.join(aList, ","))); + } + } + } + } + + public static boolean checkIfBInA(List aList, List bList, + boolean caseSensitive) { + if (null == aList || aList.isEmpty() || null == bList + || bList.isEmpty()) { + throw new IllegalArgumentException("您提供的作业配置有误, List不能为空."); + } + + try { + makeSureBInA(aList, bList, caseSensitive); + } catch (Exception e) { + return false; + } + return true; + } + + public static void makeSureBInA(List aList, List bList, + boolean caseSensitive) { + if (null == aList || aList.isEmpty() || null == bList + || bList.isEmpty()) { + throw new IllegalArgumentException("您提供的作业配置有误, List不能为空."); + } + + List all = null; + List part = null; + + if (!caseSensitive) { + all = valueToLowerCase(aList); + part = valueToLowerCase(bList); + } else { + all = new ArrayList(aList); + part = new ArrayList(bList); + } + + for (String oneValue : part) { + if (!all.contains(oneValue)) { + throw DataXException + .asDataXException( + CommonErrorCode.CONFIG_ERROR, + String.format( + "您提供的作业配置信息有误, String:[%s] 不存在于列表中:[%s].", + oneValue, StringUtils.join(aList, ","))); + } + } + + } + + public static boolean checkIfValueSame(List aList) { + if (null == aList || aList.isEmpty()) { + throw new IllegalArgumentException("您提供的作业配置有误, List不能为空."); + } + + if (1 == aList.size()) { + return true; + } else { + Boolean firstValue = aList.get(0); + for (int i = 1, len = aList.size(); i < len; i++) { + if (firstValue.booleanValue() != aList.get(i).booleanValue()) { + return false; + } + } + return true; + } + } + + public static List valueToLowerCase(List aList) { + if (null == aList || aList.isEmpty()) { + throw new IllegalArgumentException("您提供的作业配置有误, List不能为空."); + } + List result = new ArrayList(aList.size()); + for (String oneValue : aList) { + result.add(null != oneValue ? oneValue.toLowerCase() : null); + } + + return result; + } +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/RangeSplitUtil.java b/common/src/main/java/com/alibaba/datax/common/util/RangeSplitUtil.java new file mode 100755 index 000000000..791f9ea12 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/RangeSplitUtil.java @@ -0,0 +1,209 @@ +package com.alibaba.datax.common.util; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.math.BigInteger; +import java.util.*; + +/** + * 提供通用的根据数字范围、字符串范围等进行切分的通用功能. + */ +public final class RangeSplitUtil { + + public static String[] doAsciiStringSplit(String left, String right, int expectSliceNumber) { + int radix = 128; + + BigInteger[] tempResult = doBigIntegerSplit(stringToBigInteger(left, radix), + stringToBigInteger(right, radix), expectSliceNumber); + String[] result = new String[tempResult.length]; + + //处理第一个字符串(因为:在转换为数字,再还原的时候,如果首字符刚好是 basic,则不知道应该添加多少个 basic) + result[0] = left; + result[tempResult.length - 1] = right; + + for (int i = 1, len = tempResult.length - 1; i < len; i++) { + result[i] = bigIntegerToString(tempResult[i], radix); + } + + return result; + } + + + public static long[] doLongSplit(long left, long right, int expectSliceNumber) { + BigInteger[] result = doBigIntegerSplit(BigInteger.valueOf(left), + BigInteger.valueOf(right), expectSliceNumber); + long[] returnResult = new long[result.length]; + for (int i = 0, len = result.length; i < len; i++) { + returnResult[i] = result[i].longValue(); + } + return returnResult; + } + + public static BigInteger[] doBigIntegerSplit(BigInteger left, BigInteger right, int expectSliceNumber) { + if (expectSliceNumber < 1) { + throw new IllegalArgumentException(String.format( + "切分份数不能小于1. 此处:expectSliceNumber=[%s].", expectSliceNumber)); + } + + if (null == left || null == right) { + throw new IllegalArgumentException(String.format( + "对 BigInteger 进行切分时,其左右区间不能为 null. 此处:left=[%s],right=[%s].", left, right)); + } + + if (left.compareTo(right) == 0) { + return new BigInteger[]{left, right}; + } else { + // 调整大小顺序,确保 left < right + if (left.compareTo(right) > 0) { + BigInteger temp = left; + left = right; + right = temp; + } + + //left < right + BigInteger endAndStartGap = right.subtract(left); + + BigInteger step = endAndStartGap.divide(BigInteger.valueOf(expectSliceNumber)); + BigInteger remainder = endAndStartGap.remainder(BigInteger.valueOf(expectSliceNumber)); + + //remainder 不可能超过expectSliceNumber,所以不需要检查remainder的 Integer 的范围 + + // 这里不能 step.intValue()==0,因为可能溢出 + if (step.compareTo(BigInteger.ZERO) == 0) { + expectSliceNumber = remainder.intValue(); + } + + BigInteger[] result = new BigInteger[expectSliceNumber + 1]; + result[0] = left; + result[expectSliceNumber] = right; + + BigInteger lowerBound; + BigInteger upperBound = left; + for (int i = 1; i < expectSliceNumber; i++) { + lowerBound = upperBound; + upperBound = lowerBound.add(step); + upperBound = upperBound.add((remainder.compareTo(BigInteger.valueOf(i)) >= 0) + ? BigInteger.ONE : BigInteger.ZERO); + result[i] = upperBound; + } + + return result; + } + } + + private static void checkIfBetweenRange(int value, int left, int right) { + if (value < left || value > right) { + throw new IllegalArgumentException(String.format("parameter can not <[%s] or >[%s].", + left, right)); + } + } + + /** + * 由于只支持 ascii 码对应字符,所以radix 范围为[1,128] + */ + public static BigInteger stringToBigInteger(String aString, int radix) { + if (null == aString) { + throw new IllegalArgumentException("参数 bigInteger 不能为空."); + } + + checkIfBetweenRange(radix, 1, 128); + + BigInteger result = BigInteger.ZERO; + BigInteger radixBigInteger = BigInteger.valueOf(radix); + + int tempChar; + int k = 0; + + for (int i = aString.length() - 1; i >= 0; i--) { + tempChar = aString.charAt(i); + if (tempChar >= 128) { + throw new IllegalArgumentException(String.format("根据字符串进行切分时仅支持 ASCII 字符串,而字符串:[%s]非 ASCII 字符串.", aString)); + } + result = result.add(BigInteger.valueOf(tempChar).multiply(radixBigInteger.pow(k))); + k++; + } + + return result; + } + + /** + * 把BigInteger 转换为 String.注意:radix 和 basic 范围都为[1,128], radix + basic 的范围也必须在[1,128]. + */ + private static String bigIntegerToString(BigInteger bigInteger, int radix) { + if (null == bigInteger) { + throw new IllegalArgumentException("参数 bigInteger 不能为空."); + } + + checkIfBetweenRange(radix, 1, 128); + + StringBuilder resultStringBuilder = new StringBuilder(); + + List list = new ArrayList(); + BigInteger radixBigInteger = BigInteger.valueOf(radix); + BigInteger currentValue = bigInteger; + + BigInteger quotient = currentValue.divide(radixBigInteger); + while (quotient.compareTo(BigInteger.ZERO) > 0) { + list.add(currentValue.remainder(radixBigInteger).intValue()); + currentValue = currentValue.divide(radixBigInteger); + quotient = currentValue; + } + Collections.reverse(list); + + if (list.isEmpty()) { + list.add(0, bigInteger.remainder(radixBigInteger).intValue()); + } + + Map map = new HashMap(); + for (int i = 0; i < radix; i++) { + map.put(i, (char) (i)); + } + +// String msg = String.format("%s 转为 %s 进制,结果为:%s", bigInteger.longValue(), radix, list); +// System.out.println(msg); + + for (Integer aList : list) { + resultStringBuilder.append(map.get(aList)); + } + + return resultStringBuilder.toString(); + } + + /** + * 获取字符串中的最小字符和最大字符(依据 ascii 进行判断).要求字符串必须非空,并且为 ascii 字符串. + * 返回的Pair,left=最小字符,right=最大字符. + */ + public static Pair getMinAndMaxCharacter(String aString) { + if (!isPureAscii(aString)) { + throw new IllegalArgumentException(String.format("根据字符串进行切分时仅支持 ASCII 字符串,而字符串:[%s]非 ASCII 字符串.", aString)); + } + + char min = aString.charAt(0); + char max = min; + + char temp; + for (int i = 1, len = aString.length(); i < len; i++) { + temp = aString.charAt(i); + min = min < temp ? min : temp; + max = max > temp ? max : temp; + } + + return new ImmutablePair(min, max); + } + + private static boolean isPureAscii(String aString) { + if (null == aString) { + return false; + } + + for (int i = 0, len = aString.length(); i < len; i++) { + char ch = aString.charAt(i); + if (ch >= 127 || ch < 0) { + return false; + } + } + return true; + } + +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/RetryUtil.java b/common/src/main/java/com/alibaba/datax/common/util/RetryUtil.java new file mode 100755 index 000000000..51f3f277c --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/RetryUtil.java @@ -0,0 +1,171 @@ +package com.alibaba.datax.common.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.*; + +public final class RetryUtil { + + private static final Logger LOG = LoggerFactory.getLogger(RetryUtil.class); + + private static final long MAX_SLEEP_MILLISECOND = 256 * 1000; + + /** + * 重试次数工具方法. + * + * @param callable 实际逻辑 + * @param retryTimes 最大重试次数(>1) + * @param sleepTimeInMilliSecond 运行失败后休眠对应时间再重试 + * @param exponential 休眠时间是否指数递增 + * @param 返回值类型 + * @return 经过重试的callable的执行结果 + */ + public static T executeWithRetry(Callable callable, + int retryTimes, + long sleepTimeInMilliSecond, + boolean exponential) throws Exception { + Retry retry = new Retry(); + return retry.doRetry(callable, retryTimes, sleepTimeInMilliSecond, exponential); + } + + /** + * 在外部线程执行并且重试。每次执行需要在timeoutMs内执行完,不然视为失败。 + * 执行异步操作的线程池从外部传入,线程池的共享粒度由外部控制。比如,HttpClientUtil共享一个线程池。 + *

+ * 限制条件:仅仅能够在阻塞的时候interrupt线程 + * + * @param callable 实际逻辑 + * @param retryTimes 最大重试次数(>1) + * @param sleepTimeInMilliSecond 运行失败后休眠对应时间再重试 + * @param exponential 休眠时间是否指数递增 + * @param timeoutMs callable执行超时时间,毫秒 + * @param executor 执行异步操作的线程池 + * @param 返回值类型 + * @return 经过重试的callable的执行结果 + */ + public static T asyncExecuteWithRetry(Callable callable, + int retryTimes, + long sleepTimeInMilliSecond, + boolean exponential, + long timeoutMs, + ThreadPoolExecutor executor) throws Exception { + Retry retry = new AsyncRetry(timeoutMs, executor); + return retry.doRetry(callable, retryTimes, sleepTimeInMilliSecond, exponential); + } + + /** + * 创建异步执行的线程池。特性如下: + * core大小为0,初始状态下无线程,无初始消耗。 + * max大小为5,最多五个线程。 + * 60秒超时时间,闲置超过60秒线程会被回收。 + * 使用SynchronousQueue,任务不会排队,必须要有可用线程才能提交成功,否则会RejectedExecutionException。 + * + * @return 线程池 + */ + public static ThreadPoolExecutor createThreadPoolExecutor() { + return new ThreadPoolExecutor(0, 5, + 60L, TimeUnit.SECONDS, + new SynchronousQueue()); + } + + + private static class Retry { + + public T doRetry(Callable callable, int retryTimes, long sleepTimeInMilliSecond, boolean exponential) + throws Exception { + + if (null == callable) { + throw new IllegalArgumentException("系统编程错误, 入参callable不能为空 ! "); + } + + if (retryTimes < 1) { + throw new IllegalArgumentException(String.format( + "系统编程错误, 入参retrytime[%d]不能小于1 !", retryTimes)); + } + + Exception saveException = null; + for (int i = 0; i < retryTimes; i++) { + try { + return call(callable); + } catch (Exception e) { + saveException = e; + + if (i + 1 < retryTimes && sleepTimeInMilliSecond > 0) { + long startTime = System.currentTimeMillis(); + + long timeToSleep; + if (exponential) { + timeToSleep = sleepTimeInMilliSecond * (long) Math.pow(2, i); + if(timeToSleep >= MAX_SLEEP_MILLISECOND) { + timeToSleep = MAX_SLEEP_MILLISECOND; + } + } else { + timeToSleep = sleepTimeInMilliSecond; + if(timeToSleep >= MAX_SLEEP_MILLISECOND) { + timeToSleep = MAX_SLEEP_MILLISECOND; + } + } + + try { + Thread.sleep(timeToSleep); + } catch (InterruptedException ignored) { + } + + long realTimeSleep = System.currentTimeMillis()-startTime; + + LOG.error(String.format("Exception when calling callable, 即将尝试执行第%s次重试.本次重试计划等待[%s]ms,实际等待[%s]ms, 异常Msg:[%s]", + i+1, timeToSleep,realTimeSleep, e.getMessage())); + + } + } + } + throw saveException; + } + + protected T call(Callable callable) throws Exception { + return callable.call(); + } + } + + private static class AsyncRetry extends Retry { + + private long timeoutMs; + private ThreadPoolExecutor executor; + + public AsyncRetry(long timeoutMs, ThreadPoolExecutor executor) { + this.timeoutMs = timeoutMs; + this.executor = executor; + } + + /** + * 使用传入的线程池异步执行任务,并且等待。 + *

+ * future.get()方法,等待指定的毫秒数。如果任务在超时时间内结束,则正常返回。 + * 如果抛异常(可能是执行超时、执行异常、被其他线程cancel或interrupt),都记录日志并且网上抛异常。 + * 正常和非正常的情况都会判断任务是否结束,如果没有结束,则cancel任务。cancel参数为true,表示即使 + * 任务正在执行,也会interrupt线程。 + * + * @param callable + * @param + * @return + * @throws Exception + */ + @Override + protected T call(Callable callable) throws Exception { + Future future = executor.submit(callable); + try { + return future.get(timeoutMs, TimeUnit.MILLISECONDS); + } catch (Exception e) { + LOG.warn("Try once failed", e); + throw e; + } finally { + if (!future.isDone()) { + future.cancel(true); + LOG.warn("Try once task not done, cancel it, active count: " + executor.getActiveCount()); + } + } + } + } + +} diff --git a/common/src/main/java/com/alibaba/datax/common/util/StrUtil.java b/common/src/main/java/com/alibaba/datax/common/util/StrUtil.java new file mode 100755 index 000000000..82222b0d4 --- /dev/null +++ b/common/src/main/java/com/alibaba/datax/common/util/StrUtil.java @@ -0,0 +1,85 @@ +package com.alibaba.datax.common.util; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; + +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StrUtil { + + private final static long KB_IN_BYTES = 1024; + + private final static long MB_IN_BYTES = 1024 * KB_IN_BYTES; + + private final static long GB_IN_BYTES = 1024 * MB_IN_BYTES; + + private final static long TB_IN_BYTES = 1024 * GB_IN_BYTES; + + private final static DecimalFormat df = new DecimalFormat("0.00"); + + private static final Pattern VARIABLE_PATTERN = Pattern + .compile("(\\$)\\{?(\\w+)\\}?"); + + private static String SYSTEM_ENCODING = System.getProperty("file.encoding"); + + static { + if (SYSTEM_ENCODING == null) { + SYSTEM_ENCODING = "UTF-8"; + } + } + + private StrUtil() { + } + + public static String stringify(long byteNumber) { + if (byteNumber / TB_IN_BYTES > 0) { + return df.format((double) byteNumber / (double) TB_IN_BYTES) + "TB"; + } else if (byteNumber / GB_IN_BYTES > 0) { + return df.format((double) byteNumber / (double) GB_IN_BYTES) + "GB"; + } else if (byteNumber / MB_IN_BYTES > 0) { + return df.format((double) byteNumber / (double) MB_IN_BYTES) + "MB"; + } else if (byteNumber / KB_IN_BYTES > 0) { + return df.format((double) byteNumber / (double) KB_IN_BYTES) + "KB"; + } else { + return String.valueOf(byteNumber) + "B"; + } + } + + + public static String replaceVariable(final String param) { + Map mapping = new HashMap(); + + Matcher matcher = VARIABLE_PATTERN.matcher(param); + while (matcher.find()) { + String variable = matcher.group(2); + String value = System.getProperty(variable); + if (StringUtils.isBlank(value)) { + value = matcher.group(); + } + mapping.put(matcher.group(), value); + } + + String retString = param; + for (final String key : mapping.keySet()) { + retString = retString.replace(key, mapping.get(key)); + } + + return retString; + } + + public static String compressMiddle(String s, int headLength, int tailLength) { + Validate.notNull(s, "Input string must not be null"); + Validate.isTrue(headLength > 0, "Head length must be larger than 0"); + Validate.isTrue(tailLength > 0, "Tail length must be larger than 0"); + + if(headLength + tailLength >= s.length()) { + return s; + } + return s.substring(0, headLength) + "..." + s.substring(s.length() - tailLength); + } + +} diff --git a/common/src/test/java/com/alibaba/datax/common/base/BaseTest.java b/common/src/test/java/com/alibaba/datax/common/base/BaseTest.java new file mode 100755 index 000000000..bbc88d9bb --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/base/BaseTest.java @@ -0,0 +1,30 @@ +package com.alibaba.datax.common.base; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; + +import com.alibaba.datax.common.element.ColumnCast; +import com.alibaba.datax.common.element.ColumnCastTest; +import com.alibaba.datax.common.util.Configuration; +import org.junit.Test; + +public class BaseTest { + + @BeforeClass + public static void beforeClass() throws IOException { + String path = ColumnCastTest.class.getClassLoader().getResource(".") + .getFile(); + ColumnCast.bind(Configuration.from(FileUtils.readFileToString(new File( + StringUtils.join(new String[] { path, "all.json" }, + File.separator))))); + } + + @Test + public void emptyTest() { + + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/BoolColumnTest.java b/common/src/test/java/com/alibaba/datax/common/element/BoolColumnTest.java new file mode 100755 index 000000000..d1db4d0c6 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/BoolColumnTest.java @@ -0,0 +1,79 @@ +package com.alibaba.datax.common.element; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.base.BaseTest; +import com.alibaba.datax.common.exception.DataXException; + +public class BoolColumnTest extends BaseTest { + @Test + public void test_true() { + BoolColumn bool = new BoolColumn(true); + Assert.assertTrue(bool.asBoolean().equals(true)); + Assert.assertTrue(bool.asString().equals("true")); + Assert.assertTrue(bool.asDouble().equals(1.0d)); + Assert.assertTrue(bool.asLong().equals(1L)); + + try { + bool.asDate(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + bool.asBytes(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_false() { + BoolColumn bool = new BoolColumn(false); + Assert.assertTrue(bool.asBoolean().equals(false)); + Assert.assertTrue(bool.asString().equals("false")); + Assert.assertTrue(bool.asDouble().equals(0.0d)); + Assert.assertTrue(bool.asLong().equals(0L)); + + try { + bool.asDate(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + bool.asBytes(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_null() { + BoolColumn bool = new BoolColumn(); + Assert.assertTrue(bool.asBoolean() == null); + Assert.assertTrue(bool.asString() == null); + Assert.assertTrue(bool.asDouble() == null); + Assert.assertTrue(bool.asLong() == null); + + try { + bool.asDate(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + bool.asBytes(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_nullReference() { + Boolean b = null; + BoolColumn boolColumn = new BoolColumn(b); + Assert.assertTrue(boolColumn.asBoolean() == null); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/ColumnCastTest.java b/common/src/test/java/com/alibaba/datax/common/element/ColumnCastTest.java new file mode 100755 index 000000000..ff800b5cb --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/ColumnCastTest.java @@ -0,0 +1,95 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.util.Configuration; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.sql.Date; +import java.sql.Time; +import java.text.ParseException; + +public class ColumnCastTest { + private Configuration produce() throws IOException { + String path = ColumnCastTest.class.getClassLoader().getResource(".") + .getFile(); + String content = FileUtils.readFileToString(new File(StringUtils.join( + new String[] { path, "all.json" }, File.separator))); + return Configuration.from(content); + } + + @Test + public void test_string() throws IOException, ParseException { + Configuration configuration = this.produce(); + StringCast.init(configuration); + + System.out.println(StringCast.asDate(new StringColumn("2014-09-18"))); + Assert.assertTrue(StringCast.asDate(new StringColumn("2014-09-18")) + .getTime() == 1410969600000L); + + Assert.assertTrue(StringCast.asDate(new StringColumn("20140918")) + .getTime() == 1410969600000L); + + Assert.assertTrue(StringCast.asDate(new StringColumn("08:00:00")) + .getTime() == 0L); + + Assert.assertTrue(StringCast.asDate( + new StringColumn("2014-09-18 16:00:00")).getTime() == 1411027200000L); + configuration + .set("common.column.datetimeFormat", "yyyy/MM/dd HH:mm:ss"); + StringCast.init(configuration); + Assert.assertTrue(StringCast.asDate( + new StringColumn("2014/09/18 16:00:00")).getTime() == 1411027200000L); + + configuration.set("common.column.timeZone", "GMT"); + StringCast.init(configuration); + + java.util.Date date = StringCast.asDate(new StringColumn( + "2014/09/18 16:00:00")); + System.out.println(DateFormatUtils.format(date, "yyyy/MM/dd HH:mm:ss")); + Assert.assertTrue("2014/09/19 00:00:00".equals(DateFormatUtils.format( + date, "yyyy/MM/dd HH:mm:ss"))); + + } + + @Test + public void test_date() throws IOException { + Assert.assertTrue(DateCast.asString( + new DateColumn(System.currentTimeMillis())).startsWith("201")); + + Configuration configuration = this.produce(); + configuration + .set("common.column.datetimeFormat", "MM/dd/yyyy HH:mm:ss"); + DateCast.init(configuration); + System.out.println(DateCast.asString(new DateColumn(System + .currentTimeMillis()))); + Assert.assertTrue(!DateCast.asString( + new DateColumn(System.currentTimeMillis())).startsWith("2014")); + + DateColumn dateColumn = new DateColumn(new Time(0L)); + System.out.println(dateColumn.asString()); + Assert.assertTrue(dateColumn.asString().equals("08:00:00")); + + configuration.set("common.column.timeZone", "GMT"); + DateCast.init(configuration); + System.err.println(DateCast.asString(dateColumn)); + Assert.assertTrue(dateColumn.asString().equals("00:00:00")); + + configuration.set("common.column.timeZone", "GMT+8"); + DateCast.init(configuration); + System.out.println(dateColumn.asString()); + Assert.assertTrue(dateColumn.asString().equals("08:00:00")); + + dateColumn = new DateColumn(new Date(0L)); + System.out.println(dateColumn.asString()); + Assert.assertTrue(dateColumn.asString().equals("1970-01-01")); + + dateColumn = new DateColumn(new java.util.Date(0L)); + System.out.println(dateColumn.asString()); + Assert.assertTrue(dateColumn.asString().equals("01/01/1970 08:00:00")); + } +} \ No newline at end of file diff --git a/common/src/test/java/com/alibaba/datax/common/element/DateColumnTest.java b/common/src/test/java/com/alibaba/datax/common/element/DateColumnTest.java new file mode 100755 index 000000000..2c063db12 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/DateColumnTest.java @@ -0,0 +1,109 @@ +package com.alibaba.datax.common.element; + +import com.alibaba.datax.common.base.BaseTest; +import com.alibaba.datax.common.exception.DataXException; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Date; + +public class DateColumnTest extends BaseTest { + @Test + public void test() { + long time = System.currentTimeMillis(); + DateColumn date = new DateColumn(time); + Assert.assertTrue(date.getType().equals(Column.Type.DATE)); + Assert.assertTrue(date.asDate().getTime() == time); + Assert.assertTrue(date.asLong().equals(time)); + System.out.println(date.asString()); + Assert.assertTrue(date.asString().startsWith("201")); + + try { + date.asBytes(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + date.asDouble(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_null() { + DateColumn date = new DateColumn(); + DateColumn nul1 = new DateColumn((Long)null); + DateColumn nul2 = new DateColumn((Date)null); + DateColumn nul3 = new DateColumn((java.sql.Date)null); + DateColumn nul4 = new DateColumn((java.sql.Time)null); + DateColumn nul5 = new DateColumn((java.sql.Timestamp)null); + Assert.assertTrue(date.getType().equals(Column.Type.DATE)); + + Assert.assertTrue(date.asDate() == null); + Assert.assertTrue(date.asLong() == null); + Assert.assertTrue(date.asString() == null); + + Assert.assertTrue(nul1.asDate() == null); + Assert.assertTrue(nul1.asLong() == null); + Assert.assertTrue(nul1.asString() == null); + + Assert.assertTrue(nul2.asDate() == null); + Assert.assertTrue(nul2.asLong() == null); + Assert.assertTrue(nul2.asString() == null); + + Assert.assertTrue(nul3.asDate() == null); + Assert.assertTrue(nul3.asLong() == null); + Assert.assertTrue(nul3.asString() == null); + + Assert.assertTrue(nul4.asDate() == null); + Assert.assertTrue(nul4.asLong() == null); + Assert.assertTrue(nul4.asString() == null); + + Assert.assertTrue(nul5.asDate() == null); + Assert.assertTrue(nul5.asLong() == null); + Assert.assertTrue(nul5.asString() == null); + + try { + date.asBytes(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + date.asDouble(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + date.asBoolean(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + } + + @Test + public void testDataColumn() throws Exception { + DateColumn date = new DateColumn(1449925250000L); + Assert.assertEquals(date.asString(),"2015-12-12 21:00:50"); + Assert.assertEquals(date.asDate(),new Date(1449925250000L)); + + java.sql.Date dat2 = new java.sql.Date(1449925251001L); + date = new DateColumn(dat2); + Assert.assertEquals(date.asString(),"2015-12-12"); + Assert.assertEquals(date.asDate(),new Date(1449925251001L)); + + java.sql.Time dat3 = new java.sql.Time(1449925252002L); + date = new DateColumn(dat3); + Assert.assertEquals(date.asString(),"21:00:52"); + Assert.assertEquals(date.asDate(),new Date(1449925252002L)); + + java.sql.Timestamp ts = new java.sql.Timestamp(1449925253003L); + date = new DateColumn(ts); + Assert.assertEquals(date.asString(),"2015-12-12 21:00:53"); + Assert.assertEquals(date.asDate(),new Date(1449925253003L)); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/DoubleColumnTest.java b/common/src/test/java/com/alibaba/datax/common/element/DoubleColumnTest.java new file mode 100755 index 000000000..ab8d12ed7 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/DoubleColumnTest.java @@ -0,0 +1,250 @@ +package com.alibaba.datax.common.element; + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; + +public class DoubleColumnTest { + @Test + public void test_null() { + DoubleColumn column = new DoubleColumn(); + + System.out.println(column.asString()); + Assert.assertTrue(column.asString() == null); + System.out.println(column.toString()); + Assert.assertTrue(column.toString().equals( + "{\"byteSize\":0,\"type\":\"DOUBLE\"}")); + Assert.assertTrue(column.asDouble() == null); + Assert.assertTrue(column.asString() == null); + + try { + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asDate() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_double() { + DoubleColumn column = new DoubleColumn(1.0d); + + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals("1.0")); + System.out.println(column.toString()); + Assert.assertTrue(column.toString().equals( + "{\"byteSize\":3,\"rawData\":\"1.0\",\"type\":\"DOUBLE\"}")); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals(1.0d)); + + try { + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_float() { + DoubleColumn column = new DoubleColumn(1.0f); + + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals("1.0")); + System.out.println(column.toString()); + Assert.assertTrue(column.toString().equals( + "{\"byteSize\":3,\"rawData\":\"1.0\",\"type\":\"DOUBLE\"}")); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals(1.0d)); + + try { + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_string() { + DoubleColumn column = new DoubleColumn("1.0"); + + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals("1.0")); + System.out.println(column.toString()); + Assert.assertTrue(column.toString().equals( + "{\"byteSize\":3,\"rawData\":\"1.0\",\"type\":\"DOUBLE\"}")); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals(1.0d)); + + try { + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_BigDecimal() { + DoubleColumn column = new DoubleColumn(new BigDecimal("1E-100")); + + System.out.println(column.asString()); + System.out.println(column.asString().length()); + Assert.assertTrue(column.asString().length() == 102); + + Assert.assertTrue(column.asString().equals( + new BigDecimal("1E-100").toPlainString())); + + Assert.assertTrue(column + .toString() + .equals("{\"byteSize\":102,\"rawData\":\"0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\",\"type\":\"DOUBLE\"}")); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals(1.0E-100)); + + try { + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_overflow() { + DoubleColumn column = new DoubleColumn(new BigDecimal("1E-1000")); + + System.out.println(column.asString()); + + Assert.assertTrue(column.asBigDecimal().equals( + new BigDecimal("1E-1000"))); + + Assert.assertTrue(column.asBigInteger().compareTo(BigInteger.ZERO) == 0); + Assert.assertTrue(column.asLong().equals(0L)); + + try { + column.asDouble(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + column = new DoubleColumn(new BigDecimal("1E1000")); + Assert.assertTrue(column.asBigDecimal().compareTo( + new BigDecimal("1E1000")) == 0); + Assert.assertTrue(column.asBigInteger().compareTo( + new BigDecimal("1E1000").toBigInteger()) == 0); + try { + column.asDouble(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + try { + column.asLong(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + } + + @Test + public void test_NaN() { + DoubleColumn column = new DoubleColumn(String.valueOf(Double.NaN)); + Assert.assertTrue(column.asString().equals("NaN")); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + column = new DoubleColumn(String.valueOf(Double.POSITIVE_INFINITY)); + Assert.assertTrue(column.asString().equals("Infinity")); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + column = new DoubleColumn(String.valueOf(Double.NEGATIVE_INFINITY)); + Assert.assertTrue(column.asString().equals("-Infinity")); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_doubleFormat() { + System.out.println(new BigDecimal("9801523474.1234567890987654321") + .toPlainString()); + + System.out.println("double: " + 9801523474.399621d); + System.out.println("bigdecimal: " + new BigDecimal(9801523474.399621d).toPlainString()); + System.out.println("bigdecimal: " + new BigDecimal(String.valueOf(9801523474.399621d)).toPlainString()); + System.out.println(new DoubleColumn(9801523474.399621d).asString()); + Assert.assertTrue("9801523474.39962".equals(new DoubleColumn( + 9801523474.399621d).asString())); + + Assert.assertTrue(!new DoubleColumn(Double.MAX_VALUE).asString() + .contains("E")); + Assert.assertTrue(!new DoubleColumn(Float.MAX_VALUE).asString() + .contains("E")); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/LongColumnTest.java b/common/src/test/java/com/alibaba/datax/common/element/LongColumnTest.java new file mode 100755 index 000000000..aa9f242f9 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/LongColumnTest.java @@ -0,0 +1,217 @@ +package com.alibaba.datax.common.element; + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; + +public class LongColumnTest { + + @Test + public void test_null() { + LongColumn column = new LongColumn(); + System.out.println(column.asString()); + Assert.assertTrue(column.asString() == null); + System.out.println(column.toString()); + Assert.assertTrue(column.toString().equals( + "{\"byteSize\":0,\"type\":\"LONG\"}")); + Assert.assertTrue(column.asBoolean() == null); + Assert.assertTrue(column.asDouble() == null); + Assert.assertTrue(column.asString() == null); + Assert.assertTrue(column.asDate() == null); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_normal() { + LongColumn column = new LongColumn(1); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals("1")); + System.out.println(column.toString()); + Assert.assertEquals(column.toString(), + "{\"byteSize\":8,\"rawData\":1,\"type\":\"LONG\"}"); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals(1.0d)); + Assert.assertTrue(column.asDate().equals(new Date(1L))); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_max() { + LongColumn column = new LongColumn(Long.MAX_VALUE); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MAX_VALUE))); + System.out.println(column.toString()); + Assert.assertTrue(column + .toString() + .equals(String + .format("{\"byteSize\":8,\"rawData\":9223372036854775807,\"type\":\"LONG\"}", + Long.MAX_VALUE))); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals((double) Long.MAX_VALUE)); + Assert.assertTrue(column.asDate().equals(new Date(Long.MAX_VALUE))); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_min() { + LongColumn column = new LongColumn(Long.MIN_VALUE); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MIN_VALUE))); + System.out.println(column.toString()); + Assert.assertTrue(column + .toString() + .equals(String + .format("{\"byteSize\":8,\"rawData\":-9223372036854775808,\"type\":\"LONG\"}", + Long.MIN_VALUE))); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals((double) Long.MIN_VALUE)); + Assert.assertTrue(column.asDate().equals(new Date(Long.MIN_VALUE))); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_string() { + LongColumn column = new LongColumn(String.valueOf(Long.MIN_VALUE)); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MIN_VALUE))); + System.out.println(column.toString()); + Assert.assertTrue(column + .toString() + .equals("{\"byteSize\":20,\"rawData\":-9223372036854775808,\"type\":\"LONG\"}")); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals((double) Long.MIN_VALUE)); + Assert.assertTrue(column.asDate().equals(new Date(Long.MIN_VALUE))); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_science() { + LongColumn column = new LongColumn(String.valueOf("4.7E+38")); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals( + "470000000000000000000000000000000000000")); + System.out.println(column.toString()); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(">>" + column.asBigDecimal()); + System.out.println(">>" + new BigDecimal("4.7E+38").toPlainString()); + Assert.assertTrue(column.asBigDecimal().toPlainString() + .equals(new BigDecimal("4.7E+38").toPlainString())); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_bigInteger() { + LongColumn column = new LongColumn(BigInteger.valueOf(Long.MIN_VALUE)); + System.out.println(column.asString()); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MIN_VALUE))); + System.out.println(column.toString()); + Assert.assertEquals(column.toString() + ,String.format("{\"byteSize\":8,\"rawData\":-9223372036854775808,\"type\":\"LONG\"}", + Long.MIN_VALUE)); + Assert.assertTrue(column.asBoolean().equals(true)); + + System.out.println(column.asDouble()); + Assert.assertTrue(column.asDouble().equals((double) Long.MIN_VALUE)); + Assert.assertTrue(column.asDate().equals(new Date(Long.MIN_VALUE))); + + try { + Assert.assertTrue(column.asBytes() == null); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_overflow() { + LongColumn column = new LongColumn(String.valueOf(Long.MAX_VALUE) + + "000"); + + Assert.assertTrue(column.asBoolean().equals(true)); + Assert.assertTrue(column.asBigDecimal().equals( + new BigDecimal(String.valueOf(Long.MAX_VALUE) + "000"))); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MAX_VALUE) + "000")); + Assert.assertTrue(column.asBigInteger().equals( + new BigInteger(String.valueOf(Long.MAX_VALUE) + "000"))); + + try { + column.asLong(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + column = new LongColumn(String.valueOf(Long.MIN_VALUE) + "000"); + + Assert.assertTrue(column.asBoolean().equals(true)); + Assert.assertTrue(column.asBigDecimal().equals( + new BigDecimal(String.valueOf(Long.MIN_VALUE) + "000"))); + Assert.assertTrue(column.asString().equals( + String.valueOf(Long.MIN_VALUE) + "000")); + Assert.assertTrue(column.asBigInteger().equals( + new BigInteger(String.valueOf(Long.MIN_VALUE) + "000"))); + + try { + column.asLong(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/ScientificTester.java b/common/src/test/java/com/alibaba/datax/common/element/ScientificTester.java new file mode 100755 index 000000000..e6a3a1e19 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/ScientificTester.java @@ -0,0 +1,12 @@ +package com.alibaba.datax.common.element; + +import org.apache.commons.lang3.math.NumberUtils; +import org.junit.Test; + +public class ScientificTester { + @Test + public void test() { + System.out.println(NumberUtils.createBigDecimal("10E+6").toBigInteger().toString()); + System.err.println((String) null); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/element/StringColumnTest.java b/common/src/test/java/com/alibaba/datax/common/element/StringColumnTest.java new file mode 100755 index 000000000..ce32ef5a5 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/element/StringColumnTest.java @@ -0,0 +1,216 @@ +package com.alibaba.datax.common.element; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.base.BaseTest; +import com.alibaba.datax.common.exception.DataXException; + +public class StringColumnTest extends BaseTest { + + @Test + public void test_double() { + DoubleColumn real = new DoubleColumn("3.14"); + Assert.assertTrue(real.asString().equals("3.14")); + Assert.assertTrue(real.asDouble().equals(3.14d)); + Assert.assertTrue(real.asLong().equals(3L)); + + try { + real.asBoolean(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + real.asDate(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_int() { + LongColumn integer = new LongColumn("3"); + Assert.assertTrue(integer.asString().equals("3")); + Assert.assertTrue(integer.asDouble().equals(3.0d)); + Assert.assertTrue(integer.asBoolean().equals(true)); + Assert.assertTrue(integer.asLong().equals(3L)); + System.out.println(integer.asDate()); + } + + @Test + public void test_string() { + StringColumn string = new StringColumn("bazhen"); + Assert.assertTrue(string.asString().equals("bazhen")); + try { + string.asLong(); + Assert.assertTrue(false); + + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + try { + string.asDouble(); + Assert.assertTrue(false); + + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + try { + string.asDate(); + Assert.assertTrue(false); + + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + Assert.assertTrue(new String(string.asString().getBytes()) + .equals("bazhen")); + } + + @Test + public void test_bool() { + StringColumn string = new StringColumn("true"); + Assert.assertTrue(string.asString().equals("true")); + Assert.assertTrue(string.asBoolean().equals(true)); + + try { + string.asDate(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + string.asDouble(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + + try { + string.asLong(); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + } + + @Test + public void test_null() throws UnsupportedEncodingException { + StringColumn string = new StringColumn(); + Assert.assertTrue(string.asString() == null); + Assert.assertTrue(string.asLong() == null); + Assert.assertTrue(string.asDouble() == null); + Assert.assertTrue(string.asDate() == null); + Assert.assertTrue(string.asBytes() == null); + } + + @Test + public void test_overflow() { + StringColumn column = new StringColumn( + new BigDecimal("1E-1000").toPlainString()); + + System.out.println(column.asString()); + + Assert.assertTrue(column.asBigDecimal().equals( + new BigDecimal("1E-1000"))); + + Assert.assertTrue(column.asBigInteger().compareTo(BigInteger.ZERO) == 0); + Assert.assertTrue(column.asLong().equals(0L)); + + try { + column.asDouble(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + column = new StringColumn(new BigDecimal("1E1000").toPlainString()); + Assert.assertTrue(column.asBigDecimal().compareTo( + new BigDecimal("1E1000")) == 0); + Assert.assertTrue(column.asBigInteger().compareTo( + new BigDecimal("1E1000").toBigInteger()) == 0); + try { + column.asDouble(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + try { + column.asLong(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + column = new StringColumn(new BigDecimal("-1E1000").toPlainString()); + Assert.assertTrue(column.asBigDecimal().compareTo( + new BigDecimal("-1E1000")) == 0); + Assert.assertTrue(column.asBigInteger().compareTo( + new BigDecimal("-1E1000").toBigInteger()) == 0); + try { + column.asDouble(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + + try { + column.asLong(); + Assert.assertTrue(false); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(true); + } + } + + @Test + public void test_NaN() { + StringColumn column = new StringColumn(String.valueOf(Double.NaN)); + Assert.assertTrue(column.asDouble().equals(Double.NaN)); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + column = new StringColumn(String.valueOf(Double.POSITIVE_INFINITY)); + Assert.assertTrue(column.asDouble().equals(Double.POSITIVE_INFINITY)); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + column = new StringColumn(String.valueOf(Double.NEGATIVE_INFINITY)); + Assert.assertTrue(column.asDouble().equals(Double.NEGATIVE_INFINITY)); + try { + column.asBigDecimal(); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void testEmptyString() { + StringColumn column = new StringColumn(""); + try { + BigDecimal num = column.asBigDecimal(); + } catch(Exception e) { + Assert.assertTrue(e.getMessage().contains("String [\"\"] 不能转为BigDecimal")); + } + + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/exception/DataXExceptionTest.java b/common/src/test/java/com/alibaba/datax/common/exception/DataXExceptionTest.java new file mode 100755 index 000000000..96cebb966 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/exception/DataXExceptionTest.java @@ -0,0 +1,29 @@ +package com.alibaba.datax.common.exception; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.spi.ErrorCode; + +public class DataXExceptionTest { + + private DataXException dataXException; + + @Test + public void basicTest() { + ErrorCode errorCode = FakeErrorCode.FAKE_ERROR_CODE_ONLY_FOR_TEST_00; + String errorMsg = "basicTest"; + dataXException = DataXException.asDataXException(errorCode, errorMsg); + Assert.assertEquals(errorCode.toString() + " - " + errorMsg, + dataXException.getMessage()); + } + + @Test + public void basicTest_中文() { + ErrorCode errorCode = FakeErrorCode.FAKE_ERROR_CODE_ONLY_FOR_TEST_01; + String errorMsg = "basicTest中文"; + dataXException = DataXException.asDataXException(errorCode, errorMsg); + Assert.assertEquals(errorCode.toString() + " - " + errorMsg, + dataXException.getMessage()); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/exception/FakeErrorCode.java b/common/src/test/java/com/alibaba/datax/common/exception/FakeErrorCode.java new file mode 100755 index 000000000..27e2bdafa --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/exception/FakeErrorCode.java @@ -0,0 +1,37 @@ +package com.alibaba.datax.common.exception; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum FakeErrorCode implements ErrorCode { + + FAKE_ERROR_CODE_ONLY_FOR_TEST_00("FakeErrorCode-00", + "only a test, FakeErrorCode."), FAKE_ERROR_CODE_ONLY_FOR_TEST_01( + "FakeErrorCode-01", + "only a test, FakeErrorCode,测试中文."), + + ; + + private final String code; + private final String description; + + private FakeErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Describe:[%s]", this.code, + this.description); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/statistics/PerfRecordTest.java b/common/src/test/java/com/alibaba/datax/common/statistics/PerfRecordTest.java new file mode 100644 index 000000000..66c07570e --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/statistics/PerfRecordTest.java @@ -0,0 +1,471 @@ +package com.alibaba.datax.common.statistics; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.List; + +/** + * Created by liqiang on 15/8/26. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PerfRecordTest { + private static Logger LOG = LoggerFactory.getLogger(PerfRecordTest.class); + private final int TGID = 1; + + + @Before + public void setUp() throws Exception { + Field instance=PerfTrace.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(null,null); + } + + public boolean hasRecordInList(List perfRecordList,PerfRecord perfRecord){ + if(perfRecordList==null || perfRecordList.size()==0){ + return false; + } + + for(PerfRecord perfRecord1:perfRecordList){ + if(perfRecord.equals(perfRecord1)){ + return true; + } + } + + return false; + } + + @Test + public void test001PerfRecordEquals() throws Exception { + PerfTrace.getInstance(true, 1001, 1, 0, true); + + PerfRecord initPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord.start(); + Thread.sleep(50); + initPerfRecord.end(); + + PerfRecord initPerfRecord2 = initPerfRecord.copy(); + + Assert.assertTrue(initPerfRecord.equals(initPerfRecord2)); + + PerfRecord initPerfRecord3 = new PerfRecord(TGID, 1, PerfRecord.PHASE.READ_TASK_DESTROY); + initPerfRecord3.start(); + Thread.sleep(1050); + initPerfRecord3.end(); + + Assert.assertTrue(!initPerfRecord.equals(initPerfRecord3)); + + PerfRecord initPerfRecord4 = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord4.start(); + Thread.sleep(2050); + initPerfRecord4.end(); + + System.out.println(initPerfRecord4.toString()); + System.out.println(initPerfRecord.toString()); + + Assert.assertTrue(!initPerfRecord.equals(initPerfRecord4)); + + PerfRecord initPerfRecord5 = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord5.start(); + Thread.sleep(50); + initPerfRecord5.end(); + + initPerfRecord5.addCount(100); + initPerfRecord5.addSize(200); + + Assert.assertTrue(!initPerfRecord.equals(initPerfRecord5)); + + PerfRecord initPerfRecord6 = initPerfRecord.copy(); + initPerfRecord6.addCount(1001); + initPerfRecord6.addSize(1001); + + Assert.assertTrue(initPerfRecord.equals(initPerfRecord6)); + + } + + @Test + public void test002Normal() throws Exception { + + PerfTrace.getInstance(true, 1001, 1, 0, true); + + PerfRecord initPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord.start(); + Thread.sleep(1050); + initPerfRecord.end(); + + Assert.assertTrue(initPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(initPerfRecord.getElapsedTimeInNs() >= 1050000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), initPerfRecord)); + + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord.start(); + Thread.sleep(1020); + preparePerfRecord.end(); + + Assert.assertTrue(preparePerfRecord.getAction().name().equals("end")); + Assert.assertTrue(preparePerfRecord.getElapsedTimeInNs() >= 1020000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), preparePerfRecord)); + + + LOG.debug("task writer starts to write ..."); + PerfRecord dataPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecord.start(); + + Thread.sleep(1200); + dataPerfRecord.addCount(1001); + dataPerfRecord.addSize(1002); + dataPerfRecord.end(); + + Assert.assertTrue(dataPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(dataPerfRecord.getElapsedTimeInNs() >= 1020000000); + Assert.assertTrue(dataPerfRecord.getCount() == 1001); + Assert.assertTrue(dataPerfRecord.getSize() == 1002); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), dataPerfRecord)); + + + PerfRecord destoryPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.READ_TASK_DESTROY); + destoryPerfRecord.start(); + + Thread.sleep(250); + destoryPerfRecord.end(); + + Assert.assertTrue(destoryPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(destoryPerfRecord.getElapsedTimeInNs() >= 250000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DESTROY).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), destoryPerfRecord)); + + PerfRecord waitTimePerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WAIT_READ_TIME); + waitTimePerfRecord.start(); + + Thread.sleep(250); + waitTimePerfRecord.end(); + + Assert.assertTrue(waitTimePerfRecord.getAction().name().equals("end")); + Assert.assertTrue(waitTimePerfRecord.getElapsedTimeInNs() >= 250000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_READ_TIME).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), waitTimePerfRecord)); + + + + PerfRecord initPerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord2.start(); + Thread.sleep(50); + initPerfRecord2.end(); + + Assert.assertTrue(initPerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(initPerfRecord2.getElapsedTimeInNs() >= 50000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), initPerfRecord2)); + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord2.start(); + Thread.sleep(20); + preparePerfRecord2.end(); + LOG.debug("task writer starts to write ..."); + + Assert.assertTrue(preparePerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(preparePerfRecord2.getElapsedTimeInNs() >= 20000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), preparePerfRecord2)); + + + PerfRecord dataPerfRecor2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecor2.start(); + + Thread.sleep(2200); + dataPerfRecor2.addCount(2001); + dataPerfRecor2.addSize(2002); + dataPerfRecor2.end(); + + Assert.assertTrue(dataPerfRecor2.getAction().name().equals("end")); + Assert.assertTrue(dataPerfRecor2.getElapsedTimeInNs() >= 2200000000L); + Assert.assertTrue(dataPerfRecor2.getCount() == 2001); + Assert.assertTrue(dataPerfRecor2.getSize() == 2002); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), dataPerfRecor2)); + + + PerfRecord destoryPerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.READ_TASK_DESTROY); + destoryPerfRecord2.start(); + + Thread.sleep(1250); + destoryPerfRecord2.end(); + + Assert.assertTrue(destoryPerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(destoryPerfRecord2.getElapsedTimeInNs() >= 1250000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DESTROY).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), destoryPerfRecord2)); + + PerfRecord waitPerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WAIT_READ_TIME); + waitPerfRecord2.start(); + + Thread.sleep(1250); + waitPerfRecord2.end(); + + Assert.assertTrue(waitPerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(waitPerfRecord2.getElapsedTimeInNs() >= 1250000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_READ_TIME).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), waitPerfRecord2)); + + + PerfTrace.getInstance().addTaskDetails(1, " "); + PerfTrace.getInstance().addTaskDetails(1, "task 1 some thing abcdf"); + PerfTrace.getInstance().addTaskDetails(2,"before char"); + PerfTrace.getInstance().addTaskDetails(2,"task 2 some thing abcdf"); + + Assert.assertTrue(PerfTrace.getInstance().getTaskDetails().get(1).equals("task 1 some thing abcdf")); + Assert.assertTrue(PerfTrace.getInstance().getTaskDetails().get(2).equals("before char,task 2 some thing abcdf")); + System.out.println(PerfTrace.getInstance().summarizeNoException()); + } + @Test + public void test003Disable() throws Exception { + + PerfTrace.getInstance(true, 1001, 1, 0, false); + + PerfRecord initPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord.start(); + Thread.sleep(1050); + initPerfRecord.end(); + + Assert.assertTrue(initPerfRecord.getDatetime().equals("null time")); + Assert.assertTrue(initPerfRecord.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT) == null); + + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord.start(); + Thread.sleep(1020); + preparePerfRecord.end(); + LOG.debug("task writer starts to write ..."); + + Assert.assertTrue(preparePerfRecord.getDatetime().equals("null time")); + Assert.assertTrue(preparePerfRecord.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE) == null); + + + PerfRecord dataPerfRecord = new PerfRecord(TGID, 1, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecord.start(); + + Thread.sleep(1200); + dataPerfRecord.addCount(1001); + dataPerfRecord.addSize(1001); + dataPerfRecord.end(); + + Assert.assertTrue(dataPerfRecord.getDatetime().equals("null time")); + Assert.assertTrue(dataPerfRecord.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA) == null); + + PerfRecord waitPerfRecor1 = new PerfRecord(TGID, 1, PerfRecord.PHASE.WAIT_WRITE_TIME); + waitPerfRecor1.start(); + + Thread.sleep(2200); + waitPerfRecor1.end(); + + Assert.assertTrue(waitPerfRecor1.getDatetime().equals("null time")); + Assert.assertTrue(waitPerfRecor1.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_WRITE_TIME) == null); + + + PerfRecord initPerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord2.start(); + Thread.sleep(50); + initPerfRecord2.end(); + + Assert.assertTrue(initPerfRecord2.getDatetime().equals("null time")); + Assert.assertTrue(initPerfRecord2.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT) == null); + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord2.start(); + Thread.sleep(20); + preparePerfRecord2.end(); + LOG.debug("task writer starts to write ..."); + + Assert.assertTrue(preparePerfRecord2.getDatetime().equals("null time")); + Assert.assertTrue(preparePerfRecord2.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE) == null); + + + + PerfRecord dataPerfRecor2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecor2.start(); + + Thread.sleep(2200); + dataPerfRecor2.addCount(2001); + dataPerfRecor2.addSize(2001); + dataPerfRecor2.end(); + + Assert.assertTrue(dataPerfRecor2.getDatetime().equals("null time")); + Assert.assertTrue(dataPerfRecor2.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA) == null); + + PerfRecord waitPerfRecor2 = new PerfRecord(TGID, 2, PerfRecord.PHASE.WAIT_WRITE_TIME); + waitPerfRecor2.start(); + + Thread.sleep(2200); + waitPerfRecor2.end(); + + Assert.assertTrue(waitPerfRecor2.getDatetime().equals("null time")); + Assert.assertTrue(waitPerfRecor2.getElapsedTimeInNs() == -1); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_WRITE_TIME) == null); + + PerfTrace.getInstance().addTaskDetails(1, "task 1 some thing abcdf"); + PerfTrace.getInstance().addTaskDetails(2, "task 2 some thing abcdf"); + + Assert.assertTrue(PerfTrace.getInstance().getTaskDetails().size()==0); + System.out.println(PerfTrace.getInstance().summarizeNoException()); + } + + @Test + public void test004Normal2() throws Exception { + int priority = 0; + try { + priority = Integer.parseInt(System.getenv("SKYNET_PRIORITY")); + }catch (NumberFormatException e){ + LOG.warn("prioriy set to 0, because NumberFormatException, the value is: "+System.getProperty("PROIORY")); + } + + System.out.println("priority====" + priority); + + PerfTrace.getInstance(false, 1001001001001L, 1, 0, true); + + PerfRecord initPerfRecord = new PerfRecord(TGID, 10000001, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord.start(); + Thread.sleep(1050); + initPerfRecord.end(); + + Assert.assertTrue(initPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(initPerfRecord.getElapsedTimeInNs() >= 1050000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), initPerfRecord)); + + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord = new PerfRecord(TGID, 10000001, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord.start(); + Thread.sleep(1020); + preparePerfRecord.end(); + + Assert.assertTrue(preparePerfRecord.getAction().name().equals("end")); + Assert.assertTrue(preparePerfRecord.getElapsedTimeInNs() >= 1020000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), preparePerfRecord)); + + LOG.debug("task wait time ..."); + PerfRecord waitPerfRecord = new PerfRecord(TGID, 10000001, PerfRecord.PHASE.WAIT_WRITE_TIME); + waitPerfRecord.start(); + Thread.sleep(1030); + waitPerfRecord.end(); + + Assert.assertTrue(waitPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(waitPerfRecord.getElapsedTimeInNs() >= 1030000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_WRITE_TIME).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), waitPerfRecord)); + + + + LOG.debug("task writer starts to write ..."); + + PerfRecord dataPerfRecord = new PerfRecord(TGID, 10000001, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecord.start(); + + Thread.sleep(1200); + dataPerfRecord.addCount(1001); + dataPerfRecord.addSize(1002); + dataPerfRecord.end(); + + Assert.assertTrue(dataPerfRecord.getAction().name().equals("end")); + Assert.assertTrue(dataPerfRecord.getElapsedTimeInNs() >= 1020000000); + Assert.assertTrue(dataPerfRecord.getCount() == 1001); + Assert.assertTrue(dataPerfRecord.getSize() == 1002); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA).getTotalCount() == 1); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), dataPerfRecord)); + + + PerfRecord initPerfRecord2 = new PerfRecord(TGID, 10000002, PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord2.start(); + Thread.sleep(50); + initPerfRecord2.end(); + + Assert.assertTrue(initPerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(initPerfRecord2.getElapsedTimeInNs() >= 50000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_INIT).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), initPerfRecord2)); + + LOG.debug("task wait time ..."); + PerfRecord waitPerfRecord2 = new PerfRecord(TGID, 10000002, PerfRecord.PHASE.WAIT_WRITE_TIME); + waitPerfRecord2.start(); + Thread.sleep(2030); + waitPerfRecord2.end(); + + Assert.assertTrue(waitPerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(waitPerfRecord2.getElapsedTimeInNs() >= 2030000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WAIT_WRITE_TIME).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), waitPerfRecord2)); + + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord2 = new PerfRecord(TGID, 10000002, PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord2.start(); + Thread.sleep(20); + preparePerfRecord2.end(); + + Assert.assertTrue(preparePerfRecord2.getAction().name().equals("end")); + Assert.assertTrue(preparePerfRecord2.getElapsedTimeInNs() >= 20000000); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.WRITE_TASK_PREPARE).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), preparePerfRecord2)); + + + LOG.debug("task writer starts to write ..."); + + PerfRecord dataPerfRecor2 = new PerfRecord(TGID, 10000002, PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecor2.start(); + + Thread.sleep(2200); + dataPerfRecor2.addCount(2001); + dataPerfRecor2.addSize(2002); + dataPerfRecor2.end(); + + Assert.assertTrue(dataPerfRecor2.getAction().name().equals("end")); + Assert.assertTrue(dataPerfRecor2.getElapsedTimeInNs() >= 2200000000L); + Assert.assertTrue(dataPerfRecor2.getCount() == 2001); + Assert.assertTrue(dataPerfRecor2.getSize() == 2002); + Assert.assertTrue(PerfTrace.getInstance().getPerfRecordMaps().get(PerfRecord.PHASE.READ_TASK_DATA).getTotalCount() == 2); + Assert.assertTrue(hasRecordInList(PerfTrace.getInstance().getWaitingReportList(), dataPerfRecor2)); + + + PerfTrace.getInstance().addTaskDetails(10000001, "task 100000011 some thing abcdf"); + PerfTrace.getInstance().addTaskDetails(10000002, "task 100000012 some thing abcdf"); + PerfTrace.getInstance().addTaskDetails(10000004, "task 100000012 some thing abcdf?123?345"); + PerfTrace.getInstance().addTaskDetails(10000005, "task 100000012 some thing abcdf?456"); + PerfTrace.getInstance().addTaskDetails(10000006, "[task 100000012? some thing abcdf?456"); + + Assert.assertTrue(PerfTrace.getInstance().getTaskDetails().get(10000001).equals("task 100000011 some thing abcdf")); + Assert.assertTrue(PerfTrace.getInstance().getTaskDetails().get(10000002).equals("task 100000012 some thing abcdf")); + + PerfRecord.addPerfRecord(TGID, 10000003, PerfRecord.PHASE.TASK_TOTAL, System.currentTimeMillis(), 12300123L * 1000L * 1000L); + PerfRecord.addPerfRecord(TGID, 10000004, PerfRecord.PHASE.TASK_TOTAL, System.currentTimeMillis(), 22300123L * 1000L * 1000L); + PerfRecord.addPerfRecord(TGID, 10000005, PerfRecord.PHASE.SQL_QUERY, System.currentTimeMillis(), 4L); + PerfRecord.addPerfRecord(TGID, 10000006, PerfRecord.PHASE.RESULT_NEXT_ALL, System.currentTimeMillis(), 3000L); + PerfRecord.addPerfRecord(TGID, 10000006, PerfRecord.PHASE.ODPS_BLOCK_CLOSE, System.currentTimeMillis(), 2000000L); + + System.out.println(PerfTrace.getInstance().summarizeNoException()); + + + } + +} \ No newline at end of file diff --git a/common/src/test/java/com/alibaba/datax/common/statistics/VMInfoTest.java b/common/src/test/java/com/alibaba/datax/common/statistics/VMInfoTest.java new file mode 100644 index 000000000..ce97007c5 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/statistics/VMInfoTest.java @@ -0,0 +1,109 @@ +package com.alibaba.datax.common.statistics; + +import org.junit.Assert; +import org.junit.Test; + +import java.lang.management.*; +import java.util.Arrays; +import java.util.List; + +/** + * Created by liqiang on 15/11/12. + */ +public class VMInfoTest { + static final long MB = 1024 * 1024; + + @Test + public void testOs() throws Exception { + + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + System.out.println(runtimeMXBean.getName()); + System.out.println("jvm运营商:" + runtimeMXBean.getVmVendor()); + System.out.println("jvm规范版本:" + runtimeMXBean.getSpecVersion()); + System.out.println("jvm实现版本:" + runtimeMXBean.getVmVersion()); + + + OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean(); + System.out.println(osMXBean.getName()); + System.out.println(osMXBean.getArch()); + System.out.println(osMXBean.getVersion()); + System.out.println(osMXBean.getAvailableProcessors()); + + + if (VMInfo.isSunOsMBean(osMXBean)) { + long totalPhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getTotalPhysicalMemorySize"); + long freePhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getFreePhysicalMemorySize"); + System.out.println("总物理内存(M):" + totalPhysicalMemory / MB); + System.out.println("剩余物理内存(M):" + freePhysicalMemory / MB); + + long maxFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getMaxFileDescriptorCount"); + long currentOpenFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getOpenFileDescriptorCount"); + long getProcessCpuTime = VMInfo.getLongFromOperatingSystem(osMXBean, "getProcessCpuTime"); + System.out.println(osMXBean.getSystemLoadAverage()); + System.out.println("maxFileDescriptorCount=>" + maxFileDescriptorCount); + System.out.println("currentOpenFileDescriptorCount=>" + currentOpenFileDescriptorCount); + System.out.println("jvm运行时间(毫秒):" + runtimeMXBean.getUptime()); + System.out.println("getProcessCpuTime=>" + getProcessCpuTime); + + long startTime = System.currentTimeMillis(); + while (true) { + if (System.currentTimeMillis() > startTime + 1000) { + break; + } + } +// system = ManagementFactory.getOperatingSystemMXBean(); +// runtime = ManagementFactory.getRuntimeMXBean(); + System.out.println("test!!" + 2 * 2 * 2 * 123456789); + System.out.println("test!!" + 123456789 * 987654321); + System.out.println("test!!" + 2 * 2 * 2 * 2); + System.out.println("test!!" + 3 * 2 * 4); + System.out.println("test123!!"); + long upTime = runtimeMXBean.getUptime(); + long processTime = VMInfo.getLongFromOperatingSystem(osMXBean, "getProcessCpuTime"); + System.out.println("jvm运行时间(毫秒):" + upTime); + System.out.println("getProcessCpuTime=>" + processTime); + + System.out.println(String.format("%,.1f", (float) processTime / (upTime * osMXBean.getAvailableProcessors() * 10000))); + + + List garbages = ManagementFactory.getGarbageCollectorMXBeans(); + for (GarbageCollectorMXBean garbage : garbages) { + System.out.println("垃圾收集器:名称=" + garbage.getName() + ",收集=" + garbage.getCollectionCount() + ",总花费时间=" + garbage.getCollectionTime() + ",内存区名称=" + Arrays.deepToString(garbage.getMemoryPoolNames())); + } + + List pools = ManagementFactory.getMemoryPoolMXBeans(); + if (pools != null && !pools.isEmpty()) { + for (MemoryPoolMXBean pool : pools) { + //只打印一些各个内存区都有的属性,一些区的特殊属性,可看文档或百度 + // 最大值,初始值,如果没有定义的话,返回-1,所以真正使用时,要注意 + System.out.println("vm内存区:\n\t名称=" + pool.getName() + "\n\t所属内存管理者=" + Arrays.deepToString(pool.getMemoryManagerNames()) + "\n\t ObjectName=" + "\n\t初始大小(M)=" + pool.getUsage().getInit() / MB + "\n\t最大(上限)(M)=" + pool.getUsage().getMax() / MB + "\n\t已用大小(M)=" + pool.getUsage().getUsed() / MB + "\n\t已提交(已申请)(M)=" + pool.getUsage().getCommitted() / MB + "\n\t使用率=" + (pool.getUsage().getUsed() * 100 / pool.getUsage().getCommitted()) + "%"); + } + } + + } + } + + @Test + public void testVMInfo() throws Exception { + VMInfo vmInfo = VMInfo.getVmInfo(); + Assert.assertTrue(vmInfo != null); + System.out.println(vmInfo.toString()); + vmInfo.getDelta(); + int count = 0; + + while(count < 10) { + long startTime = System.currentTimeMillis(); + while (true) { + if (System.currentTimeMillis() > startTime + 1000) { + break; + } + } + vmInfo.getDelta(); + count++; + Thread.sleep(1000); + } + + vmInfo.getDelta(false); + System.out.println(vmInfo.totalString()); + } +} \ No newline at end of file diff --git a/common/src/test/java/com/alibaba/datax/common/util/ConfigurationTest.java b/common/src/test/java/com/alibaba/datax/common/util/ConfigurationTest.java new file mode 100755 index 000000000..1b8a56858 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/ConfigurationTest.java @@ -0,0 +1,699 @@ +package com.alibaba.datax.common.util; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.*; + +public class ConfigurationTest { + + @Test + public void test_get() { + Configuration configuration = Configuration + .from("{\"a\":[{\"b\":[{\"c\":[\"bazhen\"]}]}]}"); + + String path = ""; + Assert.assertTrue(JSON.toJSONString(configuration.get(path)).equals( + "{\"a\":[{\"b\":[{\"c\":[\"bazhen\"]}]}]}")); + + path = "a[0].b[0].c[0]"; + Assert.assertTrue(JSON.toJSONString(configuration.get(path)).equals( + "\"bazhen\"")); + + configuration = Configuration.from("{\"a\": [[[0]]]}"); + path = "a[0][0][0]"; + System.out.println(JSON.toJSONString(configuration.get(path))); + Assert.assertTrue(JSON.toJSONString(configuration.get(path)) + .equals("0")); + + path = "a[0]"; + System.out.println(JSON.toJSONString(configuration.get(path))); + Assert.assertTrue(JSON.toJSONString(configuration.get(path)).equals( + "[[0]]")); + + path = "c[0]"; + System.out.println(JSON.toJSONString(configuration.get(path))); + Assert.assertTrue(JSON.toJSONString(configuration.get(path)).equals( + "null")); + + configuration = Configuration.from("[1,2]"); + System.out.println(configuration.get("[0]")); + Assert.assertTrue(configuration.getString("[0]").equals("1")); + Assert.assertTrue(configuration.getString("[1]").equals("2")); + + } + + @Test + public void test_buildObject() { + + // 非法参数 + try { + Configuration.from("{}").buildObject(null, "bazhen"); + Assert.assertTrue(false); + } catch (Exception e) { + Assert.assertTrue(true); + } + + // 测试单元素 + Assert.assertTrue(Configuration.from("{}") + .buildObject(new ArrayList(), "bazhen") + .equals("bazhen")); + Assert.assertTrue(Configuration.from("{}").buildObject( + new ArrayList(), new HashMap()) instanceof Map); + Assert.assertTrue(Configuration.from("{}").buildObject( + new ArrayList(), null) == null); + + // 测试多级元素 + String path = null; + String json = null; + + path = ""; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("\"bazhen\"".equals(json)); + + path = "a"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("{\"a\":\"bazhen\"}".equals(json)); + + path = "a"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), + new HashMap())); + System.out.println(json); + Assert.assertTrue("{\"a\":{}}".equals(json)); + + path = "a"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), + new ArrayList())); + System.out.println(json); + Assert.assertTrue("{\"a\":[]}".equals(json)); + + path = "a"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), 1L)); + System.out.println(json); + Assert.assertTrue("{\"a\":1}".equals(json)); + + path = "a"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), 1.1)); + System.out.println(json); + Assert.assertTrue("{\"a\":1.1}".equals(json)); + + path = "[0]"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("[\"bazhen\"]".equals(json)); + + path = "[1]"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("[null,\"bazhen\"]".equals(json)); + + path = "a.b.c.d.e.f"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":\"bazhen\"}}}}}}" + .equals(json)); + + path = "[1].[1]"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("[null,[null,\"bazhen\"]]".equals(json)); + + path = "a.[10].b.[0].c.[1]"; + json = JSON.toJSONString(Configuration.from("{}").buildObject( + Arrays.asList(StringUtils.split(path, ".")), "bazhen")); + System.out.println(json); + Assert.assertTrue("{\"a\":[null,null,null,null,null,null,null,null,null,null,{\"b\":[{\"c\":[null,\"bazhen\"]}]}]}" + .equals(json)); + } + + @Test + public void test_setObjectRecursive() { + // 当current完全为空,类似新插入对象 + + String path = ""; + Object root = null; + + root = Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, "bazhen"); + System.out.println(root); + Assert.assertTrue(JSON.toJSONString(root).equals("\"bazhen\"")); + + root = JSON.toJSONString(Configuration.from("{}").setObjectRecursive( + null, Arrays.asList(StringUtils.split(path, ".")), 0, + new ArrayList())); + System.out.println(root); + Assert.assertTrue(root.equals("[]")); + + root = JSON.toJSONString(Configuration.from("{}").setObjectRecursive( + null, Arrays.asList(StringUtils.split(path, ".")), 0, + new HashMap())); + System.out.println(root); + Assert.assertTrue(root.equals("{}")); + + root = JSON.toJSONString(Configuration.from("{}").setObjectRecursive( + null, Arrays.asList(StringUtils.split(path, ".")), 0, 0L)); + System.out.println(root); + Assert.assertTrue(root.equals("0")); + + // 当current当前为空,但是path存在路径,类似新插入对象 + path = "a"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":\"bazhen\"}".equals(root)); + + path = "a.b"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":{\"b\":\"bazhen\"}}".equals(root)); + + path = "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":{\"h\":{\"i\":{\"j\":{\"k\":{\"l\":{\"m\":{\"n\":{\"o\":{\"p\":{\"q\":{\"r\":{\"s\":{\"t\":{\"u\":{\"v\":{\"w\":{\"x\":{\"y\":{\"z\":\"bazhen\"}}}}}}}}}}}}}}}}}}}}}}}}}}" + .equals(root)); + + path = "1.1"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"1\":{\"1\":\"bazhen\"}}".equals(root)); + + path = "-.-"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"-\":{\"-\":\"bazhen\"}}".equals(root)); + + path = "[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[\"bazhen\"]")); + + path = "[0].[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[[\"bazhen\"]]")); + + path = "[0].[0].[0].[0].[0].[0].[0].[0].[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[[[[[[[[[\"bazhen\"]]]]]]]]]")); + + path = "[0].[1].[2].[3].[4].[5].[6].[7].[8]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root + .equals("[[null,[null,null,[null,null,null,[null,null,null,null,[null,null,null,null,null,[null,null,null,null,null,null,[null,null,null,null,null,null,null,[null,null,null,null,null,null,null,null,\"bazhen\"]]]]]]]]]")); + + path = "a.[0].b.[0].c.[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(null, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root + .equals("{\"a\":[{\"b\":[{\"c\":[\"bazhen\"]}]}]}")); + + // 初始化为list,测试插入对象 + + root = JSON.parse("[]"); + path = "a"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":\"bazhen\"}".equals(root)); + + root = JSON.parse("[]"); + path = "a.b"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":{\"b\":\"bazhen\"}}".equals(root)); + + root = JSON.parse("[]"); + path = "[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[\"bazhen\"]")); + + root = JSON.parse("[]"); + path = "[0].[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[[\"bazhen\"]]")); + + // 初始化为map,测试插入对象 + root = JSON.parse("{}"); + path = "a"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":\"bazhen\"}".equals(root)); + + root = JSON.parse("{}"); + path = "a.b"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue("{\"a\":{\"b\":\"bazhen\"}}".equals(root)); + + root = JSON.parse("{}"); + path = "[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[\"bazhen\"]")); + + root = JSON.parse("{}"); + path = "[0].[0]"; + root = JSON + .toJSONString(Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, + "bazhen")); + System.out.println(root); + Assert.assertTrue(root.equals("[[\"bazhen\"]]")); + + root = JSON.parse("{\"a\": \"a\", \"b\":\"b\"}"); + path = "a.[0]"; + root = Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, "bazhen"); + System.out.println(root); + System.out.println(JSON.toJSONString(root).equals( + "{\"a\":[\"bazhen\"],\"b\":\"b\"}")); + + root = JSON + .parse("{\"a\":{\"b\":{\"c\":[0],\"B\": \"B\"},\"A\": \"A\"}}"); + path = "a.b.c.[0]"; + root = Configuration.from("{}").setObjectRecursive(root, + Arrays.asList(StringUtils.split(path, ".")), 0, "bazhen"); + System.out.println(root); + Assert.assertTrue(JSON.toJSONString(root).equals( + "{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"c\":[\"bazhen\"]}}}")); + } + + @Test + public void test_setConfiguration() { + Configuration configuration = Configuration.from("{}"); + configuration.set("b", Configuration.from("{}")); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"b\":{}}")); + + configuration = Configuration.newDefault(); + List list = new ArrayList(); + for (int i = 0; i < 3; i++) { + list.add(Configuration.newDefault()); + } + configuration.set("a", list); + System.out.println(configuration.toJSON()); + Assert.assertTrue("{\"a\":[{},{},{}]}".equals(configuration.toJSON())); + + Map map = new HashMap(); + map.put("a", Configuration.from("{\"a\": 1}")); + configuration.set("a", map); + System.out.println(configuration.toJSON()); + Assert.assertTrue("{\"a\":{\"a\":{\"a\":1}}}".equals(configuration + .toJSON())); + } + + @Test + public void test_set() { + Configuration configuration = Configuration + .from("{\"a\":{\"b\":{\"c\":[0],\"B\": \"B\"},\"A\": \"A\"}}"); + configuration.set("a.b.c[0]", 3.1415); + Assert.assertTrue(configuration.toJSON().equals( + "{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"c\":[3.1415]}}}")); + + configuration.set("a.b.c[1]", 3.1415); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration + .toJSON() + .equals("{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"c\":[3.1415,3.1415]}}}")); + configuration.set("a.b.c[0]", null); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration + .toJSON() + .equals("{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"c\":[null,3.1415]}}}")); + + configuration.set("[0]", 3.14); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("[3.14]")); + + configuration.set("[1]", 3.14); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("[3.14,3.14]")); + + configuration.set("", new HashMap()); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{}")); + + configuration = Configuration.newDefault(); + configuration.set("a[0].b", 1); + configuration.set("a[0].b", 1); + System.out.println(configuration.toJSON()); + Assert.assertTrue("{\"a\":[{\"b\":1}]}".equals(configuration.toJSON())); + + try { + configuration.set(null, 3.14); + Assert.assertFalse(true); + } catch (Exception e) { + Assert.assertTrue(true); + } + + try { + configuration.set("", 3.14); + Assert.assertFalse(true); + } catch (Exception e) { + Assert.assertTrue(true); + } + } + + @Test + public void test_getKeys() { + Set sets = new HashSet(); + + sets.clear(); + Configuration configuration = Configuration.from("{}"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(configuration.getKeys().isEmpty()); + + sets.clear(); + configuration = Configuration.from("[]"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(configuration.getKeys().isEmpty()); + + sets.clear(); + configuration = Configuration.from("[0]"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(configuration.getKeys().contains("[0]")); + + sets.clear(); + configuration = Configuration.from("[1,2]"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(configuration.getKeys().contains("[0]")); + Assert.assertTrue(configuration.getKeys().contains("[1]")); + + sets.clear(); + configuration = Configuration.from("[[[0]]]"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(configuration.getKeys().contains("[0][0][0]")); + + sets.clear(); + configuration = Configuration + .from("{\"a\":{\"b\":{\"c\":[0],\"B\": \"B\"},\"A\": \"A\"}}"); + System.out.println(JSON.toJSONString(configuration.getKeys())); + Assert.assertTrue(JSON.toJSONString(configuration.getKeys()).equals( + "[\"a.b.B\",\"a.b.c[0]\",\"a.A\"]")); + } + + @Test + public void test_merge() { + Configuration configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("[1,2]"), true); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("[1,2]")); + + configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("[1,2]"), false); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("[1,2]")); + + configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("{\"1\": 2}"), true); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"1\":2}")); + + configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("{\"1\": 2}"), false); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"1\":2}")); + + configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("{\"1\":\"2\"}"), true); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"1\":\"2\"}")); + + configuration = Configuration.from("{}"); + configuration.merge(Configuration.from("{\"1\":\"2\"}"), false); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"1\":\"2\"}")); + + configuration = Configuration + .from("{\"a\":{\"b\":{\"c\":[0],\"B\": \"B\"},\"A\": \"A\"}}"); + configuration + .merge(Configuration + .from("{\"a\":{\"b\":{\"c\":[\"bazhen\"],\"B\": \"B\"},\"A\": \"A\"}}"), + true); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals( + "{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"c\":[\"bazhen\"]}}}")); + + configuration = Configuration + .from("{\"a\":{\"b\":{\"c\":[0],\"B\": \"B\"},\"A\": \"A\"}}"); + configuration + .merge(Configuration + .from("{\"a\":{\"b\":{\"c\":[\"bazhen\"],\"B\": \"B\",\"C\": \"C\"}}}"), + false); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration + .toJSON() + .equals("{\"a\":{\"A\":\"A\",\"b\":{\"B\":\"B\",\"C\":\"C\",\"c\":[0]}}}")); + } + + @Test + public void test_type() { + Configuration configuration = Configuration.from("{\"a\": 1}"); + Assert.assertTrue(configuration.getLong("a") == 1); + } + + @Test + public void test_beautify() { + Configuration configuration = Configuration + .from(ConfigurationTest.class.getClassLoader() + .getResourceAsStream("all.json")); + System.out.println(configuration.getConfiguration("job.content") + .beautify()); + } + + @SuppressWarnings("unchecked") + @Test + public void test() { + Configuration configuration = Configuration + .from(ConfigurationTest.class.getClassLoader() + .getResourceAsStream("all.json")); + System.out.println(configuration.toJSON()); + configuration.merge(Configuration.from(ConfigurationTest.class + .getClassLoader().getResourceAsStream("all.json")), true); + Assert.assertTrue(((List) configuration + .get("job.content[0].reader.parameter.jdbcUrl")).size() == 2); + + } + + @Test(expected = DataXException.class) + public void test_remove() { + Configuration configuration = Configuration.from("{\"a\": \"b\"}"); + configuration.remove("a"); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{}")); + + configuration.set("a[1]", "b"); + System.out.println(configuration.toJSON()); + configuration.remove("a[1]"); + System.out.println(configuration.toJSON()); + Assert.assertTrue(configuration.toJSON().equals("{\"a\":[null,null]}")); + + configuration.set("a", "b"); + configuration.remove("b"); + } + + @Test + public void test_unescape() { + Configuration configuration = Configuration.from("{\"a\": \"\\t\"}"); + System.out.println("|" + configuration.getString("a") + "|"); + Assert.assertTrue("|\t|".equals("|" + configuration.getString("a") + + "|")); + + configuration = Configuration.from("{\"a\": \"\u0001\"}"); + Assert.assertTrue(configuration.getString("a").equals("\u0001")); + Assert.assertTrue(new String(new byte[] { 0x01 }).equals(configuration + .get("a"))); + + } + + @Test + public void test_list() { + Configuration configuration = Configuration.newDefault(); + List lists = new ArrayList(); + lists.add("bazhen.csy"); + configuration.set("a.b.c", lists); + System.out.println(configuration); + configuration.set("a.b.c.d", lists); + System.out.println(configuration); + } + + @Test + public void test_serialize() { + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < 128; i++) { + sb.append((char) i); + } + + Configuration configuration = Configuration.newDefault(); + configuration.set("a", sb.toString()); + Configuration another = Configuration.from(configuration.toJSON()); + Assert.assertTrue(another.getString("a").equals(configuration.get("a"))); + } + + @Test + public void test_variable() { + Properties prop = new Properties(); + System.setProperties(prop); + System.setProperty("bizdate", "20141125"); + System.setProperty("errRec", "1"); + System.setProperty("errPercent", "0.5"); + String json = "{\n" + + " \"core\": {\n" + + " \"where\": \"gmt_modified >= ${bizdate}\"\n" + + " },\n" + + " \"errorLimit\": {\n" + + " \t\"record\": ${errRec},\n" + + " \t\"percentage\": ${errPercent}\n" + + " }\n" + + "}"; + Configuration conf = Configuration.from(json); + Assert.assertEquals("gmt_modified >= 20141125", conf.getString("core.where")); + Assert.assertEquals(Integer.valueOf(1), conf.getInt("errorLimit.record")); + Assert.assertEquals(Double.valueOf(0.5), conf.getDouble("errorLimit.percentage")); + + // 依然能够转回来 + Configuration.from(conf.toJSON()); + } + + @Test + public void test_secretKey() { + Configuration config = Configuration.newDefault(); + + String keyPath1 = "a.b.c"; + String keyPath2 = "a.b.c[2].d"; + config.addSecretKeyPath(keyPath1); + config.addSecretKeyPath(keyPath2); + + Assert.assertTrue(config.isSecretPath(keyPath1)); + Assert.assertTrue(config.isSecretPath(keyPath2)); + + Configuration configClone = config.clone(); + Assert.assertTrue(configClone.isSecretPath(keyPath1)); + Assert.assertTrue(configClone.isSecretPath(keyPath2)); + + config.setSecretKeyPathSet(new HashSet()); + Assert.assertTrue(configClone.isSecretPath(keyPath1)); + Assert.assertTrue(configClone.isSecretPath(keyPath2)); + } + + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + + @Test + public void test_get_list() { + Configuration configuration = Configuration + .from(ConfigurationTest.class.getClassLoader() + .getResourceAsStream("all.json")); +// System.out.println(configuration.toJSON()); + + List noPathNameThis = configuration.get("job.no_path_named_this", List.class); + Assert.assertNull(noPathNameThis); + + noPathNameThis = configuration.getList("job.no_path_named_this", String.class); + Assert.assertNull(noPathNameThis); + + System.out.println(configuration.getString("job.setting")); + + expectedEx.expect(ClassCastException.class); + expectedEx.expectMessage("com.alibaba.fastjson.JSONObject cannot be cast to java.util.List"); + List aStringCantConvertToList = configuration.getList("job.setting"); + } + + @Test + public void test_getNecessaryValue() { + Configuration configuration = Configuration.newDefault(); + configuration.set("a.b.c", "XX"); + configuration.set("x.y.z", "true"); + configuration.getNecessaryValue("a.b.c", CommonErrorCode.CONFIG_ERROR); + configuration.getNecessaryBool("x.y.z", CommonErrorCode.CONFIG_ERROR); + } + + + @Test + public void test_getNecessaryValue2() { + expectedEx.expect(DataXException.class); + Configuration configuration = Configuration.newDefault(); + configuration.set("x.y.z", "yes"); + configuration.getNecessaryBool("x.y.z", CommonErrorCode.CONFIG_ERROR); + } + + @Test + public void test_getNecessaryValue3() { + expectedEx.expect(DataXException.class); + Configuration configuration = Configuration.newDefault(); + configuration.getNecessaryBool("x.y.z", CommonErrorCode.CONFIG_ERROR); + } + +} diff --git a/common/src/test/java/com/alibaba/datax/common/util/FilterUtilTest.java b/common/src/test/java/com/alibaba/datax/common/util/FilterUtilTest.java new file mode 100755 index 000000000..cd756e70a --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/FilterUtilTest.java @@ -0,0 +1,169 @@ +package com.alibaba.datax.common.util; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FilterUtilTest { + private static List ALL_STRS; + + @BeforeClass + public static void beforeClass() { + ALL_STRS = new ArrayList(); + ALL_STRS.add("pt=1/ds=hangzhou"); + ALL_STRS.add("pt=1/ds=shanghai"); + ALL_STRS.add("pt=2/ds2=hangzhou"); + } + + @Test + public void test00() { + String regular = "pt=[1|2]/ds=*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(0)); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test01() { + String regular = "pt=[1|2]/ds=.*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(0)); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test02() { + String regular = "pt=[1|2]/ds=.*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(0)); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test03() { + String regular = "pt=*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(ALL_STRS); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test04() { + String regular = "^pt=*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(ALL_STRS); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test05() { + String regular = "pt=1/ds=s[a-z]*"; + + List matched = FilterUtil.filterByRegular(ALL_STRS, regular); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test06() { + // 两个规则,其中规则一匹配到1个,规则二匹配到2个。希望返回值为二者的并集 + List regulars = new ArrayList(); + String regular1 = "pt=1/ds=s[a-z]*"; + String regular2 = "pt=1/ds=*"; + regulars.add(regular1); + regulars.add(regular2); + + List matched = FilterUtil.filterByRegulars(ALL_STRS, regulars); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(0)); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } + + @Test + public void test07() { + // 两个规则 一模一样,都是只能匹配到一个 + List regulars = new ArrayList(); + String regular1 = "pt=1/ds=s[a-z]*"; + String regular2 = "pt=1/ds=s[a-z]*"; + regulars.add(regular1); + regulars.add(regular2); + + List matched = FilterUtil.filterByRegulars(ALL_STRS, regulars); + + System.out.println("matched:" + matched); + List expected = new ArrayList(); + expected.add(ALL_STRS.get(1)); + + Assert.assertEquals(expected.size(), matched.size()); + + Collections.sort(expected); + Collections.sort(matched); + Assert.assertArrayEquals(expected.toArray(), matched.toArray()); + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/util/ListUtilTest.java b/common/src/test/java/com/alibaba/datax/common/util/ListUtilTest.java new file mode 100755 index 000000000..23691efd0 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/ListUtilTest.java @@ -0,0 +1,90 @@ +package com.alibaba.datax.common.util; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class ListUtilTest { + private static List aList = null; + + @BeforeClass + public static void beforeClass() { + aList = new ArrayList(); + aList.add("one"); + aList.add("onE"); + aList.add("two"); + aList.add("阿里巴巴"); + } + + @Test + public void testCheckIfValueDuplicate() { + List list = new ArrayList(aList); + list.add(aList.get(0)); + boolean result = ListUtil.checkIfValueDuplicate(list, true); + Assert.assertTrue(list + " has no duplicate value.", result); + + list = new ArrayList(aList); + list.add(aList.get(0)); + result = ListUtil.checkIfValueDuplicate(list, false); + Assert.assertTrue(list + " has duplicate value.", result); + + + list = new ArrayList(aList); + list.add(aList.get(0)); + list.set(list.size() - 1, list.get(list.size() - 1).toUpperCase()); + result = ListUtil.checkIfValueDuplicate(list, true); + Assert.assertTrue(list + " has duplicate value.", result == false); + + list = new ArrayList(aList); + list.add(aList.get(0)); + list.set(list.size() - 1, list.get(list.size() - 1).toUpperCase()); + result = ListUtil.checkIfValueDuplicate(list, false); + Assert.assertTrue(list + " has duplicate value.", result); + } + + @Test + public void testValueToLowerCase() { + List list = new ArrayList(aList); + for (int i = 0, len = list.size(); i < len; i++) { + list.set(i, list.get(i).toLowerCase()); + } + + Assert.assertArrayEquals(list.toArray(), ListUtil.valueToLowerCase(list).toArray()); + } + + @Test + public void testCheckIfValueSame() { + List boolList = new ArrayList(); + boolList.add(true); + boolList.add(true); + boolList.add(true); + Assert.assertTrue(boolList + " all value same.", ListUtil.checkIfValueSame(boolList)); + + boolList.add(false); + Assert.assertTrue(boolList + "not all value same.", ListUtil.checkIfValueSame(boolList) == false); + } + + @Test + public void testCheckIfBInA() { + List bList = new ArrayList(aList); + bList.set(0, bList.get(0) + "_hello"); + Assert.assertTrue(bList + " not all in " + aList, ListUtil.checkIfBInA(aList, bList, false) == false); + + Assert.assertTrue(bList + " not all in " + aList, ListUtil.checkIfBInA(aList, bList, true) == false); + + + bList = new ArrayList(aList); + bList.set(0, bList.get(0).toUpperCase()); + Assert.assertTrue(bList + " all in " + aList, ListUtil.checkIfBInA(aList, bList, false)); + + + bList = new ArrayList(aList); + bList.set(0, bList.get(0).toUpperCase()); + Assert.assertTrue(bList + " not all in " + aList, ListUtil.checkIfBInA(aList, bList, true) == false); + + } + +} diff --git a/common/src/test/java/com/alibaba/datax/common/util/RangeSplitUtilTest.java b/common/src/test/java/com/alibaba/datax/common/util/RangeSplitUtilTest.java new file mode 100755 index 000000000..ec6e750a8 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/RangeSplitUtilTest.java @@ -0,0 +1,185 @@ +package com.alibaba.datax.common.util; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Random; + +public class RangeSplitUtilTest { + + @Test + public void testSplitString() { + int expectSliceNumber = 3; + + String left = "00468374-8cdb-11e4-a66a-008cfac1c3b8"; + String right = "fcbc8a79-8427-11e4-a66a-008cfac1c3b8"; + + String[] result = RangeSplitUtil.doAsciiStringSplit(left, right, expectSliceNumber); + + Assert.assertTrue(result.length - 1 == expectSliceNumber); + System.out.println(Arrays.toString(result)); + } + + @Test + public void testSplitStringRandom() { + String left = RandomStringUtils.randomAlphanumeric(40); + String right = RandomStringUtils.randomAlphanumeric(40); + + for (int expectSliceNumber = 1; expectSliceNumber < 100; expectSliceNumber++) { + String[] result = RangeSplitUtil.doAsciiStringSplit(left, right, expectSliceNumber); + + Assert.assertTrue(result.length - 1 == expectSliceNumber); + + String[] clonedResult = result.clone(); +// Collections.sort(Arrays.asList(result)); + + Assert.assertTrue(Arrays.toString(clonedResult).equals(Arrays.toString(result))); + + System.out.println(result); + } + } + + //TODO + @Test + public void testLong_00() { + long count = 0; + long left = 0; + long right = count - 1; + int expectSliceNumber = 3; + long[] result = RangeSplitUtil.doLongSplit(left, right, expectSliceNumber); + + result[result.length - 1]++; + for (int i = 0; i < result.length - 1; i++) { + System.out.println("start:" + result[i] + " count:" + (result[i + 1] - result[i])); + } + +// Assert.assertTrue(result.length - 1 == expectSliceNumber); + System.out.println(Arrays.toString(result)); + } + + @Test + public void testLong_01() { + long count = 8; + long left = 0; + long right = count - 1; + int expectSliceNumber = 3; + long[] result = RangeSplitUtil.doLongSplit(left, right, expectSliceNumber); + + result[result.length - 1]++; + for (int i = 0; i < result.length - 1; i++) { + System.out.println("start:" + result[i] + " count:" + (result[i + 1] - result[i])); + } + + Assert.assertTrue(result.length - 1 == expectSliceNumber); + System.out.println(Arrays.toString(result)); + } + + @Test + public void testLong() { + long left = 8L; + long right = 301L; + int expectSliceNumber = 93; + doTest(left, right, expectSliceNumber); + + for (int i = 1; i < right * 20; i++) { + doTest(left, right, i); + } + + System.out.println(" 测试随机值..."); + int testTimes = 200; + for (int i = 0; i < testTimes; i++) { + left = getRandomLong(); + right = getRandomLong(); + expectSliceNumber = getRandomInteger(); + doTest(left, right, expectSliceNumber); + } + + } + + + @Test + public void testGetMinAndMaxCharacter() { + Pair result = RangeSplitUtil.getMinAndMaxCharacter("abc%^&"); + Assert.assertEquals('%', result.getLeft().charValue()); + Assert.assertEquals('c', result.getRight().charValue()); + + result = RangeSplitUtil.getMinAndMaxCharacter("\tAabcZx"); + Assert.assertEquals('\t', result.getLeft().charValue()); + Assert.assertEquals('x', result.getRight().charValue()); + } + + + //TODO 自动化测试 + @Test + public void testDoAsciiStringSplit() { +// String left = "adde"; +// String right = "xyz"; +// int expectSliceNumber = 4; + String left = "a"; + String right = "z"; + int expectSliceNumber = 3; + + String[] result = RangeSplitUtil.doAsciiStringSplit(left, right, expectSliceNumber); + System.out.println(ToStringBuilder.reflectionToString(result, ToStringStyle.SIMPLE_STYLE)); + + } + + private long getRandomLong() { + Random r = new Random(); + return r.nextLong(); + } + + private int getRandomInteger() { + Random r = new Random(); + return Math.abs(r.nextInt(1000) + 1); + } + + private void doTest(long left, long right, int expectSliceNumber) { + long[] result = RangeSplitUtil.doLongSplit(left, right, expectSliceNumber); + + System.out.println(String.format("left:[%s],right:[%s],expectSliceNumber:[%s]====> splitResult:[\n%s\n].\n", + left, right, expectSliceNumber, ToStringBuilder.reflectionToString(result, ToStringStyle.SIMPLE_STYLE))); + + Assert.assertTrue(doCheck(result, left, right, Math.abs(right - left) > + expectSliceNumber ? expectSliceNumber : -1)); + } + + + private boolean doCheck(long[] result, long left, + long right, int expectSliceNumber) { + if (null == result) { + throw new IllegalArgumentException("parameter result can not be null."); + } + + // 调整大小顺序,确保 left right) { + long temp = left; + left = right; + right = temp; + } + + //为了方法共用,expectSliceNumber == -1 表示不对切分份数进行校验. + boolean skipSliceNumberCheck = expectSliceNumber == -1; + if (skipSliceNumberCheck || expectSliceNumber == result.length - 1) { + boolean leftCheckOk = left == result[0]; + boolean rightCheckOk = right == result[result.length - 1]; + + if (leftCheckOk && rightCheckOk) { + for (int i = 0, len = result.length; i < len - 1; i++) { + if (result[i] > result[i + 1]) { + return false; + } + } + return true; + } + } + + return false; + } +} diff --git a/common/src/test/java/com/alibaba/datax/common/util/RetryUtilTest.java b/common/src/test/java/com/alibaba/datax/common/util/RetryUtilTest.java new file mode 100755 index 000000000..f3d2ab162 --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/RetryUtilTest.java @@ -0,0 +1,259 @@ +package com.alibaba.datax.common.util; + +import org.hamcrest.core.StringContains; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class RetryUtilTest { + + private static String OK = "I am ok now."; + + private static String BAD = "I am bad now."; + + + /** + * 模拟一个不靠谱的方法,其不靠谱体现在:调用它,前2次必定失败,第3次才能成功. 运行成功时,输出为:I am ok now. + * 运行报错时,报错中信息为:I am bad now. + */ + static class SomeService implements Callable { + private int i = 0; + + @Override + public String call() throws Exception { + i++; + if (i <= 2) { + throw new Exception(BAD); + } + return OK; + } + } + + @Test(timeout = 3000L) + public void test1() throws Exception { + long startTime = System.currentTimeMillis(); + + String result = RetryUtil.executeWithRetry(new SomeService(), 3, 1000L, + false); + long endTime = System.currentTimeMillis(); + Assert.assertEquals(result, OK); + long executeTime = endTime - startTime; + + System.out.println("executeTime:" + executeTime); + Assert.assertTrue(executeTime < 3 * 1000L); + } + + @Test(timeout = 3000L) + public void test2() throws Exception { + long startTime = System.currentTimeMillis(); + String result = RetryUtil.executeWithRetry(new SomeService(), 4, 1000L, + false); + long endTime = System.currentTimeMillis(); + Assert.assertEquals(result, OK); + long executeTime = endTime - startTime; + + System.out.println("executeTime:" + executeTime); + Assert.assertTrue(executeTime < 3 * 1000L); + } + + @Test(timeout = 3000L) + public void test3() throws Exception { + long startTime = System.currentTimeMillis(); + String result = RetryUtil.executeWithRetry(new SomeService(), 40, + 1000L, false); + long endTime = System.currentTimeMillis(); + Assert.assertEquals(result, OK); + long executeTime = endTime - startTime; + + System.out.println("executeTime:" + executeTime); + Assert.assertTrue(executeTime < 3 * 1000L); + } + + @Test(timeout = 4000L) + public void test4() throws Exception { + long startTime = System.currentTimeMillis(); + String result = RetryUtil.executeWithRetry(new SomeService(), 40, + 1000L, true); + long endTime = System.currentTimeMillis(); + Assert.assertEquals(result, OK); + long executeTime = endTime - startTime; + + System.out.println("executeTime:" + executeTime); + Assert.assertTrue(executeTime < 4 * 1000L); + Assert.assertTrue(executeTime > 3 * 1000L); + } + + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + + @Test(timeout = 3000L) + public void test5() throws Exception { + expectedEx.expect(Exception.class); + expectedEx.expectMessage(StringContains.containsString(BAD)); + + RetryUtil.executeWithRetry(new SomeService(), 2, 100L, false); + } + + /** + * 线程池无法释放,后续提交被拒绝 + * + * @throws Exception + */ + @Test + public void testExecutorService线程池占满() throws Exception { + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + expectedEx.expect(RejectedExecutionException.class); + for (int i = 0; i < 10; i++) { + executor.submit(new Callable() { + @Override + public Object call() throws Exception { + TimeUnit.SECONDS.sleep(10); + return null; + } + }); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + } + + } + + /** + * 保持有任务运行,最多4个,所有提交过来的任务都能运行 + * + * @throws Exception + */ + @Test + public void testExecutorService正常运行() throws Exception { + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + for (int i = 0; i < 10; i++) { + executor.submit(new Callable() { + @Override + public Object call() throws Exception { + TimeUnit.SECONDS.sleep(4); + return null; + } + }); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + TimeUnit.SECONDS.sleep(1); + } + } + + /** + * 线程池没有被全部占用,但是正在运行的总数超过限制,后续提交拒绝 + * + * @throws Exception + */ + @Test + public void testExecutorService正在运行的总数超过限制() throws Exception { + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + expectedEx.expect(RejectedExecutionException.class); + for (int i = 0; i < 10; i++) { + executor.submit(new Callable() { + @Override + public Object call() throws Exception { + TimeUnit.SECONDS.sleep(6); + return null; + } + }); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + TimeUnit.SECONDS.sleep(1); + } + } + + @Test + public void testExecutorService取消正在运行的任务() throws Exception { + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + List> futures = new ArrayList>(10); + for (int i = 0; i < 10; i++) { + Future f = executor.submit(new Callable() { + @Override + public Object call() throws Exception { + TimeUnit.SECONDS.sleep(6); + return null; + } + }); + futures.add(f); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + + if (i == 4) { + for (Future future : futures) { + future.cancel(true); + } + System.out.println("Cancel all"); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + } + + TimeUnit.SECONDS.sleep(1); + } + } + + @Test + public void testExecutorService取消方式错误() throws Exception { + expectedEx.expect(RejectedExecutionException.class); + + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + + List> futures = new ArrayList>(10); + for (int i = 0; i < 10; i++) { + Future f = executor.submit(new Callable() { + @Override + public Object call() throws Exception { + TimeUnit.SECONDS.sleep(6); + return null; + } + }); + futures.add(f); + System.out.println("Submit: " + i + ", running tasks: " + executor.getActiveCount()); + + if (i == 4) { + for (Future future : futures) { + future.cancel(false); + } + System.out.println("Cancel all"); + } + + TimeUnit.SECONDS.sleep(1); + } + } + + @Test + public void testRetryAsync() throws Exception { + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + final AtomicInteger runCnt = new AtomicInteger(); + String res = RetryUtil.asyncExecuteWithRetry(new Callable() { + @Override + public String call() throws Exception { + runCnt.incrementAndGet(); + if (runCnt.get() < 3) { + TimeUnit.SECONDS.sleep(10); + } else { + TimeUnit.SECONDS.sleep(1); + } + + return OK; + } + }, 3, 1000L, false, 2000L, executor); + Assert.assertEquals(res, OK); +// Assert.assertEquals(RetryUtil.EXECUTOR.getActiveCount(), 0); + } + + + @Test + public void testRetryAsync2() throws Exception { + expectedEx.expect(TimeoutException.class); + ThreadPoolExecutor executor = RetryUtil.createThreadPoolExecutor(); + String res = RetryUtil.asyncExecuteWithRetry(new Callable() { + @Override + public String call() throws Exception { + TimeUnit.SECONDS.sleep(10); + return OK; + } + }, 3, 1000L, false, 2000L, executor); + } + +} diff --git a/common/src/test/java/com/alibaba/datax/common/util/StrUtilTest.java b/common/src/test/java/com/alibaba/datax/common/util/StrUtilTest.java new file mode 100644 index 000000000..42b9aba9b --- /dev/null +++ b/common/src/test/java/com/alibaba/datax/common/util/StrUtilTest.java @@ -0,0 +1,59 @@ +package com.alibaba.datax.common.util; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +public class StrUtilTest { + + @Rule + public ExpectedException ex= ExpectedException.none(); + + + @Test + public void testReplaceVariable() throws Exception { + Properties valuesMap = System.getProperties(); + valuesMap.put("animal", "quick brown fox"); + valuesMap.put("target", "lazy dog"); + String templateString = "The $animal jumped over the ${target}."; + String resolvedString =StrUtil.replaceVariable(templateString); + System.out.println(resolvedString); + assertEquals(resolvedString, "The quick brown fox jumped over the lazy dog."); + } + + @Test + public void testCompressMiddle() throws Exception { + assertEquals(StrUtil.compressMiddle("0123456789", 2, 2), "01...89"); + assertEquals(StrUtil.compressMiddle("0123456789", 5, 5), "0123456789"); + assertEquals(StrUtil.compressMiddle("0123456789", 6, 7), "0123456789"); + assertEquals(StrUtil.compressMiddle("0123456789", 10, 1), "0123456789"); + assertEquals(StrUtil.compressMiddle("0123456789", 20, 2), "0123456789"); + assertEquals(StrUtil.compressMiddle("0123456789", 2, 20), "0123456789"); + } + + + @Test + public void testCompressMiddleFailed() throws Exception { + ex.expect(NullPointerException.class); + StrUtil.compressMiddle(null, 2, 20); + } + + @Test + public void testCompressMiddleFailed2() throws Exception { + ex.expect(IllegalArgumentException.class); + StrUtil.compressMiddle("sssss", 0, 20); + } + + @Test + public void testCompressMiddleFailed3() throws Exception { + ex.expect(IllegalArgumentException.class); + StrUtil.compressMiddle("sfsdfsd", 2, -1); + } + + + +} \ No newline at end of file diff --git a/common/src/test/resources/all.json b/common/src/test/resources/all.json new file mode 100755 index 000000000..19c5ad977 --- /dev/null +++ b/common/src/test/resources/all.json @@ -0,0 +1,151 @@ + +{ + "entry": { + "jvm": "-Xms1G -Xmx1G", + "environment": { + "PATH": "/home/admin", + "DATAX_HOME": "/home/admin" + } + }, + "common": { + "column": { + "datetimeFormat": "yyyy-MM-dd HH:mm:ss", + "timeFormat": "HH:mm:ss", + "dateFormat": "yyyy-MM-dd", + "extraFormats":["yyyyMMdd"], + "timeZone": "GMT+8", + "encoding": "utf-8" + } + }, + "core": { + "transport": { + "channel": { + "class": "com.alibaba.datax.core.transport.channel.memory.MemoryChannel", + "speed": { + "byte": 1048576 + }, + "capacity": 32 + }, + "exchanger": { + "class": "com.alibaba.datax.core.plugin.BufferedRecordExchanger", + "bufferSize": 32 + } + }, + "container": { + "job": { + "reportInterval": 1000 + }, + "taskGroup": { + "channel": 3 + } + }, + "statistics": { + "collector": { + "plugin": { + "taskClass": "com.alibaba.datax.core.statistics.plugin.task.StdoutPluginCollector", + "maxDirtyNumber": 1000 + } + } + } + }, + "plugin": { + "reader": { + "mysqlreader": { + "name": "fakereader", + "class": "com.alibaba.datax.plugins.reader.fakereader.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "oraclereader": { + "name": "oraclereader", + "class": "com.alibaba.datax.plugins.reader.oraclereader.OracleReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "fakereader": { + "name": "fakereader", + "class": "com.alibaba.datax.core.faker.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "writer": { + "fakewriter": { + "name": "fakewriter", + "class": "com.alibaba.datax.core.faker.FakeWriter", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "transformer": { + "groovyTranformer": {} + } + }, + "job": { + "setting": { + "speed": { + "byte": 104857600 + }, + "errorLimit": { + "record": null, + "percentage": null + } + }, + "content": [ + { + "reader": { + "name": "fakereader", + "parameter": { + "jdbcUrl": [ + [ + "jdbc:mysql://localhost:3305/db1", + "jdbc:mysql://localhost:3306/db1" + ], + [ + "jdbc:mysql://localhost:3305/db2", + "jdbc:mysql://localhost:3306/db2" + ] + ], + "table": [ + "bazhen_[0-15]", + "bazhen_[15-31]" + ] + } + }, + "writer": { + "name": "fakewriter", + "parameter": { + "column": [ + { + "type": "string", + "name": "id" + }, + { + "type": "int", + "name": "age" + } + ], + "encode": "utf-8", + "hbase-conf": "/home/hbase/hbase-conf.xml" + } + } + } + ] + } +} \ No newline at end of file diff --git a/common/src/test/resources/logback-test.xml b/common/src/test/resources/logback-test.xml new file mode 100644 index 000000000..d91666eba --- /dev/null +++ b/common/src/test/resources/logback-test.xml @@ -0,0 +1,18 @@ + + + + + + + + UTF-8 + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/common/src/test/resources/logback.xml b/common/src/test/resources/logback.xml new file mode 100644 index 000000000..d91666eba --- /dev/null +++ b/common/src/test/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + UTF-8 + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/core/datax-core.iml b/core/datax-core.iml new file mode 100644 index 000000000..503cdb82b --- /dev/null +++ b/core/datax-core.iml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml new file mode 100755 index 000000000..ba8dcf86f --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,145 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + + datax-core + datax-core + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + commons-configuration + commons-configuration + ${commons-configuration-version} + + + commons-cli + commons-cli + ${commons-cli-version} + + + commons-beanutils + commons-beanutils + 1.9.2 + + + org.apache.httpcomponents + httpclient + 4.4 + + + org.apache.httpcomponents + fluent-hc + 4.4 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.codehaus.janino + janino + 2.5.16 + + + + junit + junit + test + + + + org.mockito + mockito-core + 1.8.5 + test + + + org.powermock + powermock-api-mockito + 1.4.10 + test + + + + org.powermock + powermock-module-junit4 + 1.4.10 + test + + + org.apache.commons + commons-lang3 + 3.3.2 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.alibaba.datax.core.Engine + + + + + + + maven-assembly-plugin + + + + com.alibaba.datax.core.Engine + + + datax + + src/main/assembly/package.xml + + + + + + package + + single + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + diff --git a/core/src/main/assembly/package.xml b/core/src/main/assembly/package.xml new file mode 100755 index 000000000..7369f5635 --- /dev/null +++ b/core/src/main/assembly/package.xml @@ -0,0 +1,98 @@ + + + + dir + + false + + + + src/main/bin + + *.* + + + *.pyc + + 775 + /bin + + + + src/main/script + + *.* + + 775 + /script + + + + src/main/conf + + *.* + + /conf + + + + target/ + + datax-core-0.0.1-SNAPSHOT.jar + + /lib + + + + + + + + + + + + + + + + + + + + src/main/job/ + + *.json + + /job + + + + src/main/tools/ + + *.* + + /tools + + + + 777 + src/main/tmp + + *.* + + /tmp + + + + + + false + /lib + runtime + + + diff --git a/core/src/main/bin/datax.py b/core/src/main/bin/datax.py new file mode 100755 index 000000000..3e50dc636 --- /dev/null +++ b/core/src/main/bin/datax.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys +import os +import signal +import subprocess +import time +import re +import socket +import json +from optparse import OptionParser +from optparse import OptionGroup +from string import Template + +DATAX_HOME = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +DATAX_VERSION = 'UNKNOWN_DATAX_VERSION' +CLASS_PATH = ("%s/lib/*:.") % (DATAX_HOME) +LOGBACK_FILE = ("%s/conf/logback.xml") % (DATAX_HOME) +DEFAULT_JVM = "-Xms1g -Xmx1g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s/log" % (DATAX_HOME) +DEFAULT_PROPERTY_CONF = "-Dfile.encoding=UTF-8 -Dlogback.statusListenerClass=ch.qos.logback.core.status.NopStatusListener -Ddatax.home=%s -Dlogback.configurationFile=%s" % ( + DATAX_HOME, LOGBACK_FILE) +ENGINE_COMMAND = "java -server ${jvm} %s -classpath %s ${params} com.alibaba.datax.core.Engine -mode ${mode} -jobid ${jobid} -job ${job}" % ( + DEFAULT_PROPERTY_CONF, CLASS_PATH) +REMOTE_DEBUG_CONFIG = "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=9999" + +RET_STATE = { + "KILL": 143, + "FAIL": -1, + "OK": 0, + "RUN": 1, + "RETRY": 2 +} + + +def getLocalIp(): + try: + return socket.gethostbyname(socket.getfqdn(socket.gethostname())) + except: + return "Unknown" + + +def suicide(signum, e): + global child_process + print >> sys.stderr, "[Error] DataX receive unexpected signal %d, starts to suicide." % (signum) + + if child_process: + child_process.send_signal(signal.SIGQUIT) + time.sleep(1) + child_process.kill() + print >> sys.stderr, "DataX Process was killed ! you did ?" + sys.exit(RET_STATE["KILL"]) + + +def register_signal(): + global child_process + signal.signal(2, suicide) + signal.signal(3, suicide) + signal.signal(15, suicide) + + +def getOptionParser(): + usage = "usage: %prog [options] job-url-or-path" + parser = OptionParser(usage=usage) + + prodEnvOptionGroup = OptionGroup(parser, "Product Env Options", + "Normal user use these options to set jvm parameters, job runtime mode etc. " + "Make sure these options can be used in Product Env.") + prodEnvOptionGroup.add_option("-j", "--jvm", metavar="", dest="jvmParameters", action="http://github.com/store", + default=DEFAULT_JVM, help="Set jvm parameters if necessary.") + prodEnvOptionGroup.add_option("--jobid", metavar="", dest="jobid", action="http://github.com/store", default="-1", + help="Set job unique id when running by Distribute/Local Mode.") + prodEnvOptionGroup.add_option("-m", "--mode", metavar="", + action="http://github.com/store", default="standalone", + help="Set job runtime mode such as: standalone, local, distribute. " + "Default mode is standalone.") + prodEnvOptionGroup.add_option("-p", "--params", metavar="", + action="http://github.com/store", dest="params", + help='Set job parameter, eg: the source tableName you want to set it by command, ' + 'then you can use like this: -v"-DtableName=you-wanted-table-name". ' + 'Note: you should config in you job tableName with ${tableName}.') + prodEnvOptionGroup.add_option("-r", "--reader", metavar="", + action="http://github.com/store", dest="reader",type="string", + help='View job config[reader] template, eg: mysqlreader,streamreader') + prodEnvOptionGroup.add_option("-w", "--writer", metavar="", + action="http://github.com/store", dest="writer",type="string", + help='View job config[writer] template, eg: mysqlwriter,streamwriter') + parser.add_option_group(prodEnvOptionGroup) + + devEnvOptionGroup = OptionGroup(parser, "Develop/Debug Options", + "Developer use these options to trace more details of DataX.") + devEnvOptionGroup.add_option("-d", "--debug", dest="remoteDebug", action="http://github.com/store_true", + help="Set to remote debug mode.") + devEnvOptionGroup.add_option("--loglevel", metavar="", dest="loglevel", action="http://github.com/store", + default="info", help="Set log level such as: debug, info, all etc.") + parser.add_option_group(devEnvOptionGroup) + return parser + +def generateJobConfigTemplate(reader, writer): + readerRef = "Please refer to the %s document:\n https://github.com/alibaba/DataX/blob/master/%s/doc/%s.md \n" % (reader,reader,reader) + writerRef = "Please refer to the %s document:\n https://github.com/alibaba/DataX/blob/master/%s/doc/%s.md \n " % (writer,writer,writer) + print readerRef + print writerRef + jobGuid = 'Please save the following configuration as a json file and use\n python {DATAX_HOME}/bin/datax.py {JSON_FILE_NAME}.json \nto run the job.\n' + print jobGuid + jobTemplate={ + "job": { + "setting": { + "speed": { + "channel": "" + } + }, + "content": [ + { + "reader": {}, + "writer": {} + } + ] + } + } + readerTemplatePath = "%s/plugin/reader/%s/plugin_job_template.json" % (DATAX_HOME,reader) + writerTemplatePath = "%s/plugin/writer/%s/plugin_job_template.json" % (DATAX_HOME,writer) + try: + readerPar = readPluginTemplate(readerTemplatePath); + except Exception, e: + print "Read reader[%s] template error: can\'t find file %s" % (reader,readerTemplatePath) + try: + writerPar = readPluginTemplate(writerTemplatePath); + except Exception, e: + print "Read writer[%s] template error: : can\'t find file %s" % (writer,writerTemplatePath) + jobTemplate['job']['content'][0]['reader'] = readerPar; + jobTemplate['job']['content'][0]['writer'] = writerPar; + print json.dumps(jobTemplate, indent=4, sort_keys=True) + +def readPluginTemplate(plugin): + with open(plugin, 'r') as f: + return json.load(f) + +def isUrl(path): + if not path: + return False + + assert (isinstance(path, str)) + m = re.match(r"^http[s]?://\S+\w*", path.lower()) + if m: + return True + else: + return False + + +def buildStartCommand(options, args): + commandMap = {} + tempJVMCommand = DEFAULT_JVM + if options.jvmParameters: + tempJVMCommand = tempJVMCommand + " " + options.jvmParameters + + if options.remoteDebug: + tempJVMCommand = tempJVMCommand + " " + REMOTE_DEBUG_CONFIG + print 'local ip: ', getLocalIp() + + if options.loglevel: + tempJVMCommand = tempJVMCommand + " " + ("-Dloglevel=%s" % (options.loglevel)) + + if options.mode: + commandMap["mode"] = options.mode + + # jobResource 可能是 URL,也可能是本地文件路径(相对,绝对) + jobResource = args[0] + if not isUrl(jobResource): + jobResource = os.path.abspath(jobResource) + if jobResource.lower().startswith("file://"): + jobResource = jobResource[len("file://"):] + + jobParams = ("-Dlog.file.name=%s") % (jobResource[-20:].replace('/', '_').replace('.', '_')) + if options.params: + jobParams = jobParams + " " + options.params + + if options.jobid: + commandMap["jobid"] = options.jobid + + commandMap["jvm"] = tempJVMCommand + commandMap["params"] = jobParams + commandMap["job"] = jobResource + + return Template(ENGINE_COMMAND).substitute(**commandMap) + + +def printCopyright(): + print ''' +DataX (%s), From Alibaba ! +Copyright (C) 2010-2015, Alibaba Group. All Rights Reserved. + +''' % DATAX_VERSION + sys.stdout.flush() + + +if __name__ == "__main__": + printCopyright() + parser = getOptionParser() + options, args = parser.parse_args(sys.argv[1:]) + if options.reader is not None and options.writer is not None: + generateJobConfigTemplate(options.reader,options.writer) + sys.exit(RET_STATE['OK']) + if len(args) != 1: + parser.print_help() + sys.exit(RET_STATE['FAIL']) + + startCommand = buildStartCommand(options, args) + # print startCommand + + child_process = subprocess.Popen(startCommand, shell=True) + register_signal() + (stdout, stderr) = child_process.communicate() + + sys.exit(child_process.returncode) diff --git a/core/src/main/bin/dxprof.py b/core/src/main/bin/dxprof.py new file mode 100644 index 000000000..181bf9008 --- /dev/null +++ b/core/src/main/bin/dxprof.py @@ -0,0 +1,191 @@ +#! /usr/bin/env python +# vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker nu: + +import re +import sys +import time + +REG_SQL_WAKE = re.compile(r'Begin\s+to\s+read\s+record\s+by\s+Sql', re.IGNORECASE) +REG_SQL_DONE = re.compile(r'Finished\s+read\s+record\s+by\s+Sql', re.IGNORECASE) +REG_SQL_PATH = re.compile(r'from\s+(\w+)(\s+where|\s*$)', re.IGNORECASE) +REG_SQL_JDBC = re.compile(r'jdbcUrl:\s*\[(.+?)\]', re.IGNORECASE) +REG_SQL_UUID = re.compile(r'(\d+\-)+reader') +REG_COMMIT_UUID = re.compile(r'(\d+\-)+writer') +REG_COMMIT_WAKE = re.compile(r'begin\s+to\s+commit\s+blocks', re.IGNORECASE) +REG_COMMIT_DONE = re.compile(r'commit\s+blocks\s+ok', re.IGNORECASE) + +# {{{ function parse_timestamp() # +def parse_timestamp(line): + try: + ts = int(time.mktime(time.strptime(line[0:19], '%Y-%m-%d %H:%M:%S'))) + except: + ts = 0 + + return ts + +# }}} # + +# {{{ function parse_query_host() # +def parse_query_host(line): + ori = REG_SQL_JDBC.search(line) + if (not ori): + return '' + + ori = ori.group(1).split('?')[0] + off = ori.find('@') + if (off > -1): + ori = ori[off+1:len(ori)] + else: + off = ori.find('//') + if (off > -1): + ori = ori[off+2:len(ori)] + + return ori.lower() +# }}} # + +# {{{ function parse_query_table() # +def parse_query_table(line): + ori = REG_SQL_PATH.search(line) + return (ori and ori.group(1).lower()) or '' +# }}} # + +# {{{ function parse_reader_task() # +def parse_task(fname): + global LAST_SQL_UUID + global LAST_COMMIT_UUID + global DATAX_JOBDICT + global DATAX_JOBDICT_COMMIT + global UNIXTIME + LAST_SQL_UUID = '' + DATAX_JOBDICT = {} + LAST_COMMIT_UUID = '' + DATAX_JOBDICT_COMMIT = {} + + UNIXTIME = int(time.time()) + with open(fname, 'r') as f: + for line in f.readlines(): + line = line.strip() + + if (LAST_SQL_UUID and (LAST_SQL_UUID in DATAX_JOBDICT)): + DATAX_JOBDICT[LAST_SQL_UUID]['host'] = parse_query_host(line) + LAST_SQL_UUID = '' + + if line.find('CommonRdbmsReader$Task') > 0: + parse_read_task(line) + elif line.find('commit blocks') > 0: + parse_write_task(line) + else: + continue +# }}} # + +# {{{ function parse_read_task() # +def parse_read_task(line): + ser = REG_SQL_UUID.search(line) + if not ser: + return + + LAST_SQL_UUID = ser.group() + if REG_SQL_WAKE.search(line): + DATAX_JOBDICT[LAST_SQL_UUID] = { + 'stat' : 'R', + 'wake' : parse_timestamp(line), + 'done' : UNIXTIME, + 'host' : parse_query_host(line), + 'path' : parse_query_table(line) + } + elif ((LAST_SQL_UUID in DATAX_JOBDICT) and REG_SQL_DONE.search(line)): + DATAX_JOBDICT[LAST_SQL_UUID]['stat'] = 'D' + DATAX_JOBDICT[LAST_SQL_UUID]['done'] = parse_timestamp(line) +# }}} # + +# {{{ function parse_write_task() # +def parse_write_task(line): + ser = REG_COMMIT_UUID.search(line) + if not ser: + return + + LAST_COMMIT_UUID = ser.group() + if REG_COMMIT_WAKE.search(line): + DATAX_JOBDICT_COMMIT[LAST_COMMIT_UUID] = { + 'stat' : 'R', + 'wake' : parse_timestamp(line), + 'done' : UNIXTIME, + } + elif ((LAST_COMMIT_UUID in DATAX_JOBDICT_COMMIT) and REG_COMMIT_DONE.search(line)): + DATAX_JOBDICT_COMMIT[LAST_COMMIT_UUID]['stat'] = 'D' + DATAX_JOBDICT_COMMIT[LAST_COMMIT_UUID]['done'] = parse_timestamp(line) +# }}} # + +# {{{ function result_analyse() # +def result_analyse(): + def compare(a, b): + return b['cost'] - a['cost'] + + tasklist = [] + hostsmap = {} + statvars = {'sum' : 0, 'cnt' : 0, 'svr' : 0, 'max' : 0, 'min' : int(time.time())} + tasklist_commit = [] + statvars_commit = {'sum' : 0, 'cnt' : 0} + + for idx in DATAX_JOBDICT: + item = DATAX_JOBDICT[idx] + item['uuid'] = idx; + item['cost'] = item['done'] - item['wake'] + tasklist.append(item); + + if (not (item['host'] in hostsmap)): + hostsmap[item['host']] = 1 + statvars['svr'] += 1 + + if (item['cost'] > -1 and item['cost'] < 864000): + statvars['sum'] += item['cost'] + statvars['cnt'] += 1 + statvars['max'] = max(statvars['max'], item['done']) + statvars['min'] = min(statvars['min'], item['wake']) + + for idx in DATAX_JOBDICT_COMMIT: + itemc = DATAX_JOBDICT_COMMIT[idx] + itemc['uuid'] = idx + itemc['cost'] = itemc['done'] - itemc['wake'] + tasklist_commit.append(itemc) + + if (itemc['cost'] > -1 and itemc['cost'] < 864000): + statvars_commit['sum'] += itemc['cost'] + statvars_commit['cnt'] += 1 + + ttl = (statvars['max'] - statvars['min']) or 1 + idx = float(statvars['cnt']) / (statvars['sum'] or ttl) + + tasklist.sort(compare) + for item in tasklist: + print '%s\t%s.%s\t%s\t%s\t% 4d\t% 2.1f%%\t% .2f' %(item['stat'], item['host'], item['path'], + time.strftime('%H:%M:%S', time.localtime(item['wake'])), + (('D' == item['stat']) and time.strftime('%H:%M:%S', time.localtime(item['done']))) or '--', + item['cost'], 100 * item['cost'] / ttl, idx * item['cost']) + + if (not len(tasklist) or not statvars['cnt']): + return + + print '\n--- DataX Profiling Statistics ---' + print '%d task(s) on %d server(s), Total elapsed %d second(s), %.2f second(s) per task in average' %(statvars['cnt'], + statvars['svr'], statvars['sum'], float(statvars['sum']) / statvars['cnt']) + print 'Actually cost %d second(s) (%s - %s), task concurrency: %.2f, tilt index: %.2f' %(ttl, + time.strftime('%H:%M:%S', time.localtime(statvars['min'])), + time.strftime('%H:%M:%S', time.localtime(statvars['max'])), + float(statvars['sum']) / ttl, idx * tasklist[0]['cost']) + + idx_commit = float(statvars_commit['cnt']) / (statvars_commit['sum'] or ttl) + tasklist_commit.sort(compare) + print '%d task(s) done odps comit, Total elapsed %d second(s), %.2f second(s) per task in average, tilt index: %.2f' % ( + statvars_commit['cnt'], + statvars_commit['sum'], float(statvars_commit['sum']) / statvars_commit['cnt'], + idx_commit * tasklist_commit[0]['cost']) + +# }}} # + +if (len(sys.argv) < 2): + print "Usage: %s filename" %(sys.argv[0]) + quit(1) +else: + parse_task(sys.argv[1]) + result_analyse() \ No newline at end of file diff --git a/core/src/main/conf/.secret.properties b/core/src/main/conf/.secret.properties new file mode 100755 index 000000000..3b295a175 --- /dev/null +++ b/core/src/main/conf/.secret.properties @@ -0,0 +1,3 @@ +#ds basicAuth config +auth.user= +auth.pass= \ No newline at end of file diff --git a/core/src/main/conf/core.json b/core/src/main/conf/core.json new file mode 100755 index 000000000..ce5d025ae --- /dev/null +++ b/core/src/main/conf/core.json @@ -0,0 +1,61 @@ + +{ + "entry": { + "jvm": "-Xms1G -Xmx1G", + "environment": {} + }, + "common": { + "column": { + "datetimeFormat": "yyyy-MM-dd HH:mm:ss", + "timeFormat": "HH:mm:ss", + "dateFormat": "yyyy-MM-dd", + "extraFormats":["yyyyMMdd"], + "timeZone": "GMT+8", + "encoding": "utf-8" + } + }, + "core": { + "dataXServer": { + "address": "http://localhost:7001/api", + "timeout": 10000, + "reportDataxLog": false, + "reportPerfLog": false + }, + "transport": { + "channel": { + "class": "com.alibaba.datax.core.transport.channel.memory.MemoryChannel", + "speed": { + "byte": 1048576, + "record": 10000 + }, + "flowControlInterval": 20, + "capacity": 512, + "byteCapacity": 67108864 + }, + "exchanger": { + "class": "com.alibaba.datax.core.plugin.BufferedRecordExchanger", + "bufferSize": 32 + } + }, + "container": { + "job": { + "reportInterval": 10000 + }, + "taskGroup": { + "channel": 5 + }, + "trace": { + "enable": "true" + } + + }, + "statistics": { + "collector": { + "plugin": { + "taskClass": "com.alibaba.datax.core.statistics.plugin.task.StdoutPluginCollector", + "maxDirtyNumber": 10 + } + } + } + } +} diff --git a/core/src/main/conf/logback.xml b/core/src/main/conf/logback.xml new file mode 100755 index 000000000..7a433ba97 --- /dev/null +++ b/core/src/main/conf/logback.xml @@ -0,0 +1,150 @@ + + + + + + + + + + UTF-8 + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + UTF-8 + ${log.dir}/${ymd}/${log.file.name}-${byMillionSecond}.log + false + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + UTF-8 + ${perf.dir}/${ymd}/${log.file.name}-${byMillionSecond}.log + false + + %msg%n + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/datax/core/AbstractContainer.java b/core/src/main/java/com/alibaba/datax/core/AbstractContainer.java new file mode 100755 index 000000000..c4e09b757 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/AbstractContainer.java @@ -0,0 +1,35 @@ +package com.alibaba.datax.core; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import org.apache.commons.lang.Validate; + +/** + * 执行容器的抽象类,持有该容器全局的配置 configuration + */ +public abstract class AbstractContainer { + protected Configuration configuration; + + protected AbstractContainerCommunicator containerCommunicator; + + public AbstractContainer(Configuration configuration) { + Validate.notNull(configuration, "Configuration can not be null."); + + this.configuration = configuration; + } + + public Configuration getConfiguration() { + return configuration; + } + + public AbstractContainerCommunicator getContainerCommunicator() { + return containerCommunicator; + } + + public void setContainerCommunicator(AbstractContainerCommunicator containerCommunicator) { + this.containerCommunicator = containerCommunicator; + } + + public abstract void start(); + +} diff --git a/core/src/main/java/com/alibaba/datax/core/Engine.java b/core/src/main/java/com/alibaba/datax/core/Engine.java new file mode 100755 index 000000000..5f69a88fc --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/Engine.java @@ -0,0 +1,217 @@ +package com.alibaba.datax.core; + +import com.alibaba.datax.common.element.ColumnCast; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.spi.ErrorCode; +import com.alibaba.datax.common.statistics.PerfTrace; +import com.alibaba.datax.common.statistics.VMInfo; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.JobContainer; +import com.alibaba.datax.core.taskgroup.TaskGroupContainer; +import com.alibaba.datax.core.util.ConfigParser; +import com.alibaba.datax.core.util.ConfigurationValidate; +import com.alibaba.datax.core.util.ExceptionTracker; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.container.LoadUtil; +import org.apache.commons.cli.BasicParser; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Options; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Engine是DataX入口类,该类负责初始化Job或者Task的运行容器,并运行插件的Job或者Task逻辑 + */ +public class Engine { + private static final Logger LOG = LoggerFactory.getLogger(Engine.class); + + private static String RUNTIME_MODE; + + /* check job model (job/task) first */ + public void start(Configuration allConf) { + + // 绑定column转换信息 + ColumnCast.bind(allConf); + + /** + * 初始化PluginLoader,可以获取各种插件配置 + */ + LoadUtil.bind(allConf); + + boolean isJob = !("taskGroup".equalsIgnoreCase(allConf + .getString(CoreConstant.DATAX_CORE_CONTAINER_MODEL))); + + AbstractContainer container; + long instanceId; + int taskGroupId = -1; + if (isJob) { + allConf.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_MODE, RUNTIME_MODE); + container = new JobContainer(allConf); + instanceId = allConf.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, 0); + + } else { + container = new TaskGroupContainer(allConf); + instanceId = allConf.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID); + taskGroupId = allConf.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID); + } + + //缺省打开perfTrace + boolean traceEnable = allConf.getBool(CoreConstant.DATAX_CORE_CONTAINER_TRACE_ENABLE, true); + boolean perfReportEnable = allConf.getBool(CoreConstant.DATAX_CORE_REPORT_DATAX_PERFLOG, true); + + int priority = 0; + try { + priority = Integer.parseInt(System.getenv("SKYNET_PRIORITY")); + }catch (NumberFormatException e){ + LOG.warn("prioriy set to 0, because NumberFormatException, the value is: "+System.getProperty("PROIORY")); + } + + Configuration jobInfoConfig = allConf.getConfiguration(CoreConstant.DATAX_JOB_JOBINFO); + //初始化PerfTrace + PerfTrace perfTrace = PerfTrace.getInstance(isJob, instanceId, taskGroupId, priority, traceEnable); + perfTrace.setJobInfo(jobInfoConfig); + perfTrace.setPerfReportEnalbe(perfReportEnable); + container.start(); + + + } + + + // 注意屏蔽敏感信息 + public static String filterJobConfiguration(final Configuration configuration) { + Configuration jobConfWithSetting = configuration.getConfiguration("job").clone(); + + Configuration jobContent = jobConfWithSetting.getConfiguration("content"); + + filterSensitiveConfiguration(jobContent); + + jobConfWithSetting.set("content",jobContent); + + return jobConfWithSetting.beautify(); + } + + public static Configuration filterSensitiveConfiguration(Configuration configuration){ + Set keys = configuration.getKeys(); + for (final String key : keys) { + boolean isSensitive = StringUtils.endsWithIgnoreCase(key, "password") + || StringUtils.endsWithIgnoreCase(key, "accessKey"); + if (isSensitive && configuration.get(key) instanceof String) { + configuration.set(key, configuration.getString(key).replaceAll(".", "*")); + } + } + return configuration; + } + + public static void entry(final String[] args) throws Throwable { + Options options = new Options(); + options.addOption("job", true, "Job config."); + options.addOption("jobid", true, "Job unique id."); + options.addOption("mode", true, "Job runtime mode."); + + BasicParser parser = new BasicParser(); + CommandLine cl = parser.parse(options, args); + + String jobPath = cl.getOptionValue("job"); + + // 如果用户没有明确指定jobid, 则 datax.py 会指定 jobid 默认值为-1 + String jobIdString = cl.getOptionValue("jobid"); + RUNTIME_MODE = cl.getOptionValue("mode"); + + Configuration configuration = ConfigParser.parse(jobPath); + + long jobId; + if (!"-1".equalsIgnoreCase(jobIdString)) { + jobId = Long.parseLong(jobIdString); + } else { + // only for dsc & ds & datax 3 update + String dscJobUrlPatternString = "/instance/(\\d{1,})/config.xml"; + String dsJobUrlPatternString = "/inner/job/(\\d{1,})/config"; + String dsTaskGroupUrlPatternString = "/inner/job/(\\d{1,})/taskGroup/"; + List patternStringList = Arrays.asList(dscJobUrlPatternString, + dsJobUrlPatternString, dsTaskGroupUrlPatternString); + jobId = parseJobIdFromUrl(patternStringList, jobPath); + } + + boolean isStandAloneMode = "standalone".equalsIgnoreCase(RUNTIME_MODE); + if (!isStandAloneMode && jobId == -1) { + // 如果不是 standalone 模式,那么 jobId 一定不能为-1 + throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, "非 standalone 模式必须在 URL 中提供有效的 jobId."); + } + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, jobId); + + //打印vmInfo + VMInfo vmInfo = VMInfo.getVmInfo(); + if (vmInfo != null) { + LOG.info(vmInfo.toString()); + } + + LOG.info("\n" + Engine.filterJobConfiguration(configuration) + "\n"); + + LOG.debug(configuration.toJSON()); + + ConfigurationValidate.doValidate(configuration); + Engine engine = new Engine(); + engine.start(configuration); + } + + + /** + * -1 表示未能解析到 jobId + * + * only for dsc & ds & datax 3 update + */ + private static long parseJobIdFromUrl(List patternStringList, String url) { + long result = -1; + for (String patternString : patternStringList) { + result = doParseJobIdFromUrl(patternString, url); + if (result != -1) { + return result; + } + } + return result; + } + + private static long doParseJobIdFromUrl(String patternString, String url) { + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(url); + if (matcher.find()) { + return Long.parseLong(matcher.group(1)); + } + + return -1; + } + + public static void main(String[] args) throws Exception { + int exitCode = 0; + try { + Engine.entry(args); + } catch (Throwable e) { + exitCode = 1; + LOG.error("\n\n经DataX智能分析,该任务最可能的错误原因是:\n" + ExceptionTracker.trace(e)); + + if (e instanceof DataXException) { + DataXException tempException = (DataXException) e; + ErrorCode errorCode = tempException.getErrorCode(); + if (errorCode instanceof FrameworkErrorCode) { + FrameworkErrorCode tempErrorCode = (FrameworkErrorCode) errorCode; + exitCode = tempErrorCode.toExitValue(); + } + } + + System.exit(exitCode); + } + System.exit(exitCode); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/container/util/HookInvoker.java b/core/src/main/java/com/alibaba/datax/core/container/util/HookInvoker.java new file mode 100755 index 000000000..6e0ef1782 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/container/util/HookInvoker.java @@ -0,0 +1,91 @@ +package com.alibaba.datax.core.container.util; + +/** + * Created by xiafei.qiuxf on 14/12/17. + */ + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.spi.Hook; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.JarLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * 扫描给定目录的所有一级子目录,每个子目录当作一个Hook的目录。 + * 对于每个子目录,必须符合ServiceLoader的标准目录格式,见http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html。 + * 加载里头的jar,使用ServiceLoader机制调用。 + */ +public class HookInvoker { + + private static final Logger LOG = LoggerFactory.getLogger(HookInvoker.class); + private final Map msg; + private final Configuration conf; + + private File baseDir; + + public HookInvoker(String baseDirName, Configuration conf, Map msg) { + this.baseDir = new File(baseDirName); + this.conf = conf; + this.msg = msg; + } + + public void invokeAll() { + if (!baseDir.exists() || baseDir.isFile()) { + LOG.info("No hook invoked, because base dir not exists or is a file: " + baseDir.getAbsolutePath()); + return; + } + + String[] subDirs = baseDir.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return new File(dir, name).isDirectory(); + } + }); + + if (subDirs == null) { + throw DataXException.asDataXException(FrameworkErrorCode.HOOK_LOAD_ERROR, "获取HOOK子目录返回null"); + } + + for (String subDir : subDirs) { + doInvoke(new File(baseDir, subDir).getAbsolutePath()); + } + + } + + private void doInvoke(String path) { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + try { + JarLoader jarLoader = new JarLoader(new String[]{path}); + Thread.currentThread().setContextClassLoader(jarLoader); + Iterator hookIt = ServiceLoader.load(Hook.class).iterator(); + if (!hookIt.hasNext()) { + LOG.warn("No hook defined under path: " + path); + } else { + Hook hook = hookIt.next(); + LOG.info("Invoke hook [{}], path: {}", hook.getName(), path); + hook.invoke(conf, msg); + } + } catch (Exception e) { + LOG.error("Exception when invoke hook", e); + throw DataXException.asDataXException( + CommonErrorCode.HOOK_INTERNAL_ERROR, "Exception when invoke hook", e); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + public static void main(String[] args) { + new HookInvoker("/Users/xiafei/workspace/datax3/target/datax/datax/hook", + null, new HashMap()).invokeAll(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/container/util/JobAssignUtil.java b/core/src/main/java/com/alibaba/datax/core/container/util/JobAssignUtil.java new file mode 100755 index 000000000..31ba60a4d --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/container/util/JobAssignUtil.java @@ -0,0 +1,177 @@ +package com.alibaba.datax.core.container.util; + +import com.alibaba.datax.common.constant.CommonConstant; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.Validate; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +public final class JobAssignUtil { + private JobAssignUtil() { + } + + /** + * 公平的分配 task 到对应的 taskGroup 中。 + * 公平体现在:会考虑 task 中对资源负载作的 load 标识进行更均衡的作业分配操作。 + * TODO 具体文档举例说明 + */ + public static List assignFairly(Configuration configuration, int channelNumber, int channelsPerTaskGroup) { + Validate.isTrue(configuration != null, "框架获得的 Job 不能为 null."); + + List contentConfig = configuration.getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + Validate.isTrue(contentConfig.size() > 0, "框架获得的切分后的 Job 无内容."); + + Validate.isTrue(channelNumber > 0 && channelsPerTaskGroup > 0, + "每个channel的平均task数[averTaskPerChannel],channel数目[channelNumber],每个taskGroup的平均channel数[channelsPerTaskGroup]都应该为正数"); + + int taskGroupNumber = (int) Math.ceil(1.0 * channelNumber / channelsPerTaskGroup); + + Configuration aTaskConfig = contentConfig.get(0); + + String readerResourceMark = aTaskConfig.getString(CoreConstant.JOB_READER_PARAMETER + "." + + CommonConstant.LOAD_BALANCE_RESOURCE_MARK); + String writerResourceMark = aTaskConfig.getString(CoreConstant.JOB_WRITER_PARAMETER + "." + + CommonConstant.LOAD_BALANCE_RESOURCE_MARK); + + boolean hasLoadBalanceResourceMark = StringUtils.isNotBlank(readerResourceMark) || + StringUtils.isNotBlank(writerResourceMark); + + if (!hasLoadBalanceResourceMark) { + // fake 一个固定的 key 作为资源标识(在 reader 或者 writer 上均可,此处选择在 reader 上进行 fake) + for (Configuration conf : contentConfig) { + conf.set(CoreConstant.JOB_READER_PARAMETER + "." + + CommonConstant.LOAD_BALANCE_RESOURCE_MARK, "aFakeResourceMarkForLoadBalance"); + } + // 是为了避免某些插件没有设置 资源标识 而进行了一次随机打乱操作 + Collections.shuffle(contentConfig, new Random(System.currentTimeMillis())); + } + + LinkedHashMap> resourceMarkAndTaskIdMap = parseAndGetResourceMarkAndTaskIdMap(contentConfig); + List taskGroupConfig = doAssign(resourceMarkAndTaskIdMap, configuration, taskGroupNumber); + + // 调整 每个 taskGroup 对应的 Channel 个数(属于优化范畴) + adjustChannelNumPerTaskGroup(taskGroupConfig, channelNumber); + return taskGroupConfig; + } + + private static void adjustChannelNumPerTaskGroup(List taskGroupConfig, int channelNumber) { + int taskGroupNumber = taskGroupConfig.size(); + int avgChannelsPerTaskGroup = channelNumber / taskGroupNumber; + int remainderChannelCount = channelNumber % taskGroupNumber; + // 表示有 remainderChannelCount 个 taskGroup,其对应 Channel 个数应该为:avgChannelsPerTaskGroup + 1; + // (taskGroupNumber - remainderChannelCount)个 taskGroup,其对应 Channel 个数应该为:avgChannelsPerTaskGroup + + int i = 0; + for (; i < remainderChannelCount; i++) { + taskGroupConfig.get(i).set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, avgChannelsPerTaskGroup + 1); + } + + for (int j = 0; j < taskGroupNumber - remainderChannelCount; j++) { + taskGroupConfig.get(i + j).set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, avgChannelsPerTaskGroup); + } + } + + /** + * 根据task 配置,获取到: + * 资源名称 --> taskId(List) 的 map 映射关系 + */ + private static LinkedHashMap> parseAndGetResourceMarkAndTaskIdMap(List contentConfig) { + // key: resourceMark, value: taskId + LinkedHashMap> readerResourceMarkAndTaskIdMap = new LinkedHashMap>(); + LinkedHashMap> writerResourceMarkAndTaskIdMap = new LinkedHashMap>(); + + for (Configuration aTaskConfig : contentConfig) { + int taskId = aTaskConfig.getInt(CoreConstant.TASK_ID); + // 把 readerResourceMark 加到 readerResourceMarkAndTaskIdMap 中 + String readerResourceMark = aTaskConfig.getString(CoreConstant.JOB_READER_PARAMETER + "." + CommonConstant.LOAD_BALANCE_RESOURCE_MARK); + if (readerResourceMarkAndTaskIdMap.get(readerResourceMark) == null) { + readerResourceMarkAndTaskIdMap.put(readerResourceMark, new LinkedList()); + } + readerResourceMarkAndTaskIdMap.get(readerResourceMark).add(taskId); + + // 把 writerResourceMark 加到 writerResourceMarkAndTaskIdMap 中 + String writerResourceMark = aTaskConfig.getString(CoreConstant.JOB_WRITER_PARAMETER + "." + CommonConstant.LOAD_BALANCE_RESOURCE_MARK); + if (writerResourceMarkAndTaskIdMap.get(writerResourceMark) == null) { + writerResourceMarkAndTaskIdMap.put(writerResourceMark, new LinkedList()); + } + writerResourceMarkAndTaskIdMap.get(writerResourceMark).add(taskId); + } + + if (readerResourceMarkAndTaskIdMap.size() >= writerResourceMarkAndTaskIdMap.size()) { + // 采用 reader 对资源做的标记进行 shuffle + return readerResourceMarkAndTaskIdMap; + } else { + // 采用 writer 对资源做的标记进行 shuffle + return writerResourceMarkAndTaskIdMap; + } + } + + + /** + * /** + * 需要实现的效果通过例子来说是: + *
+     * a 库上有表:0, 1, 2
+     * a 库上有表:3, 4
+     * c 库上有表:5, 6, 7
+     *
+     * 如果有 4个 taskGroup
+     * 则 assign 后的结果为:
+     * taskGroup-0: 0,  4,
+     * taskGroup-1: 3,  6,
+     * taskGroup-2: 5,  2,
+     * taskGroup-3: 1,  7
+     *
+     * 
+ */ + private static List doAssign(LinkedHashMap> resourceMarkAndTaskIdMap, Configuration jobConfiguration, int taskGroupNumber) { + List contentConfig = jobConfiguration.getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + + Configuration taskGroupTemplate = jobConfiguration.clone(); + taskGroupTemplate.remove(CoreConstant.DATAX_JOB_CONTENT); + + List result = new LinkedList(); + + List> taskGroupConfigList = new ArrayList>(taskGroupNumber); + for (int i = 0; i < taskGroupNumber; i++) { + taskGroupConfigList.add(new LinkedList()); + } + + int mapValueMaxLength = -1; + + List resourceMarks = new ArrayList(); + for (Map.Entry> entry : resourceMarkAndTaskIdMap.entrySet()) { + resourceMarks.add(entry.getKey()); + if (entry.getValue().size() > mapValueMaxLength) { + mapValueMaxLength = entry.getValue().size(); + } + } + + int taskGroupIndex = 0; + for (int i = 0; i < mapValueMaxLength; i++) { + for (String resourceMark : resourceMarks) { + if (resourceMarkAndTaskIdMap.get(resourceMark).size() > 0) { + int taskId = resourceMarkAndTaskIdMap.get(resourceMark).get(0); + taskGroupConfigList.get(taskGroupIndex % taskGroupNumber).add(contentConfig.get(taskId)); + taskGroupIndex++; + + resourceMarkAndTaskIdMap.get(resourceMark).remove(0); + } + } + } + + Configuration tempTaskGroupConfig; + for (int i = 0; i < taskGroupNumber; i++) { + tempTaskGroupConfig = taskGroupTemplate.clone(); + tempTaskGroupConfig.set(CoreConstant.DATAX_JOB_CONTENT, taskGroupConfigList.get(i)); + tempTaskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, i); + + result.add(tempTaskGroupConfig); + } + + return result; + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/JobContainer.java b/core/src/main/java/com/alibaba/datax/core/job/JobContainer.java new file mode 100755 index 000000000..494509b22 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/JobContainer.java @@ -0,0 +1,923 @@ +package com.alibaba.datax.core.job; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.AbstractJobPlugin; +import com.alibaba.datax.common.plugin.JobPluginCollector; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.statistics.PerfTrace; +import com.alibaba.datax.common.statistics.VMInfo; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.StrUtil; +import com.alibaba.datax.core.AbstractContainer; +import com.alibaba.datax.core.Engine; +import com.alibaba.datax.core.container.util.HookInvoker; +import com.alibaba.datax.core.container.util.JobAssignUtil; +import com.alibaba.datax.core.job.meta.ExecuteMode; +import com.alibaba.datax.core.job.scheduler.AbstractScheduler; +import com.alibaba.datax.core.job.scheduler.processinner.StandAloneScheduler; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.statistics.container.communicator.job.StandAloneJobContainerCommunicator; +import com.alibaba.datax.core.statistics.plugin.DefaultJobPluginCollector; +import com.alibaba.datax.core.util.ErrorRecordChecker; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.ClassLoaderSwapper; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.container.LoadUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14-8-24. + *

+ * job实例运行在jobContainer容器中,它是所有任务的master,负责初始化、拆分、调度、运行、回收、监控和汇报 + * 但它并不做实际的数据同步操作 + */ +public class JobContainer extends AbstractContainer { + private static final Logger LOG = LoggerFactory + .getLogger(JobContainer.class); + + private static final SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + + private ClassLoaderSwapper classLoaderSwapper = ClassLoaderSwapper + .newCurrentThreadClassLoaderSwapper(); + + private long jobId; + + private String readerPluginName; + + private String writerPluginName; + + /** + * reader和writer jobContainer的实例 + */ + private Reader.Job jobReader; + + private Writer.Job jobWriter; + + private Configuration userConf; + + private long startTimeStamp; + + private long endTimeStamp; + + private long startTransferTimeStamp; + + private long endTransferTimeStamp; + + private int needChannelNumber; + + private int totalStage = 1; + + private ErrorRecordChecker errorLimit; + + public JobContainer(Configuration configuration) { + super(configuration); + + errorLimit = new ErrorRecordChecker(configuration); + } + + /** + * jobContainer主要负责的工作全部在start()里面,包括init、prepare、split、scheduler、 + * post以及destroy和statistics + */ + @Override + public void start() { + LOG.info("DataX jobContainer starts job."); + + boolean hasException = false; + boolean isDryRun = false; + try { + this.startTimeStamp = System.currentTimeMillis(); + isDryRun = configuration.getBool(CoreConstant.DATAX_JOB_SETTING_DRYRUN, false); + if(isDryRun) { + LOG.info("jobContainer starts to do preCheck ..."); + this.preCheck(); + } else { + userConf = configuration.clone(); + LOG.debug("jobContainer starts to do preHandle ..."); + this.preHandle(); + + LOG.debug("jobContainer starts to do init ..."); + this.init(); + LOG.debug("jobContainer starts to do prepare ..."); + this.prepare(); + LOG.debug("jobContainer starts to do split ..."); + this.totalStage = this.split(); + LOG.debug("jobContainer starts to do schedule ..."); + this.schedule(); + LOG.debug("jobContainer starts to do post ..."); + this.post(); + + LOG.debug("jobContainer starts to do postHandle ..."); + this.postHandle(); + LOG.info("DataX jobId [{}] completed successfully.", this.jobId); + + this.invokeHooks(); + } + } catch (Throwable e) { + LOG.error("Exception when job run", e); + + hasException = true; + + if (e instanceof OutOfMemoryError) { + this.destroy(); + System.gc(); + } + + + if (super.getContainerCommunicator() == null) { + // 由于 containerCollector 是在 scheduler() 中初始化的,所以当在 scheduler() 之前出现异常时,需要在此处对 containerCollector 进行初始化 + + AbstractContainerCommunicator tempContainerCollector; + // standalone + tempContainerCollector = new StandAloneJobContainerCommunicator(configuration); + + super.setContainerCommunicator(tempContainerCollector); + } + + Communication communication = super.getContainerCommunicator().collect(); + // 汇报前的状态,不需要手动进行设置 + // communication.setState(State.FAILED); + communication.setThrowable(e); + communication.setTimestamp(this.endTimeStamp); + + Communication tempComm = new Communication(); + tempComm.setTimestamp(this.startTransferTimeStamp); + + Communication reportCommunication = CommunicationTool.getReportCommunication(communication, tempComm, this.totalStage); + super.getContainerCommunicator().report(reportCommunication); + + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } finally { + if(!isDryRun) { + + this.destroy(); + this.endTimeStamp = System.currentTimeMillis(); + if (!hasException) { + //最后打印cpu的平均消耗,GC的统计 + VMInfo vmInfo = VMInfo.getVmInfo(); + if (vmInfo != null) { + vmInfo.getDelta(false); + LOG.info(vmInfo.totalString()); + } + + LOG.info(PerfTrace.getInstance().summarizeNoException()); + this.logStatistics(); + } + } + } + } + + private void preCheck() { + this.preCheckInit(); + this.adjustChannelNumber(); + + if (this.needChannelNumber <= 0) { + this.needChannelNumber = 1; + } + this.preCheckReader(); + this.preCheckWriter(); + LOG.info("PreCheck通过"); + } + + private void preCheckInit() { + this.jobId = this.configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, -1); + + if (this.jobId < 0) { + LOG.info("Set jobId = 0"); + this.jobId = 0; + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, + this.jobId); + } + + Thread.currentThread().setName("job-" + this.jobId); + + JobPluginCollector jobPluginCollector = new DefaultJobPluginCollector( + this.getContainerCommunicator()); + this.jobReader = this.preCheckReaderInit(jobPluginCollector); + this.jobWriter = this.preCheckWriterInit(jobPluginCollector); + } + + private Reader.Job preCheckReaderInit(JobPluginCollector jobPluginCollector) { + this.readerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_READER_NAME); + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + + Reader.Job jobReader = (Reader.Job) LoadUtil.loadJobPlugin( + PluginType.READER, this.readerPluginName); + + this.configuration.set(CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER + ".dryRun", true); + + // 设置reader的jobConfig + jobReader.setPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER)); + // 设置reader的readerConfig + jobReader.setPeerPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER)); + + jobReader.setJobPluginCollector(jobPluginCollector); + + classLoaderSwapper.restoreCurrentThreadClassLoader(); + return jobReader; + } + + + private Writer.Job preCheckWriterInit(JobPluginCollector jobPluginCollector) { + this.writerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_WRITER_NAME); + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + + Writer.Job jobWriter = (Writer.Job) LoadUtil.loadJobPlugin( + PluginType.WRITER, this.writerPluginName); + + this.configuration.set(CoreConstant.DATAX_JOB_CONTENT_WRITER_PARAMETER + ".dryRun", true); + + // 设置writer的jobConfig + jobWriter.setPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_WRITER_PARAMETER)); + // 设置reader的readerConfig + jobWriter.setPeerPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER)); + + jobWriter.setPeerPluginName(this.readerPluginName); + jobWriter.setJobPluginCollector(jobPluginCollector); + + classLoaderSwapper.restoreCurrentThreadClassLoader(); + + return jobWriter; + } + + private void preCheckReader() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + LOG.info(String.format("DataX Reader.Job [%s] do preCheck work .", + this.readerPluginName)); + this.jobReader.preCheck(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + private void preCheckWriter() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + LOG.info(String.format("DataX Writer.Job [%s] do preCheck work .", + this.writerPluginName)); + this.jobWriter.preCheck(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + /** + * reader和writer的初始化 + */ + private void init() { + this.jobId = this.configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, -1); + + if (this.jobId < 0) { + LOG.info("Set jobId = 0"); + this.jobId = 0; + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, + this.jobId); + } + + Thread.currentThread().setName("job-" + this.jobId); + + JobPluginCollector jobPluginCollector = new DefaultJobPluginCollector( + this.getContainerCommunicator()); + //必须先Reader ,后Writer + this.jobReader = this.initJobReader(jobPluginCollector); + this.jobWriter = this.initJobWriter(jobPluginCollector); + } + + private void prepare() { + this.prepareJobReader(); + this.prepareJobWriter(); + } + + private void preHandle() { + String handlerPluginTypeStr = this.configuration.getString( + CoreConstant.DATAX_JOB_PREHANDLER_PLUGINTYPE); + if(!StringUtils.isNotEmpty(handlerPluginTypeStr)){ + return; + } + PluginType handlerPluginType; + try { + handlerPluginType = PluginType.valueOf(handlerPluginTypeStr.toUpperCase()); + } catch (IllegalArgumentException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, + String.format("Job preHandler's pluginType(%s) set error, reason(%s)", handlerPluginTypeStr.toUpperCase(), e.getMessage())); + } + + String handlerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_PREHANDLER_PLUGINNAME); + + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + handlerPluginType, handlerPluginName)); + + AbstractJobPlugin handler = LoadUtil.loadJobPlugin( + handlerPluginType, handlerPluginName); + + JobPluginCollector jobPluginCollector = new DefaultJobPluginCollector( + this.getContainerCommunicator()); + handler.setJobPluginCollector(jobPluginCollector); + + //todo configuration的安全性,将来必须保证 + handler.preHandler(configuration); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + + LOG.info("After PreHandler: \n" + Engine.filterJobConfiguration(configuration) + "\n"); + } + + private void postHandle() { + String handlerPluginTypeStr = this.configuration.getString( + CoreConstant.DATAX_JOB_POSTHANDLER_PLUGINTYPE); + + if(!StringUtils.isNotEmpty(handlerPluginTypeStr)){ + return; + } + PluginType handlerPluginType; + try { + handlerPluginType = PluginType.valueOf(handlerPluginTypeStr.toUpperCase()); + } catch (IllegalArgumentException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, + String.format("Job postHandler's pluginType(%s) set error, reason(%s)", handlerPluginTypeStr.toUpperCase(), e.getMessage())); + } + + String handlerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_POSTHANDLER_PLUGINNAME); + + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + handlerPluginType, handlerPluginName)); + + AbstractJobPlugin handler = LoadUtil.loadJobPlugin( + handlerPluginType, handlerPluginName); + + JobPluginCollector jobPluginCollector = new DefaultJobPluginCollector( + this.getContainerCommunicator()); + handler.setJobPluginCollector(jobPluginCollector); + + handler.postHandler(configuration); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + + /** + * 执行reader和writer最细粒度的切分,需要注意的是,writer的切分结果要参照reader的切分结果, + * 达到切分后数目相等,才能满足1:1的通道模型,所以这里可以将reader和writer的配置整合到一起, + * 然后,为避免顺序给读写端带来长尾影响,将整合的结果shuffler掉 + */ + private int split() { + this.adjustChannelNumber(); + + if (this.needChannelNumber <= 0) { + this.needChannelNumber = 1; + } + + List readerTaskConfigs = this + .doReaderSplit(this.needChannelNumber); + int taskNumber = readerTaskConfigs.size(); + List writerTaskConfigs = this + .doWriterSplit(taskNumber); + + /** + * 输入是reader和writer的parameter list,输出是content下面元素的list + */ + List contentConfig = mergeReaderAndWriterTaskConfigs( + readerTaskConfigs, writerTaskConfigs); + + this.configuration.set(CoreConstant.DATAX_JOB_CONTENT, contentConfig); + + return contentConfig.size(); + } + + private void adjustChannelNumber() { + int needChannelNumberByByte = Integer.MAX_VALUE; + int needChannelNumberByRecord = Integer.MAX_VALUE; + + boolean isByteLimit = (this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_BYTE, 0) > 0); + if (isByteLimit) { + long globalLimitedByteSpeed = this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_BYTE, 10 * 1024 * 1024); + + // 在byte流控情况下,单个Channel流量最大值必须设置,否则报错! + Long channelLimitedByteSpeed = this.configuration + .getLong(CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_SPEED_BYTE); + if (channelLimitedByteSpeed == null || channelLimitedByteSpeed <= 0) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, + "在有总bps限速条件下,单个channel的bps值不能为空,也不能为非正数"); + } + + needChannelNumberByByte = + (int) (globalLimitedByteSpeed / channelLimitedByteSpeed); + needChannelNumberByByte = + needChannelNumberByByte > 0 ? needChannelNumberByByte : 1; + LOG.info("Job set Max-Byte-Speed to " + globalLimitedByteSpeed + " bytes."); + } + + boolean isRecordLimit = (this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_RECORD, 0)) > 0; + if (isRecordLimit) { + long globalLimitedRecordSpeed = this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_RECORD, 100000); + + Long channelLimitedRecordSpeed = this.configuration.getLong( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_SPEED_RECORD); + if (channelLimitedRecordSpeed == null || channelLimitedRecordSpeed <= 0) { + throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, + "在有总tps限速条件下,单个channel的tps值不能为空,也不能为非正数"); + } + + needChannelNumberByRecord = + (int) (globalLimitedRecordSpeed / channelLimitedRecordSpeed); + needChannelNumberByRecord = + needChannelNumberByRecord > 0 ? needChannelNumberByRecord : 1; + LOG.info("Job set Max-Record-Speed to " + globalLimitedRecordSpeed + " records."); + } + + // 取较小值 + this.needChannelNumber = needChannelNumberByByte < needChannelNumberByRecord ? + needChannelNumberByByte : needChannelNumberByRecord; + + // 如果从byte或record上设置了needChannelNumber则退出 + if (this.needChannelNumber < Integer.MAX_VALUE) { + return; + } + + boolean isChannelLimit = (this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_CHANNEL, 0) > 0); + if (isChannelLimit) { + this.needChannelNumber = this.configuration.getInt( + CoreConstant.DATAX_JOB_SETTING_SPEED_CHANNEL); + + LOG.info("Job set Channel-Number to " + this.needChannelNumber + + " channels."); + + return; + } + + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, + "Job运行速度必须设置"); + } + + /** + * schedule首先完成的工作是把上一步reader和writer split的结果整合到具体taskGroupContainer中, + * 同时不同的执行模式调用不同的调度策略,将所有任务调度起来 + */ + private void schedule() { + /** + * 这里的全局speed和每个channel的速度设置为B/s + */ + int channelsPerTaskGroup = this.configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, 5); + int taskNumber = this.configuration.getList( + CoreConstant.DATAX_JOB_CONTENT).size(); + + this.needChannelNumber = Math.min(this.needChannelNumber, taskNumber); + + /** + * 通过获取配置信息得到每个taskGroup需要运行哪些tasks任务 + */ + + List taskGroupConfigs = JobAssignUtil.assignFairly(this.configuration, + this.needChannelNumber, channelsPerTaskGroup); + + LOG.info("Scheduler starts [{}] taskGroups.", taskGroupConfigs.size()); + + ExecuteMode executeMode = null; + AbstractScheduler scheduler; + try { + executeMode = ExecuteMode.STANDALONE; + scheduler = initStandaloneScheduler(this.configuration); + + //设置 executeMode + for (Configuration taskGroupConfig : taskGroupConfigs) { + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_MODE, executeMode.getValue()); + } + + LOG.info("Running by {} Mode.", executeMode); + + this.startTransferTimeStamp = System.currentTimeMillis(); + + scheduler.schedule(taskGroupConfigs); + + this.endTransferTimeStamp = System.currentTimeMillis(); + } catch (Exception e) { + LOG.error("运行scheduler 模式[{}]出错.", executeMode); + this.endTransferTimeStamp = System.currentTimeMillis(); + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } + + /** + * 检查任务执行情况 + */ + this.checkLimit(); + } + + private AbstractScheduler initStandaloneScheduler(Configuration configuration) { + AbstractContainerCommunicator containerCommunicator = new StandAloneJobContainerCommunicator(configuration); + super.setContainerCommunicator(containerCommunicator); + + return new StandAloneScheduler(containerCommunicator); + } + + private void post() { + this.postJobWriter(); + this.postJobReader(); + } + + private void destroy() { + if (this.jobWriter != null) { + this.jobWriter.destroy(); + this.jobWriter = null; + } + if (this.jobReader != null) { + this.jobReader.destroy(); + this.jobReader = null; + } + } + + private void logStatistics() { + long totalCosts = (this.endTimeStamp - this.startTimeStamp) / 1000; + long transferCosts = (this.endTransferTimeStamp - this.startTransferTimeStamp) / 1000; + if (0L == transferCosts) { + transferCosts = 1L; + } + + if (super.getContainerCommunicator() == null) { + return; + } + + Communication communication = super.getContainerCommunicator().collect(); + communication.setTimestamp(this.endTimeStamp); + + Communication tempComm = new Communication(); + tempComm.setTimestamp(this.startTransferTimeStamp); + + Communication reportCommunication = CommunicationTool.getReportCommunication(communication, tempComm, this.totalStage); + + // 字节速率 + long byteSpeedPerSecond = communication.getLongCounter(CommunicationTool.READ_SUCCEED_BYTES) + / transferCosts; + + long recordSpeedPerSecond = communication.getLongCounter(CommunicationTool.READ_SUCCEED_RECORDS) + / transferCosts; + + reportCommunication.setLongCounter(CommunicationTool.BYTE_SPEED, byteSpeedPerSecond); + reportCommunication.setLongCounter(CommunicationTool.RECORD_SPEED, recordSpeedPerSecond); + + super.getContainerCommunicator().report(reportCommunication); + + LOG.info(String.format( + "\n" + "%-26s: %-18s\n" + "%-26s: %-18s\n" + "%-26s: %19s\n" + + "%-26s: %19s\n" + "%-26s: %19s\n" + "%-26s: %19s\n" + + "%-26s: %19s\n", + "任务启动时刻", + dateFormat.format(startTimeStamp), + + "任务结束时刻", + dateFormat.format(endTimeStamp), + + "任务总计耗时", + String.valueOf(totalCosts) + "s", + "任务平均流量", + StrUtil.stringify(byteSpeedPerSecond) + + "/s", + "记录写入速度", + String.valueOf(recordSpeedPerSecond) + + "rec/s", "读出记录总数", + String.valueOf(CommunicationTool.getTotalReadRecords(communication)), + "读写失败总数", + String.valueOf(CommunicationTool.getTotalErrorRecords(communication)) + )); + + + } + + /** + * reader job的初始化,返回Reader.Job + */ + private Reader.Job initJobReader( + JobPluginCollector jobPluginCollector) { + this.readerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_READER_NAME); + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + + Reader.Job jobReader = (Reader.Job) LoadUtil.loadJobPlugin( + PluginType.READER, this.readerPluginName); + + // 设置reader的jobConfig + jobReader.setPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER)); + + // 设置reader的readerConfig + jobReader.setPeerPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_WRITER_PARAMETER)); + + jobReader.setJobPluginCollector(jobPluginCollector); + jobReader.init(); + + classLoaderSwapper.restoreCurrentThreadClassLoader(); + return jobReader; + } + + /** + * writer job的初始化,返回Writer.Job + */ + private Writer.Job initJobWriter( + JobPluginCollector jobPluginCollector) { + this.writerPluginName = this.configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_WRITER_NAME); + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + + Writer.Job jobWriter = (Writer.Job) LoadUtil.loadJobPlugin( + PluginType.WRITER, this.writerPluginName); + + // 设置writer的jobConfig + jobWriter.setPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_WRITER_PARAMETER)); + + // 设置reader的readerConfig + jobWriter.setPeerPluginJobConf(this.configuration.getConfiguration( + CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER)); + + jobWriter.setPeerPluginName(this.readerPluginName); + jobWriter.setJobPluginCollector(jobPluginCollector); + jobWriter.init(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + + return jobWriter; + } + + private void prepareJobReader() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + LOG.info(String.format("DataX Reader.Job [%s] do prepare work .", + this.readerPluginName)); + this.jobReader.prepare(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + private void prepareJobWriter() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + LOG.info(String.format("DataX Writer.Job [%s] do prepare work .", + this.writerPluginName)); + this.jobWriter.prepare(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + // TODO: 如果源头就是空数据 + private List doReaderSplit(int adviceNumber) { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + List readerSlicesConfigs = + this.jobReader.split(adviceNumber); + if (readerSlicesConfigs == null || readerSlicesConfigs.size() <= 0) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_SPLIT_ERROR, + "reader切分的task数目不能小于等于0"); + } + LOG.info("DataX Reader.Job [{}] splits to [{}] tasks.", + this.readerPluginName, readerSlicesConfigs.size()); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + return readerSlicesConfigs; + } + + private List doWriterSplit(int readerTaskNumber) { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + + List writerSlicesConfigs = this.jobWriter + .split(readerTaskNumber); + if (writerSlicesConfigs == null || writerSlicesConfigs.size() <= 0) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_SPLIT_ERROR, + "writer切分的task不能小于等于0"); + } + LOG.info("DataX Writer.Job [{}] splits to [{}] tasks.", + this.writerPluginName, writerSlicesConfigs.size()); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + + return writerSlicesConfigs; + } + + /** + * 按顺序整合reader和writer的配置,这里的顺序不能乱! 输入是reader、writer级别的配置,输出是一个完整task的配置 + */ + private List mergeReaderAndWriterTaskConfigs( + List readerTasksConfigs, + List writerTasksConfigs) { + if (readerTasksConfigs.size() != writerTasksConfigs.size()) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_SPLIT_ERROR, + String.format("reader切分的task数目[%d]不等于writer切分的task数目[%d].", + readerTasksConfigs.size(), writerTasksConfigs.size()) + ); + } + + List contentConfigs = new ArrayList(); + for (int i = 0; i < readerTasksConfigs.size(); i++) { + Configuration taskConfig = Configuration.newDefault(); + taskConfig.set(CoreConstant.JOB_READER_NAME, + this.readerPluginName); + taskConfig.set(CoreConstant.JOB_READER_PARAMETER, + readerTasksConfigs.get(i)); + taskConfig.set(CoreConstant.JOB_WRITER_NAME, + this.writerPluginName); + taskConfig.set(CoreConstant.JOB_WRITER_PARAMETER, + writerTasksConfigs.get(i)); + taskConfig.set(CoreConstant.TASK_ID, i); + contentConfigs.add(taskConfig); + } + + return contentConfigs; + } + + /** + * 这里比较复杂,分两步整合 1. tasks到channel 2. channel到taskGroup + * 合起来考虑,其实就是把tasks整合到taskGroup中,需要满足计算出的channel数,同时不能多起channel + *

+ * example: + *

+ * 前提条件: 切分后是1024个分表,假设用户要求总速率是1000M/s,每个channel的速率的3M/s, + * 每个taskGroup负责运行7个channel + *

+ * 计算: 总channel数为:1000M/s / 3M/s = + * 333个,为平均分配,计算可知有308个每个channel有3个tasks,而有25个每个channel有4个tasks, + * 需要的taskGroup数为:333 / 7 = + * 47...4,也就是需要48个taskGroup,47个是每个负责7个channel,有4个负责1个channel + *

+ * 处理:我们先将这负责4个channel的taskGroup处理掉,逻辑是: + * 先按平均为3个tasks找4个channel,设置taskGroupId为0, + * 接下来就像发牌一样轮询分配task到剩下的包含平均channel数的taskGroup中 + *

+ * TODO delete it + * + * @param averTaskPerChannel + * @param channelNumber + * @param channelsPerTaskGroup + * @return 每个taskGroup独立的全部配置 + */ + @SuppressWarnings("serial") + private List distributeTasksToTaskGroup( + int averTaskPerChannel, int channelNumber, + int channelsPerTaskGroup) { + Validate.isTrue(averTaskPerChannel > 0 && channelNumber > 0 + && channelsPerTaskGroup > 0, + "每个channel的平均task数[averTaskPerChannel],channel数目[channelNumber],每个taskGroup的平均channel数[channelsPerTaskGroup]都应该为正数"); + List taskConfigs = this.configuration + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + int taskGroupNumber = channelNumber / channelsPerTaskGroup; + int leftChannelNumber = channelNumber % channelsPerTaskGroup; + if (leftChannelNumber > 0) { + taskGroupNumber += 1; + } + + /** + * 如果只有一个taskGroup,直接打标返回 + */ + if (taskGroupNumber == 1) { + final Configuration taskGroupConfig = this.configuration.clone(); + /** + * configure的clone不能clone出 + */ + taskGroupConfig.set(CoreConstant.DATAX_JOB_CONTENT, this.configuration + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT)); + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, + channelNumber); + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 0); + return new ArrayList() { + { + add(taskGroupConfig); + } + }; + } + + List taskGroupConfigs = new ArrayList(); + /** + * 将每个taskGroup中content的配置清空 + */ + for (int i = 0; i < taskGroupNumber; i++) { + Configuration taskGroupConfig = this.configuration.clone(); + List taskGroupJobContent = taskGroupConfig + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + taskGroupJobContent.clear(); + taskGroupConfig.set(CoreConstant.DATAX_JOB_CONTENT, taskGroupJobContent); + + taskGroupConfigs.add(taskGroupConfig); + } + + int taskConfigIndex = 0; + int channelIndex = 0; + int taskGroupConfigIndex = 0; + + /** + * 先处理掉taskGroup包含channel数不是平均值的taskGroup + */ + if (leftChannelNumber > 0) { + Configuration taskGroupConfig = taskGroupConfigs.get(taskGroupConfigIndex); + for (; channelIndex < leftChannelNumber; channelIndex++) { + for (int i = 0; i < averTaskPerChannel; i++) { + List taskGroupJobContent = taskGroupConfig + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + taskGroupJobContent.add(taskConfigs.get(taskConfigIndex++)); + taskGroupConfig.set(CoreConstant.DATAX_JOB_CONTENT, + taskGroupJobContent); + } + } + + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, + leftChannelNumber); + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, + taskGroupConfigIndex++); + } + + /** + * 下面需要轮询分配,并打上channel数和taskGroupId标记 + */ + int equalDivisionStartIndex = taskGroupConfigIndex; + for (; taskConfigIndex < taskConfigs.size() + && equalDivisionStartIndex < taskGroupConfigs.size(); ) { + for (taskGroupConfigIndex = equalDivisionStartIndex; taskGroupConfigIndex < taskGroupConfigs + .size() && taskConfigIndex < taskConfigs.size(); taskGroupConfigIndex++) { + Configuration taskGroupConfig = taskGroupConfigs.get(taskGroupConfigIndex); + List taskGroupJobContent = taskGroupConfig + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + taskGroupJobContent.add(taskConfigs.get(taskConfigIndex++)); + taskGroupConfig.set( + CoreConstant.DATAX_JOB_CONTENT, taskGroupJobContent); + } + } + + for (taskGroupConfigIndex = equalDivisionStartIndex; + taskGroupConfigIndex < taskGroupConfigs.size(); ) { + Configuration taskGroupConfig = taskGroupConfigs.get(taskGroupConfigIndex); + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, + channelsPerTaskGroup); + taskGroupConfig.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, + taskGroupConfigIndex++); + } + + return taskGroupConfigs; + } + + private void postJobReader() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.readerPluginName)); + LOG.info("DataX Reader.Job [{}] do post work.", + this.readerPluginName); + this.jobReader.post(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + private void postJobWriter() { + classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.writerPluginName)); + LOG.info("DataX Writer.Job [{}] do post work.", + this.writerPluginName); + this.jobWriter.post(); + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + + /** + * 检查最终结果是否超出阈值,如果阈值设定小于1,则表示百分数阈值,大于1表示条数阈值。 + * + * @param + */ + private void checkLimit() { + Communication communication = super.getContainerCommunicator().collect(); + errorLimit.checkRecordLimit(communication); + errorLimit.checkPercentageLimit(communication); + } + + /** + * 调用外部hook + */ + private void invokeHooks() { + Communication comm = super.getContainerCommunicator().collect(); + HookInvoker invoker = new HookInvoker(CoreConstant.DATAX_HOME + "/hook", configuration, comm.getCounter()); + invoker.invokeAll(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/meta/ExecuteMode.java b/core/src/main/java/com/alibaba/datax/core/job/meta/ExecuteMode.java new file mode 100644 index 000000000..956f9c4b2 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/meta/ExecuteMode.java @@ -0,0 +1,22 @@ +package com.alibaba.datax.core.job.meta; + +/** + * Created by liupeng on 15/12/21. + */ +public enum ExecuteMode { + STANDALONE("standalone"), ; + + String value; + + private ExecuteMode(String value) { + this.value = value; + } + + public String value() { + return this.value; + } + + public String getValue() { + return this.value; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/meta/State.java b/core/src/main/java/com/alibaba/datax/core/job/meta/State.java new file mode 100644 index 000000000..2a1dd227e --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/meta/State.java @@ -0,0 +1,32 @@ +package com.alibaba.datax.core.job.meta; + +/** + * Created by liupeng on 15/12/21. + */ +public enum State { + SUBMITTING(10), + WAITING(20), + RUNNING(30), + KILLING(40), + KILLED(50), + FAILED(60), + SUCCEEDED(70), ; + + int value; + + private State(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + public boolean isFinished() { + return this == KILLED || this == FAILED || this == SUCCEEDED; + } + + public boolean isRunning() { + return !this.isFinished(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/scheduler/AbstractScheduler.java b/core/src/main/java/com/alibaba/datax/core/job/scheduler/AbstractScheduler.java new file mode 100755 index 000000000..3dbc8f696 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/scheduler/AbstractScheduler.java @@ -0,0 +1,135 @@ +package com.alibaba.datax.core.job.scheduler; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.util.ErrorRecordChecker; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public abstract class AbstractScheduler { + private static final Logger LOG = LoggerFactory + .getLogger(AbstractScheduler.class); + + private ErrorRecordChecker errorLimit; + + private AbstractContainerCommunicator containerCommunicator; + + private Long jobId; + + public Long getJobId() { + return jobId; + } + + public AbstractScheduler(AbstractContainerCommunicator containerCommunicator) { + this.containerCommunicator = containerCommunicator; + } + + public void schedule(List configurations) { + Validate.notNull(configurations, + "scheduler配置不能为空"); + int jobReportIntervalInMillSec = configurations.get(0).getInt( + CoreConstant.DATAX_CORE_CONTAINER_JOB_REPORTINTERVAL, 30000); + int jobSleepIntervalInMillSec = configurations.get(0).getInt( + CoreConstant.DATAX_CORE_CONTAINER_JOB_SLEEPINTERVAL, 10000); + + this.jobId = configurations.get(0).getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID); + + errorLimit = new ErrorRecordChecker(configurations.get(0)); + + /** + * 给 taskGroupContainer 的 Communication 注册 + */ + this.containerCommunicator.registerCommunication(configurations); + + int totalTasks = calculateTaskCount(configurations); + startAllTaskGroup(configurations); + + Communication lastJobContainerCommunication = new Communication(); + + long lastReportTimeStamp = System.currentTimeMillis(); + try { + while (true) { + /** + * step 1: collect job stat + * step 2: getReport info, then report it + * step 3: errorLimit do check + * step 4: dealSucceedStat(); + * step 5: dealKillingStat(); + * step 6: dealFailedStat(); + * step 7: refresh last job stat, and then sleep for next while + * + * above steps, some ones should report info to DS + * + */ + Communication nowJobContainerCommunication = this.containerCommunicator.collect(); + nowJobContainerCommunication.setTimestamp(System.currentTimeMillis()); + LOG.debug(nowJobContainerCommunication.toString()); + + //汇报周期 + long now = System.currentTimeMillis(); + if (now - lastReportTimeStamp > jobReportIntervalInMillSec) { + Communication reportCommunication = CommunicationTool + .getReportCommunication(nowJobContainerCommunication, lastJobContainerCommunication, totalTasks); + + this.containerCommunicator.report(reportCommunication); + lastReportTimeStamp = now; + lastJobContainerCommunication = nowJobContainerCommunication; + } + + errorLimit.checkRecordLimit(nowJobContainerCommunication); + + if (nowJobContainerCommunication.getState() == State.SUCCEEDED) { + LOG.info("Scheduler accomplished all tasks."); + break; + } + + if (isJobKilling(this.getJobId())) { + dealKillingStat(this.containerCommunicator, totalTasks); + } else if (nowJobContainerCommunication.getState() == State.FAILED) { + dealFailedStat(this.containerCommunicator, nowJobContainerCommunication.getThrowable()); + } + + Thread.sleep(jobSleepIntervalInMillSec); + } + } catch (InterruptedException e) { + // 以 failed 状态退出 + LOG.error("捕获到InterruptedException异常!", e); + + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } + + } + + protected abstract void startAllTaskGroup(List configurations); + + protected abstract void dealFailedStat(AbstractContainerCommunicator frameworkCollector, Throwable throwable); + + protected abstract void dealKillingStat(AbstractContainerCommunicator frameworkCollector, int totalTasks); + + private int calculateTaskCount(List configurations) { + int totalTasks = 0; + for (Configuration taskGroupConfiguration : configurations) { + totalTasks += taskGroupConfiguration.getListConfiguration( + CoreConstant.DATAX_JOB_CONTENT).size(); + } + return totalTasks; + } + +// private boolean isJobKilling(Long jobId) { +// Result jobInfo = DataxServiceUtil.getJobInfo(jobId); +// return jobInfo.getData() == State.KILLING.value(); +// } + + protected abstract boolean isJobKilling(Long jobId); +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/ProcessInnerScheduler.java b/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/ProcessInnerScheduler.java new file mode 100755 index 000000000..2bc6e64c9 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/ProcessInnerScheduler.java @@ -0,0 +1,60 @@ +package com.alibaba.datax.core.job.scheduler.processinner; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.scheduler.AbstractScheduler; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.taskgroup.TaskGroupContainer; +import com.alibaba.datax.core.taskgroup.runner.TaskGroupContainerRunner; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public abstract class ProcessInnerScheduler extends AbstractScheduler { + + private ExecutorService taskGroupContainerExecutorService; + + public ProcessInnerScheduler(AbstractContainerCommunicator containerCommunicator) { + super(containerCommunicator); + } + + @Override + public void startAllTaskGroup(List configurations) { + this.taskGroupContainerExecutorService = Executors + .newFixedThreadPool(configurations.size()); + + for (Configuration taskGroupConfiguration : configurations) { + TaskGroupContainerRunner taskGroupContainerRunner = newTaskGroupContainerRunner(taskGroupConfiguration); + this.taskGroupContainerExecutorService.execute(taskGroupContainerRunner); + } + + this.taskGroupContainerExecutorService.shutdown(); + } + + @Override + public void dealFailedStat(AbstractContainerCommunicator frameworkCollector, Throwable throwable) { + this.taskGroupContainerExecutorService.shutdownNow(); + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_RUNTIME_ERROR, throwable); + } + + + @Override + public void dealKillingStat(AbstractContainerCommunicator frameworkCollector, int totalTasks) { + //通过进程退出返回码标示状态 + this.taskGroupContainerExecutorService.shutdownNow(); + throw DataXException.asDataXException(FrameworkErrorCode.KILLED_EXIT_VALUE, + "job killed status"); + } + + + private TaskGroupContainerRunner newTaskGroupContainerRunner( + Configuration configuration) { + TaskGroupContainer taskGroupContainer = new TaskGroupContainer(configuration); + + return new TaskGroupContainerRunner(taskGroupContainer); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/StandAloneScheduler.java b/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/StandAloneScheduler.java new file mode 100755 index 000000000..d87421b7a --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/job/scheduler/processinner/StandAloneScheduler.java @@ -0,0 +1,19 @@ +package com.alibaba.datax.core.job.scheduler.processinner; + +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; + +/** + * Created by hongjiao.hj on 2014/12/22. + */ +public class StandAloneScheduler extends ProcessInnerScheduler{ + + public StandAloneScheduler(AbstractContainerCommunicator containerCommunicator) { + super(containerCommunicator); + } + + @Override + protected boolean isJobKilling(Long jobId) { + return false; + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/communication/Communication.java b/core/src/main/java/com/alibaba/datax/core/statistics/communication/Communication.java new file mode 100755 index 000000000..2a93a80bb --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/communication/Communication.java @@ -0,0 +1,281 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.common.base.BaseObject; +import com.alibaba.datax.core.job.meta.State; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +/** + * DataX所有的状态及统计信息交互类,job、taskGroup、task等的消息汇报都走该类 + */ +public class Communication extends BaseObject implements Cloneable { + /** + * 所有的数值key-value对 * + */ + private Map counter; + + /** + * 运行状态 * + */ + private State state; + + /** + * 异常记录 * + */ + private Throwable throwable; + + /** + * 记录的timestamp * + */ + private long timestamp; + + /** + * task给job的信息 * + */ + Map> message; + + public Communication() { + this.init(); + } + + public synchronized void reset() { + this.init(); + } + + private void init() { + this.counter = new ConcurrentHashMap(); + this.state = State.RUNNING; + this.throwable = null; + this.message = new ConcurrentHashMap>(); + this.timestamp = System.currentTimeMillis(); + } + + public Map getCounter() { + return this.counter; + } + + public State getState() { + return this.state; + } + + public synchronized void setState(State state, boolean isForce) { + if (!isForce && this.state.equals(State.FAILED)) { + return; + } + + this.state = state; + } + + public synchronized void setState(State state) { + setState(state, false); + } + + public Throwable getThrowable() { + return this.throwable; + } + + public synchronized String getThrowableMessage() { + return this.throwable == null ? "" : this.throwable.getMessage(); + } + + public void setThrowable(Throwable throwable) { + setThrowable(throwable, false); + } + + public synchronized void setThrowable(Throwable throwable, boolean isForce) { + if (isForce) { + this.throwable = throwable; + } else { + this.throwable = this.throwable == null ? throwable : this.throwable; + } + } + + public long getTimestamp() { + return this.timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public Map> getMessage() { + return this.message; + } + + public List getMessage(final String key) { + return message.get(key); + } + + public synchronized void addMessage(final String key, final String value) { + Validate.isTrue(StringUtils.isNotBlank(key), "增加message的key不能为空"); + List valueList = this.message.get(key); + if (null == valueList) { + valueList = new ArrayList(); + this.message.put(key, valueList); + } + + valueList.add(value); + } + + public synchronized Long getLongCounter(final String key) { + Number value = this.counter.get(key); + + return value == null ? 0 : value.longValue(); + } + + public synchronized void setLongCounter(final String key, final long value) { + Validate.isTrue(StringUtils.isNotBlank(key), "设置counter的key不能为空"); + this.counter.put(key, value); + } + + public synchronized Double getDoubleCounter(final String key) { + Number value = this.counter.get(key); + + return value == null ? 0.0d : value.doubleValue(); + } + + public synchronized void setDoubleCounter(final String key, final double value) { + Validate.isTrue(StringUtils.isNotBlank(key), "设置counter的key不能为空"); + this.counter.put(key, value); + } + + public synchronized void increaseCounter(final String key, final long deltaValue) { + Validate.isTrue(StringUtils.isNotBlank(key), "增加counter的key不能为空"); + + long value = this.getLongCounter(key); + + this.counter.put(key, value + deltaValue); + } + + @Override + public Communication clone() { + Communication communication = new Communication(); + + /** + * clone counter + */ + if (this.counter != null) { + for (Map.Entry entry : this.counter.entrySet()) { + String key = entry.getKey(); + Number value = entry.getValue(); + if (value instanceof Long) { + communication.setLongCounter(key, (Long) value); + } else if (value instanceof Double) { + communication.setDoubleCounter(key, (Double) value); + } + } + } + + communication.setState(this.state, true); + communication.setThrowable(this.throwable, true); + communication.setTimestamp(this.timestamp); + + /** + * clone message + */ + if (this.message != null) { + for (final Map.Entry> entry : this.message.entrySet()) { + String key = entry.getKey(); + List value = new ArrayList() {{ + addAll(entry.getValue()); + }}; + communication.getMessage().put(key, value); + } + } + + return communication; + } + + public synchronized Communication mergeFrom(final Communication otherComm) { + if (otherComm == null) { + return this; + } + + /** + * counter的合并,将otherComm的值累加到this中,不存在的则创建 + * 同为long + */ + for (Entry entry : otherComm.getCounter().entrySet()) { + String key = entry.getKey(); + Number otherValue = entry.getValue(); + if (otherValue == null) { + continue; + } + + Number value = this.counter.get(key); + if (value == null) { + value = otherValue; + } else { + if (value instanceof Long && otherValue instanceof Long) { + value = value.longValue() + otherValue.longValue(); + } else { + value = value.doubleValue() + value.doubleValue(); + } + } + + this.counter.put(key, value); + } + + // 合并state + mergeStateFrom(otherComm); + + /** + * 合并throwable,当this的throwable为空时, + * 才将otherComm的throwable合并进来 + */ + this.throwable = this.throwable == null ? otherComm.getThrowable() : this.throwable; + + /** + * timestamp是整个一次合并的时间戳,单独两两communication不作合并 + */ + + /** + * message的合并采取求并的方式,即全部累计在一起 + */ + for (Entry> entry : otherComm.getMessage().entrySet()) { + String key = entry.getKey(); + List valueList = this.message.get(key); + if (valueList == null) { + valueList = new ArrayList(); + this.message.put(key, valueList); + } + + valueList.addAll(entry.getValue()); + } + + return this; + } + + /** + * 合并state,优先级: (Failed | Killed) > Running > Success + * 这里不会出现 Killing 状态,killing 状态只在 Job 自身状态上才有. + */ + public synchronized State mergeStateFrom(final Communication otherComm) { + State retState = this.getState(); + if (otherComm == null) { + return retState; + } + + if (this.state == State.FAILED || otherComm.getState() == State.FAILED + || this.state == State.KILLED || otherComm.getState() == State.KILLED) { + retState = State.FAILED; + } else if (this.state.isRunning() || otherComm.state.isRunning()) { + retState = State.RUNNING; + } + + this.setState(retState); + return retState; + } + + public synchronized boolean isFinished(){ + return this.state == State.SUCCEEDED || this.state == State.FAILED + || this.state == State.KILLED; + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/communication/CommunicationTool.java b/core/src/main/java/com/alibaba/datax/core/statistics/communication/CommunicationTool.java new file mode 100755 index 000000000..c7e0d0539 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/communication/CommunicationTool.java @@ -0,0 +1,261 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.common.statistics.PerfTrace; +import com.alibaba.datax.common.util.StrUtil; +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang.Validate; + +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * 这里主要是业务层面的处理 + */ +public final class CommunicationTool { + public static final String STAGE = "stage"; + public static final String BYTE_SPEED = "byteSpeed"; + public static final String RECORD_SPEED = "recordSpeed"; + public static final String PERCENTAGE = "percentage"; + + public static final String READ_SUCCEED_RECORDS = "readSucceedRecords"; + public static final String READ_SUCCEED_BYTES = "readSucceedBytes"; + + public static final String READ_FAILED_RECORDS = "readFailedRecords"; + public static final String READ_FAILED_BYTES = "readFailedBytes"; + + public static final String WRITE_RECEIVED_RECORDS = "writeReceivedRecords"; + public static final String WRITE_RECEIVED_BYTES = "writeReceivedBytes"; + + public static final String WRITE_FAILED_RECORDS = "writeFailedRecords"; + public static final String WRITE_FAILED_BYTES = "writeFailedBytes"; + + private static final String TOTAL_READ_RECORDS = "totalReadRecords"; + private static final String TOTAL_READ_BYTES = "totalReadBytes"; + + private static final String TOTAL_ERROR_RECORDS = "totalErrorRecords"; + private static final String TOTAL_ERROR_BYTES = "totalErrorBytes"; + + private static final String WRITE_SUCCEED_RECORDS = "writeSucceedRecords"; + private static final String WRITE_SUCCEED_BYTES = "writeSucceedBytes"; + + public static final String WAIT_WRITER_TIME = "waitWriterTime"; + + public static final String WAIT_READER_TIME = "waitReaderTime"; + + public static Communication getReportCommunication(Communication now, Communication old, int totalStage) { + Validate.isTrue(now != null && old != null, + "为汇报准备的新旧metric不能为null"); + + long totalReadRecords = getTotalReadRecords(now); + long totalReadBytes = getTotalReadBytes(now); + now.setLongCounter(TOTAL_READ_RECORDS, totalReadRecords); + now.setLongCounter(TOTAL_READ_BYTES, totalReadBytes); + now.setLongCounter(TOTAL_ERROR_RECORDS, getTotalErrorRecords(now)); + now.setLongCounter(TOTAL_ERROR_BYTES, getTotalErrorBytes(now)); + now.setLongCounter(WRITE_SUCCEED_RECORDS, getWriteSucceedRecords(now)); + now.setLongCounter(WRITE_SUCCEED_BYTES, getWriteSucceedBytes(now)); + + long timeInterval = now.getTimestamp() - old.getTimestamp(); + long sec = timeInterval <= 1000 ? 1 : timeInterval / 1000; + long bytesSpeed = (totalReadBytes + - getTotalReadBytes(old)) / sec; + long recordsSpeed = (totalReadRecords + - getTotalReadRecords(old)) / sec; + + now.setLongCounter(BYTE_SPEED, bytesSpeed < 0 ? 0 : bytesSpeed); + now.setLongCounter(RECORD_SPEED, recordsSpeed < 0 ? 0 : recordsSpeed); + now.setDoubleCounter(PERCENTAGE, now.getLongCounter(STAGE) / (double) totalStage); + + if (old.getThrowable() != null) { + now.setThrowable(old.getThrowable()); + } + + return now; + } + + public static long getTotalReadRecords(final Communication communication) { + return communication.getLongCounter(READ_SUCCEED_RECORDS) + + communication.getLongCounter(READ_FAILED_RECORDS); + } + + public static long getTotalReadBytes(final Communication communication) { + return communication.getLongCounter(READ_SUCCEED_BYTES) + + communication.getLongCounter(READ_FAILED_BYTES); + } + + public static long getTotalErrorRecords(final Communication communication) { + return communication.getLongCounter(READ_FAILED_RECORDS) + + communication.getLongCounter(WRITE_FAILED_RECORDS); + } + + public static long getTotalErrorBytes(final Communication communication) { + return communication.getLongCounter(READ_FAILED_BYTES) + + communication.getLongCounter(WRITE_FAILED_BYTES); + } + + public static long getWriteSucceedRecords(final Communication communication) { + return communication.getLongCounter(WRITE_RECEIVED_RECORDS) - + communication.getLongCounter(WRITE_FAILED_RECORDS); + } + + public static long getWriteSucceedBytes(final Communication communication) { + return communication.getLongCounter(WRITE_RECEIVED_BYTES) - + communication.getLongCounter(WRITE_FAILED_BYTES); + } + + public static class Stringify { + private final static DecimalFormat df = new DecimalFormat("0.00"); + + public static String getSnapshot(final Communication communication) { + StringBuilder sb = new StringBuilder(); + sb.append("Total "); + sb.append(getTotal(communication)); + sb.append(" | "); + sb.append("Speed "); + sb.append(getSpeed(communication)); + sb.append(" | "); + sb.append("Error "); + sb.append(getError(communication)); + sb.append(" | "); + sb.append(" All Task WaitWriterTime "); + sb.append(PerfTrace.unitTime(communication.getLongCounter(WAIT_WRITER_TIME))); + sb.append(" | "); + sb.append(" All Task WaitReaderTime "); + sb.append(PerfTrace.unitTime(communication.getLongCounter(WAIT_READER_TIME))); + sb.append(" | "); + sb.append("Percentage "); + sb.append(getPercentage(communication)); + return sb.toString(); + } + + private static String getTotal(final Communication communication) { + return String.format("%d records, %d bytes", + communication.getLongCounter(TOTAL_READ_RECORDS), + communication.getLongCounter(TOTAL_READ_BYTES)); + } + + private static String getSpeed(final Communication communication) { + return String.format("%s/s, %d records/s", + StrUtil.stringify(communication.getLongCounter(BYTE_SPEED)), + communication.getLongCounter(RECORD_SPEED)); + } + + private static String getError(final Communication communication) { + return String.format("%d records, %d bytes", + communication.getLongCounter(TOTAL_ERROR_RECORDS), + communication.getLongCounter(TOTAL_ERROR_BYTES)); + } + + private static String getPercentage(final Communication communication) { + return df.format(communication.getDoubleCounter(PERCENTAGE) * 100) + "%"; + } + } + + public static class Jsonify { + @SuppressWarnings("rawtypes") + public static String getSnapshot(Communication communication) { + Validate.notNull(communication); + + Map state = new HashMap(); + + Pair pair = getTotalBytes(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getTotalRecords(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getSpeedRecord(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getSpeedByte(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getStage(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getErrorRecords(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getErrorBytes(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getErrorMessage(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getPercentage(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getWaitReaderTime(communication); + state.put((String) pair.getKey(), pair.getValue()); + + pair = getWaitWriterTime(communication); + state.put((String) pair.getKey(), pair.getValue()); + + return JSON.toJSONString(state); + } + + private static Pair getTotalBytes(final Communication communication) { + return new Pair("totalBytes", communication.getLongCounter(TOTAL_READ_BYTES)); + } + + private static Pair getTotalRecords(final Communication communication) { + return new Pair("totalRecords", communication.getLongCounter(TOTAL_READ_RECORDS)); + } + + private static Pair getSpeedByte(final Communication communication) { + return new Pair("speedBytes", communication.getLongCounter(BYTE_SPEED)); + } + + private static Pair getSpeedRecord(final Communication communication) { + return new Pair("speedRecords", communication.getLongCounter(RECORD_SPEED)); + } + + private static Pair getErrorRecords(final Communication communication) { + return new Pair("errorRecords", communication.getLongCounter(TOTAL_ERROR_RECORDS)); + } + + private static Pair getErrorBytes(final Communication communication) { + return new Pair("errorBytes", communication.getLongCounter(TOTAL_ERROR_BYTES)); + } + + private static Pair getStage(final Communication communication) { + return new Pair("stage", communication.getLongCounter(STAGE)); + } + + private static Pair getPercentage(final Communication communication) { + return new Pair("percentage", communication.getDoubleCounter(PERCENTAGE)); + } + + private static Pair getErrorMessage(final Communication communication) { + return new Pair("errorMessage", communication.getThrowableMessage()); + } + + private static Pair getWaitReaderTime(final Communication communication) { + return new Pair("waitReaderTime", communication.getLongCounter(CommunicationTool.WAIT_READER_TIME)); + } + + private static Pair getWaitWriterTime(final Communication communication) { + return new Pair("waitWriterTime", communication.getLongCounter(CommunicationTool.WAIT_WRITER_TIME)); + } + + static class Pair { + public Pair(final K key, final V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + private K key; + + private V value; + } + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/communication/LocalTGCommunicationManager.java b/core/src/main/java/com/alibaba/datax/core/statistics/communication/LocalTGCommunicationManager.java new file mode 100755 index 000000000..163262f66 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/communication/LocalTGCommunicationManager.java @@ -0,0 +1,62 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.core.job.meta.State; +import org.apache.commons.lang3.Validate; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public final class LocalTGCommunicationManager { + private static Map taskGroupCommunicationMap = + new ConcurrentHashMap(); + + public static void registerTaskGroupCommunication( + int taskGroupId, Communication communication) { + taskGroupCommunicationMap.put(taskGroupId, communication); + } + + public static Communication getJobCommunication() { + Communication communication = new Communication(); + communication.setState(State.SUCCEEDED); + + for (Communication taskGroupCommunication : + taskGroupCommunicationMap.values()) { + communication.mergeFrom(taskGroupCommunication); + } + + return communication; + } + + /** + * 采用获取taskGroupId后再获取对应communication的方式, + * 防止map遍历时修改,同时也防止对map key-value对的修改 + * + * @return + */ + public static Set getTaskGroupIdSet() { + return taskGroupCommunicationMap.keySet(); + } + + public static Communication getTaskGroupCommunication(int taskGroupId) { + Validate.isTrue(taskGroupId >= 0, "taskGroupId不能小于0"); + + return taskGroupCommunicationMap.get(taskGroupId); + } + + public static void updateTaskGroupCommunication(final int taskGroupId, + final Communication communication) { + Validate.isTrue(taskGroupCommunicationMap.containsKey( + taskGroupId), String.format("taskGroupCommunicationMap中没有注册taskGroupId[%d]的Communication," + + "无法更新该taskGroup的信息", taskGroupId)); + taskGroupCommunicationMap.put(taskGroupId, communication); + } + + public static void clear() { + taskGroupCommunicationMap.clear(); + } + + public static Map getTaskGroupCommunicationMap() { + return taskGroupCommunicationMap; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/AbstractCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/AbstractCollector.java new file mode 100755 index 000000000..a3d18a4a7 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/AbstractCollector.java @@ -0,0 +1,69 @@ +package com.alibaba.datax.core.statistics.container.collector; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; +import com.alibaba.datax.core.util.container.CoreConstant; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class AbstractCollector { + private Map taskCommunicationMap = new ConcurrentHashMap(); + private Long jobId; + + public Map getTaskCommunicationMap() { + return taskCommunicationMap; + } + + public Long getJobId() { + return jobId; + } + + public void setJobId(Long jobId) { + this.jobId = jobId; + } + + public void registerTGCommunication(List taskGroupConfigurationList) { + for (Configuration config : taskGroupConfigurationList) { + int taskGroupId = config.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID); + LocalTGCommunicationManager.registerTaskGroupCommunication(taskGroupId, new Communication()); + } + } + + public void registerTaskCommunication(List taskConfigurationList) { + for (Configuration taskConfig : taskConfigurationList) { + int taskId = taskConfig.getInt(CoreConstant.TASK_ID); + this.taskCommunicationMap.put(taskId, new Communication()); + } + } + + public Communication collectFromTask() { + Communication communication = new Communication(); + communication.setState(State.SUCCEEDED); + + for (Communication taskCommunication : + this.taskCommunicationMap.values()) { + communication.mergeFrom(taskCommunication); + } + + return communication; + } + + public abstract Communication collectFromTaskGroup(); + + public Map getTGCommunicationMap() { + return LocalTGCommunicationManager.getTaskGroupCommunicationMap(); + } + + public Communication getTGCommunication(Integer taskGroupId) { + return LocalTGCommunicationManager.getTaskGroupCommunication(taskGroupId); + } + + public Communication getTaskCommunication(Integer taskId) { + return this.taskCommunicationMap.get(taskId); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/ProcessInnerCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/ProcessInnerCollector.java new file mode 100755 index 000000000..530794b56 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/collector/ProcessInnerCollector.java @@ -0,0 +1,17 @@ +package com.alibaba.datax.core.statistics.container.collector; + +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; + +public class ProcessInnerCollector extends AbstractCollector { + + public ProcessInnerCollector(Long jobId) { + super.setJobId(jobId); + } + + @Override + public Communication collectFromTaskGroup() { + return LocalTGCommunicationManager.getJobCommunication(); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/AbstractContainerCommunicator.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/AbstractContainerCommunicator.java new file mode 100755 index 000000000..b7b159f6f --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/AbstractContainerCommunicator.java @@ -0,0 +1,88 @@ +package com.alibaba.datax.core.statistics.container.communicator; + + +import com.alibaba.datax.common.statistics.VMInfo; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.container.collector.AbstractCollector; +import com.alibaba.datax.core.statistics.container.report.AbstractReporter; +import com.alibaba.datax.core.util.container.CoreConstant; + +import java.util.List; +import java.util.Map; + +public abstract class AbstractContainerCommunicator { + private Configuration configuration; + private AbstractCollector collector; + private AbstractReporter reporter; + + private Long jobId; + + private VMInfo vmInfo = VMInfo.getVmInfo(); + private long lastReportTime = System.currentTimeMillis(); + + + public Configuration getConfiguration() { + return this.configuration; + } + + public AbstractCollector getCollector() { + return collector; + } + + public AbstractReporter getReporter() { + return reporter; + } + + public void setCollector(AbstractCollector collector) { + this.collector = collector; + } + + public void setReporter(AbstractReporter reporter) { + this.reporter = reporter; + } + + public Long getJobId() { + return jobId; + } + + public AbstractContainerCommunicator(Configuration configuration) { + this.configuration = configuration; + this.jobId = configuration.getLong(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID); + } + + + public abstract void registerCommunication(List configurationList); + + public abstract Communication collect(); + + public abstract void report(Communication communication); + + public abstract State collectState(); + + public abstract Communication getCommunication(Integer id); + + /** + * 当 实现是 TGContainerCommunicator 时,返回的 Map: key=taskId, value=Communication + * 当 实现是 JobContainerCommunicator 时,返回的 Map: key=taskGroupId, value=Communication + */ + public abstract Map getCommunicationMap(); + + public void resetCommunication(Integer id){ + Map map = getCommunicationMap(); + map.put(id, new Communication()); + } + + public void reportVmInfo(){ + long now = System.currentTimeMillis(); + //每5分钟打印一次 + if(now - lastReportTime >= 300000) { + //当前仅打印 + if (vmInfo != null) { + vmInfo.getDelta(true); + } + lastReportTime = now; + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/job/StandAloneJobContainerCommunicator.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/job/StandAloneJobContainerCommunicator.java new file mode 100755 index 000000000..1bce7318d --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/job/StandAloneJobContainerCommunicator.java @@ -0,0 +1,63 @@ +package com.alibaba.datax.core.statistics.container.communicator.job; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.statistics.container.collector.ProcessInnerCollector; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.statistics.container.report.ProcessInnerReporter; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; + +public class StandAloneJobContainerCommunicator extends AbstractContainerCommunicator { + private static final Logger LOG = LoggerFactory + .getLogger(StandAloneJobContainerCommunicator.class); + + public StandAloneJobContainerCommunicator(Configuration configuration) { + super(configuration); + super.setCollector(new ProcessInnerCollector(configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID))); + super.setReporter(new ProcessInnerReporter()); + } + + @Override + public void registerCommunication(List configurationList) { + super.getCollector().registerTGCommunication(configurationList); + } + + @Override + public Communication collect() { + return super.getCollector().collectFromTaskGroup(); + } + + @Override + public State collectState() { + return this.collect().getState(); + } + + /** + * 和 DistributeJobContainerCollector 的 report 实现一样 + */ + @Override + public void report(Communication communication) { + super.getReporter().reportJobCommunication(super.getJobId(), communication); + + LOG.info(CommunicationTool.Stringify.getSnapshot(communication)); + reportVmInfo(); + } + + @Override + public Communication getCommunication(Integer taskGroupId) { + return super.getCollector().getTGCommunication(taskGroupId); + } + + @Override + public Map getCommunicationMap() { + return super.getCollector().getTGCommunicationMap(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/AbstractTGContainerCommunicator.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/AbstractTGContainerCommunicator.java new file mode 100755 index 000000000..fbb5b6d88 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/AbstractTGContainerCommunicator.java @@ -0,0 +1,74 @@ +package com.alibaba.datax.core.statistics.container.communicator.taskgroup; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.container.collector.ProcessInnerCollector; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.Validate; + +import java.util.List; +import java.util.Map; + +/** + * 该类是用于处理 taskGroupContainer 的 communication 的收集汇报的父类 + * 主要是 taskCommunicationMap 记录了 taskExecutor 的 communication 属性 + */ +public abstract class AbstractTGContainerCommunicator extends AbstractContainerCommunicator { + + protected long jobId; + + /** + * 由于taskGroupContainer是进程内部调度 + * 其registerCommunication(),getCommunication(), + * getCommunications(),collect()等方法是一致的 + * 所有TG的Collector都是ProcessInnerCollector + */ + protected int taskGroupId; + + public AbstractTGContainerCommunicator(Configuration configuration) { + super(configuration); + this.jobId = configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID); + super.setCollector(new ProcessInnerCollector(this.jobId)); + this.taskGroupId = configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID); + } + + @Override + public void registerCommunication(List configurationList) { + super.getCollector().registerTaskCommunication(configurationList); + } + + @Override + public final Communication collect() { + return this.getCollector().collectFromTask(); + } + + @Override + public final State collectState() { + Communication communication = new Communication(); + communication.setState(State.SUCCEEDED); + + for (Communication taskCommunication : + super.getCollector().getTaskCommunicationMap().values()) { + communication.mergeStateFrom(taskCommunication); + } + + return communication.getState(); + } + + @Override + public final Communication getCommunication(Integer taskId) { + Validate.isTrue(taskId >= 0, "注册的taskId不能小于0"); + + return super.getCollector().getTaskCommunication(taskId); + } + + @Override + public final Map getCommunicationMap() { + return super.getCollector().getTaskCommunicationMap(); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/StandaloneTGContainerCommunicator.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/StandaloneTGContainerCommunicator.java new file mode 100755 index 000000000..7852154df --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/communicator/taskgroup/StandaloneTGContainerCommunicator.java @@ -0,0 +1,19 @@ +package com.alibaba.datax.core.statistics.container.communicator.taskgroup; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.container.report.ProcessInnerReporter; +import com.alibaba.datax.core.statistics.communication.Communication; + +public class StandaloneTGContainerCommunicator extends AbstractTGContainerCommunicator { + + public StandaloneTGContainerCommunicator(Configuration configuration) { + super(configuration); + super.setReporter(new ProcessInnerReporter()); + } + + @Override + public void report(Communication communication) { + super.getReporter().reportTGCommunication(super.taskGroupId, communication); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/report/AbstractReporter.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/report/AbstractReporter.java new file mode 100755 index 000000000..57f98587a --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/report/AbstractReporter.java @@ -0,0 +1,11 @@ +package com.alibaba.datax.core.statistics.container.report; + +import com.alibaba.datax.core.statistics.communication.Communication; + +public abstract class AbstractReporter { + + public abstract void reportJobCommunication(Long jobId, Communication communication); + + public abstract void reportTGCommunication(Integer taskGroupId, Communication communication); + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/container/report/ProcessInnerReporter.java b/core/src/main/java/com/alibaba/datax/core/statistics/container/report/ProcessInnerReporter.java new file mode 100755 index 000000000..15cdccc98 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/container/report/ProcessInnerReporter.java @@ -0,0 +1,17 @@ +package com.alibaba.datax.core.statistics.container.report; + +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; + +public class ProcessInnerReporter extends AbstractReporter { + + @Override + public void reportJobCommunication(Long jobId, Communication communication) { + // do nothing + } + + @Override + public void reportTGCommunication(Integer taskGroupId, Communication communication) { + LocalTGCommunicationManager.updateTaskGroupCommunication(taskGroupId, communication); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/plugin/DefaultJobPluginCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/DefaultJobPluginCollector.java new file mode 100755 index 000000000..a9571bd44 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/DefaultJobPluginCollector.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.core.statistics.plugin; + +import com.alibaba.datax.common.plugin.JobPluginCollector; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.statistics.communication.Communication; + +import java.util.List; +import java.util.Map; + +/** + * Created by jingxing on 14-9-9. + */ +public final class DefaultJobPluginCollector implements JobPluginCollector { + private AbstractContainerCommunicator jobCollector; + + public DefaultJobPluginCollector(AbstractContainerCommunicator containerCollector) { + this.jobCollector = containerCollector; + } + + @Override + public Map> getMessage() { + Communication totalCommunication = this.jobCollector.collect(); + return totalCommunication.getMessage(); + } + + @Override + public List getMessage(String key) { + Communication totalCommunication = this.jobCollector.collect(); + return totalCommunication.getMessage(key); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/AbstractTaskPluginCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/AbstractTaskPluginCollector.java new file mode 100755 index 000000000..ada9687f2 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/AbstractTaskPluginCollector.java @@ -0,0 +1,77 @@ +package com.alibaba.datax.core.statistics.plugin.task; + +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by jingxing on 14-9-11. + */ +public abstract class AbstractTaskPluginCollector extends TaskPluginCollector { + private static final Logger LOG = LoggerFactory + .getLogger(AbstractTaskPluginCollector.class); + + private Communication communication; + + private Configuration configuration; + + private PluginType pluginType; + + public AbstractTaskPluginCollector(Configuration conf, Communication communication, + PluginType type) { + this.configuration = conf; + this.communication = communication; + this.pluginType = type; + } + + public Communication getCommunication() { + return communication; + } + + public Configuration getConfiguration() { + return configuration; + } + + public PluginType getPluginType() { + return pluginType; + } + + @Override + final public void collectMessage(String key, String value) { + this.communication.addMessage(key, value); + } + + @Override + public void collectDirtyRecord(Record dirtyRecord, Throwable t, + String errorMessage) { + + if (null == dirtyRecord) { + LOG.warn("脏数据record=null."); + return; + } + + if (this.pluginType.equals(PluginType.READER)) { + this.communication.increaseCounter( + CommunicationTool.READ_FAILED_RECORDS, 1); + this.communication.increaseCounter( + CommunicationTool.READ_FAILED_BYTES, dirtyRecord.getByteSize()); + } else if (this.pluginType.equals(PluginType.WRITER)) { + this.communication.increaseCounter( + CommunicationTool.WRITE_FAILED_RECORDS, 1); + this.communication.increaseCounter( + CommunicationTool.WRITE_FAILED_BYTES, dirtyRecord.getByteSize()); + } else { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + String.format("不知道的插件类型[%s].", this.pluginType)); + } + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/HttpPluginCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/HttpPluginCollector.java new file mode 100755 index 000000000..e479fe2c1 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/HttpPluginCollector.java @@ -0,0 +1,23 @@ +package com.alibaba.datax.core.statistics.plugin.task; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.communication.Communication; + +/** + * Created by jingxing on 14-9-9. + */ +public class HttpPluginCollector extends AbstractTaskPluginCollector { + public HttpPluginCollector(Configuration configuration, Communication Communication, + PluginType type) { + super(configuration, Communication, type); + } + + @Override + public void collectDirtyRecord(Record dirtyRecord, Throwable t, + String errorMessage) { + super.collectDirtyRecord(dirtyRecord, t, errorMessage); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/StdoutPluginCollector.java b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/StdoutPluginCollector.java new file mode 100755 index 000000000..8b2a83781 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/StdoutPluginCollector.java @@ -0,0 +1,74 @@ +package com.alibaba.datax.core.statistics.plugin.task; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.statistics.plugin.task.util.DirtyRecord; +import com.alibaba.fastjson.JSON; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by jingxing on 14-9-9. + */ +public class StdoutPluginCollector extends AbstractTaskPluginCollector { + private static final Logger LOG = LoggerFactory + .getLogger(StdoutPluginCollector.class); + + private static final int DEFAULT_MAX_DIRTYNUM = 128; + + private AtomicInteger maxLogNum = new AtomicInteger(0); + + private AtomicInteger currentLogNum = new AtomicInteger(0); + + public StdoutPluginCollector(Configuration configuration, Communication communication, + PluginType type) { + super(configuration, communication, type); + maxLogNum = new AtomicInteger( + configuration.getInt( + CoreConstant.DATAX_CORE_STATISTICS_COLLECTOR_PLUGIN_MAXDIRTYNUM, + DEFAULT_MAX_DIRTYNUM)); + } + + private String formatDirty(final Record dirty, final Throwable t, + final String msg) { + Map msgGroup = new HashMap(); + + msgGroup.put("type", super.getPluginType().toString()); + if (StringUtils.isNotBlank(msg)) { + msgGroup.put("message", msg); + } + if (null != t && StringUtils.isNotBlank(t.getMessage())) { + msgGroup.put("exception", t.getMessage()); + } + if (null != dirty) { + msgGroup.put("record", DirtyRecord.asDirtyRecord(dirty) + .getColumns()); + } + + return JSON.toJSONString(msgGroup); + } + + @Override + public void collectDirtyRecord(Record dirtyRecord, Throwable t, + String errorMessage) { + int logNum = currentLogNum.getAndIncrement(); + if(logNum==0 && t!=null){ + LOG.error("", t); + } + if (maxLogNum.intValue() < 0 || currentLogNum.intValue() < maxLogNum.intValue()) { + LOG.error("脏数据: \n" + + this.formatDirty(dirtyRecord, t, errorMessage)); + } + + super.collectDirtyRecord(dirtyRecord, t, errorMessage); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/util/DirtyRecord.java b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/util/DirtyRecord.java new file mode 100755 index 000000000..fdc5d8215 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/statistics/plugin/task/util/DirtyRecord.java @@ -0,0 +1,151 @@ +package com.alibaba.datax.core.statistics.plugin.task.util; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.fastjson.JSON; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class DirtyRecord implements Record { + private List columns = new ArrayList(); + + public static DirtyRecord asDirtyRecord(final Record record) { + DirtyRecord result = new DirtyRecord(); + for (int i = 0; i < record.getColumnNumber(); i++) { + result.addColumn(record.getColumn(i)); + } + + return result; + } + + @Override + public void addColumn(Column column) { + this.columns.add( + DirtyColumn.asDirtyColumn(column, this.columns.size())); + } + + @Override + public String toString() { + return JSON.toJSONString(this.columns); + } + + @Override + public void setColumn(int i, Column column) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public Column getColumn(int i) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public int getColumnNumber() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public int getByteSize() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public int getMemorySize() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + } + +} + +class DirtyColumn extends Column { + private int index; + + public static Column asDirtyColumn(final Column column, int index) { + return new DirtyColumn(column, index); + } + + private DirtyColumn(Column column, int index) { + this(null == column ? null : column.getRawData(), + null == column ? Column.Type.NULL : column.getType(), + null == column ? 0 : column.getByteSize(), index); + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + @Override + public Long asLong() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public Double asDouble() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public String asString() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public Date asDate() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public byte[] asBytes() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public Boolean asBoolean() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public BigDecimal asBigDecimal() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + @Override + public BigInteger asBigInteger() { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "该方法不支持!"); + } + + private DirtyColumn(Object object, Type type, int byteSize, int index) { + super(object, type, byteSize); + this.setIndex(index); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskGroupContainer.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskGroupContainer.java new file mode 100755 index 000000000..5702185bf --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskGroupContainer.java @@ -0,0 +1,540 @@ +package com.alibaba.datax.core.taskgroup; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.statistics.PerfRecord; +import com.alibaba.datax.common.statistics.PerfTrace; +import com.alibaba.datax.common.statistics.VMInfo; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.AbstractContainer; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.statistics.container.communicator.taskgroup.StandaloneTGContainerCommunicator; +import com.alibaba.datax.core.statistics.plugin.task.AbstractTaskPluginCollector; +import com.alibaba.datax.core.taskgroup.runner.AbstractRunner; +import com.alibaba.datax.core.taskgroup.runner.ReaderRunner; +import com.alibaba.datax.core.taskgroup.runner.WriterRunner; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.exchanger.BufferedRecordExchanger; +import com.alibaba.datax.core.util.ClassUtil; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.container.LoadUtil; +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class TaskGroupContainer extends AbstractContainer { + private static final Logger LOG = LoggerFactory + .getLogger(TaskGroupContainer.class); + + /** + * 当前taskGroup所属jobId + */ + private long jobId; + + /** + * 当前taskGroupId + */ + private int taskGroupId; + + /** + * 使用的channel类 + */ + private String channelClazz; + + /** + * task收集器使用的类 + */ + private String taskCollectorClass; + + private TaskMonitor taskMonitor = TaskMonitor.getInstance(); + + public TaskGroupContainer(Configuration configuration) { + super(configuration); + + initCommunicator(configuration); + + this.jobId = this.configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_JOB_ID); + this.taskGroupId = this.configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID); + + this.channelClazz = this.configuration.getString( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CLASS); + this.taskCollectorClass = this.configuration.getString( + CoreConstant.DATAX_CORE_STATISTICS_COLLECTOR_PLUGIN_TASKCLASS); + } + + private void initCommunicator(Configuration configuration) { + super.setContainerCommunicator(new StandaloneTGContainerCommunicator(configuration)); + } + + public long getJobId() { + return jobId; + } + + public int getTaskGroupId() { + return taskGroupId; + } + + @Override + public void start() { + try { + /** + * 状态check时间间隔,较短,可以把任务及时分发到对应channel中 + */ + int sleepIntervalInMillSec = this.configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_SLEEPINTERVAL, 100); + /** + * 状态汇报时间间隔,稍长,避免大量汇报 + */ + long reportIntervalInMillSec = this.configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_REPORTINTERVAL, + 5000); + + // 获取channel数目 + int channelNumber = this.configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL); + + int taskMaxRetryTimes = this.configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASK_FAILOVER_MAXRETRYTIMES, 1); + + long taskRetryIntervalInMsec = this.configuration.getLong( + CoreConstant.DATAX_CORE_CONTAINER_TASK_FAILOVER_RETRYINTERVALINMSEC, 10000); + + long taskMaxWaitInMsec = this.configuration.getLong(CoreConstant.DATAX_CORE_CONTAINER_TASK_FAILOVER_MAXWAITINMSEC, 60000); + + List taskConfigs = this.configuration + .getListConfiguration(CoreConstant.DATAX_JOB_CONTENT); + + if(LOG.isDebugEnabled()) { + LOG.debug("taskGroup[{}]'s task configs[{}]", this.taskGroupId, + JSON.toJSONString(taskConfigs)); + } + + int taskCountInThisTaskGroup = taskConfigs.size(); + LOG.info(String.format( + "taskGroupId=[%d] start [%d] channels for [%d] tasks.", + this.taskGroupId, channelNumber, taskCountInThisTaskGroup)); + + this.containerCommunicator.registerCommunication(taskConfigs); + + Map taskConfigMap = buildTaskConfigMap(taskConfigs); //taskId与task配置 + List taskQueue = buildRemainTasks(taskConfigs); //待运行task列表 + Map taskFailedExecutorMap = new HashMap(); //taskId与上次失败实例 + List runTasks = new ArrayList(channelNumber); //正在运行task + Map taskStartTimeMap = new HashMap(); //任务开始时间 + + long lastReportTimeStamp = 0; + Communication lastTaskGroupContainerCommunication = new Communication(); + + while (true) { + //1.判断task状态 + boolean failedOrKilled = false; + Map communicationMap = containerCommunicator.getCommunicationMap(); + for(Map.Entry entry : communicationMap.entrySet()){ + Integer taskId = entry.getKey(); + Communication taskCommunication = entry.getValue(); + if(!taskCommunication.isFinished()){ + continue; + } + TaskExecutor taskExecutor = removeTask(runTasks, taskId); + + //上面从runTasks里移除了,因此对应在monitor里移除 + taskMonitor.removeTask(taskId); + + //失败,看task是否支持failover,重试次数未超过最大限制 + if(taskCommunication.getState() == State.FAILED){ + taskFailedExecutorMap.put(taskId, taskExecutor); + if(taskExecutor.supportFailOver() && taskExecutor.getAttemptCount() < taskMaxRetryTimes){ + taskExecutor.shutdown(); //关闭老的executor + containerCommunicator.resetCommunication(taskId); //将task的状态重置 + Configuration taskConfig = taskConfigMap.get(taskId); + taskQueue.add(taskConfig); //重新加入任务列表 + }else{ + failedOrKilled = true; + break; + } + }else if(taskCommunication.getState() == State.KILLED){ + failedOrKilled = true; + break; + }else if(taskCommunication.getState() == State.SUCCEEDED){ + Long taskStartTime = taskStartTimeMap.get(taskId); + if(taskStartTime != null){ + Long usedTime = System.currentTimeMillis() - taskStartTime; + LOG.info("taskGroup[{}] taskId[{}] is successed, used[{}]ms", + this.taskGroupId, taskId, usedTime); + //usedTime*1000*1000 转换成PerfRecord记录的ns,这里主要是简单登记,进行最长任务的打印。因此增加特定静态方法 + PerfRecord.addPerfRecord(taskGroupId, taskId, PerfRecord.PHASE.TASK_TOTAL,taskStartTime, usedTime * 1000L * 1000L); + taskStartTimeMap.remove(taskId); + taskConfigMap.remove(taskId); + } + } + } + + // 2.发现该taskGroup下taskExecutor的总状态失败则汇报错误 + if (failedOrKilled) { + lastTaskGroupContainerCommunication = reportTaskGroupCommunication( + lastTaskGroupContainerCommunication, taskCountInThisTaskGroup); + + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_RUNTIME_ERROR, lastTaskGroupContainerCommunication.getThrowable()); + } + + //3.有任务未执行,且正在运行的任务数小于最大通道限制 + Iterator iterator = taskQueue.iterator(); + while(iterator.hasNext() && runTasks.size() < channelNumber){ + Configuration taskConfig = iterator.next(); + Integer taskId = taskConfig.getInt(CoreConstant.TASK_ID); + int attemptCount = 1; + TaskExecutor lastExecutor = taskFailedExecutorMap.get(taskId); + if(lastExecutor!=null){ + attemptCount = lastExecutor.getAttemptCount() + 1; + long now = System.currentTimeMillis(); + long failedTime = lastExecutor.getTimeStamp(); + if(now - failedTime < taskRetryIntervalInMsec){ //未到等待时间,继续留在队列 + continue; + } + if(!lastExecutor.isShutdown()){ //上次失败的task仍未结束 + if(now - failedTime > taskMaxWaitInMsec){ + markCommunicationFailed(taskId); + reportTaskGroupCommunication(lastTaskGroupContainerCommunication, taskCountInThisTaskGroup); + throw DataXException.asDataXException(CommonErrorCode.WAIT_TIME_EXCEED, "task failover等待超时"); + }else{ + lastExecutor.shutdown(); //再次尝试关闭 + continue; + } + }else{ + LOG.info("taskGroup[{}] taskId[{}] attemptCount[{}] has already shutdown", + this.taskGroupId, taskId, lastExecutor.getAttemptCount()); + } + } + Configuration taskConfigForRun = taskMaxRetryTimes > 1 ? taskConfig.clone() : taskConfig; + TaskExecutor taskExecutor = new TaskExecutor(taskConfigForRun, attemptCount); + taskStartTimeMap.put(taskId, System.currentTimeMillis()); + taskExecutor.doStart(); + + iterator.remove(); + runTasks.add(taskExecutor); + + //上面,增加task到runTasks列表,因此在monitor里注册。 + taskMonitor.registerTask(taskId, this.containerCommunicator.getCommunication(taskId)); + + taskFailedExecutorMap.remove(taskId); + LOG.info("taskGroup[{}] taskId[{}] attemptCount[{}] is started", + this.taskGroupId, taskId, attemptCount); + } + + //4.任务列表为空,executor已结束, 搜集状态为success--->成功 + if (taskQueue.isEmpty() && isAllTaskDone(runTasks) && containerCommunicator.collectState() == State.SUCCEEDED) { + // 成功的情况下,也需要汇报一次。否则在任务结束非常快的情况下,采集的信息将会不准确 + lastTaskGroupContainerCommunication = reportTaskGroupCommunication( + lastTaskGroupContainerCommunication, taskCountInThisTaskGroup); + + LOG.info("taskGroup[{}] completed it's tasks.", this.taskGroupId); + break; + } + + // 5.如果当前时间已经超出汇报时间的interval,那么我们需要马上汇报 + long now = System.currentTimeMillis(); + if (now - lastReportTimeStamp > reportIntervalInMillSec) { + lastTaskGroupContainerCommunication = reportTaskGroupCommunication( + lastTaskGroupContainerCommunication, taskCountInThisTaskGroup); + + lastReportTimeStamp = now; + + //taskMonitor对于正在运行的task,每reportIntervalInMillSec进行检查 + for(TaskExecutor taskExecutor:runTasks){ + taskMonitor.report(taskExecutor.getTaskId(),this.containerCommunicator.getCommunication(taskExecutor.getTaskId())); + } + + } + + Thread.sleep(sleepIntervalInMillSec); + } + + //6.最后还要汇报一次 + reportTaskGroupCommunication(lastTaskGroupContainerCommunication, taskCountInThisTaskGroup); + + } catch (Throwable e) { + Communication nowTaskGroupContainerCommunication = this.containerCommunicator.collect(); + + if (nowTaskGroupContainerCommunication.getThrowable() == null) { + nowTaskGroupContainerCommunication.setThrowable(e); + } + nowTaskGroupContainerCommunication.setState(State.FAILED); + this.containerCommunicator.report(nowTaskGroupContainerCommunication); + + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + }finally { + if(!PerfTrace.getInstance().isJob()){ + //最后打印cpu的平均消耗,GC的统计 + VMInfo vmInfo = VMInfo.getVmInfo(); + if (vmInfo != null) { + vmInfo.getDelta(false); + LOG.info(vmInfo.totalString()); + } + + LOG.info(PerfTrace.getInstance().summarizeNoException()); + } + } + } + + private Map buildTaskConfigMap(List configurations){ + Map map = new HashMap(); + for(Configuration taskConfig : configurations){ + int taskId = taskConfig.getInt(CoreConstant.TASK_ID); + map.put(taskId, taskConfig); + } + return map; + } + + private List buildRemainTasks(List configurations){ + List remainTasks = new LinkedList(); + for(Configuration taskConfig : configurations){ + remainTasks.add(taskConfig); + } + return remainTasks; + } + + private TaskExecutor removeTask(List taskList, int taskId){ + Iterator iterator = taskList.iterator(); + while(iterator.hasNext()){ + TaskExecutor taskExecutor = iterator.next(); + if(taskExecutor.getTaskId() == taskId){ + iterator.remove(); + return taskExecutor; + } + } + return null; + } + + private boolean isAllTaskDone(List taskList){ + for(TaskExecutor taskExecutor : taskList){ + if(!taskExecutor.isTaskFinished()){ + return false; + } + } + return true; + } + + private Communication reportTaskGroupCommunication(Communication lastTaskGroupContainerCommunication, int taskCount){ + Communication nowTaskGroupContainerCommunication = this.containerCommunicator.collect(); + nowTaskGroupContainerCommunication.setTimestamp(System.currentTimeMillis()); + Communication reportCommunication = CommunicationTool.getReportCommunication(nowTaskGroupContainerCommunication, + lastTaskGroupContainerCommunication, taskCount); + this.containerCommunicator.report(reportCommunication); + return reportCommunication; + } + + private void markCommunicationFailed(Integer taskId){ + Communication communication = containerCommunicator.getCommunication(taskId); + communication.setState(State.FAILED); + } + + /** + * TaskExecutor是一个完整task的执行器 + * 其中包括1:1的reader和writer + */ + class TaskExecutor { + private Configuration taskConfig; + + private int taskId; + + private int attemptCount; + + private Channel channel; + + private Thread readerThread; + + private Thread writerThread; + + private ReaderRunner readerRunner; + + private WriterRunner writerRunner; + + /** + * 该处的taskCommunication在多处用到: + * 1. channel + * 2. readerRunner和writerRunner + * 3. reader和writer的taskPluginCollector + */ + private Communication taskCommunication; + + public TaskExecutor(Configuration taskConf, int attemptCount) { + // 获取该taskExecutor的配置 + this.taskConfig = taskConf; + Validate.isTrue(null != this.taskConfig.getConfiguration(CoreConstant.JOB_READER) + && null != this.taskConfig.getConfiguration(CoreConstant.JOB_WRITER), + "[reader|writer]的插件参数不能为空!"); + + // 得到taskId + this.taskId = this.taskConfig.getInt(CoreConstant.TASK_ID); + this.attemptCount = attemptCount; + + /** + * 由taskId得到该taskExecutor的Communication + * 要传给readerRunner和writerRunner,同时要传给channel作统计用 + */ + this.taskCommunication = containerCommunicator + .getCommunication(taskId); + Validate.notNull(this.taskCommunication, + String.format("taskId[%d]的Communication没有注册过", taskId)); + this.channel = ClassUtil.instantiate(channelClazz, + Channel.class, configuration); + this.channel.setCommunication(this.taskCommunication); + + /** + * 生成writerThread + */ + writerRunner = (WriterRunner) generateRunner(PluginType.WRITER); + this.writerThread = new Thread(writerRunner, + String.format("%d-%d-%d-writer", + jobId, taskGroupId, this.taskId)); + //通过设置thread的contextClassLoader,即可实现同步和主程序不通的加载器 + this.writerThread.setContextClassLoader(LoadUtil.getJarLoader( + PluginType.WRITER, this.taskConfig.getString( + CoreConstant.JOB_WRITER_NAME))); + + /** + * 生成readerThread + */ + readerRunner = (ReaderRunner) generateRunner(PluginType.READER); + this.readerThread = new Thread(readerRunner, + String.format("%d-%d-%d-reader", + jobId, taskGroupId, this.taskId)); + /** + * 通过设置thread的contextClassLoader,即可实现同步和主程序不通的加载器 + */ + this.readerThread.setContextClassLoader(LoadUtil.getJarLoader( + PluginType.READER, this.taskConfig.getString( + CoreConstant.JOB_READER_NAME))); + } + + public void doStart() { + this.writerThread.start(); + + // reader没有起来,writer不可能结束 + if (!this.writerThread.isAlive() || this.taskCommunication.getState() == State.FAILED) { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + this.taskCommunication.getThrowable()); + } + + this.readerThread.start(); + + // 这里reader可能很快结束 + if (!this.readerThread.isAlive() && this.taskCommunication.getState() == State.FAILED) { + // 这里有可能出现Reader线上启动即挂情况 对于这类情况 需要立刻抛出异常 + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + this.taskCommunication.getThrowable()); + } + + } + + private AbstractRunner generateRunner(PluginType pluginType) { + AbstractRunner newRunner = null; + TaskPluginCollector pluginCollector; + + switch (pluginType) { + case READER: + newRunner = LoadUtil.loadPluginRunner(pluginType, + this.taskConfig.getString(CoreConstant.JOB_READER_NAME)); + newRunner.setJobConf(this.taskConfig.getConfiguration( + CoreConstant.JOB_READER_PARAMETER)); + + pluginCollector = ClassUtil.instantiate( + taskCollectorClass, AbstractTaskPluginCollector.class, + configuration, this.taskCommunication, + PluginType.READER); + + ((ReaderRunner) newRunner).setRecordSender( + new BufferedRecordExchanger(this.channel, pluginCollector)); + /** + * 设置taskPlugin的collector,用来处理脏数据和job/task通信 + */ + newRunner.setTaskPluginCollector(pluginCollector); + break; + case WRITER: + newRunner = LoadUtil.loadPluginRunner(pluginType, + this.taskConfig.getString(CoreConstant.JOB_WRITER_NAME)); + newRunner.setJobConf(this.taskConfig + .getConfiguration(CoreConstant.JOB_WRITER_PARAMETER)); + + pluginCollector = ClassUtil.instantiate( + taskCollectorClass, AbstractTaskPluginCollector.class, + configuration, this.taskCommunication, + PluginType.WRITER); + ((WriterRunner) newRunner).setRecordReceiver(new BufferedRecordExchanger( + this.channel, pluginCollector)); + /** + * 设置taskPlugin的collector,用来处理脏数据和job/task通信 + */ + newRunner.setTaskPluginCollector(pluginCollector); + break; + default: + throw DataXException.asDataXException(FrameworkErrorCode.ARGUMENT_ERROR, "Cant generateRunner for:" + pluginType); + } + + newRunner.setTaskGroupId(taskGroupId); + newRunner.setTaskId(this.taskId); + newRunner.setRunnerCommunication(this.taskCommunication); + + return newRunner; + } + + // 检查任务是否结束 + private boolean isTaskFinished() { + // 如果reader 或 writer没有完成工作,那么直接返回工作没有完成 + if (readerThread.isAlive() || writerThread.isAlive()) { + return false; + } + + if(taskCommunication==null || !taskCommunication.isFinished()){ + return false; + } + + return true; + } + + private int getTaskId(){ + return taskId; + } + + private long getTimeStamp(){ + return taskCommunication.getTimestamp(); + } + + private int getAttemptCount(){ + return attemptCount; + } + + private boolean supportFailOver(){ + return writerRunner.supportFailOver(); + } + + private void shutdown(){ + writerRunner.shutdown(); + readerRunner.shutdown(); + if(writerThread.isAlive()){ + writerThread.interrupt(); + } + if(readerThread.isAlive()){ + readerThread.interrupt(); + } + } + + private boolean isShutdown(){ + return !readerThread.isAlive() && !writerThread.isAlive(); + } + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskMonitor.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskMonitor.java new file mode 100644 index 000000000..d852c0e0c --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/TaskMonitor.java @@ -0,0 +1,113 @@ +package com.alibaba.datax.core.taskgroup; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by liqiang on 15/7/23. + */ +public class TaskMonitor { + + private static final Logger LOG = LoggerFactory.getLogger(TaskMonitor.class); + private static final TaskMonitor instance = new TaskMonitor(); + private static long EXPIRED_TIME = 172800 * 1000; + + private ConcurrentHashMap tasks = new ConcurrentHashMap(); + + private TaskMonitor() { + } + + public static TaskMonitor getInstance() { + return instance; + } + + public void registerTask(Integer taskid, Communication communication) { + //如果task已经finish,直接返回 + if (communication.isFinished()) { + return; + } + tasks.putIfAbsent(taskid, new TaskCommunication(taskid, communication)); + } + + public void removeTask(Integer taskid) { + tasks.remove(taskid); + } + + public void report(Integer taskid, Communication communication) { + //如果task已经finish,直接返回 + if (communication.isFinished()) { + return; + } + if (!tasks.containsKey(taskid)) { + LOG.warn("unexpected: taskid({}) missed.", taskid); + tasks.putIfAbsent(taskid, new TaskCommunication(taskid, communication)); + } else { + tasks.get(taskid).report(communication); + } + } + + public TaskCommunication getTaskCommunication(Integer taskid) { + return tasks.get(taskid); + } + + + public static class TaskCommunication { + private Integer taskid; + //记录最后更新的communication + private long lastAllReadRecords = -1; + //只有第一次,或者统计变更时才会更新TS + private long lastUpdateComunicationTS; + private long ttl; + + private TaskCommunication(Integer taskid, Communication communication) { + this.taskid = taskid; + lastAllReadRecords = CommunicationTool.getTotalReadRecords(communication); + ttl = System.currentTimeMillis(); + lastUpdateComunicationTS = ttl; + } + + public void report(Communication communication) { + + ttl = System.currentTimeMillis(); + //采集的数量增长,则变更当前记录, 优先判断这个条件,因为目的是不卡住,而不是expired + if (CommunicationTool.getTotalReadRecords(communication) > lastAllReadRecords) { + lastAllReadRecords = CommunicationTool.getTotalReadRecords(communication); + lastUpdateComunicationTS = ttl; + } else if (isExpired(lastUpdateComunicationTS)) { + communication.setState(State.FAILED); + communication.setTimestamp(ttl); + communication.setThrowable(DataXException.asDataXException(CommonErrorCode.TASK_HUNG_EXPIRED, + String.format("task(%s) hung expired [allReadRecord(%s), elased(%s)]", taskid, lastAllReadRecords, (ttl - lastUpdateComunicationTS)))); + } + + + } + + private boolean isExpired(long lastUpdateComunicationTS) { + return System.currentTimeMillis() - lastUpdateComunicationTS > EXPIRED_TIME; + } + + public Integer getTaskid() { + return taskid; + } + + public long getLastAllReadRecords() { + return lastAllReadRecords; + } + + public long getLastUpdateComunicationTS() { + return lastUpdateComunicationTS; + } + + public long getTtl() { + return ttl; + } + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/AbstractRunner.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/AbstractRunner.java new file mode 100755 index 000000000..4820698e2 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/AbstractRunner.java @@ -0,0 +1,113 @@ +package com.alibaba.datax.core.taskgroup.runner; + +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import org.apache.commons.lang.Validate; + +public abstract class AbstractRunner { + private AbstractTaskPlugin plugin; + + private Configuration jobConf; + + private Communication runnerCommunication; + + private int taskGroupId; + + private int taskId; + + public AbstractRunner(AbstractTaskPlugin taskPlugin) { + this.plugin = taskPlugin; + } + + public void destroy() { + if (this.plugin != null) { + this.plugin.destroy(); + } + } + + public State getRunnerState() { + return this.runnerCommunication.getState(); + } + + public AbstractTaskPlugin getPlugin() { + return plugin; + } + + public void setPlugin(AbstractTaskPlugin plugin) { + this.plugin = plugin; + } + + public Configuration getJobConf() { + return jobConf; + } + + public void setJobConf(Configuration jobConf) { + this.jobConf = jobConf; + this.plugin.setPluginJobConf(jobConf); + } + + public void setTaskPluginCollector(TaskPluginCollector pluginCollector) { + this.plugin.setTaskPluginCollector(pluginCollector); + } + + private void mark(State state) { + this.runnerCommunication.setState(state); + // 对 stage + 1 + this.runnerCommunication.setLongCounter(CommunicationTool.STAGE, + this.runnerCommunication.getLongCounter(CommunicationTool.STAGE) + 1); + } + + public void markRun() { + mark(State.RUNNING); + } + + public void markSuccess() { + mark(State.SUCCEEDED); + } + + public void markFail(final Throwable throwable) { + mark(State.FAILED); + this.runnerCommunication.setTimestamp(System.currentTimeMillis()); + this.runnerCommunication.setThrowable(throwable); + } + + /** + * @param taskGroupId the taskGroupId to set + */ + public void setTaskGroupId(int taskGroupId) { + this.taskGroupId = taskGroupId; + this.plugin.setTaskGroupId(taskGroupId); + } + + /** + * @return the taskGroupId + */ + public int getTaskGroupId() { + return taskGroupId; + } + + public int getTaskId() { + return taskId; + } + + public void setTaskId(int taskId) { + this.taskId = taskId; + this.plugin.setTaskId(taskId); + } + + public void setRunnerCommunication(final Communication runnerCommunication) { + Validate.notNull(runnerCommunication, + "插件的Communication不能为空"); + this.runnerCommunication = runnerCommunication; + } + + public Communication getRunnerCommunication() { + return runnerCommunication; + } + + public abstract void shutdown(); +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/ReaderRunner.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/ReaderRunner.java new file mode 100755 index 000000000..284d1b6b9 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/ReaderRunner.java @@ -0,0 +1,88 @@ +package com.alibaba.datax.core.taskgroup.runner; + +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.statistics.PerfRecord; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by jingxing on 14-9-1. + *

+ * 单个slice的reader执行调用 + */ +public class ReaderRunner extends AbstractRunner implements Runnable { + + private static final Logger LOG = LoggerFactory + .getLogger(ReaderRunner.class); + + private RecordSender recordSender; + + public void setRecordSender(RecordSender recordSender) { + this.recordSender = recordSender; + } + + public ReaderRunner(AbstractTaskPlugin abstractTaskPlugin) { + super(abstractTaskPlugin); + } + + @Override + public void run() { + assert null != this.recordSender; + + Reader.Task taskReader = (Reader.Task) this.getPlugin(); + + //统计waitWriterTime,并且在finally才end。 + PerfRecord channelWaitWrite = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WAIT_WRITE_TIME); + try { + channelWaitWrite.start(); + + LOG.debug("task reader starts to do init ..."); + PerfRecord initPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.READ_TASK_INIT); + initPerfRecord.start(); + taskReader.init(); + initPerfRecord.end(); + + LOG.debug("task reader starts to do prepare ..."); + PerfRecord preparePerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.READ_TASK_PREPARE); + preparePerfRecord.start(); + taskReader.prepare(); + preparePerfRecord.end(); + + LOG.debug("task reader starts to read ..."); + PerfRecord dataPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.READ_TASK_DATA); + dataPerfRecord.start(); + taskReader.startRead(recordSender); + recordSender.terminate(); + + dataPerfRecord.addCount(CommunicationTool.getTotalReadRecords(super.getRunnerCommunication())); + dataPerfRecord.addSize(CommunicationTool.getTotalReadBytes(super.getRunnerCommunication())); + dataPerfRecord.end(); + + LOG.debug("task reader starts to do post ..."); + PerfRecord postPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.READ_TASK_POST); + postPerfRecord.start(); + taskReader.post(); + postPerfRecord.end(); + // automatic flush + // super.markSuccess(); 这里不能标记为成功,成功的标志由 writerRunner 来标志(否则可能导致 reader 先结束,而 writer 还没有结束的严重 bug) + } catch (Throwable e) { + LOG.error("Reader runner Received Exceptions:", e); + super.markFail(e); + } finally { + LOG.debug("task reader starts to do destroy ..."); + PerfRecord desPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.READ_TASK_DESTROY); + desPerfRecord.start(); + super.destroy(); + desPerfRecord.end(); + + channelWaitWrite.end(super.getRunnerCommunication().getLongCounter(CommunicationTool.WAIT_WRITER_TIME)); + } + } + + public void shutdown(){ + recordSender.shutdown(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/TaskGroupContainerRunner.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/TaskGroupContainerRunner.java new file mode 100755 index 000000000..ab4af808b --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/TaskGroupContainerRunner.java @@ -0,0 +1,44 @@ +package com.alibaba.datax.core.taskgroup.runner; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.taskgroup.TaskGroupContainer; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +public class TaskGroupContainerRunner implements Runnable { + + private TaskGroupContainer taskGroupContainer; + + private State state; + + public TaskGroupContainerRunner(TaskGroupContainer taskGroup) { + this.taskGroupContainer = taskGroup; + this.state = State.SUCCEEDED; + } + + @Override + public void run() { + try { + Thread.currentThread().setName( + String.format("taskGroup-%d", this.taskGroupContainer.getTaskGroupId())); + this.taskGroupContainer.start(); + this.state = State.SUCCEEDED; + } catch (Throwable e) { + this.state = State.FAILED; + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } + } + + public TaskGroupContainer getTaskGroupContainer() { + return taskGroupContainer; + } + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/WriterRunner.java b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/WriterRunner.java new file mode 100755 index 000000000..8fa5d68be --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/taskgroup/runner/WriterRunner.java @@ -0,0 +1,90 @@ +package com.alibaba.datax.core.taskgroup.runner; + +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.statistics.PerfRecord; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by jingxing on 14-9-1. + *

+ * 单个slice的writer执行调用 + */ +public class WriterRunner extends AbstractRunner implements Runnable { + + private static final Logger LOG = LoggerFactory + .getLogger(WriterRunner.class); + + private RecordReceiver recordReceiver; + + public void setRecordReceiver(RecordReceiver receiver) { + this.recordReceiver = receiver; + } + + public WriterRunner(AbstractTaskPlugin abstractTaskPlugin) { + super(abstractTaskPlugin); + } + + @Override + public void run() { + Validate.isTrue(this.recordReceiver != null); + + Writer.Task taskWriter = (Writer.Task) this.getPlugin(); + //统计waitReadTime,并且在finally end + PerfRecord channelWaitRead = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WAIT_READ_TIME); + try { + channelWaitRead.start(); + LOG.debug("task writer starts to do init ..."); + PerfRecord initPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WRITE_TASK_INIT); + initPerfRecord.start(); + taskWriter.init(); + initPerfRecord.end(); + + LOG.debug("task writer starts to do prepare ..."); + PerfRecord preparePerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WRITE_TASK_PREPARE); + preparePerfRecord.start(); + taskWriter.prepare(); + preparePerfRecord.end(); + LOG.debug("task writer starts to write ..."); + + PerfRecord dataPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WRITE_TASK_DATA); + dataPerfRecord.start(); + taskWriter.startWrite(recordReceiver); + + dataPerfRecord.addCount(CommunicationTool.getTotalReadRecords(super.getRunnerCommunication())); + dataPerfRecord.addSize(CommunicationTool.getTotalReadBytes(super.getRunnerCommunication())); + dataPerfRecord.end(); + + LOG.debug("task writer starts to do post ..."); + PerfRecord postPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WRITE_TASK_POST); + postPerfRecord.start(); + taskWriter.post(); + postPerfRecord.end(); + + super.markSuccess(); + } catch (Throwable e) { + LOG.error("Writer Runner Received Exceptions:", e); + super.markFail(e); + } finally { + LOG.debug("task writer starts to do destroy ..."); + PerfRecord desPerfRecord = new PerfRecord(getTaskGroupId(), getTaskId(), PerfRecord.PHASE.WRITE_TASK_DESTROY); + desPerfRecord.start(); + super.destroy(); + desPerfRecord.end(); + channelWaitRead.end(super.getRunnerCommunication().getLongCounter(CommunicationTool.WAIT_READER_TIME)); + } + } + + public boolean supportFailOver(){ + Writer.Task taskWriter = (Writer.Task) this.getPlugin(); + return taskWriter.supportFailOver(); + } + + public void shutdown(){ + recordReceiver.shutdown(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/channel/Channel.java b/core/src/main/java/com/alibaba/datax/core/transport/channel/Channel.java new file mode 100755 index 000000000..f2845b804 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/channel/Channel.java @@ -0,0 +1,247 @@ +package com.alibaba.datax.core.transport.channel; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.transport.record.TerminateRecord; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * Created by jingxing on 14-8-25. + *

+ * 统计和限速都在这里 + */ +public abstract class Channel { + + private static final Logger LOG = LoggerFactory.getLogger(Channel.class); + + protected int taskGroupId; + + protected int capacity; + + protected int byteCapacity; + + protected long byteSpeed; // bps: bytes/s + + protected long recordSpeed; // tps: records/s + + protected long flowControlInterval; + + protected volatile boolean isClosed = false; + + protected Configuration configuration = null; + + protected volatile long waitReaderTime = 0; + + protected volatile long waitWriterTime = 0; + + private static Boolean isFirstPrint = true; + + private Communication currentCommunication; + + private Communication lastCommunication = new Communication(); + + public Channel(final Configuration configuration) { + //channel的queue里默认record为1万条。原来为512条 + int capacity = configuration.getInt( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY, 2048); + long byteSpeed = configuration.getLong( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_SPEED_BYTE, 1024 * 1024); + long recordSpeed = configuration.getLong( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_SPEED_RECORD, 10000); + + if (capacity <= 0) { + throw new IllegalArgumentException(String.format( + "通道容量[%d]必须大于0.", capacity)); + } + + synchronized (isFirstPrint) { + if (isFirstPrint) { + Channel.LOG.info("Channel set byte_speed_limit to " + byteSpeed + + (byteSpeed <= 0 ? ", No bps activated." : ".")); + Channel.LOG.info("Channel set record_speed_limit to " + recordSpeed + + (recordSpeed <= 0 ? ", No tps activated." : ".")); + isFirstPrint = false; + } + } + + this.taskGroupId = configuration.getInt( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID); + this.capacity = capacity; + this.byteSpeed = byteSpeed; + this.recordSpeed = recordSpeed; + this.flowControlInterval = configuration.getLong( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_FLOWCONTROLINTERVAL, 1000); + //channel的queue默认大小为8M,原来为64M + this.byteCapacity = configuration.getInt( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE, 8 * 1024 * 1024); + this.configuration = configuration; + } + + public void close() { + this.isClosed = true; + } + + public void open() { + this.isClosed = false; + } + + public boolean isClosed() { + return isClosed; + } + + public int getTaskGroupId() { + return this.taskGroupId; + } + + public int getCapacity() { + return capacity; + } + + public long getByteSpeed() { + return byteSpeed; + } + + public Configuration getConfiguration() { + return this.configuration; + } + + public void setCommunication(final Communication communication) { + this.currentCommunication = communication; + this.lastCommunication.reset(); + } + + public void push(final Record r) { + Validate.notNull(r, "record不能为空."); + this.doPush(r); + this.statPush(1L, r.getByteSize()); + } + + public void pushTerminate(final TerminateRecord r) { + Validate.notNull(r, "record不能为空."); + this.doPush(r); + +// // 对 stage + 1 +// currentCommunication.setLongCounter(CommunicationTool.STAGE, +// currentCommunication.getLongCounter(CommunicationTool.STAGE) + 1); + } + + public void pushAll(final Collection rs) { + Validate.notNull(rs); + Validate.noNullElements(rs); + this.doPushAll(rs); + this.statPush(rs.size(), this.getByteSize(rs)); + } + + public Record pull() { + Record record = this.doPull(); + this.statPull(1L, record.getByteSize()); + return record; + } + + public void pullAll(final Collection rs) { + Validate.notNull(rs); + this.doPullAll(rs); + this.statPull(rs.size(), this.getByteSize(rs)); + } + + protected abstract void doPush(Record r); + + protected abstract void doPushAll(Collection rs); + + protected abstract Record doPull(); + + protected abstract void doPullAll(Collection rs); + + public abstract int size(); + + public abstract boolean isEmpty(); + + public abstract void clear(); + + private long getByteSize(final Collection rs) { + long size = 0; + for (final Record each : rs) { + size += each.getByteSize(); + } + return size; + } + + private void statPush(long recordSize, long byteSize) { + currentCommunication.increaseCounter(CommunicationTool.READ_SUCCEED_RECORDS, + recordSize); + currentCommunication.increaseCounter(CommunicationTool.READ_SUCCEED_BYTES, + byteSize); + //在读的时候进行统计waitCounter即可,因为写(pull)的时候可能正在阻塞,但读的时候已经能读到这个阻塞的counter数 + + currentCommunication.setLongCounter(CommunicationTool.WAIT_READER_TIME, waitReaderTime); + currentCommunication.setLongCounter(CommunicationTool.WAIT_WRITER_TIME, waitWriterTime); + + boolean isChannelByteSpeedLimit = (this.byteSpeed > 0); + boolean isChannelRecordSpeedLimit = (this.recordSpeed > 0); + if (!isChannelByteSpeedLimit && !isChannelRecordSpeedLimit) { + return; + } + + long lastTimestamp = lastCommunication.getTimestamp(); + long nowTimestamp = System.currentTimeMillis(); + long interval = nowTimestamp - lastTimestamp; + if (interval - this.flowControlInterval >= 0) { + long byteLimitSleepTime = 0; + long recordLimitSleepTime = 0; + if (isChannelByteSpeedLimit) { + long currentByteSpeed = (CommunicationTool.getTotalReadBytes(currentCommunication) - + CommunicationTool.getTotalReadBytes(lastCommunication)) * 1000 / interval; + if (currentByteSpeed > this.byteSpeed) { + // 计算根据byteLimit得到的休眠时间 + byteLimitSleepTime = currentByteSpeed * interval / this.byteSpeed + - interval; + } + } + + if (isChannelRecordSpeedLimit) { + long currentRecordSpeed = (CommunicationTool.getTotalReadRecords(currentCommunication) - + CommunicationTool.getTotalReadRecords(lastCommunication)) * 1000 / interval; + if (currentRecordSpeed > this.recordSpeed) { + // 计算根据recordLimit得到的休眠时间 + recordLimitSleepTime = currentRecordSpeed * interval / this.recordSpeed + - interval; + } + } + + // 休眠时间取较大值 + long sleepTime = byteLimitSleepTime < recordLimitSleepTime ? + recordLimitSleepTime : byteLimitSleepTime; + if (sleepTime > 0) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + lastCommunication.setLongCounter(CommunicationTool.READ_SUCCEED_BYTES, + currentCommunication.getLongCounter(CommunicationTool.READ_SUCCEED_BYTES)); + lastCommunication.setLongCounter(CommunicationTool.READ_FAILED_BYTES, + currentCommunication.getLongCounter(CommunicationTool.READ_FAILED_BYTES)); + lastCommunication.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, + currentCommunication.getLongCounter(CommunicationTool.READ_SUCCEED_RECORDS)); + lastCommunication.setLongCounter(CommunicationTool.READ_FAILED_RECORDS, + currentCommunication.getLongCounter(CommunicationTool.READ_FAILED_RECORDS)); + lastCommunication.setTimestamp(nowTimestamp); + } + } + + private void statPull(long recordSize, long byteSize) { + currentCommunication.increaseCounter( + CommunicationTool.WRITE_RECEIVED_RECORDS, recordSize); + currentCommunication.increaseCounter( + CommunicationTool.WRITE_RECEIVED_BYTES, byteSize); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannel.java b/core/src/main/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannel.java new file mode 100755 index 000000000..e49c7878c --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannel.java @@ -0,0 +1,146 @@ +package com.alibaba.datax.core.transport.channel.memory; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.record.TerminateRecord; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.CoreConstant; + +import java.util.Collection; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 内存Channel的具体实现,底层其实是一个ArrayBlockingQueue + * + */ +public class MemoryChannel extends Channel { + + private int bufferSize = 0; + + private AtomicInteger memoryBytes = new AtomicInteger(0); + + private ArrayBlockingQueue queue = null; + + private ReentrantLock lock; + + private Condition notInsufficient, notEmpty; + + public MemoryChannel(final Configuration configuration) { + super(configuration); + this.queue = new ArrayBlockingQueue(this.getCapacity()); + this.bufferSize = configuration.getInt(CoreConstant.DATAX_CORE_TRANSPORT_EXCHANGER_BUFFERSIZE); + + lock = new ReentrantLock(); + notInsufficient = lock.newCondition(); + notEmpty = lock.newCondition(); + } + + @Override + public void close() { + super.close(); + try { + this.queue.put(TerminateRecord.get()); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void clear(){ + this.queue.clear(); + } + + @Override + protected void doPush(Record r) { + try { + long startTime = System.nanoTime(); + this.queue.put(r); + waitWriterTime += System.nanoTime() - startTime; + memoryBytes.addAndGet(r.getMemorySize()); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + @Override + protected void doPushAll(Collection rs) { + try { + long startTime = System.nanoTime(); + lock.lockInterruptibly(); + int bytes = getRecordBytes(rs); + while (memoryBytes.get() + bytes > this.byteCapacity || rs.size() > this.queue.remainingCapacity()) { + notInsufficient.await(200L, TimeUnit.MILLISECONDS); + } + this.queue.addAll(rs); + waitWriterTime += System.nanoTime() - startTime; + memoryBytes.addAndGet(bytes); + notEmpty.signalAll(); + } catch (InterruptedException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } finally { + lock.unlock(); + } + } + + @Override + protected Record doPull() { + try { + long startTime = System.nanoTime(); + Record r = this.queue.take(); + waitReaderTime += System.nanoTime() - startTime; + memoryBytes.addAndGet(-r.getMemorySize()); + return r; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } + + @Override + protected void doPullAll(Collection rs) { + assert rs != null; + rs.clear(); + try { + long startTime = System.nanoTime(); + lock.lockInterruptibly(); + while (this.queue.drainTo(rs, bufferSize) <= 0) { + notEmpty.await(200L, TimeUnit.MILLISECONDS); + } + waitReaderTime += System.nanoTime() - startTime; + int bytes = getRecordBytes(rs); + memoryBytes.addAndGet(-bytes); + notInsufficient.signalAll(); + } catch (InterruptedException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, e); + } finally { + lock.unlock(); + } + } + + private int getRecordBytes(Collection rs){ + int bytes = 0; + for(Record r : rs){ + bytes += r.getMemorySize(); + } + return bytes; + } + + @Override + public int size() { + return this.queue.size(); + } + + @Override + public boolean isEmpty() { + return this.queue.isEmpty(); + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/exchanger/BufferedRecordExchanger.java b/core/src/main/java/com/alibaba/datax/core/transport/exchanger/BufferedRecordExchanger.java new file mode 100755 index 000000000..4ea4902dd --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/exchanger/BufferedRecordExchanger.java @@ -0,0 +1,156 @@ +package com.alibaba.datax.core.transport.exchanger; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.record.TerminateRecord; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.Validate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class BufferedRecordExchanger implements RecordSender, RecordReceiver { + + private final Channel channel; + + private final Configuration configuration; + + private final List buffer; + + private int bufferSize ; + + protected final int byteCapacity; + + private final AtomicInteger memoryBytes = new AtomicInteger(0); + + private int bufferIndex = 0; + + private static Class RECORD_CLASS; + + private volatile boolean shutdown = false; + + private final TaskPluginCollector pluginCollector; + + @SuppressWarnings("unchecked") + public BufferedRecordExchanger(final Channel channel, final TaskPluginCollector pluginCollector) { + assert null != channel; + assert null != channel.getConfiguration(); + + this.channel = channel; + this.pluginCollector = pluginCollector; + this.configuration = channel.getConfiguration(); + + this.bufferSize = configuration + .getInt(CoreConstant.DATAX_CORE_TRANSPORT_EXCHANGER_BUFFERSIZE); + this.buffer = new ArrayList(bufferSize); + + //channel的queue默认大小为8M,原来为64M + this.byteCapacity = configuration.getInt( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE, 8 * 1024 * 1024); + + try { + BufferedRecordExchanger.RECORD_CLASS = ((Class) Class + .forName(configuration.getString( + CoreConstant.DATAX_CORE_TRANSPORT_RECORD_CLASS, + "com.alibaba.datax.core.transport.record.DefaultRecord"))); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, e); + } + } + + @Override + public Record createRecord() { + try { + return BufferedRecordExchanger.RECORD_CLASS.newInstance(); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, e); + } + } + + @Override + public void sendToWriter(Record record) { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + + Validate.notNull(record, "record不能为空."); + + if (record.getMemorySize() > this.byteCapacity) { + this.pluginCollector.collectDirtyRecord(record, new Exception(String.format("单条记录超过大小限制,当前限制为:%s", this.byteCapacity))); + return; + } + + boolean isFull = (this.bufferIndex >= this.bufferSize || this.memoryBytes.get() + record.getMemorySize() > this.byteCapacity); + if (isFull) { + flush(); + } + + this.buffer.add(record); + this.bufferIndex++; + memoryBytes.addAndGet(record.getMemorySize()); + } + + @Override + public void flush() { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + this.channel.pushAll(this.buffer); + this.buffer.clear(); + this.bufferIndex = 0; + this.memoryBytes.set(0); + } + + @Override + public void terminate() { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + flush(); + this.channel.pushTerminate(TerminateRecord.get()); + } + + @Override + public Record getFromReader() { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + boolean isEmpty = (this.bufferIndex >= this.buffer.size()); + if (isEmpty) { + receive(); + } + + Record record = this.buffer.get(this.bufferIndex++); + if (record instanceof TerminateRecord) { + record = null; + } + return record; + } + + @Override + public void shutdown(){ + shutdown = true; + try{ + buffer.clear(); + channel.clear(); + }catch(Throwable t){ + t.printStackTrace(); + } + } + + private void receive() { + this.channel.pullAll(this.buffer); + this.bufferIndex = 0; + this.bufferSize = this.buffer.size(); + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/exchanger/RecordExchanger.java b/core/src/main/java/com/alibaba/datax/core/transport/exchanger/RecordExchanger.java new file mode 100755 index 000000000..ed236173a --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/exchanger/RecordExchanger.java @@ -0,0 +1,99 @@ +/** + * (C) 2010-2014 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.core.transport.exchanger; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.record.TerminateRecord; + +public class RecordExchanger implements RecordSender, RecordReceiver { + + private Channel channel; + + private Configuration configuration; + + private static Class RECORD_CLASS; + + private volatile boolean shutdown = false; + + @SuppressWarnings("unchecked") + public RecordExchanger(final Channel channel) { + assert channel != null; + this.channel = channel; + this.configuration = channel.getConfiguration(); + try { + RecordExchanger.RECORD_CLASS = (Class) Class + .forName(configuration.getString( + CoreConstant.DATAX_CORE_TRANSPORT_RECORD_CLASS, + "com.alibaba.datax.core.transport.record.DefaultRecord")); + } catch (ClassNotFoundException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, e); + } + } + + @Override + public Record getFromReader() { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + Record record = this.channel.pull(); + return (record instanceof TerminateRecord ? null : record); + } + + @Override + public Record createRecord() { + try { + return RECORD_CLASS.newInstance(); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.CONFIG_ERROR, e); + } + } + + @Override + public void sendToWriter(Record record) { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + this.channel.push(record); + } + + @Override + public void flush() { + } + + @Override + public void terminate() { + if(shutdown){ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + this.channel.pushTerminate(TerminateRecord.get()); + } + + @Override + public void shutdown(){ + shutdown = true; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/record/DefaultRecord.java b/core/src/main/java/com/alibaba/datax/core/transport/record/DefaultRecord.java new file mode 100755 index 000000000..2598bc8c8 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/record/DefaultRecord.java @@ -0,0 +1,119 @@ +package com.alibaba.datax.core.transport.record; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.util.ClassSize; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by jingxing on 14-8-24. + */ + +public class DefaultRecord implements Record { + + private static final int RECORD_AVERGAE_COLUMN_NUMBER = 16; + + private List columns; + + private int byteSize; + + // 首先是Record本身需要的内存 + private int memorySize = ClassSize.DefaultRecordHead; + + public DefaultRecord() { + this.columns = new ArrayList(RECORD_AVERGAE_COLUMN_NUMBER); + } + + @Override + public void addColumn(Column column) { + columns.add(column); + incrByteSize(column); + } + + @Override + public Column getColumn(int i) { + if (i < 0 || i >= columns.size()) { + return null; + } + return columns.get(i); + } + + @Override + public void setColumn(int i, final Column column) { + if (i < 0) { + throw DataXException.asDataXException(FrameworkErrorCode.ARGUMENT_ERROR, + "不能给index小于0的column设置值"); + } + + if (i >= columns.size()) { + expandCapacity(i + 1); + } + + decrByteSize(getColumn(i)); + this.columns.set(i, column); + incrByteSize(getColumn(i)); + } + + @Override + public String toString() { + Map json = new HashMap(); + json.put("size", this.getColumnNumber()); + json.put("data", this.columns); + return JSON.toJSONString(json); + } + + @Override + public int getColumnNumber() { + return this.columns.size(); + } + + @Override + public int getByteSize() { + return byteSize; + } + + public int getMemorySize(){ + return memorySize; + } + + private void decrByteSize(final Column column) { + if (null == column) { + return; + } + + byteSize -= column.getByteSize(); + + //内存的占用是column对象的头 再加实际大小 + memorySize = memorySize - ClassSize.ColumnHead - column.getByteSize(); + } + + private void incrByteSize(final Column column) { + if (null == column) { + return; + } + + byteSize += column.getByteSize(); + + //内存的占用是column对象的头 再加实际大小 + memorySize = memorySize + ClassSize.ColumnHead + column.getByteSize(); + } + + private void expandCapacity(int totalSize) { + if (totalSize <= 0) { + return; + } + + int needToExpand = totalSize - columns.size(); + while (needToExpand-- > 0) { + this.columns.add(null); + } + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/transport/record/TerminateRecord.java b/core/src/main/java/com/alibaba/datax/core/transport/record/TerminateRecord.java new file mode 100755 index 000000000..928609abd --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/transport/record/TerminateRecord.java @@ -0,0 +1,48 @@ +package com.alibaba.datax.core.transport.record; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; + +/** + * 作为标示 生产者已经完成生产的标志 + * + */ +public class TerminateRecord implements Record { + private final static TerminateRecord SINGLE = new TerminateRecord(); + + private TerminateRecord() { + } + + public static TerminateRecord get() { + return SINGLE; + } + + @Override + public void addColumn(Column column) { + } + + @Override + public Column getColumn(int i) { + return null; + } + + @Override + public int getColumnNumber() { + return 0; + } + + @Override + public int getByteSize() { + return 0; + } + + @Override + public int getMemorySize() { + return 0; + } + + @Override + public void setColumn(int i, Column column) { + return; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ClassSize.java b/core/src/main/java/com/alibaba/datax/core/util/ClassSize.java new file mode 100644 index 000000000..1be49addf --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ClassSize.java @@ -0,0 +1,42 @@ +package com.alibaba.datax.core.util; + +/** + * Created by liqiang on 15/12/12. + */ +public class ClassSize { + + public static final int DefaultRecordHead; + public static final int ColumnHead; + + //objectHead的大小 + public static final int REFERENCE; + public static final int OBJECT; + public static final int ARRAY; + public static final int ARRAYLIST; + static { + //only 64位 + REFERENCE = 8; + + OBJECT = 2 * REFERENCE; + + ARRAY = align(3 * REFERENCE); + + // 16+8+24+16 + ARRAYLIST = align(OBJECT + align(REFERENCE) + align(ARRAY) + + (2 * Long.SIZE / Byte.SIZE)); + // 8+64+8 + DefaultRecordHead = align(align(REFERENCE) + ClassSize.ARRAYLIST + 2 * Integer.SIZE / Byte.SIZE); + //16+4 + ColumnHead = align(2 * REFERENCE + Integer.SIZE / Byte.SIZE); + } + + public static int align(int num) { + return (int)(align((long)num)); + } + + public static long align(long num) { + //The 7 comes from that the alignSize is 8 which is the number of bytes + //stored and sent together + return ((num + 7) >> 3) << 3; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ClassUtil.java b/core/src/main/java/com/alibaba/datax/core/util/ClassUtil.java new file mode 100755 index 000000000..0cf0d5617 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ClassUtil.java @@ -0,0 +1,40 @@ +package com.alibaba.datax.core.util; + +import java.lang.reflect.Constructor; + +public final class ClassUtil { + + /** + * 通过反射构造类对象 + * + * @param className + * 反射的类名称 + * @param t + * 反射类的类型Class对象 + * @param args + * 构造参数 + * + * */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static T instantiate(String className, Class t, + Object... args) { + try { + Constructor constructor = (Constructor) Class.forName(className) + .getConstructor(ClassUtil.toClassType(args)); + return (T) constructor.newInstance(args); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + private static Class[] toClassType(Object[] args) { + Class[] clazzs = new Class[args.length]; + + for (int i = 0, length = args.length; i < length; i++) { + clazzs[i] = args[i].getClass(); + } + + return clazzs; + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ConfigParser.java b/core/src/main/java/com/alibaba/datax/core/util/ConfigParser.java new file mode 100755 index 000000000..dadef752b --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ConfigParser.java @@ -0,0 +1,181 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.http.client.methods.HttpGet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public final class ConfigParser { + private static final Logger LOG = LoggerFactory.getLogger(ConfigParser.class); + /** + * 指定Job配置路径,ConfigParser会解析Job、Plugin、Core全部信息,并以Configuration返回 + */ + public static Configuration parse(final String jobPath) { + Configuration configuration = ConfigParser.parseJobConfig(jobPath); + + configuration.merge( + ConfigParser.parseCoreConfig(CoreConstant.DATAX_CONF_PATH), + false); + // todo config优化,只捕获需要的plugin + String readerPluginName = configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_READER_NAME); + String writerPluginName = configuration.getString( + CoreConstant.DATAX_JOB_CONTENT_WRITER_NAME); + try { + configuration.merge(parsePluginConfig(Lists.newArrayList(readerPluginName, writerPluginName)), false); + }catch (Exception e){ + //吞掉异常,保持log干净。这里message足够。 + LOG.warn(String.format("插件[%s,%s]加载失败,1s后重试... Exception:%s ", readerPluginName, writerPluginName, e.getMessage())); + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + // + } + configuration.merge(parsePluginConfig(Lists.newArrayList(readerPluginName, writerPluginName)), false); + } + + return configuration; + } + + private static Configuration parseCoreConfig(final String path) { + return Configuration.from(new File(path)); + } + + public static Configuration parseJobConfig(final String path) { + String jobContent = getJobContent(path); + Configuration config = Configuration.from(jobContent); + + return SecretUtil.decryptSecretKey(config); + } + + private static String getJobContent(String jobResource) { + String jobContent; + + boolean isJobResourceFromHttp = jobResource.trim().toLowerCase().startsWith("http"); + + + if (isJobResourceFromHttp) { + //设置httpclient的 HTTP_TIMEOUT_INMILLIONSECONDS + Configuration coreConfig = ConfigParser.parseCoreConfig(CoreConstant.DATAX_CONF_PATH); + int httpTimeOutInMillionSeconds = coreConfig.getInt( + CoreConstant.DATAX_CORE_DATAXSERVER_TIMEOUT, 5000); + HttpClientUtil.setHttpTimeoutInMillionSeconds(httpTimeOutInMillionSeconds); + + HttpClientUtil httpClientUtil = new HttpClientUtil(); + try { + URL url = new URL(jobResource); + HttpGet httpGet = HttpClientUtil.getGetRequest(); + httpGet.setURI(url.toURI()); + + jobContent = httpClientUtil.executeAndGetWithFailedRetry(httpGet, 6, 1000l); + } catch (Exception e) { + throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, "获取作业配置信息失败:" + jobResource, e); + } + } else { + // jobResource 是本地文件绝对路径 + try { + jobContent = FileUtils.readFileToString(new File(jobResource)); + } catch (IOException e) { + throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, "获取作业配置信息失败:" + jobResource, e); + } + } + + if (jobContent == null) { + throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, "获取作业配置信息失败:" + jobResource); + } + return jobContent; + } + + private static Configuration parsePluginConfig(List wantPluginNames) { + Configuration configuration = Configuration.newDefault(); + + Set replicaCheckPluginSet = new HashSet(); + int complete = 0; + for (final String each : ConfigParser + .getDirAsList(CoreConstant.DATAX_PLUGIN_READER_HOME)) { + Configuration eachReaderConfig = ConfigParser.parseOnePluginConfig(each, "reader", replicaCheckPluginSet, wantPluginNames); + if(eachReaderConfig!=null) { + configuration.merge(eachReaderConfig, true); + complete += 1; + } + } + + for (final String each : ConfigParser + .getDirAsList(CoreConstant.DATAX_PLUGIN_WRITER_HOME)) { + Configuration eachWriterConfig = ConfigParser.parseOnePluginConfig(each, "writer", replicaCheckPluginSet, wantPluginNames); + if(eachWriterConfig!=null) { + configuration.merge(eachWriterConfig, true); + complete += 1; + } + } + + if (wantPluginNames != null && wantPluginNames.size() > 0 && wantPluginNames.size() != complete) { + throw DataXException.asDataXException(FrameworkErrorCode.PLUGIN_INIT_ERROR, "插件加载失败,未完成指定插件加载:" + wantPluginNames); + } + + return configuration; + } + + + public static Configuration parseOnePluginConfig(final String path, + final String type, + Set pluginSet, List wantPluginNames) { + String filePath = path + File.separator + "plugin.json"; + Configuration configuration = Configuration.from(new File(filePath)); + + String pluginPath = configuration.getString("path"); + String pluginName = configuration.getString("name"); + if(!pluginSet.contains(pluginName)) { + pluginSet.add(pluginName); + } else { + throw DataXException.asDataXException(FrameworkErrorCode.PLUGIN_INIT_ERROR, "插件加载失败,存在重复插件:" + filePath); + } + + //不是想要的插件,返回null + if (wantPluginNames != null && wantPluginNames.size() > 0 && !wantPluginNames.contains(pluginName)) { + return null; + } + + boolean isDefaultPath = StringUtils.isBlank(pluginPath); + if (isDefaultPath) { + configuration.set("path", path); + } + + Configuration result = Configuration.newDefault(); + + result.set( + String.format("plugin.%s.%s", type, pluginName), + configuration.getInternal()); + + return result; + } + + private static List getDirAsList(String path) { + List result = new ArrayList(); + + String[] paths = new File(path).list(); + if (null == paths) { + return result; + } + + for (final String each : paths) { + result.add(path + File.separator + each); + } + + return result; + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ConfigurationValidate.java b/core/src/main/java/com/alibaba/datax/core/util/ConfigurationValidate.java new file mode 100755 index 000000000..bc15bcf14 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ConfigurationValidate.java @@ -0,0 +1,33 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.util.Configuration; +import org.apache.commons.lang.Validate; + +/** + * Created by jingxing on 14-9-16. + * + * 对配置文件做整体检查 + */ +public class ConfigurationValidate { + public static void doValidate(Configuration allConfig) { + Validate.isTrue(allConfig!=null, ""); + + coreValidate(allConfig); + + pluginValidate(allConfig); + + jobValidate(allConfig); + } + + private static void coreValidate(Configuration allconfig) { + return; + } + + private static void pluginValidate(Configuration allConfig) { + return; + } + + private static void jobValidate(Configuration allConfig) { + return; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ErrorRecordChecker.java b/core/src/main/java/com/alibaba/datax/core/util/ErrorRecordChecker.java new file mode 100755 index 000000000..ad7f80f61 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ErrorRecordChecker.java @@ -0,0 +1,82 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 检查任务是否到达错误记录限制。有检查条数(recordLimit)和百分比(percentageLimit)两种方式。 + * 1. errorRecord表示出错条数不能大于限制数,当超过时任务失败。比如errorRecord为0表示不容许任何脏数据。 + * 2. errorPercentage表示出错比例,在任务结束时校验。 + * 3. errorRecord优先级高于errorPercentage。 + */ +public final class ErrorRecordChecker { + private static final Logger LOG = LoggerFactory + .getLogger(ErrorRecordChecker.class); + + private Long recordLimit; + private Double percentageLimit; + + public ErrorRecordChecker(Configuration configuration) { + this(configuration.getLong(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_RECORD), + configuration.getDouble(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_PERCENT)); + } + + public ErrorRecordChecker(Long rec, Double percentage) { + recordLimit = rec; + percentageLimit = percentage; + + if (percentageLimit != null) { + Validate.isTrue(0.0 <= percentageLimit && percentageLimit <= 1.0, + "脏数据百分比限制应该在[0.0, 1.0]之间"); + } + + if (recordLimit != null) { + Validate.isTrue(recordLimit >= 0, + "脏数据条数现在应该为非负整数"); + + // errorRecord优先级高于errorPercentage. + percentageLimit = null; + } + } + + public void checkRecordLimit(Communication communication) { + if (recordLimit == null) { + return; + } + + long errorNumber = CommunicationTool.getTotalErrorRecords(communication); + if (recordLimit < errorNumber) { + LOG.debug( + String.format("Error-limit set to %d, error count check.", + recordLimit)); + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_DIRTY_DATA_LIMIT_EXCEED, + String.format("脏数据条数检查不通过,限制是[%d]条,但实际上捕获了[%d]条.", + recordLimit, errorNumber)); + } + } + + public void checkPercentageLimit(Communication communication) { + if (percentageLimit == null) { + return; + } + LOG.debug(String.format( + "Error-limit set to %f, error percent check.", percentageLimit)); + + long total = CommunicationTool.getTotalReadRecords(communication); + long error = CommunicationTool.getTotalErrorRecords(communication); + + if (total > 0 && ((double) error / (double) total) > percentageLimit) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_DIRTY_DATA_LIMIT_EXCEED, + String.format("脏数据百分比检查不通过,限制是[%f],但实际上捕获到[%f].", + percentageLimit, ((double) error / (double) total))); + } + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/ExceptionTracker.java b/core/src/main/java/com/alibaba/datax/core/util/ExceptionTracker.java new file mode 100755 index 000000000..d06f6798c --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/ExceptionTracker.java @@ -0,0 +1,15 @@ +package com.alibaba.datax.core.util; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ExceptionTracker { + public static final int STRING_BUFFER = 4096; + + public static String trace(Throwable ex) { + StringWriter sw = new StringWriter(STRING_BUFFER); + PrintWriter pw = new PrintWriter(sw); + ex.printStackTrace(pw); + return sw.toString(); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/datax/core/util/FrameworkErrorCode.java b/core/src/main/java/com/alibaba/datax/core/util/FrameworkErrorCode.java new file mode 100755 index 000000000..f50f79350 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/FrameworkErrorCode.java @@ -0,0 +1,68 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * TODO: 根据现有日志数据分析各类错误,进行细化。 + * + *

请不要格式化本类代码

+ */ +public enum FrameworkErrorCode implements ErrorCode { + + INSTALL_ERROR("Framework-00", "DataX引擎安装错误, 请联系您的运维解决 ."), + ARGUMENT_ERROR("Framework-01", "DataX引擎运行错误,该问题通常是由于内部编程错误引起,请联系DataX开发团队解决 ."), + RUNTIME_ERROR("Framework-02", "DataX引擎运行过程出错,具体原因请参看DataX运行结束时的错误诊断信息 ."), + CONFIG_ERROR("Framework-03", "DataX引擎配置错误,该问题通常是由于DataX安装错误引起,请联系您的运维解决 ."), + SECRET_ERROR("Framework-04", "DataX引擎加解密出错,该问题通常是由于DataX密钥配置错误引起,请联系您的运维解决 ."), + HOOK_LOAD_ERROR("Framework-05", "加载外部Hook出现错误,通常是由于DataX安装引起的"), + HOOK_FAIL_ERROR("Framework-06", "执行外部Hook出现错误"), + + PLUGIN_INSTALL_ERROR("Framework-10", "DataX插件安装错误, 该问题通常是由于DataX安装错误引起,请联系您的运维解决 ."), + PLUGIN_NOT_FOUND("Framework-11", "DataX插件配置错误, 该问题通常是由于DataX安装错误引起,请联系您的运维解决 ."), + PLUGIN_INIT_ERROR("Framework-12", "DataX插件初始化错误, 该问题通常是由于DataX安装错误引起,请联系您的运维解决 ."), + PLUGIN_RUNTIME_ERROR("Framework-13", "DataX插件运行时出错, 具体原因请参看DataX运行结束时的错误诊断信息 ."), + PLUGIN_DIRTY_DATA_LIMIT_EXCEED("Framework-14", "DataX传输脏数据超过用户预期,该错误通常是由于源端数据存在较多业务脏数据导致,请仔细检查DataX汇报的脏数据日志信息, 或者您可以适当调大脏数据阈值 ."), + PLUGIN_SPLIT_ERROR("Framework-15", "DataX插件切分出错, 该问题通常是由于DataX各个插件编程错误引起,请联系DataX开发团队解决"), + KILL_JOB_TIMEOUT_ERROR("Framework-16", "kill 任务超时,请联系PE解决"), + START_TASKGROUP_ERROR("Framework-17", "taskGroup启动失败,请联系DataX开发团队解决"), + CALL_DATAX_SERVICE_FAILED("Framework-18", "请求 DataX Service 出错."), + CALL_REMOTE_FAILED("Framework-19", "远程调用失败"), + KILLED_EXIT_VALUE("Framework-143", "Job 收到了 Kill 命令."); + + private final String code; + + private final String description; + + private FrameworkErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } + + /** + * 通过 "Framework-143" 来标示 任务是 Killed 状态 + */ + public int toExitValue() { + if (this == FrameworkErrorCode.KILLED_EXIT_VALUE) { + return 143; + } else { + return 1; + } + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/HttpClientUtil.java b/core/src/main/java/com/alibaba/datax/core/util/HttpClientUtil.java new file mode 100755 index 000000000..bc1f93a94 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/HttpClientUtil.java @@ -0,0 +1,169 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.RetryUtil; +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.*; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ThreadPoolExecutor; + + +public class HttpClientUtil { + + private static CredentialsProvider provider; + + private CloseableHttpClient httpClient; + + private volatile static HttpClientUtil clientUtil; + + //构建httpclient的时候一定要设置这两个参数。淘宝很多生产故障都由此引起 + private static int HTTP_TIMEOUT_INMILLIONSECONDS = 5000; + + private static final int POOL_SIZE = 20; + + private static ThreadPoolExecutor asyncExecutor = RetryUtil.createThreadPoolExecutor(); + + public static void setHttpTimeoutInMillionSeconds(int httpTimeoutInMillionSeconds) { + HTTP_TIMEOUT_INMILLIONSECONDS = httpTimeoutInMillionSeconds; + } + + public static synchronized HttpClientUtil getHttpClientUtil() { + if (null == clientUtil) { + synchronized (HttpClientUtil.class) { + if (null == clientUtil) { + clientUtil = new HttpClientUtil(); + } + } + } + return clientUtil; + } + + public HttpClientUtil() { + Properties prob = SecretUtil.getSecurityProperties(); + HttpClientUtil.setBasicAuth(prob.getProperty("auth.user"),prob.getProperty("auth.pass")); + initApacheHttpClient(); + } + + public void destroy() { + destroyApacheHttpClient(); + } + + public static void setBasicAuth(String username, String password) { + provider = new BasicCredentialsProvider(); + provider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(username,password)); + } + + // 创建包含connection pool与超时设置的client + private void initApacheHttpClient() { + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(HTTP_TIMEOUT_INMILLIONSECONDS) + .setConnectTimeout(HTTP_TIMEOUT_INMILLIONSECONDS).setConnectionRequestTimeout(HTTP_TIMEOUT_INMILLIONSECONDS) + .setStaleConnectionCheckEnabled(true).build(); + + if(null == provider) { + httpClient = HttpClientBuilder.create().setMaxConnTotal(POOL_SIZE).setMaxConnPerRoute(POOL_SIZE) + .setDefaultRequestConfig(requestConfig).build(); + } else { + httpClient = HttpClientBuilder.create().setMaxConnTotal(POOL_SIZE).setMaxConnPerRoute(POOL_SIZE) + .setDefaultRequestConfig(requestConfig).setDefaultCredentialsProvider(provider).build(); + } + } + + private void destroyApacheHttpClient() { + try { + if (httpClient != null) { + httpClient.close(); + httpClient = null; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static HttpGet getGetRequest() { + return new HttpGet(); + } + + public static HttpPost getPostRequest() { + return new HttpPost(); + } + + public static HttpPut getPutRequest() { + return new HttpPut(); + } + + public static HttpDelete getDeleteRequest() { + return new HttpDelete(); + } + + public String executeAndGet(HttpRequestBase httpRequestBase) throws Exception { + HttpResponse response; + String entiStr = ""; + try { + response = httpClient.execute(httpRequestBase); + + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + System.err.println("请求地址:" + httpRequestBase.getURI() + ", 请求方法:" + httpRequestBase.getMethod() + + ",STATUS CODE = " + response.getStatusLine().getStatusCode()); + + throw new Exception("Response Status Code : " + response.getStatusLine().getStatusCode()); + } else { + HttpEntity entity = response.getEntity(); + if (entity != null) { + entiStr = EntityUtils.toString(entity, Consts.UTF_8); + } else { + throw new Exception("Response Entity Is Null"); + } + } + } catch (Exception e) { + throw e; + } + + return entiStr; + } + + public String executeAndGetWithRetry(final HttpRequestBase httpRequestBase, final int retryTimes, final long retryInterval) { + try { + return RetryUtil.asyncExecuteWithRetry(new Callable() { + @Override + public String call() throws Exception { + return executeAndGet(httpRequestBase); + } + }, retryTimes, retryInterval, true, HTTP_TIMEOUT_INMILLIONSECONDS + 1000, asyncExecutor); + } catch (Exception e) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, e); + } + } + + public String executeAndGetWithFailedRetry(final HttpRequestBase httpRequestBase, final int retryTimes, final long retryInterval){ + try { + return RetryUtil.asyncExecuteWithRetry(new Callable() { + @Override + public String call() throws Exception { + String result = executeAndGet(httpRequestBase); + if(result!=null && result.startsWith("{\"result\":-1")){ + throw DataXException.asDataXException(FrameworkErrorCode.CALL_REMOTE_FAILED, "远程接口返回-1,将重试"); + } + return result; + } + }, retryTimes, retryInterval, true, HTTP_TIMEOUT_INMILLIONSECONDS + 1000, asyncExecutor); + } catch (Exception e) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, e); + } + } + +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/SecretUtil.java b/core/src/main/java/com/alibaba/datax/core/util/SecretUtil.java new file mode 100755 index 000000000..a9f69479c --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/SecretUtil.java @@ -0,0 +1,440 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.container.CoreConstant; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.commons.lang3.tuple.Triple; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Created by jingxing on 14/12/15. + */ +public class SecretUtil { + private static Properties properties; + + //RSA Key:keyVersion value:left:privateKey, right:publicKey, middle: type + //DESede Key: keyVersion value:left:keyContent, right:keyContent, middle: type + private static Map> versionKeyMap; + + private static final String ENCODING = "UTF-8"; + + public static final String KEY_ALGORITHM_RSA = "RSA"; + + public static final String KEY_ALGORITHM_3DES = "DESede"; + + private static final String CIPHER_ALGORITHM_3DES = "DESede/ECB/PKCS5Padding"; + + private static final Base64 base64 = new Base64(); + + /** + * BASE64加密 + * + * @param plaintextBytes + * @return + * @throws Exception + */ + public static String encryptBASE64(byte[] plaintextBytes) throws Exception { + return new String(base64.encode(plaintextBytes), ENCODING); + } + + /** + * BASE64解密 + * + * @param cipherText + * @return + * @throws Exception + */ + public static byte[] decryptBASE64(String cipherText) { + return base64.decode(cipherText); + } + + /** + * 加密
+ * @param data 裸的原始数据 + * @param key 经过base64加密的公钥(RSA)或者裸密钥(3DES) + * */ + public static String encrypt(String data, String key, String method) { + if (SecretUtil.KEY_ALGORITHM_RSA.equals(method)) { + return SecretUtil.encryptRSA(data, key); + } else if (SecretUtil.KEY_ALGORITHM_3DES.equals(method)) { + return SecretUtil.encrypt3DES(data, key); + } else { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("系统编程错误,不支持的加密类型", method)); + } + } + + /** + * 解密
+ * @param data 已经经过base64加密的密文 + * @param key 已经经过base64加密私钥(RSA)或者裸密钥(3DES) + * */ + public static String decrypt(String data, String key, String method) { + if (SecretUtil.KEY_ALGORITHM_RSA.equals(method)) { + return SecretUtil.decryptRSA(data, key); + } else if (SecretUtil.KEY_ALGORITHM_3DES.equals(method)) { + return SecretUtil.decrypt3DES(data, key); + } else { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("系统编程错误,不支持的加密类型", method)); + } + } + + /** + * 加密
+ * 用公钥加密 encryptByPublicKey + * + * @param data 裸的原始数据 + * @param key 经过base64加密的公钥 + * @return 结果也采用base64加密 + * @throws Exception + */ + public static String encryptRSA(String data, String key) { + try { + // 对公钥解密,公钥被base64加密过 + byte[] keyBytes = decryptBASE64(key); + + // 取得公钥 + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); + Key publicKey = keyFactory.generatePublic(x509KeySpec); + + // 对数据加密 + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + + return encryptBASE64(cipher.doFinal(data.getBytes(ENCODING))); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "rsa加密出错", e); + } + } + + /** + * 解密
+ * 用私钥解密 + * + * @param data 已经经过base64加密的密文 + * @param key 已经经过base64加密私钥 + * @return + * @throws Exception + */ + public static String decryptRSA(String data, String key) { + try { + // 对密钥解密 + byte[] keyBytes = decryptBASE64(key); + + // 取得私钥 + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); + Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); + + // 对数据解密 + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + + return new String(cipher.doFinal(decryptBASE64(data)), ENCODING); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "rsa解密出错", e); + } + } + + /** + * 初始化密钥 for RSA ALGORITHM + * + * @return + * @throws Exception + */ + public static String[] initKey() throws Exception { + KeyPairGenerator keyPairGen = KeyPairGenerator + .getInstance(KEY_ALGORITHM_RSA); + keyPairGen.initialize(1024); + + KeyPair keyPair = keyPairGen.generateKeyPair(); + + // 公钥 + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + + // 私钥 + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + + String[] publicAndPrivateKey = { + encryptBASE64(publicKey.getEncoded()), + encryptBASE64(privateKey.getEncoded())}; + + return publicAndPrivateKey; + } + + /** + * 加密 DESede
+ * 用密钥加密 + * + * @param data 裸的原始数据 + * @param key 加密的密钥 + * @return 结果也采用base64加密 + * @throws Exception + */ + public static String encrypt3DES(String data, String key) { + try { + // 生成密钥 + SecretKey desKey = new SecretKeySpec(build3DesKey(key), + KEY_ALGORITHM_3DES); + // 对数据加密 + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_3DES); + cipher.init(Cipher.ENCRYPT_MODE, desKey); + return encryptBASE64(cipher.doFinal(data.getBytes(ENCODING))); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "3重DES加密出错", e); + } + } + + /** + * 解密
+ * 用密钥解密 + * + * @param data 已经经过base64加密的密文 + * @param key 解密的密钥 + * @return + * @throws Exception + */ + public static String decrypt3DES(String data, String key) { + try { + // 生成密钥 + SecretKey desKey = new SecretKeySpec(build3DesKey(key), + KEY_ALGORITHM_3DES); + // 对数据解密 + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_3DES); + cipher.init(Cipher.DECRYPT_MODE, desKey); + return new String(cipher.doFinal(decryptBASE64(data)), ENCODING); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "rsa解密出错", e); + } + } + + /** + * 根据字符串生成密钥字节数组 + * + * @param keyStr + * 密钥字符串 + * @return key 符合DESede标准的24byte数组 + */ + private static byte[] build3DesKey(String keyStr) { + try { + // 声明一个24位的字节数组,默认里面都是0,warn: 字符串0(48)和数组默认值0不一样,统一字符串0(48) + byte[] key = "000000000000000000000000".getBytes(ENCODING); + byte[] temp = keyStr.getBytes(ENCODING); + if (key.length > temp.length) { + // 如果temp不够24位,则拷贝temp数组整个长度的内容到key数组中 + System.arraycopy(temp, 0, key, 0, temp.length); + } else { + // 如果temp大于24位,则拷贝temp数组24个长度的内容到key数组中 + System.arraycopy(temp, 0, key, 0, key.length); + } + return key; + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "构建三重DES密匙出错", e); + } + } + + public static synchronized Properties getSecurityProperties() { + if (properties == null) { + InputStream secretStream; + try { + secretStream = new FileInputStream( + CoreConstant.DATAX_SECRET_PATH); + } catch (FileNotFoundException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + "DataX配置要求加解密,但无法找到密钥的配置文件"); + } + + properties = new Properties(); + try { + properties.load(secretStream); + secretStream.close(); + } catch (IOException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "读取加解密配置文件出错", e); + } + } + + return properties; + } + + + public static Configuration encryptSecretKey(Configuration configuration) { + String keyVersion = configuration + .getString(CoreConstant.DATAX_JOB_SETTING_KEYVERSION); + // 没有设置keyVersion,表示不用解密 + if (StringUtils.isBlank(keyVersion)) { + return configuration; + } + + Map> versionKeyMap = getPrivateKeyMap(); + + if (null == versionKeyMap.get(keyVersion)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("DataX配置的密钥版本为[%s],但在系统中没有配置,任务密钥配置错误,不存在您配置的密钥版本", keyVersion)); + } + + String key = versionKeyMap.get(keyVersion).getRight(); + String method = versionKeyMap.get(keyVersion).getMiddle(); + // keyVersion要求的私钥没有配置 + if (StringUtils.isBlank(key)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("DataX配置的密钥版本为[%s],但在系统中没有配置,可能是任务密钥配置错误,也可能是系统维护问题", keyVersion)); + } + + String tempEncrptedData = null; + for (String path : configuration.getSecretKeyPathSet()) { + tempEncrptedData = SecretUtil.encrypt(configuration.getString(path), key, method); + int lastPathIndex = path.lastIndexOf(".") + 1; + String lastPathKey = path.substring(lastPathIndex); + + String newPath = path.substring(0, lastPathIndex) + "*" + + lastPathKey; + configuration.set(newPath, tempEncrptedData); + configuration.remove(path); + } + + return configuration; + } + + public static Configuration decryptSecretKey(Configuration config) { + String keyVersion = config + .getString(CoreConstant.DATAX_JOB_SETTING_KEYVERSION); + // 没有设置keyVersion,表示不用解密 + if (StringUtils.isBlank(keyVersion)) { + return config; + } + + Map> versionKeyMap = getPrivateKeyMap(); + if (null == versionKeyMap.get(keyVersion)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("DataX配置的密钥版本为[%s],但在系统中没有配置,任务密钥配置错误,不存在您配置的密钥版本", keyVersion)); + } + String decryptKey = versionKeyMap.get(keyVersion).getLeft(); + String method = versionKeyMap.get(keyVersion).getMiddle(); + // keyVersion要求的私钥没有配置 + if (StringUtils.isBlank(decryptKey)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + String.format("DataX配置的密钥版本为[%s],但在系统中没有配置,可能是任务密钥配置错误,也可能是系统维护问题", keyVersion)); + } + + // 对包含*号key解密处理 + for (String key : config.getKeys()) { + int lastPathIndex = key.lastIndexOf(".") + 1; + String lastPathKey = key.substring(lastPathIndex); + if (lastPathKey.length() > 1 && lastPathKey.charAt(0) == '*' + && lastPathKey.charAt(1) != '*') { + Object value = config.get(key); + if (value instanceof String) { + String newKey = key.substring(0, lastPathIndex) + + lastPathKey.substring(1); + config.set(newKey, + SecretUtil.decrypt((String) value, decryptKey, method)); + config.addSecretKeyPath(newKey); + config.remove(key); + } + } + } + + return config; + } + + private static synchronized Map> getPrivateKeyMap() { + if (versionKeyMap == null) { + versionKeyMap = new HashMap>(); + Properties properties = SecretUtil.getSecurityProperties(); + + String[] serviceUsernames = new String[] { + CoreConstant.LAST_SERVICE_USERNAME, + CoreConstant.CURRENT_SERVICE_USERNAME }; + String[] servicePasswords = new String[] { + CoreConstant.LAST_SERVICE_PASSWORD, + CoreConstant.CURRENT_SERVICE_PASSWORD }; + + for (int i = 0; i < serviceUsernames.length; i++) { + String serviceUsername = properties + .getProperty(serviceUsernames[i]); + if (StringUtils.isNotBlank(serviceUsername)) { + String servicePassword = properties + .getProperty(servicePasswords[i]); + if (StringUtils.isNotBlank(servicePassword)) { + versionKeyMap.put(serviceUsername, ImmutableTriple.of( + servicePassword, SecretUtil.KEY_ALGORITHM_3DES, + servicePassword)); + } else { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, String.format( + "DataX配置要求加解密,但配置的密钥版本[%s]存在密钥为空的情况", + serviceUsername)); + } + } + } + + String[] keyVersions = new String[] { CoreConstant.LAST_KEYVERSION, + CoreConstant.CURRENT_KEYVERSION }; + String[] privateKeys = new String[] { CoreConstant.LAST_PRIVATEKEY, + CoreConstant.CURRENT_PRIVATEKEY }; + String[] publicKeys = new String[] { CoreConstant.LAST_PUBLICKEY, + CoreConstant.CURRENT_PUBLICKEY }; + for (int i = 0; i < keyVersions.length; i++) { + String keyVersion = properties.getProperty(keyVersions[i]); + if (StringUtils.isNotBlank(keyVersion)) { + String privateKey = properties.getProperty(privateKeys[i]); + String publicKey = properties.getProperty(publicKeys[i]); + if (StringUtils.isNotBlank(privateKey) + && StringUtils.isNotBlank(publicKey)) { + versionKeyMap.put(keyVersion, ImmutableTriple.of( + privateKey, SecretUtil.KEY_ALGORITHM_RSA, + publicKey)); + } else { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, String.format( + "DataX配置要求加解密,但配置的公私钥对存在为空的情况,版本[%s]", + keyVersion)); + } + } + } + } + if (versionKeyMap.size() <= 0) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "DataX配置要求加解密,但无法找到加解密配置"); + } + return versionKeyMap; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/container/ClassLoaderSwapper.java b/core/src/main/java/com/alibaba/datax/core/util/container/ClassLoaderSwapper.java new file mode 100755 index 000000000..b878cf090 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/container/ClassLoaderSwapper.java @@ -0,0 +1,41 @@ +package com.alibaba.datax.core.util.container; + +/** + * Created by jingxing on 14-8-29. + * + * 为避免jar冲突,比如hbase可能有多个版本的读写依赖jar包,JobContainer和TaskGroupContainer + * 就需要脱离当前classLoader去加载这些jar包,执行完成后,又退回到原来classLoader上继续执行接下来的代码 + */ +public final class ClassLoaderSwapper { + private ClassLoader storeClassLoader = null; + + private ClassLoaderSwapper() { + } + + public static ClassLoaderSwapper newCurrentThreadClassLoaderSwapper() { + return new ClassLoaderSwapper(); + } + + /** + * 保存当前classLoader,并将当前线程的classLoader设置为所给classLoader + * + * @param + * @return + */ + public ClassLoader setCurrentThreadClassLoader(ClassLoader classLoader) { + this.storeClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(classLoader); + return this.storeClassLoader; + } + + /** + * 将当前线程的类加载器设置为保存的类加载 + * @return + */ + public ClassLoader restoreCurrentThreadClassLoader() { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + Thread.currentThread().setContextClassLoader(this.storeClassLoader); + return classLoader; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/container/CoreConstant.java b/core/src/main/java/com/alibaba/datax/core/util/container/CoreConstant.java new file mode 100755 index 000000000..f45df47a7 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/container/CoreConstant.java @@ -0,0 +1,168 @@ +package com.alibaba.datax.core.util.container; + +import org.apache.commons.lang.StringUtils; + +import java.io.File; + +/** + * Created by jingxing on 14-8-25. + */ +public class CoreConstant { + // --------------------------- 全局使用的变量(最好按照逻辑顺序,调整下成员变量顺序) + // -------------------------------- + + public static final String DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL = "core.container.taskGroup.channel"; + + public static final String DATAX_CORE_CONTAINER_MODEL = "core.container.model"; + + public static final String DATAX_CORE_CONTAINER_JOB_ID = "core.container.job.id"; + + public static final String DATAX_CORE_CONTAINER_TRACE_ENABLE = "core.container.trace.enable"; + + public static final String DATAX_CORE_CONTAINER_JOB_MODE = "core.container.job.mode"; + + public static final String DATAX_CORE_CONTAINER_JOB_REPORTINTERVAL = "core.container.job.reportInterval"; + + public static final String DATAX_CORE_CONTAINER_JOB_SLEEPINTERVAL = "core.container.job.sleepInterval"; + + public static final String DATAX_CORE_CONTAINER_TASKGROUP_ID = "core.container.taskGroup.id"; + + public static final String DATAX_CORE_CONTAINER_TASKGROUP_SLEEPINTERVAL = "core.container.taskGroup.sleepInterval"; + + public static final String DATAX_CORE_CONTAINER_TASKGROUP_REPORTINTERVAL = "core.container.taskGroup.reportInterval"; + + public static final String DATAX_CORE_CONTAINER_TASK_FAILOVER_MAXRETRYTIMES = "core.container.task.failOver.maxRetryTimes"; + + public static final String DATAX_CORE_CONTAINER_TASK_FAILOVER_RETRYINTERVALINMSEC = "core.container.task.failOver.retryIntervalInMsec"; + + public static final String DATAX_CORE_CONTAINER_TASK_FAILOVER_MAXWAITINMSEC = "core.container.task.failOver.maxWaitInMsec"; + + public static final String DATAX_CORE_DATAXSERVER_ADDRESS = "core.dataXServer.address"; + + public static final String DATAX_CORE_DATAXSERVER_TIMEOUT = "core.dataXServer.timeout"; + + public static final String DATAX_CORE_REPORT_DATAX_LOG = "core.dataXServer.reportDataxLog"; + + public static final String DATAX_CORE_REPORT_DATAX_PERFLOG = "core.dataXServer.reportPerfLog"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_CLASS = "core.transport.channel.class"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY = "core.transport.channel.capacity"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE = "core.transport.channel.byteCapacity"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_SPEED_BYTE = "core.transport.channel.speed.byte"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_SPEED_RECORD = "core.transport.channel.speed.record"; + + public static final String DATAX_CORE_TRANSPORT_CHANNEL_FLOWCONTROLINTERVAL = "core.transport.channel.flowControlInterval"; + + public static final String DATAX_CORE_TRANSPORT_EXCHANGER_BUFFERSIZE = "core.transport.exchanger.bufferSize"; + + public static final String DATAX_CORE_TRANSPORT_RECORD_CLASS = "core.transport.record.class"; + + public static final String DATAX_CORE_STATISTICS_COLLECTOR_PLUGIN_TASKCLASS = "core.statistics.collector.plugin.taskClass"; + + public static final String DATAX_CORE_STATISTICS_COLLECTOR_PLUGIN_MAXDIRTYNUM = "core.statistics.collector.plugin.maxDirtyNumber"; + + public static final String DATAX_JOB_CONTENT_READER_NAME = "job.content[0].reader.name"; + + public static final String DATAX_JOB_CONTENT_READER_PARAMETER = "job.content[0].reader.parameter"; + + public static final String DATAX_JOB_CONTENT_WRITER_NAME = "job.content[0].writer.name"; + + public static final String DATAX_JOB_CONTENT_WRITER_PARAMETER = "job.content[0].writer.parameter"; + + public static final String DATAX_JOB_JOBINFO = "job.jobInfo"; + + public static final String DATAX_JOB_CONTENT = "job.content"; + + public static final String DATAX_JOB_SETTING_KEYVERSION = "job.setting.keyVersion"; + + public static final String DATAX_JOB_SETTING_SPEED_BYTE = "job.setting.speed.byte"; + + public static final String DATAX_JOB_SETTING_SPEED_RECORD = "job.setting.speed.record"; + + public static final String DATAX_JOB_SETTING_SPEED_CHANNEL = "job.setting.speed.channel"; + + public static final String DATAX_JOB_SETTING_ERRORLIMIT = "job.setting.errorLimit"; + + public static final String DATAX_JOB_SETTING_ERRORLIMIT_RECORD = "job.setting.errorLimit.record"; + + public static final String DATAX_JOB_SETTING_ERRORLIMIT_PERCENT = "job.setting.errorLimit.percentage"; + + public static final String DATAX_JOB_SETTING_DRYRUN = "job.setting.dryRun"; + + public static final String DATAX_JOB_PREHANDLER_PLUGINTYPE = "job.preHandler.pluginType"; + + public static final String DATAX_JOB_PREHANDLER_PLUGINNAME = "job.preHandler.pluginName"; + + public static final String DATAX_JOB_POSTHANDLER_PLUGINTYPE = "job.postHandler.pluginType"; + + public static final String DATAX_JOB_POSTHANDLER_PLUGINNAME = "job.postHandler.pluginName"; + // ----------------------------- 局部使用的变量 + public static final String JOB_WRITER = "reader"; + + public static final String JOB_READER = "reader"; + + public static final String JOB_READER_NAME = "reader.name"; + + public static final String JOB_READER_PARAMETER = "reader.parameter"; + + public static final String JOB_WRITER_NAME = "writer.name"; + + public static final String JOB_WRITER_PARAMETER = "writer.parameter"; + + public static final String TASK_ID = "taskId"; + + // ----------------------------- 安全模块变量 ------------------ + + public static final String LAST_KEYVERSION = "last.keyVersion"; + + public static final String LAST_PUBLICKEY = "last.publicKey"; + + public static final String LAST_PRIVATEKEY = "last.privateKey"; + + public static final String LAST_SERVICE_USERNAME = "last.service.username"; + + public static final String LAST_SERVICE_PASSWORD = "last.service.password"; + + public static final String CURRENT_KEYVERSION = "current.keyVersion"; + + public static final String CURRENT_PUBLICKEY = "current.publicKey"; + + public static final String CURRENT_PRIVATEKEY = "current.privateKey"; + + public static final String CURRENT_SERVICE_USERNAME = "current.service.username"; + + public static final String CURRENT_SERVICE_PASSWORD = "current.service.password"; + + // ----------------------------- 环境变量 --------------------------------- + + public static String DATAX_HOME = System.getProperty("datax.home"); + + public static String DATAX_CONF_PATH = StringUtils.join(new String[] { + DATAX_HOME, "conf", "core.json" }, File.separator); + + public static String DATAX_CONF_LOG_PATH = StringUtils.join(new String[] { + DATAX_HOME, "conf", "logback.xml" }, File.separator); + + public static String DATAX_SECRET_PATH = StringUtils.join(new String[] { + DATAX_HOME, "conf", ".secret.properties" }, File.separator); + + public static String DATAX_PLUGIN_HOME = StringUtils.join(new String[] { + DATAX_HOME, "plugin" }, File.separator); + + public static String DATAX_PLUGIN_READER_HOME = StringUtils.join( + new String[] { DATAX_HOME, "plugin", "reader" }, File.separator); + + public static String DATAX_PLUGIN_WRITER_HOME = StringUtils.join( + new String[] { DATAX_HOME, "plugin", "writer" }, File.separator); + + public static String DATAX_BIN_HOME = StringUtils.join(new String[] { + DATAX_HOME, "bin" }, File.separator); + + public static String DATAX_JOB_HOME = StringUtils.join(new String[] { + DATAX_HOME, "job" }, File.separator); + +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/container/JarLoader.java b/core/src/main/java/com/alibaba/datax/core/util/container/JarLoader.java new file mode 100755 index 000000000..9fc113dc6 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/container/JarLoader.java @@ -0,0 +1,97 @@ +package com.alibaba.datax.core.util.container; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; + +import java.io.File; +import java.io.FileFilter; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +/** + * 提供Jar隔离的加载机制,会把传入的路径、及其子路径、以及路径中的jar文件加入到class path。 + */ +public class JarLoader extends URLClassLoader { + public JarLoader(String[] paths) { + this(paths, JarLoader.class.getClassLoader()); + } + + public JarLoader(String[] paths, ClassLoader parent) { + super(getURLs(paths), parent); + } + + private static URL[] getURLs(String[] paths) { + Validate.isTrue(null != paths && 0 != paths.length, + "jar包路径不能为空."); + + List dirs = new ArrayList(); + for (String path : paths) { + dirs.add(path); + JarLoader.collectDirs(path, dirs); + } + + List urls = new ArrayList(); + for (String path : dirs) { + urls.addAll(doGetURLs(path)); + } + + return urls.toArray(new URL[0]); + } + + private static void collectDirs(String path, List collector) { + if (null == path || StringUtils.isBlank(path)) { + return; + } + + File current = new File(path); + if (!current.exists() || !current.isDirectory()) { + return; + } + + for (File child : current.listFiles()) { + if (!child.isDirectory()) { + continue; + } + + collector.add(child.getAbsolutePath()); + collectDirs(child.getAbsolutePath(), collector); + } + } + + private static List doGetURLs(final String path) { + Validate.isTrue(!StringUtils.isBlank(path), "jar包路径不能为空."); + + File jarPath = new File(path); + + Validate.isTrue(jarPath.exists() && jarPath.isDirectory(), + "jar包路径必须存在且为目录."); + + /* set filter */ + FileFilter jarFilter = new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().endsWith(".jar"); + } + }; + + /* iterate all jar */ + File[] allJars = new File(path).listFiles(jarFilter); + List jarURLs = new ArrayList(allJars.length); + + for (int i = 0; i < allJars.length; i++) { + try { + jarURLs.add(allJars[i].toURI().toURL()); + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_INIT_ERROR, + "系统加载jar包出错", e); + } + } + + return jarURLs; + } +} diff --git a/core/src/main/java/com/alibaba/datax/core/util/container/LoadUtil.java b/core/src/main/java/com/alibaba/datax/core/util/container/LoadUtil.java new file mode 100755 index 000000000..30e926c38 --- /dev/null +++ b/core/src/main/java/com/alibaba/datax/core/util/container/LoadUtil.java @@ -0,0 +1,202 @@ +package com.alibaba.datax.core.util.container; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.AbstractJobPlugin; +import com.alibaba.datax.common.plugin.AbstractPlugin; +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.taskgroup.runner.AbstractRunner; +import com.alibaba.datax.core.taskgroup.runner.ReaderRunner; +import com.alibaba.datax.core.taskgroup.runner.WriterRunner; +import com.alibaba.datax.core.util.FrameworkErrorCode; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by jingxing on 14-8-24. + *

+ * 插件加载器,大体上分reader、transformer(还未实现)和writer三中插件类型, + * reader和writer在执行时又可能出现Job和Task两种运行时(加载的类不同) + */ +public class LoadUtil { + private static final String pluginTypeNameFormat = "plugin.%s.%s"; + + private LoadUtil() { + } + + private enum ContainerType { + Job("Job"), Task("Task"); + private String type; + + private ContainerType(String type) { + this.type = type; + } + + public String value() { + return type; + } + } + + /** + * 所有插件配置放置在pluginRegisterCenter中,为区别reader、transformer和writer,还能区别 + * 具体pluginName,故使用pluginType.pluginName作为key放置在该map中 + */ + private static Configuration pluginRegisterCenter; + + /** + * jarLoader的缓冲 + */ + private static Map jarLoaderCenter = new HashMap(); + + /** + * 设置pluginConfigs,方便后面插件来获取 + * + * @param pluginConfigs + */ + public static void bind(Configuration pluginConfigs) { + pluginRegisterCenter = pluginConfigs; + } + + private static String generatePluginKey(PluginType pluginType, + String pluginName) { + return String.format(pluginTypeNameFormat, pluginType.toString(), + pluginName); + } + + private static Configuration getPluginConf(PluginType pluginType, + String pluginName) { + Configuration pluginConf = pluginRegisterCenter + .getConfiguration(generatePluginKey(pluginType, pluginName)); + + if (null == pluginConf) { + throw DataXException.asDataXException( + FrameworkErrorCode.PLUGIN_INSTALL_ERROR, + String.format("DataX不能找到插件[%s]的配置.", + pluginName)); + } + + return pluginConf; + } + + /** + * 加载JobPlugin,reader、writer都可能要加载 + * + * @param pluginType + * @param pluginName + * @return + */ + public static AbstractJobPlugin loadJobPlugin(PluginType pluginType, + String pluginName) { + Class clazz = LoadUtil.loadPluginClass( + pluginType, pluginName, ContainerType.Job); + + try { + AbstractJobPlugin jobPlugin = (AbstractJobPlugin) clazz + .newInstance(); + jobPlugin.setPluginConf(getPluginConf(pluginType, pluginName)); + return jobPlugin; + } catch (Exception e) { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + String.format("DataX找到plugin[%s]的Job配置.", + pluginName), e); + } + } + + /** + * 加载taskPlugin,reader、writer都可能加载 + * + * @param pluginType + * @param pluginName + * @return + */ + public static AbstractTaskPlugin loadTaskPlugin(PluginType pluginType, + String pluginName) { + Class clazz = LoadUtil.loadPluginClass( + pluginType, pluginName, ContainerType.Task); + + try { + AbstractTaskPlugin taskPlugin = (AbstractTaskPlugin) clazz + .newInstance(); + taskPlugin.setPluginConf(getPluginConf(pluginType, pluginName)); + return taskPlugin; + } catch (Exception e) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + String.format("DataX不能找plugin[%s]的Task配置.", + pluginName), e); + } + } + + /** + * 根据插件类型、名字和执行时taskGroupId加载对应运行器 + * + * @param pluginType + * @param pluginName + * @return + */ + public static AbstractRunner loadPluginRunner(PluginType pluginType, String pluginName) { + AbstractTaskPlugin taskPlugin = LoadUtil.loadTaskPlugin(pluginType, + pluginName); + + switch (pluginType) { + case READER: + return new ReaderRunner(taskPlugin); + case WRITER: + return new WriterRunner(taskPlugin); + default: + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + String.format("插件[%s]的类型必须是[reader]或[writer]!", + pluginName)); + } + } + + /** + * 反射出具体plugin实例 + * + * @param pluginType + * @param pluginName + * @param pluginRunType + * @return + */ + @SuppressWarnings("unchecked") + private static synchronized Class loadPluginClass( + PluginType pluginType, String pluginName, + ContainerType pluginRunType) { + Configuration pluginConf = getPluginConf(pluginType, pluginName); + JarLoader jarLoader = LoadUtil.getJarLoader(pluginType, pluginName); + try { + return (Class) jarLoader + .loadClass(pluginConf.getString("class") + "$" + + pluginRunType.value()); + } catch (Exception e) { + throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, e); + } + } + + public static synchronized JarLoader getJarLoader(PluginType pluginType, + String pluginName) { + Configuration pluginConf = getPluginConf(pluginType, pluginName); + + JarLoader jarLoader = jarLoaderCenter.get(generatePluginKey(pluginType, + pluginName)); + if (null == jarLoader) { + String pluginPath = pluginConf.getString("path"); + if (StringUtils.isBlank(pluginPath)) { + throw DataXException.asDataXException( + FrameworkErrorCode.RUNTIME_ERROR, + String.format( + "%s插件[%s]路径非法!", + pluginType, pluginName)); + } + jarLoader = new JarLoader(new String[]{pluginPath}); + jarLoaderCenter.put(generatePluginKey(pluginType, pluginName), + jarLoader); + } + + return jarLoader; + } +} diff --git a/core/src/main/job/job.json b/core/src/main/job/job.json new file mode 100755 index 000000000..582065929 --- /dev/null +++ b/core/src/main/job/job.json @@ -0,0 +1,52 @@ +{ + "job": { + "setting": { + "speed": { + "byte":10485760 + }, + "errorLimit": { + "record": 0, + "percentage": 0.02 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column" : [ + { + "value": "DataX", + "type": "string" + }, + { + "value": 19890604, + "type": "long" + }, + { + "value": "1989-06-04 00:00:00", + "type": "date" + }, + { + "value": true, + "type": "bool" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 100000 + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": false, + "encoding": "UTF-8" + } + } + } + ] + } +} diff --git a/core/src/main/log/datax.log b/core/src/main/log/datax.log new file mode 100755 index 000000000..e69de29bb diff --git a/core/src/main/script/Readme.md b/core/src/main/script/Readme.md new file mode 100755 index 000000000..341f3f88d --- /dev/null +++ b/core/src/main/script/Readme.md @@ -0,0 +1 @@ +some script here. \ No newline at end of file diff --git a/core/src/main/tmp/readme.txt b/core/src/main/tmp/readme.txt new file mode 100755 index 000000000..74b233ce5 --- /dev/null +++ b/core/src/main/tmp/readme.txt @@ -0,0 +1,4 @@ +If you are developing DataX Plugin, In your Plugin you can use this directory to store temporary resources . + +NOTE: +Each time install DataX, this directory will be cleaned up ! \ No newline at end of file diff --git a/core/src/test/java/com/alibaba/datax/core/EngineTest.java b/core/src/test/java/com/alibaba/datax/core/EngineTest.java new file mode 100755 index 000000000..e5c8dd315 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/EngineTest.java @@ -0,0 +1,62 @@ +package com.alibaba.datax.core; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.util.ConfigParser; +import com.alibaba.datax.core.util.ExceptionTracker; +import com.alibaba.datax.core.util.container.LoadUtil; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileWriter; + +/** + * Created by jingxing on 14-9-25. + */ +public class EngineTest extends CaseInitializer { + private Configuration configuration; + + @Before + public void setUp() { + String path = EngineTest.class.getClassLoader().getResource(".") + .getFile(); + + this.configuration = ConfigParser.parse(path + File.separator + + "all.json"); + LoadUtil.bind(this.configuration); + } + + + public void test_entry() throws Throwable { + String jobConfig = this.configuration.toString(); + + String jobFile = "./job.json"; + FileWriter writer = new FileWriter(jobFile); + writer.write(jobConfig); + writer.flush(); + writer.close(); + String[] args = { "-job", jobFile, "-mode", "standalone" }; + + Engine.entry(args); + } + + @Test + public void testNN() { + try { + throwEE(); + } catch (Exception e) { + String tarce = ExceptionTracker.trace(e); + if(e instanceof NullPointerException) { + System.out.println(tarce); + } + } + } + + public static void throwEE() { + String aa = null; + aa.toString(); + //throw new NullPointerException(); + } + +} \ No newline at end of file diff --git a/core/src/test/java/com/alibaba/datax/core/constant/CoreConstantTest.java b/core/src/test/java/com/alibaba/datax/core/constant/CoreConstantTest.java new file mode 100755 index 000000000..9ebe86a8a --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/constant/CoreConstantTest.java @@ -0,0 +1,12 @@ +package com.alibaba.datax.core.constant; + +import com.alibaba.datax.core.util.container.CoreConstant; +import org.junit.Test; + +public class CoreConstantTest { + @Test + public void test() { + System.out.println(System.getProperties()); + System.out.println(CoreConstant.DATAX_PLUGIN_HOME); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/container/ClassLoaderSwapperTest.java b/core/src/test/java/com/alibaba/datax/core/container/ClassLoaderSwapperTest.java new file mode 100755 index 000000000..6c1d1ba47 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/container/ClassLoaderSwapperTest.java @@ -0,0 +1,23 @@ +package com.alibaba.datax.core.container; + +import com.alibaba.datax.core.util.container.ClassLoaderSwapper; +import org.junit.Assert; +import org.junit.Test; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Created by jingxing on 14-9-4. + */ +public class ClassLoaderSwapperTest { + @Test + public void test() { + ClassLoaderSwapper classLoaderSwapper = + ClassLoaderSwapper.newCurrentThreadClassLoaderSwapper(); + ClassLoader newClassLoader = new URLClassLoader(new URL[]{}); + classLoaderSwapper.setCurrentThreadClassLoader(newClassLoader); + Assert.assertTrue("", newClassLoader == + classLoaderSwapper.restoreCurrentThreadClassLoader()); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/container/JobAssignUtilTest.java b/core/src/test/java/com/alibaba/datax/core/container/JobAssignUtilTest.java new file mode 100755 index 000000000..f6b6e4383 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/container/JobAssignUtilTest.java @@ -0,0 +1,56 @@ +package com.alibaba.datax.core.container; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.container.util.JobAssignUtil; +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +public class JobAssignUtilTest { + @Test + public void test_01() { + Configuration configuration = Configuration.from(new File(JobAssignUtil.class.getResource("/job/job.json").getFile())); + configuration.set("job.content[0].taskId", 0); + configuration.set("job.content[1].taskId", 1); + System.out.println(configuration.beautify()); + int channelNumber = 3; + int channelsPerTaskGroup = 1; + List result = JobAssignUtil.assignFairly(configuration, channelNumber, channelsPerTaskGroup); + + System.out.println("==================================="); + for (Configuration conf : result) { + System.out.println(conf.beautify()); + System.out.println("----------------"); + } + + System.out.println(configuration); + } + + @Test + public void test_02() { + + String jobString = "{\"job\":{\"setting\":{},\"content\":[{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}},{\"reader\":{\"type\":\"fakereader\",\"parameter\":{}},\"writer\":{\"type\":\"fakewriter\",\"parameter\":{}}}]}}"; + + Configuration configuration = Configuration.from(jobString); + + int taskNumber = StringUtils.countMatches(jobString, "fakereader"); + System.out.println("taskNumber:" + taskNumber); + for (int i = 0; i < taskNumber; i++) { + configuration.set("job.content[" + i + "].taskId", i); + } +// System.out.println(configuration.beautify()); + int channelNumber = 13; + int channelsPerTaskGroup = 5; + List result = JobAssignUtil.assignFairly(configuration, channelNumber, channelsPerTaskGroup); + + System.out.println("==================================="); + for (Configuration conf : result) { + System.out.println(conf.beautify()); + System.out.println("----------------"); + } + +// System.out.println(configuration); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/container/JobContainerTest.java b/core/src/test/java/com/alibaba/datax/core/container/JobContainerTest.java new file mode 100755 index 000000000..7749f9a3e --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/container/JobContainerTest.java @@ -0,0 +1,369 @@ +package com.alibaba.datax.core.container; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.JobContainer; +import com.alibaba.datax.core.job.meta.ExecuteMode; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.util.ConfigParser; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.container.LoadUtil; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.powermock.api.mockito.PowerMockito; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class JobContainerTest extends CaseInitializer { + private Configuration configuration; + + @Before + public void setUp() { + String path = JobContainerTest.class.getClassLoader() + .getResource(".").getFile(); + + this.configuration = ConfigParser.parse(path + File.separator + + "all.json"); + LoadUtil.bind(this.configuration); + } + + /** + * standalone模式下点对点跑完全部流程 + */ + @Test + public void testStart() { + JobContainer jobContainer = new JobContainer( + this.configuration); + jobContainer.start(); + } + + @Test + public void testPreHandler() throws Exception { + JobContainer jobContainer = new JobContainer( + this.configuration); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("preHandle"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + + System.out.println(this.configuration.get("job.preHandler.test")); + Assert.assertEquals("writePreDone",this.configuration.get("job.preHandler.test")); + } + + @Test + public void testPostHandler() throws Exception { + JobContainer jobContainer = new JobContainer( + this.configuration); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("postHandle"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + + System.out.println(this.configuration.get("job.postHandler.test")); + Assert.assertEquals("writePostDone",this.configuration.get("job.postHandler.test")); + } + + @Test + public void testPreHandlerByReader() throws Exception { + + Configuration copyConfig = this.configuration.clone(); + copyConfig.set(CoreConstant.DATAX_JOB_PREHANDLER_PLUGINTYPE,"reader"); + copyConfig.set(CoreConstant.DATAX_JOB_PREHANDLER_PLUGINNAME,"fakereader"); + JobContainer jobContainer = new JobContainer( + copyConfig); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("preHandle"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + + System.out.println(copyConfig.get("job.preHandler.test")); + Assert.assertEquals("readPreDone",copyConfig.get("job.preHandler.test")); + } + + @Test + public void testPostHandlerByReader() throws Exception { + + Configuration copyConfig = this.configuration.clone(); + copyConfig.set(CoreConstant.DATAX_JOB_POSTHANDLER_PLUGINTYPE,"reader"); + copyConfig.set(CoreConstant.DATAX_JOB_POSTHANDLER_PLUGINNAME,"fakereader"); + JobContainer jobContainer = new JobContainer( + copyConfig); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("postHandle"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + + System.out.println(copyConfig.get("job.postHandler.test")); + Assert.assertEquals("readPostDone",copyConfig.get("job.postHandler.test")); + } + + @Test + public void testInitNormal() throws Exception { + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, -2); + this.configuration.set("runMode", ExecuteMode.STANDALONE.getValue()); + JobContainer jobContainer = new JobContainer( + this.configuration); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("init"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + Assert.assertEquals("default job id = 0", 0l, this.configuration + .getLong(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID) + .longValue()); + } + + @SuppressWarnings("unchecked") + @Test + public void testMergeReaderAndWriterSlicesConfigs() throws Exception { + JobContainer jobContainer = new JobContainer( + this.configuration); + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("init"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + initMethod.setAccessible(false); + + int splitNumber = 100; + List readerSplitConfigurations = new ArrayList(); + List writerSplitConfigurations = new ArrayList(); + for (int i = 0; i < splitNumber; i++) { + Configuration readerOneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format( + "jdbc:mysql://localhost:3305/db%04d", i)); + readerOneConfig.set("jdbcUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("jingxing_%04d", i)); + readerOneConfig.set("table", tableArray); + + readerSplitConfigurations.add(readerOneConfig); + + Configuration writerOneConfig = Configuration.newDefault(); + List odpsUrlArray = new ArrayList(); + odpsUrlArray.add(String.format("odps://localhost:3305/db%04d", i)); + writerOneConfig.set("jdbcUrl", odpsUrlArray); + + List odpsTableArray = new ArrayList(); + odpsTableArray.add(String.format("jingxing_%04d", i)); + writerOneConfig.set("table", odpsTableArray); + + writerSplitConfigurations.add(writerOneConfig); + } + + initMethod = jobContainer.getClass().getDeclaredMethod( + "mergeReaderAndWriterTaskConfigs", List.class, List.class); + initMethod.setAccessible(true); + + List mergedConfigs = (List) initMethod + .invoke(jobContainer, readerSplitConfigurations, writerSplitConfigurations); + + Assert.assertEquals("merge number equals to split number", splitNumber, + mergedConfigs.size()); + for (Configuration sliceConfig : mergedConfigs) { + Assert.assertNotNull("reader name not null", + sliceConfig.getString(CoreConstant.JOB_READER_NAME)); + Assert.assertNotNull("reader name not null", + sliceConfig.getString(CoreConstant.JOB_READER_PARAMETER)); + Assert.assertNotNull("reader name not null", + sliceConfig.getString(CoreConstant.JOB_WRITER_NAME)); + Assert.assertNotNull("reader name not null", + sliceConfig.getString(CoreConstant.JOB_WRITER_PARAMETER)); + Assert.assertTrue("has slice id", + sliceConfig.getInt(CoreConstant.TASK_ID) >= 0); + } + } + + @Test(expected = Exception.class) + public void testMergeReaderAndWriterSlicesConfigsException() + throws Exception { + JobContainer jobContainer = new JobContainer( + this.configuration); + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("init"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + initMethod.setAccessible(false); + + int readerSplitNumber = 100; + int writerSplitNumber = readerSplitNumber + 1; + List readerSplitConfigurations = new ArrayList(); + List writerSplitConfigurations = new ArrayList(); + for (int i = 0; i < readerSplitNumber; i++) { + Configuration readerOneConfig = Configuration.newDefault(); + readerSplitConfigurations.add(readerOneConfig); + } + for (int i = 0; i < writerSplitNumber; i++) { + Configuration readerOneConfig = Configuration.newDefault(); + writerSplitConfigurations.add(readerOneConfig); + } + + initMethod = jobContainer.getClass().getDeclaredMethod( + "mergeReaderAndWriterSlicesConfigs", List.class, List.class); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, readerSplitConfigurations, writerSplitConfigurations); + } + + @Test + public void testDistributeTasksToTaskGroupContainer() throws Exception { + distributeTasksToTaskGroupContainerTest(333, 7); + + distributeTasksToTaskGroupContainerTest(6, 7); + distributeTasksToTaskGroupContainerTest(7, 7); + distributeTasksToTaskGroupContainerTest(8, 7); + + distributeTasksToTaskGroupContainerTest(1, 1); + distributeTasksToTaskGroupContainerTest(2, 1); + distributeTasksToTaskGroupContainerTest(1, 2); + + distributeTasksToTaskGroupContainerTest(1, 1025); + distributeTasksToTaskGroupContainerTest(1024, 1025); + } + + /** + * 分发测试函数,可根据不同的通道数、每个taskGroup平均包括的channel数得到最优的分发结果 + * 注意:默认的tasks是采用faker里切分出的1024个tasks + * + * @param channelNumber + * @param channelsPerTaskGroupContainer + * @throws Exception + */ + @SuppressWarnings("unchecked") + private void distributeTasksToTaskGroupContainerTest(int channelNumber, + int channelsPerTaskGroupContainer) throws Exception { + JobContainer jobContainer = new JobContainer( + this.configuration); + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("init"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + initMethod.setAccessible(false); + + initMethod = jobContainer.getClass().getDeclaredMethod("split"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + initMethod.setAccessible(false); + + int tasksNumber = this.configuration.getListConfiguration( + CoreConstant.DATAX_JOB_CONTENT).size(); + int averSlicesPerChannel = tasksNumber / channelNumber; + + initMethod = jobContainer.getClass().getDeclaredMethod( + "distributeTasksToTaskGroup", int.class, int.class, + int.class); + initMethod.setAccessible(true); + List taskGroupConfigs = (List) initMethod + .invoke(jobContainer, averSlicesPerChannel, + channelNumber, channelsPerTaskGroupContainer); + initMethod.setAccessible(false); + + Assert.assertEquals("task size check", channelNumber + / channelsPerTaskGroupContainer + + (channelNumber % channelsPerTaskGroupContainer > 0 ? 1 : 0), + taskGroupConfigs.size()); + int sumSlices = 0; + for (Configuration taskGroupConfig : taskGroupConfigs) { + Assert.assertNotNull("have set taskGroupId", taskGroupConfig + .getInt(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID)); + int channelNo = taskGroupConfig + .getInt(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL); + Assert.assertNotNull("have set task channel number", channelNo); + int taskNumber = taskGroupConfig.getListConfiguration( + CoreConstant.DATAX_JOB_CONTENT).size(); + sumSlices += taskNumber; + Assert.assertTrue("task has average tasks", taskNumber + / channelNo == averSlicesPerChannel); + } + + Assert.assertEquals("slices equal to split sum", tasksNumber, sumSlices); + } + + @Test + public void testErrorLimitIgnoreCheck() throws Exception { + this.configuration.set(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT, -1); + JobContainer jobContainer = new JobContainer( + this.configuration); + + Communication communication = new Communication(); + communication.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + communication.setLongCounter(CommunicationTool.WRITE_RECEIVED_RECORDS, 100); +// LocalTaskGroupCommunicationManager.updateTaskGroupCommunication(0, communication); + + AbstractContainerCommunicator communicator = PowerMockito.mock(AbstractContainerCommunicator.class); + jobContainer.setContainerCommunicator(communicator); + PowerMockito.when(communicator.collect()).thenReturn(communication); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("checkLimit"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer, new Object[] {}); + initMethod.setAccessible(false); + } + + @Test(expected = Exception.class) + public void testErrorLimitPercentCheck() throws Exception { +// this.configuration.set(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT, 0.1); +// this.configuration.set(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_RECORD, null); + this.configuration.remove(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_RECORD); + this.configuration.set(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_PERCENT, 0.1); + JobContainer jobContainer = new JobContainer( + this.configuration); + + Communication communication = new Communication(); + communication.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + communication.setLongCounter(CommunicationTool.WRITE_RECEIVED_RECORDS, 80); + communication.setLongCounter(CommunicationTool.WRITE_FAILED_RECORDS, 20); +// LocalTaskGroupCommunicationManager.updateTaskGroupCommunication(0, communication); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("checkLimit"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer); + initMethod.setAccessible(false); + } + + @Test(expected = Exception.class) + public void testErrorLimitCountCheck() throws Exception { + this.configuration.remove(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_PERCENT); + this.configuration.set(CoreConstant.DATAX_JOB_SETTING_ERRORLIMIT_RECORD, 1); + JobContainer jobContainer = new JobContainer( + this.configuration); + + Communication communication = new Communication(); + communication.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + communication.setLongCounter(CommunicationTool.WRITE_RECEIVED_RECORDS, 98); + communication.setLongCounter(CommunicationTool.WRITE_FAILED_RECORDS, 2); +// LocalTaskGroupCommunicationManager.updateTaskGroupCommunication(0, communication); + + Method initMethod = jobContainer.getClass() + .getDeclaredMethod("checkLimit"); + initMethod.setAccessible(true); + initMethod.invoke(jobContainer); + initMethod.setAccessible(false); + } + + @Test + public void testStartDryRun() { + String path = JobContainerTest.class.getClassLoader() + .getResource(".").getFile(); + + this.configuration = ConfigParser.parse(path + File.separator + + "dryRunAll.json"); + LoadUtil.bind(this.configuration); + + JobContainer jobContainer = new JobContainer( + this.configuration); + jobContainer.start(); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/container/LoadUtilTest.java b/core/src/test/java/com/alibaba/datax/core/container/LoadUtilTest.java new file mode 100755 index 000000000..e6b60ce4e --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/container/LoadUtilTest.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.core.container; + +import com.alibaba.datax.common.plugin.AbstractJobPlugin; +import com.alibaba.datax.common.plugin.AbstractTaskPlugin; +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.constant.PluginType; +import com.alibaba.datax.core.util.container.LoadUtil; +import com.alibaba.datax.core.scaffold.ConfigurationProducer; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.fastjson.JSON; + +public class LoadUtilTest extends CaseInitializer { + + @Test + public void test() { + LoadUtil.bind(ConfigurationProducer.produce()); + AbstractJobPlugin jobPlugin = LoadUtil.loadJobPlugin( + PluginType.READER, "fakereader"); + System.out.println(JSON.toJSONString(jobPlugin)); + Assert.assertTrue(jobPlugin.getPluginName().equals("fakereader")); + + AbstractTaskPlugin taskPlugin = LoadUtil.loadTaskPlugin( + PluginType.READER, "fakereader"); + System.out.println(JSON.toJSONString(taskPlugin)); + Assert.assertTrue(taskPlugin.getPluginName().equals("fakereader")); + + } + +} diff --git a/core/src/test/java/com/alibaba/datax/core/container/TaskGroupContainerTest.java b/core/src/test/java/com/alibaba/datax/core/container/TaskGroupContainerTest.java new file mode 100755 index 000000000..9fff704c8 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/container/TaskGroupContainerTest.java @@ -0,0 +1,129 @@ +package com.alibaba.datax.core.container; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.faker.FakeExceptionReader; +import com.alibaba.datax.core.faker.FakeExceptionWriter; +import com.alibaba.datax.core.faker.FakeLongTimeWriter; +import com.alibaba.datax.core.faker.FakeOneReader; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; +import com.alibaba.datax.core.statistics.container.communicator.AbstractContainerCommunicator; +import com.alibaba.datax.core.taskgroup.TaskGroupContainer; +import com.alibaba.datax.core.util.ConfigParser; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.core.util.container.LoadUtil; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class TaskGroupContainerTest extends CaseInitializer { + private Configuration configuration; + private int taskNumber; + + @Before + public void setUp() { + String path = TaskGroupContainerTest.class.getClassLoader() + .getResource(".").getFile(); + + this.configuration = ConfigParser.parse(path + File.separator + + "all.json"); + LoadUtil.bind(this.configuration); + + int channelNumber = 5; + taskNumber = channelNumber + 3; + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, 0); + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + this.configuration.set( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_SLEEPINTERVAL, 200); + this.configuration.set( + CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_REPORTINTERVAL, 1000); + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, + channelNumber); + Configuration jobContent = this.configuration.getListConfiguration( + CoreConstant.DATAX_JOB_CONTENT).get(0); + List jobContents = new ArrayList(); + for (int i = 0; i < this.taskNumber; i++) { + Configuration newJobContent = jobContent.clone(); + newJobContent.set(CoreConstant.TASK_ID, i); + jobContents.add(newJobContent); + } + this.configuration.set(CoreConstant.DATAX_JOB_CONTENT, jobContents); + + LocalTGCommunicationManager.clear(); + LocalTGCommunicationManager.registerTaskGroupCommunication( + 1, new Communication()); + + } + + @Test + public void testStart() throws InterruptedException { + TaskGroupContainer taskGroupContainer = new TaskGroupContainer(this.configuration); + taskGroupContainer.start(); + + AbstractContainerCommunicator collector = taskGroupContainer.getContainerCommunicator(); + while (true) { + State totalTaskState = collector.collectState(); + if (totalTaskState.isRunning()) { + Thread.sleep(1000); + } else { + break; + } + } + + Communication totalTaskCommunication = collector.collect(); + List messages = totalTaskCommunication.getMessage("bazhen-reader"); + Assert.assertTrue(!messages.isEmpty()); + + messages = totalTaskCommunication.getMessage("bazhen-writer"); + Assert.assertTrue(!messages.isEmpty()); + + messages = totalTaskCommunication.getMessage("bazhen"); + Assert.assertNull(messages); + + State state = totalTaskCommunication.getState(); + + Assert.assertTrue("task finished", state.equals(State.SUCCEEDED)); + } + + @Test(expected = RuntimeException.class) + public void testReaderException() { + this.configuration.set("plugin.reader.fakereader.class", + FakeExceptionReader.class.getCanonicalName()); + TaskGroupContainer taskGroupContainer = new TaskGroupContainer(this.configuration); + taskGroupContainer.start(); + } + + @Test(expected = RuntimeException.class) + public void testWriterException() { + this.configuration.set("plugin.writer.fakewriter.class", + FakeExceptionWriter.class.getName()); + TaskGroupContainer taskGroupContainer = new TaskGroupContainer(this.configuration); + taskGroupContainer.start(); + } + + @Test + public void testLongTimeWriter() { + this.configuration.set("plugin.writer.fakewriter.class", + FakeOneReader.class.getName()); + this.configuration.set("plugin.writer.fakewriter.class", + FakeLongTimeWriter.class.getName()); + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_CHANNEL, + 1); + Configuration jobContent = this.configuration.getListConfiguration( + CoreConstant.DATAX_JOB_CONTENT).get(0); + List jobContents = new ArrayList(); + jobContents.add(jobContent); + this.configuration.set(CoreConstant.DATAX_JOB_CONTENT, jobContents); + + TaskGroupContainer taskGroupContainer = new TaskGroupContainer(this.configuration); + taskGroupContainer.start(); + Assert.assertTrue(State.SUCCEEDED == + taskGroupContainer.getContainerCommunicator().collect().getState()); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionReader.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionReader.java new file mode 100755 index 000000000..096685a4a --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionReader.java @@ -0,0 +1,75 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14-9-12. + */ +public class FakeExceptionReader extends Reader { + public static final class Job extends Reader.Job { + @Override + public List split(int adviceNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + for (int i = 0; i < 1024; i++) { + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format( + "jdbc:mysql://localhost:3305/db%04d", i)); + oneConfig.set("jdbcUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("jingxing_%04d", i)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + } + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake reader job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader job destroyed!"); + } + } + + public static final class Task extends Reader.Task { + @Override + public void startRead(RecordSender lineSender) { + throw new RuntimeException("just for test"); + } + + @Override + public void prepare() { + System.out.println("fake reader task prepared!"); + } + + @Override + public void post() { + System.out.println("fake reader task posted!"); + } + + @Override + public void init() { + System.out.println("fake reader task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionWriter.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionWriter.java new file mode 100755 index 000000000..812e2055c --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeExceptionWriter.java @@ -0,0 +1,76 @@ +package com.alibaba.datax.core.faker; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; + +/** + * Created by jingxing on 14-9-12. + */ +public class FakeExceptionWriter extends Writer { + public static final class Job extends Writer.Job { + + @Override + public List split(int readerSlicesNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + for(int i=0; i<1024; i++) { + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format("odps://localhost:3305/db%04d", i)); + oneConfig.set("odpsUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("odps_jingxing_%04d", i)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + } + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake writer job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer job destroyed!"); + } + } + + public static final class Task extends Writer.Task { + + @Override + public void startWrite(RecordReceiver lineReceiver) { + throw new RuntimeException("just for test"); + } + + @Override + public void prepare() { + System.out.println("fake writer task prepared!"); + } + + @Override + public void post() { + System.out.println("fake writer task posted!"); + } + + @Override + public void init() { + System.out.println("fake writer task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeJobContainer.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeJobContainer.java new file mode 100755 index 000000000..6809e6675 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeJobContainer.java @@ -0,0 +1,18 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.AbstractContainer; + +/** + * Created by jingxing on 14-9-25. + */ +public class FakeJobContainer extends AbstractContainer { + public FakeJobContainer(Configuration configuration) { + super(configuration); + } + + @Override + public void start() { + System.out.println("Fake Job start .."); + } +} \ No newline at end of file diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeLongTimeWriter.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeLongTimeWriter.java new file mode 100755 index 000000000..48c8207f9 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeLongTimeWriter.java @@ -0,0 +1,86 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14/12/24. + */ +public class FakeLongTimeWriter extends Writer { + public static final class Job extends Writer.Job { + + @Override + public List split(int readerSlicesNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format("odps://localhost:3305/db%04d", 0)); + oneConfig.set("odpsUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("odps_jingxing_%04d", 0)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake writer job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer job destroyed!"); + } + } + + public static final class Task extends Writer.Task { + + @Override + public void startWrite(RecordReceiver lineReceiver) { + Record record = null; + while ((record = lineReceiver.getFromReader()) != null) { + + } + for(int i=0; i<2; i++) { + System.out.println("writer sleep 10s ..."); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + @Override + public void prepare() { + System.out.println("fake writer task prepared!"); + } + + @Override + public void post() { + System.out.println("fake writer task posted!"); + } + + @Override + public void init() { + System.out.println("fake writer task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeOneReader.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeOneReader.java new file mode 100755 index 000000000..b97af5ea1 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeOneReader.java @@ -0,0 +1,82 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.element.LongColumn; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14/12/24. + */ +public class FakeOneReader extends Reader { + public static final class Job extends Reader.Job { + @Override + public List split(int adviceNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format( + "jdbc:mysql://localhost:3305/db%04d", 0)); + oneConfig.set("jdbcUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("jingxing_%04d", 0)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake reader job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader job destroyed!"); + } + } + + public static final class Task extends Reader.Task { + @Override + public void startRead(RecordSender lineSender) { + Record record = lineSender.createRecord(); + record.addColumn(new LongColumn(1L)); + + for (int i = 0; i < 10; i++) { + lineSender.sendToWriter(record); + } + } + + @Override + public void prepare() { + System.out.println("fake reader task prepared!"); + } + + @Override + public void post() { + System.out.println("fake reader task posted!"); + } + + @Override + public void init() { + System.out.println("fake reader task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeReader.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeReader.java new file mode 100755 index 000000000..085b71aa0 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeReader.java @@ -0,0 +1,116 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.element.LongColumn; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14-9-2. + */ +public class FakeReader extends Reader { + public static final class Job extends Reader.Job { + @Override + public List split(int adviceNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + for (int i = 0; i < 1024; i++) { + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format( + "jdbc:mysql://localhost:3305/db%04d", i)); + oneConfig.set("jdbcUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("jingxing_%04d", i)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + } + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake reader job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader job destroyed!"); + } + + public void preHandler(Configuration jobConfiguration){ + jobConfiguration.set("job.preHandler.test","readPreDone"); + } + + public void postHandler(Configuration jobConfiguration){ + jobConfiguration.set("job.postHandler.test","readPostDone"); + } + } + + public static final class Task extends Reader.Task { + @Override + public void startRead(RecordSender lineSender) { + Record record = lineSender.createRecord(); + record.addColumn(new LongColumn(1L)); + + for (int i = 0; i < 10; i++) { + lineSender.sendToWriter(record); + } + + for (int i = 0; i < 10; i++) { + this.getTaskPluginCollector().collectDirtyRecord( + record, + DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "EXCEPTION MSG"), "ERROR MSG"); + } + + for (int i = 0; i < 10; i++) { + this.getTaskPluginCollector().collectDirtyRecord(record, + "ERROR MSG"); + } + + for (int i = 0; i < 10; i++) { + this.getTaskPluginCollector().collectDirtyRecord( + record, + DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "EXCEPTION MSG")); + } + + for (int i = 0; i < 10; i++) { + this.getTaskPluginCollector().collectMessage("bazhen-reader", + "bazhen"); + } + } + + @Override + public void prepare() { + System.out.println("fake reader task prepared!"); + } + + @Override + public void post() { + System.out.println("fake reader task posted!"); + } + + @Override + public void init() { + System.out.println("fake reader task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake reader task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/faker/FakeWriter.java b/core/src/test/java/com/alibaba/datax/core/faker/FakeWriter.java new file mode 100755 index 000000000..44cb5ea69 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/faker/FakeWriter.java @@ -0,0 +1,100 @@ +package com.alibaba.datax.core.faker; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.core.util.FrameworkErrorCode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jingxing on 14-9-2. + */ +public class FakeWriter extends Writer { + public static final class Job extends Writer.Job { + + @Override + public List split(int readerSlicesNumber) { + Configuration jobParameter = this.getPluginJobConf(); + System.out.println(jobParameter); + + List splitConfigurationList = new ArrayList(); + for (int i = 0; i < 1024; i++) { + Configuration oneConfig = Configuration.newDefault(); + List jdbcUrlArray = new ArrayList(); + jdbcUrlArray.add(String.format("odps://localhost:3305/db%04d", + i)); + oneConfig.set("odpsUrl", jdbcUrlArray); + + List tableArray = new ArrayList(); + tableArray.add(String.format("odps_jingxing_%04d", i)); + oneConfig.set("table", tableArray); + + splitConfigurationList.add(oneConfig); + } + + return splitConfigurationList; + } + + @Override + public void init() { + System.out.println("fake writer job initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer job destroyed!"); + } + + public void preHandler(Configuration jobConfiguration){ + jobConfiguration.set("job.preHandler.test","writePreDone"); + } + + public void postHandler(Configuration jobConfiguration){ + jobConfiguration.set("job.postHandler.test","writePostDone"); + } + } + + public static final class Task extends Writer.Task { + + @Override + public void startWrite(RecordReceiver lineReceiver) { + Record record = null; + + while ((record = lineReceiver.getFromReader()) != null) { + this.getTaskPluginCollector().collectDirtyRecord( + record, + DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, + "TEST"), "TEST"); + } + + for (int i = 0; i < 10; i++) { + this.getTaskPluginCollector().collectMessage("bazhen-writer", + "bazhen"); + } + } + + @Override + public void prepare() { + System.out.println("fake writer task prepared!"); + } + + @Override + public void post() { + System.out.println("fake writer task posted!"); + } + + @Override + public void init() { + System.out.println("fake writer task initialized!"); + } + + @Override + public void destroy() { + System.out.println("fake writer task destroyed!"); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scaffold/ColumnProducer.java b/core/src/test/java/com/alibaba/datax/core/scaffold/ColumnProducer.java new file mode 100755 index 000000000..5e73b8649 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scaffold/ColumnProducer.java @@ -0,0 +1,30 @@ +package com.alibaba.datax.core.scaffold; + +import com.alibaba.datax.common.element.BoolColumn; +import com.alibaba.datax.common.element.BytesColumn; +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.DateColumn; +import com.alibaba.datax.common.element.LongColumn; +import com.alibaba.datax.common.element.StringColumn; + +public class ColumnProducer { + public static Column produceLongColumn(int i) { + return new LongColumn(i); + } + + public static Column produceStringColumn(String s) { + return new StringColumn(s); + } + + public static Column produceDateColumn(long time) { + return new DateColumn(time); + } + + public static Column produceBytesColumn(byte[] bytes) { + return new BytesColumn(bytes); + } + + public static Column produceBoolColumn(boolean bool) { + return new BoolColumn(bool); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scaffold/ConfigurationProducer.java b/core/src/test/java/com/alibaba/datax/core/scaffold/ConfigurationProducer.java new file mode 100755 index 000000000..427923ec0 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scaffold/ConfigurationProducer.java @@ -0,0 +1,15 @@ +package com.alibaba.datax.core.scaffold; + +import java.io.File; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.util.ConfigParser; + +public final class ConfigurationProducer { + + public static Configuration produce() { + String path = ConfigurationProducer.class.getClassLoader() + .getResource(".").getFile(); + return ConfigParser.parse(path + File.separator + "all.json"); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scaffold/RecordProducer.java b/core/src/test/java/com/alibaba/datax/core/scaffold/RecordProducer.java new file mode 100755 index 000000000..0758d794a --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scaffold/RecordProducer.java @@ -0,0 +1,25 @@ +package com.alibaba.datax.core.scaffold; + +import java.io.UnsupportedEncodingException; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.core.transport.record.DefaultRecord; + +public class RecordProducer { + public static Record produceRecord() { + + try { + Record record = new DefaultRecord(); + record.addColumn(ColumnProducer.produceLongColumn(1)); + record.addColumn(ColumnProducer.produceStringColumn("bazhen")); + record.addColumn(ColumnProducer.produceBoolColumn(true)); + record.addColumn(ColumnProducer.produceDateColumn(System + .currentTimeMillis())); + record.addColumn(ColumnProducer.produceBytesColumn("bazhen" + .getBytes("utf-8"))); + return record; + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scaffold/base/CaseInitializer.java b/core/src/test/java/com/alibaba/datax/core/scaffold/base/CaseInitializer.java new file mode 100755 index 000000000..5641dcf22 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scaffold/base/CaseInitializer.java @@ -0,0 +1,39 @@ +package com.alibaba.datax.core.scaffold.base; + +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.StringUtils; +import org.junit.BeforeClass; + +import java.io.File; + +public class CaseInitializer { + @BeforeClass + public static void beforeClass() { + CoreConstant.DATAX_HOME = CaseInitializer.class.getClassLoader() + .getResource(".").getFile(); + + CoreConstant.DATAX_CONF_PATH = StringUtils.join(new String[]{ + CoreConstant.DATAX_HOME, "conf", "core.json"}, File.separator); + + CoreConstant.DATAX_CONF_LOG_PATH = StringUtils.join( + new String[] { CoreConstant.DATAX_HOME, "conf", "logback.xml" }, File.separator); + + CoreConstant.DATAX_PLUGIN_HOME = StringUtils.join( + new String[] { CoreConstant.DATAX_HOME, "plugin" }, File.separator); + + CoreConstant.DATAX_PLUGIN_READER_HOME = StringUtils.join( + new String[] { CoreConstant.DATAX_HOME, "plugin", "reader" }, File.separator); + + CoreConstant.DATAX_PLUGIN_WRITER_HOME = StringUtils.join( + new String[] { CoreConstant.DATAX_HOME, "plugin", "writer" }, File.separator); + + CoreConstant.DATAX_BIN_HOME = StringUtils.join(new String[] { + CoreConstant.DATAX_HOME, "bin" }, File.separator); + + CoreConstant.DATAX_JOB_HOME = StringUtils.join(new String[] { + CoreConstant.DATAX_HOME, "job" }, File.separator); + + CoreConstant.DATAX_SECRET_PATH = StringUtils.join(new String[] { + CoreConstant.DATAX_HOME, "conf", ".secret.properties"}, File.separator); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scheduler/ErrorRecordLimitTest.java b/core/src/test/java/com/alibaba/datax/core/scheduler/ErrorRecordLimitTest.java new file mode 100755 index 000000000..98582c94e --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scheduler/ErrorRecordLimitTest.java @@ -0,0 +1,57 @@ +package com.alibaba.datax.core.scheduler; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import com.alibaba.datax.core.util.ErrorRecordChecker; +import org.junit.Test; + +public class ErrorRecordLimitTest { + @Test(expected = DataXException.class) + public void testCheckRecordLimit() throws Exception { + ErrorRecordChecker errLimit = new ErrorRecordChecker(0L, 0.5); + errLimit.checkRecordLimit(new Communication() { + { + this.setLongCounter(CommunicationTool.WRITE_FAILED_RECORDS, 1); + } + }); + } + + @Test + public void testCheckRecordLimit2() throws Exception { + ErrorRecordChecker errLimit = new ErrorRecordChecker(1L, 0.5); + errLimit.checkRecordLimit(new Communication() { + { + this.setLongCounter(CommunicationTool.WRITE_FAILED_RECORDS, 1); + } + }); + } + + @Test + public void testCheckRecordLimit3() throws Exception { + // 百分数无效 + ErrorRecordChecker errLimit = new ErrorRecordChecker(1L, 0.05); + errLimit.checkPercentageLimit(new Communication() { + { + this.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + this.setLongCounter(CommunicationTool.WRITE_FAILED_RECORDS, 50); + } + }); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConstruction() throws Exception { + new ErrorRecordChecker(-1L, 0.1); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConstruction2() throws Exception { + new ErrorRecordChecker(0L, -0.1); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConstruction3() throws Exception { + new ErrorRecordChecker(0L, 1.1); + } + +} \ No newline at end of file diff --git a/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneSchedulerTest.java b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneSchedulerTest.java new file mode 100755 index 000000000..b8e1d8df8 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneSchedulerTest.java @@ -0,0 +1,64 @@ +package com.alibaba.datax.core.scheduler.standalone; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.ExecuteMode; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.job.scheduler.processinner.ProcessInnerScheduler; +import com.alibaba.datax.core.job.scheduler.processinner.StandAloneScheduler; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; +import com.alibaba.datax.core.statistics.container.communicator.job.StandAloneJobContainerCommunicator; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang3.RandomUtils; +import org.junit.Test; +import org.powermock.api.mockito.PowerMockito; + +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Matchers.anyListOf; + +public class StandAloneSchedulerTest extends CaseInitializer { + + @Test + public void testSchedule() throws NoSuchFieldException, IllegalAccessException { + int taskNumber = 10; + List jobList = new ArrayList(); + + List internal = new ArrayList(); + int randomSize = 20; + int length = RandomUtils.nextInt(0, randomSize)+1; + for (int i = 0; i < length; i++) { + internal.add(Configuration.newDefault()); + } + + LocalTGCommunicationManager.clear(); + for (int i = 0; i < taskNumber; i++) { + Configuration configuration = Configuration.newDefault(); + configuration + .set(CoreConstant.DATAX_CORE_CONTAINER_JOB_REPORTINTERVAL, + 11); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, 0); + configuration.set(CoreConstant.DATAX_JOB_CONTENT, internal); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_MODE, ExecuteMode.STANDALONE.getValue()); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, i); + jobList.add(configuration); + LocalTGCommunicationManager.registerTaskGroupCommunication(i,new Communication()); + } + + StandAloneJobContainerCommunicator standAloneJobContainerCommunicator = PowerMockito. + mock(StandAloneJobContainerCommunicator.class); + ProcessInnerScheduler scheduler = PowerMockito.spy(new StandAloneScheduler(standAloneJobContainerCommunicator)); + + PowerMockito.doNothing().when(scheduler).startAllTaskGroup(anyListOf(Configuration.class)); + + Communication communication = new Communication(); + communication.setState(State.SUCCEEDED); + PowerMockito.when(standAloneJobContainerCommunicator.collect()). + thenReturn(communication); + PowerMockito.doNothing().when(standAloneJobContainerCommunicator).report(communication); + + scheduler.schedule(jobList); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestJobCollector.java b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestJobCollector.java new file mode 100755 index 000000000..2b919a320 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestJobCollector.java @@ -0,0 +1,45 @@ +package com.alibaba.datax.core.scheduler.standalone; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.container.collector.AbstractCollector; + +import java.util.List; + +public class StandAloneTestJobCollector extends AbstractCollector { + + public void registerCommunication(List configurationList) { + System.out.println("register ok"); + } + + public void report(Communication communication) { + System.out.println("job report 2"); + } + + public Communication collect() { + return new Communication() {{ + this.setState(State.SUCCEEDED); + }}; + } + + @Override + public void registerTGCommunication(List taskGroupConfigurationList) { + + } + + @Override + public void registerTaskCommunication(List taskConfigurationList) { + + } + + @Override + public Communication collectFromTask() { + return null; + } + + @Override + public Communication collectFromTaskGroup() { + return null; + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestTaskGroupContainer.java b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestTaskGroupContainer.java new file mode 100755 index 000000000..8a4e65cb1 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/scheduler/standalone/StandAloneTestTaskGroupContainer.java @@ -0,0 +1,23 @@ +package com.alibaba.datax.core.scheduler.standalone; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.taskgroup.TaskGroupContainer; + +/** + * Created by jingxing on 14-9-4. + */ +public class StandAloneTestTaskGroupContainer extends TaskGroupContainer { + public StandAloneTestTaskGroupContainer(Configuration configuration) { + super(configuration); + } + + @Override + public void start() { + try { + Thread.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("start standAlone test task container"); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/statistics/collector/ProcessInnerCollectorTest.java b/core/src/test/java/com/alibaba/datax/core/statistics/collector/ProcessInnerCollectorTest.java new file mode 100755 index 000000000..49fb0d575 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/statistics/collector/ProcessInnerCollectorTest.java @@ -0,0 +1,36 @@ +package com.alibaba.datax.core.statistics.collector; + +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; +import com.alibaba.datax.core.statistics.container.collector.ProcessInnerCollector; +import com.alibaba.datax.core.util.ReflectUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by hongjiao.hj on 2014/12/21. + */ +public class ProcessInnerCollectorTest { + @Test + public void testCollectFromTaskGroup() throws NoSuchFieldException, IllegalAccessException { + Integer taskGroupId_1 = 1; + Integer taskGroupId_2 = 2; + Communication communication_1 = new Communication(); + communication_1.setLongCounter("totalBytes",888); + Communication communication_2 = new Communication(); + communication_2.setLongCounter("totalBytes",112); + + ConcurrentHashMap taskGroupCommunicationMap = new ConcurrentHashMap(); + taskGroupCommunicationMap.put(taskGroupId_1,communication_1); + taskGroupCommunicationMap.put(taskGroupId_2,communication_2); + + ReflectUtil.setField(new LocalTGCommunicationManager(),"taskGroupCommunicationMap",taskGroupCommunicationMap); + + ProcessInnerCollector processInnerCollector = new ProcessInnerCollector(0L); + Communication comm = processInnerCollector.collectFromTaskGroup(); + Assert.assertTrue(comm.getLongCounter("totalBytes") == 1000); + System.out.println(comm); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationJsonifyTest.java b/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationJsonifyTest.java new file mode 100755 index 000000000..c1f2ee23a --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationJsonifyTest.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.junit.Assert; +import org.junit.Test; + +public class CommunicationJsonifyTest { + @Test + public void testJsonGetSnapshot() { + Communication communication = new Communication(); + communication.setLongCounter(CommunicationTool.STAGE, 10); + communication.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + communication.setLongCounter(CommunicationTool.READ_SUCCEED_BYTES, 102400); + communication.setLongCounter(CommunicationTool.BYTE_SPEED, 10240); + communication.setLongCounter(CommunicationTool.RECORD_SPEED, 100); + communication.setDoubleCounter(CommunicationTool.PERCENTAGE, 0.1); + communication.setState(State.RUNNING); + communication.setLongCounter(CommunicationTool.WRITE_RECEIVED_RECORDS, 99); + communication.setLongCounter(CommunicationTool.WRITE_RECEIVED_BYTES, 102300); + + String jsonString = CommunicationTool.Jsonify.getSnapshot(communication); + JSONObject metricJson = JSON.parseObject(jsonString); + + Assert.assertEquals(communication.getLongCounter(CommunicationTool.RECORD_SPEED), + metricJson.getLong("speedRecords")); + Assert.assertEquals(communication.getDoubleCounter(CommunicationTool.PERCENTAGE), + metricJson.getDouble("percentage")); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationTest.java b/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationTest.java new file mode 100755 index 000000000..2f3fdc6c4 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/statistics/communication/CommunicationTest.java @@ -0,0 +1,122 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.core.job.meta.State; +import org.junit.Assert; +import org.junit.Test; + +public class CommunicationTest { + @Test + public void commonTest() { + Communication comm = new Communication(); + + String longKey = "long"; + Assert.assertEquals(0, (long) comm.getLongCounter(longKey)); + long longValue = 100; + comm.setLongCounter(longKey, longValue); + String doubleKey = "double"; + Assert.assertEquals(0.0, comm.getDoubleCounter(doubleKey), 0.01); + double doubleValue = 0.01d; + comm.setDoubleCounter(doubleKey, doubleValue); + comm.setState(State.SUCCEEDED); + comm.setThrowable(new RuntimeException("runtime exception")); + long now = System.currentTimeMillis(); + comm.setTimestamp(now); + + Assert.assertEquals(longValue, (long) comm.getLongCounter("long")); + Assert.assertEquals(doubleValue, comm.getDoubleCounter("double"), 0.01); + Assert.assertTrue(State.SUCCEEDED.equals(comm.getState())); + Assert.assertTrue(comm.getThrowable() instanceof RuntimeException); + Assert.assertEquals(now, comm.getTimestamp()); + + comm.reset(); + Assert.assertTrue(State.RUNNING.equals(comm.getState())); + Assert.assertTrue(comm.getTimestamp() >= now); + + long delta = 5; + comm.increaseCounter(longKey, delta); + Assert.assertEquals(delta, (long) comm.getLongCounter(longKey)); + + String messageKey = "message"; + comm.addMessage(messageKey, "message1"); + comm.addMessage(messageKey, "message2"); + Assert.assertEquals(2, comm.getMessage(messageKey).size()); + } + + @Test + public void setStateTest() { + Communication comm = new Communication(); + Assert.assertTrue(State.RUNNING.equals(comm.getState())); + + comm.setState(State.SUCCEEDED); + Assert.assertTrue(State.SUCCEEDED.equals(comm.getState())); + + comm.setState(State.FAILED); + Assert.assertTrue(State.FAILED.equals(comm.getState())); + + comm.setState(State.SUCCEEDED); + Assert.assertTrue(State.FAILED.equals(comm.getState())); + } + + @Test + public void cloneTest() { + Communication comm0 = new Communication(); + String longKey = "long"; + long longValue = 5; + long timestamp = comm0.getTimestamp(); + comm0.setLongCounter(longKey, longValue); + comm0.setState(State.SUCCEEDED); + + Communication comm1 = comm0.clone(); + + Assert.assertEquals(longValue, (long) comm1.getLongCounter(longKey)); + Assert.assertEquals(timestamp, comm1.getTimestamp()); + Assert.assertTrue(comm0.getState().equals(comm1.getState())); + } + + @Test + public void mergeTest() { + Communication comm1 = new Communication(); + comm1.setLongCounter("long", 5); + comm1.setDoubleCounter("double", 5.1); + comm1.setState(State.SUCCEEDED); + comm1.setThrowable(new RuntimeException("run exception")); + comm1.addMessage("message", "message1"); + + Communication comm2 = new Communication(); + comm2.setLongCounter("long", 5); + comm2.setDoubleCounter("double", 5.1); + comm2.setState(State.FAILED); + comm2.setThrowable(new IllegalArgumentException("")); + comm2.addMessage("message", "message2"); + + Communication comm = comm1.mergeFrom(comm2); + Assert.assertEquals(10, (long) comm.getLongCounter("long")); + Assert.assertEquals(10.2, comm.getDoubleCounter("double"), 0.01); + Assert.assertTrue(State.FAILED.equals(comm.getState())); + Assert.assertTrue(comm.getThrowable() instanceof RuntimeException); + Assert.assertEquals(2, comm.getMessage("message").size()); + } + + @Test + public void testMergeStateFrom() { + Communication comm1 = new Communication(); + Communication comm2 = new Communication(); + + comm1.setState(State.FAILED, true); + comm2.setState(State.KILLED, true); + Assert.assertTrue(comm1.mergeStateFrom(comm2) == State.FAILED); + + comm1.setState(State.RUNNING, true); + comm2.setState(State.SUCCEEDED, true); + Assert.assertTrue(comm1.mergeStateFrom(comm2) == State.RUNNING); + + comm1.setState(State.FAILED, true); + comm2.setState(State.SUCCEEDED, true); + Assert.assertTrue(comm1.mergeStateFrom(comm2) == State.FAILED); + + comm1.setState(State.SUBMITTING, true); + comm2.setState(State.SUCCEEDED, true); + Assert.assertTrue(comm1.mergeStateFrom(comm2) == State.RUNNING); + + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/statistics/communication/LocalTaskGroupCommunicationTest.java b/core/src/test/java/com/alibaba/datax/core/statistics/communication/LocalTaskGroupCommunicationTest.java new file mode 100755 index 000000000..6323a544c --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/statistics/communication/LocalTaskGroupCommunicationTest.java @@ -0,0 +1,48 @@ +package com.alibaba.datax.core.statistics.communication; + +import com.alibaba.datax.core.job.meta.State; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class LocalTaskGroupCommunicationTest { + private final int taskGroupNumber = 5; + + @Before + public void setUp() { + LocalTGCommunicationManager.clear(); + for (int index = 0; index < taskGroupNumber; index++) { + LocalTGCommunicationManager.registerTaskGroupCommunication( + index, new Communication()); + } + } + + @Test + public void LocalCommunicationTest() { + Communication jobCommunication = + LocalTGCommunicationManager.getJobCommunication(); + Assert.assertTrue(jobCommunication.getState().equals(State.RUNNING)); + + for (int index : LocalTGCommunicationManager.getTaskGroupIdSet()) { + Communication communication = LocalTGCommunicationManager + .getTaskGroupCommunication(index); + communication.setState(State.SUCCEEDED); + LocalTGCommunicationManager.updateTaskGroupCommunication( + index, communication); + } + + jobCommunication = LocalTGCommunicationManager.getJobCommunication(); + Assert.assertTrue(jobCommunication.getState().equals(State.SUCCEEDED)); + } + + @Test(expected = IllegalArgumentException.class) + public void noTaskGroupIdForUpdate() { + LocalTGCommunicationManager.updateTaskGroupCommunication( + this.taskGroupNumber + 1, new Communication()); + } + + @Test(expected = IllegalArgumentException.class) + public void noTaskGroupIdForGet() { + LocalTGCommunicationManager.getTaskGroupCommunication(-1); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/statistics/reporter/ProcessInnerReporterTest.java b/core/src/test/java/com/alibaba/datax/core/statistics/reporter/ProcessInnerReporterTest.java new file mode 100755 index 000000000..52e016f29 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/statistics/reporter/ProcessInnerReporterTest.java @@ -0,0 +1,43 @@ +package com.alibaba.datax.core.statistics.reporter; + +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.LocalTGCommunicationManager; +import com.alibaba.datax.core.statistics.container.report.ProcessInnerReporter; +import com.alibaba.datax.core.util.ReflectUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.ConcurrentHashMap; + + +public class ProcessInnerReporterTest { + + @Test + public void testReportJobCommunication() { + Long jobId = 0L; + Communication communication = new Communication(); + + ProcessInnerReporter processInnerReporter = new ProcessInnerReporter(); + processInnerReporter.reportJobCommunication(jobId,communication); + System.out.println("this function do noting"); + } + + @Test + public void testReportTGCommunication() throws NoSuchFieldException, IllegalAccessException { + Integer taskGroupId = 1; + Communication communication = new Communication(); + communication.setState(State.SUBMITTING); + + ConcurrentHashMap map = new ConcurrentHashMap(); + map.put(taskGroupId,communication); + + ReflectUtil.setField(new LocalTGCommunicationManager(),"taskGroupCommunicationMap",map); + ProcessInnerReporter processInnerReporter = new ProcessInnerReporter(); + + Communication updateCommunication = new Communication(); + updateCommunication.setState(State.WAITING); + processInnerReporter.reportTGCommunication(taskGroupId,updateCommunication); + Assert.assertEquals(map.get(taskGroupId).getState(),State.WAITING); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/taskgroup/TaskMonitorTest.java b/core/src/test/java/com/alibaba/datax/core/taskgroup/TaskMonitorTest.java new file mode 100644 index 000000000..f4fa89421 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/taskgroup/TaskMonitorTest.java @@ -0,0 +1,192 @@ +package com.alibaba.datax.core.taskgroup; + +import com.alibaba.datax.core.job.meta.State; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.statistics.communication.CommunicationTool; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.concurrent.ConcurrentHashMap; + +public class TaskMonitorTest { + + TaskMonitor taskMonitor = TaskMonitor.getInstance(); + private ConcurrentHashMap tasks; + + @Before + public void setUp() throws Exception { + Field tasks = taskMonitor.getClass().getDeclaredField("tasks"); + tasks.setAccessible(true); + tasks.set(taskMonitor, new ConcurrentHashMap()); + this.tasks = (ConcurrentHashMap) tasks.get(taskMonitor); + } + + @Test + public void testNormal() throws Exception { + + //register task + long ttl = System.currentTimeMillis(); + + Communication communication1 = new Communication(); + + taskMonitor.registerTask(1, communication1); + + TaskMonitor.TaskCommunication taskCommunication1 = taskMonitor.getTaskCommunication(1); + + Assert.assertEquals(taskCommunication1.getLastAllReadRecords(), 0L); + Assert.assertEquals(this.tasks.size(), 1); + + Assert.assertTrue(taskCommunication1.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication1.getTtl() >= ttl); + + // report 没有任何变化的communication + + long oldTS = taskCommunication1.getLastUpdateComunicationTS(); + long oldTTL = taskCommunication1.getTtl(); + Thread.sleep(1000); + + taskMonitor.report(1, communication1); + + TaskMonitor.TaskCommunication taskCommunication1_1 = taskMonitor.getTaskCommunication(1); + + Assert.assertEquals(taskCommunication1_1.getLastAllReadRecords(), 0L); + Assert.assertEquals(taskCommunication1_1.getLastUpdateComunicationTS(), oldTS); + Assert.assertTrue(taskCommunication1_1.getTtl() > oldTTL); + + // report 已经finish的communication + Communication communication2 = new Communication(); + communication2.setState(State.KILLED); + + taskMonitor.registerTask(2, communication2); + Assert.assertEquals(this.tasks.size(), 1); + + + // report 另一个communication + Communication communication3 = new Communication(); + taskMonitor.registerTask(3, communication3); + + Assert.assertEquals(this.tasks.size(), 2); + System.out.println(this.tasks); + + //report communication + + ttl = System.currentTimeMillis(); + + communication1.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 100); + communication3.setLongCounter(CommunicationTool.READ_FAILED_RECORDS, 10); + + taskMonitor.report(1, communication1); + taskMonitor.report(3, communication3); + + taskCommunication1 = taskMonitor.getTaskCommunication(1); + + Assert.assertEquals(taskCommunication1.getLastAllReadRecords(), 100L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(taskCommunication1.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication1.getTtl() >= ttl); + + TaskMonitor.TaskCommunication taskCommunication3 = taskMonitor.getTaskCommunication(3); + + Assert.assertEquals(taskCommunication3.getLastAllReadRecords(), 10L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(taskCommunication3.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication3.getTtl() >= ttl); + + //继续report + ttl = System.currentTimeMillis(); + + communication1.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 1001); + communication3.setLongCounter(CommunicationTool.READ_FAILED_RECORDS, 101); + + taskMonitor.report(1, communication1); + taskMonitor.report(3, communication3); + + taskCommunication1 = taskMonitor.getTaskCommunication(1); + + Assert.assertEquals(taskCommunication1.getLastAllReadRecords(), 1001L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(taskCommunication1.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication1.getTtl() >= ttl); + + taskCommunication3 = taskMonitor.getTaskCommunication(3); + + Assert.assertEquals(taskCommunication3.getLastAllReadRecords(), 101L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(taskCommunication3.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication3.getTtl() >= ttl); + + // 设置EXPIRED_TIME + Field EXPIRED_TIME = taskMonitor.getClass().getDeclaredField("EXPIRED_TIME"); + EXPIRED_TIME.setAccessible(true); + EXPIRED_TIME.set(null, 1000); + + Thread.sleep(2000); + + //超时没有变更 + taskMonitor.report(1, communication1); + + System.out.println(communication1.getCounter()); + System.out.println(communication1.getThrowable()); + System.out.println(communication1.getThrowableMessage()); + System.out.println(communication1.getState()); + + Assert.assertTrue(communication1.getThrowableMessage().contains("任务hung住,Expired")); + Assert.assertEquals(communication1.getState(), State.FAILED); + + // communicatio1 已经fail, communication3 在超时后进行变更,update正常 + ttl = System.currentTimeMillis(); + + communication1.setLongCounter(CommunicationTool.READ_SUCCEED_RECORDS, 2001); + communication3.setLongCounter(CommunicationTool.READ_FAILED_RECORDS, 201); + + taskMonitor.report(1, communication1); + taskMonitor.report(3, communication3); + + + taskCommunication1 = taskMonitor.getTaskCommunication(1); + + Assert.assertEquals(taskCommunication1.getLastAllReadRecords(), 1001L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(communication1.getThrowableMessage().contains("任务hung住,Expired")); + Assert.assertEquals(communication1.getState(), State.FAILED); + + taskCommunication3 = taskMonitor.getTaskCommunication(3); + + Assert.assertEquals(taskCommunication3.getLastAllReadRecords(), 201L); + Assert.assertEquals(this.tasks.size(), 2); + + Assert.assertTrue(taskCommunication3.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication3.getTtl() >= ttl); + + + //remove 1 + taskMonitor.removeTask(1); + Assert.assertEquals(this.tasks.size(), 1); + + //remove 3 + taskMonitor.removeTask(3); + Assert.assertEquals(this.tasks.size(), 0); + + // 没有register communication3 直接report + ttl = System.currentTimeMillis(); + + communication3.setLongCounter(CommunicationTool.READ_FAILED_RECORDS, 301); + + taskMonitor.report(3, communication3); + + taskCommunication3 = taskMonitor.getTaskCommunication(3); + + Assert.assertEquals(taskCommunication3.getLastAllReadRecords(), 301L); + Assert.assertEquals(this.tasks.size(), 1); + + Assert.assertTrue(taskCommunication3.getLastUpdateComunicationTS() >= ttl); + Assert.assertTrue(taskCommunication3.getTtl() >= ttl); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannelTest.java b/core/src/test/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannelTest.java new file mode 100755 index 000000000..90de8a805 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/transport/channel/memory/MemoryChannelTest.java @@ -0,0 +1,174 @@ +package com.alibaba.datax.core.transport.channel.memory; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.datax.core.statistics.communication.Communication; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.datax.common.element.LongColumn; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.scaffold.ConfigurationProducer; +import com.alibaba.datax.core.scaffold.RecordProducer; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.record.TerminateRecord; +import com.alibaba.datax.core.util.container.CoreConstant; + +public class MemoryChannelTest extends CaseInitializer { + private Channel channel; + + @Before + public void before() { + System.out.println(ConfigurationProducer.produce().toJSON()); + Configuration configuration = ConfigurationProducer.produce(); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 0); + this.channel = new MemoryChannel(configuration); + this.channel.setCommunication(new Communication()); + } + + // 测试SEQ + @Test + public void test_seq() { + int capacity = 4; + + Record record = null; + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + this.channel.push(record); + } + + for (int i = 0; i < capacity; i++) { + record = this.channel.pull(); + System.out.println(record.getColumn(0).asLong()); + Assert.assertTrue(record.getColumn(0).asLong() == i); + } + + List records = new ArrayList(capacity); + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + records.add(record); + } + this.channel.pushAll(records); + + this.channel.pullAll(records); + System.out.println(records.size()); + for (int i = 0; i < capacity; i++) { + System.out.println(records.get(i).getColumn(0).asLong()); + Assert.assertTrue(records.get(i).getColumn(0).asLong() == i); + } + } + + @Test + public void test_Block() throws InterruptedException { + int tryCount = 100; + int capacity = ConfigurationProducer.produce().getInt( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY); + + System.out.println("capacity: " + capacity); + + Thread thread = new Thread(new Consumer(this.channel, tryCount * capacity)); + thread.start(); + + List records = new ArrayList(capacity); + for (int i = 0; i < capacity; i++) { + Record record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + records.add(record); + } + + for (int i = 0; i < tryCount; i++) { + this.channel.pushAll(records); + } + + Thread.sleep(5000L); + + List termindateRecords = new ArrayList(); + termindateRecords.add(TerminateRecord.get()); + this.channel.pushAll(termindateRecords); + + Thread.sleep(1000L); + + thread.join(); + + } + + @Test + public void test_BlockAndSeq() throws InterruptedException { + int tryCount = 100; + int capacity = ConfigurationProducer.produce().getInt( + CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY); + + System.out.println("capacity: " + capacity); + + Thread thread = new Thread(new Consumer(this.channel, tryCount * capacity)); + thread.start(); + + List records = new ArrayList(capacity); + for (int i = 0; i < capacity; i++) { + Record record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + records.add(record); + } + + for (int i = 0; i < tryCount; i++) { + this.channel.pushAll(records); + } + + Thread.sleep(5000L); + + this.channel.push(TerminateRecord.get()); + + Thread.sleep(1000L); + + thread.join(); + + } +} + +class Consumer implements Runnable { + + private Channel channel = null; + + private int needCapacity = 0; + + public Consumer(Channel channel, int needCapacity) { + this.channel = channel; + this.needCapacity = needCapacity; + return; + } + + @Override + public void run() { + List records = new ArrayList(); + + boolean isTermindate = false; + int counter = 0; + + while (true) { + this.channel.pullAll(records); + for (final Record each : records) { + if (each == TerminateRecord.get()) { + isTermindate = true; + break; + } + counter++; + continue; + } + + if (isTermindate) { + break; + } + } + + System.out.println(String.format("Need %d, Get %d .", needCapacity, + counter)); + Assert.assertTrue(counter == needCapacity); + } + +} diff --git a/core/src/test/java/com/alibaba/datax/core/transport/exchanger/RecordExchangerTest.java b/core/src/test/java/com/alibaba/datax/core/transport/exchanger/RecordExchangerTest.java new file mode 100755 index 000000000..455125919 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/transport/exchanger/RecordExchangerTest.java @@ -0,0 +1,293 @@ +package com.alibaba.datax.core.transport.exchanger; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.LongColumn; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.scaffold.ColumnProducer; +import com.alibaba.datax.core.scaffold.ConfigurationProducer; +import com.alibaba.datax.core.scaffold.RecordProducer; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.statistics.communication.Communication; +import com.alibaba.datax.core.transport.channel.Channel; +import com.alibaba.datax.core.transport.channel.memory.MemoryChannel; +import com.alibaba.datax.core.transport.record.DefaultRecord; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.mock; + +public class RecordExchangerTest extends CaseInitializer { + + private Configuration configuration = null; + + @Before + public void before() { + this.configuration = ConfigurationProducer.produce(); + this.configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + return; + } + + + @Test + public void testMemeroySize() throws Exception { + Column longColumn = ColumnProducer.produceLongColumn(1); + Column longColumn2 = new LongColumn("234567891"); + Column stringColumn= ColumnProducer.produceStringColumn("sringtest"); + Column boolColumn=ColumnProducer.produceBoolColumn(true); + Column dateColumn = ColumnProducer.produceDateColumn(System.currentTimeMillis()); + Column bytesColumn = ColumnProducer.produceBytesColumn("test".getBytes("utf-8")); + Assert.assertEquals(longColumn.getByteSize(),8); + Assert.assertEquals(longColumn2.getByteSize(),9); + Assert.assertEquals(stringColumn.getByteSize(),9); + Assert.assertEquals(boolColumn.getByteSize(),1); + Assert.assertEquals(dateColumn.getByteSize(),8); + Assert.assertEquals(bytesColumn.getByteSize(),4); + + Record record = new DefaultRecord(); + record.addColumn(longColumn); + record.addColumn(longColumn2); + record.addColumn(stringColumn); + record.addColumn(boolColumn); + record.addColumn(dateColumn); + record.addColumn(bytesColumn); + + Assert.assertEquals(record.getByteSize(),39); + // record classSize = 80 + // column classSize = 6*24 + Assert.assertEquals(record.getMemorySize(),263); + + } + + @Test + public void test_Exchanger() { + Channel channel = new MemoryChannel(configuration); + channel.setCommunication(new Communication()); + + int capacity = 10; + Record record = null; + RecordExchanger recordExchanger = new RecordExchanger(channel); + + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + recordExchanger.sendToWriter(record); + } + + System.out.println("byteSize=" + record.getByteSize()); + System.out.println("meorySize=" + record.getMemorySize()); + + channel.close(); + + int counter = 0; + while ((record = recordExchanger.getFromReader()) != null) { + System.out.println(record.getColumn(0).toString()); + Assert.assertTrue(record.getColumn(0).asLong() == counter); + counter++; + } + + Assert.assertTrue(capacity == counter); + } + + @Test + public void test_BufferExchanger() { + + Configuration configuration = ConfigurationProducer.produce(); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + + Channel channel = new MemoryChannel(configuration); + channel.setCommunication(new Communication()); + + TaskPluginCollector pluginCollector = mock(TaskPluginCollector.class); + int capacity = 10; + Record record = null; + BufferedRecordExchanger recordExchanger = new BufferedRecordExchanger( + channel,pluginCollector); + + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + recordExchanger.sendToWriter(record); + } + + recordExchanger.flush(); + + channel.close(); + + int counter = 0; + while ((record = recordExchanger.getFromReader()) != null) { + System.out.println(record.getColumn(0).toString()); + Assert.assertTrue(record.getColumn(0).asLong() == counter); + counter++; + } + + System.out.println(String.format("Capacity: %d Counter: %d .", + capacity, counter)); + Assert.assertTrue(capacity == counter); + } + + @Test + public void test_BufferExchanger_单条超过buffer的脏数据() throws Exception { + + Configuration configuration = ConfigurationProducer.produce(); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + + //测试单挑记录超过buffer大小 + configuration.set(CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE, 3); + + TaskPluginCollector pluginCollector = mock(TaskPluginCollector.class); + int capacity = 10; + Record record = null; + + Channel channel2 = new MemoryChannel(configuration); + channel2.setCommunication(new Communication()); + BufferedRecordExchanger recordExchanger2 = new BufferedRecordExchanger( + channel2,pluginCollector); + + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + recordExchanger2.sendToWriter(record); + } + + ArgumentCaptor rgArg = ArgumentCaptor.forClass(Record.class); + ArgumentCaptor eArg = ArgumentCaptor.forClass(Exception.class); + + verify(pluginCollector,times(10)).collectDirtyRecord(rgArg.capture(), eArg.capture()); + + recordExchanger2.flush(); + + channel2.close(); + + int counter = 0; + while ((record = recordExchanger2.getFromReader()) != null) { + System.out.println(record.getColumn(0).toString()); + Assert.assertTrue(record.getColumn(0).asLong() == counter); + counter++; + } + + System.out.println(String.format("Capacity: %d Counter: %d .", + capacity, counter)); + Assert.assertTrue(counter == 0); + + } + + @Test + public void test_BufferExchanger_不满32条到达buffer大小() throws Exception { + + Configuration configuration = ConfigurationProducer.produce(); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + configuration.set(CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE, 500); + + TaskPluginCollector pluginCollector = mock(TaskPluginCollector.class); + final int capacity = 10; + Record record = null; + + //测试单挑记录超过buffer大小 + + Channel channel3 = new MemoryChannel(configuration); + channel3.setCommunication(new Communication()); + final BufferedRecordExchanger recordExchangerWriter = new BufferedRecordExchanger( + channel3,pluginCollector); + + final BufferedRecordExchanger recordExchangerReader = new BufferedRecordExchanger( + channel3,pluginCollector); + + final BufferedRecordExchanger spy1=spy(recordExchangerWriter); + + Thread t = new Thread(new Runnable() { + @Override + public void run() { + int counter = 0; + Record record; + while ((record = recordExchangerReader.getFromReader()) != null) { + System.out.println(record.getColumn(0).toString()); + Assert.assertTrue(record.getColumn(0).asLong() == counter); + counter++; + } + + System.out.println(String.format("Capacity: %d Counter: %d .", + capacity, counter)); + Assert.assertTrue(capacity == counter); + } + }); + t.start(); + + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + spy1.sendToWriter(record); + } + + spy1.flush(); + + channel3.close(); + + t.join(); + + verify(spy1,times(5)).flush(); + + } + + @Test + public void test_BufferExchanger_每条大小刚好是buffersize() throws Exception { + + Configuration configuration = ConfigurationProducer.produce(); + configuration.set(CoreConstant.DATAX_CORE_CONTAINER_TASKGROUP_ID, 1); + configuration.set(CoreConstant.DATAX_CORE_TRANSPORT_CHANNEL_CAPACITY_BYTE, 229); + + TaskPluginCollector pluginCollector = mock(TaskPluginCollector.class); + final int capacity = 10; + Record record = null; + + //测试单挑记录超过buffer大小 + + Channel channel3 = new MemoryChannel(configuration); + channel3.setCommunication(new Communication()); + final BufferedRecordExchanger recordExchangerWriter = new BufferedRecordExchanger( + channel3,pluginCollector); + + final BufferedRecordExchanger recordExchangerReader = new BufferedRecordExchanger( + channel3,pluginCollector); + + final BufferedRecordExchanger spy1=spy(recordExchangerWriter); + + Thread t = new Thread(new Runnable() { + @Override + public void run() { + int counter = 0; + Record record; + while ((record = recordExchangerReader.getFromReader()) != null) { + System.out.println(record.getColumn(0).toString()); + Assert.assertTrue(record.getColumn(0).asLong() == counter); + counter++; + } + + System.out.println(String.format("Capacity: %d Counter: %d .", + capacity, counter)); + Assert.assertTrue(capacity == counter); + } + }); + t.start(); + + for (int i = 0; i < capacity; i++) { + record = RecordProducer.produceRecord(); + record.setColumn(0, new LongColumn(i)); + spy1.sendToWriter(record); + } + + spy1.flush(); + + channel3.close(); + + t.join(); + + verify(spy1,times(10)).flush(); + + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/transport/record/RecordTest.java b/core/src/test/java/com/alibaba/datax/core/transport/record/RecordTest.java new file mode 100755 index 000000000..7c588b365 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/transport/record/RecordTest.java @@ -0,0 +1,20 @@ +package com.alibaba.datax.core.transport.record; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.scaffold.RecordProducer; + +public class RecordTest { + @Test + public void test() { + Record record = RecordProducer.produceRecord(); + System.out.println(record.toString()); + + Configuration configuration = Configuration.from(record.toString()); + Assert.assertTrue(configuration.getInt("size") == 5); + Assert.assertTrue(configuration.getList("data").size() == 5); + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/util/ClassUtilTest.java b/core/src/test/java/com/alibaba/datax/core/util/ClassUtilTest.java new file mode 100755 index 000000000..af3ec99aa --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/util/ClassUtilTest.java @@ -0,0 +1,53 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.AbstractContainer; + +public final class ClassUtilTest extends CaseInitializer { + @Test + public void test() { + + Assert.assertTrue(ClassUtil.instantiate( + Dummy.class.getCanonicalName(), Dummy.class) != null); + + Dummy dummy = ClassUtil.instantiate(Dummy.class.getCanonicalName(), + Dummy.class); + Assert.assertTrue(dummy instanceof Dummy); + + String dataXServerJson = "{\n" + + "\t\"core\": {\n" + + "\t\t\"dataXServer\": {\n" + + "\t\t\t\"address\": \"http://localhost/test/",\n" + + "\t\t\t\"timeout\": 5000\n" + + "\t\t}\n" + + "\t}\n" + + "}"; + Assert.assertTrue(ClassUtil.instantiate( + DummyContainer.class.getCanonicalName(), DummyContainer.class, + Configuration.from(dataXServerJson)) instanceof DummyContainer); + + Assert.assertTrue(ClassUtil.instantiate( + DummyContainer.class.getCanonicalName(), DummyContainer.class, + Configuration.from(dataXServerJson)) instanceof DummyContainer); + } +} + +class DummyContainer extends AbstractContainer { + public DummyContainer(Configuration configuration) { + super(configuration); + } + + @Override + public void start() { + System.out.println(getConfiguration()); + } +} + +class Dummy { + public Dummy() { + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/util/ConfigParserTest.java b/core/src/test/java/com/alibaba/datax/core/util/ConfigParserTest.java new file mode 100755 index 000000000..87e2e2908 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/util/ConfigParserTest.java @@ -0,0 +1,162 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.scaffold.base.CaseInitializer; +import com.alibaba.datax.core.util.container.CoreConstant; +import org.apache.commons.lang.StringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class ConfigParserTest extends CaseInitializer { + private String jobPath; + + @Before + public void setUp() { + String path = ConfigParserTest.class.getClassLoader() + .getResource(".").getFile(); + this.jobPath = path + File.separator + + "job" + File.separator + "job.json"; + } + @Test + public void test() throws URISyntaxException { + Configuration configuration = ConfigParser.parse(jobPath); + System.out.println(configuration.toJSON()); + + Assert.assertTrue(configuration.getList("job.content").size() == 2); + Assert.assertTrue(configuration.getString("job.content[0].reader.name") + .equals("fakereader")); + Assert.assertTrue(configuration.getString("job.content[1].reader.name") + .equals("fakereader")); + Assert.assertTrue(configuration.getString("job.content[0].writer.name") + .equals("fakewriter")); + Assert.assertTrue(configuration.getString("job.content[1].writer.name") + .equals("fakewriter")); + + System.out.println(configuration.getConfiguration("plugin").toJSON()); + + configuration = configuration.getConfiguration("plugin"); + Assert.assertTrue(configuration.getString("reader.fakereader.name") + .equals("fakereader")); + Assert.assertTrue(configuration.getString("writer.fakewriter.name") + .equals("fakewriter")); + } + + @Test + public void secretTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + String password = "password"; + String accessKey = "accessKey"; + String readerParamPath = + "job.content[0].reader.parameter"; + String writerParamPath = + "job.content[1].writer.parameter"; + + Map secretMap = getPublicKeyMap(); + String keyVersion = null; + for(String version : secretMap.keySet()) { + keyVersion = version; + break; + } + + Configuration config = ConfigParser.parse(jobPath); + config.set(CoreConstant.DATAX_JOB_SETTING_KEYVERSION, + keyVersion); + config.set(readerParamPath+".*password", + SecretUtil.encrypt(password, secretMap.get(keyVersion), SecretUtil.KEY_ALGORITHM_RSA)); + config.set(readerParamPath+".*long", 100); + config.set(writerParamPath+".*accessKey", + SecretUtil.encrypt(accessKey, secretMap.get(keyVersion), SecretUtil.KEY_ALGORITHM_RSA)); + config.set(writerParamPath+".*long", 200); + + config = SecretUtil.decryptSecretKey(config); + + Assert.assertTrue(password.equals( + config.getString(readerParamPath+".password"))); + Assert.assertTrue(config.isSecretPath( + readerParamPath+".password")); + Assert.assertTrue(config.get(readerParamPath+".*long") != null); + Assert.assertTrue(accessKey.equals( + config.getString(writerParamPath+".accessKey"))); + Assert.assertTrue(config.isSecretPath( + writerParamPath+".accessKey")); + Assert.assertTrue(config.get(writerParamPath+".*long") != null); + Assert.assertTrue(StringUtils.isBlank( + config.getString(readerParamPath+".*password"))); + Assert.assertTrue(StringUtils.isBlank( + config.getString(writerParamPath+".*accessKey"))); + } + + private Map getPublicKeyMap() { + Map versionKeyMap = + new HashMap(); + InputStream secretStream = null; + try { + secretStream = new FileInputStream( + CoreConstant.DATAX_SECRET_PATH); + } catch (FileNotFoundException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + "DataX配置要求加解密,但无法找到密钥的配置文件"); + } + + Properties properties = new Properties(); + try { + properties.load(secretStream); + secretStream.close(); + } catch (IOException e) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, "读取加解密配置文件出错", e); + } + + String lastKeyVersion = properties.getProperty( + CoreConstant.LAST_KEYVERSION); + String lastPublicKey = properties.getProperty( + CoreConstant.LAST_PUBLICKEY); + String lastPrivateKey = properties.getProperty( + CoreConstant.LAST_PRIVATEKEY); + if(StringUtils.isNotBlank(lastKeyVersion)) { + if(StringUtils.isBlank(lastPublicKey) || + StringUtils.isBlank(lastPrivateKey)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + "DataX配置要求加解密,但上次配置的公私钥对存在为空的情况" + ); + } + + versionKeyMap.put(lastKeyVersion, lastPublicKey); + } + + String currentKeyVersion = properties.getProperty( + CoreConstant.CURRENT_KEYVERSION); + String currentPublicKey = properties.getProperty( + CoreConstant.CURRENT_PUBLICKEY); + String currentPrivateKey = properties.getProperty( + CoreConstant.CURRENT_PRIVATEKEY); + if(StringUtils.isNotBlank(currentKeyVersion)) { + if(StringUtils.isBlank(currentPublicKey) || + StringUtils.isBlank(currentPrivateKey)) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + "DataX配置要求加解密,但当前配置的公私钥对存在为空的情况"); + } + + versionKeyMap.put(currentKeyVersion, currentPublicKey); + } + + if(versionKeyMap.size() <= 0) { + throw DataXException.asDataXException( + FrameworkErrorCode.SECRET_ERROR, + "DataX配置要求加解密,但无法找到公私钥"); + } + + return versionKeyMap; + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/util/HttpClientUtilTest.java b/core/src/test/java/com/alibaba/datax/core/util/HttpClientUtilTest.java new file mode 100755 index 000000000..9a103290f --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/util/HttpClientUtilTest.java @@ -0,0 +1,175 @@ +package com.alibaba.datax.core.util; + +import com.alibaba.datax.common.exception.DataXException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.impl.client.CloseableHttpClient; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.mockito.Matchers.any; + +public class HttpClientUtilTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtilTest.class); + + @Test + public void testExecuteAndGet() throws Exception { + HttpGet httpGet = HttpClientUtil.getGetRequest(); + httpGet.setURI(new URI("http://127.0.0.1:8080/")); + + CloseableHttpClient httpClient = PowerMockito.mock(CloseableHttpClient.class); + CloseableHttpResponse response = PowerMockito.mock(CloseableHttpResponse.class); + + StatusLine statusLine = PowerMockito.mock(StatusLine.class); + PowerMockito.when(statusLine.getStatusCode()).thenReturn(HttpStatus.SC_BAD_REQUEST); + PowerMockito.when(response.getStatusLine()).thenReturn(statusLine); + PowerMockito.when(httpClient.execute(any(HttpRequestBase.class))).thenReturn(response); + + try { + HttpClientUtil client = HttpClientUtil.getHttpClientUtil(); + ReflectUtil.setField(client, "httpClient", httpClient); + client.executeAndGet(httpGet); + } catch (Exception e) { + LOGGER.info("msg:" + e.getMessage(), e); + Assert.assertNotNull(e); + Assert.assertEquals("Response Status Code : 400", e.getMessage()); + + } + + try { + PowerMockito.when(statusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK); + PowerMockito.when(response.getEntity()).thenReturn(null); + HttpClientUtil client = HttpClientUtil.getHttpClientUtil(); + ReflectUtil.setField(client, "httpClient", httpClient); + client.executeAndGet(httpGet); + } catch (Exception e) { + LOGGER.info("msg:" + e.getMessage(), e); + Assert.assertNotNull(e); + Assert.assertEquals("Response Entity Is Null", e.getMessage()); + + } + + InputStream is = new ByteArrayInputStream("abc".getBytes()); + HttpEntity entity = PowerMockito.mock(HttpEntity.class); + PowerMockito.when(response.getEntity()).thenReturn(entity); + PowerMockito.when(entity.getContent()).thenReturn(is); + HttpClientUtil client = HttpClientUtil.getHttpClientUtil(); + ReflectUtil.setField(client, "httpClient", httpClient); + String result = client.executeAndGet(httpGet); + Assert.assertEquals("abc", result); + LOGGER.info("result:" + result); + + } + + + @Test + public void testExecuteAndGetWithRetry() throws Exception { + String url = "http://127.0.0.1/:8080"; + HttpRequestBase httpRequestBase = new HttpGet(url); + + HttpClientUtil httpClientUtil = PowerMockito.spy(HttpClientUtil.getHttpClientUtil()); + + + PowerMockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + System.out.println("失败第1次"); + return new Exception("失败第1次"); + } + }).doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + System.out.println("失败第2次"); + return new Exception("失败第2次"); + } + }).doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + System.out.println("失败第3次"); + return new Exception("失败第3次"); + } + }).doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + System.out.println("失败第4次"); + return new Exception("失败第4次"); + } + }) + .doReturn("成功") + .when(httpClientUtil).executeAndGet(any(HttpRequestBase.class)); + + + String str = httpClientUtil.executeAndGetWithRetry(httpRequestBase, 5, 1000l); + Assert.assertEquals(str, "成功"); + + try { + httpClientUtil.executeAndGetWithRetry(httpRequestBase, 2, 1000l); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + } + httpClientUtil.destroy(); + } + + /** + * 和测试方法一样:testExecuteAndGetWithRetry(),只是换了一种写法,直接采用 Mockito 进行验证的。 + */ + @Test + public void testExecuteAndGetWithRetry2() throws Exception { + String url = "http://127.0.0.1/:8080"; + HttpRequestBase httpRequestBase = new HttpGet(url); + + HttpClientUtil httpClientUtil = Mockito.spy(HttpClientUtil.getHttpClientUtil()); + + Mockito.doThrow(new Exception("one")).doThrow(new Exception("two")).doThrow(new Exception("three")).doReturn("成功").when(httpClientUtil).executeAndGet(httpRequestBase); + + String str = httpClientUtil.executeAndGetWithRetry(httpRequestBase, 4, 1000l); + Assert.assertEquals(str, "成功"); + + + Mockito.reset(httpClientUtil); + + Mockito.doThrow(new Exception("one")).doThrow(new Exception("two")).doThrow(new Exception("three")).doReturn("成功").when(httpClientUtil).executeAndGet(httpRequestBase); + try { + httpClientUtil.executeAndGetWithRetry(httpRequestBase, 2, 1000l); + } catch (Exception e) { + Assert.assertTrue(e instanceof DataXException); + Assert.assertTrue(e.getMessage().contains("two")); + } + httpClientUtil.destroy(); + } + +// 单独运行可以成功 +// private String url = "http://abadaddress:8080/"; +// +// @Rule +// public ExpectedException expectedException = ExpectedException.none(); +// +// @Test +// public void testExecuteAndGetWithRetry_exception() throws Exception { +// HttpRequestBase httpRequestBase = new HttpGet(url); +// +// HttpClientUtil httpClientUtil = HttpClientUtil.getHttpClientUtil(); +// +// expectedException.expect(UnknownHostException.class); +// httpClientUtil.executeAndGetWithRetry(httpRequestBase, 3, 1000L); +// } + +} diff --git a/core/src/test/java/com/alibaba/datax/core/util/ReflectUtil.java b/core/src/test/java/com/alibaba/datax/core/util/ReflectUtil.java new file mode 100755 index 000000000..111377ce2 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/util/ReflectUtil.java @@ -0,0 +1,43 @@ +package com.alibaba.datax.core.util; + +import java.lang.reflect.Field; + +/** + * Created by hongjiao.hj on 2014/12/17. + */ +public class ReflectUtil { + + public static void setField(Object targetObj, String name, Object obj) throws NoSuchFieldException, IllegalAccessException { + //Class clazz = targetObj.getClass(); + Field field = getDeclaredField(targetObj,name); + field.setAccessible(true); + field.set(targetObj, obj); + } + + public static Object getField(Object targetObj, String name, Object obj) throws NoSuchFieldException, IllegalAccessException { + Class clazz = targetObj.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + return field.get(targetObj); + } + + + private static Field getDeclaredField(Object object, String fieldName){ + Field field = null ; + + Class clazz = object.getClass() ; + + for(; clazz != Object.class ; clazz = clazz.getSuperclass()) { + try { + field = clazz.getDeclaredField(fieldName) ; + return field ; + } catch (Exception e) { + //这里什么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + + } + } + + return null; + } +} diff --git a/core/src/test/java/com/alibaba/datax/core/util/SecretUtilTest.java b/core/src/test/java/com/alibaba/datax/core/util/SecretUtilTest.java new file mode 100755 index 000000000..f0c4d03f5 --- /dev/null +++ b/core/src/test/java/com/alibaba/datax/core/util/SecretUtilTest.java @@ -0,0 +1,107 @@ +package com.alibaba.datax.core.util; + +import java.lang.reflect.Field; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by jingxing on 14/12/15. + */ +public class SecretUtilTest { + + @Test + public void testRsa() throws Exception { + String[] keys = SecretUtil.initKey(); + String publicKey = keys[0]; + String privateKey = keys[1]; + System.out.println("publicKey:" + publicKey); + System.out.println("privateKey:" + privateKey); + String data = "阿里巴巴DataX"; + + System.out.println("【加密前】:" + data); + + // 加密 + String cipherText = SecretUtil.encrypt(data, publicKey, + SecretUtil.KEY_ALGORITHM_RSA); + System.out.println("【加密后】:" + cipherText); + + // 解密 + String plainText = SecretUtil.decrypt(cipherText, privateKey, + SecretUtil.KEY_ALGORITHM_RSA); + System.out.println("【解密后】:" + plainText); + + Assert.assertTrue(plainText.equals(data)); + } + + @Test + public void testDes() throws Exception { + String keyContent = "datax&cdp&dsc"; + System.out.println("keyContent:" + keyContent); + String data = "阿里巴巴DataX"; + + System.out.println("【加密前】:" + data); + + // 加密 + String cipherText = SecretUtil.encrypt(data, keyContent, + SecretUtil.KEY_ALGORITHM_3DES); + System.out.println("【加密后】:" + cipherText); + + // 解密 + String plainText = SecretUtil.decrypt(cipherText, keyContent, + SecretUtil.KEY_ALGORITHM_3DES); + System.out.println("【解密后】:" + plainText); + + Assert.assertTrue(plainText.equals(data)); + } + + @Test + public void testPythonSwitchJava() { + String data = "rootroot"; + String key = "abcabcabcabcabcabcabcabc"; + String cipherText = SecretUtil.encrypt3DES(data, key); + System.out.println(String.format( + "data[%s] : key[%s] -> cipherText[%s]", data, key, cipherText)); + Assert.assertTrue("svj4x04Oaq6WhrfZVsSRqA==".equals(cipherText)); + Assert.assertTrue(data.equals(SecretUtil.decrypt3DES(cipherText, key))); + + data = "root"; + key = "abcabcabcabcabcabcabcabc"; + cipherText = SecretUtil.encrypt3DES(data, key); + System.out.println(String.format( + "data[%s] : key[%s] -> cipherText[%s]", data, key, cipherText)); + Assert.assertTrue("0Y08MKGhNIw=".equals(cipherText)); + Assert.assertTrue(data.equals(SecretUtil.decrypt3DES(cipherText, key))); + + data = "rootroot"; + key = "abc"; + cipherText = SecretUtil.encrypt3DES(data, key); + System.out.println(String.format( + "data[%s] : key[%s] -> cipherText[%s]", data, key, cipherText)); + Assert.assertTrue("dUTw4gQQ30qtMDBX0lTpmg==".equals(cipherText)); + Assert.assertTrue(data.equals(SecretUtil.decrypt3DES(cipherText, key))); + + data = "root"; + key = "abc"; + cipherText = SecretUtil.encrypt3DES(data, key); + System.out.println(String.format( + "data[%s] : key[%s] -> cipherText[%s]", data, key, cipherText)); + Assert.assertTrue("TRc4s8bf9Yg=".equals(cipherText)); + Assert.assertTrue(data.equals(SecretUtil.decrypt3DES(cipherText, key))); + + data = "rootrootrootroot"; + key = "abc"; + cipherText = SecretUtil.encrypt3DES(data, key); + System.out.println(String.format( + "data[%s] : key[%s] -> cipherText[%s]", data, key, cipherText)); + Assert.assertTrue("dUTw4gQQ30p1RPDiBBDfSq0wMFfSVOma".equals(cipherText)); + Assert.assertTrue(data.equals(SecretUtil.decrypt3DES(cipherText, key))); + } + + @Test + public void test() throws Exception { + this.testRsa(); + System.out.println("\n\n"); + this.testDes(); + } +} diff --git a/core/src/test/resources/all.json b/core/src/test/resources/all.json new file mode 100755 index 000000000..909708640 --- /dev/null +++ b/core/src/test/resources/all.json @@ -0,0 +1,163 @@ + +{ + "entry": { + "jvm": "-Xms1G -Xmx1G", + "environment": { + "PATH": "/home/admin", + "DATAX_HOME": "/home/admin" + } + }, + "common": { + "column": { + "datetimeFormat": "yyyy-MM-dd HH:mm:ss", + "timeFormat": "HH:mm:ss", + "dateFormat": "yyyy-MM-dd", + "extraFormats":["yyyyMMdd"], + "timeZone": "GMT+8", + "encoding": "utf-8" + } + }, + "core": { + "dataXServer": { + "address": "http://localhost/", + "timeout": 10000 + }, + "transport": { + "channel": { + "class": "com.alibaba.datax.core.transport.channel.memory.MemoryChannel", + "speed": { + "byte": 1048576, + "record": 10000 + }, + "capacity": 32 + }, + "exchanger": { + "class": "com.alibaba.datax.core.plugin.BufferedRecordExchanger", + "bufferSize": 32 + } + }, + "container": { + "job": { + "reportInterval": 1000 + }, + "taskGroup": { + "channel": 3 + } + }, + "statistics": { + "collector": { + "plugin": { + "taskClass": "com.alibaba.datax.core.statistics.plugin.task.StdoutPluginCollector", + "maxDirtyNumber": 1000 + } + } + } + }, + "plugin": { + "reader": { + "mysqlreader": { + "name": "fakereader", + "class": "com.alibaba.datax.plugins.reader.fakereader.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "oraclereader": { + "name": "oraclereader", + "class": "com.alibaba.datax.plugins.reader.oraclereader.OracleReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "fakereader": { + "name": "fakereader", + "class": "com.alibaba.datax.core.faker.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "writer": { + "fakewriter": { + "name": "fakewriter", + "class": "com.alibaba.datax.core.faker.FakeWriter", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "transformer": { + "groovyTranformer": {} + } + }, + "job": { + "setting": { + "speed": { + "byte": 104857600 + }, + "errorLimit": { + "record": null, + "percentage": null + } + }, + "preHandler":{ + "pluginType":"writer", + "pluginName":"fakewriter" + }, + "postHandler":{ + "pluginType":"writer", + "pluginName":"fakewriter" + }, + "content": [ + { + "reader": { + "name": "fakereader", + "parameter": { + "jdbcUrl": [ + [ + "jdbc:mysql://localhost:3305/db1", + "jdbc:mysql://localhost:3306/db1" + ], + [ + "jdbc:mysql://localhost:3305/db2", + "jdbc:mysql://localhost:3306/db2" + ] + ], + "table": [ + "bazhen_[0-15]", + "bazhen_[15-31]" + ] + } + }, + "writer": { + "name": "fakewriter", + "parameter": { + "column": [ + { + "type": "string", + "name": "id" + }, + { + "type": "int", + "name": "age" + } + ], + "encode": "utf-8" + } + } + } + ] + } +} diff --git a/core/src/test/resources/conf/.secret.properties b/core/src/test/resources/conf/.secret.properties new file mode 100755 index 000000000..826d840bd --- /dev/null +++ b/core/src/test/resources/conf/.secret.properties @@ -0,0 +1,11 @@ +#ds basicAuth config +auth.user=datax +auth.pass=datax +last.keyVersion= +last.publicKey= +last.privateKey= +current.keyVersion=201412091312 +current.publicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDE7hkiZukRMdrb3pCsjG149BObagDjn7y4B+qde1pET9RxbzXP9bhmS63C4e8WzKmYbMd6o8paCtYn+S7R60vYFjoEwgb4p3aGPC8sp5AkpBeQXAADFZFJ7zxN1se3LMa2/UKxIjO9OA3aSieAczKd3ChmGo4Vi3hFIrecTG7oXQIDAQAB +current.privateKey=MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMTuGSJm6REx2tvekKyMbXj0E5tqAOOfvLgH6p17WkRP1HFvNc/1uGZLrcLh7xbMqZhsx3qjyloK1if5LtHrS9gWOgTCBvindoY8LyynkCSkF5BcAAMVkUnvPE3Wx7csxrb9QrEiM704DdpKJ4BzMp3cKGYajhWLeEUit5xMbuhdAgMBAAECgYEAn+CFe059LT6CZjpczhj7z1SojmYS7rmCZw3WRaAdepQs7yLQV1MwL6yFF1CB4MqrbVny4PgUkeF2V+GPR1F1sj2emYdBDBqmTj8gn5aF8xXvfHUl1uH3VnIyDQHnMG0FTSH0f1QgEv7L4WkpuLM1lcBpegkJCcuTcMt+fm3GoEECQQDvDxPyoB2K1PMLzta9aO4ZaaBLS/ggdVaPFcqlDdY0hDSuquHeWqTfvPwI3yZkc6nyhUvQNiKTKqasucSXnTGlAkEA0uK75OWQkGmuLyPwOSGTbFhW6Z0DzvtdhO1TtIBZ3y8DGr8G1a/kzNYWcEQjOK50Ula7jLymSA/lO79Dx9kuWQJBAN6bmMSu6rOT9rsBIaABLO6HGFflZym6eh8FeM1X5CbFEVWxFGD84Vji34LXYSXbOt711xIMxwdpiQmAdxuDqm0CQHKxQ5VS0RPplgUnW5AG1cH4LZSyg46/oPYZiQvDPp2mWN7kA9iV6C8LRHrcY/eA0dyyNSBuvVS16GtdM4TudkkCQQCyo2hFVn/zSbZYV02LPR47IkN2dEkNTr8j4dXcPqAy3rkx18Me86RwraHBJ0TLs6mMbRBRo5AimpH47Z9iVDdb + + diff --git a/core/src/test/resources/conf/core.json b/core/src/test/resources/conf/core.json new file mode 100755 index 000000000..64aede6b9 --- /dev/null +++ b/core/src/test/resources/conf/core.json @@ -0,0 +1,51 @@ +{ + "entry": { + "jvm": "-Xms1G -Xmx1G", + "environment": { + "PATH": "/home/admin", + "DATAX_HOME": "/home/admin" + } + }, + "common": { + "column": { + "datetimeFormat": "yyyy-MM-dd HH:mm:ss", + "timeFormat": "HH:mm:ss", + "dateFormat": "yyyy-MM-dd", + "extraFormats":["yyyyMMdd"], + "timeZone": "GMT+8", + "encoding": "utf-8" + } + }, + "core": { + "channel": { + "class": "com.alibaba.datax.core.MemoryChannel", + "speed": 1000000, + "capacity": 128, + "queue": { + "class": "com.alibaba.datax.core.transport.channel.memory.DoubleQueue", + "timeOut": 30 + } + }, + "container": { + "job": { + }, + "taskGroup": { + }, + "model": "master", + "id": 1 + }, + "statistics": { + "collector": { + "plugin": { + "maxDirtyNumber": 1000 + } + } + }, + "plugin": { + "exchanger": { + "class": "com.alibaba.datax.core.plugin.BufferedRecordExchanger", + "bufferSize": 32 + } + } + } +} \ No newline at end of file diff --git a/core/src/test/resources/conf/logback.xml b/core/src/test/resources/conf/logback.xml new file mode 100755 index 000000000..f2f73ea84 --- /dev/null +++ b/core/src/test/resources/conf/logback.xml @@ -0,0 +1,148 @@ + + + + + + + + + + UTF-8 + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + UTF-8 + ${log.dir}/${ymd}/${log.file.name}-${byMillionSecond}.log + false + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + UTF-8 + ${perf.dir}/${ymd}/${log.file.name}-${byMillionSecond}.log + false + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/test/resources/dryRunAll.json b/core/src/test/resources/dryRunAll.json new file mode 100644 index 000000000..83000b2d5 --- /dev/null +++ b/core/src/test/resources/dryRunAll.json @@ -0,0 +1,157 @@ + +{ + "entry": { + "jvm": "-Xms1G -Xmx1G", + "environment": { + "PATH": "/home/admin", + "DATAX_HOME": "/home/admin" + } + }, + "common": { + "column": { + "datetimeFormat": "yyyy-MM-dd HH:mm:ss", + "timeFormat": "HH:mm:ss", + "dateFormat": "yyyy-MM-dd", + "extraFormats":["yyyyMMdd"], + "timeZone": "GMT+8", + "encoding": "utf-8" + } + }, + "core": { + "dataXServer": { + "address": "http://localhost/", + "timeout": 10000 + }, + "transport": { + "channel": { + "class": "com.alibaba.datax.core.transport.channel.memory.MemoryChannel", + "speed": { + "byte": 1048576, + "record": 10000 + }, + "capacity": 32 + }, + "exchanger": { + "class": "com.alibaba.datax.core.plugin.BufferedRecordExchanger", + "bufferSize": 32 + } + }, + "container": { + "job": { + "reportInterval": 1000 + }, + "taskGroup": { + "channel": 3 + } + }, + "statistics": { + "collector": { + "plugin": { + "taskClass": "com.alibaba.datax.core.statistics.plugin.task.StdoutPluginCollector", + "maxDirtyNumber": 1000 + } + } + } + }, + "plugin": { + "reader": { + "mysqlreader": { + "name": "fakereader", + "class": "com.alibaba.datax.plugins.reader.fakereader.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "oraclereader": { + "name": "oraclereader", + "class": "com.alibaba.datax.plugins.reader.oraclereader.OracleReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + }, + "fakereader": { + "name": "fakereader", + "class": "com.alibaba.datax.core.faker.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "writer": { + "fakewriter": { + "name": "fakewriter", + "class": "com.alibaba.datax.core.faker.FakeWriter", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" + } + }, + "transformer": { + "groovyTranformer": {} + } + }, + "job": { + "setting": { + "dryRun": true, + "speed": { + "byte": 104857600 + }, + "errorLimit": { + "record": null, + "percentage": null + } + }, + "content": [ + { + "reader": { + "name": "fakereader", + "parameter": { + "jdbcUrl": [ + [ + "jdbc:mysql://localhost:3305/db1", + "jdbc:mysql://localhost:3306/db1" + ], + [ + "jdbc:mysql://localhost:3305/db2", + "jdbc:mysql://localhost:3306/db2" + ] + ], + "table": [ + "bazhen_[0-15]", + "bazhen_[15-31]" + ] + } + }, + "writer": { + "name": "fakewriter", + "parameter": { + "column": [ + { + "type": "string", + "name": "id" + }, + { + "type": "int", + "name": "age" + } + ], + "encode": "utf-8", + "hbase-conf": "/home/hbase/hbase-conf.xml" + } + } + } + ] + } +} diff --git a/core/src/test/resources/job/job.json b/core/src/test/resources/job/job.json new file mode 100755 index 000000000..b857fdcb7 --- /dev/null +++ b/core/src/test/resources/job/job.json @@ -0,0 +1,27 @@ +{ + "job": { + "setting": {}, + "content": [ + { + "reader": { + "name": "fakereader", + "parameter": {} + }, + "writer": { + "name": "fakewriter", + "parameter": {} + } + }, + { + "reader": { + "name": "fakereader", + "parameter": {} + }, + "writer": { + "name": "fakewriter", + "parameter": {} + } + } + ] + } +} \ No newline at end of file diff --git a/core/src/test/resources/plugin/reader/fakereader/FakePluginer.jar b/core/src/test/resources/plugin/reader/fakereader/FakePluginer.jar new file mode 100755 index 0000000000000000000000000000000000000000..3a409c85a1e233700ee2cf5402d3277510a29616 GIT binary patch literal 19608 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 literal 0 HcmV?d00001 diff --git a/core/src/test/resources/plugin/reader/fakereader/plugin.json b/core/src/test/resources/plugin/reader/fakereader/plugin.json new file mode 100755 index 000000000..95d544aa9 --- /dev/null +++ b/core/src/test/resources/plugin/reader/fakereader/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "fakereader", + "class": "com.alibaba.datax.core.faker.FakeReader", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" +} \ No newline at end of file diff --git a/core/src/test/resources/plugin/writer/fakewriter/FakePluginer.jar b/core/src/test/resources/plugin/writer/fakewriter/FakePluginer.jar new file mode 100755 index 0000000000000000000000000000000000000000..3a409c85a1e233700ee2cf5402d3277510a29616 GIT binary patch literal 19608 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 literal 0 HcmV?d00001 diff --git a/core/src/test/resources/plugin/writer/fakewriter/plugin.json b/core/src/test/resources/plugin/writer/fakewriter/plugin.json new file mode 100755 index 000000000..f91c496dd --- /dev/null +++ b/core/src/test/resources/plugin/writer/fakewriter/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "fakewriter", + "class": "com.alibaba.datax.core.faker.FakeWriter", + "description": { + "useScene": "only for performance test.", + "mechanism": "Produce Record from memory.", + "warn": "Never use it in your real job." + }, + "developer": "someBody,bug reported to : someBody@someSite" +} \ No newline at end of file diff --git a/datax-all.iml b/datax-all.iml new file mode 100644 index 000000000..eefe946ea --- /dev/null +++ b/datax-all.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/drdsreader/doc/drdsreader.md b/drdsreader/doc/drdsreader.md new file mode 100644 index 000000000..264fbe0ee --- /dev/null +++ b/drdsreader/doc/drdsreader.md @@ -0,0 +1,348 @@ + +# DrdsReader 插件文档 + + +___ + + +## 1 快速介绍 + +DrdsReader插件实现了从DRDS(分布式RDS)读取数据。在底层实现上,DrdsReader通过JDBC连接远程DRDS数据库,并执行相应的sql语句将数据从DRDS库中SELECT出来。 + +DRDS的插件目前DataX只适配了Mysql引擎的场景,DRDS对于DataX而言,就是一套分布式Mysql数据库,并且大部分通信协议遵守Mysql使用场景。 + +## 2 实现原理 + +简而言之,DrdsReader通过JDBC连接器连接到远程的DRDS数据库,并根据用户配置的信息生成查询SELECT SQL语句并发送到远程DRDS数据库,并将该SQL执行返回结果使用DataX自定义的数据类型拼装为抽象的数据集,并传递给下游Writer处理。 + +对于用户配置Table、Column、Where的信息,DrdsReader将其拼接为SQL语句发送到DRDS数据库。不同于普通的Mysql数据库,DRDS作为分布式数据库系统,无法适配所有Mysql的协议,包括复杂的Join等语句,DRDS暂时无法支持。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 配置一个从DRDS数据库同步抽取数据到本地的作业: + +``` +{ + "job": { + "setting": { + "speed": { + //设置传输速度,单位为byte/s,DataX运行会尽可能达到该速度但是不超过它. + "byte": 1048576 + } + //出错限制 + "errorLimit": { + //出错的record条数上限,当大于该值即报错。 + "record": 0, + //出错的record百分比上限 1.0表示100%,0.02表示2% + "percentage": 0.02 + } + }, + "content": [ + { + "reader": { + "name": "drdsReader", + "parameter": { + // 数据库连接用户名 + "username": "root", + // 数据库连接密码 + "password": "root", + "column": [ + "id","name" + ], + "connection": [ + { + "table": [ + "table" + ], + "jdbcUrl": [ + "jdbc:mysql://127.0.0.1:3306/database" + ] + } + ] + } + }, + "writer": { + //writer类型 + "name": "streamwriter", + //是否打印内容 + "parameter": { + "print":true, + } + } + } + ] + } +} + +``` + +* 配置一个自定义SQL的数据库同步任务到本地内容的作业: + +``` +{ + "job": { + "setting": { + }, + "content": [ + { + "reader": { + "name": "drdsreader", + "parameter": { + "username": "root", + "password": "root", + "where": "", + "connection": [ + { + "querySql": [ + "select db_id,on_line_flag from db_info where db_id < 10;" + ], + "jdbcUrl": [ + "jdbc:drds://localhost:3306/database"] + } + ] + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": false, + "encoding": "UTF-8" + } + } + } + ] + } +} +``` + + +### 3.2 参数说明 + +* **jdbcUrl** + + * 描述:描述的是到对端数据库的JDBC连接信息,使用JSON的数组描述.注意,jdbcUrl必须包含在connection配置单元中。DRDSReader中关于jdbcUrl中JSON数组填写一个JDBC连接即可。 + + jdbcUrl按照Mysql官方规范,并可以填写连接附件控制信息。具体请参看[mysql官方文档](http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html)。 + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:数据源的用户名
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:数据源指定用户名的密码
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:所选取需要抽取的表。注意,由于DRDS本身就是分布式数据源,因此填写多张表无意义。系统对多表不做校验。
+ + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:所配置的表中需要同步的列名集合,使用JSON的数组描述字段信息。用户使用*代表默认使用所有列配置,例如['*']。 + + 支持列裁剪,即列可以挑选部分列进行导出。 + + 支持列换序,即列可以不按照表schema信息进行导出。 + + 支持常量配置,用户需要按照Mysql SQL语法格式: + ["id", "\`table\`", "1", "'bazhen.csy'", "null", "to_char(a + 1)", "2.3" , "true"] + id为普通列名,\`table\`为包含保留在的列名,1为整形数字常量,'bazhen.csy'为字符串常量,null为空指针,to_char(a + 1)为表达式,2.3为浮点数,true为布尔值。 + + column必须用户显示指定同步的列集合,不允许为空! + + * 必选:是
+ + * 默认值:无
+ +* **where** + + * 描述:筛选条件,DrdsReader根据指定的column、table、where条件拼接SQL,并根据这个SQL进行数据抽取。例如在做测试时,可以将where条件指定为limit 10;在实际业务场景中,往往会选择当天的数据进行同步,可以将where条件指定为gmt_create > $bizdate 。
。 + + where条件可以有效地进行业务增量同步。where条件不配置或者为空,视作全表同步数据。 + + * 必选:否
+ + * 默认值:无
+ +* **querySql** + + * 描述:在有些业务场景下,where这一配置项不足以描述所筛选的条件,用户可以通过该配置型来自定义筛选SQL。当用户配置了这一项之后,DataX系统就会忽略table,column这些配置型,直接使用这个配置项的内容对数据进行筛选,例如需要进行多表join后同步数据,使用select a,b from table_a join table_b on table_a.id = table_b.id
+ + `当用户配置querySql时,drdsReader直接忽略table、column、where条件的配置`。 + + * 必选:否
+ + * 默认值:无
+ + +### 3.3 类型转换 + +目前DrdsReader支持大部分DRDS类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出DrdsReader针对DRDS类型转换列表: + + +| DataX 内部类型| DRDS 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, mediumint, int, bigint| +| Double |float, double, decimal| +| String |varchar, char, tinytext, text, mediumtext, longtext | +| Date |date, datetime, timestamp, time, year | +| Boolean |bit, bool | +| Bytes |tinyblob, mediumblob, blob, longblob, varbinary | + + +请注意: + +* `除上述罗列字段类型外,其他类型均不支持`。 +* `类似Mysql,tinyint(1)视作整形`。 +* `类似Mysql,bit类型读取目前是未定义状态。` + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 +建表语句: + + CREATE TABLE `tc_biz_vertical_test_0000` ( + `biz_order_id` bigint(20) NOT NULL COMMENT 'id', + `key_value` varchar(4000) NOT NULL COMMENT 'Key-value的内容', + `gmt_create` datetime NOT NULL COMMENT '创建时间', + `gmt_modified` datetime NOT NULL COMMENT '修改时间', + `attribute_cc` int(11) DEFAULT NULL COMMENT '防止并发修改的标志', + `value_type` int(11) NOT NULL DEFAULT '0' COMMENT '类型', + `buyer_id` bigint(20) DEFAULT NULL COMMENT 'buyerid', + `seller_id` bigint(20) DEFAULT NULL COMMENT 'seller_id', + PRIMARY KEY (`biz_order_id`,`value_type`), + KEY `idx_biz_vertical_gmtmodified` (`gmt_modified`) + ) ENGINE=InnoDB DEFAULT CHARSET=gbk COMMENT='tc_biz_vertical' + + +单行记录类似于: + + biz_order_id: 888888888 + key_value: ;orderIds:20148888888,2014888888813800; + gmt_create: 2011-09-24 11:07:20 + gmt_modified: 2011-10-24 17:56:34 + attribute_cc: 1 + value_type: 3 + buyer_id: 8888888 + seller_id: 1 + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu: 24核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz + 2. mem: 48GB + 3. net: 千兆双网卡 + 4. disc: DataX 数据不落磁盘,不统计此项 + +* DRDS数据库机器参数为: + 1. cpu: 32核 Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz + 2. mem: 256GB + 3. net: 千兆双网卡 + 4. disc: BTWL419303E2800RGN INTEL SSDSC2BB800G4 D2010370 + +#### 4.1.3 DataX jvm 参数 + + -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + + +### 4.2 测试报告 + +#### 4.2.1 单表测试报告 + + +| 通道数| 是否按照主键切分| DataX速度(Rec/s)| DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------|--------| --------|--------|--------|--------|--------|--------| + + +说明: + +1. 这里的单表,主键类型为 bigint(20),范围为:190247559466810-570722244711460,从主键范围划分看,数据分布均匀。 +2. 对单表如果没有安装主键切分,那么配置通道个数不会提升速度,效果与1个通道一样。 + + +#### 4.2.2 分表测试报告(2个分库,每个分库16张分表,共计32张分表) + + +| 通道数| DataX速度(Rec/s)|DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------| --------|--------|--------|--------|--------|--------| + + + +## 5 约束限制 + + +### 5.1 一致性视图问题 + +DRDS本身属于分布式数据库,对外无法提供一致性的多库多表视图,不同于Mysql等单库单表同步,DRDSReader无法抽取同一个时间切片的分库分表快照信息,也就是说DataX DrdsReader抽取底层不同的分表将获取不同的分表快照,无法保证强一致性。 + + +### 5.2 数据库编码问题 + +DRDS本身的编码设置非常灵活,包括指定编码到库、表、字段级别,甚至可以均不同编码。优先级从高到低为字段、表、库、实例。我们不推荐数据库用户设置如此混乱的编码,最好在库级别就统一到UTF-8。 + +DrdsReader底层使用JDBC进行数据抽取,JDBC天然适配各类编码,并在底层进行了编码转换。因此DrdsReader不需用户指定编码,可以自动获取编码并转码。 + +对于DRDS底层写入编码和其设定的编码不一致的混乱情况,DrdsReader对此无法识别,对此也无法提供解决方案,对于这类情况,`导出有可能为乱码`。 + +### 5.3 增量数据同步 + +DrdsReader使用JDBC SELECT语句完成数据抽取工作,因此可以使用SELECT...WHERE...进行增量数据抽取,方式有多种: + +* 数据库在线应用写入数据库时,填充modify字段为更改时间戳,包括新增、更新、删除(逻辑删)。对于这类应用,DrdsReader只需要WHERE条件跟上一同步阶段时间戳即可。 +* 对于新增流水型数据,DrdsReader可以WHERE条件后跟上一阶段最大自增ID即可。 + +对于业务上无字段区分新增、修改数据情况,DrdsReader也无法进行增量数据同步,只能同步全量数据。 + +### 5.4 Sql安全性 + +DrdsReader提供querySql语句交给用户自己实现SELECT抽取语句,DrdsReader本身对querySql不做任何安全性校验。这块交由DataX用户方自己保证。 + +## 6 FAQ + +*** + +**Q: DrdsReader同步报错,报错信息为XXX** + + A: 网络或者权限问题,请使用DRDS命令行测试: + + mysql -u -p -h -D -e "select * from <表名>" + +如果上述命令也报错,那可以证实是环境问题,请联系你的DBA。 + +*** + +**Q: 我想同步DRDS增量数据,怎么配置?** + + A: DrdsReader必须业务支持增量字段DataX才能同步增量,例如在淘宝大部分业务表中,通过gmt_modified字段表征这条记录的最新修改时间,那么DataX DrdsReader只需要配置where条件为 + +``` + "where": "Date(add_time) = '2014-06-01'" +``` + +*** + + + diff --git a/drdsreader/drdsreader.iml b/drdsreader/drdsreader.iml new file mode 100644 index 000000000..1f713bbe7 --- /dev/null +++ b/drdsreader/drdsreader.iml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drdsreader/pom.xml b/drdsreader/pom.xml new file mode 100755 index 000000000..0677e0fc8 --- /dev/null +++ b/drdsreader/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + + drdsreader + drdsreader + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + mysql + mysql-connector-java + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + \ No newline at end of file diff --git a/drdsreader/src/main/assembly/package.xml b/drdsreader/src/main/assembly/package.xml new file mode 100755 index 000000000..2d170236a --- /dev/null +++ b/drdsreader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/drdsreader + + + target/ + + drdsreader-0.0.1-SNAPSHOT.jar + + plugin/reader/drdsreader + + + + + + false + plugin/reader/drdsreader/libs + runtime + + + diff --git a/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReader.java b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReader.java new file mode 100755 index 000000000..0e6d33013 --- /dev/null +++ b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReader.java @@ -0,0 +1,150 @@ +package com.alibaba.datax.plugin.reader.drdsreader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader; +import com.alibaba.datax.plugin.rdbms.reader.Constant; +import com.alibaba.datax.plugin.rdbms.reader.Key; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.rdbms.util.TableExpandUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class DrdsReader extends Reader { + + private static final DataBaseType DATABASE_TYPE = DataBaseType.MySql; + private static final Logger LOG = LoggerFactory.getLogger(DrdsReader.class); + + public static class Job extends Reader.Job { + + private Configuration originalConfig = null; + private CommonRdbmsReader.Job commonRdbmsReaderJob; + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + int fetchSize = this.originalConfig.getInt(Constant.FETCH_SIZE, + Integer.MIN_VALUE); + this.originalConfig.set(Constant.FETCH_SIZE, fetchSize); + this.validateConfiguration(); + + this.commonRdbmsReaderJob = new CommonRdbmsReader.Job( + DATABASE_TYPE); + this.commonRdbmsReaderJob.init(this.originalConfig); + } + + @Override + public List split(int adviceNumber) { + return DrdsReaderSplitUtil.doSplit(this.originalConfig, + adviceNumber); + } + + @Override + public void post() { + this.commonRdbmsReaderJob.post(this.originalConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderJob.destroy(this.originalConfig); + } + + private void validateConfiguration() { + // do not splitPk + String splitPk = originalConfig.getString(Key.SPLIT_PK, null); + if (null != splitPk) { + LOG.warn("由于您读取数据库是drds, 所以您不需要配置 splitPk. 如果您不想看到这条提醒,请移除您源头表中配置的 splitPk."); + this.originalConfig.remove(Key.SPLIT_PK); + } + + List conns = this.originalConfig.getList( + Constant.CONN_MARK, Object.class); + if (null == conns || conns.size() != 1) { + throw DataXException.asDataXException( + DBUtilErrorCode.REQUIRED_VALUE, + "您未配置读取数据库jdbcUrl的信息. 正确的配置方式是给 jdbcUrl 配置上您需要读取的连接. 请检查您的配置并作出修改."); + } + Configuration connConf = Configuration + .from(conns.get(0).toString()); + connConf.getNecessaryValue(Key.JDBC_URL, + DBUtilErrorCode.REQUIRED_VALUE); + + // only one jdbcUrl + List jdbcUrls = connConf + .getList(Key.JDBC_URL, String.class); + if (null == jdbcUrls || jdbcUrls.size() != 1) { + throw DataXException.asDataXException( + DBUtilErrorCode.ILLEGAL_VALUE, + "您的jdbcUrl配置信息有误, 因为您配置读取数据库jdbcUrl的数量不正确. 正确的配置方式是配置且只配置 1 个目的 jdbcUrl. 请检查您的配置并作出修改."); + } + // if have table,only one + List tables = connConf.getList(Key.TABLE, String.class); + if (null != tables && tables.size() != 1) { + throw DataXException + .asDataXException(DBUtilErrorCode.ILLEGAL_VALUE, + "您的jdbcUrl配置信息有误. 由于您读取数据库是drds,配置读取源表数目错误. 正确的配置方式是配置且只配置 1 个目的 table. 请检查您的配置并作出修改."); + + } + if (null != tables && tables.size() == 1) { + List expandedTables = TableExpandUtil.expandTableConf( + DATABASE_TYPE, tables); + if (null == expandedTables || expandedTables.size() != 1) { + throw DataXException + .asDataXException(DBUtilErrorCode.ILLEGAL_VALUE, + "您的jdbcUrl配置信息有误. 由于您读取数据库是drds,配置读取源表数目错误. 正确的配置方式是配置且只配置 1 个目的 table. 请检查您的配置并作出修改."); + } + } + + // if have querySql,only one + List querySqls = connConf.getList(Key.QUERY_SQL, + String.class); + if (null != querySqls && querySqls.size() != 1) { + throw DataXException + .asDataXException(DBUtilErrorCode.ILLEGAL_VALUE, + "您的querySql配置信息有误. 由于您读取数据库是drds, 配置读取querySql数目错误. 正确的配置方式是配置且只配置 1 个 querySql. 请检查您的配置并作出修改."); + } + + // warn:other checking about table,querySql in common + } + } + + public static class Task extends Reader.Task { + + private Configuration readerSliceConfig; + private CommonRdbmsReader.Task commonRdbmsReaderTask; + + @Override + public void init() { + this.readerSliceConfig = super.getPluginJobConf(); + this.commonRdbmsReaderTask = new CommonRdbmsReader.Task( + DATABASE_TYPE,super.getTaskGroupId(), super.getTaskId()); + this.commonRdbmsReaderTask.init(this.readerSliceConfig); + + } + + @Override + public void startRead(RecordSender recordSender) { + int fetchSize = this.readerSliceConfig.getInt(Constant.FETCH_SIZE); + + this.commonRdbmsReaderTask.startRead(this.readerSliceConfig, + recordSender, super.getTaskPluginCollector(), fetchSize); + } + + @Override + public void post() { + this.commonRdbmsReaderTask.post(this.readerSliceConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderTask.destroy(this.readerSliceConfig); + } + + } + +} diff --git a/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderErrorCode.java b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderErrorCode.java new file mode 100755 index 000000000..91b3afd49 --- /dev/null +++ b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderErrorCode.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.plugin.reader.drdsreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum DrdsReaderErrorCode implements ErrorCode { + GET_TOPOLOGY_FAILED("DrdsReader-01", "获取 drds 表的拓扑结构失败."),; + + private final String code; + private final String description; + + private DrdsReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderSplitUtil.java b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderSplitUtil.java new file mode 100755 index 000000000..fefd698f7 --- /dev/null +++ b/drdsreader/src/main/java/com/alibaba/datax/plugin/reader/drdsreader/DrdsReaderSplitUtil.java @@ -0,0 +1,121 @@ +package com.alibaba.datax.plugin.reader.drdsreader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.reader.Constant; +import com.alibaba.datax.plugin.rdbms.reader.Key; +import com.alibaba.datax.plugin.rdbms.reader.util.SingleTableSplitUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.util.*; + +public class DrdsReaderSplitUtil { + + private static final Logger LOG = LoggerFactory + .getLogger(DrdsReaderSplitUtil.class); + + public static List doSplit(Configuration originalSliceConfig, + int adviceNumber) { + boolean isTableMode = originalSliceConfig.getBool(Constant.IS_TABLE_MODE).booleanValue(); + int tableNumber = originalSliceConfig.getInt(Constant.TABLE_NUMBER_MARK); + + if (isTableMode && tableNumber == 1) { + //需要先把内层的 table,connection 先放到外层 + String table = originalSliceConfig.getString(String.format("%s[0].%s[0]", Constant.CONN_MARK, Key.TABLE)).trim(); + originalSliceConfig.set(Key.TABLE, table); + + //注意:这里的 jdbcUrl 不是从数组中获取的,因为之前的 master init 方法已经进行过预处理 + String jdbcUrl = originalSliceConfig.getString(String.format("%s[0].%s", Constant.CONN_MARK, Key.JDBC_URL)).trim(); + + originalSliceConfig.set(Key.JDBC_URL, DataBaseType.DRDS.appendJDBCSuffixForReader(jdbcUrl)); + + originalSliceConfig.remove(Constant.CONN_MARK); + return doDrdsReaderSplit(originalSliceConfig); + } else { + throw DataXException.asDataXException(DBUtilErrorCode.CONF_ERROR, "您的配置信息中的表(table)的配置有误. 因为Drdsreader 只需要读取一张逻辑表,后台会通过DRDS Proxy自动获取实际对应物理表的数据. 请检查您的配置并作出修改."); + } + } + + private static List doDrdsReaderSplit(Configuration originalSliceConfig) { + List splittedConfigurations = new ArrayList(); + + Map> topology = getTopology(originalSliceConfig); + if (null == topology || topology.isEmpty()) { + throw DataXException.asDataXException(DrdsReaderErrorCode.GET_TOPOLOGY_FAILED, + "获取 drds 表拓扑结构失败, 拓扑结构不能为空."); + } else { + String table = originalSliceConfig.getString(Key.TABLE).trim(); + String column = originalSliceConfig.getString(Key.COLUMN).trim(); + String where = originalSliceConfig.getString(Key.WHERE, null); + // 不能带英语分号结尾 + String sql = SingleTableSplitUtil + .buildQuerySql(column, table, where); + // 根据拓扑拆分任务 + for (Map.Entry> entry : topology.entrySet()) { + String group = entry.getKey(); + StringBuilder sqlbuilder = new StringBuilder(); + sqlbuilder.append("/*+TDDL({'extra':{'MERGE_UNION':'false'},'type':'direct',"); + sqlbuilder.append("'vtab':'").append(table).append("',"); + sqlbuilder.append("'dbid':'").append(group).append("',"); + sqlbuilder.append("'realtabs':["); + Iterator it = entry.getValue().iterator(); + while (it.hasNext()) { + String realTable = it.next(); + sqlbuilder.append('\'').append(realTable).append('\''); + if (it.hasNext()) { + sqlbuilder.append(','); + } + } + sqlbuilder.append("]})*/"); + sqlbuilder.append(sql); + Configuration param = originalSliceConfig.clone(); + param.set(Key.QUERY_SQL, sqlbuilder.toString()); + splittedConfigurations.add(param); + } + + return splittedConfigurations; + } + } + + + private static Map> getTopology(Configuration configuration) { + Map> topology = new HashMap>(); + + String jdbcURL = configuration.getString(Key.JDBC_URL); + String username = configuration.getString(Key.USERNAME); + String password = configuration.getString(Key.PASSWORD); + String logicTable = configuration.getString(Key.TABLE).trim(); + + Connection conn = null; + ResultSet rs = null; + try { + conn = DBUtil.getConnection(DataBaseType.DRDS, jdbcURL, username, password); + rs = DBUtil.query(conn, "SHOW TOPOLOGY " + logicTable); + while (DBUtil.asyncResultSetNext(rs)) { + String groupName = rs.getString("GROUP_NAME"); + String tableName = rs.getString("TABLE_NAME"); + List tables = topology.get(groupName); + if (tables == null) { + tables = new ArrayList(); + topology.put(groupName, tables); + } + tables.add(tableName); + } + + return topology; + } catch (Exception e) { + throw DataXException.asDataXException(DrdsReaderErrorCode.GET_TOPOLOGY_FAILED, + String.format("获取 drds 表拓扑结构失败.根据您的配置, datax获取不到拓扑信息。相关上下文信息:表:%s, jdbcUrl:%s . 请联系 drds 管理员处理.", logicTable, jdbcURL), e); + } finally { + DBUtil.closeDBResources(rs, null, conn); + } + } + +} + diff --git a/drdsreader/src/main/resources/plugin.json b/drdsreader/src/main/resources/plugin.json new file mode 100755 index 000000000..eaa86d5a4 --- /dev/null +++ b/drdsreader/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "drdsreader", + "class": "com.alibaba.datax.plugin.reader.drdsreader.DrdsReader", + "description": "useScene: prod. mechanism: Jdbc connection using the database, execute select sql, retrieve data from the ResultSet. warn: The more you know about the database, the less problems you encounter.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/drdsreader/src/main/resources/plugin_job_template.json b/drdsreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..cf008227d --- /dev/null +++ b/drdsreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,11 @@ +{ + "name": "drdsreader", + "parameter": { + "jdbcUrl": "", + "username": "", + "password": "", + "table": "", + "column": [], + "where": "" + } +} \ No newline at end of file diff --git a/drdswriter/doc/drdswriter.md b/drdswriter/doc/drdswriter.md new file mode 100644 index 000000000..c3c02c2ec --- /dev/null +++ b/drdswriter/doc/drdswriter.md @@ -0,0 +1,386 @@ +# DataX DRDSWriter + + +--- + + +## 1 快速介绍 + +DRDSWriter 插件实现了写入数据到 DRDS 的目的表的功能。在底层实现上, DRDSWriter 通过 JDBC 连接远程 DRDS 数据库的 Proxy,并执行相应的 replace into ... 的 sql 语句将数据写入 DRDS,特别注意执行的 Sql 语句是 replace into,为了避免数据重复写入,需要你的表具备主键或者唯一性索引(Unique Key)。 + +DRDSWriter 面向ETL开发工程师,他们使用 DRDSWriter 从数仓导入数据到 DRDS。同时 DRDSWriter 亦可以作为数据迁移工具为DBA等用户提供服务。 + + +## 2 实现原理 + +DRDSWriter 通过 DataX 框架获取 Reader 生成的协议数据,通过 `replace into...`(没有遇到主键/唯一性索引冲突时,与 insert into 行为一致,冲突时会用新行替换原有行所有字段) 的语句写入数据到 DRDS。DRDSWriter 累积一定数据,提交给 DRDS 的 Proxy,该 Proxy 内部决定数据是写入一张还是多张表以及多张表写入时如何路由数据。 +
+ + 注意:整个任务至少需要具备 replace into...的权限,是否需要其他权限,取决于你任务配置中在 preSql 和 postSql 中指定的语句。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 这里使用一份从内存产生到 DRDS 导入的数据。 + +```json +{ + "job": { + "setting": { + "speed": { + "channel": 1 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column" : [ + { + "value": "DataX", + "type": "string" + }, + { + "value": 19880808, + "type": "long" + }, + { + "value": "1988-08-08 08:08:08", + "type": "date" + }, + { + "value": true, + "type": "bool" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 1000 + } + }, + "writer": { + "name": "DRDSWriter", + "parameter": { + "writeMode": "insert", + "username": "root", + "password": "root", + "column": [ + "id", + "name" + ], + "preSql": [ + "delete from test" + ], + "connection": [ + { + "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax?useUnicode=true&characterEncoding=gbk", + "table": [ + "test" + ] + } + ] + } + } + } + ] + } +} + +``` + + +### 3.2 参数说明 + +* **jdbcUrl** + + * 描述:目的数据库的 JDBC 连接信息。作业运行时,DataX 会在你提供的 jdbcUrl 后面追加如下属性:yearIsDateType=false&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true + + 注意:1、在一个数据库上只能配置一个 jdbcUrl 值 + 2、一个DRDS 写入任务仅能配置一个 jdbcUrl + 3、jdbcUrl按照Mysql/DRDS官方规范,并可以填写连接附加控制信息,比如想指定连接编码为 gbk ,则在 jdbcUrl 后面追加属性 useUnicode=true&characterEncoding=gbk。具体请参看 Mysql/DRDS官方文档或者咨询对应 DBA。 + + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:目的数据库的用户名
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:目的数据库的密码
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:目的表的表名称。 只能配置一个DRDS 的表名称。 + + 注意:table 和 jdbcUrl 必须包含在 connection 配置单元中 + + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:目的表需要写入数据的字段,字段之间用英文逗号分隔。例如: "column": ["id","name","age"]。如果要依次写入全部列,使用*表示, 例如: "column": ["*"] + + **column配置项必须指定,不能留空!** + + + 注意:1、我们强烈不推荐你这样配置,因为当你目的表字段个数、类型等有改动时,你的任务可能运行不正确或者失败 + 2、此处 column 不能配置任何常量值 + + * 必选:是
+ + * 默认值:否
+ +* **preSql** + + * 描述:写入数据到目的表前,会先执行这里的标准语句。比如你想在导入数据前清空数据表中的数据,那么可以配置为:`"preSql":["delete from yourTableName"]`
+ + * 必选:否
+ + * 默认值:无
+ +* **postSql** + + * 描述:写入数据到目的表后,会执行这里的标准语句。(原理同 preSql )
+ + * 必选:否
+ + * 默认值:无
+ +* **writeMode** + + * 描述:默认为 replace,目前仅支持 replace,可以不配置。
+ + * 必选:否
+ + * 默认值:replace
+ +* **batchSize** + + * 描述:一次性批量提交的记录数大小,该值可以极大减少DataX与DRDS的网络交互次数,并提升整体吞吐量。但是该值设置过大可能会造成DataX运行进程OOM情况。
+ + * 必选:否
+ + * 默认值:
+ +### 3.3 类型转换 + +类似 MysqlWriter ,目前 DRDSWriter 支持大部分 Mysql 类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出 DRDSWriter 针对 Mysql 类型转换列表: + + +| DataX 内部类型| Mysql 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, mediumint, int, bigint, year| +| Double |float, double, decimal| +| String |varchar, char, tinytext, text, mediumtext, longtext | +| Date |date, datetime, timestamp, time | +| Boolean |bit, bool | +| Bytes |tinyblob, mediumblob, blob, longblob, varbinary | + + + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 +建表语句: + +``` +CREATE TABLE `t_job` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '实例id', + `project_id` bigint(20) NOT NULL COMMENT '所属资源组,外键', + `pipeline_name` varchar(128) DEFAULT NULL COMMENT '所属资源组,以后变为非null', + `execute_name` varchar(512) DEFAULT NULL COMMENT '执行脚本', + `context` text NOT NULL COMMENT 'job的配置信息', + `trace_id` varchar(128) DEFAULT NULL COMMENT '外界标志', + `submit_user` varchar(128) DEFAULT NULL COMMENT '提交的用户', + `submit_time` datetime DEFAULT NULL COMMENT '提交时间', + `submit_ip` varchar(64) DEFAULT NULL COMMENT '实例提交的客户端ip', + `start_time` datetime DEFAULT NULL COMMENT '开始执行时间', + `end_user` varchar(128) DEFAULT NULL COMMENT '结束的用户', + `end_time` datetime DEFAULT NULL COMMENT '结束时间', + `log_url` varchar(4096) DEFAULT NULL COMMENT '实例运行log的地址', + `execute_id` varchar(256) DEFAULT NULL COMMENT '执行id', + `execute_ip` varchar(64) DEFAULT NULL COMMENT '执行所在机器ip', + `state` tinyint(3) unsigned DEFAULT '255' COMMENT '实例状态,0-success,1-submit,2-init,3-run,4-fail,5-kill,255-unknown', + `stage` float DEFAULT '0' COMMENT '实例运行进度', + `total_records` bigint(20) unsigned DEFAULT '0' COMMENT '实例总条数', + `total_bytes` bigint(20) unsigned DEFAULT '0' COMMENT '实例总bytes数', + `speed_records` bigint(20) unsigned DEFAULT '0' COMMENT '实例运行速度', + `speed_bytes` bigint(20) unsigned DEFAULT '0' COMMENT '实例运行bytes速度', + `error_records` bigint(20) unsigned DEFAULT '0' COMMENT '实例错误总条数', + `error_bytes` bigint(20) unsigned DEFAULT '0' COMMENT '实例错误总bytes数', + `error_message` text COMMENT '实例错误信息', + PRIMARY KEY (`id`), + KEY `idx_project` (`project_id`), + KEY `idx_pipeline_name` (`pipeline_name`), + KEY `idx_trace_id` (`trace_id`), + KEY `idx_submit_time` (`submit_time`) +) ENGINE=InnoDB AUTO_INCREMENT=645299 DEFAULT CHARSET=utf8 COMMENT='实例的信息表' +``` + +单行记录类似于: + +``` + id: 100605 + project_id: 112 +pipeline_name: jcs_project_128105 + execute_name: NULL + context: {"configuration":{"reader":{"parameter":{"*password":"NTdjMknTWnAlCCyaG3EVQg==","column":"`pugId`,`gmtCreated`,`gmtModified`,`gmtAuthTime`,`gmtLeaveTime`,`merchantId`,`token`,`mac`,`os`,`oauth`,`oauthInfo`","database":"witown","error-limit":"1","ip":"rdsyi7biayi7bia.mysql.rds.aliyuncs.com","port":"3306","table":"wi_pug_106","username":"rnd","where":""},"plugin":"mysql"},"writer":{"parameter":{"*access-key":"+oN7h69a9T64z1fas0CNDWmVeSsIF4i5a8s8HA5HNjo=","access-id":"IlUQ8E7i3CFFbGax","error-limit":"1","partition":"","project":"witown_rds","table":"wi_pug_106"},"plugin":"odps"}},"type":"datax"} + trace_id: NULL + submit_user: 128105 + submit_time: 2014-12-12 11:36:27 + submit_ip: 127.0.0.1 + start_time: 2014-12-12 11:36:27 + end_user: NULL + end_time: 2014-12-12 11:36:41 + log_url: /20141212/cdp/11-36-27/hwdbvm3nju4qcgadwgurv445/ + execute_id: T3_0000184404 + execute_ip: oxsgateway04.cloud.et1 + state: 4 + stage: 0 +total_records: 544 + total_bytes: 42819 +speed_records: 0 + speed_bytes: 0 +error_records: 0 + error_bytes: NULL +error_message: Code:[OdpsWriter-01], Description:[您配置的值不合法.]. - 数据源读取的列数是:11 大于目的端的列数是:10 , DataX 不允许这种行为, 请检查您的配置. +``` + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu: 24核 Intel(R) Xeon(R) CPU E5-2430 0 @ 2.20GHz + 2. mem: 96GB + 3. net: 千兆双网卡 + 4. disc: DataX 数据不落磁盘,不统计此项 + +* DRDS数据库机器参数为: + 1. 两个实例,每个实例上8个分库,每个分库上一张分表,共计16个分库16张分表 + 2. mem: 1200M + 3. 磁盘: 40960M + 4. mysql类型: MySQL5.6 + 5. 最大连接数: 300 + 6. 最大IOPS: 600 + +#### 4.1.3 DataX jvm 参数 + + -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + + +### 4.2 测试报告 + +压测基于jdbcUrl里添加了选项`rewriteBatchedStatements=true`
+ +#### 4.2.1 replace测试报告 + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DRDS QPS| 备注 | +|--------|--------| --------|--------|--------|--------|--------|--------| +| 1 | 128 | 260 | 0.39 | 0.34 | 0.03 | 2 | | +| 1 | 512 | 256 | 0.36 | 0.38 | 0.03 | 1 | | +| 1 | 1024 | 256 | 0.35 | max:0.81 min:0.002 | 0.36 | 0 | 波动很大 | +| 4 | 128 | 1011 | 1.22 | 1.75 | 0.14 | 7 | | +| 4 | 512 | 1024 | 1.27 | 1.84 | 0.06 | 1 | | +| 4 | 1024 | 1024 | 1.3 | max:2.82 min:0.76 | 0.23 | 1 | | +| 8 | 128 | 1190 | 1.6 | 2.26 | 0.15 | 6 | | +| 8 | 512 | | | | | | IndexOutOfBoundsException报错 | + +初步定位报错是drds那边通过sql去获取表元信息的时候,返回结果为空 + +#### 4.2.2 insert ignore测试报告 + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DRDS QPS| 备注 | +|--------|--------| --------|--------|--------|--------|--------|--------| +| 1 | 128 | 2444 | 3.43 | 3.41 | 0.13 | 12 | | +| 1 | 512 | 2099 | 3.00 | 2.99 | 0.13 | 3 | | +| 1 | 1024 | 2048 | 2.91 | 3.06 | 0.17 | 1 | | +| 4 | 128 | 7923 | 8.75 | 10.7 | 0.17 | 26 | | +| 4 | 512 | 8662 | 10.05 | 11.92 | 0.17 | 7 | | +| 4 | 1024 | 8211 | 10.20 | 12.74 | 0.29 | 3 | | +| 8 | 128 | | | | | | 抛错IndexOutOfBoundsException | + +#### 4.2.3 单条小数据数据量较小情况(insert ignore插入模式) +``` +建表语句 +CREATE TABLE `tddl_users` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `gmt_create` datetime NOT NULL, + `gmt_modified` datetime NOT NULL, + `name` varchar(200) NOT NULL, + `address` varchar(500) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk; + +数据值 +sun,aaa,2015-04-21 00:00:00,2015-04-21 01:00:00,kkk +``` + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DRDS QPS| 备注 | +|--------|--------| --------|--------|--------|--------|--------|--------| +| 1 | 1 | 108 | 0.005 | 0.042 | 0.08 | 110 | | +| 1 | 32 | 2611 | 0.117 | 0.188 | 0.20 | 42 | | +| 1 | 128 | 8012 | 0.36 | 0.531 | 0.4 | 37 | | +| 1 | 512 | 16025 | 0.718 | 1.12 | 0.15 | 27 | | +| 1 | 1024 | 19046 | 0.85 | 1.2 | 0.30 | 13 | | +| 1 | 40960 | 22595 | 1.01 | 1.31 | 1.27 | 1 | | + +#### 4.2.4 性能小节 + +单条数据量较大情况下: + +1. batchSize的增加对性能影响不大,且太多会导致网络波动太大,建议batchSize设置为128 + +2. 并发对写入性能影响很大,但到了8个并发就会抛错IndexOutOfBoundsException,`感觉是datax内部代码有问题` + +3. insert ignore的性能比replace好很多,用户可以根据业务场景来选取insert ignore + +4. 以上性能均是在rewriteBatchedStatements=true情况下测试的,需要datax把该选项加入到默认配置中 + +单条数据量较小情况下 + +5. batchSize设置大一点影响还是蛮大的 + +## 5 约束限制 + + +## FAQ + +*** + +**Q: DRDSWriter 执行 postSql 语句报错,那么数据导入到目标数据库了吗?** + +A: DataX 导入过程存在三块逻辑,pre 操作、导入操作、post 操作,其中任意一环报错,DataX 作业报错。由于 DataX 不能保证在同一个事务完成上述几个操作,因此有可能数据已经落入到目标端。 + +*** + +**Q: 按照上述说法,那么有部分脏数据导入数据库,如果影响到线上数据库怎么办?** + +A: 目前有两种解法,第一种配置 pre 语句,该 sql 可以清理当天导入数据, DataX 每次导入时候可以把上次清理干净并导入完整数据。第二种,向临时表导入数据,完成后再 rename 到线上表。 + +*** + +**Q: 上面第二种方法可以避免对线上数据造成影响,那我具体怎样操作?** + +A: 可以配置临时表导入 diff --git a/drdswriter/drdswriter.iml b/drdswriter/drdswriter.iml new file mode 100644 index 000000000..1f713bbe7 --- /dev/null +++ b/drdswriter/drdswriter.iml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drdswriter/pom.xml b/drdswriter/pom.xml new file mode 100755 index 000000000..6873c8fbc --- /dev/null +++ b/drdswriter/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + + drdswriter + drdswriter + jar + + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + + mysql + mysql-connector-java + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + \ No newline at end of file diff --git a/drdswriter/src/main/assembly/package.xml b/drdswriter/src/main/assembly/package.xml new file mode 100755 index 000000000..f3c893ac3 --- /dev/null +++ b/drdswriter/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/drdswriter + + + target/ + + drdswriter-0.0.1-SNAPSHOT.jar + + plugin/writer/drdswriter + + + + + + false + plugin/writer/drdswriter/libs + runtime + + + diff --git a/drdswriter/src/main/java/com/alibaba/datax/plugin/writer/drdswriter/DrdsWriter.java b/drdswriter/src/main/java/com/alibaba/datax/plugin/writer/drdswriter/DrdsWriter.java new file mode 100755 index 000000000..b2bf0ac4e --- /dev/null +++ b/drdswriter/src/main/java/com/alibaba/datax/plugin/writer/drdswriter/DrdsWriter.java @@ -0,0 +1,97 @@ +package com.alibaba.datax.plugin.writer.drdswriter; + + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter; +import com.alibaba.datax.plugin.rdbms.writer.Key; + +import java.util.List; + +public class DrdsWriter extends Writer { + private static final DataBaseType DATABASE_TYPE = DataBaseType.DRDS; + + public static class Job extends Writer.Job { + private Configuration originalConfig = null; + private String DEFAULT_WRITEMODE = "replace"; + private String INSERT_IGNORE_WRITEMODE = "insert ignore"; + private CommonRdbmsWriter.Job commonRdbmsWriterJob; + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + String writeMode = this.originalConfig.getString(Key.WRITE_MODE, DEFAULT_WRITEMODE); + if (!DEFAULT_WRITEMODE.equalsIgnoreCase(writeMode) && + !INSERT_IGNORE_WRITEMODE.equalsIgnoreCase(writeMode)) { + throw DataXException.asDataXException(DBUtilErrorCode.CONF_ERROR, + String.format("写入模式(writeMode)配置错误. DRDSWriter只支持两种写入模式为:[%s, %s], 但是您配置的写入模式为:%s. 请检查您的配置并作出修改.", + DEFAULT_WRITEMODE, INSERT_IGNORE_WRITEMODE, writeMode)); + } + + this.originalConfig.set(Key.WRITE_MODE, writeMode); + this.commonRdbmsWriterJob = new CommonRdbmsWriter.Job(DATABASE_TYPE); + this.commonRdbmsWriterJob.init(this.originalConfig); + } + + // 对于 Drds 而言,只会暴露一张逻辑表,所以直接在 Master 做 pre,post 操作 + @Override + public void prepare() { + this.commonRdbmsWriterJob.prepare(this.originalConfig); + } + + @Override + public List split(int mandatoryNumber) { + return this.commonRdbmsWriterJob.split(this.originalConfig, mandatoryNumber); + } + + // 一般来说,是需要推迟到 task 中进行post 的执行(单表情况例外) + @Override + public void post() { + this.commonRdbmsWriterJob.post(this.originalConfig); + } + + @Override + public void destroy() { + this.commonRdbmsWriterJob.destroy(this.originalConfig); + } + + } + + public static class Task extends Writer.Task { + private Configuration writerSliceConfig; + private CommonRdbmsWriter.Task commonRdbmsWriterTask; + + @Override + public void init() { + this.writerSliceConfig = super.getPluginJobConf(); + this.commonRdbmsWriterTask = new CommonRdbmsWriter.Task(DATABASE_TYPE); + this.commonRdbmsWriterTask.init(this.writerSliceConfig); + } + + @Override + public void prepare() { + this.commonRdbmsWriterTask.prepare(this.writerSliceConfig); + } + + //TODO 改用连接池,确保每次获取的连接都是可用的(注意:连接可能需要每次都初始化其 session) + public void startWrite(RecordReceiver recordReceiver) { + this.commonRdbmsWriterTask.startWrite(recordReceiver, this.writerSliceConfig, + super.getTaskPluginCollector()); + } + + @Override + public void post() { + this.commonRdbmsWriterTask.post(this.writerSliceConfig); + } + + @Override + public void destroy() { + this.commonRdbmsWriterTask.destroy(this.writerSliceConfig); + } + + } +} diff --git a/drdswriter/src/main/resources/plugin.json b/drdswriter/src/main/resources/plugin.json new file mode 100755 index 000000000..ad0db036d --- /dev/null +++ b/drdswriter/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "drdswriter", + "class": "com.alibaba.datax.plugin.writer.drdswriter.DrdsWriter", + "description": "useScene: prod. mechanism: Jdbc connection using the database, execute select sql, retrieve data from the ResultSet. warn: The more you know about the database, the less problems you encounter.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/drdswriter/src/main/resources/plugin_job_template.json b/drdswriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..93fcd4efe --- /dev/null +++ b/drdswriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,13 @@ +{ + "name": "drdswriter", + "parameter": { + "jdbcUrl": "", + "username": "", + "password": "", + "table": "", + "column": [], + "writeMode": "", + "preSql": [], + "postSql": [] + } +} \ No newline at end of file diff --git a/ftpreader/doc/ftpreader.md b/ftpreader/doc/ftpreader.md new file mode 100644 index 000000000..3af6fb3a6 --- /dev/null +++ b/ftpreader/doc/ftpreader.md @@ -0,0 +1,292 @@ +# DataX FtpReader 说明 + + +------------ + +## 1 快速介绍 + +FtpReader提供了读取远程FTP文件系统数据存储的能力。在底层实现上,FtpReader获取远程FTP文件数据,并转换为DataX传输协议传递给Writer。 + +**本地文件内容存放的是一张逻辑意义上的二维表,例如CSV格式的文本信息。** + + +## 2 功能与限制 + +FtpReader实现了从远程FTP文件读取数据并转为DataX协议的功能,远程FTP文件本身是无结构化数据存储,对于DataX而言,FtpReader实现上类比TxtFileReader,有诸多相似之处。目前FtpReader支持功能如下: + +1. 支持且仅支持读取TXT的文件,且要求TXT中shema为一张二维表。 + +2. 支持类CSV格式文件,自定义分隔符。 + +3. 支持多种类型数据读取(使用String表示),支持列裁剪,支持列常量 + +4. 支持递归读取、支持文件名过滤。 + +5. 支持文本压缩,现有压缩格式为zip、lzo、lzop、tgz、bzip2。 + +6. 多个File可以支持并发读取。 + +我们暂时不能做到: + +1. 单个File支持多线程并发读取,这里涉及到单个File内部切分算法。二期考虑支持。 + +2. 单个File在压缩情况下,从技术上无法支持多线程并发读取。 + + +## 3 功能说明 + + +### 3.1 配置样例 + +```json +{ + "setting": {}, + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "ftpReader", + "parameter": { + "protocol": "sftp", + "host": "10.101.86.94", + "port": 22, + "username": "xx", + "password": "xxx", + "path": [ + "/home/hanfa.shf/ftpReaderTest/data" + ], + "column": [ + { + "index": 0, + "type": "long" + }, + { + "index": 1, + "type": "boolean" + }, + { + "index": 2, + "type": "double" + }, + { + "index": 3, + "type": "string" + }, + { + "index": 4, + "type": "date", + "format": "yyyy.MM.dd" + } + ], + "encoding": "UTF-8", + "fieldDelimiter": "," + } + }, + "writer": { + "name": "ftpWriter", + "parameter": { + "path": "/home/hanfa.shf/ftpReaderTest/result", + "fileName": "shihf", + "writeMode": "truncate", + "format": "yyyy-MM-dd" + } + } + } + ] + } +} +``` + +### 3.2 参数说明 + +* **protocol** + + * 描述:ftp服务器协议,目前支持传输协议有ftp和sftp。
+ + * 必选:是
+ + * 默认值:无
+ +* **host** + + * 描述:ftp服务器地址。
+ + * 必选:是
+ + * 默认值:无
+ +* **port** + + * 描述:ftp服务器端口。
+ + * 必选:否
+ + * 默认值:若传输协议是sftp协议,默认值是22;若传输协议是标准ftp协议,默认值是21
+ +* **timeout** + + * 描述:连接ftp服务器连接超时时间,单位毫秒。
+ + * 必选:否
+ + * 默认值:60000(1分钟)
+* **connectPattern** + + * 描述:连接模式(主动模式或者被动模式)。该参数只在传输协议是标准ftp协议时使用,值只能为:PORT (主动),PASV(被动)。两种模式主要的不同是数据连接建立的不同。对于Port模式,是客户端在本地打开一个端口等服务器去连接建立数据连接,而Pasv模式就是服务器打开一个端口等待客户端去建立一个数据连接。
+ + * 必选:否
+ + * 默认值:PASV
+ +* **username** + + * 描述:ftp服务器访问用户名。
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:ftp服务器访问密码。
+ + * 必选:是
+ + * 默认值:无
+ +* **path** + + * 描述:远程FTP文件系统的路径信息,注意这里可以支持填写多个路径。
+ + 当指定单个远程FTP文件,FtpReader暂时只能使用单线程进行数据抽取。二期考虑在非压缩文件情况下针对单个File可以进行多线程并发读取。 + + 当指定多个远程FTP文件,FtpReader支持使用多线程进行数据抽取。线程并发数通过通道数指定。 + + 当指定通配符,FtpReader尝试遍历出多个文件信息。例如: 指定/*代表读取/目录下所有的文件,指定/bazhen/\*代表读取bazhen目录下游所有的文件。**FtpReader目前只支持\*作为文件通配符。** + + **特别需要注意的是,DataX会将一个作业下同步的所有Text File视作同一张数据表。用户必须自己保证所有的File能够适配同一套schema信息。读取文件用户必须保证为类CSV格式,并且提供给DataX权限可读。** + + **特别需要注意的是,如果Path指定的路径下没有符合匹配的文件抽取,DataX将报错。** + + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:读取字段列表,type指定源数据的类型,index指定当前列来自于文本第几列(以0开始),value指定当前类型为常量,不从源头文件读取数据,而是根据value值自动生成对应的列。
+ + 默认情况下,用户可以全部按照String类型读取数据,配置如下: + + ```json + "column": ["*"] + ``` + + 用户可以指定Column字段信息,配置如下: + + ```json + { + "type": "long", + "index": 0 //从远程FTP文件文本第一列获取int字段 + }, + { + "type": "string", + "value": "alibaba" //从FtpReader内部生成alibaba的字符串字段作为当前字段 + } + ``` + + 对于用户指定Column信息,type必须填写,index/value必须选择其一。 + + * 必选:是
+ + * 默认值:全部按照string类型读取
+ +* **fieldDelimiter** + + * 描述:读取的字段分隔符
+ + * 必选:是
+ + * 默认值:,
+ +* **compress** + + * 描述:文本压缩类型,默认不填写意味着没有压缩。支持压缩类型为gzip、bzip2。
+ + * 必选:否
+ + * 默认值:没有压缩
+ +* **encoding** + + * 描述:读取文件的编码配置。
+ + * 必选:否
+ + * 默认值:utf-8
+ +* **skipHeader** + + * 描述:类CSV格式文件可能存在表头为标题情况,需要跳过。默认不跳过。
+ + * 必选:否
+ + * 默认值:false
+ +* **nullFormat** + + * 描述:文本文件中无法使用标准字符串定义null(空指针),DataX提供nullFormat定义哪些字符串可以表示为null。
+ + 例如如果用户配置: nullFormat:"\N",那么如果源头数据是"\N",DataX视作null字段。 + + * 必选:否
+ + * 默认值:\N
+ +* **maxTraversalLevel** + + * 描述:允许遍历文件夹的最大层数。
+ + * 必选:否
+ + * 默认值:100
+ + +### 3.3 类型转换 + +远程FTP文件本身不提供数据类型,该类型是DataX FtpReader定义: + +| DataX 内部类型| 远程FTP文件 数据类型 | +| -------- | ----- | +| +| Long |Long | +| Double |Double| +| String |String| +| Boolean |Boolean | +| Date |Date | + +其中: + +* 远程FTP文件 Long是指远程FTP文件文本中使用整形的字符串表示形式,例如"19901219"。 +* 远程FTP文件 Double是指远程FTP文件文本中使用Double的字符串表示形式,例如"3.1415"。 +* 远程FTP文件 Boolean是指远程FTP文件文本中使用Boolean的字符串表示形式,例如"true"、"false"。不区分大小写。 +* 远程FTP文件 Date是指远程FTP文件文本中使用Date的字符串表示形式,例如"2014-12-31",Date可以指定format格式。 + + +## 4 性能报告 + + + +## 5 约束限制 + +略 + +## 6 FAQ + +略 + diff --git a/ftpreader/ftpreader.iml b/ftpreader/ftpreader.iml new file mode 100644 index 000000000..47f2ef4d8 --- /dev/null +++ b/ftpreader/ftpreader.iml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ftpreader/pom.xml b/ftpreader/pom.xml new file mode 100755 index 000000000..28121bafd --- /dev/null +++ b/ftpreader/pom.xml @@ -0,0 +1,92 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + ftpreader + ftpreader + FtpReader提供了读取指定ftp服务器文件功能,并可以根据用户配置的类型进行类型转换,建议开发、测试环境使用。 + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + com.alibaba.datax + plugin-unstructured-storage-util + ${datax-project-version} + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + com.google.guava + guava + 16.0.1 + + + + com.jcraft + jsch + 0.1.51 + + + commons-net + commons-net + 3.3 + + + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + \ No newline at end of file diff --git a/ftpreader/src/main/assembly/package.xml b/ftpreader/src/main/assembly/package.xml new file mode 100755 index 000000000..4c340a4cb --- /dev/null +++ b/ftpreader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/ftpreader + + + target/ + + ftpreader-0.0.1-SNAPSHOT.jar + + plugin/reader/ftpreader + + + + + + false + plugin/reader/ftpreader/libs + runtime + + + diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Constant.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Constant.java new file mode 100755 index 000000000..15019fdb5 --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Constant.java @@ -0,0 +1,14 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + + +public class Constant { + public static final String SOURCE_FILES = "sourceFiles"; + + public static final int DEFAULT_FTP_PORT = 21; + public static final int DEFAULT_SFTP_PORT = 22; + public static final int DEFAULT_TIMEOUT = 60000; + public static final int DEFAULT_MAX_TRAVERSAL_LEVEL = 100; + public static final String DEFAULT_FTP_CONNECT_PATTERN = "PASV"; + + +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpHelper.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpHelper.java new file mode 100644 index 000000000..f8b3f56f2 --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpHelper.java @@ -0,0 +1,107 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +import java.io.InputStream; +import java.util.HashSet; +import java.util.List; + +public abstract class FtpHelper { + /** + * + * @Title: LoginFtpServer + * @Description: 与ftp服务器建立连接 + * @param @param host + * @param @param username + * @param @param password + * @param @param port + * @param @param timeout + * @param @param connectMode + * @return void + * @throws + */ + public abstract void loginFtpServer(String host, String username, String password, int port, int timeout,String connectMode) ; + /** + * + * @Title: LogoutFtpServer + * todo 方法名首字母 + * @Description: 断开与ftp服务器的连接 + * @param + * @return void + * @throws + */ + public abstract void logoutFtpServer(); + /** + * + * @Title: isDirExist + * @Description: 判断指定路径是否是目录 + * @param @param directoryPath + * @param @return + * @return boolean + * @throws + */ + public abstract boolean isDirExist(String directoryPath); + /** + * + * @Title: isFileExist + * @Description: 判断指定路径是否是文件 + * @param @param filePath + * @param @return + * @return boolean + * @throws + */ + public abstract boolean isFileExist(String filePath); + /** + * + * @Title: isSymbolicLink + * @Description: 判断指定路径是否是软链接 + * @param @param filePath + * @param @return + * @return boolean + * @throws + */ + public abstract boolean isSymbolicLink(String filePath); + /** + * + * @Title: getListFiles + * @Description: 递归获取指定路径下符合条件的所有文件绝对路径 + * @param @param directoryPath + * @param @param parentLevel 父目录的递归层数(首次为0) + * @param @param maxTraversalLevel 允许的最大递归层数 + * @param @return + * @return HashSet + * @throws + */ + public abstract HashSet getListFiles(String directoryPath, int parentLevel, int maxTraversalLevel); + + /** + * + * @Title: getInputStream + * @Description: 获取指定路径的输入流 + * @param @param filePath + * @param @return + * @return InputStream + * @throws + */ + public abstract InputStream getInputStream(String filePath); + + /** + * + * @Title: getAllFiles + * @Description: 获取指定路径列表下符合条件的所有文件的绝对路径 + * @param @param srcPaths 路径列表 + * @param @param parentLevel 父目录的递归层数(首次为0) + * @param @param maxTraversalLevel 允许的最大递归层数 + * @param @return + * @return HashSet + * @throws + */ + public HashSet getAllFiles(List srcPaths, int parentLevel, int maxTraversalLevel){ + HashSet sourceAllFiles = new HashSet(); + if (!srcPaths.isEmpty()) { + for (String eachPath : srcPaths) { + sourceAllFiles.addAll(getListFiles(eachPath, parentLevel, maxTraversalLevel)); + } + } + return sourceAllFiles; + } + +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReader.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReader.java new file mode 100644 index 000000000..3802a5f69 --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReader.java @@ -0,0 +1,244 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.unstructuredstorage.reader.UnstructuredStorageReaderUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +/** + * + * @ClassName: FtpFileReader + * @date 2015年7月6日 上午9:24:57 + * + */ +public class FtpReader extends Reader { + public static class Job extends Reader.Job { + private static final Logger LOG = LoggerFactory.getLogger(Job.class); + + private Configuration originConfig = null; + + private List path = null; + + private HashSet sourceFiles; + + // ftp链接参数 + private String protocol; + private String host; + private int port; + private String username; + private String password; + private int timeout; + private String connectPattern; + private int maxTraversalLevel; + + private FtpHelper ftpHelper = null; + + @Override + public void init() { + this.originConfig = this.getPluginJobConf(); + this.sourceFiles = new HashSet(); + + this.validateParameter(); + UnstructuredStorageReaderUtil.validateParameter(this.originConfig); + + if ("sftp".equals(protocol)) { + //sftp协议 + this.port = originConfig.getInt(Key.PORT, Constant.DEFAULT_SFTP_PORT); + this.ftpHelper = new SftpHelper(); + } else if ("ftp".equals(protocol)) { + // ftp 协议 + this.port = originConfig.getInt(Key.PORT, Constant.DEFAULT_FTP_PORT); + this.ftpHelper = new StandardFtpHelper(); + } + ftpHelper.loginFtpServer(host, username, password, port, timeout, connectPattern); + + } + + private void validateParameter() { + //todo 常量 + this.protocol = this.originConfig.getNecessaryValue(Key.PROTOCOL, FtpReaderErrorCode.REQUIRED_VALUE); + boolean ptrotocolTag = "ftp".equals(this.protocol) || "sftp".equals(this.protocol); + if (!ptrotocolTag) { + throw DataXException.asDataXException(FtpReaderErrorCode.ILLEGAL_VALUE, + String.format("仅支持 ftp和sftp 传输协议 , 不支持您配置的传输协议: [%s]", protocol)); + } + this.host = this.originConfig.getNecessaryValue(Key.HOST, FtpReaderErrorCode.REQUIRED_VALUE); + this.username = this.originConfig.getNecessaryValue(Key.USERNAME, FtpReaderErrorCode.REQUIRED_VALUE); + this.password = this.originConfig.getNecessaryValue(Key.PASSWORD, FtpReaderErrorCode.REQUIRED_VALUE); + this.timeout = originConfig.getInt(Key.TIMEOUT, Constant.DEFAULT_TIMEOUT); + this.maxTraversalLevel = originConfig.getInt(Key.MAXTRAVERSALLEVEL, Constant.DEFAULT_MAX_TRAVERSAL_LEVEL); + + // only support connect pattern + this.connectPattern = this.originConfig.getUnnecessaryValue(Key.CONNECTPATTERN, Constant.DEFAULT_FTP_CONNECT_PATTERN, null); + boolean connectPatternTag = "PORT".equals(connectPattern) || "PASV".equals(connectPattern); + if (!connectPatternTag) { + throw DataXException.asDataXException(FtpReaderErrorCode.ILLEGAL_VALUE, + String.format("不支持您配置的ftp传输模式: [%s]", connectPattern)); + }else{ + this.originConfig.set(Key.CONNECTPATTERN, connectPattern); + } + + //path check + String pathInString = this.originConfig.getNecessaryValue(Key.PATH, FtpReaderErrorCode.REQUIRED_VALUE); + if (!pathInString.startsWith("[") && !pathInString.endsWith("]")) { + path = new ArrayList(); + path.add(pathInString); + } else { + path = this.originConfig.getList(Key.PATH, String.class); + if (null == path || path.size() == 0) { + throw DataXException.asDataXException(FtpReaderErrorCode.REQUIRED_VALUE, "您需要指定待读取的源目录或文件"); + } + for (String eachPath : path) { + if(!eachPath.startsWith("/")){ + String message = String.format("请检查参数path:[%s],需要配置为绝对路径", eachPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.ILLEGAL_VALUE, message); + } + } + } + + } + + @Override + public void prepare() { + LOG.debug("prepare() begin..."); + + this.sourceFiles = ftpHelper.getAllFiles(path, 0, maxTraversalLevel); + + LOG.info(String.format("您即将读取的文件数为: [%s]", this.sourceFiles.size())); + } + + @Override + public void post() { + } + + @Override + public void destroy() { + ftpHelper.logoutFtpServer(); + } + + // warn: 如果源目录为空会报错,拖空目录意图=>空文件显示指定此意图 + @Override + public List split(int adviceNumber) { + LOG.debug("split() begin..."); + List readerSplitConfigs = new ArrayList(); + + // warn:每个slice拖且仅拖一个文件, + // int splitNumber = adviceNumber; + int splitNumber = this.sourceFiles.size(); + if (0 == splitNumber) { + throw DataXException.asDataXException(FtpReaderErrorCode.EMPTY_DIR_EXCEPTION, + String.format("未能找到待读取的文件,请确认您的配置项path: %s", this.originConfig.getString(Key.PATH))); + } + + List> splitedSourceFiles = this.splitSourceFiles(new ArrayList(this.sourceFiles), splitNumber); + for (List files : splitedSourceFiles) { + Configuration splitedConfig = this.originConfig.clone(); + splitedConfig.set(Constant.SOURCE_FILES, files); + readerSplitConfigs.add(splitedConfig); + } + LOG.debug("split() ok and end..."); + return readerSplitConfigs; + } + + private List> splitSourceFiles(final List sourceList, int adviceNumber) { + List> splitedList = new ArrayList>(); + int averageLength = sourceList.size() / adviceNumber; + averageLength = averageLength == 0 ? 1 : averageLength; + + for (int begin = 0, end = 0; begin < sourceList.size(); begin = end) { + end = begin + averageLength; + if (end > sourceList.size()) { + end = sourceList.size(); + } + splitedList.add(sourceList.subList(begin, end)); + } + return splitedList; + } + + } + + public static class Task extends Reader.Task { + private static Logger LOG = LoggerFactory.getLogger(Task.class); + + private String host; + private int port; + private String username; + private String password; + private String protocol; + private int timeout; + private String connectPattern; + + private Configuration readerSliceConfig; + private List sourceFiles; + + private FtpHelper ftpHelper = null; + + @Override + public void init() {//连接重试 + /* for ftp connection */ + this.readerSliceConfig = this.getPluginJobConf(); + this.host = readerSliceConfig.getString(Key.HOST); + this.protocol = readerSliceConfig.getString(Key.PROTOCOL); + this.username = readerSliceConfig.getString(Key.USERNAME); + this.password = readerSliceConfig.getString(Key.PASSWORD); + this.timeout = readerSliceConfig.getInt(Key.TIMEOUT, Constant.DEFAULT_TIMEOUT); + + this.sourceFiles = this.readerSliceConfig.getList(Constant.SOURCE_FILES, String.class); + + if ("sftp".equals(protocol)) { + //sftp协议 + this.port = readerSliceConfig.getInt(Key.PORT, Constant.DEFAULT_SFTP_PORT); + this.ftpHelper = new SftpHelper(); + } else if ("ftp".equals(protocol)) { + // ftp 协议 + this.port = readerSliceConfig.getInt(Key.PORT, Constant.DEFAULT_FTP_PORT); + this.connectPattern = readerSliceConfig.getString(Key.CONNECTPATTERN, Constant.DEFAULT_FTP_CONNECT_PATTERN);// 默认为被动模式 + this.ftpHelper = new StandardFtpHelper(); + } + ftpHelper.loginFtpServer(host, username, password, port, timeout, connectPattern); + + } + + @Override + public void prepare() { + + } + + @Override + public void post() { + + } + + @Override + public void destroy() { + ftpHelper.logoutFtpServer(); + } + + @Override + public void startRead(RecordSender recordSender) { + LOG.debug("start read source files..."); + for (String fileName : this.sourceFiles) { + LOG.info(String.format("reading file : [%s]", fileName)); + InputStream inputStream = null; + + inputStream = ftpHelper.getInputStream(fileName); + + UnstructuredStorageReaderUtil.readFromStream(inputStream, fileName, this.readerSliceConfig, + recordSender, this.getTaskPluginCollector()); + recordSender.flush(); + } + + LOG.debug("end read source files..."); + } + + } +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReaderErrorCode.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReaderErrorCode.java new file mode 100755 index 000000000..8c71a2061 --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/FtpReaderErrorCode.java @@ -0,0 +1,52 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * Created by haiwei.luo on 14-9-20. + */ +public enum FtpReaderErrorCode implements ErrorCode { + REQUIRED_VALUE("FtpReader-00", "您缺失了必须填写的参数值."), + ILLEGAL_VALUE("FtpReader-01", "您填写的参数值不合法."), + MIXED_INDEX_VALUE("FtpReader-02", "您的列信息配置同时包含了index,value."), + NO_INDEX_VALUE("FtpReader-03","您明确的配置列信息,但未填写相应的index,value."), + + FILE_NOT_EXISTS("FtpReader-04", "您配置的目录文件路径不存在或者没有权限读取."), + OPEN_FILE_WITH_CHARSET_ERROR("FtpReader-05", "您配置的文件编码和实际文件编码不符合."), + OPEN_FILE_ERROR("FtpReader-06", "您配置的文件在打开时异常."), + READ_FILE_IO_ERROR("FtpReader-07", "您配置的文件在读取时出现IO异常."), + SECURITY_NOT_ENOUGH("FtpReader-08", "您缺少权限执行相应的文件操作."), + CONFIG_INVALID_EXCEPTION("FtpReader-09", "您的参数配置错误."), + RUNTIME_EXCEPTION("FtpReader-10", "出现运行时异常, 请联系我们"), + EMPTY_DIR_EXCEPTION("FtpReader-11", "您尝试读取的文件目录为空."), + + FAIL_LOGIN("FtpReader-12", "登录失败,无法与ftp服务器建立连接."), + FAIL_DISCONNECT("FtpReader-13", "关闭ftp连接失败,无法与ftp服务器断开连接."), + COMMAND_FTP_IO_EXCEPTION("FtpReader-14", "与ftp服务器连接异常."), + OUT_MAX_DIRECTORY_LEVEL("FtpReader-15", "超出允许的最大目录层数."), + LINK_FILE("FtpReader-16", "您尝试读取的文件为链接文件."),; + + private final String code; + private final String description; + + private FtpReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s].", this.code, + this.description); + } +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Key.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Key.java new file mode 100755 index 000000000..cdbd043cd --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/Key.java @@ -0,0 +1,13 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +public class Key { + public static final String PROTOCOL = "protocol"; + public static final String HOST = "host"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String PORT = "port"; + public static final String TIMEOUT = "timeout"; + public static final String CONNECTPATTERN = "connectPattern"; + public static final String PATH = "path"; + public static final String MAXTRAVERSALLEVEL = "maxTraversalLevel"; +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/SftpHelper.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/SftpHelper.java new file mode 100644 index 000000000..cbf53520b --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/SftpHelper.java @@ -0,0 +1,247 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +import java.io.InputStream; +import java.util.HashSet; +import java.util.Properties; +import java.util.Vector; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.plugin.reader.ftpreader.FtpReader.Job; +import com.alibaba.datax.plugin.unstructuredstorage.reader.UnstructuredStorageReaderUtil; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpException; +import com.jcraft.jsch.ChannelSftp.LsEntry; + +public class SftpHelper extends FtpHelper { + private static final Logger LOG = LoggerFactory.getLogger(Job.class); + + Session session = null; + ChannelSftp channelSftp = null; + @Override + public void loginFtpServer(String host, String username, String password, int port, int timeout, + String connectMode) { + JSch jsch = new JSch(); // 创建JSch对象 + try { + session = jsch.getSession(username, host, port); + // 根据用户名,主机ip,端口获取一个Session对象 + // 如果服务器连接不上,则抛出异常 + if (session == null) { + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, + "session is null,无法通过sftp与服务器建立链接,请检查主机名和用户名是否正确."); + } + + session.setPassword(password); // 设置密码 + Properties config = new Properties(); + config.put("StrictHostKeyChecking", "no"); + session.setConfig(config); // 为Session对象设置properties + session.setTimeout(timeout); // 设置timeout时间 + session.connect(); // 通过Session建立链接 + + channelSftp = (ChannelSftp) session.openChannel("sftp"); // 打开SFTP通道 + channelSftp.connect(); // 建立SFTP通道的连接 + + //设置命令传输编码 + //String fileEncoding = System.getProperty("file.encoding"); + //channelSftp.setFilenameEncoding(fileEncoding); + } catch (JSchException e) { + if(null != e.getCause()){ + String cause = e.getCause().toString(); + String unknownHostException = "java.net.UnknownHostException: " + host; + String illegalArgumentException = "java.lang.IllegalArgumentException: port out of range:" + port; + String wrongPort = "java.net.ConnectException: Connection refused"; + if (unknownHostException.equals(cause)) { + String message = String.format("请确认ftp服务器地址是否正确,无法连接到地址为: [%s] 的ftp服务器", host); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } else if (illegalArgumentException.equals(cause) || wrongPort.equals(cause) ) { + String message = String.format("请确认连接ftp服务器端口是否正确,错误的端口: [%s] ", port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } + }else { + if("Auth fail".equals(e.getMessage())){ + String message = String.format("与ftp服务器建立连接失败,请检查用户名和密码是否正确: [%s]", + "message:host =" + host + ",username = " + username + ",port =" + port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message); + }else{ + String message = String.format("与ftp服务器建立连接失败 : [%s]", + "message:host =" + host + ",username = " + username + ",port =" + port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } + } + } + + } + + @Override + public void logoutFtpServer() { + if (channelSftp != null) { + channelSftp.disconnect(); + } + if (session != null) { + session.disconnect(); + } + } + + @Override + public boolean isDirExist(String directoryPath) { + try { + SftpATTRS sftpATTRS = channelSftp.lstat(directoryPath); + return sftpATTRS.isDir(); + } catch (SftpException e) { + if (e.getMessage().toLowerCase().equals("no such file")) { + String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限读取", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + String message = String.format("进入目录:[%s]时发生I/O异常,请确认与ftp服务器的连接正常", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + } + + @Override + public boolean isFileExist(String filePath) { + boolean isExitFlag = false; + try { + SftpATTRS sftpATTRS = channelSftp.lstat(filePath); + if(sftpATTRS.getSize() >= 0){ + isExitFlag = true; + } + } catch (SftpException e) { + if (e.getMessage().toLowerCase().equals("no such file")) { + String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } else { + String message = String.format("获取文件:[%s] 属性时发生I/O异常,请确认与ftp服务器的连接正常", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + } + return isExitFlag; + } + + @Override + public boolean isSymbolicLink(String filePath) { + try { + SftpATTRS sftpATTRS = channelSftp.lstat(filePath); + return sftpATTRS.isLink(); + } catch (SftpException e) { + if (e.getMessage().toLowerCase().equals("no such file")) { + String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } else { + String message = String.format("获取文件:[%s] 属性时发生I/O异常,请确认与ftp服务器的连接正常", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + } + } + + HashSet sourceFiles = new HashSet(); + @Override + public HashSet getListFiles(String directoryPath, int parentLevel, int maxTraversalLevel) { + if(parentLevel < maxTraversalLevel){ + String parentPath = null;// 父级目录,以'/'结尾 + int pathLen = directoryPath.length(); + if (directoryPath.contains("*") || directoryPath.contains("?")) {//*和?的限制 + // path是正则表达式 + String subPath = UnstructuredStorageReaderUtil.getRegexPathParentPath(directoryPath); + if (isDirExist(subPath)) { + parentPath = subPath; + } else { + String message = String.format("不能进入目录:[%s]," + "请确认您的配置项path:[%s]存在,且配置的用户有权限进入", subPath, + directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + + } else if (isDirExist(directoryPath)) { + // path是目录 + if (directoryPath.charAt(pathLen - 1) == IOUtils.DIR_SEPARATOR) { + parentPath = directoryPath; + } else { + parentPath = directoryPath + IOUtils.DIR_SEPARATOR; + } + } else if(isSymbolicLink(directoryPath)){ + //path是链接文件 + String message = String.format("文件:[%s]是链接文件,当前不支持链接文件的读取", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.LINK_FILE, message); + }else if (isFileExist(directoryPath)) { + // path指向具体文件 + sourceFiles.add(directoryPath); + return sourceFiles; + } else { + String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限读取", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + + try { + Vector vector = channelSftp.ls(directoryPath); + for (int i = 0; i < vector.size(); i++) { + LsEntry le = (LsEntry) vector.get(i); + String strName = le.getFilename(); + String filePath = parentPath + strName; + + if (isDirExist(filePath)) { + // 是子目录 + if (!(strName.equals(".") || strName.equals(".."))) { + //递归处理 + getListFiles(filePath, parentLevel+1, maxTraversalLevel); + } + } else if(isSymbolicLink(filePath)){ + //是链接文件 + String message = String.format("文件:[%s]是链接文件,当前不支持链接文件的读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.LINK_FILE, message); + }else if (isFileExist(filePath)) { + // 是文件 + sourceFiles.add(filePath); + } else { + String message = String.format("请确认path:[%s]存在,且配置的用户有权限读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + + } // end for vector + } catch (SftpException e) { + String message = String.format("获取path:[%s] 下文件列表时发生I/O异常,请确认与ftp服务器的连接正常", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + + return sourceFiles; + }else{ + //超出最大递归层数 + String message = String.format("获取path:[%s] 下文件列表时超出最大层数,请确认路径[%s]下不存在软连接文件", directoryPath, directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.OUT_MAX_DIRECTORY_LEVEL, message); + } + } + + @Override + public InputStream getInputStream(String filePath) { + try { + return channelSftp.get(filePath); + } catch (SftpException e) { + String message = String.format("读取文件 : [%s] 时出错,请确认文件:[%s]存在且配置的用户有权限读取", filePath, filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.OPEN_FILE_ERROR, message); + } + } + +} diff --git a/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/StandardFtpHelper.java b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/StandardFtpHelper.java new file mode 100644 index 000000000..0ff6b5938 --- /dev/null +++ b/ftpreader/src/main/java/com/alibaba/datax/plugin/reader/ftpreader/StandardFtpHelper.java @@ -0,0 +1,229 @@ +package com.alibaba.datax.plugin.reader.ftpreader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.UnknownHostException; +import java.util.HashSet; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPReply; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.plugin.reader.ftpreader.FtpReader.Job; +import com.alibaba.datax.plugin.unstructuredstorage.reader.UnstructuredStorageReaderUtil; + +public class StandardFtpHelper extends FtpHelper { + private static final Logger LOG = LoggerFactory.getLogger(Job.class); + FTPClient ftpClient = null; + + @Override + public void loginFtpServer(String host, String username, String password, int port, int timeout, + String connectMode) { + ftpClient = new FTPClient(); + try { + // 连接 + ftpClient.connect(host, port); + // 登录 + ftpClient.login(username, password); + ftpClient.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX)); + ftpClient.setConnectTimeout(timeout); + ftpClient.setDataTimeout(timeout); + if ("PASV".equals(connectMode)) { + ftpClient.enterRemotePassiveMode(); + ftpClient.enterLocalPassiveMode(); + } else if ("PORT".equals(connectMode)) { + ftpClient.enterLocalActiveMode(); + // ftpClient.enterRemoteActiveMode(host, port); + } + int reply = ftpClient.getReplyCode(); + if (!FTPReply.isPositiveCompletion(reply)) { + ftpClient.disconnect(); + String message = String.format("与ftp服务器建立连接失败,请检查用户名和密码是否正确: [%s]", + "message:host =" + host + ",username = " + username + ",port =" + port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message); + } + //设置命令传输编码 + String fileEncoding = System.getProperty("file.encoding"); + ftpClient.setControlEncoding(fileEncoding); + } catch (UnknownHostException e) { + String message = String.format("请确认ftp服务器地址是否正确,无法连接到地址为: [%s] 的ftp服务器", host); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } catch (IllegalArgumentException e) { + String message = String.format("请确认连接ftp服务器端口是否正确,错误的端口: [%s] ", port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } catch (Exception e) { + String message = String.format("与ftp服务器建立连接失败 : [%s]", + "message:host =" + host + ",username = " + username + ",port =" + port); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_LOGIN, message, e); + } + + } + + @Override + public void logoutFtpServer() { + if (ftpClient.isConnected()) { + try { + //todo ftpClient.completePendingCommand();//打开流操作之后必须,原因还需要深究 + ftpClient.logout(); + } catch (IOException e) { + String message = "与ftp服务器断开连接失败"; + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_DISCONNECT, message, e); + }finally { + if(ftpClient.isConnected()){ + try { + ftpClient.disconnect(); + } catch (IOException e) { + String message = "与ftp服务器断开连接失败"; + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FAIL_DISCONNECT, message, e); + } + } + + } + } + } + + @Override + public boolean isDirExist(String directoryPath) { + try { + return ftpClient.changeWorkingDirectory(new String(directoryPath.getBytes(),FTP.DEFAULT_CONTROL_ENCODING)); + } catch (IOException e) { + String message = String.format("进入目录:[%s]时发生I/O异常,请确认与ftp服务器的连接正常", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + } + + @Override + public boolean isFileExist(String filePath) { + boolean isExitFlag = false; + try { + FTPFile[] ftpFiles = ftpClient.listFiles(new String(filePath.getBytes(),FTP.DEFAULT_CONTROL_ENCODING)); + if (ftpFiles.length == 1 && ftpFiles[0].isFile()) { + isExitFlag = true; + } + } catch (IOException e) { + String message = String.format("获取文件:[%s] 属性时发生I/O异常,请确认与ftp服务器的连接正常", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + return isExitFlag; + } + + @Override + public boolean isSymbolicLink(String filePath) { + boolean isExitFlag = false; + try { + FTPFile[] ftpFiles = ftpClient.listFiles(new String(filePath.getBytes(),FTP.DEFAULT_CONTROL_ENCODING)); + if (ftpFiles.length == 1 && ftpFiles[0].isSymbolicLink()) { + isExitFlag = true; + } + } catch (IOException e) { + String message = String.format("获取文件:[%s] 属性时发生I/O异常,请确认与ftp服务器的连接正常", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + return isExitFlag; + } + + HashSet sourceFiles = new HashSet(); + @Override + public HashSet getListFiles(String directoryPath, int parentLevel, int maxTraversalLevel) { + if(parentLevel < maxTraversalLevel){ + String parentPath = null;// 父级目录,以'/'结尾 + int pathLen = directoryPath.length(); + if (directoryPath.contains("*") || directoryPath.contains("?")) { + // path是正则表达式 + String subPath = UnstructuredStorageReaderUtil.getRegexPathParentPath(directoryPath); + if (isDirExist(subPath)) { + parentPath = subPath; + } else { + String message = String.format("不能进入目录:[%s]," + "请确认您的配置项path:[%s]存在,且配置的用户有权限进入", subPath, + directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + } else if (isDirExist(directoryPath)) { + // path是目录 + if (directoryPath.charAt(pathLen - 1) == IOUtils.DIR_SEPARATOR) { + parentPath = directoryPath; + } else { + parentPath = directoryPath + IOUtils.DIR_SEPARATOR; + } + } else if (isFileExist(directoryPath)) { + // path指向具体文件 + sourceFiles.add(directoryPath); + return sourceFiles; + } else if(isSymbolicLink(directoryPath)){ + //path是链接文件 + String message = String.format("文件:[%s]是链接文件,当前不支持链接文件的读取", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.LINK_FILE, message); + }else { + String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限读取", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + + try { + FTPFile[] fs = ftpClient.listFiles(new String(directoryPath.getBytes(),FTP.DEFAULT_CONTROL_ENCODING)); + for (FTPFile ff : fs) { + String strName = ff.getName(); + String filePath = parentPath + strName; + if (ff.isDirectory()) { + if (!(strName.equals(".") || strName.equals(".."))) { + //递归处理 + getListFiles(filePath, parentLevel+1, maxTraversalLevel); + } + } else if (ff.isFile()) { + // 是文件 + sourceFiles.add(filePath); + } else if(ff.isSymbolicLink()){ + //是链接文件 + String message = String.format("文件:[%s]是链接文件,当前不支持链接文件的读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.LINK_FILE, message); + }else { + String message = String.format("请确认path:[%s]存在,且配置的用户有权限读取", filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.FILE_NOT_EXISTS, message); + } + } // end for FTPFile + } catch (IOException e) { + String message = String.format("获取path:[%s] 下文件列表时发生I/O异常,请确认与ftp服务器的连接正常", directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e); + } + return sourceFiles; + + } else{ + //超出最大递归层数 + String message = String.format("获取path:[%s] 下文件列表时超出最大层数,请确认路径[%s]下不存在软连接文件", directoryPath, directoryPath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.OUT_MAX_DIRECTORY_LEVEL, message); + } + } + + @Override + public InputStream getInputStream(String filePath) { + try { + return ftpClient.retrieveFileStream(new String(filePath.getBytes(),FTP.DEFAULT_CONTROL_ENCODING)); + } catch (IOException e) { + String message = String.format("读取文件 : [%s] 时出错,请确认文件:[%s]存在且配置的用户有权限读取", filePath, filePath); + LOG.error(message); + throw DataXException.asDataXException(FtpReaderErrorCode.OPEN_FILE_ERROR, message); + } + } + +} diff --git a/ftpreader/src/main/resources/plugin-template.json b/ftpreader/src/main/resources/plugin-template.json new file mode 100755 index 000000000..9680aec67 --- /dev/null +++ b/ftpreader/src/main/resources/plugin-template.json @@ -0,0 +1,38 @@ +{ + "name": "ftpreader", + "parameter": { + "host": "", + "port": "", + "username": "", + "password": "", + "protocol": "", + "path": [ + "" + ], + "encoding": "UTF-8", + "column": [ + { + "index": 0, + "type": "long" + }, + { + "index": 1, + "type": "boolean" + }, + { + "index": 2, + "type": "double" + }, + { + "index": 3, + "type": "string" + }, + { + "index": 4, + "type": "date", + "format": "yyyy.MM.dd" + } + ], + "fieldDelimiter": "," + } +} diff --git a/ftpreader/src/main/resources/plugin.json b/ftpreader/src/main/resources/plugin.json new file mode 100755 index 000000000..ce5ce26b9 --- /dev/null +++ b/ftpreader/src/main/resources/plugin.json @@ -0,0 +1,7 @@ +{ + "name": "ftpreader", + "class": "com.alibaba.datax.plugin.reader.ftpreader.FtpReader", + "description": "useScene: test. mechanism: use datax framework to transport data from txt file. warn: The more you know about the data, the less problems you encounter.", + "developer": "alibaba" +} + diff --git a/ftpreader/src/main/resources/plugin_job_template.json b/ftpreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..88f429f3e --- /dev/null +++ b/ftpreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,19 @@ +{ + "name": "ftpreader", + "parameter": { + "host": "", + "protocol": "sftp", + "port":"", + "username": "", + "password": "", + "path": [], + "column": [ + { + "index": 0, + "type": "" + } + ], + "fieldDelimiter": ",", + "encoding": "UTF-8" + } +} \ No newline at end of file diff --git a/hbasereader/doc/hbasereader.md b/hbasereader/doc/hbasereader.md new file mode 100644 index 000000000..4a6c77364 --- /dev/null +++ b/hbasereader/doc/hbasereader.md @@ -0,0 +1,347 @@ + +# HbaseReader 插件文档 + + +___ + + + +## 1 快速介绍 + +HbaseReader 插件实现了从 Hbase 读取数据。在底层实现上,HbaseReader 通过 HBase 的 Java 客户端连接远程 HBase 服务,并通过 Scan 方式读取数据。典型示例如下: + + + Scan scan = new Scan(); + scan.setStartRow(startKey); + scan.setStopRow(endKey); + + ResultScanner resultScanner = table.getScanner(scan); + for(Result r:resultScanner){ + System.out.println(new String(r.getRow())); + for(KeyValue kv:r.raw()){ + System.out.println(new String(kv.getValue())); + } + } + + +HbaseReader 需要特别注意如下几点: + +1、HbaseReader 中有一个必填配置项是:hbaseConfig,需要你联系 HBase PE,将hbase-site.xml 中与连接 HBase 相关的配置项提取出来,以 json 格式填入。 + +2、HbaseReader 中的 mode 配置项,必须填写且值只能为:normal 或者 multiVersion。当值为 normal 时,会把 HBase 中的表,当成普通二维表进行读取;当值为 multiVersion 时,会把每一个 cell 中的值,读成 DataX 中的一个 Record,Record 中的格式是: + +| 第0列 | 第1列 | 第2列 | 第3列 | +| --------| ---------------- |----- |----- | +| rowKey | column:qualifier| timestamp | value | + + +## 2 实现原理 + +简而言之,HbaseReader 通过 HBase 的 Java 客户端,通过 HTable, Scan, ResultScanner 等 API,读取你指定 rowkey 范围内的数据,并将读取的数据使用 DataX 自定义的数据类型拼装为抽象的数据集,并传递给下游 Writer 处理。 + + + +## 3 功能说明 + +### 3.1 配置样例 + +* 配置一个从 HBase 抽取数据到本地的作业:(normal 模式) + +``` +{ + "job": { + "setting": { + "speed": { + //设置传输速度,单位为byte/s,DataX运行会尽可能达到该速度但是不超过它. + "byte": 1048576 + } + //出错限制 + "errorLimit": { + //出错的record条数上限,当大于该值即报错。 + "record": 0, + //出错的record百分比上限 1.0表示100%,0.02表示2% + "percentage": 0.02 + } + }, + "content": [ + { + "reader": { + "name": "hbasereader", + "parameter": { + "hbaseConfig": "hbase-site 文件中与连接相关的配置项,以 json 格式填写", + "table": "hbase_test_table", + "encoding": "utf8", + "mode": "normal", + "column": [ + { + "name": "rowkey", + "type": "string" + }, + { + "name": "fb:comm_result_code", + "type": "string" + }, + { + "name": "fb:exchange_amount", + "type": "string" + }, + { + "name": "fb:exchange_status", + "type": "string" + } + ], + "range": { + "startRowkey": "", + "endRowkey": "" + }, + "isBinaryRowkey": true + } + }, + "writer": { + //writer类型 + "name": "streamwriter", + //是否打印内容 + "parameter": { + "print": true + } + } + } + ] + } +} + +``` + +* 配置一个从 HBase 抽取数据到本地的作业:( multiVersion 模式) + +``` + +TODO + +``` + + +### 3.2 参数说明 + +* **hbaseConfig** + + * 描述:每个HBase集群提供给DataX客户端连接 的配置信息存放在hbase-site.xml,请联系你的HBase DBA提供配置信息,并转换为JSON格式填写如下:{"key1":"value1","key2":"value2"}。比如:{"hbase.zookeeper.quorum":"????","hbase.zookeeper.property.clientPort":"????"} 这样的形式。注意:如果是手写json,那么需要把双引号 转义为\" + + * 必选:是
+ + * 默认值:无
+ +* **mode** + + * 描述:normal/multiVersion。。。toto
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:要读取的 hbase 表名(大小写敏感)
+ + * 必选:是
+ + * 默认值:无
+ +* **encoding** + + * 描述:编码方式,UTF-8 或是 GBK,用于对二进制存储的 HBase byte[] 转为 String 时
+ + * 必选:否
+ + * 默认值:UTF-8
+ + +* **column** + + * 描述:TODO。 + + 支持列裁剪,即列可以挑选部分列进行导出。 + + 支持列换序,即列可以不按照表schema信息进行导出。 + + 支持常量配置,用户需要按照如下语法格式: + ["id", "\`table\`", "1", "'bazhen.csy'", "null", "to_char(a + 1)", "2.3" , "true"] + TODO。 + + * 必选:是
+ + * 默认值:无
+ +* **startRowkey** + + * 描述:TODO + + TODO + + * 必选:否
+ + * 默认值:空
+ +* **endRowkey** + + * 描述:TODO
。 + + TODO。 + + * 必选:否
+ + * 默认值:无
+ +* **isBinaryRowkey** + + * 描述:
+ + `当用户配置querySql时,MysqlReader直接忽略table、column、where条件的配置`,querySql优先级大于table、column、where选项。 + + * 必选:否
+ + * 默认值:无
+ + +### 3.3 类型转换(TODO) + +目前 HbaseReader 支持大部分 HBase 类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出 HbaseReader 针对 HBase 类型转换列表: + + +| DataX 内部类型| HBase 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, mediumint, int, bigint| +| Double |float, double, decimal| +| String |varchar, char, tinytext, text, mediumtext, longtext | +| Date |date, datetime, timestamp, time, year | +| Boolean |bit, bool | +| Bytes |tinyblob, mediumblob, blob, longblob, varbinary | + + + +请注意: + +* `除上述罗列字段类型外,其他类型均不支持`。 +* `bit DataX属于未定义行为`。 + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 +建表语句: + + TODO + + +单行记录类似于: + + biz_order_id: 888888888 + key_value: ;orderIds:20148888888,2014888888813800; + gmt_create: 2011-09-24 11:07:20 + gmt_modified: 2011-10-24 17:56:34 + attribute_cc: 1 + value_type: 3 + buyer_id: 8888888 + seller_id: 1 + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu: 24核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz + 2. mem: 48GB + 3. net: 千兆双网卡 + 4. disc: DataX 数据不落磁盘,不统计此项 + +* Mysql数据库机器参数为: + 1. cpu: 32核 Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz + 2. mem: 256GB + 3. net: 千兆双网卡 + 4. disc: BTWL419303E2800RGN INTEL SSDSC2BB800G4 D2010370 + +#### 4.1.3 DataX jvm 参数 + + -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + + +### 4.2 测试报告 + +#### 4.2.1 单表测试报告 + + +| 通道数| 是否按照主键切分| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡进入流量(MB/s)|DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------|--------| --------|--------|--------|--------|--------|--------| +|1| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|1| 是 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|4| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|4| 是 | 329733 | 32.60 | 58| 0.8 | 60| 0.76 | +|8| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|8| 是 | 549556 | 54.33 | 115| 1.46 | 120| 0.78 | + +说明: + +1. 这里的单表,主键类型为 bigint(20),范围为:190247559466810-570722244711460,从主键范围划分看,数据分布均匀。 +2. 对单表如果没有安装主键切分,那么配置通道个数不会提升速度,效果与1个通道一样。 + + +#### 4.2.2 分表测试报告(2个分库,每个分库16张分表,共计32张分表) + + +| 通道数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡进入流量(MB/s)|DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------| --------|--------|--------|--------|--------|--------| +|1| 202241 | 20.06 | 31.5| 1.0 | 32 | 1.1 | +|4| 726358 | 72.04 | 123.9 | 3.1 | 132 | 3.6 | +|8|1074405 | 106.56| 197 | 5.5 | 205| 5.1| +|16| 1227892 | 121.79 | 229.2 | 8.1 | 233 | 7.3 | + +## 5 约束限制 + +### 5.1 ? + +主备同步问题指Mysql使用主从灾备,备库从主库不间断通过binlog恢复数据。由于主备数据同步存在一定的时间差,特别在于某些特定情况,例如网络延迟等问题,导致备库同步恢复的数据与主库有较大差别,导致从备库同步的数据不是一份当前时间的完整镜像。 + +针对这个问题,我们提供了preSql功能,该功能待补充。 + +### 5.2 ? + +Mysql在数据存储划分中属于RDBMS系统,对外可以提供强一致性数据查询接口。例如当一次同步任务启动运行过程中,当该库存在其他数据写入方写入数据时,MysqlReader完全不会获取到写入更新数据,这是由于数据库本身的快照特性决定的。关于数据库快照特性,请参看[MVCC Wikipedia](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) + +上述是在MysqlReader单线程模型下数据同步一致性的特性,由于MysqlReader可以根据用户配置信息使用了并发数据抽取,因此不能严格保证数据一致性:当MysqlReader根据splitPk进行数据切分后,会先后启动多个并发任务完成数据同步。由于多个并发任务相互之间不属于同一个读事务,同时多个并发任务存在时间间隔。因此这份数据并不是`完整的`、`一致的`数据快照信息。 + +针对多线程的一致性快照需求,在技术上目前无法实现,只能从工程角度解决,工程化的方式存在取舍,我们提供几个解决思路给用户,用户可以自行选择: + +1. 使用单线程同步,即不再进行数据切片。缺点是速度比较慢,但是能够很好保证一致性。 + +2. 关闭其他数据写入方,保证当前数据为静态数据,例如,锁表、关闭备库同步等等。缺点是可能影响在线业务。 + +### 5.3 ? + +Mysql本身的编码设置非常灵活,包括指定编码到库、表、字段级别,甚至可以均不同编码。优先级从高到低为字段、表、库、实例。我们不推荐数据库用户设置如此混乱的编码,最好在库级别就统一到UTF-8。 + +MysqlReader底层使用JDBC进行数据抽取,JDBC天然适配各类编码,并在底层进行了编码转换。因此MysqlReader不需用户指定编码,可以自动获取编码并转码。 + +对于Mysql底层写入编码和其设定的编码不一致的混乱情况,MysqlReader对此无法识别,对此也无法提供解决方案,对于这类情况,`导出有可能为乱码`。 + +### 5.4 ? + +MysqlReader使用JDBC SELECT语句完成数据抽取工作,因此可以使用SELECT...WHERE...进行增量数据抽取,方式有多种: + +* 数据库在线应用写入数据库时,填充modify字段为更改时间戳,包括新增、更新、删除(逻辑删)。对于这类应用,MysqlReader只需要WHERE条件跟上一同步阶段时间戳即可。 +* 对于新增流水型数据,MysqlReader可以WHERE条件后跟上一阶段最大自增ID即可。 + +对于业务上无字段区分新增、修改数据情况,MysqlReader也无法进行增量数据同步,只能同步全量数据。 + + +## 6 FAQ + +*** + +**Q: ??同步报错,报错信息为XXX** + + A: 网络或者权限问题,请使用 HBase shell 命令行测试: + + TODO + +如果上述命令也报错,那可以证实是环境问题,请联系你的 PE。 diff --git a/hbasereader/hbasereader.iml b/hbasereader/hbasereader.iml new file mode 100644 index 000000000..8933a9f15 --- /dev/null +++ b/hbasereader/hbasereader.iml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hbasereader/pom.xml b/hbasereader/pom.xml new file mode 100755 index 000000000..50567df39 --- /dev/null +++ b/hbasereader/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + + hbasereader + hbasereader + 0.0.1-SNAPSHOT + + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + org.apache.hbase + hbase + 0.94.27 + + + org.apache.hadoop + hadoop-core + 0.20.205.0 + + + org.apache.zookeeper + zookeeper + 3.3.2 + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + diff --git a/hbasereader/src/main/assembly/package.xml b/hbasereader/src/main/assembly/package.xml new file mode 100755 index 000000000..51ff86f4a --- /dev/null +++ b/hbasereader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/hbasereader + + + target/ + + hbasereader-0.0.1-SNAPSHOT.jar + + plugin/reader/hbasereader + + + + + + false + plugin/reader/hbasereader/libs + runtime + + + diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ColumnType.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ColumnType.java new file mode 100755 index 000000000..a6245722b --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ColumnType.java @@ -0,0 +1,43 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import com.alibaba.datax.common.exception.DataXException; + +import java.util.Arrays; + +/** + * 只对 normal 模式读取时有用,多版本读取时,不存在列类型的 + */ +public enum ColumnType { + STRING("string"), + BINARY_STRING("binarystring"), + BYTES("bytes"), + BOOLEAN("boolean"), + SHORT("short"), + INT("int"), + LONG("long"), + FLOAT("float"), + DOUBLE("double"), + DATE("date"),; + + private String typeName; + + ColumnType(String typeName) { + this.typeName = typeName; + } + + public static ColumnType getByTypeName(String typeName) { + for (ColumnType columnType : values()) { + if (columnType.typeName.equalsIgnoreCase(typeName)) { + return columnType; + } + } + + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, + String.format("Hbasereader 不支持该类型:%s, 目前支持的类型是:%s", typeName, Arrays.asList(values()))); + } + + @Override + public String toString() { + return this.typeName; + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Constant.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Constant.java new file mode 100755 index 000000000..53973a08b --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Constant.java @@ -0,0 +1,10 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +public final class Constant { + public static final String RANGE = "range"; + + public static final String ROWKEY_FLAG = "rowkey"; + + public static final int DEFAULT_SCAN_CACHE = 256; + +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HTableManager.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HTableManager.java new file mode 100755 index 000000000..1747a38c1 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HTableManager.java @@ -0,0 +1,27 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.client.HTable; + +import java.io.IOException; + +public final class HTableManager { + + public static HTable createHTable(Configuration config, String tableName) + throws IOException { + + return new HTable(config, tableName); + } + + public static HBaseAdmin createHBaseAdmin(Configuration config) + throws IOException { + return new HBaseAdmin(config); + } + + public static void closeHTable(HTable hTable) throws IOException { + if (hTable != null) { + hTable.close(); + } + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnCell.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnCell.java new file mode 100755 index 000000000..24f052bb0 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnCell.java @@ -0,0 +1,124 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import com.alibaba.datax.common.base.BaseObject; +import com.alibaba.datax.plugin.reader.hbasereader.util.HbaseUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.hadoop.hbase.util.Bytes; + +/** + * 描述 hbasereader 插件中,column 配置中的一个单元项实体 + */ +public class HbaseColumnCell extends BaseObject { + private ColumnType columnType; + + // columnName 格式为:列族:列名 + private String columnName; + + private byte[] cf; + private byte[] qualifier; + + //对于常量类型,其常量值放到 columnValue 里 + private String columnValue; + + //当配置了 columnValue 时,isConstant=true(这个成员变量是用于方便使用本类的地方判断是否是常量类型字段) + private boolean isConstant; + + // 只在类型是时间类型时,才会设置该值,无默认值。形式如:yyyy-MM-dd HH:mm:ss + private String dateformat; + + private HbaseColumnCell(Builder builder) { + this.columnType = builder.columnType; + + //columnName 和 columnValue 必须有一个为 null + Validate.isTrue(builder.columnName == null || builder.columnValue == null, "Hbasereader 中,column 不能同时配置 列名称 和 列值,二者选其一."); + + //columnName 和 columnValue 不能都为 null + Validate.isTrue(builder.columnName != null || builder.columnValue != null, "Hbasereader 中,column 需要配置 列名称 或者 列值, 二者选其一."); + + if (builder.columnName != null) { + this.isConstant = false; + this.columnName = builder.columnName; + + // 如果 columnName 不是 rowkey,则必须配置为:列族:列名 格式 + if (!HbaseUtil.isRowkeyColumn(this.columnName)) { + + String promptInfo = "Hbasereader 中, column 的列配置格式应该是:列族:列名. 您配置的列错误:" + this.columnName; + String[] cfAndQualifier = this.columnName.split(":"); + Validate.isTrue(cfAndQualifier != null && cfAndQualifier.length == 2 + && StringUtils.isNotBlank(cfAndQualifier[0]) + && StringUtils.isNotBlank(cfAndQualifier[1]), promptInfo); + + this.cf = Bytes.toBytes(cfAndQualifier[0].trim()); + this.qualifier = Bytes.toBytes(cfAndQualifier[1].trim()); + } + } else { + this.isConstant = true; + this.columnValue = builder.columnValue; + } + + if (builder.dateformat != null) { + this.dateformat = builder.dateformat; + } + } + + public ColumnType getColumnType() { + return columnType; + } + + public String getColumnName() { + return columnName; + } + + public byte[] getCf() { + return cf; + } + + public byte[] getQualifier() { + return qualifier; + } + + public String getDateformat() { + return dateformat; + } + + public String getColumnValue() { + return columnValue; + } + + public boolean isConstant() { + return isConstant; + } + + // 内部 builder 类 + public static class Builder { + private ColumnType columnType; + private String columnName; + private String columnValue; + + private String dateformat; + + public Builder(ColumnType columnType) { + this.columnType = columnType; + } + + public Builder columnName(String columnName) { + this.columnName = columnName; + return this; + } + + public Builder columnValue(String columnValue) { + this.columnValue = columnValue; + return this; + } + + public Builder dateformat(String dateformat) { + this.dateformat = dateformat; + return this; + } + + public HbaseColumnCell build() { + return new HbaseColumnCell(this); + } + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnConfig.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnConfig.java new file mode 100755 index 000000000..bf679793e --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseColumnConfig.java @@ -0,0 +1,21 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import java.util.Arrays; + +public class HbaseColumnConfig { + public String[] columnTypes = null; + public String[] columnFamilyAndQualifiers = null; + + public HbaseColumnConfig() { + } + + @Override + public String toString() { + if (null != columnTypes && null != columnFamilyAndQualifiers) { + return "columnTypes:" + Arrays.asList(columnTypes) + "\n" + + "columnNames:" + Arrays.toString(columnFamilyAndQualifiers); + } else { + return null; + } + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReader.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReader.java new file mode 100755 index 000000000..ffe775848 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReader.java @@ -0,0 +1,130 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class HbaseReader extends Reader { + public static class Job extends Reader.Job { + private static Logger LOG = LoggerFactory.getLogger(Job.class); + private static boolean IS_DEBUG = LOG.isDebugEnabled(); + + private Configuration originalConfig; + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + + HbaseUtil.doPretreatment(this.originalConfig); + + if (IS_DEBUG) { + LOG.debug("After init(), now originalConfig is:\n{}\n", this.originalConfig); + } + } + + @Override + public void prepare() { + } + + @Override + public List split(int adviceNumber) { + return HbaseSplitUtil.split(this.originalConfig); + } + + + @Override + public void post() { + + } + + @Override + public void destroy() { + } + + } + + public static class Task extends Reader.Task { + private Configuration taskConfig; + private static Logger LOG = LoggerFactory.getLogger(Task.class); + private HbaseAbstractTask hbaseTaskProxy; + + @Override + public void init() { + this.taskConfig = super.getPluginJobConf(); + + String mode = this.taskConfig.getString(Key.MODE); + ModeType modeType = ModeType.getByTypeName(mode); + + switch (modeType) { + case Normal: + this.hbaseTaskProxy = new NormalTask(this.taskConfig); + break; + case MultiVersionFixedColumn: + this.hbaseTaskProxy = new MultiVersionFixedColumnTask(this.taskConfig); + break; + case MultiVersionDynamicColumn: + this.hbaseTaskProxy = new MultiVersionDynamicColumnTask(this.taskConfig); + break; + default: + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 不支持此类模式:" + modeType); + } + } + + @Override + public void prepare() { + try { + this.hbaseTaskProxy.prepare(); + } catch (Exception e) { + throw DataXException.asDataXException(HbaseReaderErrorCode.PREPAR_READ_ERROR, e); + } + } + + @Override + public void startRead(RecordSender recordSender) { + Record record = recordSender.createRecord(); + boolean fetchOK; + while (true) { + try { + fetchOK = this.hbaseTaskProxy.fetchLine(record); + } catch (Exception e) { + LOG.info("Exception", e); + super.getTaskPluginCollector().collectDirtyRecord(record, e); + record = recordSender.createRecord(); + continue; + } + if (fetchOK) { + recordSender.sendToWriter(record); + record = recordSender.createRecord(); + } else { + break; + } + } + recordSender.flush(); + } + + @Override + public void post() { + super.post(); + } + + @Override + public void destroy() { + if (this.hbaseTaskProxy != null) { + try { + this.hbaseTaskProxy.close(); + } catch (Exception e) { + // + } + } + } + + + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReaderErrorCode.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReaderErrorCode.java new file mode 100755 index 000000000..99275e4bf --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/HbaseReaderErrorCode.java @@ -0,0 +1,37 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum HbaseReaderErrorCode implements ErrorCode { + REQUIRED_VALUE("HbaseReader-00", "您缺失了必须填写的参数值."), + ILLEGAL_VALUE("HbaseReader-01", "您配置的值不合法."), + PREPAR_READ_ERROR("HbaseReader-02", "准备读取 Hbase 时出错."), + SPLIT_ERROR("HbaseReader-03", "切分 Hbase 表时出错."), + INIT_TABLE_ERROR("HbaseReader-04", "初始化 Hbase 抽取表时出错."), + + ; + + private final String code; + private final String description; + + private HbaseReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Key.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Key.java new file mode 100755 index 000000000..42e4b6f00 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/Key.java @@ -0,0 +1,50 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +public final class Key { + + public final static String HBASE_CONFIG = "hbaseConfig"; + + /** + * mode 可以取 normal 或者 multiVersionFixedColumn 或者 multiVersionDynamicColumn 三个值,无默认值。 + *

+ * normal 配合 column(Map 结构的)使用 + *

+ * multiVersionFixedColumn 配合 maxVersion,tetradType, column(List 结构的)使用 + *

+ * multiVersionDynamicColumn 配合 maxVersion,tetradType, columnFamily(List 结构的)使用 + */ + public final static String MODE = "mode"; + + /** + * 配合 mode = multiVersion 时使用,指明需要读取的版本个数。无默认值 + * -1 表示去读全部版本 + * 不能为0,1 + * >1 表示最多读取对应个数的版本数(不能超过 Integer 的最大值) + */ + public final static String MAX_VERSION = "maxVersion"; + + /** + * 多版本情况下,必须配置 四元组的类型(rowkey,column,timestamp,value) + */ + public final static String TETRAD_TYPE = "tetradType"; + + /** + * 默认为 utf8 + */ + public final static String ENCODING = "encoding"; + + public final static String TABLE = "table"; + + public final static String COLUMN_FAMILY = "columnFamily"; + + public final static String COLUMN = "column"; + + public final static String START_ROWKEY = "startRowkey"; + + public final static String END_ROWKEY = "endRowkey"; + + public final static String IS_BINARY_ROWKEY = "isBinaryRowkey"; + + public final static String SCAN_CACHE = "scanCache"; + +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ModeType.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ModeType.java new file mode 100644 index 000000000..3348d0752 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/ModeType.java @@ -0,0 +1,28 @@ +package com.alibaba.datax.plugin.reader.hbasereader; + +import com.alibaba.datax.common.exception.DataXException; + +import java.util.Arrays; + +public enum ModeType { + Normal("normal"), + MultiVersionFixedColumn("multiVersionFixedColumn"), + MultiVersionDynamicColumn("multiVersionDynamicColumn"),; + + private String mode; + + ModeType(String mode) { + this.mode = mode.toLowerCase(); + } + + public static ModeType getByTypeName(String modeName) { + for (ModeType modeType : values()) { + if (modeType.mode.equalsIgnoreCase(modeName)) { + return modeType; + } + } + + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, + String.format("Hbasereader 不支持该 mode 类型:%s, 目前支持的 mode 类型是:%s", modeName, Arrays.asList(values()))); + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseAbstractTask.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseAbstractTask.java new file mode 100755 index 000000000..8061f73dc --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseAbstractTask.java @@ -0,0 +1,89 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.Constant; +import com.alibaba.datax.plugin.reader.hbasereader.HTableManager; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public abstract class HbaseAbstractTask { + private final static Logger LOG = LoggerFactory.getLogger(HbaseAbstractTask.class); + + private int scanCache; + private byte[] startKey = null; + private byte[] endKey = null; + + protected HTable htable; + protected String encoding; + protected Result lastResult = null; + protected Scan scan; + protected ResultScanner resultScanner; + + public HbaseAbstractTask(Configuration configuration) { + this.htable = HbaseUtil.initHtable(configuration); + + this.encoding = configuration.getString(Key.ENCODING); + + this.scanCache = configuration.getInt(Key.SCAN_CACHE, Constant.DEFAULT_SCAN_CACHE); + + this.startKey = HbaseUtil.convertInnerStartRowkey(configuration); + this.endKey = HbaseUtil.convertInnerEndRowkey(configuration); + } + + public abstract boolean fetchLine(Record record) throws Exception; + + public abstract void initScan(Scan scan); + + public void prepare() throws Exception { + this.scan = new Scan(); + scan.setCacheBlocks(false); + + this.scan.setStartRow(startKey); + this.scan.setStopRow(endKey); + + LOG.info("The task set startRowkey=[{}], endRowkey=[{}].", Bytes.toStringBinary(this.startKey), Bytes.toStringBinary(this.endKey)); + + initScan(this.scan); + + this.scan.setCaching(this.scanCache); + this.resultScanner = this.htable.getScanner(this.scan); + } + + + public void close() throws IOException { + if (this.resultScanner != null) { + this.resultScanner.close(); + } + HTableManager.closeHTable(this.htable); + } + + protected Result getNextHbaseRow() throws IOException { + Result result; + try { + result = resultScanner.next(); + } catch (IOException e) { + if (lastResult != null) { + scan.setStartRow(lastResult.getRow()); + } + resultScanner = this.htable.getScanner(scan); + result = resultScanner.next(); + if (lastResult != null && Bytes.equals(lastResult.getRow(), result.getRow())) { + result = resultScanner.next(); + } + } + + lastResult = result; + + // may be null + return result; + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseSplitUtil.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseSplitUtil.java new file mode 100755 index 000000000..59e8ac2ab --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseSplitUtil.java @@ -0,0 +1,149 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.HTableManager; +import com.alibaba.datax.plugin.reader.hbasereader.HbaseReaderErrorCode; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public final class HbaseSplitUtil { + private final static Logger LOG = LoggerFactory.getLogger(HbaseSplitUtil.class); + + + public static List split(Configuration configuration) { + byte[] startRowkeyByte = HbaseUtil.convertUserStartRowkey(configuration); + byte[] endRowkeyByte = HbaseUtil.convertUserEndRowkey(configuration); + + /* 如果用户配置了 startRowkey 和 endRowkey,需要确保:startRowkey <= endRowkey */ + if (startRowkeyByte.length != 0 && endRowkeyByte.length != 0 + && Bytes.compareTo(startRowkeyByte, endRowkeyByte) > 0) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 中 startRowkey 不得大于 endRowkey."); + } + + HTable htable = HbaseUtil.initHtable(configuration); + + List resultConfigurations; + + try { + Pair regionRanges = htable.getStartEndKeys(); + if (null == regionRanges) { + throw DataXException.asDataXException(HbaseReaderErrorCode.SPLIT_ERROR, "获取源头 Hbase 表的 rowkey 范围失败."); + } + + resultConfigurations = HbaseSplitUtil.doSplit(configuration, startRowkeyByte, endRowkeyByte, + regionRanges); + + LOG.info("HBaseReader split job into {} tasks.", resultConfigurations.size()); + + return resultConfigurations; + } catch (Exception e) { + throw DataXException.asDataXException(HbaseReaderErrorCode.SPLIT_ERROR, "切分源头 Hbase 表失败.", e); + } finally { + try { + HTableManager.closeHTable(htable); + } catch (Exception e) { + // + } + } + } + + + private static List doSplit(Configuration config, byte[] startRowkeyByte, + byte[] endRowkeyByte, Pair regionRanges) { + + List configurations = new ArrayList(); + + for (int i = 0; i < regionRanges.getFirst().length; i++) { + + byte[] regionStartKey = regionRanges.getFirst()[i]; + byte[] regionEndKey = regionRanges.getSecond()[i]; + + // 当前的region为最后一个region + // 如果最后一个region的start Key大于用户指定的userEndKey,则最后一个region,应该不包含在内 + // 注意如果用户指定userEndKey为"",则此判断应该不成立。userEndKey为""表示取得最大的region + if (Bytes.compareTo(regionEndKey, HConstants.EMPTY_BYTE_ARRAY) == 0 + && (endRowkeyByte.length != 0 && (Bytes.compareTo( + regionStartKey, endRowkeyByte) > 0))) { + continue; + } + + // 如果当前的region不是最后一个region, + // 用户配置的userStartKey大于等于region的endkey,则这个region不应该含在内 + if ((Bytes.compareTo(regionEndKey, HConstants.EMPTY_BYTE_ARRAY) != 0) + && (Bytes.compareTo(startRowkeyByte, regionEndKey) >= 0)) { + continue; + } + + // 如果用户配置的userEndKey小于等于 region的startkey,则这个region不应该含在内 + // 注意如果用户指定的userEndKey为"",则次判断应该不成立。userEndKey为""表示取得最大的region + if (endRowkeyByte.length != 0 + && (Bytes.compareTo(endRowkeyByte, regionStartKey) <= 0)) { + continue; + } + + Configuration p = config.clone(); + + String thisStartKey = getStartKey(startRowkeyByte, regionStartKey); + + String thisEndKey = getEndKey(endRowkeyByte, regionEndKey); + + p.set(Key.START_ROWKEY, thisStartKey); + p.set(Key.END_ROWKEY, thisEndKey); + + LOG.debug("startRowkey:[{}], endRowkey:[{}] .", thisStartKey, thisEndKey); + + configurations.add(p); + } + + return configurations; + } + + private static String getEndKey(byte[] endRowkeyByte, byte[] regionEndKey) { + if (endRowkeyByte == null) {// 由于之前处理过,所以传入的userStartKey不可能为null + throw new IllegalArgumentException("userEndKey should not be null!"); + } + + byte[] tempEndRowkeyByte; + + if (endRowkeyByte.length == 0) { + tempEndRowkeyByte = regionEndKey; + } else if (Bytes.compareTo(regionEndKey, HConstants.EMPTY_BYTE_ARRAY) == 0) { + // 为最后一个region + tempEndRowkeyByte = endRowkeyByte; + } else { + if (Bytes.compareTo(endRowkeyByte, regionEndKey) > 0) { + tempEndRowkeyByte = regionEndKey; + } else { + tempEndRowkeyByte = endRowkeyByte; + } + } + + return Bytes.toStringBinary(tempEndRowkeyByte); + } + + private static String getStartKey(byte[] startRowkeyByte, byte[] regionStarKey) { + if (startRowkeyByte == null) {// 由于之前处理过,所以传入的userStartKey不可能为null + throw new IllegalArgumentException( + "userStartKey should not be null!"); + } + + byte[] tempStartRowkeyByte; + + if (Bytes.compareTo(startRowkeyByte, regionStarKey) < 0) { + tempStartRowkeyByte = regionStarKey; + } else { + tempStartRowkeyByte = startRowkeyByte; + } + + return Bytes.toStringBinary(tempStartRowkeyByte); + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseUtil.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseUtil.java new file mode 100755 index 000000000..065c37278 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/HbaseUtil.java @@ -0,0 +1,362 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.*; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.util.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class HbaseUtil { + private static Logger LOG = LoggerFactory.getLogger(HbaseUtil.class); + + private static final String META_SCANNER_CACHING = "100"; + + private static final int TETRAD_TYPE_COUNT = 4; + + public static void doPretreatment(Configuration originalConfig) { + originalConfig.getNecessaryValue(Key.HBASE_CONFIG, + HbaseReaderErrorCode.REQUIRED_VALUE); + + originalConfig.getNecessaryValue(Key.TABLE, HbaseReaderErrorCode.REQUIRED_VALUE); + + String mode = HbaseUtil.dealMode(originalConfig); + originalConfig.set(Key.MODE, mode); + + String encoding = originalConfig.getString(Key.ENCODING, "utf-8"); + if (!Charset.isSupported(encoding)) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, String.format("Hbasereader 不支持您所配置的编码:[%s]", encoding)); + } + originalConfig.set(Key.ENCODING, encoding); + + // 此处增强一个检查:isBinaryRowkey 配置不能出现在与 hbaseConfig 等配置平级地位 + Boolean isBinaryRowkey = originalConfig.getBool(Key.IS_BINARY_ROWKEY); + if (isBinaryRowkey != null) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, String.format("%s 不能配置在此处,它应该配置在 range 里面.", Key.IS_BINARY_ROWKEY)); + } + + // 处理 range 的配置,将 range 内的配置值提取到与 hbaseConfig 等配置项平级地位,方便后续获取值 + boolean hasConfiguredRange = false; + String startRowkey = originalConfig.getString(Constant.RANGE + "." + Key.START_ROWKEY); + + //此处判断需要谨慎:如果有 key range.startRowkey 但是没有值,得到的 startRowkey 是空字符串,而不是 null + if (startRowkey != null && startRowkey.length() != 0) { + hasConfiguredRange = true; + originalConfig.set(Key.START_ROWKEY, startRowkey); + } + + String endRowkey = originalConfig.getString(Constant.RANGE + "." + Key.END_ROWKEY); + //此处判断需要谨慎:如果有 key range.endRowkey 但是没有值,得到的 endRowkey 是空字符串,而不是 null + if (endRowkey != null && endRowkey.length() != 0) { + hasConfiguredRange = true; + originalConfig.set(Key.END_ROWKEY, endRowkey); + } + + // 如果配置了 range, 就必须要配置 isBinaryRowkey + if (hasConfiguredRange) { + isBinaryRowkey = originalConfig.getBool(Constant.RANGE + "." + Key.IS_BINARY_ROWKEY); + if (isBinaryRowkey == null) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, "您需要在 range 内配置 isBinaryRowkey 项,用于告诉 DataX 把您填写的 rowkey 转换为内部的二进制时,采用那个 API(值为 true 时,采用Bytes.toBytesBinary(String rowKey),值为 false 时,采用Bytes.toBytes(String rowKey))"); + } + + originalConfig.set(Key.IS_BINARY_ROWKEY, isBinaryRowkey); + } + } + + /** + * 对模式以及与模式进行配对的配置进行检查 + */ + private static String dealMode(Configuration originalConfig) { + String mode = originalConfig.getString(Key.MODE); + + ModeType modeType = ModeType.getByTypeName(mode); + switch (modeType) { + case Normal: { + // normal 模式不需要配置 maxVersion,需要配置 column,并且 column 格式为 Map 风格 + String maxVersion = originalConfig.getString(Key.MAX_VERSION); + Validate.isTrue(maxVersion == null, "您配置的是 normal 模式读取 hbase 中的数据,所以不能配置无关项:maxVersion"); + + List column = originalConfig.getList(Key.COLUMN, Map.class); + + if (column == null || column.isEmpty()) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, "您配置的是 normal 模式读取 hbase 中的数据,所以必须配置 column,其形式为:column:[{\"name\": \"cf0:column0\",\"type\": \"string\"},{\"name\": \"cf1:column1\",\"type\": \"long\"}]"); + } + + // 通过 parse 进行 column 格式的进一步检查 + HbaseUtil.parseColumnOfNormalMode(column); + break; + } + case MultiVersionFixedColumn: { + // multiVersionFixedColumn 模式需要配置 maxVersion 和 column,并且 column 格式为 List 风格 + checkMaxVersion(originalConfig, mode); + + checkTetradType(originalConfig, mode); + + List columns = originalConfig.getList(Key.COLUMN, String.class); + if (columns == null || columns.isEmpty()) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, "您配置的是 multiVersionFixedColumn 模式读取 hbase 中的数据,所以必须配置 column,其形式为: column:[\"cf0:column0\",\"cf1:column1\"]"); + } + + // 检查配置的 column 格式是否包含cf:qualifier + for (String column : columns) { + if (StringUtils.isBlank(column) || column.split(":").length != 2) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, String.format("您配置的是 multiVersionFixedColumn 模式读取 hbase 中的数据,但是您配置的列格式[%s]不正确,每一个列元素应该配置为 列族:列名 的形式, 如 column:[\"cf0:column0\",\"cf1:column1\"]", column)); + } + } + + // 检查多版本固定列读取时,不能配置 columnFamily + List columnFamilies = originalConfig.getList(Key.COLUMN_FAMILY, String.class); + if (columnFamilies != null) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "您配置的是 multiVersionFixedColumn 模式读取 hbase 中的数据,所以不能配置 columnFamily"); + } + + break; + } + case MultiVersionDynamicColumn: { + // multiVersionDynamicColumn 模式需要配置 maxVersion 和 columnFamily,并且 columnFamily 格式为 List 风格 + checkMaxVersion(originalConfig, mode); + + checkTetradType(originalConfig, mode); + + List columnFamilies = originalConfig.getList(Key.COLUMN_FAMILY, String.class); + if (columnFamilies == null || columnFamilies.isEmpty()) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, "您配置的是 multiVersionDynamicColumn 模式读取 hbase 中的数据,所以必须配置 columnFamily,其形式为:columnFamily:[\"cf0\",\"cf1\"]"); + } + + // 检查多版本动态列读取时,不能配置 column + List columns = originalConfig.getList(Key.COLUMN, String.class); + if (columns != null) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "您配置的是 multiVersionDynamicColumn 模式读取 hbase 中的数据,所以不能配置 column"); + } + + break; + } + default: + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 不支持此类模式:" + modeType); + } + + return mode; + } + + // 检查 maxVersion 是否存在,并且值是否合法 + private static void checkMaxVersion(Configuration configuration, String mode) { + Integer maxVersion = configuration.getInt(Key.MAX_VERSION); + Validate.notNull(maxVersion, String.format("您配置的是 %s 模式读取 hbase 中的数据,所以必须配置:maxVersion", mode)); + + boolean isMaxVersionValid = maxVersion == -1 || maxVersion > 1; + Validate.isTrue(isMaxVersionValid, String.format("您配置的是 %s 模式读取 hbase 中的数据,但是配置的 maxVersion 值错误. maxVersion规定:-1为读取全部版本,不能配置为0或者1(因为0或者1,我们认为用户是想用 normal 模式读取数据,而非 %s 模式读取,二者差别大),大于1则表示读取最新的对应个数的版本", mode, mode)); + } + + public static org.apache.hadoop.conf.Configuration getHbaseConf(String hbaseConf) { + if (StringUtils.isBlank(hbaseConf)) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, "读 Hbase 时需要配置 hbaseConfig,其内容为 Hbase 连接信息,请联系 Hbase PE 获取该信息."); + } + org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration(); + + try { + Map map = JSON.parseObject(hbaseConf, + new TypeReference>() { + }); + + // / 用户配置的 key-value 对 来表示 hbaseConf + Validate.isTrue(map != null, "hbaseConfig 不能为空 Map 结构!"); + for (Map.Entry entry : map.entrySet()) { + conf.set(entry.getKey(), entry.getValue()); + } + return conf; + } catch (Exception e) { + // 用户配置的 hbase 配置文件路径 + LOG.warn("尝试把您配置的 hbaseConfig: {} \n 当成 json 解析时遇到错误:", e); + LOG.warn("现在尝试把您配置的 hbaseConfig: {} \n 当成文件路径进行解析.", hbaseConf); + conf.addResource(new Path(hbaseConf)); + + LOG.warn("您配置的 hbaseConfig 是文件路径, 是不推荐的行为:因为当您的这个任务迁移到其他机器运行时,很可能出现该路径不存在的错误. 建议您把此项配置改成标准的 Hbase 连接信息,请联系 Hbase PE 获取该信息."); + return conf; + } + } + + private static void checkTetradType(Configuration configuration, String mode) { + List userConfiguredTetradTypes = configuration.getList(Key.TETRAD_TYPE, String.class); + if (userConfiguredTetradTypes == null || userConfiguredTetradTypes.isEmpty()) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, String.format("您配置的是 %s 模式读取 hbase 中的数据,但是缺失了 tetradType 配置项. tetradType规定:是长度为 4 的数组,用于指定四元组读取的类型,如:tetradType:[\"bytes\",\"string\",\"long\",\"bytes\"]", mode)); + } + + if (userConfiguredTetradTypes.size() != TETRAD_TYPE_COUNT) { + throw DataXException.asDataXException(HbaseReaderErrorCode.REQUIRED_VALUE, String.format("您配置的是 %s 模式读取 hbase 中的数据,但是 tetradType 配置项元素个数错误. tetradType规定:是长度为 4 的数组,用于指定四元组读取的类型,如:tetradType:[\"bytes\",\"string\",\"long\",\"bytes\"]", mode)); + } + + + String rowkeyType = userConfiguredTetradTypes.get(0); + String columnNameType = userConfiguredTetradTypes.get(1); + String timestampType = userConfiguredTetradTypes.get(2); + String valueType = userConfiguredTetradTypes.get(3); + + ColumnType.getByTypeName(rowkeyType); + ColumnType.getByTypeName(columnNameType); + + if (!"long".equalsIgnoreCase(timestampType)) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, String.format("您配置的是 %s 模式读取 hbase 中的数据,但是 tetradType 配置项元素类型错误. tetradType规定:第三项描述 timestamp 类型只能为 long,而您配置的值是:[%s]", mode, timestampType)); + } + + if ("date".equalsIgnoreCase(rowkeyType) || "date".equalsIgnoreCase(columnNameType) + || "date".equalsIgnoreCase(valueType)) { + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, String.format("您配置的是 %s 模式读取 hbase 中的数据,但是 tetradType 配置项元素类型错误. tetradType规定:不支持 date 类型", mode)); + } + + ColumnType.getByTypeName(valueType); + } + + public static byte[] convertUserStartRowkey(Configuration configuration) { + String startRowkey = configuration.getString(Key.START_ROWKEY); + if (StringUtils.isBlank(startRowkey)) { + return HConstants.EMPTY_BYTE_ARRAY; + } else { + boolean isBinaryRowkey = configuration.getBool(Key.IS_BINARY_ROWKEY); + return HbaseUtil.stringToBytes(startRowkey, isBinaryRowkey); + } + } + + public static byte[] convertUserEndRowkey(Configuration configuration) { + String endRowkey = configuration.getString(Key.END_ROWKEY); + if (StringUtils.isBlank(endRowkey)) { + return HConstants.EMPTY_BYTE_ARRAY; + } else { + boolean isBinaryRowkey = configuration.getBool(Key.IS_BINARY_ROWKEY); + return HbaseUtil.stringToBytes(endRowkey, isBinaryRowkey); + } + } + + /** + * 注意:convertUserStartRowkey 和 convertInnerStartRowkey,前者会受到 isBinaryRowkey 的影响,只用于第一次对用户配置的 String 类型的 rowkey 转为二进制时使用。而后者约定:切分时得到的二进制的 rowkey 回填到配置中时采用 + */ + public static byte[] convertInnerStartRowkey(Configuration configuration) { + String startRowkey = configuration.getString(Key.START_ROWKEY); + if (StringUtils.isBlank(startRowkey)) { + return HConstants.EMPTY_BYTE_ARRAY; + } + + return Bytes.toBytesBinary(startRowkey); + } + + public static byte[] convertInnerEndRowkey(Configuration configuration) { + String endRowkey = configuration.getString(Key.END_ROWKEY); + if (StringUtils.isBlank(endRowkey)) { + return HConstants.EMPTY_BYTE_ARRAY; + } + + return Bytes.toBytesBinary(endRowkey); + } + + /** + * 每次都获取一个新的HTable 注意:HTable 本身是线程不安全的 + */ + public static HTable initHtable(com.alibaba.datax.common.util.Configuration configuration) { + String hbaseConnConf = configuration.getString(Key.HBASE_CONFIG); + String tableName = configuration.getString(Key.TABLE); + HBaseAdmin admin = null; + try { + org.apache.hadoop.conf.Configuration conf = HbaseUtil.getHbaseConf(hbaseConnConf); + conf.set("hbase.meta.scanner.caching", META_SCANNER_CACHING); + + HTable htable = HTableManager.createHTable(conf, tableName); + admin = HTableManager.createHBaseAdmin(conf); + check(admin, htable); + + return htable; + } catch (Exception e) { + throw DataXException.asDataXException(HbaseReaderErrorCode.INIT_TABLE_ERROR, e); + } finally { + if (admin != null) { + try { + admin.close(); + } catch (IOException e) { + // ignore it + } + } + } + } + + + private static void check(HBaseAdmin admin, HTable htable) throws DataXException, IOException { + if (!admin.isMasterRunning()) { + throw new IllegalStateException("HBase master 没有运行, 请检查您的配置 或者 联系 Hbase 管理员."); + } + if (!admin.tableExists(htable.getTableName())) { + throw new IllegalStateException("HBase源头表" + Bytes.toString(htable.getTableName()) + + "不存在, 请检查您的配置 或者 联系 Hbase 管理员."); + } + if (!admin.isTableAvailable(htable.getTableName()) || !admin.isTableEnabled(htable.getTableName())) { + throw new IllegalStateException("HBase源头表" + Bytes.toString(htable.getTableName()) + + " 不可用, 请检查您的配置 或者 联系 Hbase 管理员."); + } + } + + private static byte[] stringToBytes(String rowkey, boolean isBinaryRowkey) { + if (isBinaryRowkey) { + return Bytes.toBytesBinary(rowkey); + } else { + return Bytes.toBytes(rowkey); + } + } + + public static boolean isRowkeyColumn(String columnName) { + return Constant.ROWKEY_FLAG.equalsIgnoreCase(columnName); + } + + /** + * 用于解析 Normal 模式下的列配置 + */ + public static List parseColumnOfNormalMode(List column) { + List hbaseColumnCells = new ArrayList(); + + HbaseColumnCell oneColumnCell; + + for (Map aColumn : column) { + ColumnType type = ColumnType.getByTypeName(aColumn.get("type")); + String columnName = aColumn.get("name"); + String columnValue = aColumn.get("value"); + String dateformat = aColumn.get("format"); + + if (type == ColumnType.DATE) { + Validate.notNull(dateformat, "Hbasereader 在 normal 方式读取时,其列配置中,如果类型为时间,则必须指定时间格式. 形如:yyyy-MM-dd HH:mm:ss,特别注意不能随意小写时间格式,那样可能导致时间转换错误!"); + + Validate.isTrue(StringUtils.isNotBlank(columnName) || StringUtils.isNotBlank(columnValue), "Hbasereader 在 normal 方式读取时则要么是 type + name + format 的组合,要么是type + value + format 的组合. 而您的配置非这两种组合,请检查并修改."); + + oneColumnCell = new HbaseColumnCell + .Builder(type) + .columnName(columnName) + .columnValue(columnValue) + .dateformat(dateformat) + .build(); + } else { + Validate.isTrue(dateformat == null, "Hbasereader 在 normal 方式读取时, 其列配置中,如果类型不为时间,则不需要指定时间格式."); + + Validate.isTrue(StringUtils.isNotBlank(columnName) || StringUtils.isNotBlank(columnValue), "Hbasereader 在 normal 方式读取时,其列配置中,如果类型不是时间,则要么是 type + name 的组合,要么是type + value 的组合. 而您的配置非这两种组合,请检查并修改."); + + oneColumnCell = new HbaseColumnCell + .Builder(type) + .columnName(columnName) + .columnValue(columnValue) + .build(); + } + + hbaseColumnCells.add(oneColumnCell); + } + + return hbaseColumnCells; + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionDynamicColumnTask.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionDynamicColumnTask.java new file mode 100644 index 000000000..070924d55 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionDynamicColumnTask.java @@ -0,0 +1,27 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; + +import java.util.List; + +public class MultiVersionDynamicColumnTask extends MultiVersionTask { + private List columnFamilies = null; + + public MultiVersionDynamicColumnTask(Configuration configuration){ + super(configuration); + + this.columnFamilies = configuration.getList(Key.COLUMN_FAMILY, String.class); + } + + @Override + public void initScan(Scan scan) { + for (String columnFamily : columnFamilies) { + scan.addFamily(Bytes.toBytes(columnFamily.trim())); + } + + super.setMaxVersions(scan); + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionFixedColumnTask.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionFixedColumnTask.java new file mode 100644 index 000000000..5826e3acd --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionFixedColumnTask.java @@ -0,0 +1,27 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; + +import java.util.List; + +public class MultiVersionFixedColumnTask extends MultiVersionTask { + private List column = null; + + public MultiVersionFixedColumnTask(Configuration configuration) { + super(configuration); + + this.column = configuration.getList(Key.COLUMN, String.class); + } + + @Override + public void initScan(Scan scan) { + for (String aColumn : this.column) { + String[] cfAndQualifier = aColumn.split(":"); + scan.addColumn(Bytes.toBytes(cfAndQualifier[0].trim()), Bytes.toBytes(cfAndQualifier[1].trim())); + } + super.setMaxVersions(scan); + } +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionTask.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionTask.java new file mode 100755 index 000000000..4ff1c7d8f --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/MultiVersionTask.java @@ -0,0 +1,141 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.ColumnType; +import com.alibaba.datax.plugin.reader.hbasereader.HbaseReaderErrorCode; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +public abstract class MultiVersionTask extends HbaseAbstractTask { + private static byte[] COLON_BYTE; + + private int maxVersion; + private List kvList = new ArrayList(); + private int currentReadPosition = 0; + + // 四元组的类型 + private ColumnType rowkeyReadoutType = null; + private ColumnType columnReadoutType = null; + private ColumnType timestampReadoutType = null; + private ColumnType valueReadoutType = null; + + public MultiVersionTask(Configuration configuration) { + super(configuration); + + this.maxVersion = configuration.getInt(Key.MAX_VERSION); + List userConfiguredTetradTypes = configuration.getList(Key.TETRAD_TYPE, String.class); + + this.rowkeyReadoutType = ColumnType.getByTypeName(userConfiguredTetradTypes.get(0)); + this.columnReadoutType = ColumnType.getByTypeName(userConfiguredTetradTypes.get(1)); + this.timestampReadoutType = ColumnType.getByTypeName(userConfiguredTetradTypes.get(2)); + this.valueReadoutType = ColumnType.getByTypeName(userConfiguredTetradTypes.get(3)); + + try { + MultiVersionTask.COLON_BYTE = ":".getBytes("utf8"); + } catch (UnsupportedEncodingException e) { + throw DataXException.asDataXException(HbaseReaderErrorCode.PREPAR_READ_ERROR, "系统内部获取 列族与列名冒号分隔符的二进制时失败.", e); + } + } + + private void convertKVToLine(KeyValue keyValue, Record record) throws Exception { + byte[] rawRowkey = keyValue.getRow(); + + long timestamp = keyValue.getTimestamp(); + + byte[] cfAndQualifierName = Bytes.add(keyValue.getFamily(), MultiVersionTask.COLON_BYTE, keyValue.getQualifier()); + + record.addColumn(convertBytesToAssignType(this.rowkeyReadoutType, rawRowkey)); + + record.addColumn(convertBytesToAssignType(this.columnReadoutType, cfAndQualifierName)); + + // 直接忽略了用户配置的 timestamp 的类型 + record.addColumn(new LongColumn(timestamp)); + + record.addColumn(convertBytesToAssignType(this.valueReadoutType, keyValue.getValue())); + } + + private Column convertBytesToAssignType(ColumnType columnType, byte[] byteArray) throws UnsupportedEncodingException { + Column column; + switch (columnType) { + case BOOLEAN: + column = new BoolColumn(byteArray == null ? null : Bytes.toBoolean(byteArray)); + break; + case SHORT: + column = new LongColumn(byteArray == null ? null : String.valueOf(Bytes.toShort(byteArray))); + break; + case INT: + column = new LongColumn(byteArray == null ? null : Bytes.toInt(byteArray)); + break; + case LONG: + column = new LongColumn(byteArray == null ? null : Bytes.toLong(byteArray)); + break; + case BYTES: + column = new BytesColumn(byteArray); + break; + case FLOAT: + column = new DoubleColumn(byteArray == null ? null : Bytes.toFloat(byteArray)); + break; + case DOUBLE: + column = new DoubleColumn(byteArray == null ? null : Bytes.toDouble(byteArray)); + break; + case STRING: + column = new StringColumn(byteArray == null ? null : new String(byteArray, super.encoding)); + break; + case BINARY_STRING: + column = new StringColumn(byteArray == null ? null : Bytes.toStringBinary(byteArray)); + break; + + default: + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 不支持您配置的列类型:" + columnType); + } + + return column; + } + + @Override + public boolean fetchLine(Record record) throws Exception { + Result result; + if (this.kvList.size() == this.currentReadPosition) { + result = super.getNextHbaseRow(); + if (result == null) { + return false; + } + + this.kvList = result.list(); + if (this.kvList == null) { + return false; + } + + this.currentReadPosition = 0; + } + + try { + KeyValue keyValue = this.kvList.get(this.currentReadPosition); + convertKVToLine(keyValue, record); + } catch (Exception e) { + throw e; + } finally { + this.currentReadPosition++; + } + + return true; + } + + public void setMaxVersions(Scan scan) { + if (this.maxVersion == -1 || this.maxVersion == Integer.MAX_VALUE) { + scan.setMaxVersions(); + } else { + scan.setMaxVersions(this.maxVersion); + } + } + +} diff --git a/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/NormalTask.java b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/NormalTask.java new file mode 100755 index 000000000..d46218cc4 --- /dev/null +++ b/hbasereader/src/main/java/com/alibaba/datax/plugin/reader/hbasereader/util/NormalTask.java @@ -0,0 +1,160 @@ +package com.alibaba.datax.plugin.reader.hbasereader.util; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.hbasereader.ColumnType; +import com.alibaba.datax.plugin.reader.hbasereader.HbaseColumnCell; +import com.alibaba.datax.plugin.reader.hbasereader.HbaseReaderErrorCode; +import com.alibaba.datax.plugin.reader.hbasereader.Key; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; + +import java.util.List; +import java.util.Map; + +public class NormalTask extends HbaseAbstractTask { + private List column; + private List hbaseColumnCells; + + public NormalTask(Configuration configuration) { + super(configuration); + + this.column = configuration.getList(Key.COLUMN, Map.class); + this.hbaseColumnCells = HbaseUtil.parseColumnOfNormalMode(this.column); + } + + @Override + public boolean fetchLine(Record record) throws Exception { + Result result = super.getNextHbaseRow(); + + if (null == result) { + return false; + } + super.lastResult = result; + + try { + byte[] hbaseColumnValue; + String columnName; + ColumnType columnType; + + byte[] cf; + byte[] qualifier; + + for (HbaseColumnCell cell : this.hbaseColumnCells) { + columnType = cell.getColumnType(); + if (cell.isConstant()) { + // 对常量字段的处理 + fillRecordWithConstantValue(record, cell); + } else { + // 根据列名称获取值 + columnName = cell.getColumnName(); + + if (HbaseUtil.isRowkeyColumn(columnName)) { + hbaseColumnValue = result.getRow(); + } else { + cf = cell.getCf(); + qualifier = cell.getQualifier(); + hbaseColumnValue = result.getValue(cf, qualifier); + } + + doFillRecord(hbaseColumnValue, columnType, super.encoding, cell.getDateformat(), record); + } + } + } catch (Exception e) { + // 注意,这里catch的异常,期望是byte数组转换失败的情况。而实际上,string的byte数组,转成整数类型是不容易报错的。但是转成double类型容易报错。 + + record.setColumn(0, new StringColumn(Bytes.toStringBinary(result.getRow()))); + + throw e; + } + + return true; + } + + @Override + public void initScan(Scan scan) { + boolean isConstant; + boolean isRowkeyColumn; + for (HbaseColumnCell cell : this.hbaseColumnCells) { + isConstant = cell.isConstant(); + isRowkeyColumn = HbaseUtil.isRowkeyColumn(cell.getColumnName()); + + if (!isConstant && !isRowkeyColumn) { + this.scan.addColumn(cell.getCf(), cell.getQualifier()); + } + } + } + + + protected void doFillRecord(byte[] byteArray, ColumnType columnType, String encoding, String dateformat, Record record) throws Exception { + switch (columnType) { + case BOOLEAN: + record.addColumn(new BoolColumn(byteArray == null ? null : Bytes.toBoolean(byteArray))); + break; + case SHORT: + record.addColumn(new LongColumn(byteArray == null ? null : String.valueOf(Bytes.toShort(byteArray)))); + break; + case INT: + record.addColumn(new LongColumn(byteArray == null ? null : Bytes.toInt(byteArray))); + break; + case LONG: + record.addColumn(new LongColumn(byteArray == null ? null : Bytes.toLong(byteArray))); + break; + case BYTES: + record.addColumn(new BytesColumn(byteArray == null ? null : byteArray)); + break; + case FLOAT: + record.addColumn(new DoubleColumn(byteArray == null ? null : Bytes.toFloat(byteArray))); + break; + case DOUBLE: + record.addColumn(new DoubleColumn(byteArray == null ? null : Bytes.toDouble(byteArray))); + break; + case STRING: + record.addColumn(new StringColumn(byteArray == null ? null : new String(byteArray, encoding))); + break; + case BINARY_STRING: + record.addColumn(new StringColumn(byteArray == null ? null : Bytes.toStringBinary(byteArray))); + break; + case DATE: + String dateValue = Bytes.toStringBinary(byteArray); + record.addColumn(byteArray == null ? null : new DateColumn(DateUtils.parseDate(dateValue, new String[]{dateformat}))); + break; + default: + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 不支持您配置的列类型:" + columnType); + } + } + + // 注意:常量列,不支持 binaryString 类型 + private void fillRecordWithConstantValue(Record record, HbaseColumnCell cell) throws Exception { + String constantValue = cell.getColumnValue(); + ColumnType columnType = cell.getColumnType(); + switch (columnType) { + case BOOLEAN: + record.addColumn(new BoolColumn(constantValue)); + break; + case SHORT: + case INT: + case LONG: + record.addColumn(new LongColumn(constantValue)); + break; + case BYTES: + record.addColumn(new BytesColumn(constantValue.getBytes("utf-8"))); + break; + case FLOAT: + case DOUBLE: + record.addColumn(new DoubleColumn(constantValue)); + break; + case STRING: + record.addColumn(new StringColumn(constantValue)); + break; + case DATE: + record.addColumn(new DateColumn(DateUtils.parseDate(constantValue, new String[]{cell.getDateformat()}))); + break; + default: + throw DataXException.asDataXException(HbaseReaderErrorCode.ILLEGAL_VALUE, "Hbasereader 常量列不支持您配置的列类型:" + columnType); + } + } +} diff --git a/hbasereader/src/main/resources/plugin.json b/hbasereader/src/main/resources/plugin.json new file mode 100755 index 000000000..20a101a0a --- /dev/null +++ b/hbasereader/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "hbasereader", + "class": "com.alibaba.datax.plugin.reader.hbasereader.HbaseReader", + "description": "useScene: prod. mechanism: Scan to read data.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/hbasereader/src/main/resources/plugin_job_template.json b/hbasereader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..1a67cbd0d --- /dev/null +++ b/hbasereader/src/main/resources/plugin_job_template.json @@ -0,0 +1,15 @@ +{ + "name": "hbasereader", + "parameter": { + "hbaseConfig": "", + "table": "", + "encoding": "", + "mode": "", + "column": [], + "range": { + "startRowkey": "", + "endRowkey": "" + }, + "isBinaryRowkey": true + } +} \ No newline at end of file diff --git a/hdfsreader/doc/hdfsreader.md b/hdfsreader/doc/hdfsreader.md new file mode 100644 index 000000000..4bcc366b2 --- /dev/null +++ b/hdfsreader/doc/hdfsreader.md @@ -0,0 +1,257 @@ +# DataX HdfsReader 插件文档 + + +------------ + +## 1 快速介绍 + +HdfsReader提供了读取分布式文件系统数据存储的能力。在底层实现上,HdfsReader获取分布式文件系统上文件的数据,并转换为DataX传输协议传递给Writer。 + +**目前HdfsReader仅支持textfile和orcfile两种格式的文件,且文件内容存放的必须是一张逻辑意义上的二维表。** + +**HdfsReader需要Jdk1.7及以上版本的支持。** + + +## 2 功能与限制 + +HdfsReader实现了从Hadoop分布式文件系统Hdfs中读取文件数据并转为DataX协议的功能。textfile是Hive建表时默认使用的存储格式,数据不做压缩,本质上textfile就是以文本的形式将数据存放在hdfs中,对于DataX而言,HdfsReader实现上类比TxtFileReader,有诸多相似之处。orcfile,它的全名是Optimized Row Columnar file,是对RCFile做了优化。据官方文档介绍,这种文件格式可以提供一种高效的方法来存储Hive数据。HdfsReader利用Hive提供的OrcSerde类,读取解析orcfile文件的数据。目前HdfsReader支持的功能如下: + +1. 支持textfile和orcfile两种格式的文件,且要求文件内容存放的是一张逻辑意义上的二维表。 + +2. 支持多种类型数据读取(使用String表示),支持列裁剪,支持列常量 + +3. 支持递归读取、支持正则表达式("*"和"?")。 + +4. 支持orcfile数据压缩,目前支持SNAPPY,ZLIB两种压缩方式。 + +5. 多个File可以支持并发读取。 + +我们暂时不能做到: + +1. 单个File支持多线程并发读取,这里涉及到单个File内部切分算法。二期考虑支持。 + + + +## 3 功能说明 + + +### 3.1 配置样例 + +```json +{ + "job": { + "setting": { + "speed": { + "channel": 3 + } + }, + "content": [ + { + "reader": { + "name": "hdfsreader", + "parameter": { + "path": "/user/hive/warehouse/mytable01/*", + "defaultFS": "hdfs://10.101.169.107:9000", + "column": [ + { + "index": 0, + "type": "long" + }, + { + "index": 1, + "type": "boolean" + }, + { + "type": "string", + "value": "hello" + }, + { + "index": 2, + "type": "double" + } + ], + "fileType": "orc", + "encoding": "UTF-8", + "fieldDelimiter": "," + } + + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": true + } + } + } + ] + } +} +``` + +### 3.2 参数说明(各个配置项值前后不允许有空格) + +* **path** + + * 描述:要读取的文件路径,如果要读取多个文件,可以使用正则表达式"*",注意这里可以支持填写多个路径。。
+ + 当指定单个Hdfs文件,HdfsReader暂时只能使用单线程进行数据抽取。二期考虑在非压缩文件情况下针对单个File可以进行多线程并发读取。 + + 当指定多个Hdfs文件,HdfsReader支持使用多线程进行数据抽取。线程并发数通过通道数指定。 + + 当指定通配符,HdfsReader尝试遍历出多个文件信息。例如: 指定/*代表读取/目录下所有的文件,指定/bazhen/\*代表读取bazhen目录下游所有的文件。HdfsReader目前只支持"*"和"?"作为文件通配符。 + + **特别需要注意的是,DataX会将一个作业下同步的所有的文件视作同一张数据表。用户必须自己保证所有的File能够适配同一套schema信息。并且提供给DataX权限可读。** + + + * 必选:是
+ + * 默认值:无
+ +* **defaultFS** + + * 描述:Hadoop hdfs文件系统namenode节点地址。
+ + + **特别需要注意的是,目前HdfsReader不支持Kerberos等认证,所以用户需要保证DATAX有权限访问该节点** + + + * 必选:是
+ + * 默认值:无
+ +* **fileType** + + * 描述:文件的类型,目前只支持用户配置为"text"或"orc"。
+ + text表示textfile文件格式 + + orc表示orcfile文件格式 + + **特别需要注意的是,HdfsReader能够自动识别文件是orcfile、textfile或者还是其它类型的文件,但该项是必填项,HdfsReader则会只读取用户配置的类型的文件,忽略路径下其他格式的文件** + + **另外需要注意的是,由于textfile和orcfile是两种完全不同的文件格式,所以HdfsReader对这两种文件的解析方式也存在差异,这种差异导致hive支持的复杂复合类型(比如map,array,struct,union)在转换为DataX支持的String类型时,转换的结果格式略有差异,比如以map类型为例:** + + orcfile map类型经hdfsreader解析转换成datax支持的string类型后,结果为"{job=80, team=60, person=70}" + + textfile map类型经hdfsreader解析转换成datax支持的string类型后,结果为"job:80,team:60,person:70" + + 从上面的转换结果可以看出,数据本身没有变化,但是表示的格式略有差异,所以如果用户配置的文件路径中要同步的字段在Hive中是复合类型的话,建议配置统一的文件格式。 + + **如果需要统一复合类型解析出来的格式,我们建议用户在hive客户端将textfile格式的表导成orcfile格式的表** + + * 必选:是
+ + * 默认值:无
+ + +* **column** + + * 描述:读取字段列表,type指定源数据的类型,index指定当前列来自于文本第几列(以0开始),value指定当前类型为常量,不从源头文件读取数据,而是根据value值自动生成对应的列。
+ + 默认情况下,用户可以全部按照String类型读取数据,配置如下: + + ```json + "column": ["*"] + ``` + + 用户可以指定Column字段信息,配置如下: + + ```json +{ + "type": "long", + "index": 0 //从本地文件文本第一列获取int字段 +}, +{ + "type": "string", + "value": "alibaba" //HdfsReader内部生成alibaba的字符串字段作为当前字段 +} + ``` + + 对于用户指定Column信息,type必须填写,index/value必须选择其一。 + + * 必选:是
+ + * 默认值:全部按照string类型读取
+ +* **fieldDelimiter** + + * 描述:读取的字段分隔符
+ + **另外需要注意的是,HdfsReader在读取textfile数据时,需要指定字段分割符,如果不指定默认为',',HdfsReader在读取orcfile时,用户无需指定字段分割符** + + * 必选:否
+ + * 默认值:,
+ + +* **encoding** + + * 描述:读取文件的编码配置。
+ + * 必选:否
+ + * 默认值:utf-8
+ + +* **nullFormat** + + * 描述:文本文件中无法使用标准字符串定义null(空指针),DataX提供nullFormat定义哪些字符串可以表示为null。
+ + 例如如果用户配置: nullFormat:"\\N",那么如果源头数据是"\N",DataX视作null字段。 + + * 必选:否
+ + * 默认值:无
+ + +### 3.3 类型转换 + +由于textfile和orcfile文件表的元数据信息由Hive维护并存放在Hive自己维护的数据库(如mysql)中,目前HdfsReader不支持对Hive元数 + +据数据库进行访问查询,因此用户在进行类型转换的时候,必须指定数据类型,如果用户配置的column为"*",则所有column默认转换为 + +string类型。HdfsReader提供了类型转换的建议表如下: + +| DataX 内部类型| Hive表 数据类型 | +| -------- | ----- | +| Long |TINYINT,SMALLINT,INT,BIGINT| +| Double |FLOAT,DOUBLE| +| String |String,CHAR,VARCHAR,STRUCT,MAP,ARRAY,UNION,BINARY| +| Boolean |BOOLEAN| +| Date |Date,TIMESTAMP| + +其中: + +* Long是指Hdfs文件文本中使用整形的字符串表示形式,例如"123456789"。 +* Double是指Hdfs文件文本中使用Double的字符串表示形式,例如"3.1415"。 +* Boolean是指Hdfs文件文本中使用Boolean的字符串表示形式,例如"true"、"false"。不区分大小写。 +* Date是指Hdfs文件文本中使用Date的字符串表示形式,例如"2014-12-31"。 + +特别提醒: + +* Hive支持的数据类型TIMESTAMP可以精确到纳秒级别,所以textfile、orcfile中TIMESTAMP存放的数据类似于"2015-08-21 22:40:47.397898389",如果转换的类型配置为DataX的Date,转换之后会导致纳秒部分丢失,所以如果需要保留纳秒部分的数据,请配置转换类型为DataX的String类型。 + + +### 3.4 按分区读取 + +Hive在建表的时候,可以指定分区partition,例如创建分区partition(day="20150820",hour="09"),对应的hdfs文件系统中,相应的表的目录下则会多出/20150820和/09两个目录,且/20150820是/09的父目录。了解了分区都会列成相应的目录结构,在按照某个分区读取某个表所有数据时,则只需配置好json中path的值即可。 + +比如需要读取表名叫mytable01下分区day为20150820这一天的所有数据,则配置如下: + +```json +"path": "/user/hive/warehouse/mytable01/20150820/*" +``` + + +## 4 性能报告 + + + +## 5 约束限制 + +略 + +## 6 FAQ + +略 + diff --git a/hdfsreader/hdfsreader.iml b/hdfsreader/hdfsreader.iml new file mode 100644 index 000000000..8c7164a5b --- /dev/null +++ b/hdfsreader/hdfsreader.iml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hdfsreader/pom.xml b/hdfsreader/pom.xml new file mode 100644 index 000000000..59156d99e --- /dev/null +++ b/hdfsreader/pom.xml @@ -0,0 +1,123 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + + hdfsreader + com.alibaba.datax + 0.0.1-SNAPSHOT + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + org.apache.hadoop + hadoop-hdfs + 2.6.0 + + + org.apache.hadoop + hadoop-common + 2.6.0 + + + org.apache.hadoop + hadoop-yarn-common + 2.6.0 + + + org.apache.hadoop + hadoop-mapreduce-client-core + 2.6.0 + + + + org.apache.hive + hive-exec + 1.2.0 + + + org.apache.hive + hive-serde + 1.2.0 + + + org.apache.hive + hive-service + 1.2.0 + + + org.apache.hive + hive-common + 1.2.0 + + + org.apache.hive.hcatalog + hive-hcatalog-core + 1.2.0 + + + + com.alibaba.datax + plugin-unstructured-storage-util + ${datax-project-version} + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + diff --git a/hdfsreader/src/main/assembly/package.xml b/hdfsreader/src/main/assembly/package.xml new file mode 100644 index 000000000..3f1393b76 --- /dev/null +++ b/hdfsreader/src/main/assembly/package.xml @@ -0,0 +1,49 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/hdfsreader + + + target/ + + hdfsreader-0.0.1-SNAPSHOT.jar + + plugin/reader/hdfsreader + + + + + + + + + + + + + + + + + + + + false + plugin/reader/hdfsreader/libs + runtime + + + diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Constant.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Constant.java new file mode 100644 index 000000000..5d1887b6a --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Constant.java @@ -0,0 +1,10 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +/** + * Created by mingya.wmy on 2015/8/14. + */ +public class Constant { + public static final String SOURCE_FILES = "sourceFiles"; + public static final String TEXT = "TEXT"; + public static final String ORC = "ORC"; +} diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/DFSUtil.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/DFSUtil.java new file mode 100644 index 000000000..ee84dd8c4 --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/DFSUtil.java @@ -0,0 +1,523 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.text.SimpleDateFormat; +import java.util.*; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.unstructuredstorage.reader.UnstructuredStorageReaderErrorCode; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.fs.*; +import org.apache.hadoop.hive.ql.io.orc.*; +import org.apache.hadoop.hive.serde2.objectinspector.StructField; +import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.compress.CompressionCodec; +import org.apache.hadoop.io.compress.CompressionCodecFactory; +import org.apache.hadoop.io.compress.CompressionInputStream; +import org.apache.hadoop.mapred.*; +import org.apache.hadoop.mapred.RecordReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by mingya.wmy on 2015/8/12. + */ +public class DFSUtil { + private static final Logger LOG = LoggerFactory.getLogger(HdfsReader.Job.class); + + private org.apache.hadoop.conf.Configuration hadoopConf = null; + + private static final int DIRECTORY_SIZE_GUESS = 16 * 1024; + + private String specifiedFileType = null; + + public DFSUtil(String defaultFS){ + hadoopConf = new org.apache.hadoop.conf.Configuration(); + hadoopConf.set("fs.defaultFS", defaultFS); + } + + + /** + * @Title: getAllFiles + * @Description: 获取指定路径列表下符合条件的所有文件的绝对路径 + * @param @param srcPaths 路径列表 + * @param @return + * @return HashSet + * @throws + */ + public HashSet getAllFiles(List srcPaths, String specifiedFileType){ + + this.specifiedFileType = specifiedFileType; + + if (!srcPaths.isEmpty()) { + for (String eachPath : srcPaths) { + getHDFSAllFiles(eachPath); + } + } + return sourceHDFSAllFilesList; + } + + private HashSet sourceHDFSAllFilesList = new HashSet(); + + public HashSet getHDFSAllFiles(String hdfsPath){ + + try { + FileSystem hdfs = FileSystem.get(hadoopConf); + //判断hdfsPath是否包含正则符号 + if(hdfsPath.contains("*") || hdfsPath.contains("?")){ + Path path = new Path(hdfsPath); + FileStatus stats[] = hdfs.globStatus(path); + for(FileStatus f : stats){ + if(f.isFile()){ + + addSourceFileByType(f.getPath().toString()); + } + else if(f.isDirectory()){ + getHDFSALLFiles_NO_Regex(f.getPath().toString(), hdfs); + } + } + } + else{ + getHDFSALLFiles_NO_Regex(hdfsPath, hdfs); + } + + return sourceHDFSAllFilesList; + + }catch (IOException e){ + String message = String.format("无法读取路径[%s]下的所有文件,请确认您的配置项path是否正确," + + "是否有读写权限,网络是否已断开!", hdfsPath); + LOG.error(message); + throw DataXException.asDataXException(HdfsReaderErrorCode.PATH_CONFIG_ERROR, message); + } + } + + private HashSet getHDFSALLFiles_NO_Regex(String path,FileSystem hdfs) throws IOException{ + + // 获取要读取的文件的根目录 + Path listFiles = new Path(path); + + // If the network disconnected, this method will retry 45 times + // each time the retry interval for 20 seconds + // 获取要读取的文件的根目录的所有二级子文件目录 + FileStatus stats[] = hdfs.listStatus(listFiles); + + for (FileStatus f : stats) { + // 判断是不是目录,如果是目录,递归调用 + if (f.isDirectory()) { + getHDFSALLFiles_NO_Regex(f.getPath().toString(),hdfs); + } + else if(f.isFile()){ + + addSourceFileByType(f.getPath().toString()); + } + else{ + String message = String.format("该路径[%s]文件类型既不是目录也不是文件,插件自动忽略。" + , f.getPath().toString()); + LOG.info(message); + } + } + return sourceHDFSAllFilesList; + } + + // 根据用户指定的文件类型,将指定的文件类型的路径加入sourceHDFSAllFilesList + private void addSourceFileByType(String filePath){ + HdfsFileType type = checkHdfsFileType(filePath); + + if(type.toString().contains(specifiedFileType.toUpperCase())){ + sourceHDFSAllFilesList.add(filePath); + } + else{ + String message = String.format("文件[%s]的类型与用户配置的fileType类型不一致," + + "请确认您配置的目录下面所有文件的类型均为[%s]" + , filePath, this.specifiedFileType); + LOG.error(message); + throw DataXException.asDataXException( + HdfsReaderErrorCode.FILE_TYPE_UNSUPPORT, message); + } + } + + + public InputStream getInputStream(String filepath){ + InputStream inputStream = null; + Path path = new Path(filepath); + try{ + FileSystem fs = FileSystem.get(hadoopConf); + inputStream = fs.open(path); + return inputStream; + }catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public BufferedReader getBufferedReader(String filepath, HdfsFileType fileType, String encoding){ + try { + FileSystem fs = FileSystem.get(hadoopConf); + Path path = new Path(filepath); + FSDataInputStream in = null; + + CompressionInputStream cin = null; + BufferedReader br = null; + + if (fileType.equals(HdfsFileType.COMPRESSED_TEXT)) { + CompressionCodecFactory factory = new CompressionCodecFactory(hadoopConf); + CompressionCodec codec = factory.getCodec(path); + if (codec == null) { + String message = String.format( + "Can't find any suitable CompressionCodec to this file:%value", + path.toString()); + throw DataXException.asDataXException(HdfsReaderErrorCode.CONFIG_INVALID_EXCEPTION, message); + } + //If the network disconnected, this method will retry 45 times + //each time the retry interval for 20 seconds + in = fs.open(path); + cin = codec.createInputStream(in); + br = new BufferedReader(new InputStreamReader(cin, encoding)); + } else { + //If the network disconnected, this method will retry 45 times + // each time the retry interval for 20 seconds + in = fs.open(path); + br = new BufferedReader(new InputStreamReader(in, encoding)); + } + return br; + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + public void orcFileStartRead(String sourceOrcFilePath, Configuration readerSliceConfig, + RecordSender recordSender, TaskPluginCollector taskPluginCollector){ + + List columnConfigs = readerSliceConfig.getListConfiguration(Key.COLUMN); + String nullFormat = readerSliceConfig.getString(Key.NULL_FORMAT); + String allColumns = ""; + String allColumnTypes = ""; + boolean isReadAllColumns = false; + int columnIndexMax = -1; + // 判断是否读取所有列 + if (null == columnConfigs || columnConfigs.size() == 0) { + int allColumnsCount = getAllColumnsCount(sourceOrcFilePath); + columnIndexMax = allColumnsCount-1; + isReadAllColumns = true; + } + else { + columnIndexMax = getMaxIndex(columnConfigs); + } + for(int i=0; i<=columnIndexMax; i++){ + allColumns += "col"; + allColumnTypes += "string"; + if(i!=columnIndexMax){ + allColumns += ","; + allColumnTypes += ":"; + } + } + if(columnIndexMax>=0) { + JobConf conf = new JobConf(hadoopConf); + Path orcFilePath = new Path(sourceOrcFilePath); + Properties p = new Properties(); + p.setProperty("columns", allColumns); + p.setProperty("columns.types", allColumnTypes); + try { + OrcSerde serde = new OrcSerde(); + serde.initialize(conf, p); + StructObjectInspector inspector = (StructObjectInspector) serde.getObjectInspector(); + InputFormat in = new OrcInputFormat(); + FileInputFormat.setInputPaths(conf, orcFilePath.toString()); + + //If the network disconnected, will retry 45 times, each time the retry interval for 20 seconds + //Each file as a split + InputSplit[] splits = in.getSplits(conf, 1); + + RecordReader reader = in.getRecordReader(splits[0], conf, Reporter.NULL); + Object key = reader.createKey(); + Object value = reader.createValue(); + // 获取列信息 + List fields = inspector.getAllStructFieldRefs(); + + List recordFields = null; + while (reader.next(key, value)) { + recordFields = new ArrayList(); + + for(int i=0; i<=columnIndexMax; i++){ + Object field = inspector.getStructFieldData(value, fields.get(i)); + recordFields.add(field); + } + transportOneRecord(columnConfigs, recordFields, recordSender, + taskPluginCollector, isReadAllColumns,nullFormat); + } + reader.close(); + }catch (Exception e){ + String message = String.format("从orcfile文件路径[%s]中读取数据发生异常,请联系系统管理员。" + , sourceOrcFilePath); + LOG.error(message); + throw DataXException.asDataXException(HdfsReaderErrorCode.READ_FILE_ERROR, message); + } + } else { + String message = String.format("请确认您所读取的列配置正确!"); + LOG.error(message); + throw DataXException.asDataXException(HdfsReaderErrorCode.BAD_CONFIG_VALUE, message); + } + } + + private Record transportOneRecord(List columnConfigs, List recordFields + , RecordSender recordSender, TaskPluginCollector taskPluginCollector, boolean isReadAllColumns, String nullFormat){ + Record record = recordSender.createRecord(); + Column columnGenerated = null; + try { + if(isReadAllColumns){ + // 读取所有列,创建都为String类型的column + for(Object recordField :recordFields){ + String columnValue = null; + if(recordField != null){ + columnValue = recordField.toString(); + } + columnGenerated = new StringColumn(columnValue); + record.addColumn(columnGenerated); + } + } + else { + for (Configuration columnConfig : columnConfigs) { + String columnType = columnConfig + .getNecessaryValue(Key.TYPE, HdfsReaderErrorCode.CONFIG_INVALID_EXCEPTION); + Integer columnIndex = columnConfig.getInt(Key.INDEX); + String columnConst = columnConfig.getString(Key.VALUE); + + String columnValue = null; + + if (null != columnIndex) { + if (null != recordFields.get(columnIndex)) + columnValue = recordFields.get(columnIndex).toString(); + } else { + columnValue = columnConst; + } + Type type = Type.valueOf(columnType.toUpperCase()); + // it's all ok if nullFormat is null + if (columnValue.equals(nullFormat)) { + columnValue = null; + } + switch (type) { + case STRING: + columnGenerated = new StringColumn(columnValue); + break; + case LONG: + try { + columnGenerated = new LongColumn(columnValue); + } catch (Exception e) { + throw new IllegalArgumentException(String.format( + "类型转换错误, 无法将[%s] 转换为[%s]", columnValue, + "LONG")); + } + break; + case DOUBLE: + try { + columnGenerated = new DoubleColumn(columnValue); + } catch (Exception e) { + throw new IllegalArgumentException(String.format( + "类型转换错误, 无法将[%s] 转换为[%s]", columnValue, + "DOUBLE")); + } + break; + case BOOLEAN: + try { + columnGenerated = new BoolColumn(columnValue); + } catch (Exception e) { + throw new IllegalArgumentException(String.format( + "类型转换错误, 无法将[%s] 转换为[%s]", columnValue, + "BOOLEAN")); + } + + break; + case DATE: + try { + if (columnValue == null) { + Date date = null; + columnGenerated = new DateColumn(date); + } else { + String formatString = columnConfig.getString(Key.FORMAT); + if (StringUtils.isNotBlank(formatString)) { + // 用户自己配置的格式转换 + SimpleDateFormat format = new SimpleDateFormat( + formatString); + columnGenerated = new DateColumn( + format.parse(columnValue)); + } else { + // 框架尝试转换 + columnGenerated = new DateColumn( + new StringColumn(columnValue) + .asDate()); + } + } + } catch (Exception e) { + throw new IllegalArgumentException(String.format( + "类型转换错误, 无法将[%s] 转换为[%s]", columnValue, + "DATE")); + } + break; + default: + String errorMessage = String.format( + "您配置的列类型暂不支持 : [%s]", columnType); + LOG.error(errorMessage); + throw DataXException + .asDataXException( + UnstructuredStorageReaderErrorCode.NOT_SUPPORT_TYPE, + errorMessage); + } + + record.addColumn(columnGenerated); + } + } + recordSender.sendToWriter(record); + } catch (IllegalArgumentException iae) { + taskPluginCollector + .collectDirtyRecord(record, iae.getMessage()); + } catch (IndexOutOfBoundsException ioe) { + taskPluginCollector + .collectDirtyRecord(record, ioe.getMessage()); + } catch (Exception e) { + if (e instanceof DataXException) { + throw (DataXException) e; + } + // 每一种转换失败都是脏数据处理,包括数字格式 & 日期格式 + taskPluginCollector.collectDirtyRecord(record, e.getMessage()); + } + + return record; + } + + private int getAllColumnsCount(String filePath){ + int columnsCount = 0; + final String colFinal = "_col"; + Path path = new Path(filePath); + try { + Reader reader = OrcFile.createReader(path, OrcFile.readerOptions(hadoopConf)); + String type_struct = reader.getObjectInspector().getTypeName(); + columnsCount = (type_struct.length() - type_struct.replace(colFinal, "").length()) + / colFinal.length(); + return columnsCount; + }catch (IOException e){ + String message = "读取orcfile column列数失败,请联系系统管理员"; + throw DataXException.asDataXException(HdfsReaderErrorCode.READ_FILE_ERROR, message); + } + } + + private int getMaxIndex(List columnConfigs){ + int maxIndex = -1; + for (Configuration columnConfig : columnConfigs) { + Integer columnIndex = columnConfig.getInt(Key.INDEX); + if (columnIndex != null && columnIndex < 0) { + String message = String.format("您column中配置的index不能小于0,请修改为正确的index"); + LOG.error(message); + throw DataXException.asDataXException(HdfsReaderErrorCode.CONFIG_INVALID_EXCEPTION, message); + } else if (columnIndex != null && columnIndex > maxIndex) { + maxIndex = columnIndex; + } + } + return maxIndex; + } + + private static enum Type { + STRING, LONG, BOOLEAN, DOUBLE, DATE, + } + + public HdfsFileType checkHdfsFileType(String filepath){ + + Path path = new Path(filepath); + + try { + FileSystem fs = FileSystem.get(hadoopConf); + + // figure out the size of the file using the option or filesystem + long size = fs.getFileStatus(path).getLen(); + + //read last bytes into buffer to get PostScript + int readSize = (int) Math.min(size, DIRECTORY_SIZE_GUESS); + FSDataInputStream file = fs.open(path); + file.seek(size - readSize); + ByteBuffer buffer = ByteBuffer.allocate(readSize); + file.readFully(buffer.array(), buffer.arrayOffset() + buffer.position(), + buffer.remaining()); + + //read the PostScript + //get length of PostScript + int psLen = buffer.get(readSize - 1) & 0xff; + HdfsFileType type = checkType(file, path, psLen, buffer, hadoopConf); + + return type; + }catch (Exception e){ + String message = String.format("检查文件[%s]类型失败,请检查您的文件是否合法。" + , filepath); + throw DataXException.asDataXException(HdfsReaderErrorCode.READ_FILE_ERROR, message); + } + } + + /** + * Check the file type + * @param in the file being read + * @param path the filename for error messages + * @param psLen the postscript length + * @param buffer the tail of the file + * @throws IOException + */ + private HdfsFileType checkType(FSDataInputStream in, + Path path, + int psLen, + ByteBuffer buffer, + org.apache.hadoop.conf.Configuration hadoopConf) throws IOException { + int len = OrcFile.MAGIC.length(); + if (psLen < len + 1) { + String message = String.format("Malformed ORC file [%s]. Invalid postscript length [%s]" + , path, psLen); + LOG.error(message); + throw DataXException.asDataXException( + HdfsReaderErrorCode.MALFORMED_ORC_ERROR, message); + } + int offset = buffer.arrayOffset() + buffer.position() + buffer.limit() - 1 + - len; + byte[] array = buffer.array(); + // now look for the magic string at the end of the postscript. + if (Text.decode(array, offset, len).equals(OrcFile.MAGIC)) { + return HdfsFileType.ORC; + } + else{ + // If it isn't there, this may be the 0.11.0 version of ORC. + // Read the first 3 bytes of the file to check for the header + in.seek(0); + byte[] header = new byte[len]; + in.readFully(header, 0, len); + // if it isn't there, this isn't an ORC file + if (Text.decode(header, 0 , len).equals(OrcFile.MAGIC)) { + return HdfsFileType.ORC; + } + else{ + in.seek(0); + switch (in.readShort()) { + case 0x5345: + if (in.readByte() == 'Q') { + return HdfsFileType.SEQ; + } + default: + in.seek(0); + CompressionCodecFactory compressionCodecFactory = new CompressionCodecFactory(hadoopConf); + CompressionCodec codec = compressionCodecFactory.getCodec(path); + if (null == codec) + return HdfsFileType.TEXT; + else { + return HdfsFileType.COMPRESSED_TEXT; + } + } + } + + } + } + +} \ No newline at end of file diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsFileType.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsFileType.java new file mode 100644 index 000000000..793489ae2 --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsFileType.java @@ -0,0 +1,8 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +/** + * Created by mingya.wmy on 2015/8/22. + */ +public enum HdfsFileType { + TEXT, COMPRESSED_TEXT, ORC, SEQ, +} diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReader.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReader.java new file mode 100644 index 000000000..677c0f3fa --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReader.java @@ -0,0 +1,298 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.unstructuredstorage.reader.UnstructuredStorageReaderUtil; +import org.apache.commons.io.Charsets; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.nio.charset.UnsupportedCharsetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class HdfsReader extends Reader { + + /** + * Job 中的方法仅执行一次,Task 中方法会由框架启动多个 Task 线程并行执行。 + *

+ * 整个 Reader 执行流程是: + *

+     * Job类init-->prepare-->split
+     *
+     * Task类init-->prepare-->startRead-->post-->destroy
+     * Task类init-->prepare-->startRead-->post-->destroy
+     *
+     * Job类post-->destroy
+     * 
+ */ + public static class Job extends Reader.Job { + private static final Logger LOG = LoggerFactory + .getLogger(Job.class); + + private Configuration readerOriginConfig = null; + private String defaultFS = null; + private String encoding = null; + private HashSet sourceFiles; + private String specifiedFileType = null; + private DFSUtil dfsUtil = null; + private List path = null; + + @Override + public void init() { + + LOG.info("init() begin..."); + this.readerOriginConfig = super.getPluginJobConf(); + this.validate(); + dfsUtil = new DFSUtil(defaultFS); + LOG.info("init() ok and end..."); + + } + + private void validate(){ + defaultFS = this.readerOriginConfig.getNecessaryValue(Key.DEFAULT_FS, + HdfsReaderErrorCode.DEFAULT_FS_NOT_FIND_ERROR); + if (StringUtils.isBlank(defaultFS)) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.PATH_NOT_FIND_ERROR, "您需要指定 defaultFS"); + } + + // path check + String pathInString = this.readerOriginConfig.getNecessaryValue(Key.PATH, HdfsReaderErrorCode.REQUIRED_VALUE); + if (!pathInString.startsWith("[") && !pathInString.endsWith("]")) { + path = new ArrayList(); + path.add(pathInString); + } else { + path = this.readerOriginConfig.getList(Key.PATH, String.class); + if (null == path || path.size() == 0) { + throw DataXException.asDataXException(HdfsReaderErrorCode.REQUIRED_VALUE, "您需要指定待读取的源目录或文件"); + } + for (String eachPath : path) { + if(!eachPath.startsWith("/")){ + String message = String.format("请检查参数path:[%s],需要配置为绝对路径", eachPath); + LOG.error(message); + throw DataXException.asDataXException(HdfsReaderErrorCode.ILLEGAL_VALUE, message); + } + } + } + + specifiedFileType = this.readerOriginConfig.getNecessaryValue(Key.FILETYPE, HdfsReaderErrorCode.REQUIRED_VALUE); + if( !specifiedFileType.equalsIgnoreCase("ORC") && + !specifiedFileType.equalsIgnoreCase("TEXT")){ + String message = "HdfsReader插件目前只支持ORC和TEXT两种格式的文件," + + "如果您需要指定读取的文件类型,请将filetype选项的值配置为ORC或者TEXT"; + throw DataXException.asDataXException( + HdfsReaderErrorCode.FILE_TYPE_ERROR, message); + } + + encoding = this.readerOriginConfig.getString(Key.ENCODING, "UTF-8"); + + try { + Charsets.toCharset(encoding); + } catch (UnsupportedCharsetException uce) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.ILLEGAL_VALUE, + String.format("不支持的编码格式 : [%s]", encoding), uce); + } catch (Exception e) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.ILLEGAL_VALUE, + String.format("运行配置异常 : %s", e.getMessage()), e); + } + + // validate the Columns + validateColumns(); + + } + + private void validateColumns(){ + + // 检测是column 是否为 ["*"] 若是则填为空 + List column = this.readerOriginConfig + .getListConfiguration(Key.COLUMN); + if (null != column + && 1 == column.size() + && ("\"*\"".equals(column.get(0).toString()) || "'*'" + .equals(column.get(0).toString()))) { + readerOriginConfig + .set(Key.COLUMN, new ArrayList()); + } else { + // column: 1. index type 2.value type 3.when type is Data, may have format + List columns = this.readerOriginConfig + .getListConfiguration(Key.COLUMN); + + if (null == columns || columns.size() == 0) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.CONFIG_INVALID_EXCEPTION, + "您需要指定 columns"); + } + + if (null != columns && columns.size() != 0) { + for (Configuration eachColumnConf : columns) { + eachColumnConf.getNecessaryValue(Key.TYPE, HdfsReaderErrorCode.REQUIRED_VALUE); + Integer columnIndex = eachColumnConf.getInt(Key.INDEX); + String columnValue = eachColumnConf.getString(Key.VALUE); + + if (null == columnIndex && null == columnValue) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.NO_INDEX_VALUE, + "由于您配置了type, 则至少需要配置 index 或 value"); + } + + if (null != columnIndex && null != columnValue) { + throw DataXException.asDataXException( + HdfsReaderErrorCode.MIXED_INDEX_VALUE, + "您混合配置了index, value, 每一列同时仅能选择其中一种"); + } + + } + } + } + } + + @Override + public void prepare() { + + LOG.info("prepare()"); + this.sourceFiles = dfsUtil.getAllFiles(path, specifiedFileType); + LOG.info(String.format("您即将读取的文件数为: [%s]", this.sourceFiles.size())); + LOG.info("待读取的所有文件绝对路径如下:"); + for(String filePath :sourceFiles){ + LOG.info(String.format("[%s]", filePath)); + } + } + + @Override + public List split(int adviceNumber) { + + LOG.info("split() begin..."); + List readerSplitConfigs = new ArrayList(); + // warn:每个slice拖且仅拖一个文件, + // int splitNumber = adviceNumber; + int splitNumber = this.sourceFiles.size(); + if (0 == splitNumber) { + throw DataXException.asDataXException(HdfsReaderErrorCode.EMPTY_DIR_EXCEPTION, + String.format("未能找到待读取的文件,请确认您的配置项path: %s", this.readerOriginConfig.getString(Key.PATH))); + } + + List> splitedSourceFiles = this.splitSourceFiles(new ArrayList(this.sourceFiles), splitNumber); + for (List files : splitedSourceFiles) { + Configuration splitedConfig = this.readerOriginConfig.clone(); + splitedConfig.set(Constant.SOURCE_FILES, files); + readerSplitConfigs.add(splitedConfig); + } + + return readerSplitConfigs; + } + + + private List> splitSourceFiles(final List sourceList, int adviceNumber) { + List> splitedList = new ArrayList>(); + int averageLength = sourceList.size() / adviceNumber; + averageLength = averageLength == 0 ? 1 : averageLength; + + for (int begin = 0, end = 0; begin < sourceList.size(); begin = end) { + end = begin + averageLength; + if (end > sourceList.size()) { + end = sourceList.size(); + } + splitedList.add(sourceList.subList(begin, end)); + } + return splitedList; + } + + + @Override + public void post() { + + } + + @Override + public void destroy() { + + } + + } + + public static class Task extends Reader.Task { + + private static Logger LOG = LoggerFactory.getLogger(Reader.Task.class); + private Configuration taskConfig; + private List sourceFiles; + private String defaultFS; + private HdfsFileType fileType; + private String specifiedFileType; + private String encoding; + private DFSUtil dfsUtil = null; + + @Override + public void init() { + + this.taskConfig = super.getPluginJobConf(); + this.sourceFiles = this.taskConfig.getList(Constant.SOURCE_FILES, String.class); + this.defaultFS = this.taskConfig.getNecessaryValue(Key.DEFAULT_FS, + HdfsReaderErrorCode.DEFAULT_FS_NOT_FIND_ERROR); + this.specifiedFileType = this.taskConfig.getNecessaryValue(Key.FILETYPE, HdfsReaderErrorCode.REQUIRED_VALUE); + this.encoding = this.taskConfig.getString(Key.ENCODING, "UTF-8"); + this.dfsUtil = new DFSUtil(defaultFS); + } + + @Override + public void prepare() { + + } + + @Override + public void startRead(RecordSender recordSender) { + + LOG.info("read start"); + for (String sourceFile : this.sourceFiles) { + LOG.info(String.format("reading file : [%s]", sourceFile)); + fileType = dfsUtil.checkHdfsFileType(sourceFile); + + if((fileType.equals(HdfsFileType.TEXT) || fileType.equals(HdfsFileType.COMPRESSED_TEXT)) + &&(this.specifiedFileType.equalsIgnoreCase(Constant.TEXT))) { + + BufferedReader bufferedReader = dfsUtil.getBufferedReader(sourceFile, fileType, encoding); + UnstructuredStorageReaderUtil.doReadFromStream(bufferedReader, sourceFile, + this.taskConfig, recordSender, this.getTaskPluginCollector()); + }else if(fileType.equals(HdfsFileType.ORC) + && (this.specifiedFileType.equalsIgnoreCase(Constant.ORC))){ + + dfsUtil.orcFileStartRead(sourceFile, this.taskConfig, + recordSender, this.getTaskPluginCollector()); + }else { + + String message = String.format("文件[%s]的类型与用户配置的fileType类型不一致," + + "请确认您配置的目录下面所有文件的类型均为[%s]" + , sourceFile, this.specifiedFileType); + LOG.error(message); + throw DataXException.asDataXException( + HdfsReaderErrorCode.FILE_TYPE_UNSUPPORT, message); + } + + if(recordSender != null){ + recordSender.flush(); + } + } + + LOG.info("end read source files..."); + } + + @Override + public void post() { + + } + + @Override + public void destroy() { + + } + + } + +} \ No newline at end of file diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReaderErrorCode.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReaderErrorCode.java new file mode 100644 index 000000000..4b1af3da9 --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/HdfsReaderErrorCode.java @@ -0,0 +1,44 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum HdfsReaderErrorCode implements ErrorCode { + BAD_CONFIG_VALUE("HdfsReader-00", "您配置的值不合法."), + PATH_NOT_FIND_ERROR("HdfsReader-01", "您未配置path值"), + DEFAULT_FS_NOT_FIND_ERROR("HdfsReader-02", "您未配置defaultFS值"), + ILLEGAL_VALUE("HdfsReader-03", "值错误"), + CONFIG_INVALID_EXCEPTION("HdfsReader-04", "参数配置错误"), + REQUIRED_VALUE("HdfsReader-05", "您缺失了必须填写的参数值."), + NO_INDEX_VALUE("HdfsReader-06","没有 Index" ), + MIXED_INDEX_VALUE("HdfsReader-07","index 和 value 混合" ), + EMPTY_DIR_EXCEPTION("HdfsReader-08", "您尝试读取的文件目录为空."), + PATH_CONFIG_ERROR("HdfsReader-09", "您配置的path格式有误"), + READ_FILE_ERROR("HdfsReader-10", "读取文件出错"), + MALFORMED_ORC_ERROR("HdfsReader-10", "ORCFILE格式异常"), + FILE_TYPE_ERROR("HdfsReader-11", "文件类型配置错误"), + FILE_TYPE_UNSUPPORT("HdfsReader-12", "文件类型目前不支持"),; + + private final String code; + private final String description; + + private HdfsReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} \ No newline at end of file diff --git a/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Key.java b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Key.java new file mode 100644 index 000000000..c9b8ae350 --- /dev/null +++ b/hdfsreader/src/main/java/com/alibaba/datax/plugin/reader/hdfsreader/Key.java @@ -0,0 +1,18 @@ +package com.alibaba.datax.plugin.reader.hdfsreader; + +public final class Key { + + /** + * 此处声明插件用到的需要插件使用者提供的配置项 + */ + public final static String PATH = "path"; + public static final String COLUMN = "column"; + public final static String DEFAULT_FS = "defaultFS"; + public final static String ENCODING = "encoding"; + public static final String TYPE = "type"; + public static final String INDEX = "index"; + public static final String VALUE = "value"; + public static final String FORMAT = "format"; + public static final String FILETYPE = "fileType"; + public static final String NULL_FORMAT = "nullFormat"; +} diff --git a/hdfsreader/src/main/resources/plugin.json b/hdfsreader/src/main/resources/plugin.json new file mode 100644 index 000000000..f3f5c7277 --- /dev/null +++ b/hdfsreader/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "hdfsreader", + "class": "com.alibaba.datax.plugin.reader.hdfsreader.HdfsReader", + "description": "useScene: test. mechanism: use datax framework to transport data from hdfs. warn: The more you know about the data, the less problems you encounter.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/hdfsreader/src/main/resources/plugin_job_template.json b/hdfsreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..d73427d30 --- /dev/null +++ b/hdfsreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,11 @@ +{ + "name": "hdfsreader", + "parameter": { + "path": "", + "defaultFS": "", + "column": [], + "fileType": "orc", + "encoding": "UTF-8", + "fieldDelimiter": "," + } +} \ No newline at end of file diff --git a/hdfswriter/doc/hdfswriter.md b/hdfswriter/doc/hdfswriter.md new file mode 100644 index 000000000..eb7122459 --- /dev/null +++ b/hdfswriter/doc/hdfswriter.md @@ -0,0 +1,355 @@ +# DataX HdfsWriter 插件文档 + + +------------ + +## 1 快速介绍 + +HdfsWriter提供向HDFS文件系统指定路径中写入TEXTFile文件和ORCFile文件,文件内容可与hive中表关联。 + + +有关Hive的资料,可以参看http://baike.corp.taobao.com/index.php/Hive%E5%9F%BA%E7%A1%80%E6%96%87%E6%A1%A3 + +## 2 功能与限制 + +* (1)、目前HdfsWriter仅支持textfile和orcfile两种格式的文件,且文件内容存放的必须是一张逻辑意义上的二维表; +* (2)、由于HDFS是文件系统,不存在schema的概念,因此不支持对部分列写入; +* (3)、目前仅支持与以下Hive数据类型: +数值型:TINYINT,SMALLINT,INT,BIGINT,FLOAT,DOUBLE +字符串类型:STRING,VARCHAR,CHAR +布尔类型:BOOLEAN +时间类型:DATE,TIMESTAMP +**目前不支持:decimal、binary、arrays、maps、structs、union类型**; +* (4)、对于Hive分区表目前仅支持一次写入单个分区; +* (5)、对于textfile需用户保证写入hdfs文件的分隔符**与在Hive上创建表时的分隔符一致**,从而实现写入hdfs数据与Hive表字段关联; +* (6)、HdfsWriter实现过程是:首先根据用户指定的path,创建一个hdfs文件系统上不存在的临时目录,创建规则:path_随机;然后将读取的文件写入这个临时目录;全部写入后再将这个临时目录下的文件移动到用户指定目录(在创建文件时保证文件名不重复); 最后删除临时目录。如果在中间过程发生网络中断等情况造成无法与hdfs建立连接,需要用户手动删除已经写入的文件和临时目录。 +* (7)、目前插件中Hive版本为1.1.1,Hadoop版本为2.5.0(Apache[为适配JDK1.6],在Hadoop 2.6.0 和Hive 1.2.0测试环境中写入正常;其它版本需后期进一步测试; +* (8)、目前HdfsWriter不支持Kerberos等认证,所以用户需要保证DATAX有权限访问该hdfs节点,并且对指定的目录有写的权限 + +## 3 功能说明 + + +### 3.1 配置样例 + +```json +{ + "setting": {}, + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "txtfilereader", + "parameter": { + "path": ["/Users/shf/workplace/txtWorkplace/job/dataorcfull.txt"], + "encoding": "UTF-8", + "column": [ + { + "index": 0, + "type": "long" + }, + { + "index": 1, + "type": "long" + }, + { + "index": 2, + "type": "long" + }, + { + "index": 3, + "type": "long" + }, + { + "index": 4, + "type": "DOUBLE" + }, + { + "index": 5, + "type": "DOUBLE" + }, + { + "index": 6, + "type": "STRING" + }, + { + "index": 7, + "type": "STRING" + }, + { + "index": 8, + "type": "STRING" + }, + { + "index": 9, + "type": "BOOLEAN" + }, + { + "index": 10, + "type": "date" + }, + { + "index": 11, + "type": "date" + } + ], + "fieldDelimiter": "\t" + } + }, + "writer": { + "name": "hdfswriter", + "parameter": { + "defaultFS": "hdfs://10.101.204.12:9000", + "fileType": "orc", + "path": "/user/hive/warehouse/writerorc.db/orcfull", + "fileName": "qiran", + "column": [ + { + "name": "col1", + "type": "TINYINT" + }, + { + "name": "col2", + "type": "SMALLINT" + }, + { + "name": "col3", + "type": "INT" + }, + { + "name": "col4", + "type": "BIGINT" + }, + { + "name": "col5", + "type": "FLOAT" + }, + { + "name": "col6", + "type": "DOUBLE" + }, + { + "name": "col7", + "type": "STRING" + }, + { + "name": "col8", + "type": "VARCHAR" + }, + { + "name": "col9", + "type": "CHAR" + }, + { + "name": "col10", + "type": "BOOLEAN" + }, + { + "name": "col11", + "type": "date" + }, + { + "name": "col12", + "type": "TIMESTAMP" + } + ], + "writeMode": "truncate", + "fieldDelimiter": "\t", + "compress":"NONE" + } + } + } + ] + } +} +``` + +### 3.2 参数说明 + +* **defaultFS** + + * 描述:Hadoop hdfs文件系统namenode节点地址。格式:hdfs://ip:端口;例如:hdfs://10.101.204.12:9000
+ + + **特别需要注意的是,目前HdfsWriter不支持Kerberos等认证,所以用户需要保证DATAX有权限访问该节点** + + + * 必选:是
+ + * 默认值:无
+ +* **fileType** + + * 描述:文件的类型,目前只支持用户配置为"text"或"orc"。
+ + text表示textfile文件格式 + + orc表示orcfile文件格式 + + * 必选:是
+ + * 默认值:无
+* **path** + + * 描述:存储到Hadoop hdfs文件系统的路径信息,HdfsWriter会根据并发配置在Path目录下写入多个文件。为与hive表关联,请填写hive表在hdfs上的存储路径。例:Hive上设置的数据仓库的存储路径为:/user/hive/warehouse/ ,已建立数据库:test,表:hello;则对应的存储路径为:/user/hive/warehouse/test.db/hello
+ + * 必选:是
+ + * 默认值:无
+ +* **fileName** + + * 描述:HdfsWriter写入时的文件名,实际执行时会在该文件名后添加随机的后缀作为每个线程写入实际文件名。
+ + * 必选:是
+ + * 默认值:无
+* **column** + + * 描述:写入数据的字段,不支持对部分列写入。为与hive中表关联,需要指定表中所有字段名和字段类型,其中:name指定字段名,type指定字段类型。
+ + 用户可以指定Column字段信息,配置如下: + + ```json + "column": + [ + { + "name": "userName", + "type": "string" + }, + { + "name": "age", + "type": "long" + } + ] + ``` + + * 必选:是
+ + * 默认值:无
+* **writeMode** + + * 描述:hdfswriter写入前数据清理处理模式:
+ + * append,写入前不做任何处理,DataX hdfswriter直接使用filename写入,并保证文件名不冲突。 + * nonConflict,如果目录下有fileName前缀的文件,直接报错。 + + * 必选:是
+ + * 默认值:无
+ +* **fieldDelimiter** + + * 描述:hdfswriter写入时的字段分隔符,**需要用户保证与创建的Hive表的字段分隔符一致,否则无法在Hive表中查到数据**
+ + * 必选:是
+ + * 默认值:无
+ +* **compress** + + * 描述:hdfs文件压缩类型,默认不填写意味着没有压缩。其中:text类型文件支持压缩类型有gzip、bzip2;orc类型文件支持的压缩类型有NONE、SNAPPY(需要用户安装SnappyCodec)。
+ + * 必选:否
+ + * 默认值:无压缩
+ +* **encoding** + + * 描述:写文件的编码配置。
+ + * 必选:否
+ + * 默认值:utf-8,**慎重修改**
+ + +### 3.3 类型转换 + +目前 HdfsWriter 支持大部分 Hive 类型,请注意检查你的类型。 + +下面列出 HdfsWriter 针对 Hive 数据类型转换列表: + +| DataX 内部类型| HIVE 数据类型 | +| -------- | ----- | +| Long |TINYINT,SMALLINT,INT,BIGINT | +| Double |FLOAT,DOUBLE | +| String |STRING,VARCHAR,CHAR | +| Boolean |BOOLEAN | +| Date |DATE,TIMESTAMP | + + +## 4 配置步骤 +* 步骤一、在Hive中创建数据库、表 +Hive数据库在HDFS上存储配置,在hive安装目录下 conf/hive-site.xml文件中配置,默认值为:/user/hive/warehouse +如下所示: + +```xml + + hive.metastore.warehouse.dir + /user/hive/warehouse + location of default database for the warehouse + +``` +Hive建库/建表语法 参考 [Hive操作手册]( https://cwiki.apache.org/confluence/display/Hive/LanguageManual) + +例: +(1)建立存储为textfile文件类型的表 +```json +create database IF NOT EXISTS hdfswriter; +use hdfswriter; +create table text_table( +col1 TINYINT, +col2 SMALLINT, +col3 INT, +col4 BIGINT, +col5 FLOAT, +col6 DOUBLE, +col7 STRING, +col8 VARCHAR(10), +col9 CHAR(10), +col10 BOOLEAN, +col11 date, +col12 TIMESTAMP +) +row format delimited +fields terminated by "\t" +STORED AS TEXTFILE; +``` +text_table在hdfs上存储路径为:/user/hive/warehouse/hdfswriter.db/text_table/ + +(2)建立存储为orcfile文件类型的表 +```json +create database IF NOT EXISTS hdfswriter; +use hdfswriter; +create table orc_table( +col1 TINYINT, +col2 SMALLINT, +col3 INT, +col4 BIGINT, +col5 FLOAT, +col6 DOUBLE, +col7 STRING, +col8 VARCHAR(10), +col9 CHAR(10), +col10 BOOLEAN, +col11 date, +col12 TIMESTAMP +) +ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' +STORED AS ORC; +``` +orc_table在hdfs上存储路径为:/user/hive/warehouse/hdfswriter.db/orc_table/ + +* 步骤二、根据步骤一的配置信息配置HdfsWriter作业 + +## 5 约束限制 + +略 + +## 6 FAQ + +略 diff --git a/hdfswriter/hdfswriter.iml b/hdfswriter/hdfswriter.iml new file mode 100644 index 000000000..3b92a594e --- /dev/null +++ b/hdfswriter/hdfswriter.iml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hdfswriter/pom.xml b/hdfswriter/pom.xml new file mode 100644 index 000000000..b3f49cbd2 --- /dev/null +++ b/hdfswriter/pom.xml @@ -0,0 +1,135 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + + hdfswriter + hdfswriter + HdfsWriter提供了写入HDFS功能。 + jar + + 1.1.1 + 2.5.0 + + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + org.apache.hadoop + hadoop-hdfs + ${hadoop.version} + + + org.apache.hadoop + hadoop-common + ${hadoop.version} + + + org.apache.hadoop + hadoop-yarn-common + ${hadoop.version} + + + org.apache.hadoop + hadoop-mapreduce-client-core + ${hadoop.version} + + + + org.apache.hive + hive-exec + ${hive.version} + + + org.apache.hive + hive-serde + ${hive.version} + + + org.apache.hive + hive-service + ${hive.version} + + + org.apache.hive + hive-common + ${hive.version} + + + org.apache.hive.hcatalog + hive-hcatalog-core + ${hive.version} + + + + com.alibaba.datax + plugin-unstructured-storage-util + ${datax-project-version} + + + + junit + junit + test + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/hdfswriter/src/main/assembly/package.xml b/hdfswriter/src/main/assembly/package.xml new file mode 100755 index 000000000..316e6b196 --- /dev/null +++ b/hdfswriter/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/hdfswriter + + + target/ + + hdfswriter-0.0.1-SNAPSHOT.jar + + plugin/writer/hdfswriter + + + + + + false + plugin/writer/hdfswriter/libs + runtime + + + diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Constant.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Constant.java new file mode 100755 index 000000000..3e4fa52f9 --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Constant.java @@ -0,0 +1,7 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +public class Constant { + + public static final String DEFAULT_ENCODING = "UTF-8"; + public static final String DEFAULT_NULL_FORMAT = "\\N"; +} diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsHelper.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsHelper.java new file mode 100644 index 000000000..60f686dad --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsHelper.java @@ -0,0 +1,515 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.util.Configuration; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.hadoop.fs.*; +import org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat; +import org.apache.hadoop.hive.ql.io.orc.OrcSerde; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory; +import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector; +import org.apache.hadoop.io.NullWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.compress.CompressionCodec; +import org.apache.hadoop.mapred.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class HdfsHelper { + public static final Logger LOG = LoggerFactory.getLogger(HdfsWriter.Job.class); + public FileSystem fileSystem = null; + public JobConf conf = null; + + public void getFileSystem(String defaultFS){ + org.apache.hadoop.conf.Configuration hadoopConf = new org.apache.hadoop.conf.Configuration(); + hadoopConf.set("fs.defaultFS", defaultFS); + conf = new JobConf(hadoopConf); + try { + fileSystem = FileSystem.get(conf); + } catch (IOException e) { + String message = String.format("获取FileSystem时发生网络IO异常,请检查您的网络是否正常!HDFS地址:[%s]", + "message:defaultFS =" + defaultFS); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, e); + }catch (Exception e) { + String message = String.format("获取FileSystem失败,请检查HDFS地址是否正确: [%s]", + "message:defaultFS =" + defaultFS); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, e); + } + + if(null == fileSystem || null == conf){ + String message = String.format("获取FileSystem失败,请检查HDFS地址是否正确: [%s]", + "message:defaultFS =" + defaultFS); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, message); + } + } + + /** + *获取指定目录先的文件列表 + * @param dir + * @return + * 拿到的是文件全路径, + */ + public String[] hdfsDirList(String dir){ + Path path = new Path(dir); + String[] files = null; + try { + FileStatus[] status = fileSystem.listStatus(path); + files = new String[status.length]; + for(int i=0;i tmpFiles, HashSet endFiles){ + Path tmpFilesParent = null; + if(tmpFiles.size() != endFiles.size()){ + String message = String.format("临时目录下文件名个数与目标文件名个数不一致!"); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.HDFS_RENAME_FILE_ERROR, message); + }else{ + try{ + for (Iterator it1=tmpFiles.iterator(),it2=endFiles.iterator();it1.hasNext()&&it2.hasNext();){ + String srcFile = it1.next().toString(); + String dstFile = it2.next().toString(); + Path srcFilePah = new Path(srcFile); + Path dstFilePah = new Path(dstFile); + if(tmpFilesParent == null){ + tmpFilesParent = srcFilePah.getParent(); + } + LOG.info(String.format("start rename file [%s] to file [%s].", srcFile,dstFile)); + boolean renameTag = false; + long fileLen = fileSystem.getFileStatus(srcFilePah).getLen(); + if(fileLen>0){ + renameTag = fileSystem.rename(srcFilePah,dstFilePah); + if(!renameTag){ + String message = String.format("重命名文件[%s]失败,请检查您的网络是否正常!", srcFile); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.HDFS_RENAME_FILE_ERROR, message); + } + LOG.info(String.format("finish rename file [%s] to file [%s].", srcFile,dstFile)); + }else{ + LOG.info(String.format("文件[%s]内容为空,请检查写入是否正常!", srcFile)); + } + } + }catch (Exception e) { + String message = String.format("重命名文件时发生异常,请检查您的网络是否正常!"); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, e); + }finally { + deleteDir(tmpFilesParent); + } + } + } + + //关闭FileSystem + public void closeFileSystem(){ + try { + fileSystem.close(); + } catch (IOException e) { + String message = String.format("关闭FileSystem时发生IO异常,请检查您的网络是否正常!"); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, e); + } + } + + + //textfile格式文件 + public FSDataOutputStream getOutputStream(String path){ + Path storePath = new Path(path); + FSDataOutputStream fSDataOutputStream = null; + try { + fSDataOutputStream = fileSystem.create(storePath); + } catch (IOException e) { + String message = String.format("Create an FSDataOutputStream at the indicated Path[%s] failed: [%s]", + "message:path =" + path); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.Write_FILE_IO_ERROR, e); + } + return fSDataOutputStream; + } + + /** + * 写textfile类型文件 + * @param lineReceiver + * @param config + * @param fileName + * @param taskPluginCollector + */ + public void textFileStartWrite(RecordReceiver lineReceiver, Configuration config, String fileName, + TaskPluginCollector taskPluginCollector){ + char fieldDelimiter = config.getChar(Key.FIELD_DELIMITER); + List columns = config.getListConfiguration(Key.COLUMN); + String compress = config.getString(Key.COMPRESS,null); + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); + String attempt = "attempt_"+dateFormat.format(new Date())+"_0001_m_000000_0"; + Path outputPath = new Path(fileName); + //todo 需要进一步确定TASK_ATTEMPT_ID + conf.set(JobContext.TASK_ATTEMPT_ID, attempt); + FileOutputFormat outFormat = new TextOutputFormat(); + outFormat.setOutputPath(conf, outputPath); + outFormat.setWorkOutputPath(conf, outputPath); + if(null != compress) { + Class codecClass = getCompressCodec(compress); + if (null != codecClass) { + outFormat.setOutputCompressorClass(conf, codecClass); + } + } + try { + RecordWriter writer = outFormat.getRecordWriter(fileSystem, conf, outputPath.toString(), Reporter.NULL); + Record record = null; + while ((record = lineReceiver.getFromReader()) != null) { + MutablePair transportResult = transportOneRecord(record, fieldDelimiter, columns, taskPluginCollector); + if (!transportResult.getRight()) { + writer.write(NullWritable.get(),transportResult.getLeft()); + } + } + writer.close(Reporter.NULL); + } catch (Exception e) { + String message = String.format("写文件文件[%s]时发生IO异常,请检查您的网络是否正常!", fileName); + LOG.error(message); + Path path = new Path(fileName); + deleteDir(path.getParent()); + throw DataXException.asDataXException(HdfsWriterErrorCode.Write_FILE_IO_ERROR, e); + } + } + + public static MutablePair transportOneRecord( + Record record, char fieldDelimiter, List columnsConfiguration, TaskPluginCollector taskPluginCollector) { + MutablePair, Boolean> transportResultList = transportOneRecord(record,columnsConfiguration,taskPluginCollector); + //保存<转换后的数据,是否是脏数据> + MutablePair transportResult = new MutablePair(); + transportResult.setRight(false); + if(null != transportResultList){ + Text recordResult = new Text(StringUtils.join(transportResultList.getLeft(), fieldDelimiter)); + transportResult.setRight(transportResultList.getRight()); + transportResult.setLeft(recordResult); + } + return transportResult; + } + + public Class getCompressCodec(String compress){ + Class codecClass = null; + if(null == compress){ + codecClass = null; + }else if("GZIP".equalsIgnoreCase(compress)){ + codecClass = org.apache.hadoop.io.compress.GzipCodec.class; + }else if ("BZIP2".equalsIgnoreCase(compress)) { + codecClass = org.apache.hadoop.io.compress.BZip2Codec.class; + }else if("SNAPPY".equalsIgnoreCase(compress)){ + //todo 等需求明确后支持 需要用户安装SnappyCodec + codecClass = org.apache.hadoop.io.compress.SnappyCodec.class; + // org.apache.hadoop.hive.ql.io.orc.ZlibCodec.class not public + //codecClass = org.apache.hadoop.hive.ql.io.orc.ZlibCodec.class; + }else { + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("目前不支持您配置的 compress 模式 : [%s]", compress)); + } + return codecClass; + } + + /** + * 写orcfile类型文件 + * @param lineReceiver + * @param config + * @param fileName + * @param taskPluginCollector + */ + public void orcFileStartWrite(RecordReceiver lineReceiver, Configuration config, String fileName, + TaskPluginCollector taskPluginCollector){ + List columns = config.getListConfiguration(Key.COLUMN); + String compress = config.getString(Key.COMPRESS, null); + List columnNames = getColumnNames(columns); + List columnTypeInspectors = getColumnTypeInspectors(columns); + StructObjectInspector inspector = (StructObjectInspector)ObjectInspectorFactory + .getStandardStructObjectInspector(columnNames, columnTypeInspectors); + + OrcSerde orcSerde = new OrcSerde(); + + FileOutputFormat outFormat = new OrcOutputFormat(); + if(!"NONE".equalsIgnoreCase(compress) && null != compress ) { + Class codecClass = getCompressCodec(compress); + if (null != codecClass) { + outFormat.setOutputCompressorClass(conf, codecClass); + } + } + try { + RecordWriter writer = outFormat.getRecordWriter(fileSystem, conf, fileName, Reporter.NULL); + Record record = null; + while ((record = lineReceiver.getFromReader()) != null) { + MutablePair, Boolean> transportResult = transportOneRecord(record,columns,taskPluginCollector); + if (!transportResult.getRight()) { + writer.write(NullWritable.get(), orcSerde.serialize(transportResult.getLeft(), inspector)); + } + } + writer.close(Reporter.NULL); + } catch (Exception e) { + String message = String.format("写文件文件[%s]时发生IO异常,请检查您的网络是否正常!", fileName); + LOG.error(message); + Path path = new Path(fileName); + deleteDir(path.getParent()); + throw DataXException.asDataXException(HdfsWriterErrorCode.Write_FILE_IO_ERROR, e); + } + } + + public List getColumnNames(List columns){ + List columnNames = Lists.newArrayList(); + for (Configuration eachColumnConf : columns) { + columnNames.add(eachColumnConf.getString(Key.NAME)); + } + return columnNames; + } + + /** + * 根据writer配置的字段类型,构建inspector + * @param columns + * @return + */ + public List getColumnTypeInspectors(List columns){ + List columnTypeInspectors = Lists.newArrayList(); + for (Configuration eachColumnConf : columns) { + SupportHiveDataType columnType = SupportHiveDataType.valueOf(eachColumnConf.getString(Key.TYPE).toUpperCase()); + ObjectInspector objectInspector = null; + switch (columnType) { + case TINYINT: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Byte.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case SMALLINT: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Short.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case INT: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Integer.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case BIGINT: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Long.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case FLOAT: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Float.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case DOUBLE: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Double.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case TIMESTAMP: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(java.sql.Timestamp.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case DATE: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(java.sql.Date.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case STRING: + case VARCHAR: + case CHAR: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(String.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + case BOOLEAN: + objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(Boolean.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA); + break; + default: + throw DataXException + .asDataXException( + HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format( + "您的配置文件中的列配置信息有误. 因为DataX 不支持数据库写入这种字段类型. 字段名:[%s], 字段类型:[%d]. 请修改表中该字段的类型或者不同步该字段.", + eachColumnConf.getString(Key.NAME), + eachColumnConf.getString(Key.TYPE))); + } + + columnTypeInspectors.add(objectInspector); + } + return columnTypeInspectors; + } + + public OrcSerde getOrcSerde(Configuration config){ + String fieldDelimiter = config.getString(Key.FIELD_DELIMITER); + String compress = config.getString(Key.COMPRESS); + String encoding = config.getString(Key.ENCODING); + + OrcSerde orcSerde = new OrcSerde(); + Properties properties = new Properties(); + properties.setProperty("orc.bloom.filter.columns", fieldDelimiter); + properties.setProperty("orc.compress", compress); + properties.setProperty("orc.encoding.strategy", encoding); + + orcSerde.initialize(conf, properties); + return orcSerde; + } + + public static MutablePair, Boolean> transportOneRecord( + Record record,List columnsConfiguration, + TaskPluginCollector taskPluginCollector){ + + MutablePair, Boolean> transportResult = new MutablePair, Boolean>(); + transportResult.setRight(false); + List recordList = Lists.newArrayList(); + int recordLength = record.getColumnNumber(); + if (0 != recordLength) { + Column column; + for (int i = 0; i < recordLength; i++) { + column = record.getColumn(i); + //todo as method + String rowData = column.getRawData().toString(); + if (null != column.getRawData() && StringUtils.isNotBlank(rowData)) { + SupportHiveDataType columnType = SupportHiveDataType.valueOf( + columnsConfiguration.get(i).getString(Key.TYPE).toUpperCase()); + //根据writer端类型配置做类型转换 + try { + switch (columnType) { + case TINYINT: + recordList.add(Byte.valueOf(rowData)); + break; + case SMALLINT: + recordList.add(Short.valueOf(rowData)); + break; + case INT: + recordList.add(Integer.valueOf(rowData)); + break; + case BIGINT: + recordList.add(column.asLong()); + break; + case FLOAT: + recordList.add(Float.valueOf(rowData)); + break; + case DOUBLE: + recordList.add(column.asDouble()); + break; + case STRING: + case VARCHAR: + case CHAR: + recordList.add(column.asString()); + break; + case BOOLEAN: + recordList.add(column.asBoolean()); + break; + case DATE: + recordList.add(new java.sql.Date(column.asDate().getTime())); + break; + case TIMESTAMP: + recordList.add(new java.sql.Timestamp(column.asDate().getTime())); + break; + default: + throw DataXException + .asDataXException( + HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format( + "您的配置文件中的列配置信息有误. 因为DataX 不支持数据库写入这种字段类型. 字段名:[%s], 字段类型:[%d]. 请修改表中该字段的类型或者不同步该字段.", + columnsConfiguration.get(i).getString(Key.NAME), + columnsConfiguration.get(i).getString(Key.TYPE))); + } + } catch (Exception e) { + // warn: 此处认为脏数据 + String message = String.format( + "字段类型转换错误:你目标字段为[%s]类型,实际字段值为[%s].", + columnsConfiguration.get(i).getString(Key.TYPE), column.getRawData().toString()); + taskPluginCollector.collectDirtyRecord(record, message); + transportResult.setRight(true); + break; + } + }else { + // warn: it's all ok if nullFormat is null + recordList.add(null); + } + } + } + transportResult.setLeft(recordList); + return transportResult; + } +} diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriter.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriter.java new file mode 100644 index 000000000..8c57eb141 --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriter.java @@ -0,0 +1,373 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.unstructuredstorage.writer.Constant; +import com.google.common.collect.Sets; +import org.apache.commons.io.Charsets; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.fs.Path; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + + +public class HdfsWriter extends Writer { + public static class Job extends Writer.Job { + private static final Logger LOG = LoggerFactory.getLogger(Job.class); + + private Configuration writerSliceConfig = null; + + private String defaultFS; + private String path; + private String fileType; + private String fileName; + private List columns; + private String writeMode; + private String fieldDelimiter; + private String compress; + private String encoding; + private HashSet tmpFiles = new HashSet();//临时文件全路径 + private HashSet endFiles = new HashSet();//最终文件全路径 + + private HdfsHelper hdfsHelper = null; + + @Override + public void init() { + this.writerSliceConfig = this.getPluginJobConf(); + this.validateParameter(); + + //创建textfile存储 + hdfsHelper = new HdfsHelper(); + + hdfsHelper.getFileSystem(defaultFS); + } + + private void validateParameter() { + this.defaultFS = this.writerSliceConfig.getNecessaryValue(Key.DEFAULT_FS, HdfsWriterErrorCode.REQUIRED_VALUE); + //fileType check + this.fileType = this.writerSliceConfig.getNecessaryValue(Key.FILE_TYPE, HdfsWriterErrorCode.REQUIRED_VALUE); + if( !fileType.equalsIgnoreCase("ORC") && !fileType.equalsIgnoreCase("TEXT")){ + String message = "HdfsWriter插件目前只支持ORC和TEXT两种格式的文件,请将filetype选项的值配置为ORC或者TEXT"; + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, message); + } + //path + this.path = this.writerSliceConfig.getNecessaryValue(Key.PATH, HdfsWriterErrorCode.REQUIRED_VALUE); + if(!path.startsWith("/")){ + String message = String.format("请检查参数path:[%s],需要配置为绝对路径", path); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, message); + }else if(path.contains("*") || path.contains("?")){ + String message = String.format("请检查参数path:[%s],不能包含*,?等特殊字符", path); + LOG.error(message); + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, message); + } + //fileName + this.fileName = this.writerSliceConfig.getNecessaryValue(Key.FILE_NAME, HdfsWriterErrorCode.REQUIRED_VALUE); + //columns check + this.columns = this.writerSliceConfig.getListConfiguration(Key.COLUMN); + if (null == columns || columns.size() == 0) { + throw DataXException.asDataXException(HdfsWriterErrorCode.REQUIRED_VALUE, "您需要指定 columns"); + }else{ + for (Configuration eachColumnConf : columns) { + eachColumnConf.getNecessaryValue(Key.NAME, HdfsWriterErrorCode.COLUMN_REQUIRED_VALUE); + eachColumnConf.getNecessaryValue(Key.TYPE, HdfsWriterErrorCode.COLUMN_REQUIRED_VALUE); + } + } + //writeMode check + this.writeMode = this.writerSliceConfig.getNecessaryValue(Key.WRITE_MODE, HdfsWriterErrorCode.REQUIRED_VALUE); + writeMode = writeMode.toLowerCase().trim(); + Set supportedWriteModes = Sets.newHashSet("append", "nonconflict"); + if (!supportedWriteModes.contains(writeMode)) { + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("仅支持append, nonConflict两种模式, 不支持您配置的 writeMode 模式 : [%s]", + writeMode)); + } + this.writerSliceConfig.set(Key.WRITE_MODE, writeMode); + //fieldDelimiter check + this.fieldDelimiter = this.writerSliceConfig.getString(Key.FIELD_DELIMITER,null); + if(null == fieldDelimiter){ + throw DataXException.asDataXException(HdfsWriterErrorCode.REQUIRED_VALUE, + String.format("您提供配置文件有误,[%s]是必填参数.", Key.FIELD_DELIMITER)); + }else if(1 != fieldDelimiter.length()){ + // warn: if have, length must be one + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("仅仅支持单字符切分, 您配置的切分为 : [%s]", fieldDelimiter)); + } + //compress check + this.compress = this.writerSliceConfig.getString(Key.COMPRESS,null); + if(fileType.equalsIgnoreCase("TEXT")){ + Set textSupportedCompress = Sets.newHashSet("GZIP", "BZIP2"); + if(null == compress ){ + this.writerSliceConfig.set(Key.COMPRESS, null); + }else { + compress = compress.toUpperCase().trim(); + if(!textSupportedCompress.contains(compress) ){ + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("目前TEXT FILE仅支持GZIP、BZIP2 两种压缩, 不支持您配置的 compress 模式 : [%s]", + compress)); + } + } + }else if(fileType.equalsIgnoreCase("ORC")){ + Set orcSupportedCompress = Sets.newHashSet("NONE", "SNAPPY"); + if(null == compress){ + this.writerSliceConfig.set(Key.COMPRESS, "NONE"); + }else { + compress = compress.toUpperCase().trim(); + if(!orcSupportedCompress.contains(compress)){ + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("目前ORC FILE仅支持SNAPPY压缩, 不支持您配置的 compress 模式 : [%s]", + compress)); + } + } + + } + // encoding check + this.encoding = this.writerSliceConfig.getString(Key.ENCODING,Constant.DEFAULT_ENCODING); + try { + encoding = encoding.trim(); + this.writerSliceConfig.set(Key.ENCODING, encoding); + Charsets.toCharset(encoding); + } catch (Exception e) { + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("不支持您配置的编码格式:[%s]", encoding), e); + } + } + + @Override + public void prepare() { + //若路径已经存在,检查path是否是目录 + if(hdfsHelper.isPathexists(path)){ + if(!hdfsHelper.isPathDir(path)){ + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("您配置的path: [%s] 不是一个合法的目录, 请您注意文件重名, 不合法目录名等情况.", + path)); + } + //根据writeMode对目录下文件进行处理 + Path[] existFilePaths = hdfsHelper.hdfsDirList(path,fileName); + boolean isExistFile = false; + if(existFilePaths.length > 0){ + isExistFile = true; + } + /** + if ("truncate".equals(writeMode) && isExistFile ) { + LOG.info(String.format("由于您配置了writeMode truncate, 开始清理 [%s] 下面以 [%s] 开头的内容", + path, fileName)); + hdfsHelper.deleteFiles(existFilePaths); + } else + */ + if ("append".equalsIgnoreCase(writeMode)) { + LOG.info(String.format("由于您配置了writeMode append, 写入前不做清理工作, [%s] 目录下写入相应文件名前缀 [%s] 的文件", + path, fileName)); + } else if ("nonconflict".equalsIgnoreCase(writeMode) && isExistFile) { + LOG.info(String.format("由于您配置了writeMode nonConflict, 开始检查 [%s] 下面的内容", path)); + List allFiles = new ArrayList(); + for (Path eachFile : existFilePaths) { + allFiles.add(eachFile.toString()); + } + LOG.error(String.format("冲突文件列表为: [%s]", StringUtils.join(allFiles, ","))); + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("由于您配置了writeMode nonConflict,但您配置的path: [%s] 目录不为空, 下面存在其他文件或文件夹.", path)); + } + }else{ + throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE, + String.format("您配置的path: [%s] 不存在, 请先在hive端创建对应的数据库和表.", path)); + } + } + + @Override + public void post() { + hdfsHelper.renameFile(tmpFiles, endFiles); + } + + @Override + public void destroy() { + hdfsHelper.closeFileSystem(); + } + + @Override + public List split(int mandatoryNumber) { + LOG.info("begin do split..."); + List writerSplitConfigs = new ArrayList(); + String filePrefix = fileName; + + Set allFiles = new HashSet(); + + //获取该路径下的所有已有文件列表 + if(hdfsHelper.isPathexists(path)){ + allFiles.addAll(Arrays.asList(hdfsHelper.hdfsDirList(path))); + } + + String fileSuffix; + //临时存放路径 + String storePath = buildTmpFilePath(this.path); + //最终存放路径 + String endStorePath = buildFilePath(); + this.path = endStorePath; + for (int i = 0; i < mandatoryNumber; i++) { + // handle same file name + + Configuration splitedTaskConfig = this.writerSliceConfig.clone(); + String fullFileName = null; + String endFullFileName = null; + + fileSuffix = UUID.randomUUID().toString().replace('-', '_'); + + fullFileName = String.format("%s%s%s__%s", defaultFS, storePath, filePrefix, fileSuffix); + endFullFileName = String.format("%s%s%s__%s", defaultFS, endStorePath, filePrefix, fileSuffix); + + while (allFiles.contains(endFullFileName)) { + fileSuffix = UUID.randomUUID().toString().replace('-', '_'); + fullFileName = String.format("%s%s%s__%s", defaultFS, storePath, filePrefix, fileSuffix); + endFullFileName = String.format("%s%s%s__%s", defaultFS, endStorePath, filePrefix, fileSuffix); + } + allFiles.add(endFullFileName); + + //设置临时文件全路径和最终文件全路径 + if("GZIP".equalsIgnoreCase(this.compress)){ + this.tmpFiles.add(fullFileName + ".gz"); + this.endFiles.add(endFullFileName + ".gz"); + }else if("BZIP2".equalsIgnoreCase(compress)){ + this.tmpFiles.add(fullFileName + ".bz2"); + this.endFiles.add(endFullFileName + ".bz2"); + }else{ + this.tmpFiles.add(fullFileName); + this.endFiles.add(endFullFileName); + } + + splitedTaskConfig + .set(com.alibaba.datax.plugin.unstructuredstorage.writer.Key.FILE_NAME, + fullFileName); + + LOG.info(String.format("splited write file name:[%s]", + fullFileName)); + + writerSplitConfigs.add(splitedTaskConfig); + } + LOG.info("end do split."); + return writerSplitConfigs; + } + + private String buildFilePath() { + boolean isEndWithSeparator = false; + switch (IOUtils.DIR_SEPARATOR) { + case IOUtils.DIR_SEPARATOR_UNIX: + isEndWithSeparator = this.path.endsWith(String + .valueOf(IOUtils.DIR_SEPARATOR)); + break; + case IOUtils.DIR_SEPARATOR_WINDOWS: + isEndWithSeparator = this.path.endsWith(String + .valueOf(IOUtils.DIR_SEPARATOR_WINDOWS)); + break; + default: + break; + } + if (!isEndWithSeparator) { + this.path = this.path + IOUtils.DIR_SEPARATOR; + } + return this.path; + } + + /** + * 创建临时目录 + * @param userPath + * @return + */ + private String buildTmpFilePath(String userPath) { + String tmpFilePath; + boolean isEndWithSeparator = false; + switch (IOUtils.DIR_SEPARATOR) { + case IOUtils.DIR_SEPARATOR_UNIX: + isEndWithSeparator = userPath.endsWith(String + .valueOf(IOUtils.DIR_SEPARATOR)); + break; + case IOUtils.DIR_SEPARATOR_WINDOWS: + isEndWithSeparator = userPath.endsWith(String + .valueOf(IOUtils.DIR_SEPARATOR_WINDOWS)); + break; + default: + break; + } + String tmpSuffix; + tmpSuffix = UUID.randomUUID().toString().replace('-', '_'); + if (!isEndWithSeparator) { + tmpFilePath = String.format("%s__%s%s", userPath, tmpSuffix, IOUtils.DIR_SEPARATOR); + }else if("/".equals(userPath)){ + tmpFilePath = String.format("%s__%s%s", userPath, tmpSuffix, IOUtils.DIR_SEPARATOR); + }else{ + tmpFilePath = String.format("%s__%s%s", userPath.substring(0,userPath.length()-1), tmpSuffix, IOUtils.DIR_SEPARATOR); + } + while(hdfsHelper.isPathexists(tmpFilePath)){ + tmpSuffix = UUID.randomUUID().toString().replace('-', '_'); + if (!isEndWithSeparator) { + tmpFilePath = String.format("%s__%s%s", userPath, tmpSuffix, IOUtils.DIR_SEPARATOR); + }else if("/".equals(userPath)){ + tmpFilePath = String.format("%s__%s%s", userPath, tmpSuffix, IOUtils.DIR_SEPARATOR); + }else{ + tmpFilePath = String.format("%s__%s%s", userPath.substring(0,userPath.length()-1), tmpSuffix, IOUtils.DIR_SEPARATOR); + } + } + return tmpFilePath; + } + } + + public static class Task extends Writer.Task { + private static final Logger LOG = LoggerFactory.getLogger(Task.class); + + private Configuration writerSliceConfig; + + private String defaultFS; + private String fileType; + private String fileName; + + private HdfsHelper hdfsHelper = null; + + @Override + public void init() { + this.writerSliceConfig = this.getPluginJobConf(); + + this.defaultFS = this.writerSliceConfig.getString(Key.DEFAULT_FS); + this.fileType = this.writerSliceConfig.getString(Key.FILE_TYPE); + this.fileName = this.writerSliceConfig.getString(Key.FILE_NAME); + + hdfsHelper = new HdfsHelper(); + hdfsHelper.getFileSystem(defaultFS); + } + + @Override + public void prepare() { + + } + + @Override + public void startWrite(RecordReceiver lineReceiver) { + LOG.info("begin do write..."); + LOG.info(String.format("write to file : [%s]", this.fileName)); + if(fileType.equalsIgnoreCase("TEXT")){ + //写TEXT FILE + hdfsHelper.textFileStartWrite(lineReceiver,this.writerSliceConfig, this.fileName, + this.getTaskPluginCollector()); + }else if(fileType.equalsIgnoreCase("ORC")){ + //写ORC FILE + hdfsHelper.orcFileStartWrite(lineReceiver,this.writerSliceConfig, this.fileName, + this.getTaskPluginCollector()); + } + + LOG.info("end do write"); + } + + @Override + public void post() { + + } + + @Override + public void destroy() { + + } + } +} diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriterErrorCode.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriterErrorCode.java new file mode 100644 index 000000000..4dedfd4f9 --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/HdfsWriterErrorCode.java @@ -0,0 +1,44 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * Created by shf on 15/10/8. + */ +public enum HdfsWriterErrorCode implements ErrorCode { + + CONFIG_INVALID_EXCEPTION("HdfsWriter-00", "您的参数配置错误."), + REQUIRED_VALUE("HdfsWriter-01", "您缺失了必须填写的参数值."), + ILLEGAL_VALUE("HdfsWriter-02", "您填写的参数值不合法."), + WRITER_FILE_WITH_CHARSET_ERROR("HdfsWriter-03", "您配置的编码未能正常写入."), + Write_FILE_IO_ERROR("HdfsWriter-04", "您配置的文件在写入时出现IO异常."), + WRITER_RUNTIME_EXCEPTION("HdfsWriter-05", "出现运行时异常, 请联系我们."), + CONNECT_HDFS_IO_ERROR("HdfsWriter-06", "与HDFS建立连接时出现IO异常."), + COLUMN_REQUIRED_VALUE("HdfsWriter-07", "您column配置中缺失了必须填写的参数值."), + HDFS_RENAME_FILE_ERROR("HdfsWriter-08", "将文件移动到配置路径失败."); + + private final String code; + private final String description; + + private HdfsWriterErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s].", this.code, + this.description); + } + +} diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Key.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Key.java new file mode 100644 index 000000000..dd7438fc6 --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/Key.java @@ -0,0 +1,32 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +/** + * Created by shf on 15/10/8. + */ +public class Key { + // must have + public static final String PATH = "path"; + //must have + public final static String DEFAULT_FS = "defaultFS"; + //must have + public final static String FILE_TYPE = "fileType"; + // must have + public static final String FILE_NAME = "fileName"; + // must have for column + public static final String COLUMN = "column"; + public static final String NAME = "name"; + public static final String TYPE = "type"; + public static final String DATE_FORMAT = "dateFormat"; + // must have + public static final String WRITE_MODE = "writeMode"; + // must have + public static final String FIELD_DELIMITER = "fieldDelimiter"; + // not must, default UTF-8 + public static final String ENCODING = "encoding"; + // not must, default no compress + public static final String COMPRESS = "compress"; + // not must, not default \N + public static final String NULL_FORMAT = "nullFormat"; + + +} diff --git a/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/SupportHiveDataType.java b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/SupportHiveDataType.java new file mode 100644 index 000000000..b7949302c --- /dev/null +++ b/hdfswriter/src/main/java/com/alibaba/datax/plugin/writer/hdfswriter/SupportHiveDataType.java @@ -0,0 +1,19 @@ +package com.alibaba.datax.plugin.writer.hdfswriter; + +public enum SupportHiveDataType { + TINYINT, + SMALLINT, + INT, + BIGINT, + FLOAT, + DOUBLE, + + TIMESTAMP, + DATE, + + STRING, + VARCHAR, + CHAR, + + BOOLEAN +} diff --git a/hdfswriter/src/main/resources/plugin.json b/hdfswriter/src/main/resources/plugin.json new file mode 100755 index 000000000..384f4a7a8 --- /dev/null +++ b/hdfswriter/src/main/resources/plugin.json @@ -0,0 +1,7 @@ +{ + "name": "hdfswriter", + "class": "com.alibaba.datax.plugin.writer.hdfswriter.HdfsWriter", + "description": "useScene: prod. mechanism: via FileSystem connect HDFS write data concurrent.", + "developer": "alibaba" +} + diff --git a/hdfswriter/src/main/resources/plugin_job_template.json b/hdfswriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..08b4ab62e --- /dev/null +++ b/hdfswriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,13 @@ +{ + "name": "hdfswriter", + "parameter": { + "defaultFS": "", + "fileType": "", + "path": "", + "fileName": "", + "column": [], + "writeMode": "", + "fieldDelimiter": "", + "compress":"" + } +} \ No newline at end of file diff --git a/mongodbreader/doc/mongodbreader.md b/mongodbreader/doc/mongodbreader.md new file mode 100644 index 000000000..b716b8d38 --- /dev/null +++ b/mongodbreader/doc/mongodbreader.md @@ -0,0 +1,149 @@ +### Datax MongoDBReader +#### 1 快速介绍 + +MongoDBReader 插件利用 MongoDB 的java客户端MongoClient进行MongoDB的读操作。最新版本的Mongo已经将DB锁的粒度从DB级别降低到document级别,配合上MongoDB强大的索引功能,基本可以达到高性能的读取MongoDB的需求。 + +#### 2 实现原理 + +MongoDBReader通过Datax框架从MongoDB并行的读取数据,通过主控的JOB程序按照指定的规则对MongoDB中的数据进行分片,并行读取,然后将MongoDB支持的类型通过逐一判断转换成Datax支持的类型。 + +#### 3 功能说明 +* 该示例从ODPS读一份数据到MongoDB。 + + { + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "mongodbreader", + "parameter": { + "address": ["127.0.0.1:27017"], + "userName": "", + "userPassword": "", + "dbName": "tag_per_data", + "collectionName": "tag_data12", + "column": [ + { + "name": "unique_id", + "type": "string" + }, + { + "name": "sid", + "type": "string" + }, + { + "name": "user_id", + "type": "string" + }, + { + "name": "auction_id", + "type": "string" + }, + { + "name": "content_type", + "type": "string" + }, + { + "name": "pool_type", + "type": "string" + }, + { + "name": "frontcat_id", + "type": "Array", + "spliter": "" + }, + { + "name": "categoryid", + "type": "Array", + "spliter": "" + }, + { + "name": "gmt_create", + "type": "string" + }, + { + "name": "taglist", + "type": "Array", + "spliter": " " + }, + { + "name": "property", + "type": "string" + }, + { + "name": "scorea", + "type": "int" + }, + { + "name": "scoreb", + "type": "int" + }, + { + "name": "scorec", + "type": "int" + } + ] + } + }, + "writer": { + "name": "odpswriter", + "parameter": { + "project": "tb_ai_recommendation", + "table": "jianying_tag_datax_read_test01", + "column": [ + "unique_id", + "sid", + "user_id", + "auction_id", + "content_type", + "pool_type", + "frontcat_id", + "categoryid", + "gmt_create", + "taglist", + "property", + "scorea", + "scoreb" + ], + "accessId": "**************", + "accessKey": "********************", + "truncate": true, + "odpsServer": "http://service-corp.odps.aliyun-inc.com/api", + "tunnelServer": "http://dt-corp.odps.aliyun-inc.com/", + "accountType": "aliyun" + } + } + } + ] + } + } +#### 4 参数说明 + +* address: MongoDB的数据地址信息,因为MonogDB可能是个集群,则ip端口信息需要以Json数组的形式给出。【必填】 +* userName:MongoDB的用户名。【选填】 +* userPassword: MongoDB的密码。【选填】 +* collectionName: MonogoDB的集合名。【必填】 +* column:MongoDB的文档列名。【必填】 +* name:Column的名字。【必填】 +* type:Column的类型。【选填】 +* splitter:因为MongoDB支持数组类型,但是Datax框架本身不支持数组类型,所以mongoDB读出来的数组类型要通过这个分隔符合并成字符串。【选填】 + +#### 5 类型转换 + +| DataX 内部类型| MongoDB 数据类型 | +| -------- | ----- | +| Long | int, Long | +| Double | double | +| String | string, array | +| Date | date | +| Boolean | boolean | +| Bytes | bytes | + + +#### 6 性能报告 +#### 7 测试报告 \ No newline at end of file diff --git a/mongodbreader/mongodbreader.iml b/mongodbreader/mongodbreader.iml new file mode 100644 index 000000000..2d482f6d0 --- /dev/null +++ b/mongodbreader/mongodbreader.iml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mongodbreader/pom.xml b/mongodbreader/pom.xml new file mode 100644 index 000000000..6f9736a34 --- /dev/null +++ b/mongodbreader/pom.xml @@ -0,0 +1,88 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + + mongodbreader + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + com.alibaba.datax + plugin-unstructured-storage-util + ${datax-project-version} + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + com.google.guava + guava + + + + org.mongodb + mongo-java-driver + 3.0.3 + + + com.google.guava + guava + 16.0.1 + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/mongodbreader/src/main/assembly/package.xml b/mongodbreader/src/main/assembly/package.xml new file mode 100644 index 000000000..a7e967f90 --- /dev/null +++ b/mongodbreader/src/main/assembly/package.xml @@ -0,0 +1,36 @@ + + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/mongodbreader + + + target/ + + mongodbreader-0.0.1-SNAPSHOT.jar + + plugin/reader/mongodbreader + + + + + + false + plugin/reader/mongodbreader/libs + runtime + + + diff --git a/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/KeyConstant.java b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/KeyConstant.java new file mode 100644 index 000000000..d70966476 --- /dev/null +++ b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/KeyConstant.java @@ -0,0 +1,67 @@ +package com.alibaba.datax.plugin.reader.mongodbreader; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public class KeyConstant { + /** + * 数组类型 + */ + public static final String ARRAY_TYPE = "array"; + /** + * mongodb 的 host 地址 + */ + public static final String MONGO_ADDRESS = "address"; + /** + * mongodb 的用户名 + */ + public static final String MONGO_USER_NAME = "userName"; + /** + * mongodb 密码 + */ + public static final String MONGO_USER_PASSWORD = "userPassword"; + /** + * mongodb 数据库名 + */ + public static final String MONGO_DB_NAME = "dbName"; + /** + * mongodb 集合名 + */ + public static final String MONGO_COLLECTION_NAME = "collectionName"; + /** + * mongodb 的列 + */ + public static final String MONGO_COLUMN = "column"; + /** + * 每个列的名字 + */ + public static final String COLUMN_NAME = "name"; + /** + * 每个列的类型 + */ + public static final String COLUMN_TYPE = "type"; + /** + * 列分隔符 + */ + public static final String COLUMN_SPLITTER = "splitter"; + /** + * 跳过的列数 + */ + public static final String SKIP_COUNT = "skipCount"; + /** + * 批量获取的记录数 + */ + public static final String BATCH_SIZE = "batchSize"; + /** + * MongoDB的idmeta + */ + public static final String MONGO_PRIMIARY_ID_META = "_id"; + /** + * 判断是否为数组类型 + * @param type 数据类型 + * @return + */ + public static boolean isArrayType(String type) { + return ARRAY_TYPE.equals(type); + } +} diff --git a/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReader.java b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReader.java new file mode 100644 index 000000000..c5ae37d6a --- /dev/null +++ b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReader.java @@ -0,0 +1,173 @@ +package com.alibaba.datax.plugin.reader.mongodbreader; +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.mongodbreader.util.CollectionSplitUtil; +import com.alibaba.datax.plugin.reader.mongodbreader.util.MongoUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.mongodb.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Array; +import java.util.*; + +/** + * Created by jianying.wcj on 2015/3/19 0019. + */ +public class MongoDBReader extends Reader { + + public static class Job extends Reader.Job { + + private Configuration originalConfig = null; + + private MongoClient mongoClient; + + private String userName = null; + private String password = null; + + @Override + public List split(int adviceNumber) { + return CollectionSplitUtil.doSplit(originalConfig,adviceNumber,mongoClient); + } + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + this.userName = originalConfig.getString(KeyConstant.MONGO_USER_NAME); + this.password = originalConfig.getString(KeyConstant.MONGO_USER_PASSWORD); + String database = originalConfig.getString(KeyConstant.MONGO_DB_NAME); + if(!Strings.isNullOrEmpty(this.userName) && !Strings.isNullOrEmpty(this.password)) { + this.mongoClient = MongoUtil.initCredentialMongoClient(originalConfig,userName,password,database); + } else { + this.mongoClient = MongoUtil.initMongoClient(originalConfig); + } + } + + @Override + public void destroy() { + + } + } + + + public static class Task extends Reader.Task { + + private Configuration readerSliceConfig; + + private MongoClient mongoClient; + + private String userName = null; + private String password = null; + + private String database = null; + private String collection = null; + + private JSONArray mongodbColumnMeta = null; + private Long batchSize = null; + /** + * 用来控制每个task取值的offset + */ + private Long skipCount = null; + /** + * 每页数据的大小 + */ + private int pageSize = 1000; + + @Override + public void startRead(RecordSender recordSender) { + + if(batchSize == null || + mongoClient == null || database == null || + collection == null || mongodbColumnMeta == null) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE, + MongoDBReaderErrorCode.ILLEGAL_VALUE.getDescription()); + } + DB db = mongoClient.getDB(database); + DBCollection col = db.getCollection(this.collection); + DBObject obj = new BasicDBObject(); + obj.put(KeyConstant.MONGO_PRIMIARY_ID_META,1); + + long pageCount = batchSize / pageSize; + long modCount = batchSize % pageSize; + + for(int i = 0; i <= pageCount; i++) { + skipCount += i * pageSize; + if(modCount == 0 && i == pageCount) { + break; + } + if (i == pageCount) { + pageCount = modCount; + } + DBCursor dbCursor = col.find().sort(obj).skip(skipCount.intValue()).limit(pageSize); + while (dbCursor.hasNext()) { + DBObject item = dbCursor.next(); + Record record = recordSender.createRecord(); + Iterator columnItera = mongodbColumnMeta.iterator(); + while (columnItera.hasNext()) { + JSONObject column = (JSONObject)columnItera.next(); + Object tempCol = item.get(column.getString(KeyConstant.COLUMN_NAME)); + if (tempCol == null) { + continue; + } + if (tempCol instanceof Double) { + record.addColumn(new DoubleColumn((Double) tempCol)); + } else if (tempCol instanceof Boolean) { + record.addColumn(new BoolColumn((Boolean) tempCol)); + } else if (tempCol instanceof Date) { + record.addColumn(new DateColumn((Date) tempCol)); + } else if (tempCol instanceof Integer) { + record.addColumn(new LongColumn((Integer) tempCol)); + }else if (tempCol instanceof Long) { + record.addColumn(new LongColumn((Long) tempCol)); + } else { + if(KeyConstant.isArrayType(column.getString(KeyConstant.COLUMN_TYPE))) { + String splitter = column.getString(KeyConstant.COLUMN_SPLITTER); + if(Strings.isNullOrEmpty(splitter)) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE, + MongoDBReaderErrorCode.ILLEGAL_VALUE.getDescription()); + } else { + ArrayList array = (ArrayList)tempCol; + String tempArrayStr = Joiner.on(splitter).join(array); + record.addColumn(new StringColumn(tempArrayStr)); + } + } else { + record.addColumn(new StringColumn(tempCol.toString())); + } + } + } + recordSender.sendToWriter(record); + } + } + } + + @Override + public void init() { + this.readerSliceConfig = super.getPluginJobConf(); + this.userName = readerSliceConfig.getString(KeyConstant.MONGO_USER_NAME); + this.password = readerSliceConfig.getString(KeyConstant.MONGO_USER_PASSWORD); + this.database = readerSliceConfig.getString(KeyConstant.MONGO_DB_NAME); + if(!Strings.isNullOrEmpty(userName) && !Strings.isNullOrEmpty(password)) { + mongoClient = MongoUtil.initCredentialMongoClient(readerSliceConfig,userName,password,database); + } else { + mongoClient = MongoUtil.initMongoClient(readerSliceConfig); + } + + this.collection = readerSliceConfig.getString(KeyConstant.MONGO_COLLECTION_NAME); + this.mongodbColumnMeta = JSON.parseArray(readerSliceConfig.getString(KeyConstant.MONGO_COLUMN)); + this.batchSize = readerSliceConfig.getLong(KeyConstant.BATCH_SIZE); + this.skipCount = readerSliceConfig.getLong(KeyConstant.SKIP_COUNT); + } + + @Override + public void destroy() { + + } + } +} diff --git a/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReaderErrorCode.java b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReaderErrorCode.java new file mode 100644 index 000000000..4b3780c26 --- /dev/null +++ b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/MongoDBReaderErrorCode.java @@ -0,0 +1,33 @@ +package com.alibaba.datax.plugin.reader.mongodbreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * Created by jianying.wcj on 2015/3/19 0019. + */ +public enum MongoDBReaderErrorCode implements ErrorCode { + + ILLEGAL_VALUE("ILLEGAL_PARAMETER_VALUE","参数不合法"), + ILLEGAL_ADDRESS("ILLEGAL_ADDRESS","不合法的Mongo地址"), + UNEXCEPT_EXCEPTION("UNEXCEPT_EXCEPTION","未知异常"); + + private final String code; + + private final String description; + + private MongoDBReaderErrorCode(String code,String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getDescription() { + return description; + } +} + diff --git a/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/CollectionSplitUtil.java b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/CollectionSplitUtil.java new file mode 100644 index 000000000..3ff758ed9 --- /dev/null +++ b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/CollectionSplitUtil.java @@ -0,0 +1,77 @@ +package com.alibaba.datax.plugin.reader.mongodbreader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.mongodbreader.KeyConstant; +import com.alibaba.datax.plugin.reader.mongodbreader.MongoDBReaderErrorCode; +import com.google.common.base.Strings; +import com.mongodb.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jianying.wcj on 2015/3/19 0019. + */ +public class CollectionSplitUtil { + + public static List doSplit( + Configuration originalSliceConfig,int adviceNumber,MongoClient mongoClient) { + + List confList = new ArrayList(); + + String dbName = originalSliceConfig.getString(KeyConstant.MONGO_DB_NAME); + + String collectionName = originalSliceConfig.getString(KeyConstant.MONGO_COLLECTION_NAME); + + if(Strings.isNullOrEmpty(dbName) || Strings.isNullOrEmpty(collectionName) || mongoClient == null) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE, + MongoDBReaderErrorCode.ILLEGAL_VALUE.getDescription()); + } + + DB db = mongoClient.getDB(dbName); + DBCollection collection = db.getCollection(collectionName); + + List countInterval = doSplitInterval(adviceNumber,collection); + for(Entry interval : countInterval) { + Configuration conf = originalSliceConfig.clone(); + conf.set(KeyConstant.SKIP_COUNT,interval.interval); + conf.set(KeyConstant.BATCH_SIZE,interval.batchSize); + confList.add(conf); + } + return confList; + } + + private static List doSplitInterval(int adviceNumber,DBCollection collection) { + + List intervalCountList = new ArrayList(); + + long totalCount = collection.count(); + if(totalCount < 0) { + return intervalCountList; + } + // 100 6 => 16 mod 4 + long batchSize = totalCount/adviceNumber; + for(int i = 0; i < adviceNumber; i++) { + Entry entry = new Entry(); + /** + * 这个判断确认不会丢失最后一页数据, + * 因为 totalCount/adviceNumber 不整除时,如果不做判断会丢失最后一页 + */ + if(i == (adviceNumber - 1)) { + entry.batchSize = batchSize + adviceNumber; + } else { + entry.batchSize = batchSize; + } + entry.interval = batchSize * i; + intervalCountList.add(entry); + } + return intervalCountList; + } + +} + +class Entry { + Long interval; + Long batchSize; +} diff --git a/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/MongoUtil.java b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/MongoUtil.java new file mode 100644 index 000000000..51d4bea7a --- /dev/null +++ b/mongodbreader/src/main/java/com/alibaba/datax/plugin/reader/mongodbreader/util/MongoUtil.java @@ -0,0 +1,99 @@ +package com.alibaba.datax.plugin.reader.mongodbreader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.mongodbreader.KeyConstant; +import com.alibaba.datax.plugin.reader.mongodbreader.MongoDBReaderErrorCode; +import com.mongodb.MongoClient; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public class MongoUtil { + + public static MongoClient initMongoClient(Configuration conf) { + + List addressList = conf.getList(KeyConstant.MONGO_ADDRESS); + if(addressList == null || addressList.size() <= 0) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE,"不合法参数"); + } + try { + return new MongoClient(parseServerAddress(addressList)); + } catch (UnknownHostException e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_ADDRESS,"不合法的地址"); + } catch (NumberFormatException e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE,"不合法参数"); + } catch (Exception e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.UNEXCEPT_EXCEPTION,"未知异常"); + } + } + + public static MongoClient initCredentialMongoClient(Configuration conf,String userName,String password,String database) { + + List addressList = conf.getList(KeyConstant.MONGO_ADDRESS); + if(!isHostPortPattern(addressList)) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE,"不合法参数"); + } + try { + MongoCredential credential = MongoCredential.createCredential(userName, database, password.toCharArray()); + return new MongoClient(parseServerAddress(addressList), Arrays.asList(credential)); + + } catch (UnknownHostException e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_ADDRESS,"不合法的地址"); + } catch (NumberFormatException e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.ILLEGAL_VALUE,"不合法参数"); + } catch (Exception e) { + throw DataXException.asDataXException(MongoDBReaderErrorCode.UNEXCEPT_EXCEPTION,"未知异常"); + } + } + /** + * 判断地址类型是否符合要求 + * @param addressList + * @return + */ + private static boolean isHostPortPattern(List addressList) { + boolean isMatch = false; + for(Object address : addressList) { + String regex = "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+)"; + if(((String)address).matches(regex)) { + isMatch = true; + } + } + return isMatch; + } + /** + * 转换为mongo地址协议 + * @param rawAddressList + * @return + */ + private static List parseServerAddress(List rawAddressList) throws UnknownHostException{ + List addressList = new ArrayList(); + for(Object address : rawAddressList) { + String[] tempAddress = ((String)address).split(":"); + try { + ServerAddress sa = new ServerAddress(tempAddress[0],Integer.valueOf(tempAddress[1])); + addressList.add(sa); + } catch (Exception e) { + throw new UnknownHostException(); + } + } + return addressList; + } + + public static void main(String[] args) { + try { + ArrayList hostAddress = new ArrayList(); + hostAddress.add("127.0.0.1:27017"); + System.out.println(MongoUtil.isHostPortPattern(hostAddress)); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/mongodbreader/src/main/resources/plugin.json b/mongodbreader/src/main/resources/plugin.json new file mode 100644 index 000000000..1bb1d262d --- /dev/null +++ b/mongodbreader/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "mongodbreader", + "class": "com.alibaba.datax.plugin.reader.mongodbreader.MongoDBReader", + "description": "useScene: prod. mechanism: via mongoclient connect mongodb reader data concurrent.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/mongodbreader/src/main/resources/plugin_job_template.json b/mongodbreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..367936139 --- /dev/null +++ b/mongodbreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,11 @@ +{ + "name": "mongodbreader", + "parameter": { + "address": [], + "userName": "", + "userPassword": "", + "dbName": "", + "collectionName": "", + "column": [] + } +} \ No newline at end of file diff --git a/mongodbwriter/doc/mongodbwriter.md b/mongodbwriter/doc/mongodbwriter.md new file mode 100644 index 000000000..0e5b79524 --- /dev/null +++ b/mongodbwriter/doc/mongodbwriter.md @@ -0,0 +1,157 @@ +### Datax MongoDBWriter +#### 1 快速介绍 + +MongoDBWriter 插件利用 MongoDB 的java客户端MongoClient进行MongoDB的写操作。最新版本的Mongo已经将DB锁的粒度从DB级别降低到document级别,配合上MongoDB强大的索引功能,基本可以满足数据源向MongoDB写入数据的需求,针对数据更新的需求,通过配置业务主键的方式也可以实现。 + +#### 2 实现原理 + +MongoDBWriter通过Datax框架获取Reader生成的数据,然后将Datax支持的类型通过逐一判断转换成MongoDB支持的类型。其中一个值得指出的点就是Datax本身不支持数组类型,但是MongoDB支持数组类型,并且数组类型的索引还是蛮强大的。为了使用MongoDB的数组类型,则可以通过参数的特殊配置,将字符串可以转换成MongoDB中的数组。类型转换之后,就可以依托于Datax框架并行的写入MongoDB。 + +#### 3 功能说明 +* 该示例从ODPS读一份数据到MongoDB。 + + { + "job": { + "setting": { + "speed": { + "channel": 2 + } + }, + "content": [ + { + "reader": { + "name": "odpsreader", + "parameter": { + "accessId": "********", + "accessKey": "*********", + "project": "tb_ai_recommendation", + "table": "jianying_tag_datax_test", + "column": [ + "unique_id", + "sid", + "user_id", + "auction_id", + "content_type", + "pool_type", + "frontcat_id", + "categoryid", + "gmt_create", + "taglist", + "property", + "scorea", + "scoreb" + ], + "splitMode": "record", + "odpsServer": "http://service-corp.odps.aliyun-inc.com/api" + } + }, + "writer": { + "name": "mongodbwriter", + "parameter": { + "address": [ + "127.0.0.1:27017" + ], + "userName": "", + "userPassword": "", + "dbName": "tag_per_data", + "collectionName": "tag_data", + "column": [ + { + "name": "unique_id", + "type": "string" + }, + { + "name": "sid", + "type": "string" + }, + { + "name": "user_id", + "type": "string" + }, + { + "name": "auction_id", + "type": "string" + }, + { + "name": "content_type", + "type": "string" + }, + { + "name": "pool_type", + "type": "string" + }, + { + "name": "frontcat_id", + "type": "Array", + "splitter": " " + }, + { + "name": "categoryid", + "type": "Array", + "splitter": " " + }, + { + "name": "gmt_create", + "type": "string" + }, + { + "name": "taglist", + "type": "Array", + "splitter": " " + }, + { + "name": "property", + "type": "string" + }, + { + "name": "scorea", + "type": "int" + }, + { + "name": "scoreb", + "type": "int" + }, + { + "name": "scorec", + "type": "int" + } + ], + "upsertInfo": { + "isUpsert": "true", + "upsertKey": "unique_id" + } + } + } + } + ] + } + } + +#### 4 参数说明 + +* address: MongoDB的数据地址信息,因为MonogDB可能是个集群,则ip端口信息需要以Json数组的形式给出。【必填】 +* userName:MongoDB的用户名。【选填】 +* userPassword: MongoDB的密码。【选填】 +* collectionName: MonogoDB的集合名。【必填】 +* column:MongoDB的文档列名。【必填】 +* name:Column的名字。【必填】 +* type:Column的类型。【选填】 +* splitter:特殊分隔符,当且仅当要处理的字符串要用分隔符分隔为字符数组时,才使用这个参数,通过这个参数指定的分隔符,将字符串分隔存储到MongoDB的数组中。【选填】 +* upsertInfo:指定了传输数据时更新的信息。【选填】 +* isUpsert:当设置为true时,表示针对相同的upsertKey做更新操作。【选填】 +* upsertKey:upsertKey指定了没行记录的业务主键。用来做更新时使用。【选填】 + +#### 5 类型转换 + +| DataX 内部类型| MongoDB 数据类型 | +| -------- | ----- | +| Long | int, Long | +| Double | double | +| String | string, array | +| Date | date | +| Boolean | boolean | +| Bytes | bytes | + + +#### 6 性能报告 +#### 7 测试报告 \ No newline at end of file diff --git a/mongodbwriter/mongodbwriter.iml b/mongodbwriter/mongodbwriter.iml new file mode 100644 index 000000000..1bc9c81c6 --- /dev/null +++ b/mongodbwriter/mongodbwriter.iml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mongodbwriter/pom.xml b/mongodbwriter/pom.xml new file mode 100644 index 000000000..0504f1373 --- /dev/null +++ b/mongodbwriter/pom.xml @@ -0,0 +1,92 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + mongodbwriter + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + com.alibaba.datax + plugin-unstructured-storage-util + ${datax-project-version} + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + com.google.guava + guava + + + + org.mongodb + mongo-java-driver + 3.0.3 + + + com.google.guava + guava + 16.0.1 + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/mongodbwriter/src/main/assembly/package.xml b/mongodbwriter/src/main/assembly/package.xml new file mode 100644 index 000000000..9225be35e --- /dev/null +++ b/mongodbwriter/src/main/assembly/package.xml @@ -0,0 +1,36 @@ + + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/mongodbwriter + + + target/ + + mongodbwriter-0.0.1-SNAPSHOT.jar + + plugin/writer/mongodbwriter + + + + + + false + plugin/writer/mongodbwriter/libs + runtime + + + diff --git a/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/KeyConstant.java b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/KeyConstant.java new file mode 100644 index 000000000..8207d7212 --- /dev/null +++ b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/KeyConstant.java @@ -0,0 +1,79 @@ +package com.alibaba.datax.plugin.writer.mongodbwriter; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public class KeyConstant { + /** + * mongodb 的 host 地址 + */ + public static final String MONGO_ADDRESS = "address"; + /** + * 数组类型 + */ + public static final String ARRAY_TYPE = "array"; + /** + * mongodb 的用户名 + */ + public static final String MONGO_USER_NAME = "userName"; + /** + * mongodb 密码 + */ + public static final String MONGO_USER_PASSWORD = "userPassword"; + /** + * mongodb 数据库名 + */ + public static final String MONGO_DB_NAME = "dbName"; + /** + * mongodb 集合名 + */ + public static final String MONGO_COLLECTION_NAME = "collectionName"; + /** + * mongodb 的列 + */ + public static final String MONGO_COLUMN = "column"; + /** + * 每个列的名字 + */ + public static final String COLUMN_NAME = "name"; + /** + * 每个列的类型 + */ + public static final String COLUMN_TYPE = "type"; + /** + * 数组中每个元素的类型 + */ + public static final String ITEM_TYPE = "itemtype"; + /** + * 列分隔符 + */ + public static final String COLUMN_SPLITTER = "splitter"; + /** + * 数据更新列信息 + */ + public static final String UPSERT_INFO = "upsertInfo"; + /** + * 有相同的记录是否覆盖,默认为false + */ + public static final String IS_UPSERT = "isUpsert"; + /** + * 指定用来判断是否覆盖的 业务主键 + */ + public static final String UNIQUE_KEY = "upsertKey"; + /** + * 判断是否为数组类型 + * @param type 数据类型 + * @return + */ + public static boolean isArrayType(String type) { + return ARRAY_TYPE.equals(type); + } + /** + * 判断一个值是否为true + * @param value + * @return + */ + public static boolean isValueTrue(String value){ + return "true".equals(value); + } +} diff --git a/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriter.java b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriter.java new file mode 100644 index 000000000..692d9a522 --- /dev/null +++ b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriter.java @@ -0,0 +1,309 @@ +package com.alibaba.datax.plugin.writer.mongodbwriter; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.writer.Key; +import com.alibaba.datax.plugin.writer.mongodbwriter.util.MongoUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Strings; +import com.mongodb.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public class MongoDBWriter extends Writer{ + + public static class Job extends Writer.Job { + + private Configuration originalConfig = null; + + @Override + public List split(int mandatoryNumber) { + List configList = new ArrayList(); + for(int i = 0; i < mandatoryNumber; i++) { + configList.add(this.originalConfig.clone()); + } + return configList; + } + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + } + + @Override + public void prepare() { + super.prepare(); + } + + @Override + public void destroy() { + + } + } + + public static class Task extends Writer.Task { + + private static final Logger logger = LoggerFactory.getLogger(Task.class); + private Configuration writerSliceConfig; + private MongoClient mongoClient; + + private String userName = null; + private String password = null; + + private String database = null; + private String collection = null; + private Integer batchSize = null; + private JSONArray mongodbColumnMeta = null; + private JSONObject upsertInfoMeta = null; + private static int BATCH_SIZE = 1000; + + @Override + public void prepare() { + super.prepare(); + //获取presql配置,并执行 + String preSql = writerSliceConfig.getString(Key.PRE_SQL); + if(Strings.isNullOrEmpty(preSql)) { + return; + } + Configuration conConf = Configuration.from(preSql); + if(Strings.isNullOrEmpty(database) || Strings.isNullOrEmpty(collection) + || mongoClient == null || mongodbColumnMeta == null || batchSize == null) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE, + MongoDBWriterErrorCode.ILLEGAL_VALUE.getDescription()); + } + DB db = mongoClient.getDB(database); + DBCollection col = db.getCollection(this.collection); + String type = conConf.getString("type"); + if (Strings.isNullOrEmpty(type)){ + return; + } + if (type.equals("drop")){ + col.drop(); + } else if (type.equals("remove")){ + String json = conConf.getString("json"); + BasicDBObject query; + if (Strings.isNullOrEmpty(json)) { + query = new BasicDBObject(); + List items = conConf.getList("item", Object.class); + for (Object con : items) { + Configuration _conf = Configuration.from(con.toString()); + if (Strings.isNullOrEmpty(_conf.getString("condition"))) { + query.put(_conf.getString("name"), _conf.get("value")); + } else { + query.put(_conf.getString("name"), + new BasicDBObject(_conf.getString("condition"), _conf.get("value"))); + } + } +// and { "pv" : { "$gt" : 200 , "$lt" : 3000} , "pid" : { "$ne" : "xxx"}} +// or { "$or" : [ { "age" : { "$gt" : 27}} , { "age" : { "$lt" : 15}}]} + } else { + query = (BasicDBObject) com.mongodb.util.JSON.parse(json); + } + col.remove(query); + } + if(logger.isDebugEnabled()) { + logger.debug("After job prepare(), originalConfig now is:[\n{}\n]", writerSliceConfig.toJSON()); + } + } + + @Override + public void startWrite(RecordReceiver lineReceiver) { + if(Strings.isNullOrEmpty(database) || Strings.isNullOrEmpty(collection) + || mongoClient == null || mongodbColumnMeta == null || batchSize == null) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE, + MongoDBWriterErrorCode.ILLEGAL_VALUE.getDescription()); + } + DB db = mongoClient.getDB(database); + DBCollection col = db.getCollection(this.collection); + List writerBuffer = new ArrayList(this.batchSize); + Record record = null; + while((record = lineReceiver.getFromReader()) != null) { + writerBuffer.add(record); + if(writerBuffer.size() >= this.batchSize) { + doBatchInsert(col,writerBuffer,mongodbColumnMeta); + writerBuffer.clear(); + } + } + if(!writerBuffer.isEmpty()) { + doBatchInsert(col,writerBuffer,mongodbColumnMeta); + writerBuffer.clear(); + } + } + + private void doBatchInsert(DBCollection collection,List writerBuffer, JSONArray columnMeta) { + + List dataList = new ArrayList(); + + for(Record record : writerBuffer) { + + BasicDBObject data = new BasicDBObject(); + + for(int i = 0; i < record.getColumnNumber(); i++) { + + String type = columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_TYPE); + if (Strings.isNullOrEmpty(record.getColumn(i).asString())) { + if (KeyConstant.isArrayType(type.toLowerCase())) { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), new Object[0]); + } else { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), record.getColumn(i).asString()); + } + continue; + } + if (Column.Type.INT.name().equalsIgnoreCase(type)){ + //配置文件中的type是没有用的,除了int,其他均按照保存时Column的类型进行处理 + try { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), + Integer.parseInt(String.valueOf(record.getColumn(i).getRawData()))); + } catch (Exception e) { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asString()); + e.printStackTrace(); + } + } else if(record.getColumn(i) instanceof StringColumn){ + //处理数组类型 + try { + if(KeyConstant.isArrayType(type.toLowerCase())) { + String splitter = columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_SPLITTER); + if (Strings.isNullOrEmpty(splitter)) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE, + MongoDBWriterErrorCode.ILLEGAL_VALUE.getDescription()); + } + String itemType = columnMeta.getJSONObject(i).getString(KeyConstant.ITEM_TYPE); + if (itemType != null && !itemType.isEmpty()) { + //如果数组指定类型不为空,将其转换为指定类型 + String[] item = record.getColumn(i).asString().split(splitter); + if (itemType.equalsIgnoreCase(Column.Type.DOUBLE.name())) { + ArrayList list = new ArrayList(); + for (String s : item) { + list.add(Double.parseDouble(s)); + } + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), list.toArray(new Double[0])); + } else if (itemType.equalsIgnoreCase(Column.Type.INT.name())) { + ArrayList list = new ArrayList(); + for (String s : item) { + list.add(Integer.parseInt(s)); + } + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), list.toArray(new Integer[0])); + } else if (itemType.equalsIgnoreCase(Column.Type.LONG.name())) { + ArrayList list = new ArrayList(); + for (String s : item) { + list.add(Long.parseLong(s)); + } + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), list.toArray(new Long[0])); + } else if (itemType.equalsIgnoreCase(Column.Type.BOOL.name())) { + ArrayList list = new ArrayList(); + for (String s : item) { + list.add(Boolean.parseBoolean(s)); + } + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), list.toArray(new Boolean[0])); + } else if (itemType.equalsIgnoreCase(Column.Type.BYTES.name())) { + ArrayList list = new ArrayList(); + for (String s : item) { + list.add(Byte.parseByte(s)); + } + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), list.toArray(new Byte[0])); + } else { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), record.getColumn(i).asString().split(splitter)); + } + } else { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), record.getColumn(i).asString().split(splitter)); + } + } else if(type.toLowerCase().equalsIgnoreCase("json")) { + //如果是json类型,将其进行转换 + Object mode = com.mongodb.util.JSON.parse(record.getColumn(i).asString()); + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),JSON.toJSON(mode)); + } else { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), record.getColumn(i).asString()); + } + } catch (Exception e) { + e.printStackTrace(); + //发生异常就按照默认类型存数 + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME), record.getColumn(i).asString()); + } + } else if(record.getColumn(i) instanceof LongColumn) { + + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asLong()); + + } else if(record.getColumn(i) instanceof DateColumn) { + + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asDate()); + + } else if(record.getColumn(i) instanceof DoubleColumn) { + + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asDouble()); + + } else if(record.getColumn(i) instanceof BoolColumn) { + + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asBoolean()); + + } else if(record.getColumn(i) instanceof BytesColumn) { + + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asBytes()); + + } else { + data.put(columnMeta.getJSONObject(i).getString(KeyConstant.COLUMN_NAME),record.getColumn(i).asString()); + } + } + dataList.add(data); + } + /** + * 如果存在重复的值覆盖 + */ + if(this.upsertInfoMeta != null && + this.upsertInfoMeta.getString(KeyConstant.IS_UPSERT) != null && + KeyConstant.isValueTrue(this.upsertInfoMeta.getString(KeyConstant.IS_UPSERT))) { + BulkWriteOperation bulkUpsert = collection.initializeUnorderedBulkOperation(); + String uniqueKey = this.upsertInfoMeta.getString(KeyConstant.UNIQUE_KEY); + if(!Strings.isNullOrEmpty(uniqueKey)) { + for(DBObject data : dataList) { + BasicDBObject query = new BasicDBObject(); + if(uniqueKey != null) { + query.put(uniqueKey,data.get(uniqueKey)); + } + bulkUpsert.find(query).upsert().replaceOne(data); + } + bulkUpsert.execute(); + } else { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE, + MongoDBWriterErrorCode.ILLEGAL_VALUE.getDescription()); + } + } else { + collection.insert(dataList); + } + } + + + @Override + public void init() { + this.writerSliceConfig = this.getPluginJobConf(); + this.userName = writerSliceConfig.getString(KeyConstant.MONGO_USER_NAME); + this.password = writerSliceConfig.getString(KeyConstant.MONGO_USER_PASSWORD); + this.database = writerSliceConfig.getString(KeyConstant.MONGO_DB_NAME); + if(!Strings.isNullOrEmpty(userName) && !Strings.isNullOrEmpty(password)) { + this.mongoClient = MongoUtil.initCredentialMongoClient(this.writerSliceConfig,userName,password,database); + } else { + this.mongoClient = MongoUtil.initMongoClient(this.writerSliceConfig); + } + this.collection = writerSliceConfig.getString(KeyConstant.MONGO_COLLECTION_NAME); + this.batchSize = BATCH_SIZE; + this.mongodbColumnMeta = JSON.parseArray(writerSliceConfig.getString(KeyConstant.MONGO_COLUMN)); + this.upsertInfoMeta = JSON.parseObject(writerSliceConfig.getString(KeyConstant.UPSERT_INFO)); + } + + @Override + public void destroy() { + mongoClient.close(); + } + } + +} diff --git a/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriterErrorCode.java b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriterErrorCode.java new file mode 100644 index 000000000..b3a19e4a3 --- /dev/null +++ b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/MongoDBWriterErrorCode.java @@ -0,0 +1,33 @@ +package com.alibaba.datax.plugin.writer.mongodbwriter; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public enum MongoDBWriterErrorCode implements ErrorCode { + + ILLEGAL_VALUE("ILLEGAL_PARAMETER_VALUE","参数不合法"), + ILLEGAL_ADDRESS("ILLEGAL_ADDRESS","不合法的Mongo地址"), + JSONCAST_EXCEPTION("JSONCAST_EXCEPTION","json类型转换异常"), + UNEXCEPT_EXCEPTION("UNEXCEPT_EXCEPTION","未知异常"); + + private final String code; + + private final String description; + + private MongoDBWriterErrorCode(String code,String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/util/MongoUtil.java b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/util/MongoUtil.java new file mode 100644 index 000000000..726bd1fed --- /dev/null +++ b/mongodbwriter/src/main/java/com/alibaba/datax/plugin/writer/mongodbwriter/util/MongoUtil.java @@ -0,0 +1,103 @@ +package com.alibaba.datax.plugin.writer.mongodbwriter.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.writer.mongodbwriter.KeyConstant; +import com.alibaba.datax.plugin.writer.mongodbwriter.MongoDBWriterErrorCode; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.mongodb.MongoClient; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * Created by jianying.wcj on 2015/3/17 0017. + */ +public class MongoUtil { + + public static MongoClient initMongoClient(Configuration conf) { + + List addressList = conf.getList(KeyConstant.MONGO_ADDRESS); + if(addressList == null || addressList.size() <= 0) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE,"不合法参数"); + } + try { + return new MongoClient(parseServerAddress(addressList)); + } catch (UnknownHostException e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_ADDRESS,"不合法的地址"); + } catch (NumberFormatException e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE,"不合法参数"); + } catch (Exception e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.UNEXCEPT_EXCEPTION,"未知异常"); + } + } + + public static MongoClient initCredentialMongoClient(Configuration conf,String userName,String password,String database) { + + List addressList = conf.getList(KeyConstant.MONGO_ADDRESS); + if(!isHostPortPattern(addressList)) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE,"不合法参数"); + } + try { + MongoCredential credential = MongoCredential.createCredential(userName, database, password.toCharArray()); + return new MongoClient(parseServerAddress(addressList), Arrays.asList(credential)); + + } catch (UnknownHostException e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_ADDRESS,"不合法的地址"); + } catch (NumberFormatException e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.ILLEGAL_VALUE,"不合法参数"); + } catch (Exception e) { + throw DataXException.asDataXException(MongoDBWriterErrorCode.UNEXCEPT_EXCEPTION,"未知异常"); + } + } + /** + * 判断地址类型是否符合要求 + * @param addressList + * @return + */ + private static boolean isHostPortPattern(List addressList) { + boolean isMatch = false; + for(Object address : addressList) { + String regex = "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+)"; + if(((String)address).matches(regex)) { + isMatch = true; + } + } + return isMatch; + } + /** + * 转换为mongo地址协议 + * @param rawAddressList + * @return + */ + private static List parseServerAddress(List rawAddressList) throws UnknownHostException{ + List addressList = new ArrayList(); + for(Object address : rawAddressList) { + String[] tempAddress = ((String)address).split(":"); + try { + ServerAddress sa = new ServerAddress(tempAddress[0],Integer.valueOf(tempAddress[1])); + addressList.add(sa); + } catch (Exception e) { + throw new UnknownHostException(); + } + } + return addressList; + } + + public static void main(String[] args) { + try { + ArrayList hostAddress = new ArrayList(); + hostAddress.add("127.0.0.1:27017"); + System.out.println(MongoUtil.isHostPortPattern(hostAddress)); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/mongodbwriter/src/main/resources/plugin.json b/mongodbwriter/src/main/resources/plugin.json new file mode 100644 index 000000000..daed8c2f1 --- /dev/null +++ b/mongodbwriter/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "mongodbwriter", + "class": "com.alibaba.datax.plugin.writer.mongodbwriter.MongoDBWriter", + "description": "useScene: prod. mechanism: via mongoclient connect mongodb write data concurrent.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/mongodbwriter/src/main/resources/plugin_job_template.json b/mongodbwriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..d4ba4bf1f --- /dev/null +++ b/mongodbwriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,15 @@ +{ + "name": "mongodbwriter", + "parameter": { + "address": [], + "userName": "", + "userPassword": "", + "dbName": "", + "collectionName": "", + "column": [], + "upsertInfo": { + "isUpsert": "", + "upsertKey": "" + } + } +} \ No newline at end of file diff --git a/mysqlreader/doc/mysqlreader.md b/mysqlreader/doc/mysqlreader.md new file mode 100644 index 000000000..f2618554e --- /dev/null +++ b/mysqlreader/doc/mysqlreader.md @@ -0,0 +1,377 @@ + +# MysqlReader 插件文档 + + +___ + + + +## 1 快速介绍 + +MysqlReader插件实现了从Mysql读取数据。在底层实现上,MysqlReader通过JDBC连接远程Mysql数据库,并执行相应的sql语句将数据从mysql库中SELECT出来。 + +**不同于其他关系型数据库,MysqlReader不支持FetchSize.** + +## 2 实现原理 + +简而言之,MysqlReader通过JDBC连接器连接到远程的Mysql数据库,并根据用户配置的信息生成查询SELECT SQL语句,然后发送到远程Mysql数据库,并将该SQL执行返回结果使用DataX自定义的数据类型拼装为抽象的数据集,并传递给下游Writer处理。 + +对于用户配置Table、Column、Where的信息,MysqlReader将其拼接为SQL语句发送到Mysql数据库;对于用户配置querySql信息,MysqlReader直接将其发送到Mysql数据库。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 配置一个从Mysql数据库同步抽取数据到本地的作业: + +``` +{ + "job": { + "setting": { + "speed": { + //设置传输速度,单位为byte/s,DataX运行会尽可能达到该速度但是不超过它. + "byte": 1048576 + } + //出错限制 + "errorLimit": { + //出错的record条数上限,当大于该值即报错。 + "record": 0, + //出错的record百分比上限 1.0表示100%,0.02表示2% + "percentage": 0.02 + } + }, + "content": [ + { + "reader": { + "name": "mysqlreader", + "parameter": { + // 数据库连接用户名 + "username": "root", + // 数据库连接密码 + "password": "root", + "checkSlave":true, + "column": [ + "id","name" + ], + //切分主键 + "splitPk": "db_id", + "connection": [ + { + "table": [ + "table" + ], + "jdbcUrl": [ + "jdbc:mysql://127.0.0.1:3306/database" + ] + } + ] + } + }, + "writer": { + //writer类型 + "name": "streamwriter", + //是否打印内容 + "parameter": { + "print":true, + } + } + } + ] + } +} + +``` + +* 配置一个自定义SQL的数据库同步任务到本地内容的作业: + +``` +{ + "job": { + "setting": { + "speed": { + "channel":1 + } + }, + "content": [ + { + "reader": { + "name": "mysqlreader", + "parameter": { + "username": "root", + "password": "root", + "connection": [ + { + "querySql": [ + "select db_id,on_line_flag from db_info where db_id < 10;" + ], + "jdbcUrl": [ + "jdbc:mysql://bad_ip:3306/database", + "jdbc:mysql://127.0.0.1:bad_port/database", + "jdbc:mysql://127.0.0.1:3306/database" + ] + } + ] + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": false, + "encoding": "UTF-8" + } + } + } + ] + } +} +``` + + +### 3.2 参数说明 + +* **jdbcUrl** + + * 描述:描述的是到对端数据库的JDBC连接信息,使用JSON的数组描述,并支持一个库填写多个连接地址。之所以使用JSON数组描述连接信息,是因为阿里集团内部支持多个IP探测,如果配置了多个,MysqlReader可以依次探测ip的可连接性,直到选择一个合法的IP。如果全部连接失败,MysqlReader报错。 注意,jdbcUrl必须包含在connection配置单元中。对于阿里集团外部使用情况,JSON数组填写一个JDBC连接即可。 + + jdbcUrl按照Mysql官方规范,并可以填写连接附件控制信息。具体请参看[Mysql官方文档](http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html)。 + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:数据源的用户名
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:数据源指定用户名的密码
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:所选取的需要同步的表。使用JSON的数组描述,因此支持多张表同时抽取。当配置为多张表时,用户自己需保证多张表是同一schema结构,MysqlReader不予检查表是否同一逻辑表。注意,table必须包含在connection配置单元中。
+ + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:所配置的表中需要同步的列名集合,使用JSON的数组描述字段信息。用户使用*代表默认使用所有列配置,例如['*']。 + + 支持列裁剪,即列可以挑选部分列进行导出。 + + 支持列换序,即列可以不按照表schema信息进行导出。 + + 支持常量配置,用户需要按照Mysql SQL语法格式: + ["id", "\`table\`", "1", "'bazhen.csy'", "null", "to_char(a + 1)", "2.3" , "true"] + id为普通列名,\`table\`为包含保留在的列名,1为整形数字常量,'bazhen.csy'为字符串常量,null为空指针,to_char(a + 1)为表达式,2.3为浮点数,true为布尔值。 + + * 必选:是
+ + * 默认值:无
+ +* **splitPk** + + * 描述:MysqlReader进行数据抽取时,如果指定splitPk,表示用户希望使用splitPk代表的字段进行数据分片,DataX因此会启动并发任务进行数据同步,这样可以大大提供数据同步的效能。 + + 推荐splitPk用户使用表主键,因为表主键通常情况下比较均匀,因此切分出来的分片也不容易出现数据热点。 + + 目前splitPk仅支持整形、字符串型数据切分,`不支持浮点、日期等其他类型`。如果用户指定其他非支持类型,MysqlReader将报错! + + 如果splitPk不填写,包括不提供splitPk或者splitPk值为空,DataX视作使用单通道同步该表数据。 + + * 必选:否
+ + * 默认值:空
+ +* **where** + + * 描述:筛选条件,MysqlReader根据指定的column、table、where条件拼接SQL,并根据这个SQL进行数据抽取。例如在做测试时,可以将where条件指定为limit 10;在实际业务场景中,往往会选择当天的数据进行同步,可以将where条件指定为gmt_create > $bizdate 。
。 + + where条件可以有效地进行业务增量同步。如果不填写where语句,包括不提供where的key或者value,DataX均视作同步全量数据。 + + * 必选:否
+ + * 默认值:无
+ +* **querySql** + + * 描述:在有些业务场景下,where这一配置项不足以描述所筛选的条件,用户可以通过该配置型来自定义筛选SQL。当用户配置了这一项之后,DataX系统就会忽略table,column这些配置型,直接使用这个配置项的内容对数据进行筛选,例如需要进行多表join后同步数据,使用select a,b from table_a join table_b on table_a.id = table_b.id
+ + `当用户配置querySql时,MysqlReader直接忽略table、column、where条件的配置`,querySql优先级大于table、column、where选项。 + + * 必选:否
+ + * 默认值:无
+ + +### 3.3 类型转换 + +目前MysqlReader支持大部分Mysql类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出MysqlReader针对Mysql类型转换列表: + + +| DataX 内部类型| Mysql 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, mediumint, int, bigint| +| Double |float, double, decimal| +| String |varchar, char, tinytext, text, mediumtext, longtext, year | +| Date |date, datetime, timestamp, time | +| Boolean |bit, bool | +| Bytes |tinyblob, mediumblob, blob, longblob, varbinary | + + + +请注意: + +* `除上述罗列字段类型外,其他类型均不支持`。 +* `tinyint(1) DataX视作为整形`。 +* `year DataX视作为字符串类型` +* `bit DataX属于未定义行为`。 + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 +建表语句: + + CREATE TABLE `tc_biz_vertical_test_0000` ( + `biz_order_id` bigint(20) NOT NULL COMMENT 'id', + `key_value` varchar(4000) NOT NULL COMMENT 'Key-value的内容', + `gmt_create` datetime NOT NULL COMMENT '创建时间', + `gmt_modified` datetime NOT NULL COMMENT '修改时间', + `attribute_cc` int(11) DEFAULT NULL COMMENT '防止并发修改的标志', + `value_type` int(11) NOT NULL DEFAULT '0' COMMENT '类型', + `buyer_id` bigint(20) DEFAULT NULL COMMENT 'buyerid', + `seller_id` bigint(20) DEFAULT NULL COMMENT 'seller_id', + PRIMARY KEY (`biz_order_id`,`value_type`), + KEY `idx_biz_vertical_gmtmodified` (`gmt_modified`) + ) ENGINE=InnoDB DEFAULT CHARSET=gbk COMMENT='tc_biz_vertical' + + +单行记录类似于: + + biz_order_id: 888888888 + key_value: ;orderIds:20148888888,2014888888813800; + gmt_create: 2011-09-24 11:07:20 + gmt_modified: 2011-10-24 17:56:34 + attribute_cc: 1 + value_type: 3 + buyer_id: 8888888 + seller_id: 1 + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu: 24核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz + 2. mem: 48GB + 3. net: 千兆双网卡 + 4. disc: DataX 数据不落磁盘,不统计此项 + +* Mysql数据库机器参数为: + 1. cpu: 32核 Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz + 2. mem: 256GB + 3. net: 千兆双网卡 + 4. disc: BTWL419303E2800RGN INTEL SSDSC2BB800G4 D2010370 + +#### 4.1.3 DataX jvm 参数 + + -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + + +### 4.2 测试报告 + +#### 4.2.1 单表测试报告 + + +| 通道数| 是否按照主键切分| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡进入流量(MB/s)|DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------|--------| --------|--------|--------|--------|--------|--------| +|1| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|1| 是 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|4| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|4| 是 | 329733 | 32.60 | 58| 0.8 | 60| 0.76 | +|8| 否 | 183185 | 18.11 | 29| 0.6 | 31| 0.6 | +|8| 是 | 549556 | 54.33 | 115| 1.46 | 120| 0.78 | + +说明: + +1. 这里的单表,主键类型为 bigint(20),范围为:190247559466810-570722244711460,从主键范围划分看,数据分布均匀。 +2. 对单表如果没有安装主键切分,那么配置通道个数不会提升速度,效果与1个通道一样。 + + +#### 4.2.2 分表测试报告(2个分库,每个分库16张分表,共计32张分表) + + +| 通道数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡进入流量(MB/s)|DataX机器运行负载|DB网卡流出流量(MB/s)|DB运行负载| +|--------| --------|--------|--------|--------|--------|--------| +|1| 202241 | 20.06 | 31.5| 1.0 | 32 | 1.1 | +|4| 726358 | 72.04 | 123.9 | 3.1 | 132 | 3.6 | +|8|1074405 | 106.56| 197 | 5.5 | 205| 5.1| +|16| 1227892 | 121.79 | 229.2 | 8.1 | 233 | 7.3 | + +## 5 约束限制 + +### 5.1 主备同步数据恢复问题 + +主备同步问题指Mysql使用主从灾备,备库从主库不间断通过binlog恢复数据。由于主备数据同步存在一定的时间差,特别在于某些特定情况,例如网络延迟等问题,导致备库同步恢复的数据与主库有较大差别,导致从备库同步的数据不是一份当前时间的完整镜像。 + +针对这个问题,我们提供了preSql功能,该功能待补充。 + +### 5.2 一致性约束 + +Mysql在数据存储划分中属于RDBMS系统,对外可以提供强一致性数据查询接口。例如当一次同步任务启动运行过程中,当该库存在其他数据写入方写入数据时,MysqlReader完全不会获取到写入更新数据,这是由于数据库本身的快照特性决定的。关于数据库快照特性,请参看[MVCC Wikipedia](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) + +上述是在MysqlReader单线程模型下数据同步一致性的特性,由于MysqlReader可以根据用户配置信息使用了并发数据抽取,因此不能严格保证数据一致性:当MysqlReader根据splitPk进行数据切分后,会先后启动多个并发任务完成数据同步。由于多个并发任务相互之间不属于同一个读事务,同时多个并发任务存在时间间隔。因此这份数据并不是`完整的`、`一致的`数据快照信息。 + +针对多线程的一致性快照需求,在技术上目前无法实现,只能从工程角度解决,工程化的方式存在取舍,我们提供几个解决思路给用户,用户可以自行选择: + +1. 使用单线程同步,即不再进行数据切片。缺点是速度比较慢,但是能够很好保证一致性。 + +2. 关闭其他数据写入方,保证当前数据为静态数据,例如,锁表、关闭备库同步等等。缺点是可能影响在线业务。 + +### 5.3 数据库编码问题 + +Mysql本身的编码设置非常灵活,包括指定编码到库、表、字段级别,甚至可以均不同编码。优先级从高到低为字段、表、库、实例。我们不推荐数据库用户设置如此混乱的编码,最好在库级别就统一到UTF-8。 + +MysqlReader底层使用JDBC进行数据抽取,JDBC天然适配各类编码,并在底层进行了编码转换。因此MysqlReader不需用户指定编码,可以自动获取编码并转码。 + +对于Mysql底层写入编码和其设定的编码不一致的混乱情况,MysqlReader对此无法识别,对此也无法提供解决方案,对于这类情况,`导出有可能为乱码`。 + +### 5.4 增量数据同步 + +MysqlReader使用JDBC SELECT语句完成数据抽取工作,因此可以使用SELECT...WHERE...进行增量数据抽取,方式有多种: + +* 数据库在线应用写入数据库时,填充modify字段为更改时间戳,包括新增、更新、删除(逻辑删)。对于这类应用,MysqlReader只需要WHERE条件跟上一同步阶段时间戳即可。 +* 对于新增流水型数据,MysqlReader可以WHERE条件后跟上一阶段最大自增ID即可。 + +对于业务上无字段区分新增、修改数据情况,MysqlReader也无法进行增量数据同步,只能同步全量数据。 + +### 5.5 Sql安全性 + +MysqlReader提供querySql语句交给用户自己实现SELECT抽取语句,MysqlReader本身对querySql不做任何安全性校验。这块交由DataX用户方自己保证。 + +## 6 FAQ + +*** + +**Q: MysqlReader同步报错,报错信息为XXX** + + A: 网络或者权限问题,请使用mysql命令行测试: + + mysql -u -p -h -D -e "select * from <表名>" + +如果上述命令也报错,那可以证实是环境问题,请联系你的DBA。 + + diff --git a/mysqlreader/mysqlreader.iml b/mysqlreader/mysqlreader.iml new file mode 100644 index 000000000..1f713bbe7 --- /dev/null +++ b/mysqlreader/mysqlreader.iml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mysqlreader/pom.xml b/mysqlreader/pom.xml new file mode 100755 index 000000000..fe74d9776 --- /dev/null +++ b/mysqlreader/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + mysqlreader + mysqlreader + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + mysql + mysql-connector-java + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/mysqlreader/src/main/assembly/package.xml b/mysqlreader/src/main/assembly/package.xml new file mode 100755 index 000000000..3b35d9381 --- /dev/null +++ b/mysqlreader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/mysqlreader + + + target/ + + mysqlreader-0.0.1-SNAPSHOT.jar + + plugin/reader/mysqlreader + + + + + + false + plugin/reader/mysqlreader/libs + runtime + + + diff --git a/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReader.java b/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReader.java new file mode 100755 index 000000000..9dfff9c18 --- /dev/null +++ b/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReader.java @@ -0,0 +1,97 @@ +package com.alibaba.datax.plugin.reader.mysqlreader; + +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader; +import com.alibaba.datax.plugin.rdbms.reader.Constant; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class MysqlReader extends Reader { + + private static final DataBaseType DATABASE_TYPE = DataBaseType.MySql; + + public static class Job extends Reader.Job { + private static final Logger LOG = LoggerFactory + .getLogger(Job.class); + + private Configuration originalConfig = null; + private CommonRdbmsReader.Job commonRdbmsReaderJob; + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + + Integer userConfigedFetchSize = this.originalConfig.getInt(Constant.FETCH_SIZE); + if (userConfigedFetchSize != null) { + LOG.warn("对 mysqlreader 不需要配置 fetchSize, mysqlreader 将会忽略这项配置. 如果您不想再看到此警告,请去除fetchSize 配置."); + } + + this.originalConfig.set(Constant.FETCH_SIZE, Integer.MIN_VALUE); + + this.commonRdbmsReaderJob = new CommonRdbmsReader.Job(DATABASE_TYPE); + this.commonRdbmsReaderJob.init(this.originalConfig); + } + + @Override + public void preCheck(){ + init(); + this.commonRdbmsReaderJob.preCheck(this.originalConfig,DATABASE_TYPE); + + } + + @Override + public List split(int adviceNumber) { + return this.commonRdbmsReaderJob.split(this.originalConfig, adviceNumber); + } + + @Override + public void post() { + this.commonRdbmsReaderJob.post(this.originalConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderJob.destroy(this.originalConfig); + } + + } + + public static class Task extends Reader.Task { + + private Configuration readerSliceConfig; + private CommonRdbmsReader.Task commonRdbmsReaderTask; + + @Override + public void init() { + this.readerSliceConfig = super.getPluginJobConf(); + this.commonRdbmsReaderTask = new CommonRdbmsReader.Task(DATABASE_TYPE,super.getTaskGroupId(), super.getTaskId()); + this.commonRdbmsReaderTask.init(this.readerSliceConfig); + + } + + @Override + public void startRead(RecordSender recordSender) { + int fetchSize = this.readerSliceConfig.getInt(Constant.FETCH_SIZE); + + this.commonRdbmsReaderTask.startRead(this.readerSliceConfig, recordSender, + super.getTaskPluginCollector(), fetchSize); + } + + @Override + public void post() { + this.commonRdbmsReaderTask.post(this.readerSliceConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderTask.destroy(this.readerSliceConfig); + } + + } + +} diff --git a/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReaderErrorCode.java b/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReaderErrorCode.java new file mode 100755 index 000000000..de9525e9d --- /dev/null +++ b/mysqlreader/src/main/java/com/alibaba/datax/plugin/reader/mysqlreader/MysqlReaderErrorCode.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.plugin.reader.mysqlreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum MysqlReaderErrorCode implements ErrorCode { + ; + + private final String code; + private final String description; + + private MysqlReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/mysqlreader/src/main/resources/TODO.txt b/mysqlreader/src/main/resources/TODO.txt new file mode 100755 index 000000000..b9e54f0a1 --- /dev/null +++ b/mysqlreader/src/main/resources/TODO.txt @@ -0,0 +1,3 @@ +报错的异常,可重复跑的? +对所有必填参数,进行校验。注意:conf.getString(path) 如果 path 不存在,是直接返回 null,而不是报错。 +字符串主键切分 diff --git a/mysqlreader/src/main/resources/plugin.json b/mysqlreader/src/main/resources/plugin.json new file mode 100755 index 000000000..6a8227b8e --- /dev/null +++ b/mysqlreader/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "mysqlreader", + "class": "com.alibaba.datax.plugin.reader.mysqlreader.MysqlReader", + "description": "useScene: prod. mechanism: Jdbc connection using the database, execute select sql, retrieve data from the ResultSet. warn: The more you know about the database, the less problems you encounter.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/mysqlreader/src/main/resources/plugin_job_template.json b/mysqlreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..68b25b32c --- /dev/null +++ b/mysqlreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,15 @@ +{ + "name": "mysqlreader", + "parameter": { + "username": "", + "password": "", + "column": [], + "connection": [ + { + "jdbcUrl": "", + "table": [] + } + ], + "where": "" + } +} \ No newline at end of file diff --git a/mysqlwriter/doc/mysqlwriter.md b/mysqlwriter/doc/mysqlwriter.md new file mode 100644 index 000000000..4fa3e1a58 --- /dev/null +++ b/mysqlwriter/doc/mysqlwriter.md @@ -0,0 +1,359 @@ +# DataX MysqlWriter + + +--- + + +## 1 快速介绍 + +MysqlWriter 插件实现了写入数据到 Mysql 主库的目的表的功能。在底层实现上, MysqlWriter 通过 JDBC 连接远程 Mysql 数据库,并执行相应的 insert into ... 或者 ( replace into ...) 的 sql 语句将数据写入 Mysql,内部会分批次提交入库,需要数据库本身采用 innodb 引擎。 + +MysqlWriter 面向ETL开发工程师,他们使用 MysqlWriter 从数仓导入数据到 Mysql。同时 MysqlWriter 亦可以作为数据迁移工具为DBA等用户提供服务。 + + +## 2 实现原理 + +MysqlWriter 通过 DataX 框架获取 Reader 生成的协议数据,根据你配置的 `writeMode` 生成 + + +* `insert into...`(当主键/唯一性索引冲突时会写不进去冲突的行) + +##### 或者 + +* `replace into...`(没有遇到主键/唯一性索引冲突时,与 insert into 行为一致,冲突时会用新行替换原有行所有字段) 的语句写入数据到 Mysql。出于性能考虑,采用了 `PreparedStatement + Batch`,并且设置了:`rewriteBatchedStatements=true`,将数据缓冲到线程上下文 Buffer 中,当 Buffer 累计到预定阈值时,才发起写入请求。 + +
+ + 注意:目的表所在数据库必须是主库才能写入数据;整个任务至少需要具备 insert/replace into...的权限,是否需要其他权限,取决于你任务配置中在 preSql 和 postSql 中指定的语句。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 这里使用一份从内存产生到 Mysql 导入的数据。 + +```json +{ + "job": { + "setting": { + "speed": { + "channel": 1 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column" : [ + { + "value": "DataX", + "type": "string" + }, + { + "value": 19880808, + "type": "long" + }, + { + "value": "1988-08-08 08:08:08", + "type": "date" + }, + { + "value": true, + "type": "bool" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 1000 + } + }, + "writer": { + "name": "mysqlwriter", + "parameter": { + "writeMode": "insert", + "username": "root", + "password": "root", + "column": [ + "id", + "name" + ], + "session": [ + "set session sql_mode='ANSI'" + ], + "preSql": [ + "delete from test" + ], + "connection": [ + { + "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax?useUnicode=true&characterEncoding=gbk", + "table": [ + "test" + ] + } + ] + } + } + } + ] + } +} + +``` + + +### 3.2 参数说明 + +* **jdbcUrl** + + * 描述:目的数据库的 JDBC 连接信息。作业运行时,DataX 会在你提供的 jdbcUrl 后面追加如下属性:yearIsDateType=false&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true + + 注意:1、在一个数据库上只能配置一个 jdbcUrl 值。这与 MysqlReader 支持多个备库探测不同,因为此处不支持同一个数据库存在多个主库的情况(双主导入数据情况) + 2、jdbcUrl按照Mysql官方规范,并可以填写连接附加控制信息,比如想指定连接编码为 gbk ,则在 jdbcUrl 后面追加属性 useUnicode=true&characterEncoding=gbk。具体请参看 Mysql官方文档或者咨询对应 DBA。 + + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:目的数据库的用户名
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:目的数据库的密码
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:目的表的表名称。支持写入一个或者多个表。当配置为多张表时,必须确保所有表结构保持一致。 + + 注意:table 和 jdbcUrl 必须包含在 connection 配置单元中 + + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:目的表需要写入数据的字段,字段之间用英文逗号分隔。例如: "column": ["id","name","age"]。如果要依次写入全部列,使用*表示, 例如: "column": ["*"]。 + + **column配置项必须指定,不能留空!** + + 注意:1、我们强烈不推荐你这样配置,因为当你目的表字段个数、类型等有改动时,你的任务可能运行不正确或者失败 + 2、 column 不能配置任何常量值 + + * 必选:是
+ + * 默认值:否
+ +* **session** + + * 描述: DataX在获取Mysql连接时,执行session指定的SQL语句,修改当前connection session属性 + + * 必须: 否 + + * 默认值: 空 + +* **preSql** + + * 描述:写入数据到目的表前,会先执行这里的标准语句。如果 Sql 中有你需要操作到的表名称,请使用 `@table` 表示,这样在实际执行 Sql 语句时,会对变量按照实际表名称进行替换。比如你的任务是要写入到目的端的100个同构分表(表名称为:datax_00,datax01, ... datax_98,datax_99),并且你希望导入数据前,先对表中数据进行删除操作,那么你可以这样配置:`"preSql":["delete from 表名"]`,效果是:在执行到每个表写入数据前,会先执行对应的 delete from 对应表名称
+ + * 必选:否
+ + * 默认值:无
+ +* **postSql** + + * 描述:写入数据到目的表后,会执行这里的标准语句。(原理同 preSql )
+ + * 必选:否
+ + * 默认值:无
+ +* **writeMode** + + * 描述:控制写入数据到目标表采用 `insert into` 或者 `replace into` 语句
+ + * 必选:是
+ + * 默认值:insert
+ +* **batchSize** + + * 描述:一次性批量提交的记录数大小,该值可以极大减少DataX与Mysql的网络交互次数,并提升整体吞吐量。但是该值设置过大可能会造成DataX运行进程OOM情况。
+ + * 必选:否
+ + * 默认值:1024
+ + +### 3.3 类型转换 + +类似 MysqlReader ,目前 MysqlWriter 支持大部分 Mysql 类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出 MysqlWriter 针对 Mysql 类型转换列表: + + +| DataX 内部类型| Mysql 数据类型 | +| -------- | ----- | +| Long |int, tinyint, smallint, mediumint, int, bigint, year| +| Double |float, double, decimal| +| String |varchar, char, tinytext, text, mediumtext, longtext | +| Date |date, datetime, timestamp, time | +| Boolean |bit, bool | +| Bytes |tinyblob, mediumblob, blob, longblob, varbinary | + + * `bit类型目前是未定义类型转换` + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 +建表语句: + + CREATE TABLE `datax_mysqlwriter_perf_00` ( + `biz_order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `key_value` varchar(4000) NOT NULL COMMENT 'Key-value的内容', + `gmt_create` datetime NOT NULL COMMENT '创建时间', + `gmt_modified` datetime NOT NULL COMMENT '修改时间', + `attribute_cc` int(11) DEFAULT NULL COMMENT '防止并发修改的标志', + `value_type` int(11) NOT NULL DEFAULT '0' COMMENT '类型', + `buyer_id` bigint(20) DEFAULT NULL COMMENT 'buyerid', + `seller_id` bigint(20) DEFAULT NULL COMMENT 'seller_id', + PRIMARY KEY (`biz_order_id`,`value_type`), + KEY `idx_biz_vertical_gmtmodified` (`gmt_modified`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='datax perf test' + + +单行记录类似于: + + key_value: ;orderIds:20148888888,2014888888813800; + gmt_create: 2011-09-24 11:07:20 + gmt_modified: 2011-10-24 17:56:34 + attribute_cc: 1 + value_type: 3 + buyer_id: 8888888 + seller_id: 1 + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu: 24核 Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz + 2. mem: 48GB + 3. net: 千兆双网卡 + 4. disc: DataX 数据不落磁盘,不统计此项 + +* Mysql数据库机器参数为: + 1. cpu: 32核 Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz + 2. mem: 256GB + 3. net: 千兆双网卡 + 4. disc: BTWL419303E2800RGN INTEL SSDSC2BB800G4 D2010370 + +#### 4.1.3 DataX jvm 参数 + + -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + + +### 4.2 测试报告 + +#### 4.2.1 单表测试报告 + + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DB网卡进入流量(MB/s)|DB运行负载|DB TPS| +|--------|--------| --------|--------|--------|--------|--------|--------|--------| +|1| 128 | 5319 | 0.260 | 0.580 | 0.05 | 0.620| 0.5 | 50 | +|1| 512 | 14285 | 0.697 | 1.6 | 0.12 | 1.6 | 0.6 | 28 | +|1| 1024 | 17241 | 0.842 | 1.9 | 0.20 | 1.9 | 0.6 | 16| +|1| 2048 | 31250 | 1.49 | 2.8 | 0.15 | 3.0| 0.8 | 15 | +|1| 4096 | 31250 | 1.49 | 3.5 | 0.20 | 3.6| 0.8 | 8 | +|4| 128 | 11764 | 0.574 | 1.5 | 0.21 | 1.6| 0.8 | 112 | +|4| 512 | 30769 | 1.47 | 3.5 | 0.3 | 3.6 | 0.9 | 88 | +|4| 1024 | 50000 | 2.38 | 5.4 | 0.3 | 5.5 | 1.0 | 66 | +|4| 2048 | 66666 | 3.18 | 7.0 | 0.3 | 7.1| 1.37 | 46 | +|4| 4096 | 80000 | 3.81 | 7.3| 0.5 | 7.3| 1.40 | 26 | +|8| 128 | 17777 | 0.868 | 2.9 | 0.28 | 2.9| 0.8 | 200 | +|8| 512 | 57142 | 2.72 | 8.5 | 0.5 | 8.5| 0.70 | 159 | +|8| 1024 | 88888 | 4.24 | 12.2 | 0.9 | 12.4 | 1.0 | 108 | +|8| 2048 | 133333 | 6.36 | 14.7 | 0.9 | 14.7 | 1.0 | 81 | +|8| 4096 | 166666 | 7.95 | 19.5 | 0.9 | 19.5 | 3.0 | 45 | +|16| 128 | 32000 | 1.53 | 3.3 | 0.6 | 3.4 | 0.88 | 401 | +|16| 512 | 106666 | 5.09 | 16.1| 0.9 | 16.2 | 2.16 | 260 | +|16| 1024 | 173913 | 8.29 | 22.1| 1.5 | 22.2 | 4.5 | 200 | +|16| 2048 | 228571 | 10.90 | 28.6 | 1.61 | 28.7 | 4.60 | 128 | +|16| 4096 | 246153 | 11.74 | 31.1| 1.65 | 31.2| 4.66 | 57 | +|32| 1024 | 246153 | 11.74 | 30.5| 3.17 | 30.7 | 12.10 | 270 | + + +说明: + +1. 这里的单表,主键类型为 bigint(20),自增。 +2. batchSize 和 通道个数,对性能影响较大。 +3. 16通道,4096批量提交时,出现 full gc 2次。 + + +#### 4.2.2 分表测试报告(2个分库,每个分库4张分表,共计8张分表) + + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DB网卡进入流量(MB/s)|DB运行负载|DB TPS| +|--------|--------| --------|--------|--------|--------|--------|--------|--------| +|8| 128 | 26764 | 1.28 | 2.9 | 0.5 | 3.0| 0.8 | 209 | +|8| 512 | 95180 | 4.54 | 10.5 | 0.7 | 10.9 | 0.8 | 188 | +|8| 1024 | 94117 | 4.49 | 12.3 | 0.6 | 12.4 | 1.09 | 120 | +|8| 2048 | 133333 | 6.36 | 19.4 | 0.9 | 19.5| 1.35 | 85 | +|8| 4096 | 191692 | 9.14 | 22.1 | 1.0 | 22.2| 1.45 | 45 | + + +#### 4.2.3 分表测试报告(2个分库,每个分库8张分表,共计16张分表) + + +| 通道数| 批量提交行数| DataX速度(Rec/s)|DataX流量(MB/s)| DataX机器网卡流出流量(MB/s)|DataX机器运行负载|DB网卡进入流量(MB/s)|DB运行负载|DB TPS| +|--------|--------| --------|--------|--------|--------|--------|--------|--------| +|16| 128 | 50124 | 2.39 | 5.6 | 0.40 | 6.0| 2.42 | 378 | +|16| 512 | 155084 | 7.40 | 18.6 | 1.30 | 18.9| 2.82 | 325 | +|16| 1024 | 177777 | 8.48 | 24.1 | 1.43 | 25.5| 3.5 | 233 | +|16| 2048 | 289382 | 13.8 | 33.1 | 2.5 | 33.5| 4.5 | 150 | +|16| 4096 | 326451 | 15.52 | 33.7 | 1.5 | 33.9| 4.3 | 80 | + +#### 4.2.4 性能测试小结 +1. 批量提交行数(batchSize)对性能影响很大,当 `batchSize>=512` 之后,单线程写入速度能达到每秒写入一万行 +2. 在 `batchSize>=512` 的基础上,随着通道数的增加(通道数<32),速度呈线性比增加。 +3. `通常不建议写入数据库时,通道个数 >32` + + +## 5 约束限制 + + + + +## FAQ + +*** + +**Q: MysqlWriter 执行 postSql 语句报错,那么数据导入到目标数据库了吗?** + +A: DataX 导入过程存在三块逻辑,pre 操作、导入操作、post 操作,其中任意一环报错,DataX 作业报错。由于 DataX 不能保证在同一个事务完成上述几个操作,因此有可能数据已经落入到目标端。 + +*** + +**Q: 按照上述说法,那么有部分脏数据导入数据库,如果影响到线上数据库怎么办?** + +A: 目前有两种解法,第一种配置 pre 语句,该 sql 可以清理当天导入数据, DataX 每次导入时候可以把上次清理干净并导入完整数据。第二种,向临时表导入数据,完成后再 rename 到线上表。 + +*** + +**Q: 上面第二种方法可以避免对线上数据造成影响,那我具体怎样操作?** + +A: 可以配置临时表导入 diff --git a/mysqlwriter/mysqlwriter.iml b/mysqlwriter/mysqlwriter.iml new file mode 100644 index 000000000..1f713bbe7 --- /dev/null +++ b/mysqlwriter/mysqlwriter.iml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mysqlwriter/pom.xml b/mysqlwriter/pom.xml new file mode 100755 index 000000000..3eaee3561 --- /dev/null +++ b/mysqlwriter/pom.xml @@ -0,0 +1,78 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + mysqlwriter + mysqlwriter + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + + mysql + mysql-connector-java + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/mysqlwriter/src/main/assembly/package.xml b/mysqlwriter/src/main/assembly/package.xml new file mode 100755 index 000000000..03883c7be --- /dev/null +++ b/mysqlwriter/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/mysqlwriter + + + target/ + + mysqlwriter-0.0.1-SNAPSHOT.jar + + plugin/writer/mysqlwriter + + + + + + false + plugin/writer/mysqlwriter/libs + runtime + + + diff --git a/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriter.java b/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriter.java new file mode 100755 index 000000000..9d2c82ee7 --- /dev/null +++ b/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriter.java @@ -0,0 +1,101 @@ +package com.alibaba.datax.plugin.writer.mysqlwriter; + +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter; +import com.alibaba.datax.plugin.rdbms.writer.Key; + +import java.util.List; + + +//TODO writeProxy +public class MysqlWriter extends Writer { + private static final DataBaseType DATABASE_TYPE = DataBaseType.MySql; + + public static class Job extends Writer.Job { + private Configuration originalConfig = null; + private CommonRdbmsWriter.Job commonRdbmsWriterJob; + + @Override + public void preCheck(){ + this.init(); + this.commonRdbmsWriterJob.writerPreCheck(this.originalConfig, DATABASE_TYPE); + } + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + this.commonRdbmsWriterJob = new CommonRdbmsWriter.Job(DATABASE_TYPE); + this.commonRdbmsWriterJob.init(this.originalConfig); + } + + // 一般来说,是需要推迟到 task 中进行pre 的执行(单表情况例外) + @Override + public void prepare() { + //实跑先不支持 权限 检验 + //this.commonRdbmsWriterJob.privilegeValid(this.originalConfig, DATABASE_TYPE); + this.commonRdbmsWriterJob.prepare(this.originalConfig); + } + + @Override + public List split(int mandatoryNumber) { + return this.commonRdbmsWriterJob.split(this.originalConfig, mandatoryNumber); + } + + // 一般来说,是需要推迟到 task 中进行post 的执行(单表情况例外) + @Override + public void post() { + this.commonRdbmsWriterJob.post(this.originalConfig); + } + + @Override + public void destroy() { + this.commonRdbmsWriterJob.destroy(this.originalConfig); + } + + } + + public static class Task extends Writer.Task { + private Configuration writerSliceConfig; + private CommonRdbmsWriter.Task commonRdbmsWriterTask; + + @Override + public void init() { + this.writerSliceConfig = super.getPluginJobConf(); + this.commonRdbmsWriterTask = new CommonRdbmsWriter.Task(DATABASE_TYPE); + this.commonRdbmsWriterTask.init(this.writerSliceConfig); + } + + @Override + public void prepare() { + this.commonRdbmsWriterTask.prepare(this.writerSliceConfig); + } + + //TODO 改用连接池,确保每次获取的连接都是可用的(注意:连接可能需要每次都初始化其 session) + public void startWrite(RecordReceiver recordReceiver) { + this.commonRdbmsWriterTask.startWrite(recordReceiver, this.writerSliceConfig, + super.getTaskPluginCollector()); + } + + @Override + public void post() { + this.commonRdbmsWriterTask.post(this.writerSliceConfig); + } + + @Override + public void destroy() { + this.commonRdbmsWriterTask.destroy(this.writerSliceConfig); + } + + @Override + public boolean supportFailOver(){ + String writeMode = writerSliceConfig.getString(Key.WRITE_MODE); + return "replace".equalsIgnoreCase(writeMode); + } + + } + + +} diff --git a/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriterErrorCode.java b/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriterErrorCode.java new file mode 100755 index 000000000..e94adbfe9 --- /dev/null +++ b/mysqlwriter/src/main/java/com/alibaba/datax/plugin/writer/mysqlwriter/MysqlWriterErrorCode.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.plugin.writer.mysqlwriter; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum MysqlWriterErrorCode implements ErrorCode { + ; + + private final String code; + private final String describe; + + private MysqlWriterErrorCode(String code, String describe) { + this.code = code; + this.describe = describe; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.describe; + } + + @Override + public String toString() { + return String.format("Code:[%s], Describe:[%s]. ", this.code, + this.describe); + } +} diff --git a/mysqlwriter/src/main/resources/plugin.json b/mysqlwriter/src/main/resources/plugin.json new file mode 100755 index 000000000..e2b62538a --- /dev/null +++ b/mysqlwriter/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "mysqlwriter", + "class": "com.alibaba.datax.plugin.writer.mysqlwriter.MysqlWriter", + "description": "useScene: prod. mechanism: Jdbc connection using the database, execute insert sql. warn: The more you know about the database, the less problems you encounter.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/mysqlwriter/src/main/resources/plugin_job_template.json b/mysqlwriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..1edb50048 --- /dev/null +++ b/mysqlwriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,17 @@ +{ + "name": "mysqlwriter", + "parameter": { + "username": "", + "password": "", + "writeMode": "", + "column": [], + "session": [], + "preSql": [], + "connection": [ + { + "jdbcUrl": "", + "table": [] + } + ] + } +} \ No newline at end of file diff --git a/ocswriter/doc/ocswriter.md b/ocswriter/doc/ocswriter.md new file mode 100644 index 000000000..885ac697a --- /dev/null +++ b/ocswriter/doc/ocswriter.md @@ -0,0 +1,168 @@ +# DataX OCSWriter 适用memcached客户端写入ocs +--- +## 1 快速介绍 +### 1.1 OCS简介 +开放缓存服务( Open Cache Service,简称OCS)是基于内存的缓存服务,支持海量小数据的高速访问。OCS可以极大缓解对后端存储的压力,提高网站或应用的响应速度。OCS支持Key-Value的数据结构,兼容Memcached协议的客户端都可与OCS通信。
+ +OCS 支持即开即用的方式快速部署;对于动态Web、APP应用,可通过缓存服务减轻对数据库的压力,从而提高网站整体的响应速度。
+ +与本地MemCache相同之处在于OCS兼容Memcached协议,与用户环境兼容,可直接用于OCS服务 不同之处在于硬件和数据部署在云端,有完善的基础设施、网络安全保障、系统维护服务。所有的这些服务,都不需要投资,只需根据使用量进行付费即可。 +### 1.2 OCSWriter简介 +OCSWriter是DataX实现的,基于Memcached协议的数据写入OCS通道。 +## 2 功能说明 +### 2.1 配置样例 +* 这里使用一份从内存产生的数据导入到OCS。 + +``` +{ + "job": { + "setting": { + "speed": { + "channel": 1 + } + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column": [ + { + "value": "DataX", + "type": "string" + }, + { + "value": 19880808, + "type": "long" + }, + { + "value": "1988-08-08 08:08:08", + "type": "date" + }, + { + "value": true, + "type": "bool" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 1000 + } + }, + "writer": { + "name": "ocswriter", + "parameter": { + "proxy": "10.101.72.137", + "port": "11211", + "userName": "user", + "password": "******", + "writeMode": "set|add|replace|append|prepend", + "writeFormat": "text|binary", + "fieldDelimiter": "\u0001", + "expireTime": 1000, + "indexes": "0,2", + "batchSize": 1000 + } + } + } + ] + } +} +``` + +### 2.2 参数说明 + +* **proxy** + + * 描述:OCS机器的ip或host。 + * 必选:是 + +* **port** + + * 描述:OCS的连接域名,默认为11211 + * 必选:否 + * 默认值:11211 + +* **username** + + * 描述:OCS连接的访问账号。 + * 必选:是 + +* **password** + + * 描述:OCS连接的访问密码 + * 必选:是 + +* **writeMode** + + * 描述: OCSWriter写入方式,具体为: + * set: 存储这个数据,如果已经存在则覆盖 + * add: 存储这个数据,当且仅当这个key不存在的时候 + * replace: 存储这个数据,当且仅当这个key存在 + * append: 将数据存放在已存在的key对应的内容的后面,忽略exptime + * prepend: 将数据存放在已存在的key对应的内容的前面,忽略exptime + * 必选:是 + +* **writeFormat** + + * 描述: OCSWriter写出数据格式,目前支持两类数据写入方式: + * text: 将源端数据序列化为文本格式,其中第一个字段作为OCS写入的KEY,后续所有字段序列化为STRING类型,使用用户指定的fieldDelimiter作为间隔符,将文本拼接为完整的字符串再写入OCS。 + * binary: 将源端数据作为二进制直接写入,这类场景为未来做扩展使用,目前不支持。如果填写binary将会报错! + * 必选:否 + * 默认值:text + +* **expireTime** + + * 描述: OCS值缓存失效时间,目前MemCache支持两类过期时间, + + * Unix时间(自1970.1.1开始到现在的秒数),该时间指定了到未来某个时刻数据失效。 + * 相对当前时间的秒数,该时间指定了从现在开始多长时间后数据失效。 + **注意:如果过期时间的秒数大于60*60*24*30(即30天),则服务端认为是Unix时间。** + * 单位:秒 + * 必选:否 + * 默认值:0【0表示永久有效】 + +* **indexes** + + * 描述: 用数据的第几列当做ocs的key + * 必选:否 + * 默认值:0 + +* **batchSize** + + * 描述:一次性批量提交的记录数大小,该值可以极大减少DataX与OCS的网络交互次数,并提升整体吞吐量。但是该值设置过大可能会造成DataX运行进程OOM情况[memcached版本暂不支持批量写]。 + * 必选:否 + * 默认值:256 + +* **fieldDelimiter** + * 描述:写入ocs的key和value分隔符。比如:key=tom\u0001boston, value=28\u0001lawer\u0001male\u0001married + * 必选:否 + * 默认值:\u0001 + +## 3 性能报告 +### 3.1 datax机器配置 +``` +CPU:16核、内存:24GB、网卡:单网卡1000mbps +``` +### 3.2 任务资源配置 +``` +-Xms8g -Xmx8g -XX:+HeapDumpOnOutOfMemoryError +``` +### 3.3 测试报告 +| 单条数据大小 | 通道并发数 | TPS | 通道流量 | 出口流量 | 备注 | +| :--------: | :--------:| :--: | :--: | :--: | :--: | +| 1KB | 1 | 579 tps | 583.31KB/s | 648.63KB/s | 无 | +| 1KB | 10 | 6006 tps | 5.87MB/s | 6.73MB/s | 无 | +| 1KB | 100 | 49916 tps | 48.56MB/s | 55.55MB/s | 无 | +| 10KB | 1 | 438 tps | 4.62MB/s | 5.07MB/s | 无 | +| 10KB | 10 | 4313 tps | 45.57MB/s | 49.51MB/s | 无 | +| 10KB | 100 | 10713 tps | 112.80MB/s | 123.01MB/s | 无 | +| 100KB | 1 | 275 tps | 26.09MB/s | 144.90KB/s | 无。数据冗余大,压缩比高。 | +| 100KB | 10 | 2492 tps | 236.33MB/s | 1.30MB/s | 无 | +| 100KB | 100 | 3187 tps | 302.17MB/s | 1.77MB/s | 无 | + +### 3.4 性能测试小结 +1. 单条数据小于10KB时建议开启100并发。 +2. 不建议10KB以上的数据写入ocs。 diff --git a/ocswriter/ocswriter.iml b/ocswriter/ocswriter.iml new file mode 100644 index 000000000..a64d9e2c5 --- /dev/null +++ b/ocswriter/ocswriter.iml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ocswriter/pom.xml b/ocswriter/pom.xml new file mode 100644 index 000000000..0afc74db6 --- /dev/null +++ b/ocswriter/pom.xml @@ -0,0 +1,94 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + + ocswriter + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + com.alibaba.datax + datax-core + ${datax-project-version} + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + org.slf4j + slf4j-api + + + org.testng + testng + 6.8.8 + test + + + org.easymock + easymock + 3.3.1 + test + + + com.google.code.simple-spring-memcached + spymemcached + 2.8.1 + + + + com.google.guava + guava + 16.0.1 + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + 3.2 + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + + \ No newline at end of file diff --git a/ocswriter/src/main/assembly/package.xml b/ocswriter/src/main/assembly/package.xml new file mode 100644 index 000000000..804456e6f --- /dev/null +++ b/ocswriter/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/ocswriter + + + target/ + + ocswriter-0.0.1-SNAPSHOT.jar + + plugin/writer/ocswriter + + + + + + false + plugin/writer/ocswriter/libs + runtime + + + diff --git a/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/Key.java b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/Key.java new file mode 100644 index 000000000..00bdea8d2 --- /dev/null +++ b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/Key.java @@ -0,0 +1,26 @@ +package com.alibaba.datax.plugin.writer.ocswriter; + +/** + * Time: 2015-05-06 19:54 + */ +public final class Key { + public final static String USER = "username"; + + public final static String PASSWORD = "password"; + + public final static String PROXY = "proxy"; + + public final static String PORT = "port"; + + public final static String WRITE_MODE = "writeMode"; + + public final static String WRITE_FORMAT = "writeFormat"; + + public final static String FIELD_DELIMITER = "fieldDelimiter"; + + public final static String EXPIRE_TIME = "expireTime"; + + public final static String BATCH_SIZE = "batchSize"; + + public final static String INDEXES = "indexes"; +} diff --git a/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/OcsWriter.java b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/OcsWriter.java new file mode 100644 index 000000000..6b46f38b9 --- /dev/null +++ b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/OcsWriter.java @@ -0,0 +1,321 @@ +package com.alibaba.datax.plugin.writer.ocswriter; + +import com.alibaba.datax.common.element.Column; +import com.alibaba.datax.common.element.Record; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.RetryUtil; +import com.alibaba.datax.plugin.writer.ocswriter.utils.ConfigurationChecker; +import com.alibaba.datax.plugin.writer.ocswriter.utils.OcsWriterErrorCode; +import com.google.common.annotations.VisibleForTesting; +import net.spy.memcached.AddrUtil; +import net.spy.memcached.ConnectionFactoryBuilder; +import net.spy.memcached.MemcachedClient; +import net.spy.memcached.auth.AuthDescriptor; +import net.spy.memcached.auth.PlainCallbackHandler; +import net.spy.memcached.internal.OperationFuture; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +/** + * Time: 2015-05-06 16:01 + * 1,控制速度 + * 2、MemcachedClient长连接长时间不写入数据可能会被server强行关闭 + * 3、以后支持json格式的value + */ +public class OcsWriter extends Writer { + + public static class Job extends Writer.Job { + private Configuration configuration; + + @Override + public void init() { + this.configuration = super.getPluginJobConf(); + //参数有效性检查 + ConfigurationChecker.check(this.configuration); + } + + @Override + public void prepare() { + super.prepare(); + } + + @Override + public List split(int mandatoryNumber) { + ArrayList configList = new ArrayList(); + for (int i = 0; i < mandatoryNumber; i++) { + configList.add(this.configuration.clone()); + } + return configList; + } + + @Override + public void destroy() { + } + } + + public static class Task extends Writer.Task { + + private Configuration configuration; + private MemcachedClient client; + private Set indexesFromUser = new HashSet(); + private String delimiter; + private int expireTime; + //private int batchSize; + private ConfigurationChecker.WRITE_MODE writeMode; + private TaskPluginCollector taskPluginCollector; + + @Override + public void init() { + this.configuration = this.getPluginJobConf(); + this.taskPluginCollector = super.getTaskPluginCollector(); + } + + @Override + public void prepare() { + super.prepare(); + + //如果用户不配置,默认为第0列 + String indexStr = this.configuration.getString(Key.INDEXES, "0"); + for (String index : indexStr.split(",")) { + indexesFromUser.add(Integer.parseInt(index)); + } + + //如果用户不配置,默认为\u0001 + delimiter = this.configuration.getString(Key.FIELD_DELIMITER, "\u0001"); + expireTime = this.configuration.getInt(Key.EXPIRE_TIME, 0); + //todo 此版本不支持批量提交,待ocswriter发布新版本client后支持。batchSize = this.configuration.getInt(Key.BATCH_SIZE, 100); + writeMode = ConfigurationChecker.WRITE_MODE.valueOf(this.configuration.getString(Key.WRITE_MODE)); + + String proxy = this.configuration.getString(Key.PROXY); + //默认端口为11211 + String port = this.configuration.getString(Key.PORT, "11211"); + String username = this.configuration.getString(Key.USER); + String password = this.configuration.getString(Key.PASSWORD); + AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(username, password)); + + try { + client = getMemcachedConn(proxy, port, ad); + } catch (Exception e) { + //异常不能吃掉,直接抛出,便于定位 + throw DataXException.asDataXException(OcsWriterErrorCode.OCS_INIT_ERROR, String.format("初始化ocs客户端失败"), e); + } + } + + /** + * 建立ocs客户端连接 + * 重试9次,间隔时间指数增长 + */ + private MemcachedClient getMemcachedConn(final String proxy, final String port, final AuthDescriptor ad) throws Exception { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public MemcachedClient call() throws Exception { + return new MemcachedClient( + new ConnectionFactoryBuilder().setProtocol(ConnectionFactoryBuilder.Protocol.BINARY) + .setAuthDescriptor(ad) + .build(), + AddrUtil.getAddresses(proxy + ":" + port)); + } + }, 9, 1000L, true); + } + + @Override + public void startWrite(RecordReceiver lineReceiver) { + Record record; + String key; + String value; + while ((record = lineReceiver.getFromReader()) != null) { + try { + key = buildKey(record); + value = buildValue(record); + switch (writeMode) { + case set: + case replace: + case add: + commitWithRetry(key, value); + break; + case append: + case prepend: + commit(key, value); + break; + default: + //没有default,因为参数检查的时候已经判断,不可能出现5中模式之外的模式 + } + } catch (Exception e) { + this.taskPluginCollector.collectDirtyRecord(record, e); + } + } + } + + /** + * 没有重试的commit + */ + private void commit(final String key, final String value) { + OperationFuture future; + switch (writeMode) { + case set: + future = client.set(key, expireTime, value); + break; + case add: + //幂等原则:相同的输入得到相同的输出,不管调用多少次。 + //所以add和replace是幂等的。 + future = client.add(key, expireTime, value); + break; + case replace: + future = client.replace(key, expireTime, value); + break; + //todo 【注意】append和prepend重跑任务不能支持幂等,使用需谨慎,不需要重试 + case append: + future = client.append(0L, key, value); + break; + case prepend: + future = client.prepend(0L, key, value); + break; + default: + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("不支持的写入模式%s", writeMode.toString())); + //因为前面参数校验的时候已经判断,不可能存在5中操作之外的类型。 + } + //【注意】getStatus()返回为null有可能是因为get()超时导致,此种情况当做脏数据处理。但有可能数据已经成功写入ocs。 + if (future == null || future.getStatus() == null || !future.getStatus().isSuccess()) { + throw DataXException.asDataXException(OcsWriterErrorCode.COMMIT_FAILED, "提交数据到ocs失败"); + } + } + + /** + * 提交数据到ocs,有重试机制 + */ + private void commitWithRetry(final String key, final String value) throws Exception { + RetryUtil.executeWithRetry(new Callable() { + @Override + public Object call() throws Exception { + commit(key, value); + return null; + } + }, 3, 1000L, false); + } + + /** + * 构建value + * 如果有二进制字段当做脏数据处理 + * 如果col为null,当做脏数据处理 + */ + private String buildValue(Record record) { + ArrayList valueList = new ArrayList(); + int colNum = record.getColumnNumber(); + for (int i = 0; i < colNum; i++) { + Column col = record.getColumn(i); + if (col != null) { + String value; + Column.Type type = col.getType(); + switch (type) { + case STRING: + case BOOL: + case DOUBLE: + case LONG: + case DATE: + value = col.asString(); + //【注意】value字段中如果有分隔符,当做脏数据处理 + if (value != null && value.contains(delimiter)) { + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("数据中包含分隔符:%s", value)); + } + break; + default: + //目前不支持二进制,如果遇到二进制,则当做脏数据处理 + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("不支持的数据格式:%s", type.toString())); + } + valueList.add(value); + } else { + //如果取到的列为null,需要当做脏数据处理 + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("record中不存在第%s个字段", i)); + } + } + return StringUtils.join(valueList, delimiter); + } + + /** + * 构建key + * 构建数据为空时当做脏数据处理 + */ + private String buildKey(Record record) { + ArrayList keyList = new ArrayList(); + for (int index : indexesFromUser) { + Column col = record.getColumn(index); + if (col == null) { + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("不存在第%s列", index)); + } + Column.Type type = col.getType(); + String value; + switch (type) { + case STRING: + case BOOL: + case DOUBLE: + case LONG: + case DATE: + value = col.asString(); + if (value != null && value.contains(delimiter)) { + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("主键中包含分隔符:%s", value)); + } + keyList.add(value); + break; + default: + //目前不支持二进制,如果遇到二进制,则当做脏数据处理 + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("不支持的数据格式:%s", type.toString())); + } + } + String rtn = StringUtils.join(keyList, delimiter); + if (StringUtils.isBlank(rtn)) { + throw DataXException.asDataXException(OcsWriterErrorCode.DIRTY_RECORD, String.format("构建主键为空,请检查indexes的配置")); + } + return rtn; + } + + /** + * shutdown中会有数据异步提交,需要重试。 + */ + @Override + public void destroy() { + try { + RetryUtil.executeWithRetry(new Callable() { + @Override + public Object call() throws Exception { + if (client == null || client.shutdown(10000L, TimeUnit.MILLISECONDS)) { + return null; + } else { + throw DataXException.asDataXException(OcsWriterErrorCode.SHUTDOWN_FAILED, "关闭ocsClient失败"); + } + } + }, 8, 1000L, true); + } catch (Exception e) { + throw DataXException.asDataXException(OcsWriterErrorCode.SHUTDOWN_FAILED, "关闭ocsClient失败", e); + } + } + + /** + * 以下为测试使用 + */ + @VisibleForTesting + public String buildValue_test(Record record) { + return this.buildValue(record); + } + + @VisibleForTesting + public String buildKey_test(Record record) { + return this.buildKey(record); + } + + @VisibleForTesting + public void setIndexesFromUser(HashSet indexesFromUser) { + this.indexesFromUser = indexesFromUser; + } + + } +} diff --git a/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/CommonUtils.java b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/CommonUtils.java new file mode 100644 index 000000000..cf1f9630a --- /dev/null +++ b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/CommonUtils.java @@ -0,0 +1,15 @@ +package com.alibaba.datax.plugin.writer.ocswriter.utils; + +/** + * Time: 2015-05-12 15:02 + */ +public class CommonUtils { + + public static void sleepInMs(long time) { + try{ + Thread.sleep(time); + } catch (InterruptedException e) { + // + } + } +} diff --git a/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/ConfigurationChecker.java b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/ConfigurationChecker.java new file mode 100644 index 000000000..f0bf42714 --- /dev/null +++ b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/ConfigurationChecker.java @@ -0,0 +1,147 @@ +package com.alibaba.datax.plugin.writer.ocswriter.utils; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.writer.ocswriter.Key; +import com.google.common.annotations.VisibleForTesting; + +import net.spy.memcached.AddrUtil; +import net.spy.memcached.ConnectionFactoryBuilder; +import net.spy.memcached.MemcachedClient; +import net.spy.memcached.auth.AuthDescriptor; +import net.spy.memcached.auth.PlainCallbackHandler; + +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; + + +/** + * Time: 2015-05-07 16:48 + */ +public class ConfigurationChecker { + + public static void check(Configuration config) { + paramCheck(config); + hostReachableCheck(config); + } + + public enum WRITE_MODE { + set, + add, + replace, + append, + prepend + } + + private enum WRITE_FORMAT { + text + } + + /** + * 参数有效性基本检查 + */ + private static void paramCheck(Configuration config) { + String proxy = config.getString(Key.PROXY); + if (StringUtils.isBlank(proxy)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("ocs服务地址%s不能设置为空", Key.PROXY)); + } + String user = config.getString(Key.USER); + if (StringUtils.isBlank(user)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("访问ocs的用户%s不能设置为空", Key.USER)); + } + String password = config.getString(Key.PASSWORD); + if (StringUtils.isBlank(password)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("访问ocs的用户%s不能设置为空", Key.PASSWORD)); + } + + String port = config.getString(Key.PORT, "11211"); + if (StringUtils.isBlank(port)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("ocs端口%s不能设置为空", Key.PORT)); + } + + String indexes = config.getString(Key.INDEXES, "0"); + if (StringUtils.isBlank(indexes)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("当做key的列编号%s不能为空", Key.INDEXES)); + } + for (String index : indexes.split(",")) { + try { + if (Integer.parseInt(index) < 0) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("列编号%s必须为逗号分隔的非负整数", Key.INDEXES)); + } + } catch (NumberFormatException e) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("列编号%s必须为逗号分隔的非负整数", Key.INDEXES)); + } + } + + String writerMode = config.getString(Key.WRITE_MODE); + if (StringUtils.isBlank(writerMode)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("操作方式%s不能为空", Key.WRITE_MODE)); + } + if (!EnumUtils.isValidEnum(WRITE_MODE.class, writerMode.toLowerCase())) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("不支持操作方式%s,仅支持%s", writerMode, StringUtils.join(WRITE_MODE.values(), ","))); + } + + String writerFormat = config.getString(Key.WRITE_FORMAT, "text"); + if (StringUtils.isBlank(writerFormat)) { + throw DataXException.asDataXException(OcsWriterErrorCode.REQUIRED_VALUE, String.format("写入格式%s不能为空", Key.WRITE_FORMAT)); + } + if (!EnumUtils.isValidEnum(WRITE_FORMAT.class, writerFormat.toLowerCase())) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("不支持写入格式%s,仅支持%s", writerFormat, StringUtils.join(WRITE_FORMAT.values(), ","))); + } + + int expireTime = config.getInt(Key.EXPIRE_TIME, 0); + if (expireTime < 0) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("数据过期时间设置%s不能小于0", Key.EXPIRE_TIME)); + } + + int batchSiz = config.getInt(Key.BATCH_SIZE, 100); + if (batchSiz <= 0) { + throw DataXException.asDataXException(OcsWriterErrorCode.ILLEGAL_PARAM_VALUE, String.format("批量写入大小设置%s必须大于0", Key.BATCH_SIZE)); + } + //fieldDelimiter不需要检查,默认为\u0001 + } + + /** + * 检查ocs服务器网络是否可达 + */ + private static void hostReachableCheck(Configuration config) { + String proxy = config.getString(Key.PROXY); + String port = config.getString(Key.PORT); + String username = config.getString(Key.USER); + String password = config.getString(Key.PASSWORD); + AuthDescriptor ad = new AuthDescriptor(new String[] { "PLAIN" }, + new PlainCallbackHandler(username, password)); + try { + MemcachedClient client = new MemcachedClient( + new ConnectionFactoryBuilder() + .setProtocol( + ConnectionFactoryBuilder.Protocol.BINARY) + .setAuthDescriptor(ad).build(), + AddrUtil.getAddresses(proxy + ":" + port)); + client.get("for_check_connectivity"); + client.getVersions(); + if (client.getAvailableServers().isEmpty()) { + throw new RuntimeException( + "没有可用的Servers: getAvailableServers() -> is empty"); + } + client.shutdown(); + } catch (Exception e) { + throw DataXException.asDataXException( + OcsWriterErrorCode.HOST_UNREACHABLE, + String.format("OCS[%s]服务不可用", proxy), e); + } + } + + /** + * 以下为测试使用 + */ + @VisibleForTesting + public static void paramCheck_test(Configuration configuration) { + paramCheck(configuration); + } + + @VisibleForTesting + public static void hostReachableCheck_test(Configuration configuration) { + hostReachableCheck(configuration); + } +} diff --git a/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/OcsWriterErrorCode.java b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/OcsWriterErrorCode.java new file mode 100644 index 000000000..e67e746a5 --- /dev/null +++ b/ocswriter/src/main/java/com/alibaba/datax/plugin/writer/ocswriter/utils/OcsWriterErrorCode.java @@ -0,0 +1,34 @@ +package com.alibaba.datax.plugin.writer.ocswriter.utils; + +import com.alibaba.datax.common.spi.ErrorCode; + +/** + * Time: 2015-05-22 16:45 + */ +public enum OcsWriterErrorCode implements ErrorCode { + REQUIRED_VALUE("OcsWriterErrorCode-000", "参数不能为空"), + ILLEGAL_PARAM_VALUE("OcsWriterErrorCode-001", "参数不合法"), + HOST_UNREACHABLE("OcsWriterErrorCode-002", "服务不可用"), + OCS_INIT_ERROR("OcsWriterErrorCode-003", "初始化ocs client失败"), + DIRTY_RECORD("OcsWriterErrorCode-004", "脏数据"), + SHUTDOWN_FAILED("OcsWriterErrorCode-005", "关闭ocs client失败"), + COMMIT_FAILED("OcsWriterErrorCode-006", "提交数据到ocs失败"); + + private final String code; + private final String description; + + private OcsWriterErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return null; + } + + @Override + public String getDescription() { + return null; + } +} diff --git a/ocswriter/src/main/resources/plugin.json b/ocswriter/src/main/resources/plugin.json new file mode 100644 index 000000000..4874911a4 --- /dev/null +++ b/ocswriter/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "ocswriter", + "class": "com.alibaba.datax.plugin.writer.ocswriter.OcsWriter", + "description": "set|add|replace|append|prepend record into ocs.", + "developer": "alibaba" +} \ No newline at end of file diff --git a/ocswriter/src/main/resources/plugin_job_template.json b/ocswriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..d62f3c96c --- /dev/null +++ b/ocswriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,15 @@ +{ + "name": "ocswriter", + "parameter": { + "proxy": "", + "port": "", + "userName": "", + "password": "", + "writeMode": "", + "writeFormat": "", + "fieldDelimiter": "", + "expireTime": "", + "indexes": "", + "batchSize": "" + } +} \ No newline at end of file diff --git a/odpsreader/doc/odpsreader.md b/odpsreader/doc/odpsreader.md new file mode 100644 index 000000000..6c04d2632 --- /dev/null +++ b/odpsreader/doc/odpsreader.md @@ -0,0 +1,349 @@ +# DataX ODPSReader + + +--- + + +## 1 快速介绍 +ODPSReader 实现了从 ODPS读取数据的功能,有关ODPS请参看(http://wiki.aliyun-inc.com/projects/apsara/wiki/odps)。 在底层实现上,ODPSReader 根据你配置的 源头项目 / 表 / 分区 / 表字段 等信息,通过 `Tunnel` 从 ODPS 系统中读取数据。 + +
+ + 注意 1、如果你需要使用ODPSReader/Writer插件,由于 AccessId/AccessKey 解密的需要,请务必使用 JDK 1.6.32 及以上版本。JDK 安装事项,请联系 PE 处理 + 2、ODPSReader 不是通过 ODPS SQL (select ... from ... where ... )来抽取数据的 + 3、注意区分你要读取的表是线上环境还是线下环境 + 4、目前 DataX3 依赖的 SDK 版本是: + + com.aliyun.odps + odps-sdk-core-internal + 0.13.2 + + + +## 2 实现原理 +ODPSReader 支持读取分区表、非分区表,不支持读取虚拟视图。当要读取分区表时,需要指定出具体的分区配置,比如读取 t0 表,其分区为 pt=1,ds=hangzhou 那么你需要在配置中配置该值。当要读取非分区表时,你不能提供分区配置。表字段可以依序指定全部列,也可以指定部分列,或者调整列顺序,或者指定常量字段,但是表字段中不能指定分区列(分区列不是表字段)。 + + 注意:要特别注意 odpsServer、project、table、accessId、accessKey 的配置,因为直接影响到是否能够加载到你需要读取数据的表。很多权限问题都出现在这里。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 这里使用一份读出 ODPS 数据然后打印到屏幕的配置样板。 + +``` +{ + "job": { + "setting": { + "speed": { + "channel": 1 + } + }, + "content": [ + { + "reader": { + "name": "odpsreader", + "parameter": { + "accessId": "accessId", + "accessKey": "accessKey", + "project": "targetProjectName", + "table": "tableName", + "partition": [ + "pt=1,ds=hangzhou" + ], + "column": [ + "customer_id", + "nickname" + ], + "packageAuthorizedProject": "yourCurrentProjectName", + "splitMode": "record", + "odpsServer": "odpsServer" + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "fieldDelimiter": "\t", + "print": "true" + } + } + } + ] + } +} + +``` + + +### 3.2 参数说明 + +## 参数 + +* **accessId** + * 描述:ODPS系统登录ID
+ + * 必选:是
+ + * 默认值:无
+ +* **accessKey** + * 描述:ODPS系统登录Key
+ + * 必选:是
+ + * 默认值:无
+ +* **project** + + * 描述:读取数据表所在的 ODPS 项目名称(大小写不敏感)
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:读取数据表的表名称(大小写不敏感)
+ + * 必选:是
+ + * 默认值:无
+ +* **partition** + + * 描述:读取数据所在的分区信息,支持linux shell通配符,包括 * 表示0个或多个字符,?代表任意一个字符。例如现在有分区表 test,其存在 pt=1,ds=hangzhou pt=1,ds=shanghai pt=2,ds=hangzhou pt=2,ds=beijing 四个分区,如果你想读取 pt=1,ds=shanghai 这个分区的数据,那么你应该配置为: `"partition":["pt=1,ds=shanghai"]`; 如果你想读取 pt=1下的所有分区,那么你应该配置为: `"partition":["pt=1,ds=* "]`;如果你想读取整个 test 表的所有分区的数据,那么你应该配置为: `"partition":["pt=*,ds=*"]`
+ + * 必选:如果表为分区表,则必填。如果表为非分区表,则不能填写
+ + * 默认值:无
+ +* **column** + + * 描述:读取 odps 源头表的列信息。例如现在有表 test,其字段为:id,name,age 如果你想依次读取 id,name,age 那么你应该配置为: `"column":["id","name","age"]` 或者配置为:`"column"=["*"]` 这里 * 表示依次读取表的每个字段,但是我们不推荐你配置抽取字段为 * ,因为当你的表字段顺序调整、类型变更或者个数增减,你的任务就会存在源头表列和目的表列不能对齐的风险,会直接导致你的任务运行结果不正确甚至运行失败。如果你想依次读取 name,id 那么你应该配置为: `"coulumn":["name","id"]` 如果你想在源头抽取的字段中添加常量字段(以适配目标表的字段顺序),比如你想抽取的每一行数据值为 age 列对应的值,name列对应的值,常量日期值1988-08-08 08:08:08,id 列对应的值 那么你应该配置为:`"column":["age","name","'1988-08-08 08:08:08'","id"]` 即常量列首尾用符号`'` 包住即可,我们内部实现上识别常量是通过检查你配置的每一个字段,如果发现有字段首尾都有`'`,则认为其是常量字段,其实际值为去除`'` 之后的值。 + + 注意:ODPSReader 抽取数据表不是通过 ODPS 的 Select SQL 语句,所以不能在字段上指定函数,也不能指定分区字段名称(分区字段不属于表字段) + + * 必选:是
+ + * 默认值:无
+ +* **odpsServer** + + * 描述:源头表 所在 ODPS 系统的server 地址
+ + * 必选:是
+ + * 默认值:无
+ +* **tunnelServer** + + * 描述:源头表 所在 ODPS 系统的tunnel 地址
+ + * 必选:是,如果地址是对内的(含有"-inc")则可以不填
+ + * 默认值:无
+ +* **splitMode** + + * 描述:读取源头表时切分所需要的模式。默认值为 record,可不填,表示根据切分份数,按照记录数进行切分。如果你的任务目的端为 Mysql,并且是 Mysql 的多个表,那么根据现在 DataX 结构,你的源头表必须是分区表,并且每个分区依次对应目的端 Mysql 的多个分表,则此时应该配置为`"splitMode":"partition"`
+ + * 必选:否
+ + * 默认值:record
+ +* **accountProvider** [待定] + + * 描述:读取时使用的 ODPS 账号类型。目前支持 aliyun/taobao 两种类型。默认为 aliyun,可不填
+ + * 必选:否
+ + * 默认值:aliyun
+ +* **packageAuthorizedProject** + + * 描述:被package授权的project,即用户当前所在project
+ + * 必选:否
+ + * 默认值:无
+ +* **isCompress** + + * 描述:是否压缩读取,bool类型: "true"表示压缩, "false"标示不压缩
+ + * 必选:否
+ + * 默认值:"false" : 不压缩
+ +### 3.3 类型转换 + +下面列出 ODPSReader 读出类型与 DataX 内部类型的转换关系: + + +| ODPS 数据类型| DataX 内部类型 | +| -------- | ----- | +| BIGINT | Long | +| DOUBLE | Double | +| STRING | String | +| DATETIME | Date | +| Boolean | Bool | + + +## 4 性能报告(线上环境实测) + +### 4.1 环境准备 + +#### 4.1.1 数据特征 + +建表语句: + + use cdo_datasync; + create table datax3_odpswriter_perf_10column_1kb_00( + s_0 string, + bool_1 boolean, + bi_2 bigint, + dt_3 datetime, + db_4 double, + s_5 string, + s_6 string, + s_7 string, + s_8 string, + s_9 string + )PARTITIONED by (pt string,year string); + +单行记录类似于: + + s_0 : 485924f6ab7f272af361cd3f7f2d23e0d764942351#$%^&fdafdasfdas%%^(*&^^&* + bool_1 : true + bi_2 : 1696248667889 + dt_3 : 2013-07-0600: 00: 00 + db_4 : 3.141592653578 + s_5 : 100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209 + s_6 : 100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11fdsafdsfdsa209 + s_7 : 100DAFDSAFDSAHOFJDPSAWIFDISHAF;dsadsafdsahfdsajf;dsfdsa;FJDSAL;11209 + s_8 : 100dafdsafdsahofjdpsawifdishaf;DSADSAFDSAHFDSAJF;dsfdsa;fjdsal;11209 + s_9 : 12~!2345100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209 + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu : 24 Core Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz cache 15.36MB + 2. mem : 50GB + 3. net : 千兆双网卡 + 4. jvm : -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + 5. disc: DataX 数据不落磁盘,不统计此项 + +* 任务配置为: +``` +{ + "job": { + "setting": { + "speed": { + "channel": 1 + } + }, + "content": [ + { + "reader": { + "name": "odpsreader", + "parameter": { + "accessId": "******************************", + "accessKey": "*****************************", + "column": [ + "*" + ], + "partition": [ + "pt=20141010000000,year=2014" + ], + "odpsServer": "http://service.odps.aliyun-inc.com/api", + "project": "cdo_datasync", + "table": "datax3_odpswriter_perf_10column_1kb_00", + "tunnelServer": "http://dt.odps.cm11.aliyun-inc.com/" + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": false, + "column": [ + { + "value": "485924f6ab7f272af361cd3f7f2d23e0d764942351#$%^&fdafdasfdas%%^(*&^^&*" + }, + { + "value": "true", + "type": "bool" + }, + { + "value": "1696248667889", + "type": "long" + }, + { + "type": "date", + "value": "2013-07-06 00:00:00", + "dateFormat": "yyyy-mm-dd hh:mm:ss" + }, + { + "value": "3.141592653578", + "type": "double" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11fdsafdsfdsa209" + }, + { + "value": "100DAFDSAFDSAHOFJDPSAWIFDISHAF;dsadsafdsahfdsajf;dsfdsa;FJDSAL;11209" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;DSADSAFDSAHFDSAJF;dsfdsa;fjdsal;11209" + }, + { + "value": "12~!2345100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209" + } + ] + } + } + } + ] + } +} +``` + +### 4.2 测试报告 + + +| 并发任务数| DataX速度(Rec/s)|DataX流量(MB/S)|网卡流量(MB/S)|DataX运行负载| +|--------| --------|--------|--------|--------| +|1|117507|50.20|53.7|0.62| +|2|232976|99.54|108.1|0.99| +|4|387382|165.51|181.3|1.98| +|5|426054|182.03|202.2|2.35| +|6|434793|185.76|204.7|2.77| +|8|495904|211.87|230.2|2.86| +|16|501596|214.31|234.7|2.84| +|32|501577|214.30|234.7|2.99| +|64|501625|214.32|234.7|3.22| + +说明: + +1. OdpsReader 影响速度最主要的是channel数目,这里到达8时已经打满网卡,过多调大反而会影响系统性能。 +2. channel数目的选择,可以考虑odps表文件组织,可尝试合并小文件再进行同步调优。 + + +## 5 约束限制 + + + + +## FAQ(待补充) + +*** + +**Q: 你来问** + +A: 我来答。 + +*** + diff --git a/odpsreader/odpsreader.iml b/odpsreader/odpsreader.iml new file mode 100644 index 000000000..811ad6ab5 --- /dev/null +++ b/odpsreader/odpsreader.iml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/odpsreader/pom.xml b/odpsreader/pom.xml new file mode 100755 index 000000000..1cf43b32a --- /dev/null +++ b/odpsreader/pom.xml @@ -0,0 +1,118 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + + odpsreader + odpsreader + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + com.google.guava + guava + 16.0.1 + + + + com.aliyun.odps + odps-sdk-core + 0.19.3-public + + + + org.mockito + mockito-core + 1.8.5 + test + + + org.powermock + powermock-api-mockito + 1.4.10 + test + + + org.powermock + powermock-module-junit4 + 1.4.10 + test + + + + org.mockito + mockito-core + 1.8.5 + test + + + org.powermock + powermock-api-mockito + 1.4.10 + test + + + + org.powermock + powermock-module-junit4 + 1.4.10 + test + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/odpsreader/src/main/assembly/package.xml b/odpsreader/src/main/assembly/package.xml new file mode 100755 index 000000000..db659a179 --- /dev/null +++ b/odpsreader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/odpsreader + + + target/ + + odpsreader-0.0.1-SNAPSHOT.jar + + plugin/reader/odpsreader + + + + + + false + plugin/reader/odpsreader/libs + runtime + + + diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ColumnType.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ColumnType.java new file mode 100644 index 000000000..eb674a7f6 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ColumnType.java @@ -0,0 +1,31 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +public enum ColumnType { + PARTITION, NORMAL, CONSTANT, UNKNOWN, ; + + @Override + public String toString() { + switch (this) { + case PARTITION: + return "partition"; + case NORMAL: + return "normal"; + case CONSTANT: + return "constant"; + default: + return "unknown"; + } + } + + public static ColumnType asColumnType(String columnTypeString) { + if ("partition".equals(columnTypeString)) { + return PARTITION; + } else if ("normal".equals(columnTypeString)) { + return NORMAL; + } else if ("constant".equals(columnTypeString)) { + return CONSTANT; + } else { + return UNKNOWN; + } + } +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Constant.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Constant.java new file mode 100755 index 000000000..c3c674ddd --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Constant.java @@ -0,0 +1,35 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +public class Constant { + + public final static String START_INDEX = "startIndex"; + + public final static String STEP_COUNT = "stepCount"; + + public final static String SESSION_ID = "sessionId"; + + public final static String IS_PARTITIONED_TABLE = "isPartitionedTable"; + + public static final String DEFAULT_SPLIT_MODE = "record"; + + public static final String PARTITION_SPLIT_MODE = "partition"; + + public static final String DEFAULT_ACCOUNT_TYPE = "aliyun"; + + public static final String TAOBAO_ACCOUNT_TYPE = "taobao"; + + // 常量字段用COLUMN_CONSTANT_FLAG 首尾包住即可 + public final static String COLUMN_CONSTANT_FLAG = "'"; + + /** + * 以下是获取accesskey id 需要用到的常量值 + */ + public static final String SKYNET_ACCESSID = "SKYNET_ACCESSID"; + + public static final String SKYNET_ACCESSKEY = "SKYNET_ACCESSKEY"; + + public static final String PARTITION_COLUMNS = "partitionColumns"; + + public static final String PARSED_COLUMNS = "parsedColumns"; + +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Key.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Key.java new file mode 100755 index 000000000..9537cb939 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/Key.java @@ -0,0 +1,34 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +public class Key { + + public final static String ACCESS_ID = "accessId"; + + public final static String ACCESS_KEY = "accessKey"; + + public static final String PROJECT = "project"; + + public final static String TABLE = "table"; + + public final static String PARTITION = "partition"; + + public final static String ODPS_SERVER = "odpsServer"; + + // 线上环境不需要填写,线下环境必填 + public final static String TUNNEL_SERVER = "tunnelServer"; + + public final static String COLUMN = "column"; + + // 当值为:partition 则只切分到分区;当值为:record,则当按照分区切分后达不到adviceNum时,继续按照record切分 + public final static String SPLIT_MODE = "splitMode"; + + // 账号类型,默认为aliyun,也可能为taobao等其他类型 + public final static String ACCOUNT_TYPE = "accountType"; + + public final static String PACKAGE_AUTHORIZED_PROJECT = "packageAuthorizedProject"; + + public final static String IS_COMPRESS = "isCompress"; + + public final static String MAX_RETRY_TIME = "maxRetryTime"; + +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReader.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReader.java new file mode 100755 index 000000000..f5cf10ca2 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReader.java @@ -0,0 +1,390 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.FilterUtil; +import com.alibaba.datax.plugin.reader.odpsreader.util.IdAndKeyUtil; +import com.alibaba.datax.plugin.reader.odpsreader.util.OdpsSplitUtil; +import com.alibaba.datax.plugin.reader.odpsreader.util.OdpsUtil; +import com.aliyun.odps.*; +import com.aliyun.odps.tunnel.TableTunnel.DownloadSession; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class OdpsReader extends Reader { + public static class Job extends Reader.Job { + private static final Logger LOG = LoggerFactory + .getLogger(Job.class); + + private static boolean IS_DEBUG = LOG.isDebugEnabled(); + + private Configuration originalConfig; + private Odps odps; + private Table table; + + public void preCheck() { + this.init(); + } + + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + + //如果用户没有配置accessId/accessKey,尝试从环境变量获取 + String accountType = originalConfig.getString(Key.ACCOUNT_TYPE, Constant.DEFAULT_ACCOUNT_TYPE); + if (Constant.DEFAULT_ACCOUNT_TYPE.equalsIgnoreCase(accountType)) { + this.originalConfig = IdAndKeyUtil.parseAccessIdAndKey(this.originalConfig); + } + + //检查必要的参数配置 + OdpsUtil.checkNecessaryConfig(this.originalConfig); + //重试次数的配置检查 + OdpsUtil.dealMaxRetryTime(this.originalConfig); + + //确定切分模式 + dealSplitMode(this.originalConfig); + + this.odps = OdpsUtil.initOdps(this.originalConfig); + String tableName = this.originalConfig.getString(Key.TABLE); + String projectName = this.originalConfig.getString(Key.PROJECT); + + this.table = OdpsUtil.getTable(this.odps, projectName, tableName); + this.originalConfig.set(Constant.IS_PARTITIONED_TABLE, + OdpsUtil.isPartitionedTable(table)); + + boolean isVirtualView = this.table.isVirtualView(); + if (isVirtualView) { + throw DataXException.asDataXException(OdpsReaderErrorCode.VIRTUAL_VIEW_NOT_SUPPORT, + String.format("源头表:%s 是虚拟视图,DataX 不支持读取虚拟视图.", tableName)); + } + + this.dealPartition(this.table); + this.dealColumn(this.table); + } + + private void dealSplitMode(Configuration originalConfig) { + String splitMode = originalConfig.getString(Key.SPLIT_MODE, Constant.DEFAULT_SPLIT_MODE).trim(); + if (splitMode.equalsIgnoreCase(Constant.DEFAULT_SPLIT_MODE) || + splitMode.equalsIgnoreCase(Constant.PARTITION_SPLIT_MODE)) { + originalConfig.set(Key.SPLIT_MODE, splitMode); + } else { + throw DataXException.asDataXException(OdpsReaderErrorCode.SPLIT_MODE_ERROR, + String.format("您所配置的 splitMode:%s 不正确. splitMode 仅允许配置为 record 或者 partition.", splitMode)); + } + } + + /** + * 对分区的配置处理。最终效果是所有正则配置,完全展开成实际对应的分区配置。正则规则如下: + *

+ *

    + *
  1. 如果是分区表,则必须配置分区:可以配置为*,表示整表读取;也可以配置为分别列出要读取的叶子分区.
    TODO + * 未来会支持一些常用的分区正则筛选配置. 分区配置中,不能在分区所表示的数组中配置多个*,因为那样就是多次读取全表,无意义.
  2. + *
  3. 如果是非分区表,则不能配置分区值.
  4. + *
+ */ + private void dealPartition(Table table) { + List userConfiguredPartitions = this.originalConfig.getList( + Key.PARTITION, String.class); + + boolean isPartitionedTable = this.originalConfig.getBool(Constant.IS_PARTITIONED_TABLE); + List partitionColumns = new ArrayList(); + + if (isPartitionedTable) { + // 分区表,需要配置分区 + if (null == userConfiguredPartitions || userConfiguredPartitions.isEmpty()) { + throw DataXException.asDataXException(OdpsReaderErrorCode.PARTITION_ERROR, + String.format("分区信息没有配置.由于源头表:%s 为分区表, 所以您需要配置其抽取的表的分区信息. 格式形如:pt=hello,ds=hangzhou,请您参考此格式修改该配置项.", + table.getName())); + } else { + List allPartitions = OdpsUtil.getTableAllPartitions(table); + + if (null == allPartitions || allPartitions.isEmpty()) { + throw DataXException.asDataXException(OdpsReaderErrorCode.PARTITION_ERROR, + String.format("分区信息配置错误.源头表:%s 虽然为分区表, 但其实际分区值并不存在. 请确认源头表已经生成该分区,再进行数据抽取.", + table.getName())); + } + + List parsedPartitions = expandUserConfiguredPartition( + allPartitions, userConfiguredPartitions); + + if (null == parsedPartitions || parsedPartitions.isEmpty()) { + throw DataXException.asDataXException( + OdpsReaderErrorCode.PARTITION_ERROR, + String.format( + "分区配置错误,根据您所配置的分区没有匹配到源头表中的分区. 源头表所有分区是:[\n%s\n], 您配置的分区是:[\n%s\n]. 请您根据实际情况在作出修改. ", + StringUtils.join(allPartitions, "\n"), + StringUtils.join(userConfiguredPartitions, "\n"))); + } + this.originalConfig.set(Key.PARTITION, parsedPartitions); + + for (Column column : table.getSchema() + .getPartitionColumns()) { + partitionColumns.add(column.getName()); + } + } + } else { + // 非分区表,则不能配置分区 + if (null != userConfiguredPartitions + && !userConfiguredPartitions.isEmpty()) { + throw DataXException.asDataXException(OdpsReaderErrorCode.PARTITION_ERROR, + String.format("分区配置错误,源头表:%s 为非分区表, 您不能配置分区. 请您删除该配置项. ", table.getName())); + } + } + + this.originalConfig.set(Constant.PARTITION_COLUMNS, partitionColumns); + if (isPartitionedTable) { + LOG.info("{源头表:{} 的所有分区列是:[{}]}", table.getName(), + StringUtils.join(partitionColumns, ",")); + } + } + + private List expandUserConfiguredPartition( + List allPartitions, List userConfiguredPartitions) { + // 对odps 本身的所有分区进行特殊字符的处理 + List allStandardPartitions = OdpsUtil + .formatPartitions(allPartitions); + + // 对用户自身配置的所有分区进行特殊字符的处理 + List allStandardUserConfiguredPartitions = OdpsUtil + .formatPartitions(userConfiguredPartitions); + + /** + * 对配置的分区级数(深度)进行检查 + * (1)先检查用户配置的分区级数,自身级数是否相等 + * (2)检查用户配置的分区级数是否与源头表的的分区级数一样 + */ + String firstPartition = allStandardUserConfiguredPartitions.get(0); + int firstPartitionDepth = firstPartition.split(",").length; + + String comparedPartition = null; + int comparedPartitionDepth = -1; + for (int i = 1, len = allStandardUserConfiguredPartitions.size(); i < len; i++) { + comparedPartition = allStandardUserConfiguredPartitions.get(i); + comparedPartitionDepth = comparedPartition.split(",").length; + if (comparedPartitionDepth != firstPartitionDepth) { + throw DataXException.asDataXException(OdpsReaderErrorCode.PARTITION_ERROR, + String.format("分区配置错误, 您所配置的分区级数和该表的实际情况不一致, 比如分区:[%s] 是 %s 级分区, 而分区:[%s] 是 %s 级分区. DataX 是通过英文逗号判断您所配置的分区级数的. 正确的格式形如\"pt=${bizdate}, type=0\" ,请您参考示例修改该配置项. ", + firstPartition, firstPartitionDepth, comparedPartition, comparedPartitionDepth)); + } + } + + int tableOriginalPartitionDepth = allStandardPartitions.get(0).split(",").length; + if (firstPartitionDepth != tableOriginalPartitionDepth) { + throw DataXException.asDataXException(OdpsReaderErrorCode.PARTITION_ERROR, + String.format("分区配置错误, 您所配置的分区:%s 的级数:%s 与您要读取的 ODPS 源头表的分区级数:%s 不相等. DataX 是通过英文逗号判断您所配置的分区级数的.正确的格式形如\"pt=${bizdate}, type=0\" ,请您参考示例修改该配置项.", + firstPartition, firstPartitionDepth, tableOriginalPartitionDepth)); + } + + List retPartitions = FilterUtil.filterByRegulars(allStandardPartitions, + allStandardUserConfiguredPartitions); + + return retPartitions; + } + + private void dealColumn(Table table) { + // 用户配置的 column 之前已经确保其不为空 + List userConfiguredColumns = this.originalConfig.getList( + Key.COLUMN, String.class); + + List allColumns = OdpsUtil.getTableAllColumns(table); + List allNormalColumns = OdpsUtil + .getTableOriginalColumnNameList(allColumns); + + StringBuilder columnMeta = new StringBuilder(); + for (Column column : allColumns) { + columnMeta.append(column.getName()).append(":").append(column.getType()).append(","); + } + columnMeta.setLength(columnMeta.length() - 1); + + LOG.info("源头表:{} 的所有字段是:[{}]", table.getName(), columnMeta.toString()); + + if (1 == userConfiguredColumns.size() + && "*".equals(userConfiguredColumns.get(0))) { + LOG.warn("这是一条警告信息,您配置的 ODPS 读取的列为*,这是不推荐的行为,因为当您的表字段个数、类型有变动时,可能影响任务正确性甚至会运行出错. 建议您把所有需要抽取的列都配置上. "); + this.originalConfig.set(Key.COLUMN, allNormalColumns); + } + + userConfiguredColumns = this.originalConfig.getList( + Key.COLUMN, String.class); + + /** + * warn: 字符串常量需要与表原生字段tableOriginalColumnNameList 分开存放 demo: + * ["id","'id'","name"] + */ + List allPartitionColumns = this.originalConfig.getList( + Constant.PARTITION_COLUMNS, String.class); + List> parsedColumns = OdpsUtil + .parseColumns(allNormalColumns, allPartitionColumns, + userConfiguredColumns); + + this.originalConfig.set(Constant.PARSED_COLUMNS, parsedColumns); + + StringBuilder sb = new StringBuilder(); + sb.append("[ "); + for (int i = 0, len = parsedColumns.size(); i < len; i++) { + Pair pair = parsedColumns.get(i); + sb.append(String.format(" %s : %s", pair.getLeft(), + pair.getRight())); + if (i != len - 1) { + sb.append(","); + } + } + sb.append(" ]"); + LOG.info("parsed column details: {} .", sb.toString()); + } + + + @Override + public void prepare() { + } + + @Override + public List split(int adviceNumber) { + return OdpsSplitUtil.doSplit(this.originalConfig, this.odps, adviceNumber); + } + + @Override + public void post() { + } + + @Override + public void destroy() { + } + } + + public static class Task extends Reader.Task { + private static final Logger LOG = LoggerFactory.getLogger(Task.class); + private Configuration readerSliceConf; + + private String tunnelServer; + private Odps odps = null; + private Table table = null; + private String projectName = null; + private String tableName = null; + private boolean isPartitionedTable; + private String sessionId; + private boolean isCompress; + + @Override + public void init() { + this.readerSliceConf = super.getPluginJobConf(); + this.tunnelServer = this.readerSliceConf.getString( + Key.TUNNEL_SERVER, null); + + this.odps = OdpsUtil.initOdps(this.readerSliceConf); + this.projectName = this.readerSliceConf.getString(Key.PROJECT); + this.tableName = this.readerSliceConf.getString(Key.TABLE); + this.table = OdpsUtil.getTable(this.odps, projectName, tableName); + this.isPartitionedTable = this.readerSliceConf + .getBool(Constant.IS_PARTITIONED_TABLE); + this.sessionId = this.readerSliceConf.getString(Constant.SESSION_ID, null); + + + + this.isCompress = this.readerSliceConf.getBool(Key.IS_COMPRESS, false); + + // sessionId 为空的情况是:切分级别只到 partition 的情况 + if (StringUtils.isBlank(this.sessionId)) { + DownloadSession session = OdpsUtil.createMasterSessionForPartitionedTable(odps, + tunnelServer, projectName, tableName, this.readerSliceConf.getString(Key.PARTITION)); + this.sessionId = session.getId(); + } + + LOG.info("sessionId:{}", this.sessionId); + } + + @Override + public void prepare() { + } + + @Override + public void startRead(RecordSender recordSender) { + DownloadSession downloadSession = null; + String partition = this.readerSliceConf.getString(Key.PARTITION); + + if (this.isPartitionedTable) { + downloadSession = OdpsUtil.getSlaveSessionForPartitionedTable(this.odps, this.sessionId, + this.tunnelServer, this.projectName, this.tableName, partition); + } else { + downloadSession = OdpsUtil.getSlaveSessionForNonPartitionedTable(this.odps, this.sessionId, + this.tunnelServer, this.projectName, this.tableName); + } + + long start = this.readerSliceConf.getLong(Constant.START_INDEX, 0); + long count = this.readerSliceConf.getLong(Constant.STEP_COUNT, + downloadSession.getRecordCount()); + + if (count > 0) { + LOG.info(String.format( + "Begin to read ODPS table:%s, partition:%s, startIndex:%s, count:%s.", + this.tableName, partition, start, count)); + } else if (count == 0) { + LOG.warn(String.format("源头表:%s 的分区:%s 没有内容可抽取, 请您知晓.", + this.tableName, partition)); + return; + } else { + throw DataXException.asDataXException(OdpsReaderErrorCode.READ_DATA_FAIL, + String.format("源头表:%s 的分区:%s 读取行数为负数, 请联系 ODPS 管理员查看表状态!", + this.tableName, partition)); + } + + TableSchema tableSchema = this.table.getSchema(); + Set allColumns = new HashSet(); + allColumns.addAll(tableSchema.getColumns()); + allColumns.addAll(tableSchema.getPartitionColumns()); + + Map columnTypeMap = new HashMap(); + for (Column column : allColumns) { + columnTypeMap.put(column.getName(), column.getType()); + } + + try { + List parsedColumnsTmp = this.readerSliceConf + .getListConfiguration(Constant.PARSED_COLUMNS); + List> parsedColumns = new ArrayList>(); + for (int i = 0; i < parsedColumnsTmp.size(); i++) { + Configuration eachColumnConfig = parsedColumnsTmp.get(i); + String columnName = eachColumnConfig.getString("left"); + ColumnType columnType = ColumnType + .asColumnType(eachColumnConfig.getString("right")); + parsedColumns.add(new MutablePair( + columnName, columnType)); + + } + ReaderProxy readerProxy = new ReaderProxy(recordSender, downloadSession, + columnTypeMap, parsedColumns, partition, this.isPartitionedTable, + start, count, this.isCompress); + + readerProxy.doRead(); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.READ_DATA_FAIL, + String.format("源头表:%s 的分区:%s 读取失败, 请联系 ODPS 管理员查看错误详情.", this.tableName, partition), e); + } + + } + + + @Override + public void post() { + } + + @Override + public void destroy() { + } + + } +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReaderErrorCode.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReaderErrorCode.java new file mode 100755 index 000000000..cdda6ac86 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/OdpsReaderErrorCode.java @@ -0,0 +1,60 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum OdpsReaderErrorCode implements ErrorCode { + REQUIRED_VALUE("OdpsReader-00", "您缺失了必须填写的参数值."), + ILLEGAL_VALUE("OdpsReader-01", "您配置的值不合法."), + CREATE_DOWNLOADSESSION_FAIL("OdpsReader-03", "创建 ODPS 的 downloadSession 失败."), + GET_DOWNLOADSESSION_FAIL("OdpsReader-04", "获取 ODPS 的 downloadSession 失败."), + READ_DATA_FAIL("OdpsReader-05", "读取 ODPS 源头表失败."), + GET_ID_KEY_FAIL("OdpsReader-06", "获取 accessId/accessKey 失败."), + + ODPS_READ_EXCEPTION("OdpsReader-07", "读取 odps 异常"), + OPEN_RECORD_READER_FAILED("OdpsReader-08", "打开 recordReader 失败."), + + ODPS_PROJECT_NOT_FOUNT("OdpsReader-10", "您配置的值不合法, odps project 不存在."), //ODPS-0420111: Project not found + + ODPS_TABLE_NOT_FOUNT("OdpsReader-12", "您配置的值不合法, odps table 不存在."), // ODPS-0130131:Table not found + + ODPS_ACCESS_KEY_ID_NOT_FOUND("OdpsReader-13", "您配置的值不合法, odps accessId,accessKey 不存在."), //ODPS-0410051:Invalid credentials - accessKeyId not found + + ODPS_ACCESS_KEY_INVALID("OdpsReader-14", "您配置的值不合法, odps accessKey 错误."), //ODPS-0410042:Invalid signature value - User signature dose not match + + ODPS_ACCESS_DENY("OdpsReader-15", "拒绝访问, 您不在 您配置的 project 中."), //ODPS-0420095: Access Denied - Authorization Failed [4002], You doesn't exist in project + + + + SPLIT_MODE_ERROR("OdpsReader-30", "splitMode配置错误."), + + ACCOUNT_TYPE_ERROR("OdpsReader-31", "odps 账号类型错误."), + + VIRTUAL_VIEW_NOT_SUPPORT("OdpsReader-32", "Datax 不支持 读取虚拟视图."), + + PARTITION_ERROR("OdpsReader-33", "分区配置错误."), + + ; + private final String code; + private final String description; + + private OdpsReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ReaderProxy.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ReaderProxy.java new file mode 100755 index 000000000..8e069ef56 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/ReaderProxy.java @@ -0,0 +1,281 @@ +package com.alibaba.datax.plugin.reader.odpsreader; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.plugin.reader.odpsreader.util.OdpsUtil; +import com.aliyun.odps.OdpsType; +import com.aliyun.odps.data.Record; +import com.aliyun.odps.data.RecordReader; +import com.aliyun.odps.tunnel.TableTunnel; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.ParseException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ReaderProxy { + private static final Logger LOG = LoggerFactory + .getLogger(ReaderProxy.class); + private static boolean IS_DEBUG = LOG.isDebugEnabled(); + + private RecordSender recordSender; + private TableTunnel.DownloadSession downloadSession; + private Map columnTypeMap; + private List> parsedColumns; + private String partition; + private boolean isPartitionTable; + + private long start; + private long count; + private boolean isCompress; + + public ReaderProxy(RecordSender recordSender, TableTunnel.DownloadSession downloadSession, + Map columnTypeMap, + List> parsedColumns, String partition, + boolean isPartitionTable, long start, long count, boolean isCompress) { + this.recordSender = recordSender; + this.downloadSession = downloadSession; + this.columnTypeMap = columnTypeMap; + this.parsedColumns = parsedColumns; + this.partition = partition; + this.isPartitionTable = isPartitionTable; + this.start = start; + this.count = count; + this.isCompress = isCompress; + } + + // warn: odps 分区列和正常列不能重名, 所有列都不不区分大小写 + public void doRead() { + try { + LOG.info("start={}, count={}",start, count); + //RecordReader recordReader = downloadSession.openRecordReader(start, count, isCompress); + RecordReader recordReader = OdpsUtil.getRecordReader(downloadSession, start, count, isCompress); + + Record odpsRecord; + Map partitionMap = this + .parseCurrentPartitionValue(); + + int retryTimes = 1; + while (true) { + try { + odpsRecord = recordReader.read(); + } catch(Exception e) { + //odps read 异常后重试10次 + LOG.warn("warn : odps read exception: {}", e.getMessage()); + if(retryTimes < 10) { + try { + Thread.sleep(2000); + } catch (InterruptedException ignored) { + } + recordReader = downloadSession.openRecordReader(start, count, isCompress); + LOG.warn("odps-read-exception, 重试第{}次", retryTimes); + retryTimes++; + continue; + } else { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_READ_EXCEPTION, e); + } + } + //记录已经读取的点 + start++; + count--; + + if (odpsRecord != null) { + + com.alibaba.datax.common.element.Record dataXRecord = recordSender + .createRecord(); + // warn: for PARTITION||NORMAL columnTypeMap's key + // sets(columnName) is big than parsedColumns's left + // sets(columnName), always contain + for (Pair pair : this.parsedColumns) { + String columnName = pair.getLeft(); + switch (pair.getRight()) { + case PARTITION: + String partitionColumnValue = this + .getPartitionColumnValue(partitionMap, + columnName); + this.odpsColumnToDataXField(odpsRecord, dataXRecord, + this.columnTypeMap.get(columnName), + partitionColumnValue, true); + break; + case NORMAL: + this.odpsColumnToDataXField(odpsRecord, dataXRecord, + this.columnTypeMap.get(columnName), columnName, + false); + break; + case CONSTANT: + dataXRecord.addColumn(new StringColumn(columnName)); + break; + default: + break; + } + } + recordSender.sendToWriter(dataXRecord); + } else { + break; + } + } + //fixed, 避免recordReader.close失败,跟鸣天确认过,可以不用关闭RecordReader + try { + recordReader.close(); + } catch (Exception e) { + LOG.warn("recordReader close exception", e); + } + } catch (DataXException e) { + throw e; + } catch (Exception e) { + // warn: if dirty + throw DataXException.asDataXException( + OdpsReaderErrorCode.READ_DATA_FAIL, e); + } + } + + private Map parseCurrentPartitionValue() { + Map partitionMap = new HashMap(); + if (this.isPartitionTable) { + String[] splitedPartition = this.partition.split(","); + for (String eachPartition : splitedPartition) { + String[] partitionDetail = eachPartition.split("="); + // warn: check partition like partition=1 + if (2 != partitionDetail.length) { + throw DataXException + .asDataXException( + OdpsReaderErrorCode.ILLEGAL_VALUE, + String.format( + "您的分区 [%s] 解析出现错误,解析后正确的配置方式类似为 [ pt=1,dt=1 ].", + eachPartition)); + } + // warn: translate to lower case, it's more comfortable to + // compare whit user's input columns + String partitionName = partitionDetail[0].toLowerCase(); + String partitionValue = partitionDetail[1]; + partitionMap.put(partitionName, partitionValue); + } + } + if (IS_DEBUG) { + LOG.debug(String.format("partition value details: %s", + com.alibaba.fastjson.JSON.toJSONString(partitionMap))); + } + return partitionMap; + } + + private String getPartitionColumnValue(Map partitionMap, + String partitionColumnName) { + // warn: to lower case + partitionColumnName = partitionColumnName.toLowerCase(); + // it's will never happen, but add this checking + if (!partitionMap.containsKey(partitionColumnName)) { + String errorMessage = String.format( + "表所有分区信息为: %s 其中找不到 [%s] 对应的分区值.", + com.alibaba.fastjson.JSON.toJSONString(partitionMap), + partitionColumnName); + throw DataXException.asDataXException( + OdpsReaderErrorCode.READ_DATA_FAIL, errorMessage); + } + return partitionMap.get(partitionColumnName); + } + + /** + * TODO warn: odpsRecord 的 String 可能获取出来的是 binary + * + * warn: there is no dirty data in reader plugin, so do not handle dirty + * data with TaskPluginCollector + * + * warn: odps only support BIGINT && String partition column actually + * + * @param odpsRecord + * every line record of odps table + * @param dataXRecord + * every datax record, to be send to writer. method getXXX() case sensitive + * @param type + * odps column type + * @param columnNameValue + * for partition column it's column value, for normal column it's + * column name + * @param isPartitionColumn + * true means partition column and false means normal column + * */ + private void odpsColumnToDataXField(Record odpsRecord, + com.alibaba.datax.common.element.Record dataXRecord, OdpsType type, + String columnNameValue, boolean isPartitionColumn) { + switch (type) { + case BIGINT: { + if (isPartitionColumn) { + dataXRecord.addColumn(new LongColumn(columnNameValue)); + } else { + dataXRecord.addColumn(new LongColumn(odpsRecord + .getBigint(columnNameValue))); + } + break; + } + case BOOLEAN: { + if (isPartitionColumn) { + dataXRecord.addColumn(new BoolColumn(columnNameValue)); + } else { + dataXRecord.addColumn(new BoolColumn(odpsRecord + .getBoolean(columnNameValue))); + } + break; + } + case DATETIME: { + if (isPartitionColumn) { + try { + dataXRecord.addColumn(new DateColumn(ColumnCast + .string2Date(new StringColumn(columnNameValue)))); + } catch (ParseException e) { + LOG.error(String.format("", this.partition)); + String errMessage = String.format( + "您读取分区 [%s] 出现日期转换异常, 日期的字符串表示为 [%s].", + this.partition, columnNameValue); + LOG.error(errMessage); + throw DataXException.asDataXException( + OdpsReaderErrorCode.READ_DATA_FAIL, errMessage, e); + } + } else { + dataXRecord.addColumn(new DateColumn(odpsRecord + .getDatetime(columnNameValue))); + } + + break; + } + case DOUBLE: { + if (isPartitionColumn) { + dataXRecord.addColumn(new DoubleColumn(columnNameValue)); + } else { + dataXRecord.addColumn(new DoubleColumn(odpsRecord + .getDouble(columnNameValue))); + } + break; + } + case DECIMAL: { + if(isPartitionColumn) { + dataXRecord.addColumn(new DoubleColumn(columnNameValue)); + } else { + dataXRecord.addColumn(new DoubleColumn(odpsRecord.getDecimal(columnNameValue))); + } + break; + } + case STRING: { + if (isPartitionColumn) { + dataXRecord.addColumn(new StringColumn(columnNameValue)); + } else { + dataXRecord.addColumn(new StringColumn(odpsRecord + .getString(columnNameValue))); + } + break; + } + default: + throw DataXException + .asDataXException( + OdpsReaderErrorCode.ILLEGAL_VALUE, + String.format( + "DataX 抽取 ODPS 数据不支持字段类型为:[%s]. 目前支持抽取的字段类型有:bigint, boolean, datetime, double, decimal, string. " + + "您可以选择不抽取 DataX 不支持的字段或者联系 ODPS 管理员寻求帮助.", + type)); + } + } + +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/DESCipher.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/DESCipher.java new file mode 100644 index 000000000..dad82d501 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/DESCipher.java @@ -0,0 +1,355 @@ +/** + * (C) 2010-2014 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.plugin.reader.odpsreader.util; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import java.security.SecureRandom; + +/** + *   * DES加解密,支持与delphi交互(字符串编码需统一为UTF-8) + * + *   * + * + *   * @author wym + * + *    + */ + +public class DESCipher { + + /** + *   * 密钥 + * + *    + */ + + public static final String KEY = "u4Gqu4Z8"; + + private final static String DES = "DES"; + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @param key + * + *   * 密钥,长度必须是8的倍数 + * + *   * @return 密文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] encrypt(byte[] src, byte[] key) throws Exception { + + // DES算法要求有一个可信任的随机数源 + + SecureRandom sr = new SecureRandom(); + + // 从原始密匙数据创建DESKeySpec对象 + + DESKeySpec dks = new DESKeySpec(key); + + // 创建一个密匙工厂,然后用它把DESKeySpec转换成 + + // 一个SecretKey对象 + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); + + SecretKey securekey = keyFactory.generateSecret(dks); + + // Cipher对象实际完成加密操作 + + Cipher cipher = Cipher.getInstance(DES); + + // 用密匙初始化Cipher对象 + + cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); + + // 现在,获取数据并加密 + + // 正式执行加密操作 + + return cipher.doFinal(src); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @param key + * + *   * 密钥,长度必须是8的倍数 + * + *   * @return 明文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] decrypt(byte[] src, byte[] key) throws Exception { + + // DES算法要求有一个可信任的随机数源 + + SecureRandom sr = new SecureRandom(); + + // 从原始密匙数据创建一个DESKeySpec对象 + + DESKeySpec dks = new DESKeySpec(key); + + // 创建一个密匙工厂,然后用它把DESKeySpec对象转换成 + + // 一个SecretKey对象 + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); + + SecretKey securekey = keyFactory.generateSecret(dks); + + // Cipher对象实际完成解密操作 + + Cipher cipher = Cipher.getInstance(DES); + + // 用密匙初始化Cipher对象 + + cipher.init(Cipher.DECRYPT_MODE, securekey, sr); + + // 现在,获取数据并解密 + + // 正式执行解密操作 + + return cipher.doFinal(src); + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @return 密文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] encrypt(byte[] src) throws Exception { + + return encrypt(src, KEY.getBytes()); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @return 明文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] decrypt(byte[] src) throws Exception { + + return decrypt(src, KEY.getBytes()); + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字符串) + * + *   * @return 密文(16进制字符串) + * + *   * @throws Exception + * + *    + */ + + public final static String encrypt(String src) { + + try { + + return byte2hex(encrypt(src.getBytes(), KEY.getBytes())); + + } catch (Exception e) { + + e.printStackTrace(); + + } + + return null; + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字符串) + * + *   * @return 明文(字符串) + * + *   * @throws Exception + * + *    + */ + + public final static String decrypt(String src) { + try { + + return new String(decrypt(hex2byte(src.getBytes()), KEY.getBytes())); + + } catch (Exception e) { + + e.printStackTrace(); + + } + + return null; + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @return 密文(16进制字符串) + * + *   * @throws Exception + * + *    + */ + + public static String encryptToString(byte[] src) throws Exception { + + return encrypt(new String(src)); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @return 明文(字符串) + * + *   * @throws Exception + * + *    + */ + + public static String decryptToString(byte[] src) throws Exception { + + return decrypt(new String(src)); + + } + + public static String byte2hex(byte[] b) { + + String hs = ""; + + String stmp = ""; + + for (int n = 0; n < b.length; n++) { + + stmp = (Integer.toHexString(b[n] & 0XFF)); + + if (stmp.length() == 1) + + hs = hs + "0" + stmp; + + else + + hs = hs + stmp; + + } + + return hs.toUpperCase(); + + } + + public static byte[] hex2byte(byte[] b) { + + if ((b.length % 2) != 0) + + throw new IllegalArgumentException("长度不是偶数"); + + byte[] b2 = new byte[b.length / 2]; + + for (int n = 0; n < b.length; n += 2) { + + String item = new String(b, n, 2); + + b2[n / 2] = (byte) Integer.parseInt(item, 16); + + } + return b2; + + } + + /* + * public static void main(String[] args) { try { String src = "cheetah"; + * String crypto = DESCipher.encrypt(src); System.out.println("密文[" + src + + * "]:" + crypto); System.out.println("解密后:" + DESCipher.decrypt(crypto)); } + * catch (Exception e) { e.printStackTrace(); } } + */ +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/IdAndKeyUtil.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/IdAndKeyUtil.java new file mode 100644 index 000000000..faa90a987 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/IdAndKeyUtil.java @@ -0,0 +1,85 @@ +/** + * (C) 2010-2014 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.plugin.reader.odpsreader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.reader.odpsreader.Constant; +import com.alibaba.datax.plugin.reader.odpsreader.Key; +import com.alibaba.datax.plugin.reader.odpsreader.OdpsReaderErrorCode; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class IdAndKeyUtil { + private static Logger LOG = LoggerFactory.getLogger(IdAndKeyUtil.class); + + public static Configuration parseAccessIdAndKey(Configuration originalConfig) { + String accessId = originalConfig.getString(Key.ACCESS_ID); + String accessKey = originalConfig.getString(Key.ACCESS_KEY); + + // 只要 accessId,accessKey 二者配置了一个,就理解为是用户本意是要直接手动配置其 accessid/accessKey + if (StringUtils.isNotBlank(accessId) || StringUtils.isNotBlank(accessKey)) { + LOG.info("Try to get accessId/accessKey from your config."); + //通过如下语句,进行检查是否确实配置了 + accessId = originalConfig.getNecessaryValue(Key.ACCESS_ID, OdpsReaderErrorCode.REQUIRED_VALUE); + accessKey = originalConfig.getNecessaryValue(Key.ACCESS_KEY, OdpsReaderErrorCode.REQUIRED_VALUE); + //检查完毕,返回即可 + return originalConfig; + } else { + Map envProp = System.getenv(); + return getAccessIdAndKeyFromEnv(originalConfig, envProp); + } + } + + private static Configuration getAccessIdAndKeyFromEnv(Configuration originalConfig, + Map envProp) { + String accessId = null; + String accessKey = null; + + String skynetAccessID = envProp.get(Constant.SKYNET_ACCESSID); + String skynetAccessKey = envProp.get(Constant.SKYNET_ACCESSKEY); + + if (StringUtils.isNotBlank(skynetAccessID) + || StringUtils.isNotBlank(skynetAccessKey)) { + /** + * 环境变量中,如果存在SKYNET_ACCESSID/SKYNET_ACCESSKEy(只要有其中一个变量,则认为一定是两个都存在的!), + * 则使用其值作为odps的accessId/accessKey(会解密) + */ + + LOG.info("Try to get accessId/accessKey from environment."); + accessId = skynetAccessID; + accessKey = DESCipher.decrypt(skynetAccessKey); + if (StringUtils.isNotBlank(accessKey)) { + originalConfig.set(Key.ACCESS_ID, accessId); + originalConfig.set(Key.ACCESS_KEY, accessKey); + LOG.info("Get accessId/accessKey from environment variables successfully."); + } else { + throw DataXException.asDataXException(OdpsReaderErrorCode.GET_ID_KEY_FAIL, + String.format("从环境变量中获取accessId/accessKey 失败, accessId=[%s]", accessId)); + } + } else { + // 无处获取(既没有配置在作业中,也没用在环境变量中) + throw DataXException.asDataXException(OdpsReaderErrorCode.GET_ID_KEY_FAIL, + "无法获取到accessId/accessKey. 它们既不存在于您的配置中,也不存在于环境变量中."); + } + + return originalConfig; + } +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsExceptionMsg.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsExceptionMsg.java new file mode 100644 index 000000000..35ac82214 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsExceptionMsg.java @@ -0,0 +1,18 @@ +package com.alibaba.datax.plugin.reader.odpsreader.util; + +/** + * Created by hongjiao.hj on 2015/6/9. + */ +public class OdpsExceptionMsg { + + public static final String ODPS_PROJECT_NOT_FOUNT = "ODPS-0420111: Project not found"; + + public static final String ODPS_TABLE_NOT_FOUNT = "ODPS-0130131:Table not found"; + + public static final String ODPS_ACCESS_KEY_ID_NOT_FOUND = "ODPS-0410051:Invalid credentials - accessKeyId not found"; + + public static final String ODPS_ACCESS_KEY_INVALID = "ODPS-0410042:Invalid signature value - User signature dose not match"; + + public static final String ODPS_ACCESS_DENY = "ODPS-0420095: Access Denied - Authorization Failed [4002], You doesn't exist in project"; + +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsSplitUtil.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsSplitUtil.java new file mode 100755 index 000000000..b7f4f1aaf --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsSplitUtil.java @@ -0,0 +1,168 @@ +package com.alibaba.datax.plugin.reader.odpsreader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.RangeSplitUtil; +import com.alibaba.datax.plugin.reader.odpsreader.Constant; +import com.alibaba.datax.plugin.reader.odpsreader.Key; +import com.alibaba.datax.plugin.reader.odpsreader.OdpsReaderErrorCode; +import com.aliyun.odps.Odps; +import com.aliyun.odps.tunnel.TableTunnel.DownloadSession; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public final class OdpsSplitUtil { + + public static List doSplit(Configuration originalConfig, Odps odps, + int adviceNum) { + boolean isPartitionedTable = originalConfig.getBool(Constant.IS_PARTITIONED_TABLE); + if (isPartitionedTable) { + // 分区表 + return splitPartitionedTable(odps, originalConfig, adviceNum); + } else { + // 非分区表 + return splitForNonPartitionedTable(odps, adviceNum, originalConfig); + } + + } + + private static List splitPartitionedTable(Odps odps, Configuration originalConfig, + int adviceNum) { + List splittedConfigs = new ArrayList(); + + List partitions = originalConfig.getList(Key.PARTITION, + String.class); + + if (null == partitions || partitions.isEmpty()) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ILLEGAL_VALUE, + "您所配置的分区不能为空白."); + } + + //splitMode 默认为 record + String splitMode = originalConfig.getString(Key.SPLIT_MODE); + Configuration tempConfig = null; + if (partitions.size() > adviceNum || Constant.PARTITION_SPLIT_MODE.equals(splitMode)) { + // 此时不管 splitMode 是什么,都不需要再进行切分了 + // 注意:此处没有把 sessionId 设置到 config 中去,所以后续在 task 中获取 sessionId 时,需要针对这种情况重新创建 sessionId + for (String onePartition : partitions) { + tempConfig = originalConfig.clone(); + tempConfig.set(Key.PARTITION, onePartition); + splittedConfigs.add(tempConfig); + } + + return splittedConfigs; + } else { + // 还需要计算对每个分区,切分份数等信息 + int eachPartitionShouldSplittedNumber = calculateEachPartitionShouldSplittedNumber( + adviceNum, partitions.size()); + + for (String onePartition : partitions) { + List configs = splitOnePartition(odps, + onePartition, eachPartitionShouldSplittedNumber, + originalConfig); + splittedConfigs.addAll(configs); + } + + return splittedConfigs; + } + } + + private static int calculateEachPartitionShouldSplittedNumber( + int adviceNumber, int partitionNumber) { + double tempNum = 1.0 * adviceNumber / partitionNumber; + + return (int) Math.ceil(tempNum); + } + + private static List splitForNonPartitionedTable(Odps odps, + int adviceNum, Configuration sliceConfig) { + List params = new ArrayList(); + + String tunnelServer = sliceConfig.getString(Key.TUNNEL_SERVER); + String tableName = sliceConfig.getString(Key.TABLE); + + String projectName = sliceConfig.getString(Key.PROJECT); + + DownloadSession session = OdpsUtil.createMasterSessionForNonPartitionedTable(odps, + tunnelServer, projectName, tableName); + + String id = session.getId(); + long count = session.getRecordCount(); + + List> splitResult = splitRecordCount(count, adviceNum); + + for (Pair pair : splitResult) { + Configuration iParam = sliceConfig.clone(); + iParam.set(Constant.SESSION_ID, id); + iParam.set(Constant.START_INDEX, pair.getLeft().longValue()); + iParam.set(Constant.STEP_COUNT, pair.getRight().longValue()); + + params.add(iParam); + } + + return params; + } + + private static List splitOnePartition(Odps odps, + String onePartition, int adviceNum, Configuration sliceConfig) { + List params = new ArrayList(); + + String tunnelServer = sliceConfig.getString(Key.TUNNEL_SERVER); + String tableName = sliceConfig.getString(Key.TABLE); + + String projectName = sliceConfig.getString(Key.PROJECT); + + DownloadSession session = OdpsUtil.createMasterSessionForPartitionedTable(odps, + tunnelServer, projectName, tableName, onePartition); + + String id = session.getId(); + long count = session.getRecordCount(); + + List> splitResult = splitRecordCount(count, adviceNum); + + for (Pair pair : splitResult) { + Configuration iParam = sliceConfig.clone(); + iParam.set(Key.PARTITION, onePartition); + iParam.set(Constant.SESSION_ID, id); + iParam.set(Constant.START_INDEX, pair.getLeft().longValue()); + iParam.set(Constant.STEP_COUNT, pair.getRight().longValue()); + + params.add(iParam); + } + + return params; + } + + /** + * Pair left: startIndex, right: stepCount + */ + private static List> splitRecordCount(long recordCount, int adviceNum) { + if(recordCount<0){ + throw new IllegalArgumentException("切分的 recordCount 不能为负数.recordCount=" + recordCount); + } + + if(adviceNum<1){ + throw new IllegalArgumentException("切分的 adviceNum 不能为负数.adviceNum=" + adviceNum); + } + + List> result = new ArrayList>(); + // 为了适配 RangeSplitUtil 的处理逻辑,起始值从0开始计算 + if (recordCount == 0) { + result.add(ImmutablePair.of(0L, 0L)); + return result; + } + + long[] tempResult = RangeSplitUtil.doLongSplit(0L, recordCount - 1, adviceNum); + + tempResult[tempResult.length - 1]++; + + for (int i = 0; i < tempResult.length - 1; i++) { + result.add(ImmutablePair.of(tempResult[i], (tempResult[i + 1] - tempResult[i]))); + } + return result; + } + +} diff --git a/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsUtil.java b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsUtil.java new file mode 100755 index 000000000..f441cbb10 --- /dev/null +++ b/odpsreader/src/main/java/com/alibaba/datax/plugin/reader/odpsreader/util/OdpsUtil.java @@ -0,0 +1,377 @@ +package com.alibaba.datax.plugin.reader.odpsreader.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.RetryUtil; +import com.alibaba.datax.plugin.reader.odpsreader.ColumnType; +import com.alibaba.datax.plugin.reader.odpsreader.Constant; +import com.alibaba.datax.plugin.reader.odpsreader.Key; +import com.alibaba.datax.plugin.reader.odpsreader.OdpsReaderErrorCode; +import com.aliyun.odps.*; +import com.aliyun.odps.account.Account; +import com.aliyun.odps.account.AliyunAccount; +import com.aliyun.odps.data.RecordReader; +import com.aliyun.odps.tunnel.TableTunnel; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; + +public final class OdpsUtil { + private static final Logger LOG = LoggerFactory.getLogger(OdpsUtil.class); + + public static int MAX_RETRY_TIME = 10; + + public static void checkNecessaryConfig(Configuration originalConfig) { + originalConfig.getNecessaryValue(Key.ODPS_SERVER, OdpsReaderErrorCode.REQUIRED_VALUE); + + originalConfig.getNecessaryValue(Key.PROJECT, OdpsReaderErrorCode.REQUIRED_VALUE); + originalConfig.getNecessaryValue(Key.TABLE, OdpsReaderErrorCode.REQUIRED_VALUE); + + if (null == originalConfig.getList(Key.COLUMN) || + originalConfig.getList(Key.COLUMN, String.class).isEmpty()) { + throw DataXException.asDataXException(OdpsReaderErrorCode.REQUIRED_VALUE, "datax获取不到源表的列信息, 由于您未配置读取源头表的列信息. datax无法知道该抽取表的哪些字段的数据 " + + "正确的配置方式是给 column 配置上您需要读取的列名称,用英文逗号分隔."); + } + + } + + public static void dealMaxRetryTime(Configuration originalConfig) { + int maxRetryTime = originalConfig.getInt(Key.MAX_RETRY_TIME, + OdpsUtil.MAX_RETRY_TIME); + if (maxRetryTime < 1 || maxRetryTime > OdpsUtil.MAX_RETRY_TIME) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ILLEGAL_VALUE, "您所配置的maxRetryTime 值错误. 该值不能小于1, 且不能大于 " + OdpsUtil.MAX_RETRY_TIME + + ". 推荐的配置方式是给maxRetryTime 配置1-11之间的某个值. 请您检查配置并做出相应修改."); + } + MAX_RETRY_TIME = maxRetryTime; + } + + public static Odps initOdps(Configuration originalConfig) { + String odpsServer = originalConfig.getString(Key.ODPS_SERVER); + + String accessId = originalConfig.getString(Key.ACCESS_ID); + String accessKey = originalConfig.getString(Key.ACCESS_KEY); + String project = originalConfig.getString(Key.PROJECT); + + String packageAuthorizedProject = originalConfig.getString(Key.PACKAGE_AUTHORIZED_PROJECT); + + String defaultProject; + if(StringUtils.isBlank(packageAuthorizedProject)) { + defaultProject = project; + } else { + defaultProject = packageAuthorizedProject; + } + + String accountType = originalConfig.getString(Key.ACCOUNT_TYPE, + Constant.DEFAULT_ACCOUNT_TYPE); + + Account account = null; + if (accountType.equalsIgnoreCase(Constant.DEFAULT_ACCOUNT_TYPE)) { + account = new AliyunAccount(accessId, accessKey); + } else { + throw DataXException.asDataXException(OdpsReaderErrorCode.ACCOUNT_TYPE_ERROR, + String.format("不支持的账号类型:[%s]. 账号类型目前仅支持aliyun, taobao.", accountType)); + } + + Odps odps = new Odps(account); + boolean isPreCheck = originalConfig.getBool("dryRun", false); + if(isPreCheck) { + odps.getRestClient().setConnectTimeout(3); + odps.getRestClient().setReadTimeout(3); + odps.getRestClient().setRetryTimes(2); + } + odps.setDefaultProject(defaultProject); + odps.setEndpoint(odpsServer); + + return odps; + } + + public static Table getTable(Odps odps, String projectName, String tableName) { + final Table table = odps.tables().get(projectName, tableName); + try { + //通过这种方式检查表是否存在,失败重试。重试策略:每秒钟重试一次,最大重试3次 + return RetryUtil.executeWithRetry(new Callable() { + @Override + public Table call() throws Exception { + table.reload(); + return table; + } + }, 3, 1000, false); + } catch (Exception e) { + throwDataXExceptionWhenReloadTable(e, tableName); + } + return table; + } + + public static boolean isPartitionedTable(Table table) { + return getPartitionDepth(table) > 0; + } + + public static int getPartitionDepth(Table table) { + TableSchema tableSchema = table.getSchema(); + + return tableSchema.getPartitionColumns().size(); + } + + public static List getTableAllPartitions(Table table) { + List tableAllPartitions = table.getPartitions(); + + List retPartitions = new ArrayList(); + + if (null != tableAllPartitions) { + for (Partition partition : tableAllPartitions) { + retPartitions.add(partition.getPartitionSpec().toString()); + } + } + + return retPartitions; + } + + public static List getTableAllColumns(Table table) { + TableSchema tableSchema = table.getSchema(); + return tableSchema.getColumns(); + } + + + public static List getTableOriginalColumnNameList( + List columns) { + List tableOriginalColumnNameList = new ArrayList(); + + for (Column column : columns) { + tableOriginalColumnNameList.add(column.getName()); + } + + return tableOriginalColumnNameList; + } + + public static String formatPartition(String partition) { + if (StringUtils.isBlank(partition)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ILLEGAL_VALUE, + "您所配置的分区不能为空白."); + } else { + return partition.trim().replaceAll(" *= *", "=") + .replaceAll(" */ *", ",").replaceAll(" *, *", ",") + .replaceAll("'", ""); + } + } + + public static List formatPartitions(List partitions) { + if (null == partitions || partitions.isEmpty()) { + return Collections.emptyList(); + } else { + List formattedPartitions = new ArrayList(); + for (String partition : partitions) { + formattedPartitions.add(formatPartition(partition)); + + } + return formattedPartitions; + } + } + + public static List> parseColumns( + List allNormalColumns, List allPartitionColumns, + List userConfiguredColumns) { + List> parsededColumns = new ArrayList>(); + // warn: upper & lower case + for (String column : userConfiguredColumns) { + MutablePair pair = new MutablePair(); + + // if constant column + if (OdpsUtil.checkIfConstantColumn(column)) { + // remove first and last ' + pair.setLeft(column.substring(1, column.length() - 1)); + pair.setRight(ColumnType.CONSTANT); + parsededColumns.add(pair); + continue; + } + + // if normal column, warn: in o d p s normal columns can not + // repeated in partitioning columns + int index = OdpsUtil.indexOfIgnoreCase(allNormalColumns, column); + if (0 <= index) { + pair.setLeft(allNormalColumns.get(index)); + pair.setRight(ColumnType.NORMAL); + parsededColumns.add(pair); + continue; + } + + // if partition column + index = OdpsUtil.indexOfIgnoreCase(allPartitionColumns, column); + if (0 <= index) { + pair.setLeft(allPartitionColumns.get(index)); + pair.setRight(ColumnType.PARTITION); + parsededColumns.add(pair); + continue; + } + // not exist column + throw DataXException.asDataXException( + OdpsReaderErrorCode.ILLEGAL_VALUE, + String.format("源头表的列配置错误. 您所配置的列 [%s] 不存在.", column)); + + } + return parsededColumns; + } + + private static int indexOfIgnoreCase(List columnCollection, + String column) { + int index = -1; + for (int i = 0; i < columnCollection.size(); i++) { + if (columnCollection.get(i).equalsIgnoreCase(column)) { + index = i; + break; + } + } + return index; + } + + public static boolean checkIfConstantColumn(String column) { + if (column.length() >= 2 && column.startsWith(Constant.COLUMN_CONSTANT_FLAG) && + column.endsWith(Constant.COLUMN_CONSTANT_FLAG)) { + return true; + } else { + return false; + } + } + + public static TableTunnel.DownloadSession createMasterSessionForNonPartitionedTable(Odps odps, String tunnelServer, + final String projectName, final String tableName) { + + final TableTunnel tunnel = new TableTunnel(odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tunnel.setEndpoint(tunnelServer); + } + + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.DownloadSession call() throws Exception { + return tunnel.createDownloadSession( + projectName, tableName); + } + }, MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.CREATE_DOWNLOADSESSION_FAIL, e); + } + } + + public static TableTunnel.DownloadSession getSlaveSessionForNonPartitionedTable(Odps odps, final String sessionId, + String tunnelServer, final String projectName, final String tableName) { + + final TableTunnel tunnel = new TableTunnel(odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tunnel.setEndpoint(tunnelServer); + } + + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.DownloadSession call() throws Exception { + return tunnel.getDownloadSession( + projectName, tableName, sessionId); + } + }, MAX_RETRY_TIME ,1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.GET_DOWNLOADSESSION_FAIL, e); + } + } + + public static TableTunnel.DownloadSession createMasterSessionForPartitionedTable(Odps odps, String tunnelServer, + final String projectName, final String tableName, String partition) { + + final TableTunnel tunnel = new TableTunnel(odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tunnel.setEndpoint(tunnelServer); + } + + final PartitionSpec partitionSpec = new PartitionSpec(partition); + + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.DownloadSession call() throws Exception { + return tunnel.createDownloadSession( + projectName, tableName, partitionSpec); + } + }, MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.CREATE_DOWNLOADSESSION_FAIL, e); + } + } + + public static TableTunnel.DownloadSession getSlaveSessionForPartitionedTable(Odps odps, final String sessionId, + String tunnelServer, final String projectName, final String tableName, String partition) { + + final TableTunnel tunnel = new TableTunnel(odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tunnel.setEndpoint(tunnelServer); + } + + final PartitionSpec partitionSpec = new PartitionSpec(partition); + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.DownloadSession call() throws Exception { + return tunnel.getDownloadSession( + projectName, tableName, partitionSpec, sessionId); + } + }, MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.GET_DOWNLOADSESSION_FAIL, e); + } + } + + + + public static RecordReader getRecordReader(final TableTunnel.DownloadSession downloadSession, final long start, final long count, + final boolean isCompress) { + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public RecordReader call() throws Exception { + return downloadSession.openRecordReader(start, count, isCompress); + } + }, MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsReaderErrorCode.OPEN_RECORD_READER_FAILED, + "open RecordReader失败. 请联系 ODPS 管理员处理.", e); + } + } + + /** + * table.reload() 方法抛出的 odps 异常 转化为更清晰的 datax 异常 抛出 + */ + public static void throwDataXExceptionWhenReloadTable(Exception e, String tableName) { + if(e.getMessage() != null) { + if(e.getMessage().contains(OdpsExceptionMsg.ODPS_PROJECT_NOT_FOUNT)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_PROJECT_NOT_FOUNT, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 [project] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_TABLE_NOT_FOUNT)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_TABLE_NOT_FOUNT, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 [table] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_KEY_ID_NOT_FOUND)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_ACCESS_KEY_ID_NOT_FOUND, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 [accessId] [accessKey]是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_KEY_INVALID)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_ACCESS_KEY_INVALID, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 [accessKey] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_DENY)) { + throw DataXException.asDataXException(OdpsReaderErrorCode.ODPS_ACCESS_DENY, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 [accessId] [accessKey] [project]是否匹配.", tableName), e); + } + } + throw DataXException.asDataXException(OdpsReaderErrorCode.ILLEGAL_VALUE, + String.format("加载 ODPS 源头表:%s 失败. " + + "请检查您配置的 ODPS 源头表的 project,table,accessId,accessKey,odpsServer等值.", tableName), e); + } +} diff --git a/odpsreader/src/main/resources/TODO.txt b/odpsreader/src/main/resources/TODO.txt new file mode 100755 index 000000000..aaf8e64eb --- /dev/null +++ b/odpsreader/src/main/resources/TODO.txt @@ -0,0 +1,6 @@ +1、哪些方法需要重试? 风险何在? +2、哪些对象是非线程安全的? +3、切分后为 null 的任务,框架怎么处理? +4、读取分区的配置方式? +5、内部的解密key 的逻辑 +6、表名称大小写敏感性的问题? \ No newline at end of file diff --git a/odpsreader/src/main/resources/plugin.json b/odpsreader/src/main/resources/plugin.json new file mode 100755 index 000000000..2d441acf6 --- /dev/null +++ b/odpsreader/src/main/resources/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "odpsreader", + "class": "com.alibaba.datax.plugin.reader.odpsreader.OdpsReader", + "description": { + "useScene": "prod.", + "mechanism": "TODO", + "warn": "TODO" + }, + "developer": "alibaba" +} \ No newline at end of file diff --git a/odpsreader/src/main/resources/plugin_job_template.json b/odpsreader/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..6eddf0cd2 --- /dev/null +++ b/odpsreader/src/main/resources/plugin_job_template.json @@ -0,0 +1,14 @@ +{ + "name": "odpsreader", + "parameter": { + "accessId": "", + "accessKey": "", + "project": "", + "table": "", + "partition": [], + "column": [], + "packageAuthorizedProject": "", + "splitMode": "", + "odpsServer": "" + } +} \ No newline at end of file diff --git a/odpswriter/doc/odpswriter.md b/odpswriter/doc/odpswriter.md new file mode 100644 index 000000000..229405d66 --- /dev/null +++ b/odpswriter/doc/odpswriter.md @@ -0,0 +1,338 @@ +# DataX ODPS写入 + + +--- + + +## 1 快速介绍 + +ODPSWriter插件用于实现往ODPS插入或者更新数据,主要提供给etl开发同学将业务数据导入odps,适合于TB,GB数量级的数据传输,如果需要传输PB量级的数据,请选择dt task工具 (http://odps.alibaba-inc.com/download/DTTask_User_Manuals.pdf?spm=0.0.0.0.TWkq8m&file=DTTask_User_Manuals.pdf). + + + +## 2 实现原理 + +在底层实现上,ODPSWriter是通过DT Tunnel写入ODPS系统的,有关ODPS的更多技术细节请参看 ODPS主站 http://odps.alibaba-inc.com/ 和ODPS产品文档 http://odps.alibaba-inc.com/doc/ + +目前 DataX3 依赖的 SDK 版本是: + + + com.aliyun.odps + odps-sdk-core-internal + 0.13.2 + + + +注意: **如果你需要使用ODPSReader/Writer插件,请务必使用JDK 1.6-32及以上版本** +使用java -version查看Java版本号 + +## 3 功能说明 + +### 3.1 配置样例 +* 这里使用一份从内存产生到ODPS导入的数据。 + +```json +{ + "job": { + "setting": { + "speed": {"byte": 1048576} + }, + "content": [ + { + "reader": { + "name": "streamreader", + "parameter": { + "column" : [ + { + "value": "DataX", + "type": "string" + }, + { + "value": "test", + "type": "bytes" + } + ], + "sliceRecordCount": 100000 + } + }, + "writer": { + "name": "odpswriter", + "parameter": { + "project": "chinan_test", + "table": "odps_write_test00_partitioned", + "partition":"school=SiChuan-School,class=1", + "column": ["id","name"], + "accessId": "**b7**", + "accessKey": "***dv**yk**mm", + "truncate": true, + "odpsServer": "http://service.odpsstg.aliyun-inc.com/stgnew/", + "tunnelServer": "http://tunnel.odpsstg.aliyun-inc.com/", + "accountType": "aliyun" + } + } + } + } + ] + } +} +``` + + +### 3.2 参数说明 + + +* **accessId** + * 描述:ODPS系统登录ID
+ * 必选:是
+ * 默认值:无
+ +* **accessKey** + * 描述:ODPS系统登录Key
+ * 必选:是
+ * 默认值:无
+ +* **project** + + * 描述:ODPS表所属的project,注意:Project只能是字母+数字组合,请填写英文名称。在云端等用户看到的ODPS项目中文名只是显示名,请务必填写底层真实地Project英文标识名。
+ * 必选:是
+ * 默认值:无
+ +* **table** + + * 描述:写入数据的表名,不能填写多张表,因为DataX不支持同时导入多张表。
+ * 必选:是
+ * 默认值:无
+ +* **partition** + + * 描述:需要写入数据表的分区信息,必须指定到最后一级分区。把数据写入一个三级分区表,必须配置到最后一级分区,例如pt=20150101/type=1/biz=2。 +
+ * 必选:**如果是分区表,该选项必填,如果非分区表,该选项不可填写。** + * 默认值:空
+ +* **column** + + * 描述:需要导入的字段列表,当导入全部字段时,可以配置为"column": ["*"], 当需要插入部分odps列填写部分列,例如"column": ["id", "name"]。ODPSWriter支持列筛选、列换序,例如表有a,b,c三个字段,用户只同步c,b两个字段。可以配置成["c","b"], 在导入过程中,字段a自动补空,设置为null。
+ * 必选:否
+ * 默认值:无
+ +* **truncate** + * 描述:ODPSWriter通过配置"truncate": true,保证写入的幂等性,即当出现写入失败再次运行时,ODPSWriter将清理前述数据,并导入新数据,这样可以保证每次重跑之后的数据都保持一致。
+ + **truncate选项不是原子操作!ODPS SQL无法做到原子性。因此当多个任务同时向一个Table/Partition清理分区时候,可能出现并发时序问题,请务必注意!**针对这类问题,我们建议尽量不要多个作业DDL同时操作同一份分区,或者在多个并发作业启动前,提前创建分区。 + + * 必选:是
+ * 默认值:无
+ +* **odpsServer** + + * 描述:ODPS的server,线上地址为 http://service.odps.aliyun-inc.com/api 日常地址:http://service-corp.odps.aliyun-inc.com/api
+ * 必选:是
+ * 默认值:无
+ +* **tunnelServer** + + * 描述:ODPS的tunnelserver,线上地址为 http://dt.odps.aliyun-inc.com 日常地址:http://dt-corp.odps.aliyun-inc.com
+ * 必选:是,如果地址是对内的(含有"-inc")则可以不填
+ * 默认值:无
+ + +### 3.3 类型转换 + +类似ODPSReader,目前ODPSWriter支持大部分ODPS类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出ODPSWriter针对ODPS类型转换列表: + + +| DataX 内部类型| ODPS 数据类型 | +| -------- | ----- | +| Long |bigint | +| Double |double | +| String |string | +| Date |datetime | +| Boolean |bool | + + + + +## 4 插件特点 + +### 4.1 关于列筛选的问题 + +* ODPS本身不支持列筛选、重排序、补空等等,但是DataX ODPSWriter完成了上述需求,支持列筛选、重排序、补空。例如需要导入的字段列表,当导入全部字段时,可以配置为"column": ["*"],odps表有a,b,c三个字段,用户只同步c,b两个字段,在列配置中可以写成"column": ["c","b"],表示会把reader的第一列和第二列导入odps的c字段和b字段,而odps表中新插入纪的录的a字段会被置为null. + +### 4.2 列配置错误的处理 + +* 为了保证写入数据的可靠性,避免多余列数据丢失造成数据质量故障。对于写入多余的列,ODPSWriter将报错。例如ODPS表字段为a,b,c,但是ODPSWriter写入的字段为多于3列的话ODPSWriter将报错。 + +### 4.3 分区配置注意事项 + +* ODPSWriter只提供 **写入到最后一级分区** 功能,不支持写入按照某个字段进行分区路由等功能。假设表一共有3级分区,那么在分区配置中就必须指明写入到某个三级分区,例如把数据写入一个表的第三级分区,可以配置为 pt=20150101/type=1/biz=2,但是不能配置为pt=20150101/type=1或者pt=20150101。 + +### 4.4 任务重跑和failover +* ODPSWriter通过配置"truncate": true,保证写入的幂等性,即当出现写入失败再次运行时,ODPSWriter将清理前述数据,并导入新数据,这样可以保证每次重跑之后的数据都保持一致。如果在运行过程中因为其他的异常导致了任务中断,是不能保证数据的原子性的,数据不会回滚也不会自动重跑,需要用户利用幂等性这一特点重跑去确保保证数据的完整性。**truncate为true的情况下,会将指定分区\表的数据全部清理,请谨慎使用!** + + + +## 5 性能报告(线上环境实测) + +### 5.1 环境准备 + +#### 5.1.1 数据特征 + +建表语句: + + use cdo_datasync; + create table datax3_odpswriter_perf_10column_1kb_00( + s_0 string, + bool_1 boolean, + bi_2 bigint, + dt_3 datetime, + db_4 double, + s_5 string, + s_6 string, + s_7 string, + s_8 string, + s_9 string + )PARTITIONED by (pt string,year string); + +单行记录类似于: + + s_0 : 485924f6ab7f272af361cd3f7f2d23e0d764942351#$%^&fdafdasfdas%%^(*&^^&* + bool_1 : true + bi_2 : 1696248667889 + dt_3 : 2013-07-0600: 00: 00 + db_4 : 3.141592653578 + s_5 : 100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209 + s_6 : 100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11fdsafdsfdsa209 + s_7 : 100DAFDSAFDSAHOFJDPSAWIFDISHAF;dsadsafdsahfdsajf;dsfdsa;FJDSAL;11209 + s_8 : 100dafdsafdsahofjdpsawifdishaf;DSADSAFDSAHFDSAJF;dsfdsa;fjdsal;11209 + s_9 : 12~!2345100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209 + +#### 5.1.2 机器参数 + +* 执行DataX的机器参数为: + 1. cpu : 24 Core Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz cache 15.36MB + 2. mem : 50GB + 3. net : 千兆双网卡 + 4. jvm : -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError + 5. disc: DataX 数据不落磁盘,不统计此项 + +* 任务配置为: +``` +{ + "job": { + "setting": { + "speed": { + "channel": "1,2,4,5,6,8,16,32,64" + } + }, + "content": [ + { + "reader": { + "name": "odpsreader", + "parameter": { + "accessId": "******************************", + "accessKey": "*****************************", + "column": [ + "*" + ], + "partition": [ + "pt=20141010000000,year=2014" + ], + "odpsServer": "http://service.odps.aliyun-inc.com/api", + "project": "cdo_datasync", + "table": "datax3_odpswriter_perf_10column_1kb_00", + "tunnelServer": "http://dt.odps.cm11.aliyun-inc.com/" + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "print": false, + "column": [ + { + "value": "485924f6ab7f272af361cd3f7f2d23e0d764942351#$%^&fdafdasfdas%%^(*&^^&*" + }, + { + "value": "true", + "type": "bool" + }, + { + "value": "1696248667889", + "type": "long" + }, + { + "type": "date", + "value": "2013-07-06 00:00:00", + "dateFormat": "yyyy-mm-dd hh:mm:ss" + }, + { + "value": "3.141592653578", + "type": "double" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11fdsafdsfdsa209" + }, + { + "value": "100DAFDSAFDSAHOFJDPSAWIFDISHAF;dsadsafdsahfdsajf;dsfdsa;FJDSAL;11209" + }, + { + "value": "100dafdsafdsahofjdpsawifdishaf;DSADSAFDSAHFDSAJF;dsfdsa;fjdsal;11209" + }, + { + "value": "12~!2345100dafdsafdsahofjdpsawifdishaf;dsadsafdsahfdsajf;dsfdsa;fjdsal;11209" + } + ] + } + } + } + ] + } +} +``` + +### 5.2 测试报告 + + +| 并发任务数|blockSizeInMB| DataX速度(Rec/s)|DataX流量(MB/S)|网卡流量(MB/S)|DataX运行负载| +|--------| --------|--------|--------|--------|--------| +|1|32|30303|13.03|14.5|0.12| +|1|64|38461|16.54|16.5|0.44| +|1|128|46454|20.55|26.7|0.47| +|1|256|52631|22.64|26.7|0.47| +|1|512|58823|25.30|28.7|0.44| +|4|32|114816|49.38|55.3|0.75| +|4|64|147577|63.47|71.3|0.82| +|4|128|177744|76.45|83.2|0.97| +|4|256|173913|74.80|80.1|1.01| +|4|512|200000|86.02|95.1|1.41| +|8|32|204480|87.95|92.7|1.16| +|8|64|294224|126.55|135.3|1.65| +|8|128|365475|157.19|163.7|2.89| +|8|256|394713|169.83|176.7|2.72| +|8|512|241691|103.95|125.7|2.29| +|16|32|420838|181.01|198.0|2.56| +|16|64|458144|197.05|217.4|2.85| +|16|128|443219|190.63|210.5|3.29| +|16|256|315235|135.58|140.0|0.95| +|16|512|OOM||||| + +说明: + +1. OdpsWriter 影响速度的是channel 和 blockSizeInMB。blockSizeInMB 取`32` 和 `64`时,速度比较稳定,过分大的 blockSizeInMB 可能造成速度波动以及内存OOM。 +2. channel 和 blockSizeInMB 对速度的影响都很明显,建议综合考虑配合选择。 +3. channel 数目的选择,可以综合考虑源端数据特征进行选择,对于StreamReader,在16个channel时将网卡打满。 + + +## 6 FAQ +#### 1 导数据到 odps 的日志中有以下报错,该怎么处理呢?"ODPS-0420095: Access Denied - Authorization Failed [4002], You doesn‘t exist in project example_dev“ + +解决办法 :找ODPS Prject 的 owner给用户的云账号授权,授权语句: +grant Describe,Select,Alter,Update on table [tableName] to user XXX + +#### 2 可以导入数据到odps的视图吗? +目前不支持通过视图到数据到odps,视图是ODPS非实体化数据存储对象,技术上无法向视图导入数据。 diff --git a/odpswriter/odpswriter.iml b/odpswriter/odpswriter.iml new file mode 100644 index 000000000..8f28870d8 --- /dev/null +++ b/odpswriter/odpswriter.iml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/odpswriter/pom.xml b/odpswriter/pom.xml new file mode 100755 index 000000000..4e633fd18 --- /dev/null +++ b/odpswriter/pom.xml @@ -0,0 +1,100 @@ + + 4.0.0 + + com.alibaba.datax + datax-all + 0.0.1-SNAPSHOT + + odpswriter + odpswriter + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + com.aliyun.odps + odps-sdk-core + 0.19.3-public + + + + + commons-httpclient + commons-httpclient + 3.1 + + + + + org.mockito + mockito-core + 1.8.5 + test + + + org.powermock + powermock-api-mockito + 1.4.10 + test + + + org.powermock + powermock-module-junit4 + 1.4.10 + test + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + \ No newline at end of file diff --git a/odpswriter/src/main/assembly/package.xml b/odpswriter/src/main/assembly/package.xml new file mode 100755 index 000000000..0ef0b43b1 --- /dev/null +++ b/odpswriter/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/writer/odpswriter + + + target/ + + odpswriter-0.0.1-SNAPSHOT.jar + + plugin/writer/odpswriter + + + + + + false + plugin/writer/odpswriter/libs + runtime + + + diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Constant.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Constant.java new file mode 100755 index 000000000..22bcc16cb --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Constant.java @@ -0,0 +1,15 @@ +package com.alibaba.datax.plugin.writer.odpswriter; + + +public class Constant { + public static final String SKYNET_ACCESSID = "SKYNET_ACCESSID"; + + public static final String SKYNET_ACCESSKEY = "SKYNET_ACCESSKEY"; + + public static final String DEFAULT_ACCOUNT_TYPE = "aliyun"; + + public static final String TAOBAO_ACCOUNT_TYPE = "taobao"; + + public static final String COLUMN_POSITION = "columnPosition"; + +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Key.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Key.java new file mode 100755 index 000000000..f578d72d9 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/Key.java @@ -0,0 +1,34 @@ +package com.alibaba.datax.plugin.writer.odpswriter; + + +public final class Key { + + public final static String ODPS_SERVER = "odpsServer"; + + public final static String TUNNEL_SERVER = "tunnelServer"; + + public final static String ACCESS_ID = "accessId"; + + public final static String ACCESS_KEY = "accessKey"; + + public final static String PROJECT = "project"; + + public final static String TABLE = "table"; + + public final static String PARTITION = "partition"; + + public final static String COLUMN = "column"; + + public final static String TRUNCATE = "truncate"; + + public final static String MAX_RETRY_TIME = "maxRetryTime"; + + public final static String BLOCK_SIZE_IN_MB = "blockSizeInMB"; + + //boolean 类型,default:false + public final static String EMPTY_AS_NULL = "emptyAsNull"; + + public final static String ACCOUNT_TYPE = "accountType"; + + public final static String IS_COMPRESS = "isCompress"; +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriter.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriter.java new file mode 100755 index 000000000..60deb5dd3 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriter.java @@ -0,0 +1,356 @@ +package com.alibaba.datax.plugin.writer.odpswriter; + +import com.alibaba.datax.common.exception.CommonErrorCode; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordReceiver; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.common.spi.Writer; +import com.alibaba.datax.common.statistics.PerfRecord; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.ListUtil; +import com.alibaba.datax.plugin.writer.odpswriter.util.IdAndKeyUtil; +import com.alibaba.datax.plugin.writer.odpswriter.util.OdpsUtil; + +import com.aliyun.odps.Odps; +import com.aliyun.odps.Table; +import com.aliyun.odps.TableSchema; +import com.aliyun.odps.tunnel.TableTunnel; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 已修改为:每个 task 各自创建自己的 upload,拥有自己的 uploadId,并在 task 中完成对对应 block 的提交。 + */ +public class OdpsWriter extends Writer { + + public static class Job extends Writer.Job { + private static final Logger LOG = LoggerFactory + .getLogger(Job.class); + + private static final boolean IS_DEBUG = LOG.isDebugEnabled(); + + private Configuration originalConfig; + private Odps odps; + private Table table; + + private String projectName; + private String tableName; + private String tunnelServer; + private String partition; + private String accountType; + private boolean truncate; + private String uploadId; + private TableTunnel.UploadSession masterUpload; + private int blockSizeInMB; + + public void preCheck() { + this.init(); + this.doPreCheck(); + } + + public void doPreCheck() { + //检查accessId,accessKey配置 + if (Constant.DEFAULT_ACCOUNT_TYPE + .equalsIgnoreCase(this.accountType)) { + this.originalConfig = IdAndKeyUtil.parseAccessIdAndKey(this.originalConfig); + String accessId = this.originalConfig.getString(Key.ACCESS_ID); + String accessKey = this.originalConfig.getString(Key.ACCESS_KEY); + if (IS_DEBUG) { + LOG.debug("accessId:[{}], accessKey:[{}] .", accessId, + accessKey); + } + LOG.info("accessId:[{}] .", accessId); + } + // init odps config + this.odps = OdpsUtil.initOdpsProject(this.originalConfig); + + //检查表等配置是否正确 + this.table = OdpsUtil.getTable(odps,this.projectName,this.tableName); + + //检查列信息是否正确 + List allColumns = OdpsUtil.getAllColumns(this.table.getSchema()); + LOG.info("allColumnList: {} .", StringUtils.join(allColumns, ',')); + dealColumn(this.originalConfig, allColumns); + + //检查分区信息是否正确 + OdpsUtil.preCheckPartition(this.odps, this.table, this.partition, this.truncate); + } + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + + OdpsUtil.checkNecessaryConfig(this.originalConfig); + OdpsUtil.dealMaxRetryTime(this.originalConfig); + + this.projectName = this.originalConfig.getString(Key.PROJECT); + this.tableName = this.originalConfig.getString(Key.TABLE); + this.tunnelServer = this.originalConfig.getString(Key.TUNNEL_SERVER, null); + + //check isCompress + this.originalConfig.getBool(Key.IS_COMPRESS, false); + + this.partition = OdpsUtil.formatPartition(this.originalConfig + .getString(Key.PARTITION, "")); + this.originalConfig.set(Key.PARTITION, this.partition); + + this.accountType = this.originalConfig.getString(Key.ACCOUNT_TYPE, + Constant.DEFAULT_ACCOUNT_TYPE); + if (!Constant.DEFAULT_ACCOUNT_TYPE.equalsIgnoreCase(this.accountType) && + !Constant.TAOBAO_ACCOUNT_TYPE.equalsIgnoreCase(this.accountType)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ACCOUNT_TYPE_ERROR, + String.format("账号类型错误,因为你的账号 [%s] 不是datax目前支持的账号类型,目前仅支持aliyun, taobao账号,请修改您的账号信息.", accountType)); + } + this.originalConfig.set(Key.ACCOUNT_TYPE, this.accountType); + + this.truncate = this.originalConfig.getBool(Key.TRUNCATE); + + boolean emptyAsNull = this.originalConfig.getBool(Key.EMPTY_AS_NULL, false); + this.originalConfig.set(Key.EMPTY_AS_NULL, emptyAsNull); + if (emptyAsNull) { + LOG.warn("这是一条需要注意的信息 由于您的作业配置了写入 ODPS 的目的表时emptyAsNull=true, 所以 DataX将会把长度为0的空字符串作为 java 的 null 写入 ODPS."); + } + + this.blockSizeInMB = this.originalConfig.getInt(Key.BLOCK_SIZE_IN_MB, 64); + if(this.blockSizeInMB < 8) { + this.blockSizeInMB = 8; + } + this.originalConfig.set(Key.BLOCK_SIZE_IN_MB, this.blockSizeInMB); + LOG.info("blockSizeInMB={}.", this.blockSizeInMB); + + if (IS_DEBUG) { + LOG.debug("After master init(), job config now is: [\n{}\n] .", + this.originalConfig.toJSON()); + } + } + + @Override + public void prepare() { + String accessId = null; + String accessKey = null; + if (Constant.DEFAULT_ACCOUNT_TYPE + .equalsIgnoreCase(this.accountType)) { + this.originalConfig = IdAndKeyUtil.parseAccessIdAndKey(this.originalConfig); + accessId = this.originalConfig.getString(Key.ACCESS_ID); + accessKey = this.originalConfig.getString(Key.ACCESS_KEY); + if (IS_DEBUG) { + LOG.debug("accessId:[{}], accessKey:[{}] .", accessId, + accessKey); + } + LOG.info("accessId:[{}] .", accessId); + } + + // init odps config + this.odps = OdpsUtil.initOdpsProject(this.originalConfig); + + //检查表等配置是否正确 + this.table = OdpsUtil.getTable(odps,this.projectName,this.tableName); + + OdpsUtil.dealTruncate(this.odps, this.table, this.partition, this.truncate); + } + + /** + * 此处主要是对 uploadId进行设置,以及对 blockId 的开始值进行设置。 + *

+ * 对 blockId 需要同时设置开始值以及下一个 blockId 的步长值(INTERVAL_STEP)。 + */ + @Override + public List split(int mandatoryNumber) { + List configurations = new ArrayList(); + + // 此处获取到 masterUpload 只是为了拿到 RecordSchema,以完成对 column 的处理 + TableTunnel tableTunnel = new TableTunnel(this.odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tableTunnel.setEndpoint(tunnelServer); + } + + this.masterUpload = OdpsUtil.createMasterTunnelUpload( + tableTunnel, this.projectName, this.tableName, this.partition); + this.uploadId = this.masterUpload.getId(); + LOG.info("Master uploadId:[{}].", this.uploadId); + + TableSchema schema = this.masterUpload.getSchema(); + List allColumns = OdpsUtil.getAllColumns(schema); + LOG.info("allColumnList: {} .", StringUtils.join(allColumns, ',')); + + dealColumn(this.originalConfig, allColumns); + + for (int i = 0; i < mandatoryNumber; i++) { + Configuration tempConfig = this.originalConfig.clone(); + + configurations.add(tempConfig); + } + + if (IS_DEBUG) { + LOG.debug("After master split, the job config now is:[\n{}\n].", this.originalConfig); + } + + this.masterUpload = null; + + return configurations; + } + + private void dealColumn(Configuration originalConfig, List allColumns) { + //之前已经检查了userConfiguredColumns 一定不为空 + List userConfiguredColumns = originalConfig.getList(Key.COLUMN, String.class); + if (1 == userConfiguredColumns.size() && "*".equals(userConfiguredColumns.get(0))) { + userConfiguredColumns = allColumns; + originalConfig.set(Key.COLUMN, allColumns); + } else { + //检查列是否重复,大小写不敏感(所有写入,都是不允许写入段的列重复的) + ListUtil.makeSureNoValueDuplicate(userConfiguredColumns, false); + + //检查列是否存在,大小写不敏感 + ListUtil.makeSureBInA(allColumns, userConfiguredColumns, false); + } + + List columnPositions = OdpsUtil.parsePosition(allColumns, userConfiguredColumns); + originalConfig.set(Constant.COLUMN_POSITION, columnPositions); + } + + @Override + public void post() { + } + + @Override + public void destroy() { + } + } + + + public static class Task extends Writer.Task { + private static final Logger LOG = LoggerFactory + .getLogger(Task.class); + + private static final boolean IS_DEBUG = LOG.isDebugEnabled(); + + private Configuration sliceConfig; + private Odps odps; + + private String projectName; + private String tableName; + private String tunnelServer; + private String partition; + private boolean emptyAsNull; + private boolean isCompress; + + private TableTunnel.UploadSession managerUpload; + private TableTunnel.UploadSession workerUpload; + + private String uploadId = null; + private List blocks; + private int blockSizeInMB; + + private Integer failoverState = 0; //0 未failover 1准备failover 2已提交,不能failover + private byte[] lock = new byte[0]; + + @Override + public void init() { + this.sliceConfig = super.getPluginJobConf(); + + this.projectName = this.sliceConfig.getString(Key.PROJECT); + this.tableName = this.sliceConfig.getString(Key.TABLE); + this.tunnelServer = this.sliceConfig.getString(Key.TUNNEL_SERVER, null); + this.partition = OdpsUtil.formatPartition(this.sliceConfig + .getString(Key.PARTITION, "")); + this.sliceConfig.set(Key.PARTITION, this.partition); + + this.emptyAsNull = this.sliceConfig.getBool(Key.EMPTY_AS_NULL); + this.blockSizeInMB = this.sliceConfig.getInt(Key.BLOCK_SIZE_IN_MB); + this.isCompress = this.sliceConfig.getBool(Key.IS_COMPRESS, false); + if (this.blockSizeInMB < 1 || this.blockSizeInMB > 512) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ILLEGAL_VALUE, + String.format("您配置的blockSizeInMB:%s 参数错误. 正确的配置是[1-512]之间的整数. 请修改此参数的值为该区间内的数值", this.blockSizeInMB)); + } + + if (IS_DEBUG) { + LOG.debug("After init in task, sliceConfig now is:[\n{}\n].", this.sliceConfig); + } + + } + + @Override + public void prepare() { + this.odps = OdpsUtil.initOdpsProject(this.sliceConfig); + + TableTunnel tableTunnel = new TableTunnel(this.odps); + if (StringUtils.isNoneBlank(tunnelServer)) { + tableTunnel.setEndpoint(tunnelServer); + } + + this.managerUpload = OdpsUtil.createMasterTunnelUpload(tableTunnel, this.projectName, + this.tableName, this.partition); + this.uploadId = this.managerUpload.getId(); + LOG.info("task uploadId:[{}].", this.uploadId); + + this.workerUpload = OdpsUtil.getSlaveTunnelUpload(tableTunnel, this.projectName, + this.tableName, this.partition, uploadId); + } + + @Override + public void startWrite(RecordReceiver recordReceiver) { + blocks = new ArrayList(); + + AtomicLong blockId = new AtomicLong(0); + + List columnPositions = this.sliceConfig.getList(Constant.COLUMN_POSITION, + Integer.class); + + try { + TaskPluginCollector taskPluginCollector = super.getTaskPluginCollector(); + + OdpsWriterProxy proxy = new OdpsWriterProxy(this.workerUpload, this.blockSizeInMB, blockId, + columnPositions, taskPluginCollector, this.emptyAsNull, this.isCompress); + + com.alibaba.datax.common.element.Record dataXRecord = null; + + PerfRecord blockClose = new PerfRecord(super.getTaskGroupId(),super.getTaskId(), PerfRecord.PHASE.ODPS_BLOCK_CLOSE); + blockClose.start(); + long blockCloseUsedTime = 0; + while ((dataXRecord = recordReceiver.getFromReader()) != null) { + blockCloseUsedTime += proxy.writeOneRecord(dataXRecord, blocks); + } + + blockCloseUsedTime += proxy.writeRemainingRecord(blocks); + blockClose.end(blockCloseUsedTime); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.WRITER_RECORD_FAIL, "写入 ODPS 目的表失败. 请联系 ODPS 管理员处理.", e); + } + } + + @Override + public void post() { + synchronized (lock){ + if(failoverState==0){ + failoverState = 2; + LOG.info("Slave which uploadId=[{}] begin to commit blocks:[\n{}\n].", this.uploadId, + StringUtils.join(blocks, ",")); + OdpsUtil.masterCompleteBlocks(this.managerUpload, blocks.toArray(new Long[0])); + LOG.info("Slave which uploadId=[{}] commit blocks ok.", this.uploadId); + }else{ + throw DataXException.asDataXException(CommonErrorCode.SHUT_DOWN_TASK, ""); + } + } + } + + @Override + public void destroy() { + } + + @Override + public boolean supportFailOver(){ + synchronized (lock){ + if(failoverState==0){ + failoverState = 1; + return true; + } + return false; + } + } + } +} \ No newline at end of file diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterErrorCode.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterErrorCode.java new file mode 100755 index 000000000..02020c046 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterErrorCode.java @@ -0,0 +1,66 @@ +package com.alibaba.datax.plugin.writer.odpswriter; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum OdpsWriterErrorCode implements ErrorCode { + REQUIRED_VALUE("OdpsWriter-00", "您缺失了必须填写的参数值."), + ILLEGAL_VALUE("OdpsWriter-01", "您配置的值不合法."), + UNSUPPORTED_COLUMN_TYPE("OdpsWriter-02", "DataX 不支持写入 ODPS 的目的表的此种数据类型."), + + TABLE_TRUNCATE_ERROR("OdpsWriter-03", "清空 ODPS 目的表时出错."), + CREATE_MASTER_UPLOAD_FAIL("OdpsWriter-04", "创建 ODPS 的 uploadSession 失败."), + GET_SLAVE_UPLOAD_FAIL("OdpsWriter-05", "获取 ODPS 的 uploadSession 失败."), + GET_ID_KEY_FAIL("OdpsWriter-06", "获取 accessId/accessKey 失败."), + GET_PARTITION_FAIL("OdpsWriter-07", "获取 ODPS 目的表的所有分区失败."), + + ADD_PARTITION_FAILED("OdpsWriter-08", "添加分区到 ODPS 目的表失败."), + WRITER_RECORD_FAIL("OdpsWriter-09", "写入数据到 ODPS 目的表失败."), + + COMMIT_BLOCK_FAIL("OdpsWriter-10", "提交 block 到 ODPS 目的表失败."), + RUN_SQL_FAILED("OdpsWriter-11", "执行 ODPS Sql 失败."), + CHECK_IF_PARTITIONED_TABLE_FAILED("OdpsWriter-12", "检查 ODPS 目的表:%s 是否为分区表失败."), + + RUN_SQL_ODPS_EXCEPTION("OdpsWriter-13", "执行 ODPS Sql 时抛出异常, 可重试"), + + ACCOUNT_TYPE_ERROR("OdpsWriter-30", "账号类型错误."), + + PARTITION_ERROR("OdpsWriter-31", "分区配置错误."), + + COLUMN_NOT_EXIST("OdpsWriter-32", "用户配置的列不存在."), + + ODPS_PROJECT_NOT_FOUNT("OdpsWriter-100", "您配置的值不合法, odps project 不存在."), //ODPS-0420111: Project not found + + ODPS_TABLE_NOT_FOUNT("OdpsWriter-101", "您配置的值不合法, odps table 不存在"), // ODPS-0130131:Table not found + + ODPS_ACCESS_KEY_ID_NOT_FOUND("OdpsWriter-102", "您配置的值不合法, odps accessId,accessKey 不存在"), //ODPS-0410051:Invalid credentials - accessKeyId not found + + ODPS_ACCESS_KEY_INVALID("OdpsWriter-103", "您配置的值不合法, odps accessKey 错误"), //ODPS-0410042:Invalid signature value - User signature dose not match; + + ODPS_ACCESS_DENY("OdpsWriter-104", "拒绝访问, 您不在 您配置的 project 中") //ODPS-0420095: Access Denied - Authorization Failed [4002], You doesn't exist in project + + ; + + private final String code; + private final String description; + + private OdpsWriterErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterProxy.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterProxy.java new file mode 100755 index 000000000..000a1d8e7 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/OdpsWriterProxy.java @@ -0,0 +1,190 @@ +package com.alibaba.datax.plugin.writer.odpswriter; + +import com.alibaba.datax.common.element.StringColumn; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.TaskPluginCollector; +import com.alibaba.datax.plugin.writer.odpswriter.util.OdpsUtil; + +import com.aliyun.odps.OdpsType; +import com.aliyun.odps.TableSchema; + +import com.aliyun.odps.data.Record; + +import com.aliyun.odps.tunnel.TableTunnel; + +import com.aliyun.odps.tunnel.TunnelException; +import com.aliyun.odps.tunnel.io.ProtobufRecordPack; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +public class OdpsWriterProxy { + private static final Logger LOG = LoggerFactory + .getLogger(OdpsWriterProxy.class); + + private volatile boolean printColumnLess;// 是否打印对于源头字段数小于 ODPS 目的表的行的日志 + + private TaskPluginCollector taskPluginCollector; + + private TableTunnel.UploadSession slaveUpload; + private TableSchema schema; + private int maxBufferSize; + private ProtobufRecordPack protobufRecordPack; + private int protobufCapacity; + private AtomicLong blockId; + + private List columnPositions; + private List tableOriginalColumnTypeList; + private boolean emptyAsNull; + private boolean isCompress; + + public OdpsWriterProxy(TableTunnel.UploadSession slaveUpload, int blockSizeInMB, + AtomicLong blockId, List columnPositions, + TaskPluginCollector taskPluginCollector, boolean emptyAsNull, boolean isCompress) + throws IOException, TunnelException { + this.slaveUpload = slaveUpload; + this.schema = this.slaveUpload.getSchema(); + this.tableOriginalColumnTypeList = OdpsUtil + .getTableOriginalColumnTypeList(this.schema); + + this.blockId = blockId; + this.columnPositions = columnPositions; + this.taskPluginCollector = taskPluginCollector; + this.emptyAsNull = emptyAsNull; + this.isCompress = isCompress; + + // 初始化与 buffer 区相关的值 + this.maxBufferSize = (blockSizeInMB - 4) * 1024 * 1024; + this.protobufCapacity = blockSizeInMB * 1024 * 1024; + this.protobufRecordPack = new ProtobufRecordPack(this.schema, null, this.protobufCapacity); + printColumnLess = true; + + } + + public long writeOneRecord( + com.alibaba.datax.common.element.Record dataXRecord, + List blocks) throws Exception { + + Record record = dataxRecordToOdpsRecord(dataXRecord); + + if (null == record) { + return 0; + } + protobufRecordPack.append(record); + + if (protobufRecordPack.getTotalBytes() >= maxBufferSize) { + long startTimeInNs = System.nanoTime(); + OdpsUtil.slaveWriteOneBlock(this.slaveUpload, + protobufRecordPack, blockId.get(), this.isCompress); + LOG.info("write block {} ok.", blockId.get()); + blocks.add(blockId.get()); + protobufRecordPack.reset(); + this.blockId.incrementAndGet(); + return System.nanoTime() - startTimeInNs; + } + return 0; + } + + public long writeRemainingRecord(List blocks) throws Exception { + // complete protobuf stream, then write to http + if (protobufRecordPack.getTotalBytes() != 0) { + long startTimeInNs = System.nanoTime(); + OdpsUtil.slaveWriteOneBlock(this.slaveUpload, + protobufRecordPack, blockId.get(), this.isCompress); + LOG.info("write block {} ok.", blockId.get()); + + blocks.add(blockId.get()); + // reset the buffer for next block + protobufRecordPack.reset(); + return System.nanoTime() - startTimeInNs; + } + return 0; + } + + public Record dataxRecordToOdpsRecord( + com.alibaba.datax.common.element.Record dataXRecord) throws Exception { + int sourceColumnCount = dataXRecord.getColumnNumber(); + Record odpsRecord = slaveUpload.newRecord(); + + int userConfiguredColumnNumber = this.columnPositions.size(); +//todo + if (sourceColumnCount > userConfiguredColumnNumber) { + throw DataXException + .asDataXException( + OdpsWriterErrorCode.ILLEGAL_VALUE, + String.format( + "亲,配置中的源表的列个数和目的端表不一致,源表中您配置的列数是:%s 大于目的端的列数是:%s , 这样会导致源头数据无法正确导入目的端, 请检查您的配置并修改.", + sourceColumnCount, + userConfiguredColumnNumber)); + } else if (sourceColumnCount < userConfiguredColumnNumber) { + if (printColumnLess) { + LOG.warn( + "源表的列个数小于目的表的列个数,源表列数是:{} 目的表列数是:{} , 数目不匹配. DataX 会把目的端多出的列的值设置为空值. 如果这个默认配置不符合您的期望,请保持源表和目的表配置的列数目保持一致.", + sourceColumnCount, userConfiguredColumnNumber); + } + printColumnLess = false; + } + + int currentIndex; + int sourceIndex = 0; + try { + com.alibaba.datax.common.element.Column columnValue; + + for (; sourceIndex < sourceColumnCount; sourceIndex++) { + currentIndex = columnPositions.get(sourceIndex); + OdpsType type = this.tableOriginalColumnTypeList + .get(currentIndex); + columnValue = dataXRecord.getColumn(sourceIndex); + + if (columnValue == null) { + continue; + } + // for compatible dt lib, "" as null + if(this.emptyAsNull && columnValue instanceof StringColumn && "".equals(columnValue.asString())){ + continue; + } + + switch (type) { + case STRING: + odpsRecord.setString(currentIndex, columnValue.asString()); + break; + case BIGINT: + odpsRecord.setBigint(currentIndex, columnValue.asLong()); + break; + case BOOLEAN: + odpsRecord.setBoolean(currentIndex, columnValue.asBoolean()); + break; + case DATETIME: + odpsRecord.setDatetime(currentIndex, columnValue.asDate()); + break; + case DOUBLE: + odpsRecord.setDouble(currentIndex, columnValue.asDouble()); + break; + case DECIMAL: + odpsRecord.setDecimal(currentIndex, columnValue.asBigDecimal()); + String columnStr = columnValue.asString(); + if(columnStr != null && columnStr.indexOf(".") >= 36) { + throw new Exception("Odps decimal 类型的整数位个数不能超过35"); + } + default: + break; + } + } + + return odpsRecord; + } catch (Exception e) { + String message = String.format( + "写入 ODPS 目的表时遇到了脏数据, 因为源端第[%s]个字段, 具体值[%s] 的数据不符合 ODPS 对应字段的格式要求,请检查该数据并作出修改 或者您可以增大阀值,忽略这条记录.", sourceIndex, + dataXRecord.getColumn(sourceIndex)); + this.taskPluginCollector.collectDirtyRecord(dataXRecord, e, + message); + + return null; + } + + } +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/DESCipher.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/DESCipher.java new file mode 100755 index 000000000..bf7f5a883 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/DESCipher.java @@ -0,0 +1,355 @@ +/** + * (C) 2010-2014 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.plugin.writer.odpswriter.util; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import java.security.SecureRandom; + +/** + *   * DES加解密,支持与delphi交互(字符串编码需统一为UTF-8) + * + *   * + * + *   * @author wym + * + *    + */ + +public class DESCipher { + + /** + *   * 密钥 + * + *    + */ + + public static final String KEY = "u4Gqu4Z8"; + + private final static String DES = "DES"; + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @param key + * + *   * 密钥,长度必须是8的倍数 + * + *   * @return 密文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] encrypt(byte[] src, byte[] key) throws Exception { + + // DES算法要求有一个可信任的随机数源 + + SecureRandom sr = new SecureRandom(); + + // 从原始密匙数据创建DESKeySpec对象 + + DESKeySpec dks = new DESKeySpec(key); + + // 创建一个密匙工厂,然后用它把DESKeySpec转换成 + + // 一个SecretKey对象 + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); + + SecretKey securekey = keyFactory.generateSecret(dks); + + // Cipher对象实际完成加密操作 + + Cipher cipher = Cipher.getInstance(DES); + + // 用密匙初始化Cipher对象 + + cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); + + // 现在,获取数据并加密 + + // 正式执行加密操作 + + return cipher.doFinal(src); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @param key + * + *   * 密钥,长度必须是8的倍数 + * + *   * @return 明文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] decrypt(byte[] src, byte[] key) throws Exception { + + // DES算法要求有一个可信任的随机数源 + + SecureRandom sr = new SecureRandom(); + + // 从原始密匙数据创建一个DESKeySpec对象 + + DESKeySpec dks = new DESKeySpec(key); + + // 创建一个密匙工厂,然后用它把DESKeySpec对象转换成 + + // 一个SecretKey对象 + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); + + SecretKey securekey = keyFactory.generateSecret(dks); + + // Cipher对象实际完成解密操作 + + Cipher cipher = Cipher.getInstance(DES); + + // 用密匙初始化Cipher对象 + + cipher.init(Cipher.DECRYPT_MODE, securekey, sr); + + // 现在,获取数据并解密 + + // 正式执行解密操作 + + return cipher.doFinal(src); + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @return 密文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] encrypt(byte[] src) throws Exception { + + return encrypt(src, KEY.getBytes()); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @return 明文(字节) + * + *   * @throws Exception + * + *    + */ + + public static byte[] decrypt(byte[] src) throws Exception { + + return decrypt(src, KEY.getBytes()); + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字符串) + * + *   * @return 密文(16进制字符串) + * + *   * @throws Exception + * + *    + */ + + public final static String encrypt(String src) { + + try { + + return byte2hex(encrypt(src.getBytes(), KEY.getBytes())); + + } catch (Exception e) { + + e.printStackTrace(); + + } + + return null; + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字符串) + * + *   * @return 明文(字符串) + * + *   * @throws Exception + * + *    + */ + + public final static String decrypt(String src) { + try { + + return new String(decrypt(hex2byte(src.getBytes()), KEY.getBytes())); + + } catch (Exception e) { + + e.printStackTrace(); + + } + + return null; + + } + + /** + *   * 加密 + * + *   * + * + *   * @param src + * + *   * 明文(字节) + * + *   * @return 密文(16进制字符串) + * + *   * @throws Exception + * + *    + */ + + public static String encryptToString(byte[] src) throws Exception { + + return encrypt(new String(src)); + + } + + /** + *   * 解密 + * + *   * + * + *   * @param src + * + *   * 密文(字节) + * + *   * @return 明文(字符串) + * + *   * @throws Exception + * + *    + */ + + public static String decryptToString(byte[] src) throws Exception { + + return decrypt(new String(src)); + + } + + public static String byte2hex(byte[] b) { + + String hs = ""; + + String stmp = ""; + + for (int n = 0; n < b.length; n++) { + + stmp = (Integer.toHexString(b[n] & 0XFF)); + + if (stmp.length() == 1) + + hs = hs + "0" + stmp; + + else + + hs = hs + stmp; + + } + + return hs.toUpperCase(); + + } + + public static byte[] hex2byte(byte[] b) { + + if ((b.length % 2) != 0) + + throw new IllegalArgumentException("长度不是偶数"); + + byte[] b2 = new byte[b.length / 2]; + + for (int n = 0; n < b.length; n += 2) { + + String item = new String(b, n, 2); + + b2[n / 2] = (byte) Integer.parseInt(item, 16); + + } + return b2; + + } + + /* + * public static void main(String[] args) { try { String src = "cheetah"; + * String crypto = DESCipher.encrypt(src); System.out.println("密文[" + src + + * "]:" + crypto); System.out.println("解密后:" + DESCipher.decrypt(crypto)); } + * catch (Exception e) { e.printStackTrace(); } } + */ +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/IdAndKeyUtil.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/IdAndKeyUtil.java new file mode 100755 index 000000000..95e4b56b5 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/IdAndKeyUtil.java @@ -0,0 +1,85 @@ +/** + * (C) 2010-2014 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.datax.plugin.writer.odpswriter.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.writer.odpswriter.Constant; +import com.alibaba.datax.plugin.writer.odpswriter.Key; +import com.alibaba.datax.plugin.writer.odpswriter.OdpsWriterErrorCode; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class IdAndKeyUtil { + private static Logger LOG = LoggerFactory.getLogger(IdAndKeyUtil.class); + + public static Configuration parseAccessIdAndKey(Configuration originalConfig) { + String accessId = originalConfig.getString(Key.ACCESS_ID); + String accessKey = originalConfig.getString(Key.ACCESS_KEY); + + // 只要 accessId,accessKey 二者配置了一个,就理解为是用户本意是要直接手动配置其 accessid/accessKey + if (StringUtils.isNotBlank(accessId) || StringUtils.isNotBlank(accessKey)) { + LOG.info("Try to get accessId/accessKey from your config."); + //通过如下语句,进行检查是否确实配置了 + accessId = originalConfig.getNecessaryValue(Key.ACCESS_ID, OdpsWriterErrorCode.REQUIRED_VALUE); + accessKey = originalConfig.getNecessaryValue(Key.ACCESS_KEY, OdpsWriterErrorCode.REQUIRED_VALUE); + //检查完毕,返回即可 + return originalConfig; + } else { + Map envProp = System.getenv(); + return getAccessIdAndKeyFromEnv(originalConfig, envProp); + } + } + + private static Configuration getAccessIdAndKeyFromEnv(Configuration originalConfig, + Map envProp) { + String accessId = null; + String accessKey = null; + + String skynetAccessID = envProp.get(Constant.SKYNET_ACCESSID); + String skynetAccessKey = envProp.get(Constant.SKYNET_ACCESSKEY); + + if (StringUtils.isNotBlank(skynetAccessID) + || StringUtils.isNotBlank(skynetAccessKey)) { + /** + * 环境变量中,如果存在SKYNET_ACCESSID/SKYNET_ACCESSKEy(只要有其中一个变量,则认为一定是两个都存在的!), + * 则使用其值作为odps的accessId/accessKey(会解密) + */ + + LOG.info("Try to get accessId/accessKey from environment."); + accessId = skynetAccessID; + accessKey = DESCipher.decrypt(skynetAccessKey); + if (StringUtils.isNotBlank(accessKey)) { + originalConfig.set(Key.ACCESS_ID, accessId); + originalConfig.set(Key.ACCESS_KEY, accessKey); + LOG.info("Get accessId/accessKey from environment variables successfully."); + } else { + throw DataXException.asDataXException(OdpsWriterErrorCode.GET_ID_KEY_FAIL, + String.format("从环境变量中获取accessId/accessKey 失败, accessId=[%s]", accessId)); + } + } else { + // 无处获取(既没有配置在作业中,也没用在环境变量中) + throw DataXException.asDataXException(OdpsWriterErrorCode.GET_ID_KEY_FAIL, + "无法获取到accessId/accessKey. 它们既不存在于您的配置中,也不存在于环境变量中."); + } + + return originalConfig; + } +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsExceptionMsg.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsExceptionMsg.java new file mode 100644 index 000000000..d613eefda --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsExceptionMsg.java @@ -0,0 +1,18 @@ +package com.alibaba.datax.plugin.writer.odpswriter.util; + +/** + * Created by hongjiao.hj on 2015/6/9. + */ +public class OdpsExceptionMsg { + + public static final String ODPS_PROJECT_NOT_FOUNT = "ODPS-0420111: Project not found"; + + public static final String ODPS_TABLE_NOT_FOUNT = "ODPS-0130131:Table not found"; + + public static final String ODPS_ACCESS_KEY_ID_NOT_FOUND = "ODPS-0410051:Invalid credentials - accessKeyId not found"; + + public static final String ODPS_ACCESS_KEY_INVALID = "ODPS-0410042:Invalid signature value - User signature dose not match"; + + public static final String ODPS_ACCESS_DENY = "ODPS-0420095: Access Denied - Authorization Failed [4002], You doesn't exist in project"; + +} diff --git a/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsUtil.java b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsUtil.java new file mode 100755 index 000000000..272c23423 --- /dev/null +++ b/odpswriter/src/main/java/com/alibaba/datax/plugin/writer/odpswriter/util/OdpsUtil.java @@ -0,0 +1,585 @@ +package com.alibaba.datax.plugin.writer.odpswriter.util; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.common.util.RetryUtil; +import com.alibaba.datax.plugin.writer.odpswriter.Constant; +import com.alibaba.datax.plugin.writer.odpswriter.Key; + +import com.alibaba.datax.plugin.writer.odpswriter.OdpsWriterErrorCode; +import com.aliyun.odps.*; +import com.aliyun.odps.account.Account; +import com.aliyun.odps.account.AliyunAccount; +import com.aliyun.odps.task.SQLTask; +import com.aliyun.odps.tunnel.TableTunnel; + +import com.aliyun.odps.tunnel.io.ProtobufRecordPack; +import com.aliyun.odps.tunnel.io.TunnelRecordWriter; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.Callable; + +public class OdpsUtil { + private static final Logger LOG = LoggerFactory.getLogger(OdpsUtil.class); + + public static int MAX_RETRY_TIME = 10; + + public static void checkNecessaryConfig(Configuration originalConfig) { + originalConfig.getNecessaryValue(Key.ODPS_SERVER, + OdpsWriterErrorCode.REQUIRED_VALUE); + + originalConfig.getNecessaryValue(Key.PROJECT, + OdpsWriterErrorCode.REQUIRED_VALUE); + originalConfig.getNecessaryValue(Key.TABLE, + OdpsWriterErrorCode.REQUIRED_VALUE); + + if (null == originalConfig.getList(Key.COLUMN) || + originalConfig.getList(Key.COLUMN, String.class).isEmpty()) { + throw DataXException.asDataXException(OdpsWriterErrorCode.REQUIRED_VALUE, "您未配置写入 ODPS 目的表的列信息. " + + "正确的配置方式是给datax的 column 项配置上您需要读取的列名称,用英文逗号分隔 例如: \"column\": [\"id\",\"name\"]."); + } + + // getBool 内部要求,值只能为 true,false 的字符串(大小写不敏感),其他一律报错,不再有默认配置 + Boolean truncate = originalConfig.getBool(Key.TRUNCATE); + if (null == truncate) { + throw DataXException.asDataXException(OdpsWriterErrorCode.REQUIRED_VALUE, "[truncate]是必填配置项, 意思是写入 ODPS 目的表前是否清空表/分区. " + + "请您增加 truncate 的配置,根据业务需要选择上true 或者 false."); + } + } + + public static void dealMaxRetryTime(Configuration originalConfig) { + int maxRetryTime = originalConfig.getInt(Key.MAX_RETRY_TIME, + OdpsUtil.MAX_RETRY_TIME); + if (maxRetryTime < 1 || maxRetryTime > OdpsUtil.MAX_RETRY_TIME) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ILLEGAL_VALUE, "您所配置的maxRetryTime 值错误. 该值不能小于1, 且不能大于 " + OdpsUtil.MAX_RETRY_TIME + + ". 推荐的配置方式是给maxRetryTime 配置1-11之间的某个值. 请您检查配置并做出相应修改."); + } + MAX_RETRY_TIME = maxRetryTime; + } + + public static String formatPartition(String partitionString) { + if (null == partitionString) { + return null; + } + + return partitionString.trim().replaceAll(" *= *", "=").replaceAll(" */ *", ",") + .replaceAll(" *, *", ",").replaceAll("'", ""); + } + + + public static Odps initOdpsProject(Configuration originalConfig) { + String accountType = originalConfig.getString(Key.ACCOUNT_TYPE); + String accessId = originalConfig.getString(Key.ACCESS_ID); + String accessKey = originalConfig.getString(Key.ACCESS_KEY); + + String odpsServer = originalConfig.getString(Key.ODPS_SERVER); + String project = originalConfig.getString(Key.PROJECT); + + Account account; + if (accountType.equalsIgnoreCase(Constant.DEFAULT_ACCOUNT_TYPE)) { + account = new AliyunAccount(accessId, accessKey); + } else { + throw DataXException.asDataXException(OdpsWriterErrorCode.ACCOUNT_TYPE_ERROR, + String.format("不支持的账号类型:[%s]. 账号类型目前仅支持aliyun, taobao.", accountType)); + } + + Odps odps = new Odps(account); + boolean isPreCheck = originalConfig.getBool("dryRun", false); + if(isPreCheck) { + odps.getRestClient().setConnectTimeout(3); + odps.getRestClient().setReadTimeout(3); + odps.getRestClient().setRetryTimes(2); + } + odps.setDefaultProject(project); + odps.setEndpoint(odpsServer); + + return odps; + } + + public static Table getTable(Odps odps, String projectName, String tableName) { + final Table table = odps.tables().get(projectName, tableName); + try { + //通过这种方式检查表是否存在,失败重试。重试策略:每秒钟重试一次,最大重试3次 + return RetryUtil.executeWithRetry(new Callable

() { + @Override + public Table call() throws Exception { + table.reload(); + return table; + } + }, 3, 1000, false); + } catch (Exception e) { + throwDataXExceptionWhenReloadTable(e, tableName); + } + return table; + } + + public static List listOdpsPartitions(Table table) { + List parts = new ArrayList(); + try { + List partitions = table.getPartitions(); + for(Partition partition : partitions) { + parts.add(partition.getPartitionSpec().toString()); + } + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.GET_PARTITION_FAIL, String.format("获取 ODPS 目的表:%s 的所有分区失败. 请联系 ODPS 管理员处理.", + table.getName()), e); + } + return parts; + } + + public static boolean isPartitionedTable(Table table) { + //必须要是非分区表才能 truncate 整个表 + List partitionKeys; + try { + partitionKeys = table.getSchema().getPartitionColumns(); + if (null != partitionKeys && !partitionKeys.isEmpty()) { + return true; + } + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.CHECK_IF_PARTITIONED_TABLE_FAILED, + String.format("检查 ODPS 目的表:%s 是否为分区表失败, 请联系 ODPS 管理员处理.", table.getName()), e); + } + return false; + } + + + public static void truncateNonPartitionedTable(Odps odps, Table tab) { + String truncateNonPartitionedTableSql = "truncate table " + tab.getName() + ";"; + + try { + runSqlTaskWithRetry(odps, truncateNonPartitionedTableSql, MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.TABLE_TRUNCATE_ERROR, + String.format(" 清空 ODPS 目的表:%s 失败, 请联系 ODPS 管理员处理.", tab.getName()), e); + } + } + + public static void truncatePartition(Odps odps, Table table, String partition) { + if (isPartitionExist(table, partition)) { + dropPart(odps, table, partition); + } + addPart(odps, table, partition); + } + + private static boolean isPartitionExist(Table table, String partition) { + // check if exist partition 返回值不为 null + List odpsParts = OdpsUtil.listOdpsPartitions(table); + + int j = 0; + for (; j < odpsParts.size(); j++) { + if (odpsParts.get(j).replaceAll("'", "").equals(partition)) { + break; + } + } + + return j != odpsParts.size(); + } + + public static void addPart(Odps odps, Table table, String partition) { + String partSpec = getPartSpec(partition); + // add if not exists partition + StringBuilder addPart = new StringBuilder(); + addPart.append("alter table ").append(table.getName()).append(" add IF NOT EXISTS partition(") + .append(partSpec).append(");"); + try { + runSqlTaskWithRetry(odps, addPart.toString(), MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ADD_PARTITION_FAILED, + String.format("添加 ODPS 目的表的分区失败. 错误发生在添加 ODPS 的项目:%s 的表:%s 的分区:%s. 请联系 ODPS 管理员处理.", + table.getProject(), table.getName(), partition), e); + } + } + + + public static TableTunnel.UploadSession createMasterTunnelUpload(final TableTunnel tunnel, final String projectName, + final String tableName, final String partition) { + if(StringUtils.isBlank(partition)) { + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.UploadSession call() throws Exception { + return tunnel.createUploadSession(projectName, tableName); + } + }, MAX_RETRY_TIME, 1000L, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.CREATE_MASTER_UPLOAD_FAIL, + "创建TunnelUpload失败. 请联系 ODPS 管理员处理.", e); + } + } else { + final PartitionSpec partitionSpec = new PartitionSpec(partition); + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.UploadSession call() throws Exception { + return tunnel.createUploadSession(projectName, tableName, partitionSpec); + } + }, MAX_RETRY_TIME, 1000L, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.CREATE_MASTER_UPLOAD_FAIL, + "创建TunnelUpload失败. 请联系 ODPS 管理员处理.", e); + } + } + } + + public static TableTunnel.UploadSession getSlaveTunnelUpload(final TableTunnel tunnel, final String projectName, final String tableName, + final String partition, final String uploadId) { + + if(StringUtils.isBlank(partition)) { + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.UploadSession call() throws Exception { + return tunnel.getUploadSession(projectName, tableName, uploadId); + } + }, MAX_RETRY_TIME, 1000L, true); + + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.GET_SLAVE_UPLOAD_FAIL, + "获取TunnelUpload失败. 请联系 ODPS 管理员处理.", e); + } + } else { + final PartitionSpec partitionSpec = new PartitionSpec(partition); + try { + return RetryUtil.executeWithRetry(new Callable() { + @Override + public TableTunnel.UploadSession call() throws Exception { + return tunnel.getUploadSession(projectName, tableName, partitionSpec, uploadId); + } + }, MAX_RETRY_TIME, 1000L, true); + + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.GET_SLAVE_UPLOAD_FAIL, + "获取TunnelUpload失败. 请联系 ODPS 管理员处理.", e); + } + } + } + + + private static void dropPart(Odps odps, Table table, String partition) { + String partSpec = getPartSpec(partition); + StringBuilder dropPart = new StringBuilder(); + dropPart.append("alter table ").append(table.getName()) + .append(" drop IF EXISTS partition(").append(partSpec) + .append(");"); + try { + runSqlTaskWithRetry(odps, dropPart.toString(), MAX_RETRY_TIME, 1000, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ADD_PARTITION_FAILED, + String.format("Drop ODPS 目的表分区失败. 错误发生在项目:%s 的表:%s 的分区:%s .请联系 ODPS 管理员处理.", + table.getProject(), table.getName(), partition), e); + } + } + + private static String getPartSpec(String partition) { + StringBuilder partSpec = new StringBuilder(); + String[] parts = partition.split(","); + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + String[] kv = part.split("="); + if (kv.length != 2) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ILLEGAL_VALUE, + String.format("ODPS 目的表自身的 partition:%s 格式不对. 正确的格式形如: pt=1,ds=hangzhou", partition)); + } + partSpec.append(kv[0]).append("="); + partSpec.append("'").append(kv[1].replace("'", "")).append("'"); + if (i != parts.length - 1) { + partSpec.append(","); + } + } + return partSpec.toString(); + } + + /** + * 该方法只有在 sql 为幂等的才可以使用,且odps抛出异常时候才会进行重试 + * + * @param odps odps + * @param query 执行sql + * @throws Exception + */ + public static void runSqlTaskWithRetry(final Odps odps, final String query, int retryTimes, + long sleepTimeInMilliSecond, boolean exponential) throws Exception { + for(int i = 0; i < retryTimes; i++) { + try { + runSqlTask(odps, query); + return; + } catch (DataXException e) { + if (OdpsWriterErrorCode.RUN_SQL_ODPS_EXCEPTION.equals(e.getErrorCode())) { + LOG.debug("Exception when calling callable", e); + if (i + 1 < retryTimes && sleepTimeInMilliSecond > 0) { + long timeToSleep; + if (exponential) { + timeToSleep = sleepTimeInMilliSecond * (long) Math.pow(2, i); + if(timeToSleep >= 128 * 1000) { + timeToSleep = 128 * 1000; + } + } else { + timeToSleep = sleepTimeInMilliSecond; + if(timeToSleep >= 128 * 1000) { + timeToSleep = 128 * 1000; + } + } + + try { + Thread.sleep(timeToSleep); + } catch (InterruptedException ignored) { + } + } else { + throw e; + } + } else { + throw e; + } + } catch (Exception e) { + throw e; + } + } + } + + public static void runSqlTask(Odps odps, String query) { + if (StringUtils.isBlank(query)) { + return; + } + + String taskName = "datax_odpswriter_trunacte_" + UUID.randomUUID().toString().replace('-', '_'); + + LOG.info("Try to start sqlTask:[{}] to run odps sql:[\n{}\n] .", taskName, query); + + //todo:biz_id set (目前ddl先不做) + Instance instance; + Instance.TaskStatus status; + try { + instance = SQLTask.run(odps, odps.getDefaultProject(), query, taskName, null, null); + instance.waitForSuccess(); + status = instance.getTaskStatus().get(taskName); + if (!Instance.TaskStatus.Status.SUCCESS.equals(status.getStatus())) { + throw DataXException.asDataXException(OdpsWriterErrorCode.RUN_SQL_FAILED, + String.format("ODPS 目的表在运行 ODPS SQL失败, 返回值为:%s. 请联系 ODPS 管理员处理. SQL 内容为:[\n%s\n].", instance.getTaskResults().get(taskName), + query)); + } + } catch (DataXException e) { + throw e; + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.RUN_SQL_ODPS_EXCEPTION, + String.format("ODPS 目的表在运行 ODPS SQL 时抛出异常, 请联系 ODPS 管理员处理. SQL 内容为:[\n%s\n].", query), e); + } + } + + public static void masterCompleteBlocks(final TableTunnel.UploadSession masterUpload, final Long[] blocks) { + try { + RetryUtil.executeWithRetry(new Callable() { + @Override + public Void call() throws Exception { + masterUpload.commit(blocks); + return null; + } + }, MAX_RETRY_TIME, 1000L, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.COMMIT_BLOCK_FAIL, + String.format("ODPS 目的表在提交 block:[\n%s\n] 时失败, uploadId=[%s]. 请联系 ODPS 管理员处理.", StringUtils.join(blocks, ","), masterUpload.getId()), e); + } + } + + public static void slaveWriteOneBlock(final TableTunnel.UploadSession slaveUpload, final ProtobufRecordPack protobufRecordPack, + final long blockId, final boolean isCompress) { + try { + RetryUtil.executeWithRetry(new Callable() { + @Override + public Void call() throws Exception { + TunnelRecordWriter tunnelRecordWriter = (TunnelRecordWriter)slaveUpload.openRecordWriter(blockId, isCompress); + tunnelRecordWriter.write(protobufRecordPack); + tunnelRecordWriter.close(); + return null; + } + }, MAX_RETRY_TIME, 1000L, true); + } catch (Exception e) { + throw DataXException.asDataXException(OdpsWriterErrorCode.WRITER_RECORD_FAIL, + String.format("ODPS 目的表写 block:%s 失败, uploadId=[%s]. 请联系 ODPS 管理员处理.", blockId, slaveUpload.getId()), e); + } + + } + + public static List parsePosition(List allColumnList, + List userConfiguredColumns) { + List retList = new ArrayList(); + + boolean hasColumn; + for (String col : userConfiguredColumns) { + hasColumn = false; + for (int i = 0, len = allColumnList.size(); i < len; i++) { + if (allColumnList.get(i).equalsIgnoreCase(col)) { + retList.add(i); + hasColumn = true; + break; + } + } + if (!hasColumn) { + throw DataXException.asDataXException(OdpsWriterErrorCode.COLUMN_NOT_EXIST, + String.format("ODPS 目的表的列配置错误. 由于您所配置的列:%s 不存在,会导致datax无法正常插入数据,请检查该列是否存在,如果存在请检查大小写等配置.", col)); + } + } + return retList; + } + + public static List getAllColumns(TableSchema schema) { + if (null == schema) { + throw new IllegalArgumentException("parameter schema can not be null."); + } + + List allColumns = new ArrayList(); + + List columns = schema.getColumns(); + OdpsType type; + for(Column column: columns) { + allColumns.add(column.getName()); + type = column.getType(); + if (type == OdpsType.ARRAY || type == OdpsType.MAP) { + throw DataXException.asDataXException(OdpsWriterErrorCode.UNSUPPORTED_COLUMN_TYPE, + String.format("DataX 写入 ODPS 表不支持该字段类型:[%s]. 目前支持抽取的字段类型有:bigint, boolean, datetime, double, string. " + + "您可以选择不抽取 DataX 不支持的字段或者联系 ODPS 管理员寻求帮助.", + type)); + } + } + return allColumns; + } + + public static List getTableOriginalColumnTypeList(TableSchema schema) { + List tableOriginalColumnTypeList = new ArrayList(); + + List columns = schema.getColumns(); + for (Column column : columns) { + tableOriginalColumnTypeList.add(column.getType()); + } + + return tableOriginalColumnTypeList; + } + + public static void dealTruncate(Odps odps, Table table, String partition, boolean truncate) { + boolean isPartitionedTable = OdpsUtil.isPartitionedTable(table); + + if (truncate) { + //需要 truncate + if (isPartitionedTable) { + //分区表 + if (StringUtils.isBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, String.format("您没有配置分区信息,因为你配置的表是分区表:%s 如果需要进行 truncate 操作,必须指定需要清空的具体分区. 请修改分区配置,格式形如 pt=${bizdate} .", + table.getName())); + } else { + LOG.info("Try to truncate partition=[{}] in table=[{}].", partition, table.getName()); + OdpsUtil.truncatePartition(odps, table, partition); + } + } else { + //非分区表 + if (StringUtils.isNotBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, String.format("分区信息配置错误,你的ODPS表是非分区表:%s 进行 truncate 操作时不需要指定具体分区值. 请检查您的分区配置,删除该配置项的值.", + table.getName())); + } else { + LOG.info("Try to truncate table:[{}].", table.getName()); + OdpsUtil.truncateNonPartitionedTable(odps, table); + } + } + } else { + //不需要 truncate + if (isPartitionedTable) { + //分区表 + if (StringUtils.isBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, + String.format("您的目的表是分区表,写入分区表:%s 时必须指定具体分区值. 请修改您的分区配置信息,格式形如 格式形如 pt=${bizdate}.", table.getName())); + } else { + boolean isPartitionExists = OdpsUtil.isPartitionExist(table, partition); + if (!isPartitionExists) { + LOG.info("Try to add partition:[{}] in table:[{}].", partition, + table.getName()); + OdpsUtil.addPart(odps, table, partition); + } + } + } else { + //非分区表 + if (StringUtils.isNotBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, + String.format("您的目的表是非分区表,写入非分区表:%s 时不需要指定具体分区值. 请删除分区配置信息", table.getName())); + } + } + } + } + + + /** + * 检查odpswriter 插件的分区信息 + * + * @param odps + * @param table + * @param partition + * @param truncate + */ + public static void preCheckPartition(Odps odps, Table table, String partition, boolean truncate) { + boolean isPartitionedTable = OdpsUtil.isPartitionedTable(table); + + if (truncate) { + //需要 truncate + if (isPartitionedTable) { + //分区表 + if (StringUtils.isBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, String.format("您没有配置分区信息,因为你配置的表是分区表:%s 如果需要进行 truncate 操作,必须指定需要清空的具体分区. 请修改分区配置,格式形如 pt=${bizdate} .", + table.getName())); + } + } else { + //非分区表 + if (StringUtils.isNotBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, String.format("分区信息配置错误,你的ODPS表是非分区表:%s 进行 truncate 操作时不需要指定具体分区值. 请检查您的分区配置,删除该配置项的值.", + table.getName())); + } + } + } else { + //不需要 truncate + if (isPartitionedTable) { + //分区表 + if (StringUtils.isBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, + String.format("您的目的表是分区表,写入分区表:%s 时必须指定具体分区值. 请修改您的分区配置信息,格式形如 格式形如 pt=${bizdate}.", table.getName())); + } + } else { + //非分区表 + if (StringUtils.isNotBlank(partition)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.PARTITION_ERROR, + String.format("您的目的表是非分区表,写入非分区表:%s 时不需要指定具体分区值. 请删除分区配置信息", table.getName())); + } + } + } + } + + /** + * table.reload() 方法抛出的 odps 异常 转化为更清晰的 datax 异常 抛出 + */ + public static void throwDataXExceptionWhenReloadTable(Exception e, String tableName) { + if(e.getMessage() != null) { + if(e.getMessage().contains(OdpsExceptionMsg.ODPS_PROJECT_NOT_FOUNT)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ODPS_PROJECT_NOT_FOUNT, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 [project] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_TABLE_NOT_FOUNT)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ODPS_TABLE_NOT_FOUNT, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 [table] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_KEY_ID_NOT_FOUND)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ODPS_ACCESS_KEY_ID_NOT_FOUND, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 [accessId] [accessKey]是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_KEY_INVALID)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ODPS_ACCESS_KEY_INVALID, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 [accessKey] 是否正确.", tableName), e); + } else if(e.getMessage().contains(OdpsExceptionMsg.ODPS_ACCESS_DENY)) { + throw DataXException.asDataXException(OdpsWriterErrorCode.ODPS_ACCESS_DENY, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 [accessId] [accessKey] [project]是否匹配.", tableName), e); + } + } + throw DataXException.asDataXException(OdpsWriterErrorCode.ILLEGAL_VALUE, + String.format("加载 ODPS 目的表:%s 失败. " + + "请检查您配置的 ODPS 目的表的 project,table,accessId,accessKey,odpsServer等值.", tableName), e); + } + +} diff --git a/odpswriter/src/main/resources/TODO.txt b/odpswriter/src/main/resources/TODO.txt new file mode 100755 index 000000000..d05f28f1d --- /dev/null +++ b/odpswriter/src/main/resources/TODO.txt @@ -0,0 +1,3 @@ +2、truncate 必填项 +3、对于非分区表,允许出现 partition 配置的 Key,Value 为空。 但是需要提示用户 +4、2w blockid 问题? \ No newline at end of file diff --git a/odpswriter/src/main/resources/plugin.json b/odpswriter/src/main/resources/plugin.json new file mode 100755 index 000000000..d867129e8 --- /dev/null +++ b/odpswriter/src/main/resources/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "odpswriter", + "class": "com.alibaba.datax.plugin.writer.odpswriter.OdpsWriter", + "description": { + "useScene": "prod.", + "mechanism": "TODO", + "warn": "TODO" + }, + "developer": "alibaba" +} \ No newline at end of file diff --git a/odpswriter/src/main/resources/plugin_job_template.json b/odpswriter/src/main/resources/plugin_job_template.json new file mode 100644 index 000000000..3570f9eba --- /dev/null +++ b/odpswriter/src/main/resources/plugin_job_template.json @@ -0,0 +1,14 @@ +{ + "name": "odpswriter", + "parameter": { + "project": "", + "table": "", + "partition":"", + "column": [], + "accessId": "", + "accessKey": "", + "truncate": true, + "odpsServer": "", + "tunnelServer": "" + } +} \ No newline at end of file diff --git a/oraclereader/doc/oraclereader.md b/oraclereader/doc/oraclereader.md new file mode 100644 index 000000000..d5a5d110c --- /dev/null +++ b/oraclereader/doc/oraclereader.md @@ -0,0 +1,347 @@ + +# OracleReader 插件文档 + + +___ + + +## 1 快速介绍 + +OracleReader插件实现了从Oracle读取数据。在底层实现上,OracleReader通过JDBC连接远程Oracle数据库,并执行相应的sql语句将数据从Oracle库中SELECT出来。 + +## 2 实现原理 + +简而言之,OracleReader通过JDBC连接器连接到远程的Oracle数据库,并根据用户配置的信息生成查询SELECT SQL语句并发送到远程Oracle数据库,并将该SQL执行返回结果使用DataX自定义的数据类型拼装为抽象的数据集,并传递给下游Writer处理。 + +对于用户配置Table、Column、Where的信息,OracleReader将其拼接为SQL语句发送到Oracle数据库;对于用户配置querySql信息,Oracle直接将其发送到Oracle数据库。 + + +## 3 功能说明 + +### 3.1 配置样例 + +* 配置一个从Oracle数据库同步抽取数据到本地的作业: + +``` +{ + "job": { + "setting": { + "speed": { + //设置传输速度 byte/s 尽量逼近这个速度但是不高于它. + "byte": 1048576 + }, + //出错限制 + "errorLimit": { + //先选择record + "record": 0, + //百分比 1表示100% + "percentage": 0.02 + } + }, + "content": [ + { + "reader": { + "name": "oraclereader", + "parameter": { + // 数据库连接用户名 + "username": "root", + // 数据库连接密码 + "password": "root", + "column": [ + "id","name" + ], + //切分主键 + "splitPk": "db_id", + "connection": [ + { + "table": [ + "table" + ], + "jdbcUrl": [ + "jdbc:oracle:thin:@[HOST_NAME]:PORT:[DATABASE_NAME]" + ] + } + ] + } + }, + "writer": { + //writer类型 + "name": "streamwriter", + // 是否打印内容 + "parameter": { + "print": true + } + } + } + ] + } +} + +``` + +* 配置一个自定义SQL的数据库同步任务到本地内容的作业: + +``` +{ + "job": { + "setting": { + "speed": 1048576 + }, + "content": [ + { + "reader": { + "name": "oraclereader", + "parameter": { + "username": "root", + "password": "root", + "where": "", + "connection": [ + { + "querySql": [ + "select db_id,on_line_flag from db_info where db_id < 10;" + ], + "jdbcUrl": [ + "jdbc:oracle:thin:@[HOST_NAME]:PORT:[DATABASE_NAME]" + ] + } + ] + } + }, + "writer": { + "name": "streamwriter", + "parameter": { + "visible": false, + "encoding": "UTF-8" + } + } + } + ] + } +} +``` + + +### 3.2 参数说明 + +* **jdbcUrl** + + * 描述:描述的是到对端数据库的JDBC连接信息,使用JSON的数组描述,并支持一个库填写多个连接地址。之所以使用JSON数组描述连接信息,是因为阿里集团内部支持多个IP探测,如果配置了多个,OracleReader可以依次探测ip的可连接性,直到选择一个合法的IP。如果全部连接失败,OracleReader报错。 注意,jdbcUrl必须包含在connection配置单元中。对于阿里集团外部使用情况,JSON数组填写一个JDBC连接即可。 + + jdbcUrl按照Oracle官方规范,并可以填写连接附件控制信息。具体请参看[Oracle官方文档](http://www.oracle.com/technetwork/database/enterprise-edition/documentation/index.html)。 + + * 必选:是
+ + * 默认值:无
+ +* **username** + + * 描述:数据源的用户名
+ + * 必选:是
+ + * 默认值:无
+ +* **password** + + * 描述:数据源指定用户名的密码
+ + * 必选:是
+ + * 默认值:无
+ +* **table** + + * 描述:所选取的需要同步的表。使用JSON的数组描述,因此支持多张表同时抽取。当配置为多张表时,用户自己需保证多张表是同一schema结构,OracleReader不予检查表是否同一逻辑表。注意,table必须包含在connection配置单元中。
+ + * 必选:是
+ + * 默认值:无
+ +* **column** + + * 描述:所配置的表中需要同步的列名集合,使用JSON的数组描述字段信息。用户使用*代表默认使用所有列配置,例如['*']。 + + 支持列裁剪,即列可以挑选部分列进行导出。 + + 支持列换序,即列可以不按照表schema信息进行导出。 + + 支持常量配置,用户需要按照JSON格式: + ["id", "`table`", "1", "'bazhen.csy'", "null", "to_char(a + 1)", "2.3" , "true"] + id为普通列名,\`table\`为包含保留在的列名,1为整形数字常量,'bazhen.csy'为字符串常量,null为空指针,to_char(a + 1)为表达式,2.3为浮点数,true为布尔值。 + + Column必须显示填写,不允许为空! + + * 必选:是
+ + * 默认值:无
+ +* **splitPk** + + * 描述:OracleReader进行数据抽取时,如果指定splitPk,表示用户希望使用splitPk代表的字段进行数据分片,DataX因此会启动并发任务进行数据同步,这样可以大大提供数据同步的效能。 + + 推荐splitPk用户使用表主键,因为表主键通常情况下比较均匀,因此切分出来的分片也不容易出现数据热点。 + + 目前splitPk仅支持整形、字符串型数据切分,`不支持浮点、日期等其他类型`。如果用户指定其他非支持类型,OracleReader将报错! + + splitPk如果不填写,将视作用户不对单表进行切分,OracleReader使用单通道同步全量数据。 + + * 必选:否
+ + * 默认值:无
+ +* **where** + + * 描述:筛选条件,OracleReader根据指定的column、table、where条件拼接SQL,并根据这个SQL进行数据抽取。例如在做测试时,可以将where条件指定为limit 10;在实际业务场景中,往往会选择当天的数据进行同步,可以将where条件指定为gmt_create > $bizdate 。
。 + + where条件可以有效地进行业务增量同步。 + + * 必选:否
+ + * 默认值:无
+ +* **querySql** + + * 描述:在有些业务场景下,where这一配置项不足以描述所筛选的条件,用户可以通过该配置型来自定义筛选SQL。当用户配置了这一项之后,DataX系统就会忽略table,column这些配置型,直接使用这个配置项的内容对数据进行筛选,例如需要进行多表join后同步数据,使用select a,b from table_a join table_b on table_a.id = table_b.id
+ + `当用户配置querySql时,OracleReader直接忽略table、column、where条件的配置`。 + + * 必选:否
+ + * 默认值:无
+ +* **fetchSize** + + * 描述:该配置项定义了插件和数据库服务器端每次批量数据获取条数,该值决定了DataX和服务器端的网络交互次数,能够较大的提升数据抽取性能。
+ + `注意,该值过大(>2048)可能造成DataX进程OOM。`。 + + * 必选:否
+ + * 默认值:1024
+ +* **session** + + * 描述:控制写入数据的时间格式,时区等的配置,如果表中有时间字段,配置该值以明确告知写入 oracle 的时间格式。通常配置的参数为:NLS_DATE_FORMAT,NLS_TIME_FORMAT。其配置的值为 json 格式,例如: +``` +"session": [ + "alter session set NLS_DATE_FORMAT='yyyy-mm-dd hh24:mi:ss'", + "alter session set NLS_TIMESTAMP_FORMAT='yyyy-mm-dd hh24:mi:ss'", + "alter session set NLS_TIMESTAMP_TZ_FORMAT='yyyy-mm-dd hh24:mi:ss'", + "alter session set TIME_ZONE='US/Pacific'" + ] +``` + `(注意"是 " 的转义字符串)`。 + + * 必选:否
+ + * 默认值:无
+ + +### 3.3 类型转换 + +目前OracleReader支持大部分Oracle类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。 + +下面列出OracleReader针对Oracle类型转换列表: + + +| DataX 内部类型| Oracle 数据类型 | +| -------- | ----- | +| Long |NUMBER,RAWID,INTEGER,INT,SMALLINT| +| Double |NUMERIC,DECIMAL,FLOAT,DOUBLE PRECISION,REAL| +| String |LONG,CHAR,NCHAR,VARCHAR,VARCHAR2,NVARCHAR2,CLOB,NCLOB,CHARACTER,CHARACTER VARYING,CHAR VARYING,NATIONAL CHARACTER,NATIONAL CHAR,NATIONAL CHARACTER VARYING,NATIONAL CHAR VARYING,NCHAR VARYING | +| Date |TIMESTAMP,DATE | +| Boolean |bit, bool | +| Bytes |BLOB,BFILE,RAW,LONG RAW | + + + +请注意: + +* `除上述罗列字段类型外,其他类型均不支持`。 + + +## 4 性能报告 + +### 4.1 环境准备 + +#### 4.1.1 数据特征 + +为了模拟线上真实数据,我们设计两个Oracle数据表,分别为: + +#### 4.1.2 机器参数 + +* 执行DataX的机器参数为: + +* Oracle数据库机器参数为: + +### 4.2 测试报告 + +#### 4.2.1 表1测试报告 + + +| 并发任务数| DataX速度(Rec/s)|DataX流量|网卡流量|DataX运行负载|DB运行负载| +|--------| --------|--------|--------|--------|--------| +|1| DataX 统计速度(Rec/s)|DataX统计流量|网卡流量|DataX运行负载|DB运行负载| + +## 5 约束限制 + +### 5.1 主备同步数据恢复问题 + +主备同步问题指Oracle使用主从灾备,备库从主库不间断通过binlog恢复数据。由于主备数据同步存在一定的时间差,特别在于某些特定情况,例如网络延迟等问题,导致备库同步恢复的数据与主库有较大差别,导致从备库同步的数据不是一份当前时间的完整镜像。 + +针对这个问题,我们提供了preSql功能,该功能待补充。 + +### 5.2 一致性约束 + +Oracle在数据存储划分中属于RDBMS系统,对外可以提供强一致性数据查询接口。例如当一次同步任务启动运行过程中,当该库存在其他数据写入方写入数据时,OracleReader完全不会获取到写入更新数据,这是由于数据库本身的快照特性决定的。关于数据库快照特性,请参看[MVCC Wikipedia](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) + +上述是在OracleReader单线程模型下数据同步一致性的特性,由于OracleReader可以根据用户配置信息使用了并发数据抽取,因此不能严格保证数据一致性:当OracleReader根据splitPk进行数据切分后,会先后启动多个并发任务完成数据同步。由于多个并发任务相互之间不属于同一个读事务,同时多个并发任务存在时间间隔。因此这份数据并不是`完整的`、`一致的`数据快照信息。 + +针对多线程的一致性快照需求,在技术上目前无法实现,只能从工程角度解决,工程化的方式存在取舍,我们提供几个解决思路给用户,用户可以自行选择: + +1. 使用单线程同步,即不再进行数据切片。缺点是速度比较慢,但是能够很好保证一致性。 + +2. 关闭其他数据写入方,保证当前数据为静态数据,例如,锁表、关闭备库同步等等。缺点是可能影响在线业务。 + +### 5.3 数据库编码问题 + + +OracleReader底层使用JDBC进行数据抽取,JDBC天然适配各类编码,并在底层进行了编码转换。因此OracleReader不需用户指定编码,可以自动获取编码并转码。 + +对于Oracle底层写入编码和其设定的编码不一致的混乱情况,OracleReader对此无法识别,对此也无法提供解决方案,对于这类情况,`导出有可能为乱码`。 + +### 5.4 增量数据同步 + +OracleReader使用JDBC SELECT语句完成数据抽取工作,因此可以使用SELECT...WHERE...进行增量数据抽取,方式有多种: + +* 数据库在线应用写入数据库时,填充modify字段为更改时间戳,包括新增、更新、删除(逻辑删)。对于这类应用,OracleReader只需要WHERE条件跟上一同步阶段时间戳即可。 +* 对于新增流水型数据,OracleReader可以WHERE条件后跟上一阶段最大自增ID即可。 + +对于业务上无字段区分新增、修改数据情况,OracleReader也无法进行增量数据同步,只能同步全量数据。 + +### 5.5 Sql安全性 + +OracleReader提供querySql语句交给用户自己实现SELECT抽取语句,OracleReader本身对querySql不做任何安全性校验。这块交由DataX用户方自己保证。 + +## 6 FAQ + +*** + +**Q: OracleReader同步报错,报错信息为XXX** + + A: 网络或者权限问题,请使用Oracle命令行测试: + sqlplus username/password@//host:port/sid + + +如果上述命令也报错,那可以证实是环境问题,请联系你的DBA。 + + +**Q: OracleReader抽取速度很慢怎么办?** + + A: 影响抽取时间的原因大概有如下几个:(来自专业 DBA 卫绾) + 1. 由于SQL的plan异常,导致的抽取时间长; 在抽取时,尽可能使用全表扫描代替索引扫描; + 2. 合理sql的并发度,减少抽取时间;根据表的大小, + <50G可以不用并发, + <100G添加如下hint: parallel(a,2), + >100G添加如下hint : parallel(a,4); + 3. 抽取sql要简单,尽量不用replace等函数,这个非常消耗cpu,会严重影响抽取速度; \ No newline at end of file diff --git a/oraclereader/oraclereader.iml b/oraclereader/oraclereader.iml new file mode 100644 index 000000000..c352ce1cc --- /dev/null +++ b/oraclereader/oraclereader.iml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/oraclereader/pom.xml b/oraclereader/pom.xml new file mode 100755 index 000000000..739dff042 --- /dev/null +++ b/oraclereader/pom.xml @@ -0,0 +1,86 @@ + + + + datax-all + com.alibaba.datax + 0.0.1-SNAPSHOT + + 4.0.0 + + oraclereader + oraclereader + jar + + + + com.alibaba.datax + datax-common + ${datax-project-version} + + + slf4j-log4j12 + org.slf4j + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.alibaba.datax + plugin-rdbms-util + ${datax-project-version} + + + + com.oracle + ojdbc6 + 11.2.0.3 + system + ${basedir}/src/main/lib/ojdbc6-11.2.0.3.jar + + + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + ${project-sourceEncoding} + + + + + maven-assembly-plugin + + + src/main/assembly/package.xml + + datax + + + + dwzip + package + + single + + + + + + + + \ No newline at end of file diff --git a/oraclereader/src/main/assembly/package.xml b/oraclereader/src/main/assembly/package.xml new file mode 100755 index 000000000..a954a30d5 --- /dev/null +++ b/oraclereader/src/main/assembly/package.xml @@ -0,0 +1,35 @@ + + + + dir + + false + + + src/main/resources + + plugin.json + plugin_job_template.json + + plugin/reader/oraclereader + + + target/ + + oraclereader-0.0.1-SNAPSHOT.jar + + plugin/reader/oraclereader + + + + + + false + plugin/reader/oraclereader/libs + runtime + + + diff --git a/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/Constant.java b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/Constant.java new file mode 100755 index 000000000..8006b1a6c --- /dev/null +++ b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/Constant.java @@ -0,0 +1,7 @@ +package com.alibaba.datax.plugin.reader.oraclereader; + +public class Constant { + + public static final int DEFAULT_FETCH_SIZE = 1024; + +} diff --git a/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReader.java b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReader.java new file mode 100755 index 000000000..403b30e9b --- /dev/null +++ b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReader.java @@ -0,0 +1,126 @@ +package com.alibaba.datax.plugin.reader.oraclereader; + +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.plugin.RecordSender; +import com.alibaba.datax.common.spi.Reader; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader; +import com.alibaba.datax.plugin.rdbms.reader.Key; +import com.alibaba.datax.plugin.rdbms.reader.util.HintUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class OracleReader extends Reader { + + private static final DataBaseType DATABASE_TYPE = DataBaseType.Oracle; + + public static class Job extends Reader.Job { + private static final Logger LOG = LoggerFactory + .getLogger(OracleReader.Job.class); + + private Configuration originalConfig = null; + private CommonRdbmsReader.Job commonRdbmsReaderJob; + + @Override + public void init() { + this.originalConfig = super.getPluginJobConf(); + + dealFetchSize(this.originalConfig); + + this.commonRdbmsReaderJob = new CommonRdbmsReader.Job( + DATABASE_TYPE); + this.commonRdbmsReaderJob.init(this.originalConfig); + + // 注意:要在 this.commonRdbmsReaderJob.init(this.originalConfig); 之后执行,这样可以直接快速判断是否是querySql 模式 + dealHint(this.originalConfig); + } + + @Override + public void preCheck(){ + init(); + this.commonRdbmsReaderJob.preCheck(this.originalConfig,DATABASE_TYPE); + } + + @Override + public List split(int adviceNumber) { + return this.commonRdbmsReaderJob.split(this.originalConfig, + adviceNumber); + } + + @Override + public void post() { + this.commonRdbmsReaderJob.post(this.originalConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderJob.destroy(this.originalConfig); + } + + private void dealFetchSize(Configuration originalConfig) { + int fetchSize = originalConfig.getInt( + com.alibaba.datax.plugin.rdbms.reader.Constant.FETCH_SIZE, + Constant.DEFAULT_FETCH_SIZE); + if (fetchSize < 1) { + throw DataXException + .asDataXException(DBUtilErrorCode.REQUIRED_VALUE, + String.format("您配置的 fetchSize 有误,fetchSize:[%d] 值不能小于 1.", + fetchSize)); + } + originalConfig.set( + com.alibaba.datax.plugin.rdbms.reader.Constant.FETCH_SIZE, + fetchSize); + } + + private void dealHint(Configuration originalConfig) { + String hint = originalConfig.getString(Key.HINT); + if (StringUtils.isNotBlank(hint)) { + boolean isTableMode = originalConfig.getBool(com.alibaba.datax.plugin.rdbms.reader.Constant.IS_TABLE_MODE).booleanValue(); + if(!isTableMode){ + throw DataXException.asDataXException(OracleReaderErrorCode.HINT_ERROR, "当且仅当非 querySql 模式读取 oracle 时才能配置 HINT."); + } + HintUtil.initHintConf(DATABASE_TYPE, originalConfig); + } + } + } + + public static class Task extends Reader.Task { + + private Configuration readerSliceConfig; + private CommonRdbmsReader.Task commonRdbmsReaderTask; + + @Override + public void init() { + this.readerSliceConfig = super.getPluginJobConf(); + this.commonRdbmsReaderTask = new CommonRdbmsReader.Task( + DATABASE_TYPE ,super.getTaskGroupId(), super.getTaskId()); + this.commonRdbmsReaderTask.init(this.readerSliceConfig); + } + + @Override + public void startRead(RecordSender recordSender) { + int fetchSize = this.readerSliceConfig + .getInt(com.alibaba.datax.plugin.rdbms.reader.Constant.FETCH_SIZE); + + this.commonRdbmsReaderTask.startRead(this.readerSliceConfig, + recordSender, super.getTaskPluginCollector(), fetchSize); + } + + @Override + public void post() { + this.commonRdbmsReaderTask.post(this.readerSliceConfig); + } + + @Override + public void destroy() { + this.commonRdbmsReaderTask.destroy(this.readerSliceConfig); + } + + } + +} diff --git a/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReaderErrorCode.java b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReaderErrorCode.java new file mode 100755 index 000000000..05ee8604a --- /dev/null +++ b/oraclereader/src/main/java/com/alibaba/datax/plugin/reader/oraclereader/OracleReaderErrorCode.java @@ -0,0 +1,33 @@ +package com.alibaba.datax.plugin.reader.oraclereader; + +import com.alibaba.datax.common.spi.ErrorCode; + +public enum OracleReaderErrorCode implements ErrorCode { + HINT_ERROR("Oraclereader-00", "您的 Hint 配置出错."), + + ; + + private final String code; + private final String description; + + private OracleReaderErrorCode(String code, String description) { + this.code = code; + this.description = description; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String toString() { + return String.format("Code:[%s], Description:[%s]. ", this.code, + this.description); + } +} diff --git a/oraclereader/src/main/lib/ojdbc6-11.2.0.3.jar b/oraclereader/src/main/lib/ojdbc6-11.2.0.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..01da074d5a137914da574f929a4736ede7811a23 GIT binary patch literal 2714189 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μgD^KgtR7X`W%eN5Wg%dq<7ts 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ž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

r?oA(+gT|Hu8#SoN?z2RBW)cKo-1 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⪼{K2Gp0A@_cO1Wp9>`~pQAIEN9yox{g4@C((z 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%0Dj#>mi!JU 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

uCkMfevHK=va0moyu;abJ@+bmi-(3 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

mSZ{dUQuK;?vrXitlrgi%q>g3 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 z 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 ~SOtARn3gD4c(x5RPc_GOt%H>S{eMO#NvH z(7^R2Qd}{mBt?1zav5j3YIi$dNqQ72nC($Wn|kp}H`BcXFN&EEeQhh?rZk)z;?QB9 z{H@&=my|1ELz_eed3&60k?MlEu+X$%s=pWLXpiMry*J_?&6`Kv&7wv5Q-qk0b&nh! z9SKoWZ8~1aJNdUO1hE>Q4e%|DqWTtca4=#I5^~9Y(SBLSHEip3-~_dXPkc>Cpf;gO z1?dMqSg(Iln^CCYFWf=MGj%eVDH1c9u`!}uo5Tae=1<_mDpsI@?~~Xf!YI7+c?Mu( zeWyWk7bi73z&U67Mo|^Yc2d^tGhT83Gjzwdi20;Hu!jNu{l4S>K>xRy3+^ZTH9jyf zFkmn{H!wCgFgY=>y8X|^qGOfznH&`{u)h7IqQ&E+#Uhp7nvo_EH!wOeu+igBov*`1 zp0Ao75#NrUC}mRxD=jNUD?KI!e0He#ab|k@)(KAX#tx3wj6^{IlN3KWBfYLZe0Z1R7(YaVdA#ufLcIo*HW#Q#UL z)C_H0|9>=TdX$--u63M~tf7;mH8Vi~z$C;^&PcDj$4^Pk+8L54 zh*GU-69W?iBLjmlFfsr`risB3z=94e5tka68;kre&5`a(ZxH!omT+JI05tz=bHv0X z|5^?Ak5A{ntut9$9$673bd9n!-BP+xAxfu5%|PwR82e~mUb*)9dePC=7;^EUuGSCfFphNVZApC0-?5 zCH0VPBqt2|;n*K~OebK%JQ|u~omJn;$l6=#_@U1QzPD;&?2*>PmG4l}Txf)Oh_ zVl*8U*mw0Njxlh{iIq7z4rla z=F#ozFoA9+f&V9gZWW8NwPq6*lDRdUbnnz1cTyd1Z7CwC+c|xqrL3yjaBI}8WI&NR zNidgmqlZ0HadvqsGtJggDymTPQC(4A@loATw|%XW)nB<))mD+zU20XSt@XC&q~ zWSvo@<|jtMFZxXo zv2EM7ZNJeQ+uE;cxBkC&w`%YDvM;);&r_$Xj_jh`=Jm&puWQ?mgnQSHoO|1bomo&3JcSUT+PvJ@(ryg7(|oz!$#p zF?W-PF6NKiX+IjwzSzCQxtkNf%k4+Ue@ddj=X<=L5O!Z760U;%L^)xB9q#kvR?tBSnY)GQvy%+oxt zw|Vbna;IfrIL0PVv`N{tTr^+v@U9j$&#_(QZNl7cMRJa*T_wuhN}~!%-Z6o;p^V;H zDK2mGqBC}Mw{?{ z%t(DYf9AJ4AVxz6iW-C04nGRj>9BhZ?K-mg6%uMG6Y(Sd)f(b(KoQ>FW*?uNXL(^` z)uFt{c8vgiKFk^+{EO}C4ruU) zAFE{&<$lU$VtVrs5!`#|OFexh->o#>dSyp_{ND^#0b{6|4k=cgj#8;AZt#IYcbuYf zuGV^36yJ0m|DtWA+(7*b_xhfx7|*93(Jqxm-0#l`9WeDJV|#~iQ*MP zM1ls+l6cJp(Rt9bg*GN#R4{dS80JAQa8fYUKD7ahk1dkmg@6^TWSg8!IG>huI{;a?4S-3P z$q^$yT~$GcD_Ne;Ej&1}UJBkLijgnaS=OpJOLkLSZV(`r)VhQaoGF)GfRUtaStevl zz9ZWOXT?zw?3UFW{)~d5+a@mC8Okl^1OJ!9B2Vh$Og#xM}n}iZM~W+#bmStActQ>PKpDJgfv?{TRx=@S^>ko6L5pLTL`ENu{?kn>95mrCc8;v23pwt1xDwp}da+@F2~9~^WP;0P5~ zuM=qI+T@|+a2sj}U_&}(J-lG#Yi>}4NflpPuWV;;dXpkqx%V2s##X-^(79}ZV>Z59)J%9Tt|$YVT{I%hj;I_$_-z!gFE z-_9?S#YsIZJLa_i^sqKbAjA#MWjb?q`hH_QnL(xsVn~0i&gQ2mdpj(X!%NVov6_D% z@A(tJP%34AW89bdNLGvLrS$7>YB!(xqQ-AdUp&pd)A)BV$Ac%eq+as*y0VH!Q_9(i z*MH^EwetvuoACM3k|TXC({G z(2gM2$$FRk5hR^2Ea57^*yO`3a8zR5kBojO`qSLD*!yz%iD%CTm2$jxmZw*wX+o07HW?F5CZLP_^O774C59gGyrq{L7lZtDmaFkok=O(z$y;`S$DFDk>}X}pY)`zn;aA)ehmC8qnmoi+dzN`&$*q-j9VanLUBsWHQn&ES^to=p zv9*qvY;e$Kw(+7kq6v930b&kml9f}(;HG%57h1~lWk21=b7#|yy~U07lH263l5wBV zV;84uwlEHEZ~swSFWRgJ-?(Ll@3}>@OBu_oZI1(uY?*Wb-b>mJ2v=?Iv9M;cJST)R zkfJ9s*e-NlPH_q1m`7W+%iIa6cG=yQ+YsfHQK?M@VG@^lGhNX0Wz~L*_vDatf|^LG zR(;BkBRbtR8*4$R)Xbv1|yRxuX=xz4e z()PeDZ3L-sN4ZM%T-=KJM7AVvXmyW&mK8w!U45PzR<@Nvz%ZbnbyRQn_(u0(GgKp~ z3vr5b1Q*NM0B7Nv2XETs(E}g3%BjpR_C;%&qi|IZQp49KTq>2ZNF?*mlDvguq>mmG z>zztp@&s|F*}L?(wu#p}b%)ZMh}53PR5%T~_rWOMaNB)jON(J8e6w&IK7i$ zdz1Q3EPgX_u$naauIv^y5H&g3r>3vm8$}lkg{`Y(rz7+qnvF+$v`_x^VE8$~r1Hz6sw*LS1*Am@x75XQ@N%jAg1&2J=Q1`-RX8xhD}+GB zJc&b_-^r1n?oU=DV{p}nR=Wkh*#W5jvDVr;L1j5^on!Bbq#HT2hFRT%Z+~A2&@m?9 zhVF!OawEHBs#JZ?!KSp1xrE&%rOWStQeY&l>twu%gLQ1m>v*)yflLWk;AkuCtkF$Z zoJFGiSS|Ul;Kfq96E+VI>?S?nq)oix;%m55Zx!?R;y{;M`jbBuoDti&lE1fl?7MY$->QNJXghHw zWUmCc_Lki#FhG2Lhpr1Q4{>Bbu+rnrJepx%FfZ{D7`vxvl0^2H zdkpcp=IC$ywgslxxDrqZaEDCI>O(MeU_8o;YBYIL3l2!gHvEmj;W@#6q9OhRG$=yFM%f_z@5Wd?I@C@x#9S zfc@`Cs~*{GfDQKR*FMz${de{MBdx5Vr@gC-l%1LV|D@WKWF3_yLA0@-tY-Mw17av} zA+g`IVprgbiBXtnLa_Y(jK*VWNT9z(23e_$zeM#t60mtVxep<4MYwY1bhL>Q@135V zoidzL zVi38(bW9>DOB+nD&Qqt5HdtMphYT&|uF5~G8i6=wPEtEr6?8guS4!!Z$|6hNUV#N1 zWgA^mWfo-av}_$-mj&smzAXmj7vy_X3XlI?`D@x>EJ7U;c<1M^**0cc-;VaKT1<5s zYaZv;(oE}>^>dT)9d^m|Y!w-|1-)i=TL{yI#>c_z3hp@h-U9#R>h{pW6AajQ2fh&2 ziOSNmIF@Yb5-f3md3cOcT*yl^XQy)Gw(SmEGdI}`)rJ}6fL3J#bG90;?CpT4%6?Kx zB@uZRzhN%{Yl^f~K5DSxA4*ofp{X@YpslP^m|-(CbaV=B87_-VL6uwx1X*iji~>6i z!(MtJTzuteG@|;YkAWX}Fyyxl@~^;*~Jl zySAHTTH7uIokua71gK3eKfu47UYDKTErW#K0`>PgVk8fka*Ep~m8}WXgV?Uhhh&7h z5?ZA#X}(FkouMgKFW5w{enkKj9drR45i&JN_G=_Ci)4Jyu^>iKm{x@Q5$nsu8wp}K z9x5^q30@*KN{L`GZktOhp?3U3ai+ z`s=q!Sji4T`qh9gLWlJLZ2H`1%pp>_h34tZs3paLmuMJjeoBX7-O(G z_Tzy#rkA5iw2tNW>>p&SYYVrve!kcjcwWX^#fzzTKI{F&(GJ#=B~1fKsICF*`zfC1 zT-%P;_14v7mtnUI8!P`b8(-VjDC-aYjDN1-T{>_gw(JuZ^mSBKm2%wM?z<|SI!2P7 zPn~nW#KVrEWTlW)h1X9)f?hp2BzT=jHYiAXkFD6v7==Ravb96jG zb*#8qy0u$bcJ+dFW?i_gE{{CQ=;yhx{zGC35qSF za(EHX11+p~*pZ~T6s?EM#?h()v!-y*(w3@7DP49)1QGHureQ`8)&Zj?{nJHJ0&`i~ zLgBHDwIk?64c5<#hM-74IEx*XMRYmcF&7*)?nVC(bKsYTy{mKhH)*q`w|g3Fqa1o% zytB_>y-=oealK1a3yGHId9w)^#d93fyY4$sWGdh+7RlJ_^%tZgyP&pNzz}lWzE1!q zad*VRuQ5h~eKJ|3QJ_Ry{tLPh?4wyo$0CR()iX8|9e@yQtctWL0&Id%lGMMD<_#8n zF~bllDjf!83BS;VS6bscYB(BpdXiT%^w{4n6vR*qA25Z3dZKzkcC+{ofHy|KHU9ubd5ENFP`b??TS;gfX*zwc6aqP-E8pAZJlqn1dP*zH^8P~{x+359-uRY z?{%R9uJ3i}+)c$4-(yGGuN?`N-J1i%TgVDm3O3%OlPlGAvCy66*0CX;SAA+Xul&Bq zX?{fi^qaD6l4S2>Z9?YzW$*&xzx{`;r zH{7#N!q2=%&!w5Y!qzs+ZJy-=z4z|2hnFP-ke`0Awg>l}PZ5qE$x}j=Gt?Y^X%FAh zhdI9bVcj9j<$DH>pMQ&Wyr0(Jv046A4>vB~J+nVofoz}9IY0RiKl3<#E)PE_mj1;B zKSgs2tQ$(7P?DIk4!UVboeAsYtlPg13US)#A6a*a7R&b+#JEes=$R>Jmc=lhrpYP! zEDR84$($hwE-a+ZX89u*~Z^!F7y0(xleV*WVn0q4HSxRQB7s(7+_M0QNe zU>Z?|XGZOm#fTExk;HAcOI8j=wWuJUw;E7J4fN73Ov0EXu1wOHMXpTb_yk9D`w}s( z(T;XZyI?#C5QVC;4$+YW?XVr#m=19N6p|OrQQ$oyA!JL#s6t*<+tS4?ne$w+g zBqhD(d9*BGQ%3r!`lRh$L=6Bf^Hh~OSG;4%)iI2Ic6mgrxvD}9 zv2IX+6sl=MPCHv>hY17-OEWBvj3nz9M$1t3$YQ3cc!ko}7C%z!>B^n4b+)H2Ubr~& zmGrHQz*~<0-hz%**V`_S&T?^NDR76if^npA?TqE`D*_-aGUWjQZhG4X$nG$Ul0mHh z+I2AdB-oK(=1=wYwoj2?q9MzVh4e06qQhMlYNPc!*K4BrI)S$lJ%uWmA1-(G^v~Yw zqIVJW1g_Czyf)pOf_cGqcbqE%2N>bJ)v~;282-2Q69C2;hY)^+Gk~SuXJYy*wjOU) z^eJz(B(Fl!cjW%h#*CzWRNs8KYWypWul{31+VI{sz!b4cxUiA>4#roXjQcYu^*u8@ zhg`p`HcIG6D9?ZKRL;sHI^u^Nea|u4-SsY)es^sIlJ!jXc~$B_OxHO!*= ziWC}+Nwx40_w{Wr<;JNtHJG-yfn!fw(~uw@h|s|^-Opt)|6Z(-6M{ICDV(8WTi_}% z;Cp^lRkeq26Fudqg*9H9u89u52$~rf#kmCLcDQ=F`of+xE1E16IziZ=uZ9uJV9aRh z)>@g<))r6DoXpi|vsgc8V^2}18r8jNY7p4Ph*sei!2}74KyjvRG*}s~*i;(2&1_ei z9;*&rWloY!sl^&3sBj&6tQf~yRc7mjI-8`xEt;yWiRx5dm~&bYN2OPm60Kv2ElL26V*e1~R23D-2^D*m zJMyLSDdB|!S&pQnBe~fcNL`?=35AxCz5%Btlq=STKkg8;y4OHG5mG31a>b zUtO(gRLaySMEG7@0VvucvN&ZSoy4o`pXL}`q=6sa+NhTCtx94dXb~Z>lxxFMHp)kIy z^!x@z4SR&Q^}SD61$yEY&Kk{Oz%3s2bh+C)!Ztjq87O^l0Se-)HwHdfJ)>Uyc`wD1wOEv3*9iJh{EIN-v^=J(^yl7f7&(tUG#x0aXqb{%uuWM^-Y{g}~D$+1^3%6)b6`scHb=o{<@MXcF-sz0hlMCXxvnNOy6bncLxgyH-k`M0~_ke8K zf9j|ds{x{9_}9|ZIs|kKEEGZ@Y9Yi*W&4^rUg)**a<$uNPm*U)@90cFP7a35pGV9f zlh;up;?l4nSWGb$1Y8mwznOr(8b2|g(V6d1mQh}8irP}5TzsMO&67hx3ARM@! zG5rc}k|*Q!1KAD>O66)}z4i|Bbl`PX)GidNXK;(!i7?ANNQGqu1&Br*-v)joWoVTu zwaDZK!7}{T$PnqKpsFsB@_+PJ+hqZ}3CU-52Zz)C8><;Pg0?js6oT0F7{+7T8H7f|K6K1Cb+f-5sGgV9FQ6(U@4W=iwI_eKsah{gGNnEAWrJDWzkg{&q$9bmJ+6oc02^|VB`_)VdP*!4nVFgb$ zpKMoUgK7mzjFLhr4#~*d%_PUT(fyORbJ_6b8Ugenw>Ayv*>q1@v`TXDo8~5hEn~TAj0LBE&84@q z#(3jxG4i_IR^>1fr;0vDy1aYLFjTrVyvsyI6md8!WY4j6YHywIN10wU_o*v0!&tdw z2NEIe!+;aTv{SUd)j z^x(&F^QT(xyvFso>)=@KBj6SU(wN%B!8_BnZ0iVawF7o#b9)x+e>Vu>^uzMkt1c~r zdqQ1(FwpG_XWQy^;Hf;v6L1haN~R3_|Jeoih~n3p_lZ@dX)mH6h*(~&`}1`5Cvf-8 z(=EZB9q7QXMzL{TvDjtUNs5?Z`M?p%bjSwp3|xx>`-q!IzP?NuPXFUER(h?L3Bm8 zkf~PobZ7P0kL&vc6L~wMO$S!I3?K_&UxGb%5A2%WU^m7;;#_jkPWCeI(S2Yy3O>6} zfrLFC^o|FHh;bm{b1xhGbxI?GL`LB|Hkh6m0Q#zi`X;7ka_2eOIGkO=1ID(|l<3{u zmQgf}+pXK)t5rZz6YSfG!fy}fn-N|@anOar3ztzo{hNMpoYL`f|EO1p$ctb!w(T^I zC-`9tu958eYZ(`pR6z5c8e9#MbNf0_OFZVMu7(o#9;ftfIxqsP;Us+3-Sgx!BkY|i zrKd(ESBJR(G|dhY)?B)5BxRyf#Mvv9(c$tTg_HAaj+I*MPdGpF$ZwEfShx6rrS>tpXn1}wv8=D$9b*K% zKro5@e&o17%m*1bEn*3*OaAlKr42f_ZkzGMVukB61S<&%*04bmSth1+Fx8w3JacUJ zU_MDX-)uSgzKw(;Ng1E9UXJy(OI(q-RAV?U^*ELz4=tsKLlJ+Z#JZg?1MyW;N8>Qq;qiRF^OY zBHEV@S=DMbpranjlo3VDj%*^&?kY${;=j``H++!F0>`D2I;I+=Y&kiW@35HAbYvqk zn+PH@TQbMXwU+=JAy;R-2EairQV4!IeiN-ThSw*hf#Xjp`>PgU27cX2zAZcL#&g>*dk079!Ihb z>vmh8g(K?Y#@fv6qxVXKkXJr_O}%Q->FeRO6@C_=`?C@N6*>t-;!D>&n+1u=8L zd{`q`QHnNarzn+AD>_(Si{LA-b;l27Cg*m z82;#i5;N6$yrN|yC~JR65zXm%JmJ;O-LCQq zxvu3J3BHxWZdkTRSR(@BLXn+J-*)d0j*b1|ZJO3NE166|Jwlwz15#tN zT>=~%f6OY}E?!oX-zC`^^=%7O+E!MdF(L560jWauh-PruB{jB0li4ETAJU6xS(1ag zEvuoX7&F3UNY=7r>vSBrPSM-awHHS3)qc{ul~o;bAxBnA5slJynZdRy(s zXJNb|xt6yjKG@GD>W}%P2>d7U}Cn!?7aE*!^>` zEaJ=7Ny&D)&YP2IvrWPmI)ikHnsDmvt(~h9lR0?)7dWFD_;Tv|{I0!W(wBH~^6MCY zldZ`0G8B@op+sb~L|i8x+dK=a%7IC8U1gTzW~fHX*n!qWHI$VZ_%Iu>6SLC-&T(9- z?~X`*4wYrVdL8<}IlMZl+#Hy4=JCQ#YmC%w;xtLD-H!YR%<4e>s!$fLt9wf4g)B*t zlKzhHDecJYVM2-P%)tyAIcavpur)Ri_^Em8W#FcMS-4p_b#|U!2=*W|CI^jq;`w}5 z*J;^0=jBbFZNH)+arT=4_vBGlEq*+t8rHoN+8M!3clgw$M$AprStYbJ)ox!6U?t8) z?uVUv@4*7TY3C}wo-jQ^6-KJ`w;U5>$RB?oHS4r4%M@x2|@uw*W)!DMFI)cIsuzgtw!H0LNuQya4z6&CX|lVlcX36qSDd*9b9zqHKLJD{GSFN_6HhEL9sFRUK;G3*;0_Dc)=r?+3j=v7 z1=R#SM=#u@KlBZ0Uwzicdpa)x?zXh@yqa8kSue78d>F;0lE!NE9@hz(RpRSXyy~K4 z*=gd8iOGGZF72F#eF1=*M-#W}^0Ki}=)T3{l32E<+Ipw0a3vOEZq&aq81XT64aBpLYqfz6&h=<3K3nu@`6xzuu z!m4KaO{0z_6MC)5jO;MDQ3bZ!{>Qn7Biy>K?as;pL){{(Z!KB^4Kg+rad z&H{#`@Q#fS#;ZjwQd6}KF|%^5`g&~#N1VcTKRwSA6QFtXIgCH7B;!9)Zb$g=bw3;T z(UM+MSR<*^?J$%5)yThwT)?ma?+I?d77iYBr&8_NP)iO2O z>dY#?sy~o}UajcAq6!dmf(&XALxZXL6iW2n_`7~#bt!(41Bhw=UQ+%II+npdo~rlh zDDnXx>_D0N^|h`R_g>ZTjpJ66dCHyQ)G4lZ245*qX04pks(lu#?v-?&Cz94)=>yxP zR?^n6SK$&qn6_(nU zAWhjqk?cm6>_(CNOq$G%BJGVTodaFs3tbY9D*b^f9Z#A};F_EoSWM$WOE|p9x!=#| z`Zl8PAW%&C%IU|aiReIM;ehK6>KwKajc=r2B#rcKAe4@v{Iv2V`};X47w*u_VF({a zoS`WXJlHARks%|KIHuPx#_bfAr-C~Ue}=wEPV^&L>xDnxb$(y^#O%6LXz1mw$Fjotf z#WTh8DO&IcDdM+t)WE+laIUPX0TpD5S`)B0ZVJ!8`XU=1I}KCx-lp_PbsMmi!)Fzd zq4KcL#e8^3oS=MP`1@A@y(uH%LJZd-pD_Lgh>t=+FVPAsgdBwX_@p~s5kT(*_!|)d zpWnU*#x@_rX0Tw3>(P`)A>+Sr6G2h~9KG6&3hGBuUIQf)UHoW{vZ@~` z1wjhg|HO&@EynCm%OBEc|M@Fo{|fOw@WOeAhya7oO!dm4lWE_w%Cno-2kG-x!^mp6 z07hYK>P7)Kn4y=nCAdVcvNjN@iWRIfkB1{-J<9oL0D7M;dR!~ye-cDA4KGFu4>}#7 zL<=_BAe+U^SFaJnd}uov)7CQbAIrgRP^GGtU4?(sD80c+0WepG8n!Ii%UMkapq8ts z&_yBPAgm`0?l7Q1f;Ewu`a7AAQJzel{0+v??C*KQZCyJPp z#(l!);aOVC5E*J8MD@&&Y6cU5;mc-n0nBKUs1yQ5;5Jwu>kh0f?EgjA_m#3QRD%bEbL|-H=6^0Y683A29OraGAj{(y` z^^jCTECe!_UcWVByI2e1OSO+EpFT|eAY)=4oN3_hRoG{QP)Q|BiMc=-vE6AC@s=EE z%mguL!gp;j?w@T;YCRb<)cRRlf0Z^F8-nOquxz+Q<27fDZ60x^_C)eS+n(rDL^2X* zKusk;O{t(9&}Bg#r}oITsYgq5V^2$qnx_Q!E!rk8;!}=U+Cxza zA)zMZ(Q`NZ{zCro&2 zOYvMWp9q6N2%K(WTMO~Boaj(vp!JBwknpz7S_eK9AG; zz#m?U7)LejaB!mH*TY z+#_hN!H_7zqUp%?^j01*9=*#f51!Ber5*Uj{+5SQ`+GfXUm7=xK;6DGT*INOx;PW-FZ(qQgB&*TH^dcOcH9 z1h{S*0uNTY>02P}>eNrDEyJ5EGo7a`XVsUoW3Or$e{Ic{wAz|&byQyIvbDlcOf|1# zQgFs|zWAuX$+B|qgHGMLTzM31EL=2t%~N;NM>bx$j(8f7kIM8{2_3fV9|(<~T>Ocz zlW66~&OMsB1&!~Y;)S_+z<5oy45Ofu9mMW^Q=8-R@Ss;VkES1nXR~9bdFlv1U+8}|kscB3?RB8(hRX#pHV%q}4Dr#uF9efUA?><>IPWZZ;s zxfRnQRN8=az1ZPw^4yUoI%eI+AJY+fIT)3(-Uo8V8G8eRv&70{hihWcSNtxaEXld*9sxDZ zL^PMg=y6^7&~WbV`xzv=*!(zEwXft;JOJIu3WOV@jcFYuWd!_V-<@=mXEH%)!5vnU zjx3OO#;P-Cnn;W9vHp4;0Xq=X>F(MlxY-uRn&!AKQ zjPAK$$shGwp>&ZX;Xd$syyfpzr?#u`u7sCO>T$YiTKThB%3$B1l?IrnwH*w$?)wIO z#!;GwW~QU9&U@XQ+Yfc1%o$(JzEyBF%1S5VwHT4oqX+vR>E{7o$|xw{_hf5P8jo%h zv&)$fS`dBIACcDrNwgsgB~a91sB|iE;ZQ7aiU_89@t9C}%{HZ&a23&Cv&g76+G_p3 zjsrW9Hh+s@!iyJ~;smiGVMU~o=!FrlFz1INHpTt4juhH*#v*E{9zH%mMYGkm&Q8f} z9R#MJD>PUA+OVejf}Fs38jQ+GQ5R{bu#5r=cT)#PNWtsJ*2OA_6Nf4?%$CNt`YQ{O zmJZr8tO}$l9r(qBFFh=)>)J8X-}5IAvl2f>A|Tt(&G4XYI%=!QA{x~DpkNXpZ^00k zq&6aDL|+`~DY^QFkdVrSuvR6 zmZ0|Muev9muMB0CPu!N$AK9DYE8y05PyO0u*rKuYT8%??MxuNF_U9Gj5O$LbHz3(J z`K1u-g)!w>rDB+Ry zbEhde4nX$t!V9!X0Z)pY!RIYl|Nn4ETVRD?7feF+q=IigYq3nnQ2kzZayKdP*^pKE z7C|I#MUu97x;-)^E5U*AkD!0HwgcfJ1w2ebOJq-YC2P=Rrk(Fih_~vw!_Nr&e_|Fb z3Rdx+K1A3Nc^V^4xTGBqBbvsbr5(j;WJQsoHZWoxK_e<_U)>RQo53zv&nTSujFX!n zkdIyJWmq!G)g@cHO|)y7s6>$BQJgOmW z6d5ApvYo@k_|i@K(9Q+at9^{FKN6SX@GX!K#P0AYABqeDaEBwtj8b?(6@WjosPQ7v z9-y;m{`Cr=PK?5w5b*5*7*j+EjPN;XPEe9h*`_L2v|A~BGNG%IZ0}z!BU@>jo9?6) z1W~q%$Ep}(!r6fI&I;l@FYIscL`mnz8q%A;ys^X|662_I`Q!YsAa{5%NON1cPrn%F ztNrS(r>65mOiYVI3nBcb(w*MLG9uHb6r+FNrKd}qZ!sX}5e|$avMr#}Z0Nt@QV|0H z@*bX{lTT+M8tUW9n2tYs;<4~UFBcAp8La+!;wR_N3R(FE&8_(I-DlkbC>x{F~xS|FHrfyTlvU$-19l@ z(zBoinh*5eFBwsVQBB>N;RX7@+R$(Qi}|{poy>NB8T7Wm?9OeRP9DR@ zxGw6+mG|hQoyuAPAxt&}ST#NOqnjz;$n7B#);@Ya_1rEHa5llaWjT5EDLWI8m78ic z4324zKbsXaK9~`PvF*~@heeg3l{Oee&6hmn!EFby1C#EPM?XD zzn~MhjB`&@o)kka3dUoHC)ky4y`BflIQ={KvZNmTTOs*1Hh5kB_EEBJ8n|ky`_W)E z|A|gfsX_;J*OzTkG!&8TLBckEC(|)Ztf?2&5`4-tcNy&CKA1uW_Y_C9LnBYF;TkM#LK=y<*Lx*SX8O{NfCx@L`4rWjpPC-pie z3auh14PcF!Jha|TrzV8Yg^!JECV!tBrp@yv{4Q~|`ZF%)SdM?~O1!^Paz!wt1ix8v zh18{pc&Z|tnvVvb@CMu`nLd@cQU&NJ9?XwDzPq#g|E8e6SvSf)rX&p` zammFbEsc{}aYHPtP?HPW|ajqE-CESElqx)kvGo$0K9n4r-l4rc=pl6ad zvd8;nL@PU!1|9~eKf+=uXVr0E@d{(=#f07(Vky`*kUal`v3Cx#Y|FNX)2>vdZQIVO zv~8nK+E%4)+qP}nwkmBKU)}E8zt{J6$NS!i*b!&P*?;V@#+q1bt}{o!v0j%H#n-$9 zC+9FlLS0NFyB_?o6ryXjac{#6K=%N#MQH^>GD!M|5h^_GaA9qDHSY%dN7;%diC> z2TBp<9I88iuI*YjHJN(G;~T$*kL1>w_|_S*Vnr$s`_gs;g~wQkk0D=;+OIKmek(^A z)n6BCKv_eFnoiUt{#SAzVW8kbJ^5%{GfEf<?=S7nsIJPeT_74qtJL6VTwk5cH=7wpE72fnOkbMRDjl$FY*q?` z)nuz@)^5m8p=~vrso8IKI*_M5HVPAMaH$3ea5F1O2Cf(sqY-~As-#hD_>n@JQcB8f zgYI%uudp(BQ0PD}HT$%x-iWo{hm&3bVVo8blhvXNLs7#+S0HH87$NJr8wT|#>FOQ+ zRM=F9BZN^YTS6k0PFAFZY@})NX4gvJ&x@dphVOrmOOr%p3>I&mEO?2YWeC1^s%P1~ zL%3I)X;fWLl(er;mvnE3vlbUkFeic4;4eW3=TLXgvohkQxWQ67XXOVCj*;b9%eO{Y zk>RRIn3r+iz=c}x+Z2~$or-;=_ihIr!rkaMrcHJGLko;e{|?3u63UgE>V#Xbxcw{Y zy|ztwJ9gpNR^8@}=b|p(aOCjDnQX1!PohV=rn5bDJN~JJsO%B1c!U^8*Kd52V|#HX zH&It{`-<)2A2HT3Q&*NZoSr3b%w6Ii0b8V>p+=v=o^qWQ<`p^9il!8;cl;=EmY!nA zq=hHt+?wT@#TORf{Kb3Py$+t0OvPASN?}j7iF;8^B>Wp$V=vCNz_{Z{cP=uW2hn#9 zuUIBXx)wgk7W~9$3Ksy-xS>zx`>zI_Lh5!hUCm7d;1zOAQ4iU*97$hJ^!$p@(1+u= zmZS53F+Ibljyn?yb{;l+j@0!Ws1Rp z2y(A5ta(3=L|+2>P`gl513T7{;u1`it~sa`d=jt(+~BxhCnmpg>1oly_PZUfD;*#g zT<|!5z+VkOG|zh*ltr1Rr8VIGoTDCFKVmLAtc_)I#=cB(@exBRJ}$5Rl$&f9q>;RJ zpDPa@%d5pke5`dyUkH{yAPYMS)mAI!lem%S$n0y@Dcj{_olI;;qOv*uLA+olqMr9v zFBSHxuk4%6}brG z5MyM}Iw%La>;~t@FK#tc@-)QLMF@7qsSrvxnKQj14mndlsCyd8nYwa6X^A7wEH@dM z8GAd(wAg9;Zw65^Yz=?N-9U zvitK*L$O!JYgyz^Ms8i^@YaBv_FUJcE2i0FMu~UVV-7LhiQ(i;ogO0hBKIki1Tx&a zXP9x~vrXj)(MwDL=aKybDLAM@PHB+f+xeBe$c0P=7HD4_(kyMyuRy{D&##cgo*6N2 zzB=Uc3twI_-$8YG-{0s?lXUsRGIU6Jeo-BBJuhUMQ)S2Zu`$C(6yTH_}IkqRP!G>RP zzb#px$y0v6duZD6jH-d}S#_|FVDi&7C~@l1^!;h80pufRG0Uss3nDK|7Do9O6u>G$ zjRZE$Ndw`oKt)%x7B<<%{5Yh{<97rOOo-cG%5o0DKZ~u7=eAuR0%u?FToO9GH7@Pp zC^q$`ZWB;ud*0JazI{8)>OMbd9O!%ODe^!)aQGnP8CAXgdK6N`VFIZR`5aPM72L8_ zOb}*g9?#3zZ{-=wMU6vGCx7UR^-dn^!g`=(lYlX@G`m2A6^x~09)Q7HZal4N7)8Ah zHm4uYJse5}8ii!PC{25zR|h-U_CV$q7JASWuLA-7iENfmRD=c=4G06ho1F{0=!^Z< zg8?EpU3J0ZW}_h10XyhW&3VFiDa_@PEf~~|M*&09K|M3*JwGT=$cE=;S}?7f1{AO= zgi#^wd%gODVy>`T%92XSWKJ)F4cAv~Gdn@Bjt!g5{Pqm099^W?>+m~?tk>}VX}oC) z9PxQsXGJ69YN_X{5aBorz_*2H%5Cgqq5&jG3t)Z2y|V6Sf%nnnHzCVZuxb!QInmH_ zs4->1`ThkR)?~T%RPjxs%x&B+IW~SX4YO*~`o&a5pS(bv3_W6>!je>KUWJ>-m$FgR zhG|RB(j^d8Hw*J>D?sI?6UgjEWxD^T2}}prlZ->1-039%_U-9XX2E}d)WEIIjE`_l z2DC;hN|J0H;@3OwncAD`&b*QGFw@X(7YtUCibV;B`mS(R^E{Z9+;J30N0Bg5W1yZ58v`u*37Vqu@b>B>~8$^`(H8e}rSv0C^D1lL(# zA-yOAxYdcwz!UAMz7DsYVLX)=+wEEeuh4k+j@+f3)41OgZwKMbDD1JCRJ@9!;TEZ! znZxlzsQ0A=VQV;z*5-WiVlr10IpIMP^>({~!}GhrCiVWD{tGJ{RYz?<%*8l6HR(Wx zg=u;p#7sw`6SUP#K{IdC_e>{FxcN$N{nZ2pfi{??Lk)LWh+QqB5#E4Uxd$eG! zPE(caOy~lqY`lgox2ZZ$oF7lzE447;oXa=gn2LxWO@F8C5%8rL51bNbLwey&%Tcd~ z8gg^*&$t%gKO<$`!YgN@eq4xTcgenYXIU%2Gv;-r{m7#1_Z*7vf~<{gI{)t9#C(65 zY@w$4w1~oAJSxGJI?biU%<(j-{N z&+hz7a=|+&>r7hX&J1Cn+pc091NU89? z08F9o_YK#DC95ETGyx&_`lDZG-6OU&CFA$R;#1aIP2N+E)Nl^(@G#okdikeL$=j`< zRNBr08D(EmYuX1Kqbd+i&S1x97?P~RR&+fxU%uNC;tWlx-f$tKsXeeqoL8fJMGmYP zMi-db=(puSO(fd{7mM{rOQa{J^6$mdoJ zkPPAkO(m4(%TSj*ZQAgB9G3E;f4RZIXhG^>6b@7hvSIP&MA<1rMIcMg&Mu#K1=7$Y z$Ns)jX@X*CM5AeB3Dq;d*Ybq@aD^Yafs5Uz@A{UwrWgyz5Kj!X8kt2!jiaF_Qr8iv zefu(U!xX!ZN-{Pkmbm1VNE7>UVUkpY1H1^FMS4uXw6?*spPVB@3^gr`maV=>PosU3 z&Wt%J8mXvN#KpQJm*F~_H-(hsedfkR(KJSy6X_>jhc4_eQu?~t$b4L5BIm2C#-@IqNP@BP(e=WR)wrx8( zKdb9IC{=;Tc+gClxd2r;GhG`RbpMO(d+VDFp&jbbn z5(NEU{^hR#(ElN5ZRG%P`Lo$zfWp`xT57zY0Wgc`#cJ0+QQ+A%WOS@nVrod}2FooN zW5uimtmpGbx~99twmXnd@`K#qTP%esDcpyd_J`^DRn}AVK#et-K_SmPwG@ZZJ-(}G zjx@(=M#BM2!4{a{zB%)?@0q9~nT|WQW$!b~fZ=qm-gBnp3Ruqp+9Y>l6#^M;eaW&C zjsB4f&P?J*Os7(4d*p!zc)!J~wmtpaeV1K=lZ@c);H+kU6phY_4R{0`M||&89%q5T zg&lfam`%&4Oq3-B%u~@H43qvAUIVOU4gKB3LY5EANg;{pTw4!$-DuLHElfe2%L)d# zsG!tptPG*7pj;wwd(p=c!lFWw9Ad-2hDrJBDa9JBpH`lTIw zU6$@8K2W9Hgn%HSA6V!KMS+}5PH(i9*i;jVV2*i>TV&AW?X_~V~#mM@xO}$7rkvpwOIbX%C;4zUcoyRflw0EvD`SES7^&%}s z_u47}tAcZ1Puw%4hDB@iIMyy4E}=)(Dv6)t@+a>olhUxh%$SJ4r;?eFr#A>xADPzu zTzaJ0L@G_YQ8|VMAoS=!8Icj2NxhKqCn(c$W(XB zn@N@^UTaE;!Fd4T2XKHY25GdqUv74|$98q{^8wQ^NFy1?3gpMZ89#?2+{F*Oo zBg~I-I>L6WdY>4X{3uP(Od;$IwrM2~Vz`%?5x=FuJ5gbUKZJUs|3E?)Wf&Z<#Oz>d z^?>YPgpRh6#q`0%j zf9XFg^N;qzk+B|K{juYi}R{VZ<+}~W`{1*(;`ZhNI0uT_%2=Dt1QTUU<*B~e08g8|Da9KW8EeFlcCqW7d zOs$q6M78b;2ye8R10rPW7bCLkAe?hYI#-Y2)90hxB-i$AaxR%)7E z8_RJlN>7Kw z?i6p-)yHhB_x9^^}~*Y)_#u@Lghma26ukTU=aMVqh1k9TYig5>IPr^ zFLOMtL%&E|KrRH_LL|c+OhKQ(sY-tqPM&Dd6X;7Pie~g_@OxlQ7v^ zAz#@sM_6~H87H6Gka>5OS8ZnFYj}?(tl3OY;~5(>vDv@cDx~3IF#nY44KIq=Q&haJn{#5K%1A0 zSim+EGP)HAz3@Mw#2;X$Q&Tcoa<;!XgxCy7wiB3NExFgGM5#|6YBXj*lff>V2s5!2 z*Xs*>i6$s2w`GYri@B}$*{5hH)feI77F0oQp@HWAxq+M5yF@lrwG~`+yK9od=jq%a z-;#2|5?6AE$=IhrTW5$KD*6>G5_(=%4tiZ>Wfa!RM`{eEFSp{B6(^}{Iz!Bv4B}S| zbK?UBsA(A+s%6GdyH*B9{&7ZOJX02x=0xsk5540XOpfdAeu3lC?>gTtf}siz zU0y@tdi7^Hys10A!Rp*>18}_tsPWoM^(VOtqaraT7i}R_rbAXN1!|IKup=8t-62Um zI16RR5Jqo$Oq5`D_b!AgM%Pw_>Q$&@Dk7Jz*iCheRTffhW!ecnRC9EPwrV2SBlEr* zKZnR=%PvA(>EntYlg7+mBQT!-I-0qbZ9nema(Ki3oViBwP#V&Fs)}r~6%yhv{6&*K zAs||oX6ndXVdYf5culHRXjmYo6pA!qAXEqNkF-k3iY;rQt7Gw&J!-~CI>M@!A2Ke0 z)(@yO)rbj9?d8+yoStlpTn#{2oLZd^_1UZlo*C}#eQ}u zKxgMjPPp#RABMNuizwTOHyk{5;51y7K^xehT(qrF_P#E+F6=?8O{g@1RYM%!P>-5h z?gQfKkdO8HD0tK@vr@mv73mO4)#Y1&9ar?dh7hWqT9zYvrJ~-RLbHwI1hC_m$4E%S zlrJLNck{3%-?8Zt7l1#s3!q5e${)t;zClxX0^!$FW?CCo>N5=|U`0ufRvg7oZOmxoQE1 z4s)(NGS^rAEk3S(T>lc5naA%SLKy=9hoh&C?j&&bA4c$mxt4#-6^ulYdlW;G4n8XcID7E0E#@jx_wDf?@Q+?XsR#~+I3yZo zUf8_e@CO`jYSJI-8*jt5&ws{{JwDnf0DqU_5N{{}5VoaKSWImPI4vG5kb$KzIdM^{ z<#7cgYh2G0NJtO!)Pux6JDZo(548ZiL8u8QMe@`~W)s2n;F4b#p9&&%lbRBRiZY%O zbLTege+;3(!L{x_DhiI(|Ni`2wac=0gGkZe7#E0HRsh~PhVsAfgwm2PUD5sB1Svq-uf4r(H>csqxUz(+#^JRXSqRJuR% zR(&d&AJ%TVAH?^tlk$d9@*2SlmbtF$%R|;QiuZpC|9qoMKCt84iHc}E3U4KElbut4 z^ht?o#sul^vl3w)8L^+`pQl7o<%cGi-0r`DPgXrngaLf$?N4nMf**gcQ1^-0FG z5≪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

uCkMfevHK=va0moyu;abJ@+bmi-(3 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

mSZ{dUQuK;?vrXitlrgi%q>g3 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 z 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 ~SOtARn3gD4c(x5RPc_GOt%H>S{eMO#NvH z(7^R2Qd}{mBt?1zav5j3YIi$dNqQ72nC($Wn|kp}H`BcXFN&EEeQhh?rZk)z;?QB9 z{H@&=my|1ELz_eed3&60k?MlEu+X$%s=pWLXpiMry*J_?&6`Kv&7wv5Q-qk0b&nh! z9SKoWZ8~1aJNdUO1hE>Q4e%|DqWTtca4=#I5^~9Y(SBLSHEip3-~_dXPkc>Cpf;gO z1?dMqSg(Iln^CCYFWf=MGj%eVDH1c9u`!}uo5Tae=1<_mDpsI@?~~Xf!YI7+c?Mu( zeWyWk7bi73z&U67Mo|^Yc2d^tGhT83Gjzwdi20;Hu!jNu{l4S>K>xRy3+^ZTH9jyf zFkmn{H!wCgFgY=>y8X|^qGOfznH&`{u)h7IqQ&E+#Uhp7nvo_EH!wOeu+igBov*`1 zp0Ao75#NrUC}mRxD=jNUD?KI!e0He#ab|k@)(KAX#tx3wj6^{IlN3KWBfYLZe0Z1R7(YaVdA#ufLcIo*HW#Q#UL z)C_H0|9>=TdX$--u63M~tf7;mH8Vi~z$C;^&PcDj$4^Pk+8L54 zh*GU-69W?iBLjmlFfsr`risB3z=94e5tka68;kre&5`a(ZxH!omT+JI05tz=bHv0X z|5^?Ak5A{ntut9$9$673bd9n!-BP+xAxfu5%|PwR82e~mUb*)9dePC=7;^EUuGSCfFphNVZApC0-?5 zCH0VPBqt2|;n*K~OebK%JQ|u~omJn;$l6=#_@U1QzPD;&?2*>PmG4l}Txf)Oh_ zVl*8U*mw0Njxlh{iIq7z4rla z=F#ozFoA9+f&V9gZWW8NwPq6*lDRdUbnnz1cTyd1Z7CwC+c|xqrL3yjaBI}8WI&NR zNidgmqlZ0HadvqsGtJggDymTPQC(4A@loATw|%XW)nB<))mD+zU20XSt@XC&q~ zWSvo@<|jtMFZxXo zv2EM7ZNJeQ+uE;cxBkC&w`%YDvM;);&r_$Xj_jh`=Jm&puWQ?mgnQSHoO|1bomo&3JcSUT+PvJ@(ryg7(|oz!$#p zF?W-PF6NKiX+IjwzSzCQxtkNf%k4+Ue@ddj=X<=L5O!Z760U;%L^)xB9q#kvR?tBSnY)GQvy%+oxt zw|Vbna;IfrIL0PVv`N{tTr^+v@U9j$&#_(QZNl7cMRJa*T_wuhN}~!%-Z6o;p^V;H zDK2mGqBC}Mw{?{ z%t(DYf9AJ4AVxz6iW-C04nGRj>9BhZ?K-mg6%uMG6Y(Sd)f(b(KoQ>FW*?uNXL(^` z)uFt{c8vgiKFk^+{EO}C4ruU) zAFE{&<$lU$VtVrs5!`#|OFexh->o#>dSyp_{ND^#0b{6|4k=cgj#8;AZt#IYcbuYf zuGV^36yJ0m|DtWA+(7*b_xhfx7|*93(Jqxm-0#l`9WeDJV|#~iQ*MP zM1ls+l6cJp(Rt9bg*GN#R4{dS80JAQa8fYUKD7ahk1dkmg@6^TWSg8!IG>huI{;a?4S-3P z$q^$yT~$GcD_Ne;Ej&1}UJBkLijgnaS=OpJOLkLSZV(`r)VhQaoGF)GfRUtaStevl zz9ZWOXT?zw?3UFW{)~d5+a@mC8Okl^1OJ!9B2Vh$Og#xM}n}iZM~W+#bmStActQ>PKpDJgfv?{TRx=@S^>ko6L5pLTL`ENu{?kn>95mrCc8;v23pwt1xDwp}da+@F2~9~^WP;0P5~ zuM=qI+T@|+a2sj}U_&}(J-lG#Yi>}4NflpPuWV;;dXpkqx%V2s##X-^(79}ZV>Z59)J%9Tt|$YVT{I%hj;I_$_-z!gFE z-_9?S#YsIZJLa_i^sqKbAjA#MWjb?q`hH_QnL(xsVn~0i&gQ2mdpj(X!%NVov6_D% z@A(tJP%34AW89bdNLGvLrS$7>YB!(xqQ-AdUp&pd)A)BV$Ac%eq+as*y0VH!Q_9(i z*MH^EwetvuoACM3k|TXC({G z(2gM2$$FRk5hR^2Ea57^*yO`3a8zR5kBojO`qSLD*!yz%iD%CTm2$jxmZw*wX+o07HW?F5CZLP_^O774C59gGyrq{L7lZtDmaFkok=O(z$y;`S$DFDk>}X}pY)`zn;aA)ehmC8qnmoi+dzN`&$*q-j9VanLUBsWHQn&ES^to=p zv9*qvY;e$Kw(+7kq6v930b&kml9f}(;HG%57h1~lWk21=b7#|yy~U07lH263l5wBV zV;84uwlEHEZ~swSFWRgJ-?(Ll@3}>@OBu_oZI1(uY?*Wb-b>mJ2v=?Iv9M;cJST)R zkfJ9s*e-NlPH_q1m`7W+%iIa6cG=yQ+YsfHQK?M@VG@^lGhNX0Wz~L*_vDatf|^LG zR(;BkBRbtR8*4$R)Xbv1|yRxuX=xz4e z()PeDZ3L-sN4ZM%T-=KJM7AVvXmyW&mK8w!U45PzR<@Nvz%ZbnbyRQn_(u0(GgKp~ z3vr5b1Q*NM0B7Nv2XETs(E}g3%BjpR_C;%&qi|IZQp49KTq>2ZNF?*mlDvguq>mmG z>zztp@&s|F*}L?(wu#p}b%)ZMh}53PR5%T~_rWOMaNB)jON(J8e6w&IK7i$ zdz1Q3EPgX_u$naauIv^y5H&g3r>3vm8$}lkg{`Y(rz7+qnvF+$v`_x^VE8$~r1Hz6sw*LS1*Am@x75XQ@N%jAg1&2J=Q1`-RX8xhD}+GB zJc&b_-^r1n?oU=DV{p}nR=Wkh*#W5jvDVr;L1j5^on!Bbq#HT2hFRT%Z+~A2&@m?9 zhVF!OawEHBs#JZ?!KSp1xrE&%rOWStQeY&l>twu%gLQ1m>v*)yflLWk;AkuCtkF$Z zoJFGiSS|Ul;Kfq96E+VI>?S?nq)oix;%m55Zx!?R;y{;M`jbBuoDti&lE1fl?7MY$->QNJXghHw zWUmCc_Lki#FhG2Lhpr1Q4{>Bbu+rnrJepx%FfZ{D7`vxvl0^2H zdkpcp=IC$ywgslxxDrqZaEDCI>O(MeU_8o;YBYIL3l2!gHvEmj;W@#6q9OhRG$=yFM%f_z@5Wd?I@C@x#9S zfc@`Cs~*{GfDQKR*FMz${de{MBdx5Vr@gC-l%1LV|D@WKWF3_yLA0@-tY-Mw17av} zA+g`IVprgbiBXtnLa_Y(jK*VWNT9z(23e_$zeM#t60mtVxep<4MYwY1bhL>Q@135V zoidzL zVi38(bW9>DOB+nD&Qqt5HdtMphYT&|uF5~G8i6=wPEtEr6?8guS4!!Z$|6hNUV#N1 zWgA^mWfo-av}_$-mj&smzAXmj7vy_X3XlI?`D@x>EJ7U;c<1M^**0cc-;VaKT1<5s zYaZv;(oE}>^>dT)9d^m|Y!w-|1-)i=TL{yI#>c_z3hp@h-U9#R>h{pW6AajQ2fh&2 ziOSNmIF@Yb5-f3md3cOcT*yl^XQy)Gw(SmEGdI}`)rJ}6fL3J#bG90;?CpT4%6?Kx zB@uZRzhN%{Yl^f~K5DSxA4*ofp{X@YpslP^m|-(CbaV=B87_-VL6uwx1X*iji~>6i z!(MtJTzuteG@|;YkAWX}Fyyxl@~^;*~Jl zySAHTTH7uIokua71gK3eKfu47UYDKTErW#K0`>PgVk8fka*Ep~m8}WXgV?Uhhh&7h z5?ZA#X}(FkouMgKFW5w{enkKj9drR45i&JN_G=_Ci)4Jyu^>iKm{x@Q5$nsu8wp}K z9x5^q30@*KN{L`GZktOhp?3U3ai+ z`s=q!Sji4T`qh9gLWlJLZ2H`1%pp>_h34tZs3paLmuMJjeoBX7-O(G z_Tzy#rkA5iw2tNW>>p&SYYVrve!kcjcwWX^#fzzTKI{F&(GJ#=B~1fKsICF*`zfC1 zT-%P;_14v7mtnUI8!P`b8(-VjDC-aYjDN1-T{>_gw(JuZ^mSBKm2%wM?z<|SI!2P7 zPn~nW#KVrEWTlW)h1X9)f?hp2BzT=jHYiAXkFD6v7==Ravb96jG zb*#8qy0u$bcJ+dFW?i_gE{{CQ=;yhx{zGC35qSF za(EHX11+p~*pZ~T6s?EM#?h()v!-y*(w3@7DP49)1QGHureQ`8)&Zj?{nJHJ0&`i~ zLgBHDwIk?64c5<#hM-74IEx*XMRYmcF&7*)?nVC(bKsYTy{mKhH)*q`w|g3Fqa1o% zytB_>y-=oealK1a3yGHId9w)^#d93fyY4$sWGdh+7RlJ_^%tZgyP&pNzz}lWzE1!q zad*VRuQ5h~eKJ|3QJ_Ry{tLPh?4wyo$0CR()iX8|9e@yQtctWL0&Id%lGMMD<_#8n zF~bllDjf!83BS;VS6bscYB(BpdXiT%^w{4n6vR*qA25Z3dZKzkcC+{ofHy|KHU9ubd5ENFP`b??TS;gfX*zwc6aqP-E8pAZJlqn1dP*zH^8P~{x+359-uRY z?{%R9uJ3i}+)c$4-(yGGuN?`N-J1i%TgVDm3O3%OlPlGAvCy66*0CX;SAA+Xul&Bq zX?{fi^qaD6l4S2>Z9?YzW$*&xzx{`;r zH{7#N!q2=%&!w5Y!qzs+ZJy-=z4z|2hnFP-ke`0Awg>l}PZ5qE$x}j=Gt?Y^X%FAh zhdI9bVcj9j<$DH>pMQ&Wyr0(Jv046A4>vB~J+nVofoz}9IY0RiKl3<#E)PE_mj1;B zKSgs2tQ$(7P?DIk4!UVboeAsYtlPg13US)#A6a*a7R&b+#JEes=$R>Jmc=lhrpYP! zEDR84$($hwE-a+ZX89u*~Z^!F7y0(xleV*WVn0q4HSxRQB7s(7+_M0QNe zU>Z?|XGZOm#fTExk;HAcOI8j=wWuJUw;E7J4fN73Ov0EXu1wOHMXpTb_yk9D`w}s( z(T;XZyI?#C5QVC;4$+YW?XVr#m=19N6p|OrQQ$oyA!JL#s6t*<+tS4?ne$w+g zBqhD(d9*BGQ%3r!`lRh$L=6Bf^Hh~OSG;4%)iI2Ic6mgrxvD}9 zv2IX+6sl=MPCHv>hY17-OEWBvj3nz9M$1t3$YQ3cc!ko}7C%z!>B^n4b+)H2Ubr~& zmGrHQz*~<0-hz%**V`_S&T?^NDR76if^npA?TqE`D*_-aGUWjQZhG4X$nG$Ul0mHh z+I2AdB-oK(=1=wYwoj2?q9MzVh4e06qQhMlYNPc!*K4BrI)S$lJ%uWmA1-(G^v~Yw zqIVJW1g_Czyf)pOf_cGqcbqE%2N>bJ)v~;282-2Q69C2;hY)^+Gk~SuXJYy*wjOU) z^eJz(B(Fl!cjW%h#*CzWRNs8KYWypWul{31+VI{sz!b4cxUiA>4#roXjQcYu^*u8@ zhg`p`HcIG6D9?ZKRL;sHI^u^Nea|u4-SsY)es^sIlJ!jXc~$B_OxHO!*= ziWC}+Nwx40_w{Wr<;JNtHJG-yfn!fw(~uw@h|s|^-Opt)|6Z(-6M{ICDV(8WTi_}% z;Cp^lRkeq26Fudqg*9H9u89u52$~rf#kmCLcDQ=F`of+xE1E16IziZ=uZ9uJV9aRh z)>@g<))r6DoXpi|vsgc8V^2}18r8jNY7p4Ph*sei!2}74KyjvRG*}s~*i;(2&1_ei z9;*&rWloY!sl^&3sBj&6tQf~yRc7mjI-8`xEt;yWiRx5dm~&bYN2OPm60Kv2ElL26V*e1~R23D-2^D*m zJMyLSDdB|!S&pQnBe~fcNL`?=35AxCz5%Btlq=STKkg8;y4OHG5mG31a>b zUtO(gRLaySMEG7@0VvucvN&ZSoy4o`pXL}`q=6sa+NhTCtx94dXb~Z>lxxFMHp)kIy z^!x@z4SR&Q^}SD61$yEY&Kk{Oz%3s2bh+C)!Ztjq87O^l0Se-)HwHdfJ)>Uyc`wD1wOEv3*9iJh{EIN-v^=J(^yl7f7&(tUG#x0aXqb{%uuWM^-Y{g}~D$+1^3%6)b6`scHb=o{<@MXcF-sz0hlMCXxvnNOy6bncLxgyH-k`M0~_ke8K zf9j|ds{x{9_}9|ZIs|kKEEGZ@Y9Yi*W&4^rUg)**a<$uNPm*U)@90cFP7a35pGV9f zlh;up;?l4nSWGb$1Y8mwznOr(8b2|g(V6d1mQh}8irP}5TzsMO&67hx3ARM@! zG5rc}k|*Q!1KAD>O66)}z4i|Bbl`PX)GidNXK;(!i7?ANNQGqu1&Br*-v)joWoVTu zwaDZK!7}{T$PnqKpsFsB@_+PJ+hqZ}3CU-52Zz)C8><;Pg0?js6oT0F7{+7T8H7f|K6K1Cb+f-5sGgV9FQ6(U@4W=iwI_eKsah{gGNnEAWrJDWzkg{&q$9bmJ+6oc02^|VB`_)VdP*!4nVFgb$ zpKMoUgK7mzjFLhr4#~*d%_PUT(fyORbJ_6b8Ugenw>Ayv*>q1@v`TXDo8~5hEn~TAj0LBE&84@q z#(3jxG4i_IR^>1fr;0vDy1aYLFjTrVyvsyI6md8!WY4j6YHywIN10wU_o*v0!&tdw z2NEIe!+;aTv{SUd)j z^x(&F^QT(xyvFso>)=@KBj6SU(wN%B!8_BnZ0iVawF7o#b9)x+e>Vu>^uzMkt1c~r zdqQ1(FwpG_XWQy^;Hf;v6L1haN~R3_|Jeoih~n3p_lZ@dX)mH6h*(~&`}1`5Cvf-8 z(=EZB9q7QXMzL{TvDjtUNs5?Z`M?p%bjSwp3|xx>`-q!IzP?NuPXFUER(h?L3Bm8 zkf~PobZ7P0kL&vc6L~wMO$S!I3?K_&UxGb%5A2%WU^m7;;#_jkPWCeI(S2Yy3O>6} zfrLFC^o|FHh;bm{b1xhGbxI?GL`LB|Hkh6m0Q#zi`X;7ka_2eOIGkO=1ID(|l<3{u zmQgf}+pXK)t5rZz6YSfG!fy}fn-N|@anOar3ztzo{hNMpoYL`f|EO1p$ctb!w(T^I zC-`9tu958eYZ(`pR6z5c8e9#MbNf0_OFZVMu7(o#9;ftfIxqsP;Us+3-Sgx!BkY|i zrKd(ESBJR(G|dhY)?B)5BxRyf#Mvv9(c$tTg_HAaj+I*MPdGpF$ZwEfShx6rrS>tpXn1}wv8=D$9b*K% zKro5@e&o17%m*1bEn*3*OaAlKr42f_ZkzGMVukB61S<&%*04bmSth1+Fx8w3JacUJ zU_MDX-)uSgzKw(;Ng1E9UXJy(OI(q-RAV?U^*ELz4=tsKLlJ+Z#JZg?1MyW;N8>Qq;qiRF^OY zBHEV@S=DMbpranjlo3VDj%*^&?kY${;=j``H++!F0>`D2I;I+=Y&kiW@35HAbYvqk zn+PH@TQbMXwU+=JAy;R-2EairQV4!IeiN-ThSw*hf#Xjp`>PgU27cX2zAZcL#&g>*dk079!Ihb z>vmh8g(K?Y#@fv6qxVXKkXJr_O}%Q->FeRO6@C_=`?C@N6*>t-;!D>&n+1u=8L zd{`q`QHnNarzn+AD>_(Si{LA-b;l27Cg*m z82;#i5;N6$yrN|yC~JR65zXm%JmJ;O-LCQq zxvu3J3BHxWZdkTRSR(@BLXn+J-*)d0j*b1|ZJO3NE166|Jwlwz15#tN zT>=~%f6OY}E?!oX-zC`^^=%7O+E!MdF(L560jWauh-PruB{jB0li4ETAJU6xS(1ag zEvuoX7&F3UNY=7r>vSBrPSM-awHHS3)qc{ul~o;bAxBnA5slJynZdRy(s zXJNb|xt6yjKG@GD>W}%P2>d7U}Cn!?7aE*!^>` zEaJ=7Ny&D)&YP2IvrWPmI)ikHnsDmvt(~h9lR0?)7dWFD_;Tv|{I0!W(wBH~^6MCY zldZ`0G8B@op+sb~L|i8x+dK=a%7IC8U1gTzW~fHX*n!qWHI$VZ_%Iu>6SLC-&T(9- z?~X`*4wYrVdL8<}IlMZl+#Hy4=JCQ#YmC%w;xtLD-H!YR%<4e>s!$fLt9wf4g)B*t zlKzhHDecJYVM2-P%)tyAIcavpur)Ri_^Em8W#FcMS-4p_b#|U!2=*W|CI^jq;`w}5 z*J;^0=jBbFZNH)+arT=4_vBGlEq*+t8rHoN+8M!3clgw$M$AprStYbJ)ox!6U?t8) z?uVUv@4*7TY3C}wo-jQ^6-KJ`w;U5>$RB?oHS4r4%M@x2|@uw*W)!DMFI)cIsuzgtw!H0LNuQya4z6&CX|lVlcX36qSDd*9b9zqHKLJD{GSFN_6HhEL9sFRUK;G3*;0_Dc)=r?+3j=v7 z1=R#SM=#u@KlBZ0Uwzicdpa)x?zXh@yqa8kSue78d>F;0lE!NE9@hz(RpRSXyy~K4 z*=gd8iOGGZF72F#eF1=*M-#W}^0Ki}=)T3{l32E<+Ipw0a3vOEZq&aq81XT64aBpLYqfz6&h=<3K3nu@`6xzuu z!m4KaO{0z_6MC)5jO;MDQ3bZ!{>Qn7Biy>K?as;pL){{(Z!KB^4Kg+rad z&H{#`@Q#fS#;ZjwQd6}KF|%^5`g&~#N1VcTKRwSA6QFtXIgCH7B;!9)Zb$g=bw3;T z(UM+MSR<*^?J$%5)yThwT)?ma?+I?d77iYBr&8_NP)iO2O z>dY#?sy~o}UajcAq6!dmf(&XALxZXL6iW2n_`7~#bt!(41Bhw=UQ+%II+npdo~rlh zDDnXx>_D0N^|h`R_g>ZTjpJ66dCHyQ)G4lZ245*qX04pks(lu#?v-?&Cz94)=>yxP zR?^n6SK$&qn6_(nU zAWhjqk?cm6>_(CNOq$G%BJGVTodaFs3tbY9D*b^f9Z#A};F_EoSWM$WOE|p9x!=#| z`Zl8PAW%&C%IU|aiReIM;ehK6>KwKajc=r2B#rcKAe4@v{Iv2V`};X47w*u_VF({a zoS`WXJlHARks%|KIHuPx#_bfAr-C~Ue}=wEPV^&L>xDnxb$(y^#O%6LXz1mw$Fjotf z#WTh8DO&IcDdM+t)WE+laIUPX0TpD5S`)B0ZVJ!8`XU=1I}KCx-lp_PbsMmi!)Fzd zq4KcL#e8^3oS=MP`1@A@y(uH%LJZd-pD_Lgh>t=+FVPAsgdBwX_@p~s5kT(*_!|)d zpWnU*#x@_rX0Tw3>(P`)A>+Sr6G2h~9KG6&3hGBuUIQf)UHoW{vZ@~` z1wjhg|HO&@EynCm%OBEc|M@Fo{|fOw@WOeAhya7oO!dm4lWE_w%Cno-2kG-x!^mp6 z07hYK>P7)Kn4y=nCAdVcvNjN@iWRIfkB1{-J<9oL0D7M;dR!~ye-cDA4KGFu4>}#7 zL<=_BAe+U^SFaJnd}uov)7CQbAIrgRP^GGtU4?(sD80c+0WepG8n!Ii%UMkapq8ts z&_yBPAgm`0?l7Q1f;Ewu`a7AAQJzel{0+v??C*KQZCyJPp z#(l!);aOVC5E*J8MD@&&Y6cU5;mc-n0nBKUs1yQ5;5Jwu>kh0f?EgjA_m#3QRD%bEbL|-H=6^0Y683A29OraGAj{(y` z^^jCTECe!_UcWVByI2e1OSO+EpFT|eAY)=4oN3_hRoG{QP)Q|BiMc=-vE6AC@s=EE z%mguL!gp;j?w@T;YCRb<)cRRlf0Z^F8-nOquxz+Q<27fDZ60x^_C)eS+n(rDL^2X* zKusk;O{t(9&}Bg#r}oITsYgq5V^2$qnx_Q!E!rk8;!}=U+Cxza zA)zMZ(Q`NZ{zCro&2 zOYvMWp9q6N2%K(WTMO~Boaj(vp!JBwknpz7S_eK9AG; zz#m?U7)LejaB!mH*TY z+#_hN!H_7zqUp%?^j01*9=*#f51!Ber5*Uj{+5SQ`+GfXUm7=xK;6DGT*INOx;PW-FZ(qQgB&*TH^dcOcH9 z1h{S*0uNTY>02P}>eNrDEyJ5EGo7a`XVsUoW3Or$e{Ic{wAz|&byQyIvbDlcOf|1# zQgFs|zWAuX$+B|qgHGMLTzM31EL=2t%~N;NM>bx$j(8f7kIM8{2_3fV9|(<~T>Ocz zlW66~&OMsB1&!~Y;)S_+z<5oy45Ofu9mMW^Q=8-R@Ss;VkES1nXR~9bdFlv1U+8}|kscB3?RB8(hRX#pHV%q}4Dr#uF9efUA?><>IPWZZ;s zxfRnQRN8=az1ZPw^4yUoI%eI+AJY+fIT)3(-Uo8V8G8eRv&70{hihWcSNtxaEXld*9sxDZ zL^PMg=y6^7&~WbV`xzv=*!(zEwXft;JOJIu3WOV@jcFYuWd!_V-<@=mXEH%)!5vnU zjx3OO#;P-Cnn;W9vHp4;0Xq=X>F(MlxY-uRn&!AKQ zjPAK$$shGwp>&ZX;Xd$syyfpzr?#u`u7sCO>T$YiTKThB%3$B1l?IrnwH*w$?)wIO z#!;GwW~QU9&U@XQ+Yfc1%o$(JzEyBF%1S5VwHT4oqX+vR>E{7o$|xw{_hf5P8jo%h zv&)$fS`dBIACcDrNwgsgB~a91sB|iE;ZQ7aiU_89@t9C}%{HZ&a23&Cv&g76+G_p3 zjsrW9Hh+s@!iyJ~;smiGVMU~o=!FrlFz1INHpTt4juhH*#v*E{9zH%mMYGkm&Q8f} z9R#MJD>PUA+OVejf}Fs38jQ+GQ5R{bu#5r=cT)#PNWtsJ*2OA_6Nf4?%$CNt`YQ{O zmJZr8tO}$l9r(qBFFh=)>)J8X-}5IAvl2f>A|Tt(&G4XYI%=!QA{x~DpkNXpZ^00k zq&6aDL|+`~DY^QFkdVrSuvR6 zmZ0|Muev9muMB0CPu!N$AK9DYE8y05PyO0u*rKuYT8%??MxuNF_U9Gj5O$LbHz3(J z`K1u-g)!w>rDB+Ry zbEhde4nX$t!V9!X0Z)pY!RIYl|Nn4ETVRD?7feF+q=IigYq3nnQ2kzZayKdP*^pKE z7C|I#MUu97x;-)^E5U*AkD!0HwgcfJ1w2ebOJq-YC2P=Rrk(Fih_~vw!_Nr&e_|Fb z3Rdx+K1A3Nc^V^4xTGBqBbvsbr5(j;WJQsoHZWoxK_e<_U)>RQo53zv&nTSujFX!n zkdIyJWmq!G)g@cHO|)y7s6>$BQJgOmW z6d5ApvYo@k_|i@K(9Q+at9^{FKN6SX@GX!K#P0AYABqeDaEBwtj8b?(6@WjosPQ7v z9-y;m{`Cr=PK?5w5b*5*7*j+EjPN;XPEe9h*`_L2v|A~BGNG%IZ0}z!BU@>jo9?6) z1W~q%$Ep}(!r6fI&I;l@FYIscL`mnz8q%A;ys^X|662_I`Q!YsAa{5%NON1cPrn%F ztNrS(r>65mOiYVI3nBcb(w*MLG9uHb6r+FNrKd}qZ!sX}5e|$avMr#}Z0Nt@QV|0H z@*bX{lTT+M8tUW9n2tYs;<4~UFBcAp8La+!;wR_N3R(FE&8_(I-DlkbC>x{F~xS|FHrfyTlvU$-19l@ z(zBoinh*5eFBwsVQBB>N;RX7@+R$(Qi}|{poy>NB8T7Wm?9OeRP9DR@ zxGw6+mG|hQoyuAPAxt&}ST#NOqnjz;$n7B#);@Ya_1rEHa5llaWjT5EDLWI8m78ic z4324zKbsXaK9~`PvF*~@heeg3l{Oee&6hmn!EFby1C#EPM?XD zzn~MhjB`&@o)kka3dUoHC)ky4y`BflIQ={KvZNmTTOs*1Hh5kB_EEBJ8n|ky`_W)E z|A|gfsX_;J*OzTkG!&8TLBckEC(|)Ztf?2&5`4-tcNy&CKA1uW_Y_C9LnBYF;TkM#LK=y<*Lx*SX8O{NfCx@L`4rWjpPC-pie z3auh14PcF!Jha|TrzV8Yg^!JECV!tBrp@yv{4Q~|`ZF%)SdM?~O1!^Paz!wt1ix8v zh18{pc&Z|tnvVvb@CMu`nLd@cQU&NJ9?XwDzPq#g|E8e6SvSf)rX&p` zammFbEsc{}aYHPtP?HPW|ajqE-CESElqx)kvGo$0K9n4r-l4rc=pl6ad zvd8;nL@PU!1|9~eKf+=uXVr0E@d{(=#f07(Vky`*kUal`v3Cx#Y|FNX)2>vdZQIVO zv~8nK+E%4)+qP}nwkmBKU)}E8zt{J6$NS!i*b!&P*?;V@#+q1bt}{o!v0j%H#n-$9 zC+9FlLS0NFyB_?o6ryXjac{#6K=%N#MQH^>GD!M|5h^_GaA9qDHSY%dN7;%diC> z2TBp<9I88iuI*YjHJN(G;~T$*kL1>w_|_S*Vnr$s`_gs;g~wQkk0D=;+OIKmek(^A z)n6BCKv_eFnoiUt{#SAzVW8kbJ^5%{GfEf<?=S7nsIJPeT_74qtJL6VTwk5cH=7wpE72fnOkbMRDjl$FY*q?` z)nuz@)^5m8p=~vrso8IKI*_M5HVPAMaH$3ea5F1O2Cf(sqY-~As-#hD_>n@JQcB8f zgYI%uudp(BQ0PD}HT$%x-iWo{hm&3bVVo8blhvXNLs7#+S0HH87$NJr8wT|#>FOQ+ zRM=F9BZN^YTS6k0PFAFZY@})NX4gvJ&x@dphVOrmOOr%p3>I&mEO?2YWeC1^s%P1~ zL%3I)X;fWLl(er;mvnE3vlbUkFeic4;4eW3=TLXgvohkQxWQ67XXOVCj*;b9%eO{Y zk>RRIn3r+iz=c}x+Z2~$or-;=_ihIr!rkaMrcHJGLko;e{|?3u63UgE>V#Xbxcw{Y zy|ztwJ9gpNR^8@}=b|p(aOCjDnQX1!PohV=rn5bDJN~JJsO%B1c!U^8*Kd52V|#HX zH&It{`-<)2A2HT3Q&*NZoSr3b%w6Ii0b8V>p+=v=o^qWQ<`p^9il!8;cl;=EmY!nA zq=hHt+?wT@#TORf{Kb3Py$+t0OvPASN?}j7iF;8^B>Wp$V=vCNz_{Z{cP=uW2hn#9 zuUIBXx)wgk7W~9$3Ksy-xS>zx`>zI_Lh5!hUCm7d;1zOAQ4iU*97$hJ^!$p@(1+u= zmZS53F+Ibljyn?yb{;l+j@0!Ws1Rp z2y(A5ta(3=L|+2>P`gl513T7{;u1`it~sa`d=jt(+~BxhCnmpg>1oly_PZUfD;*#g zT<|!5z+VkOG|zh*ltr1Rr8VIGoTDCFKVmLAtc_)I#=cB(@exBRJ}$5Rl$&f9q>;RJ zpDPa@%d5pke5`dyUkH{yAPYMS)mAI!lem%S$n0y@Dcj{_olI;;qOv*uLA+olqMr9v zFBSHxuk4%6}brG z5MyM}Iw%La>;~t@FK#tc@-)QLMF@7qsSrvxnKQj14mndlsCyd8nYwa6X^A7wEH@dM z8GAd(wAg9;Zw65^Yz=?N-9U zvitK*L$O!JYgyz^Ms8i^@YaBv_FUJcE2i0FMu~UVV-7LhiQ(i;ogO0hBKIki1Tx&a zXP9x~vrXj)(MwDL=aKybDLAM@PHB+f+xeBe$c0P=7HD4_(kyMyuRy{D&##cgo*6N2 zzB=Uc3twI_-$8YG-{0s?lXUsRGIU6Jeo-BBJuhUMQ)S2Zu`$C(6yTH_}IkqRP!G>RP zzb#px$y0v6duZD6jH-d}S#_|FVDi&7C~@l1^!;h80pufRG0Uss3nDK|7Do9O6u>G$ zjRZE$Ndw`oKt)%x7B<<%{5Yh{<97rOOo-cG%5o0DKZ~u7=eAuR0%u?FToO9GH7@Pp zC^q$`ZWB;ud*0JazI{8)>OMbd9O!%ODe^!)aQGnP8CAXgdK6N`VFIZR`5aPM72L8_ zOb}*g9?#3zZ{-=wMU6vGCx7UR^-dn^!g`=(lYlX@G`m2A6^x~09)Q7HZal4N7)8Ah zHm4uYJse5}8ii!PC{25zR|h-U_CV$q7JASWuLA-7iENfmRD=c=4G06ho1F{0=!^Z< zg8?EpU3J0ZW}_h10XyhW&3VFiDa_@PEf~~|M*&09K|M3*JwGT=$cE=;S}?7f1{AO= zgi#^wd%gODVy>`T%92XSWKJ)F4cAv~Gdn@Bjt!g5{Pqm099^W?>+m~?tk>}VX}oC) z9PxQsXGJ69YN_X{5aBorz_*2H%5Cgqq5&jG3t)Z2y|V6Sf%nnnHzCVZuxb!QInmH_ zs4->1`ThkR)?~T%RPjxs%x&B+IW~SX4YO*~`o&a5pS(bv3_W6>!je>KUWJ>-m$FgR zhG|RB(j^d8Hw*J>D?sI?6UgjEWxD^T2}}prlZ->1-039%_U-9XX2E}d)WEIIjE`_l z2DC;hN|J0H;@3OwncAD`&b*QGFw@X(7YtUCibV;B`mS(R^E{Z9+;J30N0Bg5W1yZ58v`u*37Vqu@b>B>~8$^`(H8e}rSv0C^D1lL(# zA-yOAxYdcwz!UAMz7DsYVLX)=+wEEeuh4k+j@+f3)41OgZwKMbDD1JCRJ@9!;TEZ! znZxlzsQ0A=VQV;z*5-WiVlr10IpIMP^>({~!}GhrCiVWD{tGJ{RYz?<%*8l6HR(Wx zg=u;p#7sw`6SUP#K{IdC_e>{FxcN$N{nZ2pfi{??Lk)LWh+QqB5#E4Uxd$eG! zPE(caOy~lqY`lgox2ZZ$oF7lzE447;oXa=gn2LxWO@F8C5%8rL51bNbLwey&%Tcd~ z8gg^*&$t%gKO<$`!YgN@eq4xTcgenYXIU%2Gv;-r{m7#1_Z*7vf~<{gI{)t9#C(65 zY@w$4w1~oAJSxGJI?biU%<(j-{N z&+hz7a=|+&>r7hX&J1Cn+pc091NU89? z08F9o_YK#DC95ETGyx&_`lDZG-6OU&CFA$R;#1aIP2N+E)Nl^(@G#okdikeL$=j`< zRNBr08D(EmYuX1Kqbd+i&S1x97?P~RR&+fxU%uNC;tWlx-f$tKsXeeqoL8fJMGmYP zMi-db=(puSO(fd{7mM{rOQa{J^6$mdoJ zkPPAkO(m4(%TSj*ZQAgB9G3E;f4RZIXhG^>6b@7hvSIP&MA<1rMIcMg&Mu#K1=7$Y z$Ns)jX@X*CM5AeB3Dq;d*Ybq@aD^Yafs5Uz@A{UwrWgyz5Kj!X8kt2!jiaF_Qr8iv zefu(U!xX!ZN-{Pkmbm1VNE7>UVUkpY1H1^FMS4uXw6?*spPVB@3^gr`maV=>PosU3 z&Wt%J8mXvN#KpQJm*F~_H-(hsedfkR(KJSy6X_>jhc4_eQu?~t$b4L5BIm2C#-@IqNP@BP(e=WR)wrx8( zKdb9IC{=;Tc+gClxd2r;GhG`RbpMO(d+VDFp&jbbn z5(NEU{^hR#(ElN5ZRG%P`Lo$zfWp`xT57zY0Wgc`#cJ0+QQ+A%WOS@nVrod}2FooN zW5uimtmpGbx~99twmXnd@`K#qTP%esDcpyd_J`^DRn}AVK#et-K_SmPwG@ZZJ-(}G zjx@(=M#BM2!4{a{zB%)?@0q9~nT|WQW$!b~fZ=qm-gBnp3Ruqp+9Y>l6#^M;eaW&C zjsB4f&P?J*Os7(4d*p!zc)!J~wmtpaeV1K=lZ@c);H+kU6phY_4R{0`M||&89%q5T zg&lfam`%&4Oq3-B%u~@H43qvAUIVOU4gKB3LY5EANg;{pTw4!$-DuLHElfe2%L)d# zsG!tptPG*7pj;wwd(p=c!lFWw9Ad-2hDrJBDa9JBpH`lTIw zU6$@8K2W9Hgn%HSA6V!KMS+}5PH(i9*i;jVV2*i>TV&AW?X_~V~#mM@xO}$7rkvpwOIbX%C;4zUcoyRflw0EvD`SES7^&%}s z_u47}tAcZ1Puw%4hDB@iIMyy4E}=)(Dv6)t@+a>olhUxh%$SJ4r;?eFr#A>xADPzu zTzaJ0L@G_YQ8|VMAoS=!8Icj2NxhKqCn(c$W(XB zn@N@^UTaE;!Fd4T2XKHY25GdqUv74|$98q{^8wQ^NFy1?3gpMZ89#?2+{F*Oo zBg~I-I>L6WdY>4X{3uP(Od;$IwrM2~Vz`%?5x=FuJ5gbUKZJUs|3E?)Wf&Z<#Oz>d z^?>YPgpRh6#q`0%j zf9XFg^N;qzk+B|K{juYi}R{VZ<+}~W`{1*(;`ZhNI0uT_%2=Dt1QTUU<*B~e08g8|Da9KW8EeFlcCqW7d zOs$q6M78b;2ye8R10rPW7bCLkAe?hYI#-Y2)90hxB-i$AaxR%)7E z8_RJlN>7Kw z?i6p-)yHhB_x9^^}~*Y)_#u@Lghma26ukTU=aMVqh1k9TYig5>IPr^ zFLOMtL%&E|KrRH_LL|c+OhKQ(sY-tqPM&Dd6X;7Pie~g_@OxlQ7v^ zAz#@sM_6~H87H6Gka>5OS8ZnFYj}?(tl3OY;~5(>vDv@cDx~3IF#nY44KIq=Q&haJn{#5K%1A0 zSim+EGP)HAz3@Mw#2;X$Q&Tcoa<;!XgxCy7wiB3NExFgGM5#|6YBXj*lff>V2s5!2 z*Xs*>i6$s2w`GYri@B}$*{5hH)feI77F0oQp@HWAxq+M5yF@lrwG~`+yK9od=jq%a z-;#2|5?6AE$=IhrTW5$KD*6>G5_(=%4tiZ>Wfa!RM`{eEFSp{B6(^}{Iz!Bv4B}S| zbK?UBsA(A+s%6GdyH*B9{&7ZOJX02x=0xsk5540XOpfdAeu3lC?>gTtf}siz zU0y@tdi7^Hys10A!Rp*>18}_tsPWoM^(VOtqaraT7i}R_rbAXN1!|IKup=8t-62Um zI16RR5Jqo$Oq5`D_b!AgM%Pw_>Q$&@Dk7Jz*iCheRTffhW!ecnRC9EPwrV2SBlEr* zKZnR=%PvA(>EntYlg7+mBQT!-I-0qbZ9nema(Ki3oViBwP#V&Fs)}r~6%yhv{6&*K zAs||oX6ndXVdYf5culHRXjmYo6pA!qAXEqNkF-k3iY;rQt7Gw&J!-~CI>M@!A2Ke0 z)(@yO)rbj9?d8+yoStlpTn#{2oLZd^_1UZlo*C}#eQ}u zKxgMjPPp#RABMNuizwTOHyk{5;51y7K^xehT(qrF_P#E+F6=?8O{g@1RYM%!P>-5h z?gQfKkdO8HD0tK@vr@mv73mO4)#Y1&9ar?dh7hWqT9zYvrJ~-RLbHwI1hC_m$4E%S zlrJLNck{3%-?8Zt7l1#s3!q5e${)t;zClxX0^!$FW?CCo>N5=|U`0ufRvg7oZOmxoQE1 z4s)(NGS^rAEk3S(T>lc5naA%SLKy=9hoh&C?j&&bA4c$mxt4#-6^ulYdlW;G4n8XcID7E0E#@jx_wDf?@Q+?XsR#~+I3yZo zUf8_e@CO`jYSJI-8*jt5&ws{{JwDnf0DqU_5N{{}5VoaKSWImPI4vG5kb$KzIdM^{ z<#7cgYh2G0NJtO!)Pux6JDZo(548ZiL8u8QMe@`~W)s2n;F4b#p9&&%lbRBRiZY%O zbLTege+;3(!L{x_DhiI(|Ni`2wac=0gGkZe7#E0HRsh~PhVsAfgwm2PUD5sB1Svq-uf4r(H>csqxUz(+#^JRXSqRJuR% zR(&d&AJ%TVAH?^tlk$d9@*2SlmbtF$%R|;QiuZpC|9qoMKCt84iHc}E3U4KElbut4 z^ht?o#sul^vl3w)8L^+`pQl7o<%cGi-0r`DPgXrngaLf$?N4nMf**gcQ1^-0FG z5≪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