nickva commented on a change in pull request #2666: soft-deletion for database
URL: https://github.com/apache/couchdb/pull/2666#discussion_r400979556
##########
File path: src/fabric/src/fabric2_fdb.erl
##########
@@ -346,12 +351,97 @@ delete(#{} = Db) ->
} = ensure_current(Db),
DbKey = erlfdb_tuple:pack({?ALL_DBS, DbName}, LayerPrefix),
- erlfdb:clear(Tx, DbKey),
- erlfdb:clear_range_startswith(Tx, DbPrefix),
+ DoRecovery = fabric2_util:do_recovery(),
+ case DoRecovery of
+ true ->
+ Timestamp = list_to_binary(fabric2_util:iso8601_timestamp()),
+ DeletedDbKey = erlfdb_tuple:pack({?DELETED_DBS, DbName, Timestamp},
+ LayerPrefix),
+ case erlfdb:wait(erlfdb:get(Tx, DeletedDbKey)) of
+ not_found ->
+ erlfdb:set(Tx, DeletedDbKey, DbPrefix),
+ erlfdb:clear(Tx, DbKey);
+ _Val ->
+ erlang:error({deleted_database_exists, DbName})
+ end;
+ false ->
+ erlfdb:clear(Tx, DbKey),
+ erlfdb:clear_range_startswith(Tx, DbPrefix)
+ end,
bump_metadata_version(Tx),
ok.
+deleted_dbs_info(#{} = Db0) ->
+ #{
+ name := DbName,
+ tx := Tx,
+ layer_prefix := LayerPrefix
+ } = ensure_current(Db0, false),
+
+ DeletedDbKey = erlfdb_tuple:pack({?DELETED_DBS, DbName}, LayerPrefix),
+ DeletedDbs = erlfdb:wait(erlfdb:get_range_startswith(Tx, DeletedDbKey)),
+ lists:foldl(fun({DbKey, DbPrefix}, Acc) ->
+ DBInfo = get_info_wait(get_info_future(Tx, DbPrefix)),
+ {?DELETED_DBS, DbName, DeletedTS} =
+ erlfdb_tuple:unpack(DbKey, LayerPrefix),
+ [{DeletedTS, DBInfo}| Acc]
+ end, [], DeletedDbs).
+
+
+undelete(#{} = Db0, TgtDbName, TimeStamp) ->
+ #{
+ name := DbName,
+ tx := Tx,
+ layer_prefix := LayerPrefix
+ } = ensure_current(Db0, false),
+ DbKey = erlfdb_tuple:pack({?ALL_DBS, TgtDbName}, LayerPrefix),
+ case erlfdb:wait(erlfdb:get(Tx, DbKey)) of
+ Bin when is_binary(Bin) ->
+ {error, file_exists};
+ not_found ->
+ DeletedDbTupleKey = {
+ ?DELETED_DBS,
+ DbName,
+ TimeStamp
+ },
+ DeleteDbKey = erlfdb_tuple:pack(DeletedDbTupleKey, LayerPrefix),
+ case erlfdb:wait(erlfdb:get(Tx, DeleteDbKey)) of
+ not_found ->
+ erlang:error({not_found, invalid_timestamp});
+ DbPrefix ->
+ erlfdb:set(Tx, DbKey, DbPrefix),
+ erlfdb:clear(Tx, DeleteDbKey),
+ bump_metadata_version(Tx),
+ ok
+ end
+ end.
+
+
+delete_deleted(#{} = Db0, TimeStamp) ->
+ #{
+ name := DbName,
+ tx := Tx,
+ layer_prefix := LayerPrefix
+ } = ensure_current(Db0),
+
+ DeletedDbTupleKey = {
+ ?DELETED_DBS,
+ DbName,
+ TimeStamp
+ },
+ DeleteDbKey = erlfdb_tuple:pack(DeletedDbTupleKey, LayerPrefix),
+ case erlfdb:wait(erlfdb:get(Tx, DeleteDbKey)) of
+ not_found ->
+ erlang:error({not_found});
+ DbPrefix ->
+ erlfdb:clear(Tx, DeleteDbKey),
+ erlfdb:clear_range_startswith(Tx, DbPrefix),
+ bump_metadata_version(Tx)
Review comment:
Thinking more about tests I think we'd want at least for these scenarios:
Cases where old db handle can't read the data anymore:
- db soft deleted
- db hard deleted
- db soft deleted and re-created
- db soft deleted and undeleted
- db hard deleted and re-created
Indexing stops when:
- db soft deleted
- db hard deleted
- db soft deleted and re-created
- db soft deleted and undeleted
- db hard deleted and re-created
Obviously indexing will stop if the first set of tests pass, however we want
to make sure the way indexing detects that db is now deleted hasn't changed and
it reacts the same as before. Look for db re-created or rename tests in recent
commits and I think we could modify those to take soft deletion into
consideration.
If we are using timestamps with 1 second resolution also make sure we handle
cases were we soft-delete/undelete multiple times in the same second, and also
tests where we do it across a few different seconds.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services