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

vatamane pushed a commit to branch accept-infinity-for-auto-purge-conifg
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 3db79febb09882a94a722359ca21a6574d55e413
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Wed Feb 25 02:23:13 2026 -0500

    Allow infinity for auto purge ttl setting
    
    The explicit `infinity` value can work better with multiple config levels.
    
    Also, users can now enable ttl for the whole cluster but disable it for
    specific dbs by setting their ttl in {db}/_auto_purge to `infinity`.
    
    While at it, update the etc default.ini config comment since we switched to
    using the `{num}_{timeunit}` format.
---
 rel/overlay/etc/default.ini                        |  8 +++--
 src/chttpd/src/chttpd_db.erl                       |  4 +++
 src/couch/src/couch_auto_purge_plugin.erl          | 21 +++++++++---
 .../test/eunit/couch_auto_purge_plugin_tests.erl   | 38 ++++++++++++++++++++++
 src/docs/src/config/scanner.rst                    |  9 +++--
 5 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 6fbc99f58..462233d47 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -1224,9 +1224,11 @@ url = {{nouveau_url}}
 ; one request.
 ;max_batch_size = 500
 
-; The default time-to-live, measured in seconds, before a
-; deleted document is eligible to be purged by the plugin.
-; Defaults to undefined, which disables auto purging.
+; The default time-to-live before a deleted document is eligible to be purged
+; by the plugin. Possible formats are: {num}_{timeunit} (ex: 1000_sec, 30_min,
+; 8_hours, 24_hours, 2_days, 3_weeks, 1_month, 2_years). Defaults to undefined
+; (or "infinity") which disables auto purging. Individual database ttl settings
+; will override this value.
 ;deleted_document_ttl =
 
 ; Set the log level for starting, stopping and purge report summary log 
entries.
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 5ef69f33f..200e705d2 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -412,6 +412,10 @@ handle_auto_purge_req(#httpd{} = Req, _Db) ->
 
 validate_auto_purge_props([]) ->
     ok;
+validate_auto_purge_props([{<<"deleted_document_ttl">>, <<"infinity">>} | 
Rest]) ->
+    % Setting the value to "infinity" is way to explicilty disable auto-purge
+    % individual databases while allowing cluster level auto-purge to happen
+    validate_auto_purge_props(Rest);
 validate_auto_purge_props([{<<"deleted_document_ttl">>, Value} | Rest]) when 
is_binary(Value) ->
     case couch_scanner_util:parse_non_weekday_period(?b2l(Value)) of
         undefined ->
diff --git a/src/couch/src/couch_auto_purge_plugin.erl 
b/src/couch/src/couch_auto_purge_plugin.erl
index 4fd904fdd..5589be244 100644
--- a/src/couch/src/couch_auto_purge_plugin.erl
+++ b/src/couch/src/couch_auto_purge_plugin.erl
@@ -197,6 +197,8 @@ ttl(St, DbName) ->
                 case parse_deleted_document_ttl(AutoPurgeProps) of
                     TTL when is_integer(TTL) ->
                         TTL;
+                    infinity ->
+                        infinity;
                     undefined ->
                         undefined;
                     Else ->
@@ -215,22 +217,33 @@ ttl(St, DbName) ->
                 ),
                 undefined
         end,
-    if
-        DbTTL /= undefined -> DbTTL;
-        DefaultTTL /= undefined -> parse_ttl(DefaultTTL);
-        true -> undefined
+    case {DbTTL, DefaultTTL} of
+        {undefined, undefined} ->
+            undefined;
+        {undefined, infinity} ->
+            undefined;
+        {infinity, _} ->
+            undefined;
+        {undefined, Val} when is_list(Val) ->
+            parse_ttl(Val);
+        {Val, _} when is_integer(Val) ->
+            Val
     end.
 
 parse_deleted_document_ttl(AutoPurgeProps) ->
     case couch_util:get_value(<<"deleted_document_ttl">>, AutoPurgeProps) of
         undefined ->
             undefined;
+        <<"infinity">> ->
+            infinity;
         Else ->
             parse_ttl(Else)
     end.
 
 parse_ttl(Bin) when is_binary(Bin) ->
     parse_ttl(binary_to_list(Bin));
+parse_ttl("infinity") ->
+    infinity;
 parse_ttl([$- | TTL]) ->
     -(parse_ttl(TTL));
 parse_ttl(TTL) ->
diff --git a/src/couch/test/eunit/couch_auto_purge_plugin_tests.erl 
b/src/couch/test/eunit/couch_auto_purge_plugin_tests.erl
index 38b325022..8e71be0a1 100644
--- a/src/couch/test/eunit/couch_auto_purge_plugin_tests.erl
+++ b/src/couch/test/eunit/couch_auto_purge_plugin_tests.erl
@@ -26,6 +26,9 @@ couch_quickjs_scanner_plugin_test_() ->
             ?TDEF_FE(t_no_auto_purge_by_default, 10),
             ?TDEF_FE(t_auto_purge_after_config_ttl, 10),
             ?TDEF_FE(t_auto_purge_after_db_ttl, 10),
+            ?TDEF_FE(t_no_auto_purge_after_db_ttl_set_to_infinity, 10),
+            ?TDEF_FE(t_no_auto_purge_after_config_ttl_set_to_infinity, 10),
+            ?TDEF_FE(t_db_auto_purge_overrides_cluster_ttl_infinity, 10),
             ?TDEF_FE(t_min_batch_size_1, 10),
             ?TDEF_FE(t_min_batch_size_2, 10),
             ?TDEF_FE(t_max_batch_size_1, 10),
@@ -90,6 +93,41 @@ t_auto_purge_after_db_ttl({_, DbName}) ->
     ?assertEqual(0, doc_del_count(DbName)),
     ok.
 
+t_no_auto_purge_after_config_ttl_set_to_infinity({_, DbName}) ->
+    config:set(atom_to_list(?PLUGIN), "deleted_document_ttl", "infinity", 
false),
+    ok = add_doc(DbName, <<"doc1">>, #{<<"_deleted">> => true}),
+    ?assertEqual(1, doc_del_count(DbName)),
+    meck:reset(couch_scanner_server),
+    meck:reset(?PLUGIN),
+    config:set("couch_scanner_plugins", atom_to_list(?PLUGIN), "true", false),
+    wait_exit(10000),
+    ?assertEqual(1, doc_del_count(DbName)),
+    ok.
+
+t_no_auto_purge_after_db_ttl_set_to_infinity({_, DbName}) ->
+    config:set(atom_to_list(?PLUGIN), "deleted_document_ttl", "-3_hour", 
false),
+    ok = fabric:set_auto_purge_props(DbName, [{<<"deleted_document_ttl">>, 
<<"infinity">>}]),
+    ok = add_doc(DbName, <<"doc1">>, #{<<"_deleted">> => true}),
+    ?assertEqual(1, doc_del_count(DbName)),
+    meck:reset(couch_scanner_server),
+    meck:reset(?PLUGIN),
+    config:set("couch_scanner_plugins", atom_to_list(?PLUGIN), "true", false),
+    wait_exit(10000),
+    ?assertEqual(1, doc_del_count(DbName)),
+    ok.
+
+t_db_auto_purge_overrides_cluster_ttl_infinity({_, DbName}) ->
+    config:set(atom_to_list(?PLUGIN), "deleted_document_ttl", "infinity", 
false),
+    ok = fabric:set_auto_purge_props(DbName, [{<<"deleted_document_ttl">>, 
"-3_hour"}]),
+    ok = add_doc(DbName, <<"doc1">>, #{<<"_deleted">> => true}),
+    ?assertEqual(1, doc_del_count(DbName)),
+    meck:reset(couch_scanner_server),
+    meck:reset(?PLUGIN),
+    config:set("couch_scanner_plugins", atom_to_list(?PLUGIN), "true", false),
+    wait_exit(10000),
+    ?assertEqual(0, doc_del_count(DbName)),
+    ok.
+
 t_dry_run({_, DbName}) ->
     config:set(atom_to_list(?PLUGIN), "dry_run", "true", false),
     config:set(atom_to_list(?PLUGIN), "deleted_document_ttl", "-3_hour", 
false),
diff --git a/src/docs/src/config/scanner.rst b/src/docs/src/config/scanner.rst
index e03ad7006..cb49acd6f 100644
--- a/src/docs/src/config/scanner.rst
+++ b/src/docs/src/config/scanner.rst
@@ -259,10 +259,13 @@ settings in their ``[{plugin}]`` section.
         Set the default interval before the plugin will purge
         a deleted document. Possible ttl formats are: ``{num}_{timeunit}`` 
(ex.:
         ``1000_sec``, ``30_min``, ``8_hours``, ``24_hour``, ``2_days``,
-        ``3_weeks``, ``1_month``).
+        ``3_weeks``, ``1_month``) or ``infinity``.
+
         The database may override this setting with the
-        :ref:`api/db/auto_purge` endpoint. If neither is set, the
-        plugin will not purge deleted documents.
+        :ref:`api/db/auto_purge` endpoint. If neither is set, the plugin will
+        not purge deleted documents. Setting the config value to ``infinity``
+        disables cluster level auto-purge, which may be used to run auto-purge
+        only for specific databases with the database level settings.
 
     .. config:option:: log_level
 

Reply via email to