drBatty писал(а): ↑28.05.2012 13:36
может таки вам научится понимать прочитанное
Понимаете ли, я приводил Вам цитаты, которые подтверждают мою точку зрения. Эти цитаты можно найти в статье и в исходниках. Теперь Ваша очередь. Приведите мне цитату, которая подтверждает Ваши слова о расчете метрики указанным Вами способом и особенно про Хэмминга.
drBatty писал(а): ↑28.05.2012 13:36
ну и как-же можно "сравнить префикс"?
Итак, приведу алгоритм, описанный в статье и реализованный в aMule.
Определения.
k-bucket — список длиной ≤ k, хранит {IP, Port, ID} узлов.
N — число узлов в сети.
Prefix(ID1, ID2) = длина общего префикса ID1 и ID2.
Distance(ID1, ID2) = ID1^ID2.
Состояние узла.
1. Каждый узел имеет ID. ID нашего узла обозначим
OurID.
2. Узел хранит динамический массив k-bucket'ов, B. Длина Blen массива меняется с течением времени. k-bucket'ы B[i] для i < Blen-1 хранят узлы с ID: Prefix(ID, OurID) = i. B[Blen-1] хранит узлы с ID: Prefix(ID, OurID) ≥ Blen-1.
Обновление массива B.
Массив обновляется не только при получении информации о новом узле, но и при практически любой успешной коммуникации с некоторым узлом.
0. Исходное состояние — один k-bucket, содержащий единственный «затравочный» узел.
1. Допустим, мы получаем информацию об узле {NewIP, NewPort, NewID}.
2. Plen = Prefix(NewID, OurID).
3. Если Plen ≥ Blen-1, то Plen=Blen-1, goto our-0, иначе goto update-0.
update-0. Если B[Plen] содержит меньше, чем k элементов, добавляем новый узел в конец k-bucket'а, return.
Иначе (если B[Plen] полностью заполнен):
update-1. Если NewID уже содержится в k-bucket'е, перемещаем его в конец. return.
Иначе (B[Plen] не содержит NewID):
update-2. Посылаем PING узлу B[Plen][0].
update-3. Если B[Plen][0] не ответил, выкидываем его, помещаем новый узел в конец k-bucket'а, return.
update-4. Если B[Plen][0] ответил, перемещаем его в конец k-bucket'а, новый узел выбрасываем, return.
our-0. Если B[Plen] содержит меньше, чем k элементов, добавляем новый узел в конец k-bucket'а, return.
Иначе (если B[Plen] полностью заполнен):
our-1. Если NewID уже содержится в k-bucket'е, перемещаем его в конец. return.
Иначе (B[Plen] не содержит NewID):
our-2. Посылаем PING узлу B[Plen][0].
our-3. Если B[Plen][0] не ответил, выкидываем его, помещаем новый узел в конец k-bucket'а, return.
our-4. Если B[Plen][0] ответил, добавляем новый k-bucket B[Blen], и раскладываем элементы, включая новый узел, по B[Blen-1] и B[Blen] в соответствии с их префиксами. return.
Таким образом, очевидно, что в пределе Blen ~ O(log_2 N). По построению ясно, что bucket'ы из B полностью и без пересечений покрывают всё пространство ключей.
RPC-вызов FIND_VALUE(ID).
0. Если наша нода хранит объект с заданным ID, возвращаем его.
1. Plen = Prefix(ID, OurID).
2. Если Plen ≥ Blen-1, то Plen = Blen-1.
3. Результат = B[Plen]. Если набралось меньше k, дополняем результат узлами из B[i], где Plen < i ≤ Blen-1, по возрастанию. Если набралось меньше k, дополняем узлами из B[i], где 0 ≤ i < Plen, по убыванию. Возвращаем результат, даже если его длина < k.
Поиск объекта с ключом ID.
0. Делаем локальный вызов FIND_VALUE(ID). Если объект найден, return. Если нет, инициализируем массив C возвращенным списком узлов. Сортируем C по Distance(C[i], ID).
1. Вызываем FIND_VALUE(ID) на alpha ближайших к ID узлах из C. Параллельно.
2. Если вызов FIND_VALUE вернул значение, return.
3. Если вызов FIND_VALUE вернул список узлов, объединяем этот список с C (сортируем по Distance(C[i], ID), оставляем k элементов с наименьшей метрикой).
4. Вызываем FIND_VALUE у ближайшего к ID узла из C, который еще не опрашивали. Goto 2. Если же таких узлов не осталось, возвращаем «не найдено».
По построению массива B очевидно, что для узлов из B[Plen], для Plen < Blen-1, выполняется Prefix(B[Plen][i], ID) = Plen+1 и, рассуждая аналогично, они возвращают узлы, которые имеют общий префикс Plen+2. Т.е. длина общего префикса увеличивается на 1 на каждом шаге. Т.е. число вызовов RPC для поиска ~ O(log_2 N).
Вопросы и задания.
0. Всё ли правильно?
1. Где здесь подсчет числа единичных битов?
2. Где здесь расстояние Хэмминга?
3. В принципе, для каждого B[i] можно установить диапазон IDmin, IDmax ключей, которые попадают в этот bucket и искать нужный bucket обчными сравнениями. Где здесь маски и <<, >>?