Pull to refresh

Хэш коллизии в кэш-абстракции Spring для методов с несколькими аргументами

Скоро наступит 2013 год, но тем не менее в программировании есть еще люди, полагающиеся на уникальность хэшкода.

Spring Framework сильно удивил стратегией по умолчанию для генерации ключа в своей кэш-абстракции: в случае для метода с несколькими параметрами, в версии фреймворка 3.1 и 3.2 в качестве ключа выбирается общий хэш значений аргументов, аналогичный тому алгоритму, что используется в методе Objects.hash(Object… ) или Arrays.hashСode(Object[]) — в хэш функцию последовательно передаются значения аргументов метода.

К счастью или (несчастью) все это быстро всплыло, т.к. одно только магическое умножение не дает качественного разброса по значениям.

Алгоритм генерации ключа:

public Object generate(Object target, Method method, Object... params) {
		if (params.length == 1) {
			return (params[0] == null ? NULL_PARAM_KEY : params[0]);
		}
		if (params.length == 0) {
			return NO_PARAM_KEY;
		}
		int hashCode = 17;
		for (Object object : params) {
			hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
		}
		return Integer.valueOf(hashCode);
	}


Народ уже столкнулся в продакшене с коллизией

new Integer( 109 ),new Integer( 434)

и
new Integer( 110 ),new Integer( 403)


Так и представляю, как при просмотре счета в какой нибудь распределенной системе типа «интернет-банк» (банки Spring любят) выведутся данные чужого счета.

Неясно, что мешало разработчикам Spring провести конкатенацию аргументов, или лучше документировать вопрос в руководстве. Но судя по примеру
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

можно сделать вывод, что они действительно верят в стратегию с хэшированием.

Хотя, по-моему все же лучшее решение — стараться не использовать несколько первичных ключей вообще.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.