| 196 | |
| 197 | template <typename Cache> |
| 198 | static void test_cache_erase_parallel(size_t megabytes) |
| 199 | { |
| 200 | double load = 1; |
| 201 | local_rand_ctx = FastRandomContext(true); |
| 202 | std::vector<uint256> hashes; |
| 203 | Cache set{}; |
| 204 | size_t bytes = megabytes * (1 << 20); |
| 205 | set.setup_bytes(bytes); |
| 206 | uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256))); |
| 207 | hashes.resize(n_insert); |
| 208 | for (uint32_t i = 0; i < n_insert; ++i) { |
| 209 | uint32_t* ptr = (uint32_t*)hashes[i].begin(); |
| 210 | for (uint8_t j = 0; j < 8; ++j) |
| 211 | *(ptr++) = local_rand_ctx.rand32(); |
| 212 | } |
| 213 | /** We make a copy of the hashes because future optimizations of the |
| 214 | * cuckoocache may overwrite the inserted element, so the test is |
| 215 | * "future proofed". |
| 216 | */ |
| 217 | std::vector<uint256> hashes_insert_copy = hashes; |
| 218 | boost::shared_mutex mtx; |
| 219 | |
| 220 | { |
| 221 | /** Grab lock to make sure we release inserts */ |
| 222 | boost::unique_lock<boost::shared_mutex> l(mtx); |
| 223 | /** Insert the first half */ |
| 224 | for (uint32_t i = 0; i < (n_insert / 2); ++i) |
| 225 | set.insert(hashes_insert_copy[i]); |
| 226 | } |
| 227 | |
| 228 | /** Spin up 3 threads to run contains with erase. |
| 229 | */ |
| 230 | std::vector<std::thread> threads; |
| 231 | /** Erase the first quarter */ |
| 232 | for (uint32_t x = 0; x < 3; ++x) |
| 233 | /** Each thread is emplaced with x copy-by-value |
| 234 | */ |
| 235 | threads.emplace_back([&, x] { |
| 236 | boost::shared_lock<boost::shared_mutex> l(mtx); |
| 237 | size_t ntodo = (n_insert/4)/3; |
| 238 | size_t start = ntodo*x; |
| 239 | size_t end = ntodo*(x+1); |
| 240 | for (uint32_t i = start; i < end; ++i) |
| 241 | set.contains(hashes[i], true); |
| 242 | }); |
| 243 | |
| 244 | /** Wait for all threads to finish |
| 245 | */ |
| 246 | for (std::thread& t : threads) |
| 247 | t.join(); |
| 248 | /** Grab lock to make sure we observe erases */ |
| 249 | boost::unique_lock<boost::shared_mutex> l(mtx); |
| 250 | /** Insert the second half */ |
| 251 | for (uint32_t i = (n_insert / 2); i < n_insert; ++i) |
| 252 | set.insert(hashes_insert_copy[i]); |
| 253 | |
| 254 | /** elements that we marked erased but that are still there */ |
| 255 | size_t count_erased_but_contained = 0; |
nothing calls this directly
no test coverage detected