1. Java / Говнокод #22606

    −12

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    private Map<String, PreparedStatement> statements = new ConcurrentHashMap<>();
    
    public PreparedStatement prepare(String cql) {
    
        cql = cql.toLowerCase();
    
        synchronized (cql.intern()) {
            if (!statements.containsKey(cql)) {
                PreparedStatement statement = session.prepare(cql);
                statements.put(cql, statement);
            }
        }
    
        return statements.get(cql);
    }

    Ручное кеширование com.datastax.driver.core.PreparedStateme nt с синхронизацией на String.intern(). Кажется, годно для публикации!

    Запостил: jericho, 17 Марта 2017

    Комментарии (19) RSS

    • это просто современный модный способ написания "Sleep(Random() % 10)"
      Ответить
      • а разве есть какойто смысл использовать ConcurrentHashMap в синхронизированном контексте или другими словами ConcurrentHashMap уже thread safe и нет смысла его синкать еще раз :)
        Ответить
        • Никакого ConcurrentHashMap локфри
          Ответить
        • от рэйс кондишнов "thread safe" структуры не спасают - у тебя ведь здесь два доступа. хотя в данном контексте максимум что произойдет, это два одинаковых стейтмента будут prepare'd ренундантно - но в мапе в конце все равно будет только один элемент.
          Ответить
          • computeIfAbsent, не?
            Ответить
            • и да, и нет. да - потому что желаемый эффект. нет - потому что залочит мап пока prepare будет исполнятся. в коде сверху, мап незалочен пока prepare исполняется. если препаре тормозной (как он типично в базах) то это очень сильно нежелаемый эффект.

              PS
              https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfAbsent-K-java.util.function.Function-

              но как здесь описывается, то вроде бы чтение из мапа не будет заблокировано - только запись в мап. не совсем желательно - но часто это достаточно.
              Ответить
              • Переделать на computeIfAbsent() здесь ок.

                Исходники у этого метода, канеш, вырви глаз, но мапа полностью не лочится. Здесь как и везде в конкаррент мапе есть а ля бакеты, которые вычисляются для каждой строки cql. То есть в случае коллизий будет лочиться только один бакет.
                Ответить
          • ренундантно

            Шо это за слово такое? :)
            Ответить
        • > нет смысла его синкать еще раз

          А кто сказал, что session.prepare(cql); потокобезопасен?

          Тут смех скорее не в блокировках, а в том, как происходит инвалидация кэша.

          Что происходит с PreparedStatement, когда сессия закрывается?
          Кто удаляет старые записи из кэша?
          Ответить
          • > Кто удаляет старые записи из кэша?

            "Java uses garbage collection, thus there are no memory leak by design. You simply need to install more RAM on your servers."
            Ответить
          • Если ещё подумать, то это должна быть обёртка над session, и кэш должен удаляться при закрытии сессии.
            Ответить
          • > А кто сказал, что session.prepare(cql); потокобезопасен?

            Что-то я и сам затупил. Лок тут используется не для того, чтобы защитить session, и не для того, чтобы защитить мапу.

            Он тут используется для того, чтобы не подготавливать один и тот же запрос дважды.

            Осталось проверить, является ли session потокобезопасным.
            Ответить
            • Session - это из cassandra driver. В доках по кассандре как раз рекомендуется использовать один объект сессии на все приложение. Так что он потокобезопасен.
              Ответить
          • Конкретно здесь никто не удаляет. Уникальных кверей не много. Заботится об инвалидации смысла нет. К тому же приложение регулярно рестартуется.
            Ответить
          • Что происходит с PreparedStatement, когда сессия закрывается?

            Сессия закрывается при остановке приложения. То есть все время жизни приложения PreparedStatement абсолютно валиден.
            Ответить
    • В рот мне ноги. Увидел капчу с буквами - охерел.
      Наконец-то за сайт взялись
      а меня пронесло?
      Ответить

    Добавить комментарий