This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch 3.3.x
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit cf00ff8e1deecf0a83d4bb0acadf403761afd7c2
Author: Nick Vatamaniuc <vatam...@gmail.com>
AuthorDate: Thu Nov 9 12:51:34 2023 -0500

    Fix update bug in ets_lru
    
    Previously, when an existing cache entry was updated, we didn't update the
    atime. Subsequently, when the entry was removed, we never cleaned the orphan
    atime entry. During trimming, we traverse the atime entries, and since the
    orphaned one didn't have any matching objects or ctime entries, the ets_lru
    cache would crash, possibly taking down the primary couch supervisor.
---
 src/ets_lru/src/ets_lru.erl       |  5 +++--
 src/ets_lru/test/ets_lru_test.erl | 28 ++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/src/ets_lru/src/ets_lru.erl b/src/ets_lru/src/ets_lru.erl
index 891aeeb57..6416fc8f1 100644
--- a/src/ets_lru/src/ets_lru.erl
+++ b/src/ets_lru/src/ets_lru.erl
@@ -167,8 +167,9 @@ handle_call({insert, Key, Val}, _From, St) ->
     Pattern = #entry{key = Key, atime = '$1', _ = '_'},
     case ets:match(St#st.objects, Pattern) of
         [[ATime]] ->
-            Update = {#entry.val, Val},
-            true = ets:update_element(St#st.objects, Key, Update),
+            true = ets:update_element(St#st.objects, Key, [
+                {#entry.val, Val}, {#entry.atime, NewATime}
+            ]),
             true = ets:delete(St#st.atimes, ATime),
             true = ets:insert(St#st.atimes, {NewATime, Key});
         [] ->
diff --git a/src/ets_lru/test/ets_lru_test.erl 
b/src/ets_lru/test/ets_lru_test.erl
index 5dd193f8d..eb5b79841 100644
--- a/src/ets_lru/test/ets_lru_test.erl
+++ b/src/ets_lru/test/ets_lru_test.erl
@@ -132,6 +132,34 @@ basic_behavior_test_() ->
                             ?_assertEqual(not_found, ets_lru:lookup(LRU, foo))
                         }
                     ]
+                end,
+                fun({ok, LRU}) ->
+                    [
+                        {
+                            "Insert the value twice",
+                            ?_assertEqual(ok, ets_lru:insert(LRU, foo, bar))
+                        },
+                        {
+                            "Objects table size should be 1",
+                            ?_assertEqual(1, ets:info(test_lru_objects, size))
+                        },
+                        {
+                            "ATimes table size should be 1",
+                            ?_assertEqual(1, ets:info(test_lru_atimes, size))
+                        },
+                        {
+                            "CTimes table size should be 1",
+                            ?_assertEqual(1, ets:info(test_lru_ctimes, size))
+                        },
+                        {
+                            "Clear LRU after duplicate insert",
+                            ?_assertEqual(ok, ets_lru:clear(LRU))
+                        },
+                        {
+                            "Lookup returned not_found after a clear after a 
duplicate insert",
+                            ?_assertEqual(not_found, ets_lru:lookup(LRU, foo))
+                        }
+                    ]
                 end
             ]}
     }.

Reply via email to