You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2022/12/03 16:11:55 UTC

svn commit: r1905718 - /pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java

Author: lehmi
Date: Sat Dec  3 16:11:55 2022
New Revision: 1905718

URL: http://svn.apache.org/viewvc?rev=1905718&view=rev
Log:
PDFBOX-5550: share RandomAccessReadBufferedFile when creating a new view within the same thread for the file

Modified:
    pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java

Modified: pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java?rev=1905718&r1=1905717&r2=1905718&view=diff
==============================================================================
--- pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java (original)
+++ pdfbox/trunk/io/src/main/java/org/apache/pdfbox/io/RandomAccessReadBufferedFile.java Sat Dec  3 16:11:55 2022
@@ -21,8 +21,11 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.file.StandardOpenOption;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 /**
  * Provides random access to portions of a file combined with buffered reading of content. Start of next bytes to read
@@ -39,6 +42,8 @@ public class RandomAccessReadBufferedFil
     private static final long PAGE_OFFSET_MASK = -1L << PAGE_SIZE_SHIFT;
     private static final int MAX_CACHED_PAGES = 1000;
 
+    private static ThreadLocal<Map<String, ThreadLocalRandomAccessRead>> randomAccessFiles = new ThreadLocal<Map<String, ThreadLocalRandomAccessRead>>();
+
     private ByteBuffer lastRemovedCachePage = null;
 
     /** Create a LRU page cache. */
@@ -92,6 +97,7 @@ public class RandomAccessReadBufferedFil
         this.file = file;
         fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ);
         fileLength = file.length();
+        randomAccessFiles.set(new ConcurrentHashMap<>(1));
         seek(0);
     }
 
@@ -225,9 +231,19 @@ public class RandomAccessReadBufferedFil
     @Override
     public void close() throws IOException
     {
-        fileChannel.close();
-        pageCache.clear();
-        isClosed = true;
+        Map<String, ThreadLocalRandomAccessRead> map = randomAccessFiles.get();
+        ThreadLocalRandomAccessRead tlRandomAccessRead = map.get(file.toString());
+        if (tlRandomAccessRead != null)
+        {
+            tlRandomAccessRead.removeClosedViews();
+        }
+        if (tlRandomAccessRead == null || tlRandomAccessRead.allViewsClosed())
+        {
+            map.remove(file.toString());
+            fileChannel.close();
+            pageCache.clear();
+            isClosed = true;
+        }
     }
 
     @Override
@@ -258,7 +274,53 @@ public class RandomAccessReadBufferedFil
     public RandomAccessReadView createView(long startPosition, long streamLength) throws IOException
     {
         checkClosed();
-        return new RandomAccessReadView(new RandomAccessReadBufferedFile(file), startPosition,
-                streamLength, true);
+        Map<String, ThreadLocalRandomAccessRead> mapRandomAccessRead = randomAccessFiles.get();
+        ThreadLocalRandomAccessRead tlRandomAccessRead = mapRandomAccessRead.get(file.toString());
+        boolean newlyCreated = false;
+        if (tlRandomAccessRead == null || tlRandomAccessRead.getRandomAccessRead().isClosed())
+        {
+            tlRandomAccessRead = new ThreadLocalRandomAccessRead(
+                    new RandomAccessReadBufferedFile(file));
+            mapRandomAccessRead.put(file.toString(), tlRandomAccessRead);
+            newlyCreated = true;
+        }
+        RandomAccessReadView view = new RandomAccessReadView(
+                tlRandomAccessRead.getRandomAccessRead(), startPosition, streamLength,
+                newlyCreated);
+        tlRandomAccessRead.addRandomAccessView(view);
+        return view;
+    }
+
+    private class ThreadLocalRandomAccessRead
+    {
+        private final RandomAccessReadBufferedFile randomAccessReadBufferedFile;
+        private final HashSet<RandomAccessReadView> randomAccessViews;
+
+        ThreadLocalRandomAccessRead(RandomAccessReadBufferedFile randomAccessRead)
+        {
+            randomAccessReadBufferedFile = randomAccessRead;
+            randomAccessViews = new HashSet<>();
+        }
+
+        public RandomAccessReadBufferedFile getRandomAccessRead()
+        {
+            return randomAccessReadBufferedFile;
+        }
+
+        public boolean addRandomAccessView(RandomAccessReadView randomAccessReadView)
+        {
+            return randomAccessViews.add(randomAccessReadView);
+        }
+
+        public void removeClosedViews()
+        {
+            randomAccessViews.removeAll(randomAccessViews.stream()
+                    .filter(RandomAccessReadView::isClosed).collect(Collectors.toList()));
+        }
+
+        public boolean allViewsClosed()
+        {
+            return randomAccessViews.isEmpty();
+        }
     }
-}
+}
\ No newline at end of file