* cache_reduce_memory * Evict older and less recently used items from the cache in order to * reduce the memory consumption back to something below the * MemoizeState's mem_limit. * * 'specialkey', if not NULL, causes the function to return false if the entry * which the key belongs to is removed from the cache. */
| 408 | * which the key belongs to is removed from the cache. |
| 409 | */ |
| 410 | static bool |
| 411 | cache_reduce_memory(MemoizeState *mstate, MemoizeKey *specialkey) |
| 412 | { |
| 413 | bool specialkey_intact = true; /* for now */ |
| 414 | dlist_mutable_iter iter; |
| 415 | uint64 evictions = 0; |
| 416 | |
| 417 | /* Update peak memory usage */ |
| 418 | if (mstate->mem_used > mstate->stats.mem_peak) |
| 419 | mstate->stats.mem_peak = mstate->mem_used; |
| 420 | |
| 421 | /* We expect only to be called when we've gone over budget on memory */ |
| 422 | Assert(mstate->mem_used > mstate->mem_limit); |
| 423 | |
| 424 | /* Start the eviction process starting at the head of the LRU list. */ |
| 425 | dlist_foreach_modify(iter, &mstate->lru_list) |
| 426 | { |
| 427 | MemoizeKey *key = dlist_container(MemoizeKey, lru_node, iter.cur); |
| 428 | MemoizeEntry *entry; |
| 429 | |
| 430 | /* |
| 431 | * Populate the hash probe slot in preparation for looking up this LRU |
| 432 | * entry. |
| 433 | */ |
| 434 | prepare_probe_slot(mstate, key); |
| 435 | |
| 436 | /* |
| 437 | * Ideally the LRU list pointers would be stored in the entry itself |
| 438 | * rather than in the key. Unfortunately, we can't do that as the |
| 439 | * simplehash.h code may resize the table and allocate new memory for |
| 440 | * entries which would result in those pointers pointing to the old |
| 441 | * buckets. However, it's fine to use the key to store this as that's |
| 442 | * only referenced by a pointer in the entry, which of course follows |
| 443 | * the entry whenever the hash table is resized. Since we only have a |
| 444 | * pointer to the key here, we must perform a hash table lookup to |
| 445 | * find the entry that the key belongs to. |
| 446 | */ |
| 447 | entry = memoize_lookup(mstate->hashtable, NULL); |
| 448 | |
| 449 | /* |
| 450 | * Sanity check that we found the entry belonging to the LRU list |
| 451 | * item. A misbehaving hash or equality function could cause the |
| 452 | * entry not to be found or the wrong entry to be found. |
| 453 | */ |
| 454 | if (unlikely(entry == NULL || entry->key != key)) |
| 455 | elog(ERROR, "could not find memoization table entry"); |
| 456 | |
| 457 | /* |
| 458 | * If we're being called to free memory while the cache is being |
| 459 | * populated with new tuples, then we'd better take some care as we |
| 460 | * could end up freeing the entry which 'specialkey' belongs to. |
| 461 | * Generally callers will pass 'specialkey' as the key for the cache |
| 462 | * entry which is currently being populated, so we must set |
| 463 | * 'specialkey_intact' to false to inform the caller the specialkey |
| 464 | * entry has been removed. |
| 465 | */ |
| 466 | if (key == specialkey) |
| 467 | specialkey_intact = false; |
no test coverage detected