in cpp/src/hnswalg.h [1197:1268]
void repairConnectionsForUpdate(const data_t *dataPoint,
tableint entryPointInternalId,
tableint dataPointInternalId,
int dataPointLevel, int maxLevel) {
tableint currObj = entryPointInternalId;
if (dataPointLevel < maxLevel) {
dist_t curdist = fstdistfunc_(dataPoint, getDataByInternalId(currObj),
dist_func_param_);
for (int level = maxLevel; level > dataPointLevel; level--) {
bool changed = true;
while (changed) {
changed = false;
unsigned int *data;
std::unique_lock<std::mutex> lock(link_list_locks_[currObj]);
data = get_linklist_at_level(currObj, level);
int size = getListCount(data);
tableint *datal = (tableint *)(data + 1);
for (int i = 0; i < size; i++) {
tableint cand = datal[i];
dist_t d = fstdistfunc_(dataPoint, getDataByInternalId(cand),
dist_func_param_);
if (d < curdist) {
curdist = d;
currObj = cand;
changed = true;
}
}
}
}
}
if (dataPointLevel > maxLevel)
throw std::runtime_error(
"Level of item to be updated cannot be bigger than max level");
for (int level = dataPointLevel; level >= 0; level--) {
std::priority_queue<std::pair<dist_t, tableint>,
std::vector<std::pair<dist_t, tableint>>,
CompareByFirst>
topCandidates = searchBaseLayer(currObj, dataPoint, level);
std::priority_queue<std::pair<dist_t, tableint>,
std::vector<std::pair<dist_t, tableint>>,
CompareByFirst>
filteredTopCandidates;
while (topCandidates.size() > 0) {
if (topCandidates.top().second != dataPointInternalId)
filteredTopCandidates.push(topCandidates.top());
topCandidates.pop();
}
// Since element_levels_ is being used to get `dataPointLevel`, there
// could be cases where `topCandidates` could just contains entry point
// itself. To prevent self loops, the `topCandidates` is filtered and thus
// can be empty.
if (filteredTopCandidates.size() > 0) {
bool epDeleted = isMarkedDeleted(entryPointInternalId);
if (epDeleted) {
filteredTopCandidates.emplace(
fstdistfunc_(dataPoint, getDataByInternalId(entryPointInternalId),
dist_func_param_),
entryPointInternalId);
if (filteredTopCandidates.size() > ef_construction_)
filteredTopCandidates.pop();
}
currObj = mutuallyConnectNewElement(dataPoint, dataPointInternalId,
filteredTopCandidates, level, true);
}
}
}