diff options
author | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-12-03 12:45:36 -0600 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2020-02-13 16:25:40 -0600 |
commit | 416de8defaa956ed82ab07ad2dd076e897631224 (patch) | |
tree | 0852feef6bbecf6096233924d9a6846c2f83e405 | |
parent | ad066abf4ec90e02f1b618b7dffe25ae737d4537 (diff) | |
download | couchdb-416de8defaa956ed82ab07ad2dd076e897631224.tar.gz |
Implement `fabric2_db:list_dbs_info/1,2,3`
This API allows for listing all database info blobs in a single request.
It accepts the same parameters as `_all_dbs` for controlling pagination
of results and so on.
-rw-r--r-- | src/fabric/src/fabric2_db.erl | 100 | ||||
-rw-r--r-- | src/fabric/src/fabric2_fdb.erl | 11 | ||||
-rw-r--r-- | src/fabric/test/fabric2_db_crud_tests.erl | 31 |
3 files changed, 126 insertions, 16 deletions
diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl index 6d015df0e..17c899d27 100644 --- a/src/fabric/src/fabric2_db.erl +++ b/src/fabric/src/fabric2_db.erl @@ -22,6 +22,10 @@ list_dbs/1, list_dbs/3, + list_dbs_info/0, + list_dbs_info/1, + list_dbs_info/3, + check_is_admin/1, check_is_member/1, @@ -238,6 +242,46 @@ list_dbs(UserFun, UserAcc0, Options) -> end). +list_dbs_info() -> + list_dbs_info([]). + + +list_dbs_info(Options) -> + Callback = fun(Value, Acc) -> + NewAcc = case Value of + {meta, _} -> Acc; + {row, DbInfo} -> [DbInfo | Acc]; + complete -> Acc + end, + {ok, NewAcc} + end, + {ok, DbInfos} = list_dbs_info(Callback, [], Options), + {ok, lists:reverse(DbInfos)}. + + +list_dbs_info(UserFun, UserAcc0, Options) -> + FoldFun = fun(DbName, InfoFuture, {FutureQ, Count, Acc}) -> + NewFutureQ = queue:in({DbName, InfoFuture}, FutureQ), + drain_info_futures(NewFutureQ, Count + 1, UserFun, Acc) + end, + fabric2_fdb:transactional(fun(Tx) -> + try + UserAcc1 = maybe_stop(UserFun({meta, []}, UserAcc0)), + InitAcc = {queue:new(), 0, UserAcc1}, + {FinalFutureQ, _, UserAcc2} = fabric2_fdb:list_dbs_info( + Tx, + FoldFun, + InitAcc, + Options + ), + UserAcc3 = drain_all_info_futures(FinalFutureQ, UserFun, UserAcc2), + {ok, maybe_stop(UserFun(complete, UserAcc3))} + catch throw:{stop, FinalUserAcc} -> + {ok, FinalUserAcc} + end + end). + + is_admin(Db, {SecProps}) when is_list(SecProps) -> case fabric2_db_plugin:check_is_admin(Db) of true -> @@ -313,21 +357,7 @@ get_db_info(#{} = Db) -> DbProps = fabric2_fdb:transactional(Db, fun(TxDb) -> fabric2_fdb:get_info(TxDb) end), - - BaseProps = [ - {cluster, {[{n, 0}, {q, 0}, {r, 0}, {w, 0}]}}, - {compact_running, false}, - {data_size, 0}, - {db_name, name(Db)}, - {disk_format_version, 0}, - {disk_size, 0}, - {instance_start_time, <<"0">>}, - {purge_seq, 0} - ], - - {ok, lists:foldl(fun({Key, Val}, Acc) -> - lists:keystore(Key, 1, Acc, {Key, Val}) - end, BaseProps, DbProps)}. + {ok, make_db_info(name(Db), DbProps)}. get_del_doc_count(#{} = Db) -> @@ -944,6 +974,46 @@ maybe_add_sys_db_callbacks(Db) -> }. +make_db_info(DbName, Props) -> + BaseProps = [ + {cluster, {[{n, 0}, {q, 0}, {r, 0}, {w, 0}]}}, + {compact_running, false}, + {data_size, 0}, + {db_name, DbName}, + {disk_format_version, 0}, + {disk_size, 0}, + {instance_start_time, <<"0">>}, + {purge_seq, 0} + ], + + lists:foldl(fun({Key, Val}, Acc) -> + lists:keystore(Key, 1, Acc, {Key, Val}) + end, BaseProps, Props). + + +drain_info_futures(FutureQ, Count, _UserFun, Acc) when Count < 100 -> + {FutureQ, Count, Acc}; + +drain_info_futures(FutureQ, Count, UserFun, Acc) when Count >= 100 -> + {{value, {DbName, Future}}, RestQ} = queue:out(FutureQ), + InfoProps = fabric2_fdb:get_info_wait(Future), + DbInfo = make_db_info(DbName, InfoProps), + NewAcc = maybe_stop(UserFun({row, DbInfo}, Acc)), + {RestQ, Count - 1, NewAcc}. + + +drain_all_info_futures(FutureQ, UserFun, Acc) -> + case queue:out(FutureQ) of + {{value, {DbName, Future}}, RestQ} -> + InfoProps = fabric2_fdb:get_info_wait(Future), + DbInfo = make_db_info(DbName, InfoProps), + NewAcc = maybe_stop(UserFun({row, DbInfo}, Acc)), + drain_all_info_futures(RestQ, UserFun, NewAcc); + {empty, _} -> + Acc + end. + + new_revid(Db, Doc) -> #doc{ id = DocId, diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl index 0e7cba859..99611b0a1 100644 --- a/src/fabric/src/fabric2_fdb.erl +++ b/src/fabric/src/fabric2_fdb.erl @@ -27,6 +27,7 @@ get_dir/1, list_dbs/4, + list_dbs_info/4, get_info/1, get_info_future/2, @@ -330,6 +331,16 @@ list_dbs(Tx, Callback, AccIn, Options) -> end, AccIn, Options). +list_dbs_info(Tx, Callback, AccIn, Options) -> + LayerPrefix = get_dir(Tx), + Prefix = erlfdb_tuple:pack({?ALL_DBS}, LayerPrefix), + fold_range({tx, Tx}, Prefix, fun({DbNameKey, DbPrefix}, Acc) -> + {DbName} = erlfdb_tuple:unpack(DbNameKey, Prefix), + InfoFuture = get_info_future(Tx, DbPrefix), + Callback(DbName, InfoFuture, Acc) + end, AccIn, Options). + + get_info(#{} = Db) -> #{ tx := Tx, diff --git a/src/fabric/test/fabric2_db_crud_tests.erl b/src/fabric/test/fabric2_db_crud_tests.erl index cc44f7d6b..80525513a 100644 --- a/src/fabric/test/fabric2_db_crud_tests.erl +++ b/src/fabric/test/fabric2_db_crud_tests.erl @@ -29,7 +29,8 @@ crud_test_() -> ?TDEF(create_db), ?TDEF(open_db), ?TDEF(delete_db), - ?TDEF(list_dbs) + ?TDEF(list_dbs), + ?TDEF(list_dbs_info) ]) } }. @@ -84,3 +85,31 @@ list_dbs(_) -> ?assertEqual(ok, fabric2_db:delete(DbName, [])), AllDbs3 = fabric2_db:list_dbs(), ?assert(not lists:member(DbName, AllDbs3)). + + +list_dbs_info(_) -> + DbName = ?tempdb(), + {ok, AllDbInfos1} = fabric2_db:list_dbs_info(), + + ?assert(is_list(AllDbInfos1)), + ?assert(not is_db_info_member(DbName, AllDbInfos1)), + + ?assertMatch({ok, _}, fabric2_db:create(DbName, [])), + {ok, AllDbInfos2} = fabric2_db:list_dbs_info(), + ?assert(is_db_info_member(DbName, AllDbInfos2)), + + ?assertEqual(ok, fabric2_db:delete(DbName, [])), + {ok, AllDbInfos3} = fabric2_db:list_dbs_info(), + ?assert(not is_db_info_member(DbName, AllDbInfos3)). + + +is_db_info_member(_, []) -> + false; + +is_db_info_member(DbName, [DbInfo | RestInfos]) -> + case lists:keyfind(db_name, 1, DbInfo) of + {db_name, DbName} -> + true; + _E -> + is_db_info_member(DbName, RestInfos) + end. |