Skip to content

Commit

Permalink
objectionary#1230 introduce multithreading for parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
mximp committed Oct 14, 2022
1 parent ac9e2ce commit a89a45a
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 15 deletions.
86 changes: 71 additions & 15 deletions eo-maven-plugin/src/main/java/org/eolang/maven/ParseMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
Expand All @@ -47,6 +53,8 @@
* Parse EO to XML.
*
* @since 0.1
* @todo #1230:30min Make number of threads in parsing executor configurable
* via mojo parameter. Default value should be 4.
*/
@Mojo(
name = "parse",
Expand Down Expand Up @@ -96,30 +104,78 @@ public void exec() throws IOException {
final Collection<Tojo> tojos = this.scopedTojos().select(
row -> row.exists(AssembleMojo.ATTR_EO)
);
int total = 0;
for (final Tojo tojo : tojos) {
if (tojo.exists(AssembleMojo.ATTR_XMIR)) {
final Path xmir = Paths.get(tojo.get(AssembleMojo.ATTR_XMIR));
final Path src = Paths.get(tojo.get(AssembleMojo.ATTR_EO));
if (xmir.toFile().lastModified() >= src.toFile().lastModified()) {
Logger.debug(
this, "Already parsed %s to %s (it's newer than the source)",
tojo.get(Tojos.KEY), new Home().rel(xmir)
final Set<Callable<Object>> tasks = new HashSet<>(0);
final AtomicInteger total = new AtomicInteger(0);
tojos.stream()
.map(SynchronizedTojo::new)
.forEach(
tojo -> {
if (tojo.exists(AssembleMojo.ATTR_XMIR)) {
final Path xmir = Paths.get(tojo.get(AssembleMojo.ATTR_XMIR));
final Path src = Paths.get(tojo.get(AssembleMojo.ATTR_EO));
if (xmir.toFile().lastModified() >= src.toFile().lastModified()) {
Logger.debug(
this, "Already parsed %s to %s (it's newer than the source)",
tojo.get(Tojos.KEY), new Home().rel(xmir)
);
return;
}
}
tasks.add(
Executors.callable(
() -> {
try {
this.parse(tojo);
total.incrementAndGet();
} catch (final IOException ex) {
throw new IllegalStateException(
String.format(
"Unable to parse %s",
tojo.get(Tojos.KEY)
),
ex
);
}
}
)
);
continue;
}
}
this.parse(tojo);
++total;
);
try {
Executors.newFixedThreadPool(4)
.invokeAll(tasks)
.forEach(
completed -> {
try {
completed.get();
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (final ExecutionException ex) {
throw new IllegalArgumentException(
ex.getCause().getMessage(),
ex
);
}
}
);
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException(
String.format(
"Interrupted while waiting for %d parsing to finish",
total.get()
),
ex
);
}
if (total == 0) {
if (total.get() == 0) {
if (tojos.isEmpty()) {
Logger.info(this, "No .eo sources need to be parsed to XMIRs");
} else {
Logger.info(this, "No .eo sources parsed to XMIRs");
}
} else {
Logger.info(this, "Parsed %d .eo sources to XMIRs", total);
Logger.info(this, "Parsed %d .eo sources to XMIRs", total.get());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2022 Objectionary.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.eolang.maven;

import com.yegor256.tojos.Tojo;

/**
* Thread-safe version of tojo. Synchronizes on global single lock within JVM.
* @since 1.0
*/
final class SynchronizedTojo implements Tojo {
/**
* Lock object.
*/
private static final Object LOCK = SynchronizedTojo.class;

/**
* Origin tojo.
*/
private final Tojo origin;

/**
* Ctor.
* @param origin Tojo
*/
SynchronizedTojo(final Tojo origin) {
this.origin = origin;
}

@Override
public boolean exists(final String key) {
synchronized (SynchronizedTojo.LOCK) {
return this.origin.exists(key);
}
}

@Override
public String get(final String key) {
synchronized (SynchronizedTojo.LOCK) {
return this.origin.get(key);
}
}

@Override
public Tojo set(final String key, final Object value) {
synchronized (SynchronizedTojo.LOCK) {
return this.origin.set(key, value);
}
}
}

0 comments on commit a89a45a

Please sign in to comment.