Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 Это как?  [new]
no56892
Member

Откуда:
Сообщений: 587
Периодически падает Xpath.evaluate если звать параллельно. На винде где то 1%, на линуксе 90%. Нашел баг:
https://bugs.openjdk.java.net/browse/JDK-8179941
Решил раскопать, и вот...

К сообщению приложен файл. Размер - 134Kb
1 фев 19, 20:01    [21800114]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
Герой дня
Member

Откуда: obmanula.ru
Сообщений: 30518
no56892,

fParseInProgress - статическая? если статическая, то парсер однопоточный. Иначе непонятно, как может падать.
1 фев 19, 20:47    [21800149]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
no56892
Member

Откуда:
Сообщений: 587
Герой дня,

protected boolean fParseInProgress = false;

Тогда и вопроса то не было.
Однопоточный? То есть во всем приложении вообще любое выполнение Xpath надо в синхронайзд помещать?

Там по ссылке вполне резонный пример:
import java.io.StringReader;

import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.xml.sax.InputSource;

public class XPathTest {

    // This field is set to true as soon as one thread encounters an exception. When this happens, both threads will terminate.
    private static volatile boolean exception;

    private static Object lock = new Object();

    public static void main(String[] args) {
        Thread thread1 = createThread();
        Thread thread2 = createThread();
        thread1.start();
        thread2.start();
        try {
            // wait at most two minutes
            thread1.join(60000);
            thread2.join(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static Thread createThread() {
        String xml = "<test/>";
        return new Thread(new Runnable() {
            @Override
            public void run() {
                while (!exception) {
                    try {
                        XPathFactory xPathFactory;
                        // Synchronize both threads, as XPathFactory.newInstance() is not thread-safe.
                        synchronized (lock) {
                            xPathFactory = XPathFactory.newInstance();
                        }
                        xPathFactory.newXPath().compile("/test").evaluate(new InputSource(new StringReader(xml)));
                    } catch (XPathExpressionException e) {
                        e.printStackTrace();
                        exception = true;
                    }
                }
            }
        });

    }
}
1 фев 19, 20:53    [21800153]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
mayton
Member

Откуда: loopback
Сообщений: 39873
no56892,

Вот ты чудак. Да 99% алгоритмов пр своей природе - одно поточные.

Если ты хочешь долбить экземпляр алгоритма из двух и более потоков - создай из фабрики 2 и более экземпляра нужного алгоритма.
1 фев 19, 21:16    [21800169]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
no56892
Member

Откуда:
Сообщений: 587
mayton,
Не понял мысли, что за алгоритмы (а) и где они долбятся (б) из нескольких потоков?
1 фев 19, 21:18    [21800171]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
no56892
Member

Откуда:
Сообщений: 587
no56892,
Такой баг даже есть https://issues.apache.org/jira/browse/XALANJ-2463?attachmentOrder=desc, но похоже на него тупо забили, 10 лет прошло.
Проблема оказалась в классе XPathExpressionImpl, там есть 3 статик ансейф поля:

static DocumentBuilderFactory dbf = null;
    static DocumentBuilder db = null;
    static Document d = null;

и далее по тексту:

if ( dbf == null ) {
                dbf = FactoryImpl.getDOMFactory(useServicesMechanism);
                dbf.setNamespaceAware( true );
                dbf.setValidating( false );
            }
            db = dbf.newDocumentBuilder();
            Document document = db.parse( source );

На скриншоте в первом посте, собственно и парсится этим db, одним единственным, то есть флаг был тру, зашел первый поток, затем второй закончил парсить поставил флаг фалс, и тут я поймал в дебаге.
То есть это делает невозможным какое-то вменяемое использование "штатного" Xpath в принципе. Единственно, что заработает ок это:
synchronized (GLOBAL_LOCK) {
     XPathFactory.newInstance().newXPath().compile("/test").evaluate(new InputSource(new StringReader(xml)));
}

И это вообще для каждого, даже не связанного между собой выражения ВО ВСЕМ ПРИЛОЖЕНИИ (в пределах класслоудера правда, но в большинстве случаев он и есть один на все приложение), и никакой строчки из синхронайзд отсюда нельзя выкинуть, ни фабрику закешировать, не уж тем более скомпилированное выражение xpath, ничего!

Здорово, правда?
2 фев 19, 00:38    [21800250]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
no56892
Member

Откуда:
Сообщений: 587
no56892,
Нашел там еще метод есть один, может авторы посчитали что компилировать выражение это дешево? Надо проверить будет, вообщем вот так тоже прокатит:
XPath xPath = null;
     synchronized (GLOBAL_LOCK) {
         xPath = XPathFactory.newInstance().newXPath();
     }
xPath.evaluate("/test", new InputSource(new StringReader(xml)));

И может даже можно newXPath вынести, надо будет детально посмотреть что он там передает при создании. Но все равно я оч сильно удивлен, что в джаве любое скопилированное икспас выражение нужно вставлять в глобал лок.
2 фев 19, 01:07    [21800261]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
mayton
Member

Откуда: loopback
Сообщений: 39873
Хм... Мдя.

Интересно узнать следуюшую инфу. Баг создан на восьмерку и девятку. Сейчас транковая HEAD версия это 11.
Воспроизводится ли дефект в ней?

По каментам. Какой-то особой активности по ней нету. Приоритет выставили в "P4". (Что за хрень? Непоня...)
Fix versions - to be discussed.

Похоже никого особо не парит.

Сама библиотечка com.sun.org.apache.xerces где лежат эти исходники производит хреновенькое впречатление.
По коду Sonar ругается много.

Есть предположение что fParseInProgress это след некой нативной оптимизации где что-то лежало не в Java
а в сях и потом так и осталось.

По исходникам на OpenJDK по ветке Xerces никаких за год не было изменений чтоб фиксили именно механизмы
XPath. Если судить по текстовым каментам Git.
2 фев 19, 02:27    [21800273]     Ответить | Цитировать Сообщить модератору
 Re: Это как?  [new]
lleming
Member

Откуда:
Сообщений: 1555
можно попробовать сделать threadlocal и для каждого потока отдельный экземпляр (через classloader сделать "независимые") парсера.

Грязно конешно но как воркараунд если уперлись во чтото, то можно, ну или воспользоваться другим парсером
4 фев 19, 11:05    [21801098]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить