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 1d31d05b92f95988779483cd5088881a2e5dd432 Author: Robert Newson <[email protected]> AuthorDate: Tue Sep 2 15:32:21 2025 +0100 wip --- src/couch/src/couch_tombstone_remover.erl | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/couch/src/couch_tombstone_remover.erl b/src/couch/src/couch_tombstone_remover.erl new file mode 100644 index 000000000..4a5304816 --- /dev/null +++ b/src/couch/src/couch_tombstone_remover.erl @@ -0,0 +1,90 @@ +% 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(couch_tombstone_remover). +-behaviour(couch_scanner_plugin). + +-export([ + start/2, + resume/2, + complete/1, + checkpoint/1, + db/2, + doc_fdi/3, + db_closing/2 +]). + +-include_lib("couch_scanner/include/couch_scanner_plugin.hrl"). + +start(ScanId, #{}) -> + St = init_config(ScanId), + case should_run() of + true -> + ?INFO("Starting.", [], St), + {ok, St}; + false -> + ?INFO("Not starting.", [], St), + skip + end. + +resume(ScanId, #{}) -> + St = init_config(ScanId), + case should_run() of + true -> + ?INFO("Resuming.", [], St), + {ok, St}; + false -> + ?INFO("Not resuming.", [], St), + skip + end. + +complete(St) -> + ?INFO("Completed", [], St), + {ok, #{}}. + +checkpoint(_St) -> + {ok, #{}}. + +db(St, _DbName) -> + {ok, St}. + +doc_fdi(St, #full_doc_info{} = FDI, Db) when not is_map_key(Db, St) -> + %% cache TimeSeq for this db. + doc_fdi(St#{couch_db:name(Db) => couch_db:get_time_seq(Db)}, FDI, Db); +doc_fdi(#{sid := ScanId} = St, #full_doc_info{deleted = true} = FDI, Db) -> + TimeSeq = maps:get(couch_db:name(Db), St), + TTL = 30 * 24 * 60 * 60, + SinceSeq = couch_time_seq:since(TimeSeq, couch_time_seq:timestamp() - TTL), + ?INFO("burp ~p.", [St], #{sid => ScanId}), + if + FDI#full_doc_info.update_seq =< SinceSeq -> + ?INFO("purging tombstone ~p in ~p.", [FDI#full_doc_info.id, Db], #{sid => ScanId}), + purge(Db, FDI); + true -> + ok + end, + {ok, St}; +doc_fdi(St, #full_doc_info{}, _Db) -> + ?INFO("burp2 ~p.", [St]), + {stop, St}. + +db_closing(St, Db) -> + {ok, maps:remove(couch_db:name(Db), St)}. + +init_config(ScanId) -> + #{sid => ScanId}. + +should_run() -> + couch_scanner_util:on_first_node(). + +purge(Db, #full_doc_info{} = FDI) -> + ok.
