Как может сбиться согласованность оракула с найденным ключевым объектом? - PullRequest
3 голосов
/ 18 февраля 2012

У нас странная проблема. Мы получаем набор ключей из кэша Oracle Coherence, но не можем напрямую получить значения из кэша, даже если на нем нет операций обновления.

Следующий код последовательно завершается с ошибкой (то есть выводит «>>>> NULL», поскольку объект не извлекается). Вопрос: ПОЧЕМУ?

    NamedCache nc = CacheFactory.getCache(cacheName);
    Set<Object> keys = (Set<Object>)nc.keySet();
    for ( Object key : keys ) {
        Object o = nc.get(key);
        if ( o == null ) {
            System.out.println(">>>>NULL:"+keyStr);
        } 
    }

Кеш - это секционированный именованный кеш с несколькими индексами.

Ключ - это объект (не показан) с одной переменной экземпляра, HashMap.

Ключевой объект также имеет методы equals () и hashCode () следующим образом:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((values == null) ? 0 : values.hashCode());
    return result;
}


@Override
public boolean equals(Object obj) {
    System.out.println("EQUALS");
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    AbstractCacheKey other = (AbstractCacheKey) obj;
    if (values == null) {
        if (other.values != null)
            return false;
    } else if (!values.equals(other.values))
        return false;
    return true;
}

Я полагаю, что Coherence использует хеш-код объекта сериализованного ключа в этой конфигурации, что сделает эти два метода неактуальными, за исключением того, что я не знаю, что это верно как для фронтального кэша (локальная JVM, локальное хранилище отключено), так и обратно кеш (узел хранения JVM).

Часть нашего кода частично решает эту проблему, перестраивая ключ, вставляя значения в стандартном порядке. Это обычно работает. Я не понимаю, почему это необходимо, поскольку наш метод hashCode () и hashCode () Java для HashMap, AFAIK, нечувствительны к порядку итерации хеша. Почему это обычно, но не всегда работает - тоже загадка.

1 Ответ

2 голосов
/ 26 февраля 2012

Ответ (спасибо, Дмитрий) заключается в том, что HashMap не гарантирует порядок его сериализации, поэтому serialized-hash -> десериализация -> object-hash -> serialize -> serialized-hash может привести к тому, что второй сериализованный хэш будет потоком байтов, отличным от первого.

Java не дает никаких гарантий относительно упорядочения в хэше, а сериализация зависит от упорядочения. Сериализация может отличаться от одной JVM к другой, и даже внутри одной JVM. Поскольку внутренняя реализация HashMap представляет собой типичный хэш в памяти, с N сегментами, каждый из которых содержит (возможно, через связанный список) набор записей, хэш которых соответствует сегменту, порядок, в котором записи помещаются в хэш, определяет (не указанным способом) порядок, в котором итерация набора ключей будет возвращать их. TreeMap , для сравнения, должен производить согласованное упорядочение и, следовательно, предположительно согласованную сериализацию.

Когерентные секционированные кэши хранят ключи и значения в форме сериализованной , поэтому они вычисляют хэш-функцию в сериализованной версии ключа и выполняют проверки на равенство в сериализованных ключах. Несмотря на то, что сериализованный поток эквивалентен для целей восстановления объекта, он не гарантированно идентичен, что необходимо для операций хеширования и проверки на равенство.

Чтобы еще больше усложнить ситуацию, в ближнем кеше объект хранится в десериализованной форме и, следовательно, вместо него используются методы equals () и hashCode () .

Наконец, Coherence рекомендует использовать их запатентованную сериализацию POF, что обычно приводит к уменьшению сериализованного размера и дает прямой контроль сериализации для сериализуемого объекта.

...