This is an automated email from the ASF dual-hosted git repository. rnewson pushed a commit to branch auto-delete-tseq in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 4c4c11a304418f5f2b331bbb71b2554b7d207bfc Author: Robert Newson <rnew...@apache.org> AuthorDate: Tue Sep 16 15:25:01 2025 +0100 add get/set interface for auto purge properties --- src/chttpd/src/chttpd_db.erl | 20 ++++++- src/chttpd/src/chttpd_httpd_handlers.erl | 1 + src/fabric/src/fabric.erl | 10 +++- src/fabric/src/fabric_auto_purge.erl | 96 ++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index 4bab083d4..61d5f06ea 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -30,7 +30,8 @@ handle_view_cleanup_req/2, update_doc/4, http_code_from_status/1, - handle_partition_req/2 + handle_partition_req/2, + handle_auto_purge_req/2 ]). -import( @@ -390,6 +391,23 @@ update_partition_stats(PathParts) -> ok end. +handle_auto_purge_req(#httpd{method = 'GET'} = Req, Db) -> + case fabric:get_auto_purge_props(Db) of + {ok, AutoPurgeProps} -> + send_json(Req, {AutoPurgeProps}); + {error, Reason} -> + chttpd:send_error(Req, Reason) + end; +handle_auto_purge_req(#httpd{method = 'POST'} = Req, Db) -> + chttpd:validate_ctype(Req, "application/json"), + {AutoPurgeProps} = chttpd:json_body_obj(Req), + case fabric:set_auto_purge_props(Db, AutoPurgeProps) of + ok -> + send_json(Req, 202, {[{ok, true}]}); + {error, Reason} -> + chttpd:send_error(Req, Reason) + end. + handle_design_req( #httpd{ path_parts = [_DbName, _Design, Name, <<"_", _/binary>> = Action | _Rest] diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl b/src/chttpd/src/chttpd_httpd_handlers.erl index 932b52e5f..3e499b72d 100644 --- a/src/chttpd/src/chttpd_httpd_handlers.erl +++ b/src/chttpd/src/chttpd_httpd_handlers.erl @@ -35,6 +35,7 @@ db_handler(<<"_design">>) -> fun chttpd_db:handle_design_req/2; db_handler(<<"_partition">>) -> fun chttpd_db:handle_partition_req/2; db_handler(<<"_temp_view">>) -> fun chttpd_view:handle_temp_view_req/2; db_handler(<<"_changes">>) -> fun chttpd_db:handle_changes_req/2; +db_handler(<<"_auto_purge">>) -> fun chttpd_db:handle_auto_purge_req/2; db_handler(_) -> no_match. design_handler(<<"_view">>) -> fun chttpd_view:handle_view_req/3; diff --git a/src/fabric/src/fabric.erl b/src/fabric/src/fabric.erl index a2bf82482..c83b98f39 100644 --- a/src/fabric/src/fabric.erl +++ b/src/fabric/src/fabric.erl @@ -35,7 +35,9 @@ set_purge_infos_limit/3, get_purged_infos/1, compact/1, compact/2, - get_partition_info/2 + get_partition_info/2, + get_auto_purge_props/1, + set_auto_purge_props/2 ]). % Documents @@ -132,6 +134,12 @@ get_db_info(DbName) -> get_partition_info(DbName, Partition) -> fabric_db_partition_info:go(dbname(DbName), Partition). +get_auto_purge_props(DbName) -> + fabric_auto_purge:get(dbname(DbName)). + +set_auto_purge_props(DbName, AutoPurgeProps) -> + fabric_auto_purge:set(dbname(DbName), AutoPurgeProps). + %% @doc the number of docs in a database %% @equiv get_doc_count(DbName, <<"_all_docs">>) get_doc_count(DbName) -> diff --git a/src/fabric/src/fabric_auto_purge.erl b/src/fabric/src/fabric_auto_purge.erl new file mode 100644 index 000000000..a84947f9d --- /dev/null +++ b/src/fabric/src/fabric_auto_purge.erl @@ -0,0 +1,96 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(fabric_auto_purge). + +-export([get/1, set/2]). + +-export([set_int/2]). + +-include_lib("couch/include/couch_db.hrl"). +-define(KEY, <<"auto_purge">>). + +get(DbName) when is_binary(DbName) -> + with_db(fun(Db) -> get_cb(Db, DbName) end). + +get_cb(Db, DocId) -> + case couch_db:open_doc(Db, DocId) of + {error, Reason} -> + {error, Reason}; + {not_found, _Reason} -> + {ok, []}; + {ok, Doc} -> + {Props} = couch_doc:to_json_obj(Doc, []), + {AutoPurgeProps} = couch_util:get_value(?KEY, Props, {[]}), + {ok, AutoPurgeProps} + end. + +set(DbName, AutoPurgeProps) when is_binary(DbName) -> + Node = hd(mem3_util:live_nodes()), + case rpc:call(Node, ?MODULE, set_int, [DbName, AutoPurgeProps]) of + {badrpc, Reason} -> + {error, Reason}; + Result -> + Result + end. + +set_int(DbName, AutoPurgeProps) -> + case validate_props(AutoPurgeProps) of + {error, Reason} -> + {error, Reason}; + ok -> + with_db(fun(Db) -> set_cb(Db, DbName, AutoPurgeProps) end) + end. + +set_cb(Db, DocId, AutoPurgeProps) -> + case couch_db:open_doc(Db, DocId) of + {error, Reason} -> + {error, Reason}; + {not_found, _Reason} -> + {error, not_found}; + {ok, #doc{} = Doc0} -> + {Props0} = couch_doc:to_json_obj(Doc0, []), + Props1 = lists:keystore(?KEY, 1, Props0, {?KEY, {AutoPurgeProps}}), + Doc1 = couch_doc:from_json_obj({Props1}), + case couch_db:update_doc(Db, Doc1, []) of + {ok, _NewRev} -> + ok; + {error, Reason} -> + {error, Reason} + end + end. + +validate_props([]) -> + ok; +validate_props([{<<"deleted_document_ttl">>, Value} | Rest]) when is_integer(Value) -> + validate_props(Rest); +validate_props([{<<"deleted_document_ttl">>, _Value} | _Rest]) -> + {error, <<"deleted_document_ttl must be an integer">>}; +validate_props([{_K, _V} | _Rest]) -> + {error, <<"invalid auto purge property">>}; +validate_props(_Else) -> + {error, <<"malformed auto purge body">>}. + +with_db(Fun) -> + case couch_db:open_int(dbs_db(), [?ADMIN_CTX]) of + {ok, Db} -> + try + Fun(Db) + after + catch couch_db:close(Db) + end; + Else -> + Else + end. + +dbs_db() -> + ?l2b(config:get("mem3", "shards_db", "_dbs")).