| 219 | |
| 220 | |
| 221 | bool ConcurrentMap::remove(slice key, hash_t hash) { |
| 222 | assert_precondition(key); |
| 223 | int i = indexOfHash(hash); |
| 224 | while (true) { |
| 225 | retry: |
| 226 | Entry current = _entries[i]; |
| 227 | switch (current.keyOffset) { |
| 228 | case kEmptyKeyOffset: |
| 229 | // Not found. |
| 230 | return false; |
| 231 | case kDeletedKeyOffset: |
| 232 | break; |
| 233 | default: |
| 234 | if (auto keyPtr = offsetToKey(current.keyOffset); equalKeys(keyPtr, key)) { |
| 235 | // Found it -- now replace with a tombstone. Leave the value alone in case |
| 236 | // a concurrent torn read sees the prior offset + new value. |
| 237 | Entry tombstone = {kDeletedKeyOffset, current.value}; |
| 238 | if (_usuallyFalse(!_entries[i].compareAndSwap(current, tombstone))) { |
| 239 | // I was beaten to it; retry (at the same index, |
| 240 | // in case CAS was a false negative) |
| 241 | goto retry; |
| 242 | } |
| 243 | // Success! |
| 244 | --_count; |
| 245 | // Freeing the key string will only do anything if it was the latest key |
| 246 | // to be added, but it's worth a try. |
| 247 | (void)freeKey(keyPtr); |
| 248 | return true; |
| 249 | } |
| 250 | break; |
| 251 | } |
| 252 | i = wrap(i + 1); |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | |
| 257 | const char* ConcurrentMap::allocKey(slice key) { |
nothing calls this directly
no test coverage detected