This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new 9f9b452634 TIKA-4954: speed up parser loading and pipes fork startup: 
build pars… (#3297)
9f9b452634 is described below

commit 9f9b452634bac9d0e04f78b8c113cd69aee13603
Author: Tim Allison <[email protected]>
AuthorDate: Wed Oct 7 15:01:12 2026 -0400

    TIKA-4954: speed up parser loading and pipes fork startup: build pars… 
(#3297)
    
    * TIKA-4954: speed up parser loading and pipes fork startup: build parsers' 
default EncodingDetector lazily, recognize a failed fork start within 100ms
    
    * TIKA-4954: DBFParser honors the configured EncodingDetector
    
    ---------
    
    Co-authored-by: Tilman Hausherr <[email protected]>
---
 CHANGES.txt                                           |  8 ++++++++
 .../tika/parser/AbstractEncodingDetectorParser.java   | 16 +++++++++++++---
 .../apache/tika/config/TikaEncodingDetectorTest.java  |  6 +++---
 .../java/org/apache/tika/parser/dbf/DBFParser.java    | 19 +++++++++++--------
 .../org/apache/tika/parser/dbf/DBFParserTest.java     | 17 +++++++++++++++++
 .../tika/pipes/core/PerClientServerManager.java       |  4 ++--
 6 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index dc63817378..a8d1fcbf40 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -88,6 +88,14 @@ Release 4.2.0 - unreleased
      exit, and the ilst length no longer counts its own header twice. Since
      4.0.0 (TIKA-4957).
 
+   * Faster parser loading and pipes fork startup: parsers no longer build a
+     default EncodingDetector (loading the charset models) only to have the
+     loader replace it, saving about 1.3s per AutoDetectParser build and per
+     forked JVM; a fork that fails to start is recognized within 100ms instead
+     of 1s (TIKA-4954).
+     DBFParser now honors the configured EncodingDetector instead of always
+     building its own default (TIKA-4954).
+
    * tika-core's OSGi manifest no longer requires a Service Loader Mediator or
      providers for Parser, Detector, EncodingDetector, LanguageDetector and
      MetadataFilter; 4.1.0 failed to install on its own in Equinox/p2
diff --git 
a/tika-core/src/main/java/org/apache/tika/parser/AbstractEncodingDetectorParser.java
 
b/tika-core/src/main/java/org/apache/tika/parser/AbstractEncodingDetectorParser.java
index db104a4b2b..fcf70dbe4c 100644
--- 
a/tika-core/src/main/java/org/apache/tika/parser/AbstractEncodingDetectorParser.java
+++ 
b/tika-core/src/main/java/org/apache/tika/parser/AbstractEncodingDetectorParser.java
@@ -27,10 +27,10 @@ import org.apache.tika.detect.EncodingDetector;
 public abstract class AbstractEncodingDetectorParser implements Parser {
 
 
-    private EncodingDetector encodingDetector;
+    // lazy: loaders replace it with the shared detector, and building one 
loads the models
+    private volatile EncodingDetector encodingDetector;
 
     public AbstractEncodingDetectorParser() {
-        encodingDetector = new DefaultEncodingDetector();
     }
 
     public AbstractEncodingDetectorParser(EncodingDetector encodingDetector) {
@@ -55,7 +55,17 @@ public abstract class AbstractEncodingDetectorParser 
implements Parser {
     }
 
     public EncodingDetector getEncodingDetector() {
-        return encodingDetector;
+        EncodingDetector detector = encodingDetector;
+        if (detector == null) {
+            synchronized (this) {
+                detector = encodingDetector;
+                if (detector == null) {
+                    detector = new DefaultEncodingDetector();
+                    encodingDetector = detector;
+                }
+            }
+        }
+        return detector;
     }
 
     public void setEncodingDetector(EncodingDetector encodingDetector) {
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/TikaEncodingDetectorTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/TikaEncodingDetectorTest.java
index fdbe71d0be..84828bb3d6 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/TikaEncodingDetectorTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/TikaEncodingDetectorTest.java
@@ -147,7 +147,7 @@ public class TikaEncodingDetectorTest extends TikaTest {
         List<Parser> parsers = new ArrayList<>();
         findEncodingDetectionParsers(p, parsers);
 
-        assertEquals(8, parsers.size());
+        assertEquals(9, parsers.size());
         EncodingDetector encodingDetector =
                 ((AbstractEncodingDetectorParser) 
parsers.get(0)).getEncodingDetector();
         assertTrue(encodingDetector instanceof CompositeEncodingDetector);
@@ -177,7 +177,7 @@ public class TikaEncodingDetectorTest extends TikaTest {
         List<Parser> parsers = new ArrayList<>();
         findEncodingDetectionParsers(p, parsers);
 
-        assertEquals(9, parsers.size());
+        assertEquals(10, parsers.size());
 
         for (Parser encodingDetectingParser : parsers) {
             EncodingDetector encodingDetector =
@@ -203,7 +203,7 @@ public class TikaEncodingDetectorTest extends TikaTest {
         List<Parser> parsers = new ArrayList<>();
         findEncodingDetectionParsers(p, parsers);
 
-        assertEquals(8, parsers.size());
+        assertEquals(9, parsers.size());
         for (Parser childParser : parsers) {
             EncodingDetector encodingDetector =
                     ((AbstractEncodingDetectorParser) 
childParser).getEncodingDetector();
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/dbf/DBFParser.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/dbf/DBFParser.java
index 0be11be78c..7389ccb795 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/dbf/DBFParser.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/dbf/DBFParser.java
@@ -31,7 +31,6 @@ import org.xml.sax.SAXException;
 
 import org.apache.tika.annotation.TikaComponent;
 import org.apache.tika.detect.CharsetSupersets;
-import org.apache.tika.detect.DefaultEncodingDetector;
 import org.apache.tika.detect.EncodingDetector;
 import org.apache.tika.detect.EncodingResult;
 import org.apache.tika.exception.TikaException;
@@ -40,8 +39,8 @@ import org.apache.tika.metadata.HttpHeaders;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.mime.MediaType;
+import org.apache.tika.parser.AbstractEncodingDetectorParser;
 import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.Parser;
 import org.apache.tika.sax.XHTMLContentHandler;
 
 /**
@@ -53,16 +52,23 @@ import org.apache.tika.sax.XHTMLContentHandler;
  * on the "character" cells.
  */
 @TikaComponent
-public class DBFParser implements Parser {
+public class DBFParser extends AbstractEncodingDetectorParser {
 
     private static final int ROWS_TO_BUFFER_FOR_CHARSET_DETECTION = 10;
     private static final int MAX_CHARS_FOR_CHARSET_DETECTION = 20000;
     private static final Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
-    private static final EncodingDetector DEFAULT_ENCODING_DETECTOR = new 
DefaultEncodingDetector();
 
     private static final Set<MediaType> SUPPORTED_TYPES =
             Collections.singleton(MediaType.application("x-dbf"));
 
+    public DBFParser() {
+        super();
+    }
+
+    public DBFParser(EncodingDetector encodingDetector) {
+        super(encodingDetector);
+    }
+
     @Override
     public Set<MediaType> getSupportedTypes(ParseContext context) {
         return SUPPORTED_TYPES;
@@ -142,10 +148,7 @@ public class DBFParser implements Parser {
         }
         byte[] bytes = bos.toByteArray();
         if (bytes.length > 20) {
-            EncodingDetector detector = 
parseContext.get(EncodingDetector.class);
-            if (detector == null) {
-                detector = DEFAULT_ENCODING_DETECTOR;
-            }
+            EncodingDetector detector = getEncodingDetector(parseContext);
             try (TikaInputStream tis = TikaInputStream.get(bytes)) {
                 List<EncodingResult> results =
                         detector.detect(tis, new Metadata(), parseContext);
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/dbf/DBFParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/dbf/DBFParserTest.java
index 772833cca7..cdf65e6005 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/dbf/DBFParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/dbf/DBFParserTest.java
@@ -21,16 +21,20 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Test;
 
 import org.apache.tika.TikaTest;
+import org.apache.tika.detect.EncodingDetector;
+import org.apache.tika.detect.OverrideEncodingDetector;
 import org.apache.tika.exception.TikaException;
 import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.HttpHeaders;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
 
 public class DBFParserTest extends TikaTest {
@@ -61,6 +65,19 @@ public class DBFParserTest extends TikaTest {
         assertContains("<td>licour</td>", xml);
     }
 
+    @Test
+    public void testConfiguredEncodingDetector() throws Exception {
+        Parser p = new DBFParser(new 
OverrideEncodingDetector(StandardCharsets.ISO_8859_1));
+        XMLResult r = getXML("testDBF.dbf", p, new Metadata());
+        assertEquals("ISO-8859-1", 
r.metadata.get(HttpHeaders.CONTENT_ENCODING));
+
+        ParseContext context = new ParseContext();
+        context.set(EncodingDetector.class,
+                new OverrideEncodingDetector(StandardCharsets.UTF_16LE));
+        r = getXML("testDBF.dbf", p, new Metadata(), context);
+        assertEquals("UTF-16LE", r.metadata.get(HttpHeaders.CONTENT_ENCODING));
+    }
+
     @Test
     public void testGB18030Encoded() throws Exception {
         XMLResult r = getXML("testDBF_gb18030.dbf");
diff --git 
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PerClientServerManager.java
 
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PerClientServerManager.java
index 59390013f4..f6a7b17a45 100644
--- 
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PerClientServerManager.java
+++ 
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PerClientServerManager.java
@@ -414,8 +414,8 @@ public class PerClientServerManager implements 
ServerManager {
             throw new IllegalStateException("Server not started. Call 
ensureRunning() first.");
         }
 
-        // Accept incoming connection from the server process
-        ss.setSoTimeout(1000); // 1 second timeout for each poll
+        // Accept the server's connection; poll briefly so a child that dies 
first is noticed fast
+        ss.setSoTimeout(100);
         long startTime = System.currentTimeMillis();
 
         while (true) {

Reply via email to