From 591e4f3ee829d43dbced0f281b41fafa8ea71a30 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 9 May 2012 02:01:57 +0000 Subject: [PATCH] Implement a multithreaded pipeline to load the component preset files. This greatly reduces the time to load them. git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@657 180e2498-e6e9-4542-8430-84ac67f01cd8 --- .../database/ComponentPresetDatabase.java | 8 +- ...ncurrentComponentPresetDatabaseLoader.java | 140 ++++++++++++++++++ .../net/sf/openrocket/startup/Startup2.java | 55 +------ 3 files changed, 146 insertions(+), 57 deletions(-) create mode 100644 core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java diff --git a/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java b/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java index 6fc187e7..0fd0d419 100644 --- a/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java +++ b/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java @@ -1,6 +1,5 @@ package net.sf.openrocket.database; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; @@ -23,11 +22,10 @@ public class ComponentPresetDatabase extends Database implement private static final LogHelper log = Application.getLogger(); - private static class ComponentPresetLoader implements Loader { + public static class ComponentPresetLoader implements Loader { @Override - public Collection load(InputStream stream, - String filename) throws IOException { + public Collection load(InputStream stream, String filename) { log.debug("Loading presets from file " + filename); @@ -41,7 +39,7 @@ public class ComponentPresetDatabase extends Database implement preset.setFavorite(true); } } - + log.debug("ComponentPreset file " + filename + " contained " + presets.size() + " presets"); return presets; } catch (JAXBException e) { throw new BugException("Unable to parser file: "+ filename, e); diff --git a/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java b/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java new file mode 100644 index 00000000..a97d688c --- /dev/null +++ b/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java @@ -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 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 presets = loader.load(is, fileName); + PresetWriter writer = new PresetWriter(presets); + writerPool.execute(writer); + } + } + + private class PresetWriter implements Runnable { + private final Collection presets; + + public PresetWriter(Collection presets) { + super(); + this.presets = presets; + } + + @Override + public void run() { + presetCount += presets.size(); + componentPresetDao.addAll(presets); + } + + } +} diff --git a/core/src/net/sf/openrocket/startup/Startup2.java b/core/src/net/sf/openrocket/startup/Startup2.java index d7206f30..b2e13195 100644 --- a/core/src/net/sf/openrocket/startup/Startup2.java +++ b/core/src/net/sf/openrocket/startup/Startup2.java @@ -4,13 +4,6 @@ import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; 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.Timer; @@ -20,21 +13,13 @@ import net.sf.openrocket.communication.UpdateInfo; import net.sf.openrocket.communication.UpdateInfoRetriever; import net.sf.openrocket.database.ComponentPresetDatabase; 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.main.BasicFrame; import net.sf.openrocket.gui.main.Splash; import net.sf.openrocket.gui.main.SwingExceptionHandler; 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.logging.LogHelper; -import net.sf.openrocket.motor.Motor; -import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.util.BuildProperties; /** @@ -91,22 +76,10 @@ public class Startup2 { log.info("Initializing the splash screen"); 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 ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(); - exec.submit( new ComponentPresetLoader( loading, componentPresetDao)); + ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( componentPresetDao ); + presetLoader.load(); Application.setComponentPresetDao( componentPresetDao ); @@ -147,7 +120,7 @@ public class Startup2 { Databases.fakeMethod(); try { - loading.await(); + presetLoader.await(); } catch ( InterruptedException iex) { } @@ -226,28 +199,6 @@ public class Startup2 { 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 * when starting the first instance of OpenRocket or later when OpenRocket is -- 2.47.2