| 234 | } |
| 235 | |
| 236 | int SocketMap::Insert(const SocketMapKey& key, SocketId* id, |
| 237 | SocketOptions& opt) { |
| 238 | ShowSocketMapInBvarIfNeed(); |
| 239 | |
| 240 | std::unique_lock<butil::Mutex> mu(_mutex); |
| 241 | SingleConnection* sc = _map.seek(key); |
| 242 | if (sc) { |
| 243 | if (!sc->socket->Failed() || sc->socket->HCEnabled()) { |
| 244 | ++sc->ref_count; |
| 245 | *id = sc->socket->id(); |
| 246 | return 0; |
| 247 | } |
| 248 | // A socket w/o HC is failed (permanently), replace it. |
| 249 | ReleaseReference(sc->socket); |
| 250 | _map.erase(key); // in principle, we can override the entry in map w/o |
| 251 | // removing and inserting it again. But this would make error branches |
| 252 | // below have to remove the entry before returning, which is |
| 253 | // error-prone. We prefer code maintainability here. |
| 254 | sc = NULL; |
| 255 | } |
| 256 | SocketId tmp_id; |
| 257 | opt.remote_side = key.peer.addr; |
| 258 | if (_options.socket_creator->CreateSocket(opt, &tmp_id) != 0) { |
| 259 | PLOG(FATAL) << "Fail to create socket to " << key.peer; |
| 260 | return -1; |
| 261 | } |
| 262 | // Add a reference to make sure that sc->socket is always accessible. Not |
| 263 | // use SocketUniquePtr which cannot put into containers before c++11. |
| 264 | // The ref will be removed at entry's removal. |
| 265 | SocketUniquePtr ptr; |
| 266 | int rc = Socket::AddressFailedAsWell(tmp_id, &ptr); |
| 267 | if (rc < 0) { |
| 268 | LOG(FATAL) << "Fail to address SocketId=" << tmp_id; |
| 269 | return -1; |
| 270 | } else if (rc > 0 && !ptr->HCEnabled()) { |
| 271 | LOG(FATAL) << "Failed socket is not HC-enabled"; |
| 272 | return -1; |
| 273 | } |
| 274 | // If health check is enabled, a health-checking-related reference |
| 275 | // is hold in Socket::Create. |
| 276 | // If health check is disabled, hold a reference in SocketMap. |
| 277 | SingleConnection new_sc = { 1, ptr->HCEnabled() ? ptr.get() : ptr.release(), 0 }; |
| 278 | _map[key] = new_sc; |
| 279 | *id = tmp_id; |
| 280 | mu.unlock(); |
| 281 | return 0; |
| 282 | } |
| 283 | |
| 284 | void SocketMap::Remove(const SocketMapKey& key, SocketId expected_id) { |
| 285 | return RemoveInternal(key, expected_id, false); |