Проблема с инициализацией сериализации в QueryCursor

#ignite

#ignite

Вопрос:

Я совсем новичок в ignite и пытаюсь «заполнить» кеш из EntryProcessor, но не могу просмотреть результаты ScanQuery в приложении

У меня есть кластер ignite версии v2.6.0 с двумя атомарными разделенными кэшами и включенной загрузкой однорангового класса:

 Cache A : IgniteCache<Long, A>
Cache B : IgniteCache<UUID, ScheduledTask>


interface ScheduledTask extends Serializable {
     Instant getExecuteAt()
}

one of classes that are stored in cache B:

class ExpirationTask implements ScheduledTask 
  

Приложение Spring boot (написанное на Kotlin) асинхронно вызывает процессор ввода из кэша A. Процессор заполняет данные в обоих кэшах (A и B). Затем приложение запрашивает кэш B:

  val dueQuery = ScanQuery<UUID, ScheduledTask> { _, task -> task.executeAt <= now }

       bCache.query(dueQuery, { it.key }).use { taskKeys ->
            for (taskKey in taskKeys) {
   ………………………
          }
}
  

Но курсор запроса вызывает ClassCastException:

 Caused by: java.lang.ClassCastException: ExpirationTask cannot be cast to ScheduledTask
    at ….Scheduler$poll$dueQuery$1.apply(Scheduler:61)
    at org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager$ScanQueryIterator.advance(GridCacheQueryManager.java:3089)
    at org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager$ScanQueryIterator.onHasNext(GridCacheQueryManager.java:2982)
    at org.apache.ignite.internal.util.GridCloseableIteratorAdapter.hasNextX(GridCloseableIteratorAdapter.java:53)
    at org.apache.ignite.internal.util.lang.GridIteratorAdapter.hasNext(GridIteratorAdapter.java:45)
    at org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager.runQuery(GridCacheQueryManager.java:1164)
    at org.apache.ignite.internal.processors.cache.query.GridCacheDistributedQueryManager.processQueryRequest(GridCacheDistributedQueryManager.java:230)
    at org.apache.ignite.internal.processors.cache.query.GridCacheDistributedQueryManager$2.apply(GridCacheDistributedQueryManager.java:108)
    at org.apache.ignite.internal.processors.cache.query.GridCacheDistributedQueryManager$2.apply(GridCacheDistributedQueryManager.java:106)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager.processMessage(GridCacheIoManager.java:1054)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager.onMessage0(GridCacheIoManager.java:579)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:378)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:304)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager.access$100(GridCacheIoManager.java:99)
    at org.apache.ignite.internal.processors.cache.GridCacheIoManager$1.onMessage(GridCacheIoManager.java:293)
    at org.apache.ignite.internal.managers.communication.GridIoManager.invokeListener(GridIoManager.java:1556)
    at org.apache.ignite.internal.managers.communication.GridIoManager.processRegularMessage0(GridIoManager.java:1184)
    at org.apache.ignite.internal.managers.communication.GridIoManager.access$4200(GridIoManager.java:125)
    at org.apache.ignite.internal.managers.communication.GridIoManager$9.run(GridIoManager.java:1091)
    ... 3 common frames omitted
  

Оба класса A и B маршалируются OptimizedMarshaller из-за пользовательской сериализации, такой как:

 data class B(val dueTime: Instant, val id: Long) : ScheduledTask {

 override fun getExecuteAt(): Instant {
        return dueTime
    }
    private fun writeObject(stream: ObjectOutputStream) {
        // Only used to indicate custom serialization for Ignite. Real work done by writeReplace()
    }

    private fun readObject(stream: ObjectInputStream) {
        // Only used to indicate custom serialization for Ignite. Real work done by writeReplace()
    }

    private fun writeReplace(): Any = Serializer(this)

    class Serializer @JvmOverloads constructor(var source: B? = null) : Externalizable {
        override fun readExternal(stream: ObjectInput) {
            val dueTime = stream.readObject() as Instant
            val id = stream.readLong()
           source = B(dueTime, id)
        }

        override fun writeExternal(stream: ObjectOutput) {
            stream.writeObject(source!!.dueTime)
            stream.writeLong(source!!.id)
       }

        private fun readResolve(): Any = source!!

        companion object {
            private const val serialVersionUID: Long = 1
        }
    }

    companion object {
        private const val serialVersionUID: Long = 42
    }
}

  

Итак, я ищу способ выполнять полиморфные запросы над значениями кэша.

Спасибо

Ответ №1:

  • Ignite не будет загружать типы ключей / значений кэша однорангового класса, поэтому вам не стоит беспокоиться об этом.
  • Возможно ли, что у вас B загружен разными загрузчиками классов? Вы могли бы отладить это, проверив getClass().getClassLoader() один из B.
  • Может быть, Kotlin ожидает, что в какой-то момент тип B будет обернут?

Комментарии:

1. >> Ignite не будет загружать типы ключей / значений кэша однорангового класса, поэтому вам не стоит беспокоиться о том, что в этом случае, как процессор ввода сможет десериализовать / обновить значения в кэше? >> Может быть, Kotlin ожидает, что в какой-то момент будет завернутый тип B? У нас нет встроенных классов, если я правильно понял ваш вопрос. Если нет — не могли бы вы, пожалуйста, уточнить немного больше?

2. Если вы хотите, чтобы ваши процессоры ввода работали с типами ключей / значений (а не с BinaryObject), вы должны развернуть их на всех узлах, где они хранятся.

3. включена загрузка одноранговых классов настройки сериализации для принудительного использования оптимизированного маршаллера отлично работают для процессоров. Я запускаю его для кэша a, и он также заполняет некоторые данные в кэше B. Проблема возникает, когда я пытаюсь просмотреть результаты ScanQuery в кэше B на узле приложения

4. Пожалуйста, сравните ClassLoader на этом этапе программы и расскажите нам, что происходит. Измените его общий тип на Object и там выведите val.getClassLoader().toString() и B.class.getClassLoader().toString , чтобы посмотреть, что здесь произойдет.

5. В аналогичном сообщении: apache-ignite-users.70518.x6.nabble.com / … люди сводят проблемы с загрузкой классов к spring-devtools, есть ли шанс, что это применимо?