embulk-output-multi 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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