From 4c74be21410b96dc64b28437f9a225c2c99e4196 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sat, 18 Apr 2020 22:35:56 +0200 Subject: [PATCH] allow getMetas without synchronized --- .../nikiroo/fanfix/library/BasicLibrary.java | 47 ++--- .../nikiroo/fanfix/library/CacheLibrary.java | 80 +++++---- .../nikiroo/fanfix/library/LocalLibrary.java | 167 ++++++++++++------ .../nikiroo/fanfix/library/RemoteLibrary.java | 6 +- 4 files changed, 185 insertions(+), 115 deletions(-) diff --git a/src/be/nikiroo/fanfix/library/BasicLibrary.java b/src/be/nikiroo/fanfix/library/BasicLibrary.java index 215bd1a7..586c4ef1 100644 --- a/src/be/nikiroo/fanfix/library/BasicLibrary.java +++ b/src/be/nikiroo/fanfix/library/BasicLibrary.java @@ -98,7 +98,7 @@ abstract public class BasicLibrary { * Do NOT alter this file. * * @param luid - * the Library UID of the story + * the Library UID of the story, can be NULL * @param pg * the optional {@link Progress} * @@ -123,7 +123,7 @@ abstract public class BasicLibrary { public abstract Image getCover(String luid) throws IOException; // TODO: ensure it is the main used interface - public synchronized MetaResultList getList(Progress pg) throws IOException { + public MetaResultList getList(Progress pg) throws IOException { return new MetaResultList(getMetas(pg)); } @@ -338,7 +338,7 @@ abstract public class BasicLibrary { * @param pg * the optional progress reporter */ - public synchronized void refresh(Progress pg) { + public void refresh(Progress pg) { try { getMetas(pg); } catch (IOException e) { @@ -384,7 +384,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public synchronized List getSources() throws IOException { + public List getSources() throws IOException { List list = new ArrayList(); for (MetaData meta : getMetas(null)) { String storySource = meta.getSource(); @@ -414,8 +414,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public synchronized Map> getSourcesGrouped() - throws IOException { + public Map> getSourcesGrouped() throws IOException { Map> map = new TreeMap>(); for (String source : getSources()) { String name; @@ -450,7 +449,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public synchronized List getAuthors() throws IOException { + public List getAuthors() throws IOException { List list = new ArrayList(); for (MetaData meta : getMetas(null)) { String storyAuthor = meta.getAuthor(); @@ -606,14 +605,14 @@ abstract public class BasicLibrary { * cover image MAY not be included. * * @param luid - * the Library UID of the story + * the Library UID of the story, can be NULL * - * @return the corresponding {@link Story} + * @return the corresponding {@link Story} or NULL if not found * * @throws IOException * in case of IOException */ - public synchronized MetaData getInfo(String luid) throws IOException { + public MetaData getInfo(String luid) throws IOException { if (luid != null) { for (MetaData meta : getMetas(null)) { if (luid.equals(meta.getLuid())) { @@ -668,6 +667,8 @@ abstract public class BasicLibrary { * Retrieve a specific {@link Story}. * * @param luid + * the LUID of the story + * @param meta * the meta of the story * @param pg * the optional progress reporter @@ -677,8 +678,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public synchronized Story getStory(String luid, - @SuppressWarnings("javadoc") MetaData meta, Progress pg) + public synchronized Story getStory(String luid, MetaData meta, Progress pg) throws IOException { if (pg == null) { @@ -693,12 +693,21 @@ abstract public class BasicLibrary { pg.addProgress(pgProcess, 1); Story story = null; - File file = getFile(luid, pgGet); + File file = null; + + if (luid != null && meta != null) { + file = getFile(luid, pgGet); + } + pgGet.done(); try { - SupportType type = SupportType.valueOfAllOkUC(meta.getType()); - URL url = file.toURI().toURL(); - if (type != null) { + if (file != null) { + SupportType type = SupportType.valueOfAllOkUC(meta.getType()); + if (type == null) { + throw new IOException("Unknown type: " + meta.getType()); + } + + URL url = file.toURI().toURL(); story = BasicSupport.getSupport(type, url) // .process(pgProcess); @@ -706,13 +715,9 @@ abstract public class BasicLibrary { meta.setCover(story.getMeta().getCover()); meta.setResume(story.getMeta().getResume()); story.setMeta(meta); - // - } else { - throw new IOException("Unknown type: " + meta.getType()); } } catch (IOException e) { - // We should not have not-supported files in the - // library + // We should not have not-supported files in the library Instance.getInstance().getTraceHandler() .error(new IOException(String.format( "Cannot load file of type '%s' from library: %s", diff --git a/src/be/nikiroo/fanfix/library/CacheLibrary.java b/src/be/nikiroo/fanfix/library/CacheLibrary.java index 56558452..23f19a9e 100644 --- a/src/be/nikiroo/fanfix/library/CacheLibrary.java +++ b/src/be/nikiroo/fanfix/library/CacheLibrary.java @@ -24,6 +24,8 @@ import be.nikiroo.utils.Progress; public class CacheLibrary extends BasicLibrary { private List metasReal; private List metasMixed; + private Object metasLock = new Object(); + private BasicLibrary lib; private LocalLibrary cacheLib; @@ -60,28 +62,28 @@ public class CacheLibrary extends BasicLibrary { } @Override - protected synchronized List getMetas(Progress pg) - throws IOException { - // We make sure that cached metas have precedence - + protected List getMetas(Progress pg) throws IOException { if (pg == null) { pg = new Progress(); } - if (metasMixed == null) { - if (metasReal == null) { - metasReal = lib.getMetas(pg); - } + synchronized (metasLock) { + // We make sure that cached metas have precedence + if (metasMixed == null) { + if (metasReal == null) { + metasReal = lib.getMetas(pg); + } - metasMixed = new ArrayList(); - TreeSet cachedLuids = new TreeSet(); - for (MetaData cachedMeta : cacheLib.getMetas(null)) { - metasMixed.add(cachedMeta); - cachedLuids.add(cachedMeta.getLuid()); - } - for (MetaData realMeta : metasReal) { - if (!cachedLuids.contains(realMeta.getLuid())) { - metasMixed.add(realMeta); + metasMixed = new ArrayList(); + TreeSet cachedLuids = new TreeSet(); + for (MetaData cachedMeta : cacheLib.getMetas(null)) { + metasMixed.add(cachedMeta); + cachedLuids.add(cachedMeta.getLuid()); + } + for (MetaData realMeta : metasReal) { + if (!cachedLuids.contains(realMeta.getLuid())) { + metasMixed.add(realMeta); + } } } } @@ -252,17 +254,19 @@ public class CacheLibrary extends BasicLibrary { // return TRUE = added private boolean updateMetaCache(List metas, MetaData meta) { if (meta != null && metas != null) { - boolean changed = false; - for (int i = 0; i < metas.size(); i++) { - if (metas.get(i).getLuid().equals(meta.getLuid())) { - metas.set(i, meta); - changed = true; + synchronized (metasLock) { + boolean changed = false; + for (int i = 0; i < metas.size(); i++) { + if (metas.get(i).getLuid().equals(meta.getLuid())) { + metas.set(i, meta); + changed = true; + } } - } - if (!changed) { - metas.add(meta); - return true; + if (!changed) { + metas.add(meta); + return true; + } } } @@ -272,8 +276,10 @@ public class CacheLibrary extends BasicLibrary { @Override protected void invalidateInfo(String luid) { if (luid == null) { - metasReal = null; - metasMixed = null; + synchronized (metasLock) { + metasReal = null; + metasMixed = null; + } } else { invalidateInfo(metasReal, luid); invalidateInfo(metasMixed, luid); @@ -286,9 +292,11 @@ public class CacheLibrary extends BasicLibrary { // luid cannot be null private void invalidateInfo(List metas, String luid) { if (metas != null) { - for (int i = 0; i < metas.size(); i++) { - if (metas.get(i).getLuid().equals(luid)) { - metas.remove(i--); + synchronized (metasLock) { + for (int i = 0; i < metas.size(); i++) { + if (metas.get(i).getLuid().equals(luid)) { + metas.remove(i--); + } } } } @@ -318,7 +326,7 @@ public class CacheLibrary extends BasicLibrary { } @Override - public synchronized void delete(String luid) throws IOException { + public void delete(String luid) throws IOException { if (isCached(luid)) { cacheLib.delete(luid); } @@ -383,8 +391,7 @@ public class CacheLibrary extends BasicLibrary { } @Override - public synchronized MetaData imprt(URL url, Progress pg) - throws IOException { + public MetaData imprt(URL url, Progress pg) throws IOException { if (pg == null) { pg = new Progress(); } @@ -397,7 +404,10 @@ public class CacheLibrary extends BasicLibrary { MetaData meta = lib.imprt(url, pgImprt); updateMetaCache(metasReal, meta); - metasMixed = null; + synchronized (metasLock) { + metasMixed = null; + } + clearFromCache(meta.getLuid()); pg.done(); diff --git a/src/be/nikiroo/fanfix/library/LocalLibrary.java b/src/be/nikiroo/fanfix/library/LocalLibrary.java index 0300b9e4..3cf5a25b 100644 --- a/src/be/nikiroo/fanfix/library/LocalLibrary.java +++ b/src/be/nikiroo/fanfix/library/LocalLibrary.java @@ -14,7 +14,6 @@ import java.util.Map; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.bundles.ConfigBundle; -import be.nikiroo.fanfix.bundles.UiConfigBundle; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.output.BasicOutput; @@ -33,6 +32,7 @@ import be.nikiroo.utils.StringUtils; */ public class LocalLibrary extends BasicLibrary { private int lastId; + private Object lock = new Object(); private Map stories; // Files: [ infoFile, TargetFile ] private Map sourceCovers; private Map authorCovers; @@ -102,7 +102,7 @@ public class LocalLibrary extends BasicLibrary { } @Override - protected synchronized List getMetas(Progress pg) { + protected List getMetas(Progress pg) { return new ArrayList(getStories(pg).keySet()); } @@ -115,10 +115,12 @@ public class LocalLibrary extends BasicLibrary { String mess = "no file found for "; MetaData meta = getInfo(luid); - File[] files = getStories(pg).get(meta); - if (files != null) { - mess = "file retrieved for "; - file = files[1]; + if (meta != null) { + File[] files = getStories(pg).get(meta); + if (files != null) { + mess = "file retrieved for "; + file = files[1]; + } } Instance.getInstance().getTraceHandler() @@ -153,20 +155,25 @@ public class LocalLibrary extends BasicLibrary { } @Override - protected synchronized void updateInfo(MetaData meta) { + protected void updateInfo(MetaData meta) { invalidateInfo(); } @Override protected void invalidateInfo(String luid) { - stories = null; - sourceCovers = null; + synchronized (lock) { + stories = null; + sourceCovers = null; + } } @Override - protected synchronized int getNextId() { + protected int getNextId() { getStories(null); // make sure lastId is set - return ++lastId; + + synchronized (lock) { + return ++lastId; + } } @Override @@ -224,14 +231,18 @@ public class LocalLibrary extends BasicLibrary { } @Override - public synchronized Image getCustomSourceCover(String source) { - if (sourceCovers == null) { - sourceCovers = new HashMap(); + public Image getCustomSourceCover(String source) { + synchronized (lock) { + if (sourceCovers == null) { + sourceCovers = new HashMap(); + } } - Image img = sourceCovers.get(source); - if (img != null) { - return img; + synchronized (lock) { + Image img = sourceCovers.get(source); + if (img != null) { + return img; + } } File coverDir = getExpectedDir(source); @@ -242,7 +253,9 @@ public class LocalLibrary extends BasicLibrary { try { in = new FileInputStream(cover); try { - sourceCovers.put(source, new Image(in)); + synchronized (lock) { + sourceCovers.put(source, new Image(in)); + } } finally { in.close(); } @@ -258,18 +271,24 @@ public class LocalLibrary extends BasicLibrary { } } - return sourceCovers.get(source); + synchronized (lock) { + return sourceCovers.get(source); + } } @Override - public synchronized Image getCustomAuthorCover(String author) { - if (authorCovers == null) { - authorCovers = new HashMap(); + public Image getCustomAuthorCover(String author) { + synchronized (lock) { + if (authorCovers == null) { + authorCovers = new HashMap(); + } } - Image img = authorCovers.get(author); - if (img != null) { - return img; + synchronized (lock) { + Image img = authorCovers.get(author); + if (img != null) { + return img; + } } File cover = getAuthorCoverFile(author); @@ -278,7 +297,9 @@ public class LocalLibrary extends BasicLibrary { try { in = new FileInputStream(cover); try { - authorCovers.put(author, new Image(in)); + synchronized (lock) { + authorCovers.put(author, new Image(in)); + } } finally { in.close(); } @@ -293,7 +314,9 @@ public class LocalLibrary extends BasicLibrary { } } - return authorCovers.get(author); + synchronized (lock) { + return authorCovers.get(author); + } } @Override @@ -314,15 +337,17 @@ public class LocalLibrary extends BasicLibrary { * @param coverImage * the cover image */ - synchronized void setSourceCover(String source, Image coverImage) { + void setSourceCover(String source, Image coverImage) { File dir = getExpectedDir(source); dir.mkdirs(); File cover = new File(dir, ".cover"); try { Instance.getInstance().getCache().saveAsImage(coverImage, cover, true); - if (sourceCovers != null) { - sourceCovers.put(source, coverImage); + synchronized (lock) { + if (sourceCovers != null) { + sourceCovers.put(source, coverImage); + } } } catch (IOException e) { Instance.getInstance().getTraceHandler().error(e); @@ -337,14 +362,16 @@ public class LocalLibrary extends BasicLibrary { * @param coverImage * the cover image */ - synchronized void setAuthorCover(String author, Image coverImage) { + void setAuthorCover(String author, Image coverImage) { File cover = getAuthorCoverFile(author); cover.getParentFile().mkdirs(); try { Instance.getInstance().getCache().saveAsImage(coverImage, cover, true); - if (authorCovers != null) { - authorCovers.put(author, coverImage); + synchronized (lock) { + if (authorCovers != null) { + authorCovers.put(author, coverImage); + } } } catch (IOException e) { Instance.getInstance().getTraceHandler().error(e); @@ -602,48 +629,76 @@ public class LocalLibrary extends BasicLibrary { * @return the list of stories (for each item, the first {@link File} is the * info file, the second file is the target {@link File}) */ - private synchronized Map getStories(Progress pg) { + private Map getStories(Progress pg) { if (pg == null) { pg = new Progress(); } else { pg.setMinMax(0, 100); } - if (stories == null) { - stories = new HashMap(); + Map stories = this.stories; + synchronized (lock) { + if (stories == null) { + stories = getStoriesDo(pg); + this.stories = stories; + } + } - lastId = 0; + pg.done(); + return stories; - File[] dirs = baseDir.listFiles(new FileFilter() { - @Override - public boolean accept(File file) { - return file != null && file.isDirectory(); - } - }); + } - if (dirs != null) { - Progress pgDirs = new Progress(0, 100 * dirs.length); - pg.addProgress(pgDirs, 100); + /** + * Actually do the work of {@link LocalLibrary#getStories(Progress)} (i.e., + * do not retrieve the cache). + * + * @param pg + * the optional {@link Progress} + * + * @return the list of stories (for each item, the first {@link File} is the + * info file, the second file is the target {@link File}) + */ + private synchronized Map getStoriesDo(Progress pg) { + if (pg == null) { + pg = new Progress(); + } else { + pg.setMinMax(0, 100); + } - for (File dir : dirs) { - Progress pgFiles = new Progress(); - pgDirs.addProgress(pgFiles, 100); - pgDirs.setName("Loading from: " + dir.getName()); + Map stories = new HashMap(); - addToStories(pgFiles, dir); + File[] dirs = baseDir.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return file != null && file.isDirectory(); + } + }); - pgFiles.setName(null); - } + if (dirs != null) { + Progress pgDirs = new Progress(0, 100 * dirs.length); + pg.addProgress(pgDirs, 100); + + for (File dir : dirs) { + Progress pgFiles = new Progress(); + pgDirs.addProgress(pgFiles, 100); + pgDirs.setName("Loading from: " + dir.getName()); + + addToStories(stories, pgFiles, dir); - pgDirs.setName("Loading directories"); + pgFiles.setName(null); } + + pgDirs.setName("Loading directories"); } pg.done(); + return stories; } - private void addToStories(Progress pgFiles, File dir) { + private void addToStories(Map stories, Progress pgFiles, + File dir) { File[] infoFilesAndSubdirs = dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { @@ -665,7 +720,7 @@ public class LocalLibrary extends BasicLibrary { } if (infoFileOrSubdir.isDirectory()) { - addToStories(null, infoFileOrSubdir); + addToStories(stories, null, infoFileOrSubdir); } else { try { MetaData meta = InfoReader.readMeta(infoFileOrSubdir, diff --git a/src/be/nikiroo/fanfix/library/RemoteLibrary.java b/src/be/nikiroo/fanfix/library/RemoteLibrary.java index 65be7b17..bbe772a8 100644 --- a/src/be/nikiroo/fanfix/library/RemoteLibrary.java +++ b/src/be/nikiroo/fanfix/library/RemoteLibrary.java @@ -426,7 +426,7 @@ public class RemoteLibrary extends BasicLibrary { } @Override - public synchronized File getFile(final String luid, Progress pg) { + public File getFile(final String luid, Progress pg) { throw new java.lang.InternalError( "Operation not supportorted on remote Libraries"); } @@ -449,7 +449,7 @@ public class RemoteLibrary extends BasicLibrary { } @Override - public synchronized MetaData getInfo(String luid) throws IOException { + public MetaData getInfo(String luid) throws IOException { List metas = getMetasList(luid, null); if (!metas.isEmpty()) { return metas.get(0); @@ -459,7 +459,7 @@ public class RemoteLibrary extends BasicLibrary { } @Override - protected synchronized List getMetas(Progress pg) throws IOException { + protected List getMetas(Progress pg) throws IOException { return getMetasList("*", pg); } -- 2.27.0