lru_cache.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/lru_cache.h>
  6. static int s_lru_cache_put(struct aws_cache *cache, const void *key, void *p_value);
  7. static int s_lru_cache_find(struct aws_cache *cache, const void *key, void **p_value);
  8. static void *s_lru_cache_use_lru_element(struct aws_cache *cache);
  9. static void *s_lru_cache_get_mru_element(const struct aws_cache *cache);
  10. struct lru_cache_impl_vtable {
  11. void *(*use_lru_element)(struct aws_cache *cache);
  12. void *(*get_mru_element)(const struct aws_cache *cache);
  13. };
  14. static struct aws_cache_vtable s_lru_cache_vtable = {
  15. .destroy = aws_cache_base_default_destroy,
  16. .find = s_lru_cache_find,
  17. .put = s_lru_cache_put,
  18. .remove = aws_cache_base_default_remove,
  19. .clear = aws_cache_base_default_clear,
  20. .get_element_count = aws_cache_base_default_get_element_count,
  21. };
  22. struct aws_cache *aws_cache_new_lru(
  23. struct aws_allocator *allocator,
  24. aws_hash_fn *hash_fn,
  25. aws_hash_callback_eq_fn *equals_fn,
  26. aws_hash_callback_destroy_fn *destroy_key_fn,
  27. aws_hash_callback_destroy_fn *destroy_value_fn,
  28. size_t max_items) {
  29. AWS_ASSERT(allocator);
  30. AWS_ASSERT(max_items);
  31. struct aws_cache *lru_cache = NULL;
  32. struct lru_cache_impl_vtable *impl = NULL;
  33. if (!aws_mem_acquire_many(
  34. allocator, 2, &lru_cache, sizeof(struct aws_cache), &impl, sizeof(struct lru_cache_impl_vtable))) {
  35. return NULL;
  36. }
  37. impl->use_lru_element = s_lru_cache_use_lru_element;
  38. impl->get_mru_element = s_lru_cache_get_mru_element;
  39. lru_cache->allocator = allocator;
  40. lru_cache->max_items = max_items;
  41. lru_cache->vtable = &s_lru_cache_vtable;
  42. lru_cache->impl = impl;
  43. if (aws_linked_hash_table_init(
  44. &lru_cache->table, allocator, hash_fn, equals_fn, destroy_key_fn, destroy_value_fn, max_items)) {
  45. return NULL;
  46. }
  47. return lru_cache;
  48. }
  49. /* implementation for lru cache put */
  50. static int s_lru_cache_put(struct aws_cache *cache, const void *key, void *p_value) {
  51. if (aws_linked_hash_table_put(&cache->table, key, p_value)) {
  52. return AWS_OP_ERR;
  53. }
  54. /* Manage the space if we actually added a new element and the cache is full. */
  55. if (aws_linked_hash_table_get_element_count(&cache->table) > cache->max_items) {
  56. /* we're over the cache size limit. Remove whatever is in the front of
  57. * the linked_hash_table, which is the LRU element */
  58. const struct aws_linked_list *list = aws_linked_hash_table_get_iteration_list(&cache->table);
  59. struct aws_linked_list_node *node = aws_linked_list_front(list);
  60. struct aws_linked_hash_table_node *table_node = AWS_CONTAINER_OF(node, struct aws_linked_hash_table_node, node);
  61. return aws_linked_hash_table_remove(&cache->table, table_node->key);
  62. }
  63. return AWS_OP_SUCCESS;
  64. }
  65. /* implementation for lru cache find */
  66. static int s_lru_cache_find(struct aws_cache *cache, const void *key, void **p_value) {
  67. return (aws_linked_hash_table_find_and_move_to_back(&cache->table, key, p_value));
  68. }
  69. static void *s_lru_cache_use_lru_element(struct aws_cache *cache) {
  70. const struct aws_linked_list *list = aws_linked_hash_table_get_iteration_list(&cache->table);
  71. if (aws_linked_list_empty(list)) {
  72. return NULL;
  73. }
  74. struct aws_linked_list_node *node = aws_linked_list_front(list);
  75. struct aws_linked_hash_table_node *lru_node = AWS_CONTAINER_OF(node, struct aws_linked_hash_table_node, node);
  76. aws_linked_hash_table_move_node_to_end_of_list(&cache->table, lru_node);
  77. return lru_node->value;
  78. }
  79. static void *s_lru_cache_get_mru_element(const struct aws_cache *cache) {
  80. const struct aws_linked_list *list = aws_linked_hash_table_get_iteration_list(&cache->table);
  81. if (aws_linked_list_empty(list)) {
  82. return NULL;
  83. }
  84. struct aws_linked_list_node *node = aws_linked_list_back(list);
  85. struct aws_linked_hash_table_node *mru_node = AWS_CONTAINER_OF(node, struct aws_linked_hash_table_node, node);
  86. return mru_node->value;
  87. }
  88. void *aws_lru_cache_use_lru_element(struct aws_cache *cache) {
  89. AWS_PRECONDITION(cache);
  90. AWS_PRECONDITION(cache->impl);
  91. struct lru_cache_impl_vtable *impl_vtable = cache->impl;
  92. return impl_vtable->use_lru_element(cache);
  93. }
  94. void *aws_lru_cache_get_mru_element(const struct aws_cache *cache) {
  95. AWS_PRECONDITION(cache);
  96. AWS_PRECONDITION(cache->impl);
  97. struct lru_cache_impl_vtable *impl_vtable = cache->impl;
  98. return impl_vtable->get_mru_element(cache);
  99. }