Implement a multithreaded pipeline to load the component preset files. This greatly reduces the time to load them.
This commit is contained in:
parent
692fcebb11
commit
7b093f79f8
@ -1,6 +1,5 @@
|
|||||||
package net.sf.openrocket.database;
|
package net.sf.openrocket.database;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -23,11 +22,10 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
|
|||||||
|
|
||||||
private static final LogHelper log = Application.getLogger();
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
private static class ComponentPresetLoader implements Loader<ComponentPreset> {
|
public static class ComponentPresetLoader implements Loader<ComponentPreset> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ComponentPreset> load(InputStream stream,
|
public Collection<ComponentPreset> load(InputStream stream, String filename) {
|
||||||
String filename) throws IOException {
|
|
||||||
|
|
||||||
log.debug("Loading presets from file " + filename);
|
log.debug("Loading presets from file " + filename);
|
||||||
|
|
||||||
@ -41,7 +39,7 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
|
|||||||
preset.setFavorite(true);
|
preset.setFavorite(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.debug("ComponentPreset file " + filename + " contained " + presets.size() + " presets");
|
||||||
return presets;
|
return presets;
|
||||||
} catch (JAXBException e) {
|
} catch (JAXBException e) {
|
||||||
throw new BugException("Unable to parser file: "+ filename, e);
|
throw new BugException("Unable to parser file: "+ filename, e);
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
package net.sf.openrocket.startup;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import net.sf.openrocket.database.ComponentPresetDatabase;
|
||||||
|
import net.sf.openrocket.file.iterator.DirectoryIterator;
|
||||||
|
import net.sf.openrocket.file.iterator.FileIterator;
|
||||||
|
import net.sf.openrocket.gui.util.SimpleFileFilter;
|
||||||
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
|
import net.sf.openrocket.preset.ComponentPreset;
|
||||||
|
import net.sf.openrocket.util.Pair;
|
||||||
|
|
||||||
|
public class ConcurrentComponentPresetDatabaseLoader {
|
||||||
|
|
||||||
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
private static final String SYSTEM_PRESET_DIR = "datafiles/presets";
|
||||||
|
|
||||||
|
private final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
private final ComponentPresetDatabase componentPresetDao;
|
||||||
|
|
||||||
|
private final ExecutorService writerPool;
|
||||||
|
|
||||||
|
private final ExecutorService loaderPool;
|
||||||
|
|
||||||
|
private final Thread workGenerator;
|
||||||
|
|
||||||
|
private FileIterator iterator;
|
||||||
|
|
||||||
|
private long startTime;
|
||||||
|
private long fileCount = 0;
|
||||||
|
private long presetCount = 0;
|
||||||
|
|
||||||
|
ConcurrentComponentPresetDatabaseLoader( ComponentPresetDatabase componentPresetDao ) {
|
||||||
|
this.componentPresetDao = componentPresetDao;
|
||||||
|
|
||||||
|
writerPool = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r,"PresetWriterThread");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loaderPool = Executors.newFixedThreadPool(15, new ThreadFactory() {
|
||||||
|
int threadCount = 0;
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r,"PresetLoaderPool-" + threadCount++);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
workGenerator = new Thread( new WorkGenerator(),"PresetGeneratorThread");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
workGenerator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void await() throws InterruptedException {
|
||||||
|
latch.await();
|
||||||
|
loaderPool.shutdown();
|
||||||
|
loaderPool.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
|
writerPool.shutdown();
|
||||||
|
writerPool.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
|
iterator.close();
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
log.debug("Time to load presets: " + (end-startTime) + "ms " + presetCount + " loaded from " + fileCount + " files");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class WorkGenerator implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Start loading
|
||||||
|
log.info("Loading component presets from " + SYSTEM_PRESET_DIR);
|
||||||
|
|
||||||
|
iterator = DirectoryIterator.findDirectory(SYSTEM_PRESET_DIR,
|
||||||
|
new SimpleFileFilter("", false, "orc"));
|
||||||
|
|
||||||
|
if (iterator == null) {
|
||||||
|
throw new IllegalStateException("Component preset directory " + SYSTEM_PRESET_DIR +
|
||||||
|
" not found, distribution built wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
while( iterator.hasNext() ) {
|
||||||
|
Pair<String,InputStream> f = iterator.next();
|
||||||
|
FileLoader loader = new FileLoader( f.getV(), f.getU() );
|
||||||
|
loaderPool.execute(loader);
|
||||||
|
fileCount ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FileLoader implements Runnable {
|
||||||
|
private final InputStream is;
|
||||||
|
private final String fileName;
|
||||||
|
|
||||||
|
public FileLoader(InputStream is, String fileName) {
|
||||||
|
super();
|
||||||
|
this.is = is;
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ComponentPresetDatabase.ComponentPresetLoader loader = new ComponentPresetDatabase.ComponentPresetLoader();
|
||||||
|
Collection<ComponentPreset> presets = loader.load(is, fileName);
|
||||||
|
PresetWriter writer = new PresetWriter(presets);
|
||||||
|
writerPool.execute(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PresetWriter implements Runnable {
|
||||||
|
private final Collection<ComponentPreset> presets;
|
||||||
|
|
||||||
|
public PresetWriter(Collection<ComponentPreset> presets) {
|
||||||
|
super();
|
||||||
|
this.presets = presets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
presetCount += presets.size();
|
||||||
|
componentPresetDao.addAll(presets);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,6 @@ import java.awt.GraphicsEnvironment;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
@ -20,21 +13,13 @@ import net.sf.openrocket.communication.UpdateInfo;
|
|||||||
import net.sf.openrocket.communication.UpdateInfoRetriever;
|
import net.sf.openrocket.communication.UpdateInfoRetriever;
|
||||||
import net.sf.openrocket.database.ComponentPresetDatabase;
|
import net.sf.openrocket.database.ComponentPresetDatabase;
|
||||||
import net.sf.openrocket.database.Databases;
|
import net.sf.openrocket.database.Databases;
|
||||||
import net.sf.openrocket.database.ThrustCurveMotorSet;
|
|
||||||
import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
|
|
||||||
import net.sf.openrocket.file.iterator.DirectoryIterator;
|
|
||||||
import net.sf.openrocket.file.iterator.FileIterator;
|
|
||||||
import net.sf.openrocket.file.motor.MotorLoaderHelper;
|
|
||||||
import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
|
import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
|
||||||
import net.sf.openrocket.gui.main.BasicFrame;
|
import net.sf.openrocket.gui.main.BasicFrame;
|
||||||
import net.sf.openrocket.gui.main.Splash;
|
import net.sf.openrocket.gui.main.Splash;
|
||||||
import net.sf.openrocket.gui.main.SwingExceptionHandler;
|
import net.sf.openrocket.gui.main.SwingExceptionHandler;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
import net.sf.openrocket.gui.util.SimpleFileFilter;
|
|
||||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||||
import net.sf.openrocket.logging.LogHelper;
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.motor.Motor;
|
|
||||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
|
||||||
import net.sf.openrocket.util.BuildProperties;
|
import net.sf.openrocket.util.BuildProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,22 +76,10 @@ public class Startup2 {
|
|||||||
log.info("Initializing the splash screen");
|
log.info("Initializing the splash screen");
|
||||||
Splash.init();
|
Splash.init();
|
||||||
|
|
||||||
// Latch which counts the number of background loading processes we need to complete.
|
|
||||||
CountDownLatch loading = new CountDownLatch(1);
|
|
||||||
ExecutorService exec = Executors.newFixedThreadPool(1, new ThreadFactory() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Thread newThread(Runnable r) {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Must be done after localization is initialized
|
// Must be done after localization is initialized
|
||||||
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
|
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
|
||||||
exec.submit( new ComponentPresetLoader( loading, componentPresetDao));
|
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( componentPresetDao );
|
||||||
|
presetLoader.load();
|
||||||
|
|
||||||
Application.setComponentPresetDao( componentPresetDao );
|
Application.setComponentPresetDao( componentPresetDao );
|
||||||
|
|
||||||
@ -147,7 +120,7 @@ public class Startup2 {
|
|||||||
Databases.fakeMethod();
|
Databases.fakeMethod();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.await();
|
presetLoader.await();
|
||||||
} catch ( InterruptedException iex) {
|
} catch ( InterruptedException iex) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -226,28 +199,6 @@ public class Startup2 {
|
|||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ComponentPresetLoader implements Callable {
|
|
||||||
|
|
||||||
CountDownLatch latch;
|
|
||||||
ComponentPresetDatabase componentPresetDao;
|
|
||||||
|
|
||||||
private ComponentPresetLoader( CountDownLatch latch, ComponentPresetDatabase componentPresetDao ) {
|
|
||||||
this.componentPresetDao = componentPresetDao;
|
|
||||||
this.latch = latch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
componentPresetDao.load("datafiles/presets", "(?i).*orc");
|
|
||||||
latch.countDown();
|
|
||||||
long end = System.currentTimeMillis();
|
|
||||||
log.debug("Time to load presets: " + (end-start) + "ms");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles arguments passed from the command line. This may be used either
|
* Handles arguments passed from the command line. This may be used either
|
||||||
* when starting the first instance of OpenRocket or later when OpenRocket is
|
* when starting the first instance of OpenRocket or later when OpenRocket is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user