embulk-output-multi 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40d2c979fbce0853ed920cae18f0f867284e9491
4
- data.tar.gz: e02bef302e6b8061f9029dc4d7077a00b7563623
3
+ metadata.gz: 133f0b4290cb49bc787590e22edacf2e4f4df4e1
4
+ data.tar.gz: bb8c9a01232bb0ab43bc845af45a66039988133d
5
5
  SHA512:
6
- metadata.gz: ba665f2f4108d65c1cf48ad5a94789e6d719443bb0e8bc7f579f05357407918ab275b41cd55aa96af0ae0854e572427f55039a8502e332c8ab22d6707d6118f9
7
- data.tar.gz: 7fa76fd0c1a8c06e89b2b0eff90e6b16e00985db269444a37812da6af0f40e3a74a748b00c7e3dfc675b35f7c60875e5f57efd87bf6963eacf57f05cc04a9e79
6
+ metadata.gz: 7a63b03b9c0d566b49c88fb666390d94ddab230ef21d1fe4254f7131fc4fb6977610b6b95d9966e98631ec8d842dbdcbfc1639d076f6f7bd394f076a4dbe913d
7
+ data.tar.gz: 754f5fe52bb5b00f87eebdbaef36157dc4d1e9c1ddcbc541f66d9d6cb54af134c02010a50684f5114a3107ea2dfb2f3ec087807da5aa2b411e13bbd2d1889f7a
data/gradle.properties CHANGED
@@ -1 +1 @@
1
- version=0.2.1
1
+ version=0.2.2
@@ -5,22 +5,22 @@ import org.embulk.config.TaskReport;
5
5
  import org.embulk.config.TaskSource;
6
6
  import org.embulk.spi.OutputPlugin;
7
7
 
8
- import java.util.ArrayList;
9
8
  import java.util.List;
10
9
  import java.util.concurrent.Callable;
10
+ import java.util.concurrent.ConcurrentHashMap;
11
+ import java.util.concurrent.ConcurrentMap;
11
12
  import java.util.concurrent.CountDownLatch;
12
13
  import java.util.concurrent.ExecutionException;
13
14
  import java.util.concurrent.ExecutorService;
14
15
  import java.util.concurrent.Executors;
15
16
  import java.util.concurrent.Future;
16
- import java.util.concurrent.atomic.AtomicReferenceArray;
17
17
 
18
18
  class AsyncRunControl {
19
19
  private static final String THREAD_NAME_FORMAT = "multi-run-control-%d";
20
20
  private final MultiOutputPlugin.PluginTask task;
21
21
  private final OutputPlugin.Control control;
22
22
  private final CountDownLatch latch;
23
- private final AtomicReferenceArray<TaskSource> taskSources;
23
+ private final ConcurrentMap<String, TaskSource> taskSources;
24
24
  private final ExecutorService executorService;
25
25
  private Future<List<TaskReport>> result;
26
26
 
@@ -32,7 +32,7 @@ class AsyncRunControl {
32
32
  this.task = task;
33
33
  this.control = control;
34
34
  this.latch = new CountDownLatch(task.getOutputConfigs().size());
35
- this.taskSources = new AtomicReferenceArray<>(task.getOutputConfigs().size());
35
+ this.taskSources = new ConcurrentHashMap<>(task.getOutputConfigs().size());
36
36
  this.executorService = Executors.newSingleThreadExecutor(
37
37
  new ThreadFactoryBuilder().setNameFormat(THREAD_NAME_FORMAT).build()
38
38
  );
@@ -42,8 +42,8 @@ class AsyncRunControl {
42
42
  result.cancel(true);
43
43
  }
44
44
 
45
- void addTaskSource(int index, TaskSource taskSource) {
46
- taskSources.set(index, taskSource);
45
+ void addTaskSource(String tag, TaskSource taskSource) {
46
+ taskSources.putIfAbsent(tag, taskSource);
47
47
  latch.countDown();
48
48
  }
49
49
 
@@ -64,10 +64,6 @@ class AsyncRunControl {
64
64
  @Override
65
65
  public List<TaskReport> call() throws Exception {
66
66
  latch.await();
67
- List<TaskSource> taskSources = new ArrayList<>(AsyncRunControl.this.taskSources.length());
68
- for (int i = 0; i < AsyncRunControl.this.taskSources.length(); i++) {
69
- taskSources.add(AsyncRunControl.this.taskSources.get(i));
70
- }
71
67
  task.setTaskSources(taskSources);
72
68
  return control.run(task.dump());
73
69
  }
@@ -16,12 +16,15 @@ import org.embulk.spi.OutputPlugin;
16
16
  import org.embulk.spi.Page;
17
17
  import org.embulk.spi.Schema;
18
18
  import org.embulk.spi.TransactionalPageOutput;
19
+ import org.slf4j.Logger;
20
+ import org.slf4j.LoggerFactory;
19
21
 
20
22
  import java.util.ArrayList;
23
+ import java.util.HashMap;
21
24
  import java.util.List;
25
+ import java.util.Map;
22
26
  import java.util.Optional;
23
27
  import java.util.concurrent.ExecutionException;
24
- import java.util.concurrent.Future;
25
28
  import java.util.function.Function;
26
29
  import java.util.stream.Collectors;
27
30
 
@@ -32,12 +35,13 @@ public class MultiOutputPlugin implements OutputPlugin {
32
35
 
33
36
  @Config(CONFIG_NAME_OUTPUT_CONFIG_DIFFS)
34
37
  @ConfigDefault("null")
35
- Optional<List<ConfigDiff>> getOutputConfigDiffs();
38
+ Optional<Map<String, ConfigDiff>> getOutputConfigDiffs();
36
39
 
37
- List<TaskSource> getTaskSources();
38
- void setTaskSources(List<TaskSource> taskSources);
40
+ Map<String, TaskSource> getTaskSources();
41
+ void setTaskSources(Map<String, TaskSource> taskSources);
39
42
  }
40
43
 
44
+ private static final Logger LOGGER = LoggerFactory.getLogger(MultiOutputPlugin.class);
41
45
  private static final String CONFIG_NAME_OUTPUT_CONFIG_DIFFS = "output_config_diffs";
42
46
  static final String CONFIG_NAME_OUTPUT_TASK_REPORTS = "output_task_reports";
43
47
 
@@ -123,11 +127,11 @@ public class MultiOutputPlugin implements OutputPlugin {
123
127
  @Override
124
128
  public TaskReport commit() {
125
129
  final TaskReport report = Exec.newTaskReport();
126
- final List<TaskReport> reports = new ArrayList<>();
130
+ final Map<String, TaskReport> reports = new HashMap<>();
127
131
  final List<OutputPluginDelegate> errorPlugins = new ArrayList<>();
128
132
  for (TransactionalPageOutputDelegate output : delegates) {
129
133
  try {
130
- reports.add(output.commit());
134
+ reports.put(output.getTag(), output.commit());
131
135
  } catch (PluginExecutionException e) {
132
136
  errorPlugins.add(e.getPlugin());
133
137
  }
@@ -135,7 +139,7 @@ public class MultiOutputPlugin implements OutputPlugin {
135
139
  if (!errorPlugins.isEmpty()) {
136
140
  throw new RuntimeException(
137
141
  String.format("Following plugins failed to output [%s]",
138
- errorPlugins.stream().map(OutputPluginDelegate::getPluginCode).collect(Collectors.joining(", "))
142
+ errorPlugins.stream().map(OutputPluginDelegate::getTag).collect(Collectors.joining(", "))
139
143
  ));
140
144
  }
141
145
  report.set(CONFIG_NAME_OUTPUT_TASK_REPORTS, new TaskReports(reports));
@@ -144,12 +148,12 @@ public class MultiOutputPlugin implements OutputPlugin {
144
148
  };
145
149
  }
146
150
 
147
- private static ConfigDiff buildConfigDiff(List<Future<ConfigDiff>> runPluginTasks) {
151
+ private static ConfigDiff buildConfigDiff(List<OutputPluginDelegate.Transaction> transactions) {
148
152
  final ConfigDiff configDiff = Exec.newConfigDiff();
149
- List<ConfigDiff> configDiffs = new ArrayList<>();
150
- for (Future<ConfigDiff> pluginTask : runPluginTasks) {
153
+ Map<String, ConfigDiff> configDiffs = new HashMap<>();
154
+ for (OutputPluginDelegate.Transaction transaction: transactions) {
151
155
  try {
152
- configDiffs.add(pluginTask.get());
156
+ configDiffs.put(transaction.getTag(), transaction.getResult());
153
157
  } catch (InterruptedException e) {
154
158
  Thread.currentThread().interrupt();
155
159
  throw new RuntimeException(e);
@@ -163,18 +167,29 @@ public class MultiOutputPlugin implements OutputPlugin {
163
167
 
164
168
  private <T> List<T> mapWithPluginDelegate(PluginTask task, ExecSession session, Function<OutputPluginDelegate, T> action) {
165
169
  List<T> result = new ArrayList<>();
166
- for (int pluginIndex = 0; pluginIndex < task.getOutputConfigs().size(); pluginIndex++) {
167
- final ConfigSource config = task.getOutputConfigs().get(pluginIndex);
168
- if (task.getOutputConfigDiffs().isPresent()) {
169
- config.merge(task.getOutputConfigDiffs().get().get(pluginIndex));
170
- }
170
+ for (int i = 0; i < task.getOutputConfigs().size(); i++) {
171
+ final ConfigSource config = task.getOutputConfigs().get(i);
171
172
  final PluginType pluginType = config.get(PluginType.class, "type");
172
173
  final OutputPlugin outputPlugin = session.newPlugin(OutputPlugin.class, pluginType);
174
+
175
+ final String tag = String.format("%s_%d", pluginType.getName(), i);
176
+
177
+ // Merge ConfigDiff if exists
178
+ if (task.getOutputConfigDiffs().isPresent()) {
179
+ final ConfigDiff configDiff = task.getOutputConfigDiffs().get().get(tag);
180
+ if (configDiff != null) {
181
+ config.merge(configDiff);
182
+ } else {
183
+ LOGGER.debug("ConfigDiff for '{}' not found.", tag);
184
+ }
185
+ }
186
+ // Set TaskSource if exists
173
187
  TaskSource taskSource = null;
174
188
  if (task.getTaskSources() != null) {
175
- taskSource = task.getTaskSources().get(pluginIndex);
189
+ taskSource = task.getTaskSources().get(tag);
176
190
  }
177
- result.add(action.apply(new OutputPluginDelegate(pluginIndex, pluginType, outputPlugin, config, taskSource)));
191
+
192
+ result.add(action.apply(new OutputPluginDelegate(tag, outputPlugin, config, taskSource)));
178
193
  }
179
194
  return result;
180
195
  }
@@ -5,7 +5,6 @@ import org.embulk.config.ConfigDiff;
5
5
  import org.embulk.config.ConfigSource;
6
6
  import org.embulk.config.TaskReport;
7
7
  import org.embulk.config.TaskSource;
8
- import org.embulk.plugin.PluginType;
9
8
  import org.embulk.spi.OutputPlugin;
10
9
  import org.embulk.spi.Schema;
11
10
  import org.embulk.spi.TransactionalPageOutput;
@@ -23,105 +22,92 @@ import java.util.concurrent.Future;
23
22
  class OutputPluginDelegate {
24
23
  private static final Logger LOGGER = LoggerFactory.getLogger(OutputPluginDelegate.class);
25
24
  private static final String THREAD_NAME_FORMAT = "multi-output-plugin-%s-%%d";
26
- private final int pluginIndex;
27
- private final PluginType type;
25
+ private final String tag;
28
26
  private final OutputPlugin plugin;
29
27
  private final ConfigSource config;
30
28
  private final TaskSource taskSource;
31
29
  private final ExecutorService executorService;
32
30
 
33
31
  OutputPluginDelegate(
34
- int pluginIndex,
35
- PluginType type,
32
+ String tag,
36
33
  OutputPlugin plugin,
37
34
  ConfigSource config,
38
35
  TaskSource taskSource
39
36
  ) {
40
- this.pluginIndex = pluginIndex;
41
- this.type = type;
37
+ this.tag = tag;
42
38
  this.plugin = plugin;
43
39
  this.config = config;
44
40
  this.taskSource = taskSource;
45
41
  this.executorService = Executors.newSingleThreadExecutor(
46
- new ThreadFactoryBuilder().setNameFormat(String.format(THREAD_NAME_FORMAT, generatePluginCode(type, pluginIndex))).build()
42
+ new ThreadFactoryBuilder().setNameFormat(String.format(THREAD_NAME_FORMAT, tag)).build()
47
43
  );
48
44
  }
49
45
 
50
- Future<ConfigDiff> transaction(Schema schema, int taskCount, AsyncRunControl runControl) {
51
- return executorService.submit(() -> {
46
+ Transaction transaction(Schema schema, int taskCount, AsyncRunControl runControl) {
47
+ return new Transaction(executorService.submit(() -> {
52
48
  try {
53
- LOGGER.debug("Run #transaction for {}", getPluginCode());
54
- return plugin.transaction(config, schema, taskCount, new Control(pluginIndex, runControl));
49
+ LOGGER.debug("Run #transaction for {}", getTag());
50
+ return plugin.transaction(config, schema, taskCount, new Control(runControl));
55
51
  } catch (CancellationException e) {
56
- LOGGER.error("Canceled #transaction for {} by other plugin's error", getPluginCode());
52
+ LOGGER.error("Canceled #transaction for {} by other plugin's error", getTag());
57
53
  throw e;
58
54
  } catch (Exception e) {
59
- LOGGER.error("Transaction for {} failed.", getPluginCode(), e);
55
+ LOGGER.error("Transaction for {} failed.", getTag(), e);
60
56
  runControl.cancel();
61
57
  throw e;
62
58
  } finally {
63
59
  executorService.shutdown();
64
60
  }
65
- });
61
+ }));
66
62
  }
67
63
 
68
- Future<ConfigDiff> resume(Schema schema, int taskCount, AsyncRunControl runControl) {
69
- return executorService.submit(() -> {
64
+ Transaction resume(Schema schema, int taskCount, AsyncRunControl runControl) {
65
+ return new Transaction(executorService.submit(() -> {
70
66
  try {
71
- LOGGER.debug("Run #resume for {}", getPluginCode());
72
- return plugin.resume(taskSource, schema, taskCount, new Control(pluginIndex, runControl));
67
+ LOGGER.debug("Run #resume for {}", getTag());
68
+ return plugin.resume(taskSource, schema, taskCount, new Control(runControl));
73
69
  } catch (CancellationException e) {
74
- LOGGER.error("Canceled #resume for {} by other plugin's error", getPluginCode());
70
+ LOGGER.error("Canceled #resume for {} by other plugin's error", getTag());
75
71
  throw e;
76
72
  } catch (Exception e) {
77
- LOGGER.error("Resume for {} failed.", getPluginCode(), e);
73
+ LOGGER.error("Resume for {} failed.", getTag(), e);
78
74
  runControl.cancel();
79
75
  throw e;
80
76
  } finally {
81
77
  executorService.shutdown();
82
78
  }
83
- });
79
+ }));
84
80
  }
85
81
 
86
82
  void cleanup(Schema schema, int taskCount, List<TaskReport> successTaskReports) {
87
- LOGGER.debug("Run #cleanup for {}", getPluginCode());
83
+ LOGGER.debug("Run #cleanup for {}", getTag());
88
84
  List<TaskReport> successReportsForPlugin = new ArrayList<>();
89
85
  for (TaskReport successTaskReport : successTaskReports) {
90
- final TaskReport report = successTaskReport.get(TaskReports.class, MultiOutputPlugin.CONFIG_NAME_OUTPUT_TASK_REPORTS).get(pluginIndex);
86
+ final TaskReport report = successTaskReport.get(TaskReports.class, MultiOutputPlugin.CONFIG_NAME_OUTPUT_TASK_REPORTS).get(tag);
91
87
  successReportsForPlugin.add(report);
92
88
  }
93
89
  plugin.cleanup(taskSource, schema, taskCount, successReportsForPlugin);
94
90
  }
95
91
 
96
92
  TransactionalPageOutput open(Schema schema, int taskIndex) {
97
- LOGGER.debug("Run #open for {}", getPluginCode());
93
+ LOGGER.debug("Run #open for {}", getTag());
98
94
  return plugin.open(taskSource, schema, taskIndex);
99
95
  }
100
96
 
101
- PluginType getType() {
102
- return type;
97
+ String getTag() {
98
+ return tag;
103
99
  }
104
100
 
105
- String getPluginCode() {
106
- return generatePluginCode(type, pluginIndex);
107
- }
108
-
109
- private static String generatePluginCode(PluginType type, int pluginIndex) {
110
- return String.format("%s-%d", type.getName(), pluginIndex);
111
- }
112
-
113
- private static class Control implements OutputPlugin.Control {
114
- private final int pluginIndex;
101
+ private class Control implements OutputPlugin.Control {
115
102
  private final AsyncRunControl runControl;
116
103
 
117
- Control(int index, AsyncRunControl runControl) {
118
- this.pluginIndex = index;
104
+ Control(AsyncRunControl runControl) {
119
105
  this.runControl = runControl;
120
106
  }
121
107
 
122
108
  @Override
123
109
  public List<TaskReport> run(TaskSource taskSource) {
124
- runControl.addTaskSource(pluginIndex, taskSource);
110
+ runControl.addTaskSource(tag, taskSource);
125
111
  List<TaskReport> reports;
126
112
  try {
127
113
  reports = runControl.waitAndGetResult();
@@ -134,10 +120,26 @@ class OutputPluginDelegate {
134
120
 
135
121
  final List<TaskReport> result = new ArrayList<>();
136
122
  for (TaskReport taskReport : reports) {
137
- final TaskReport report = taskReport.get(TaskReports.class, MultiOutputPlugin.CONFIG_NAME_OUTPUT_TASK_REPORTS).get(pluginIndex);
123
+ final TaskReport report = taskReport.get(TaskReports.class, MultiOutputPlugin.CONFIG_NAME_OUTPUT_TASK_REPORTS).get(tag);
138
124
  result.add(report);
139
125
  }
140
126
  return result;
141
127
  }
142
128
  }
129
+
130
+ class Transaction {
131
+ private final Future<ConfigDiff> future;
132
+
133
+ private Transaction(Future<ConfigDiff> future) {
134
+ this.future = future;
135
+ }
136
+
137
+ String getTag() {
138
+ return OutputPluginDelegate.this.getTag();
139
+ }
140
+
141
+ ConfigDiff getResult() throws ExecutionException, InterruptedException {
142
+ return future.get();
143
+ }
144
+ }
143
145
  }
@@ -4,22 +4,22 @@ import com.fasterxml.jackson.annotation.JsonCreator;
4
4
  import com.fasterxml.jackson.annotation.JsonProperty;
5
5
  import org.embulk.config.TaskReport;
6
6
 
7
- import java.util.List;
7
+ import java.util.Map;
8
8
 
9
9
  class TaskReports {
10
- private final List<TaskReport> reports;
10
+ private final Map<String, TaskReport> reports;
11
11
 
12
12
  @JsonCreator
13
- TaskReports(@JsonProperty("reports") List<TaskReport> reports) {
13
+ TaskReports(@JsonProperty("reports") Map<String, TaskReport> reports) {
14
14
  this.reports = reports;
15
15
  }
16
16
 
17
17
  @JsonProperty("reports")
18
- List<TaskReport> getReports() {
18
+ Map<String, TaskReport> getReports() {
19
19
  return reports;
20
20
  }
21
21
 
22
- TaskReport get(int index) {
23
- return reports.get(index);
22
+ TaskReport get(String tag) {
23
+ return reports.get(tag);
24
24
  }
25
25
  }
@@ -31,7 +31,7 @@ class TransactionalPageOutputDelegate {
31
31
  this.delegate = delegate;
32
32
  this.taskQueue = new LinkedBlockingQueue<>();
33
33
  this.executorService = Executors.newSingleThreadExecutor(
34
- new ThreadFactoryBuilder().setNameFormat(String.format(THREAD_NAME_FORMAT, source.getPluginCode(), taskIndex)).build()
34
+ new ThreadFactoryBuilder().setNameFormat(String.format(THREAD_NAME_FORMAT, source.getTag(), taskIndex)).build()
35
35
  );
36
36
  this.result = executorService.submit(new Worker());
37
37
  }
@@ -78,6 +78,10 @@ class TransactionalPageOutputDelegate {
78
78
  }
79
79
  }
80
80
 
81
+ String getTag() {
82
+ return source.getTag();
83
+ }
84
+
81
85
  private class Worker implements Callable<TaskReport> {
82
86
  @Override
83
87
  public TaskReport call() throws InterruptedException {
@@ -24,10 +24,10 @@ import static org.embulk.test.Utils.configFromResource;
24
24
  import static org.embulk.test.Utils.record;
25
25
  import static org.junit.jupiter.api.Assertions.assertEquals;
26
26
  import static org.junit.jupiter.api.Assertions.assertNull;
27
- import static org.junit.jupiter.api.Assertions.assertTrue;
28
27
 
29
28
  @EmbulkTest(MultiOutputPlugin.class)
30
29
  class TestMultiOutputPlugin extends EmbulkPluginTest {
30
+
31
31
  @Test
32
32
  void testMultipleOutputWorking() throws IOException {
33
33
  final ConfigSource inConfig = configFromResource("yaml/in_base.yml");
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-output-multi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shinichi ISHIMURA
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-07 00:00:00.000000000 Z
11
+ date: 2019-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ files:
50
50
  - LICENSE
51
51
  - README.md
52
52
  - build.gradle
53
- - classpath/embulk-output-multi-0.2.1.jar
53
+ - classpath/embulk-output-multi-0.2.2.jar
54
54
  - gradle.properties
55
55
  - gradle/dependency-locks/compileClasspath.lockfile
56
56
  - gradle/dependency-locks/testCompileClasspath.lockfile