| 41 | } |
| 42 | |
| 43 | void HashRing::AddNode(const IpAddr& node, std::string_view scheduling_seed_in) { |
| 44 | // This node should not already be in the set. |
| 45 | std::pair<NodeIterator, bool> node_pair = nodes_.insert(node); |
| 46 | // 'second' tells whether a new element was inserted. It must be true. |
| 47 | DCHECK(node_pair.second) << "Failed to add: " << node; |
| 48 | NodeIterator node_it = node_pair.first; |
| 49 | // If the scheduling seed argument is empty, use the IP address |
| 50 | std::string_view scheduling_seed = scheduling_seed_in; |
| 51 | if (scheduling_seed.empty()) scheduling_seed = node; |
| 52 | uint32_t hash = HashUtil::Hash(scheduling_seed.data(), scheduling_seed.length(), 0); |
| 53 | // Generate multiple hashes for the node by using the hash as a seed to a PRNG. |
| 54 | pcg32 prng(hash); |
| 55 | for (uint32_t i = 0; i < num_replicas_; i++) { |
| 56 | uint32_t hash_val = prng(); |
| 57 | // Check for hash collision |
| 58 | auto hashmap_it = hash_to_node_.find(hash_val); |
| 59 | // Write this new value if: |
| 60 | // 1. There is no hash collision. |
| 61 | // -OR- |
| 62 | // 2. There is a hash collision, but the underlying IpAddr is less than |
| 63 | // the current value. |
| 64 | // This guarantees consistency regardless of the order of adds and removes. |
| 65 | if (hashmap_it == hash_to_node_.end() || *node_it < *hashmap_it->second) { |
| 66 | hash_to_node_[hash_val] = node_it; |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | void HashRing::RemoveNode(const IpAddr& node) { |
| 72 | // This node must be in the set. Keep the iterator to erase it later. |