You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2020/02/13 21:56:19 UTC

[couchdb] branch prototype/fdb-layer-get-dbs-info updated (8899334 -> 123c241)

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

davisp pushed a change to branch prototype/fdb-layer-get-dbs-info
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


 discard 8899334  fixup: add db size tests
 discard ec59327  more db size tests
 discard ae8d939  fixup: add size tests
 discard a472206  fixup size tests
 discard 9d5062b  fixup: add size tests
 discard 0161223  fixup: add size tracking
 discard 052610c  fixup: db size tests
 discard 1cfd2a5  Fix doc attachment tests
 discard a50fbfa  fixup: add db size tracking
 discard 04cbdbd  Add database size tests
 discard 9cecf8a  Track the size of data stored in a database
 discard 3d4970f  Support `GET /_dbs_info` endpoint
 discard 7505bfd  Implement `fabric2_db:list_dbs_info/1,2,3`
 discard b8b13ec  Implement async API for `fabric2_fdb:get_info/1`
 discard b2b5208  Track a database level view size rollup
     add 17055f4  Encode startkey/endkey for all_docs (#2538)
     add b50f17d  Fix doc attachment tests
     new 6cbc720  Track a database level view size rollup
     new cf01a52  Implement async API for `fabric2_fdb:get_info/1`
     new 1337fd0  Implement `fabric2_db:list_dbs_info/1,2,3`
     new 123c241  Support `GET /_dbs_info` endpoint

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (8899334)
            \
             N -- N -- N   refs/heads/prototype/fdb-layer-get-dbs-info (123c241)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/chttpd/src/chttpd_db.erl               |  10 +-
 src/couch/src/couch_att.erl                |  19 -
 src/fabric/include/fabric2.hrl             |   7 +-
 src/fabric/src/fabric2_db.erl              |  11 +-
 src/fabric/src/fabric2_fdb.erl             | 144 +----
 src/fabric/src/fabric2_util.erl            |  65 +--
 src/fabric/test/fabric2_db_size_tests.erl  | 824 -----------------------------
 src/fabric/test/fabric2_doc_crud_tests.erl |   5 +-
 src/fabric/test/fabric2_doc_size_tests.erl | 340 ------------
 test/elixir/test/all_docs_test.exs         |  53 +-
 10 files changed, 89 insertions(+), 1389 deletions(-)
 delete mode 100644 src/fabric/test/fabric2_db_size_tests.erl
 delete mode 100644 src/fabric/test/fabric2_doc_size_tests.erl


[couchdb] 03/04: Implement `fabric2_db:list_dbs_info/1,2,3`

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/fdb-layer-get-dbs-info
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 1337fd02850d404d05c3b24fe795e53637d6b342
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Tue Dec 3 12:45:36 2019 -0600

    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.
---
 src/fabric/src/fabric2_db.erl             | 100 +++++++++++++++++++++++++-----
 src/fabric/src/fabric2_fdb.erl            |  11 ++++
 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 6d015df..17c899d 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 0e7cba8..99611b0 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 cc44f7d..8052551 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.


[couchdb] 02/04: Implement async API for `fabric2_fdb:get_info/1`

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/fdb-layer-get-dbs-info
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit cf01a5232ae3ce0dbf3add0a23678fa4be7d59d7
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Tue Dec 3 12:44:34 2019 -0600

    Implement async API for `fabric2_fdb:get_info/1`
---
 src/fabric/src/fabric2_fdb.erl | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index 8bfbb74..0e7cba8 100644
--- a/src/fabric/src/fabric2_fdb.erl
+++ b/src/fabric/src/fabric2_fdb.erl
@@ -29,6 +29,8 @@
     list_dbs/4,
 
     get_info/1,
+    get_info_future/2,
+    get_info_wait/1,
     set_config/3,
 
     get_stat/2,
@@ -333,7 +335,10 @@ get_info(#{} = Db) ->
         tx := Tx,
         db_prefix := DbPrefix
     } = ensure_current(Db),
+    get_info_wait(get_info_future(Tx, DbPrefix)).
 
+
+get_info_future(Tx, DbPrefix) ->
     {CStart, CEnd} = erlfdb_tuple:range({?DB_CHANGES}, DbPrefix),
     ChangesFuture = erlfdb:get_range(Tx, CStart, CEnd, [
         {streaming_mode, exact},
@@ -344,6 +349,10 @@ get_info(#{} = Db) ->
     StatsPrefix = erlfdb_tuple:pack({?DB_STATS}, DbPrefix),
     MetaFuture = erlfdb:get_range_startswith(Tx, StatsPrefix),
 
+    {DbPrefix, ChangesFuture, MetaFuture}.
+
+
+get_info_wait({DbPrefix, ChangesFuture, MetaFuture}) ->
     RawSeq = case erlfdb:wait(ChangesFuture) of
         [] ->
             vs_to_seq(fabric2_util:seq_zero_vs());


[couchdb] 04/04: Support `GET /_dbs_info` endpoint

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/fdb-layer-get-dbs-info
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 123c241f66f05423599481dbfeb7d417a0951b81
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Tue Dec 3 13:44:35 2019 -0600

    Support `GET /_dbs_info` endpoint
    
    Previously only `POST` with a list of keys was supported. The new `GET`
    support just dumps all database info blobs in a single ordered response.
---
 src/chttpd/src/chttpd_misc.erl | 49 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/src/chttpd/src/chttpd_misc.erl b/src/chttpd/src/chttpd_misc.erl
index 186ec9f..b181f3c 100644
--- a/src/chttpd/src/chttpd_misc.erl
+++ b/src/chttpd/src/chttpd_misc.erl
@@ -157,6 +157,37 @@ all_dbs_callback({error, Reason}, #vacc{resp=Resp0}=Acc) ->
     {ok, Resp1} = chttpd:send_delayed_error(Resp0, Reason),
     {ok, Acc#vacc{resp=Resp1}}.
 
+handle_dbs_info_req(#httpd{method = 'GET'} = Req) ->
+    ok = chttpd:verify_is_server_admin(Req),
+
+    #mrargs{
+        start_key = StartKey,
+        end_key = EndKey,
+        direction = Dir,
+        limit = Limit,
+        skip = Skip
+    } = couch_mrview_http:parse_params(Req, undefined),
+
+    Options = [
+        {start_key, StartKey},
+        {end_key, EndKey},
+        {dir, Dir},
+        {limit, Limit},
+        {skip, Skip}
+    ],
+
+    % TODO: Figure out if we can't calculate a valid
+    % ETag for this request. \xFFmetadataVersion won't
+    % work as we don't bump versions on size changes
+
+    {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, []),
+    Callback = fun dbs_info_callback/2,
+    Acc = #vacc{req = Req, resp = Resp},
+    {ok, Resp} = fabric2_db:list_dbs_info(Callback, Acc, Options),
+    case is_record(Resp, vacc) of
+        true -> {ok, Resp#vacc.resp};
+        _ -> {ok, Resp}
+    end;
 handle_dbs_info_req(#httpd{method='POST', user_ctx=UserCtx}=Req) ->
     chttpd:validate_ctype(Req, "application/json"),
     Props = chttpd:json_body_obj(Req),
@@ -188,7 +219,23 @@ handle_dbs_info_req(#httpd{method='POST', user_ctx=UserCtx}=Req) ->
     send_chunk(Resp, "]"),
     chttpd:end_json_response(Resp);
 handle_dbs_info_req(Req) ->
-    send_method_not_allowed(Req, "POST").
+    send_method_not_allowed(Req, "GET,HEAD,POST").
+
+dbs_info_callback({meta, _Meta}, #vacc{resp = Resp0} = Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, "["),
+    {ok, Acc#vacc{resp = Resp1}};
+dbs_info_callback({row, Props}, #vacc{resp = Resp0} = Acc) ->
+    Prepend = couch_mrview_http:prepend_val(Acc),
+    Chunk = [Prepend, ?JSON_ENCODE({Props})],
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, Chunk),
+    {ok, Acc#vacc{prepend = ",", resp = Resp1}};
+dbs_info_callback(complete, #vacc{resp = Resp0} = Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, "]"),
+    {ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
+    {ok, Acc#vacc{resp = Resp2}};
+dbs_info_callback({error, Reason}, #vacc{resp = Resp0} = Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_error(Resp0, Reason),
+    {ok, Acc#vacc{resp = Resp1}}.
 
 handle_task_status_req(#httpd{method='GET'}=Req) ->
     ok = chttpd:verify_is_server_admin(Req),


[couchdb] 01/04: Track a database level view size rollup

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/fdb-layer-get-dbs-info
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 6cbc72048a0fade78846242d0e4b824684e7dbd1
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Tue Dec 3 10:24:36 2019 -0600

    Track a database level view size rollup
    
    This way we can expose the total view size for a database in the dbinfo
    JSON blob.
---
 src/couch_views/src/couch_views_fdb.erl | 17 ++++++++++++++--
 src/fabric/src/fabric2_fdb.erl          | 36 ++++++++++++++++-----------------
 2 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/src/couch_views/src/couch_views_fdb.erl b/src/couch_views/src/couch_views_fdb.erl
index 98cff46..5edaa3a 100644
--- a/src/couch_views/src/couch_views_fdb.erl
+++ b/src/couch_views/src/couch_views_fdb.erl
@@ -272,8 +272,16 @@ update_kv_size(TxDb, Sig, ViewId, Increment) ->
         tx := Tx,
         db_prefix := DbPrefix
     } = TxDb,
-    Key = kv_size_key(DbPrefix, Sig, ViewId),
-    erlfdb:add(Tx, Key, Increment).
+
+    % Track a view specific size for calls to
+    % GET /dbname/_design/doc/_info`
+    IdxKey = kv_size_key(DbPrefix, Sig, ViewId),
+    erlfdb:add(Tx, IdxKey, Increment),
+
+    % Track a database level rollup for calls to
+    % GET /dbname
+    DbKey = db_kv_size_key(DbPrefix),
+    erlfdb:add(Tx, DbKey, Increment).
 
 
 seq_key(DbPrefix, Sig) ->
@@ -291,6 +299,11 @@ kv_size_key(DbPrefix, Sig, ViewId) ->
     erlfdb_tuple:pack(Key, DbPrefix).
 
 
+db_kv_size_key(DbPrefix) ->
+    Key = {?DB_STATS, <<"sizes">>, <<"views">>},
+    erlfdb_tuple:pack(Key, DbPrefix).
+
+
 id_idx_key(DbPrefix, Sig, DocId, ViewId) ->
     Key = {?DB_VIEWS, Sig, ?VIEW_ID_RANGE, DocId, ViewId},
     erlfdb_tuple:pack(Key, DbPrefix).
diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index 6abe1f6..8bfbb74 100644
--- a/src/fabric/src/fabric2_fdb.erl
+++ b/src/fabric/src/fabric2_fdb.erl
@@ -174,11 +174,16 @@ create(#{} = Db0, Options) ->
         {?DB_STATS, <<"doc_del_count">>, ?uint2bin(0)},
         {?DB_STATS, <<"doc_design_count">>, ?uint2bin(0)},
         {?DB_STATS, <<"doc_local_count">>, ?uint2bin(0)},
-        {?DB_STATS, <<"size">>, ?uint2bin(2)}
+        {?DB_STATS, <<"sizes">>, <<"external">>, ?uint2bin(2)},
+        {?DB_STATS, <<"sizes">>, <<"views">>, ?uint2bin(0)}
     ],
-    lists:foreach(fun({P, K, V}) ->
-        Key = erlfdb_tuple:pack({P, K}, DbPrefix),
-        erlfdb:set(Tx, Key, V)
+    lists:foreach(fun
+        ({P, K, V}) ->
+            Key = erlfdb_tuple:pack({P, K}, DbPrefix),
+            erlfdb:set(Tx, Key, V);
+        ({P, S, K, V}) ->
+            Key = erlfdb_tuple:pack({P, S, K}, DbPrefix),
+            erlfdb:set(Tx, Key, V)
     end, Defaults),
 
     UserCtx = fabric2_util:get_value(user_ctx, Options, #user_ctx{}),
@@ -348,26 +353,21 @@ get_info(#{} = Db) ->
     end,
     CProp = {update_seq, RawSeq},
 
-    MProps = lists:flatmap(fun({K, V}) ->
+    MProps = lists:foldl(fun({K, V}, Acc) ->
         case erlfdb_tuple:unpack(K, DbPrefix) of
             {?DB_STATS, <<"doc_count">>} ->
-                [{doc_count, ?bin2uint(V)}];
+                [{doc_count, ?bin2uint(V)} | Acc];
             {?DB_STATS, <<"doc_del_count">>} ->
-                [{doc_del_count, ?bin2uint(V)}];
-            {?DB_STATS, <<"size">>} ->
+                [{doc_del_count, ?bin2uint(V)} | Acc];
+            {?DB_STATS, <<"sizes">>, Name} ->
                 Val = ?bin2uint(V),
-                [
-                    {other, {[{data_size, Val}]}},
-                    {sizes, {[
-                        {active, 0},
-                        {external, Val},
-                        {file, 0}
-                    ]}}
-                ];
+                {_, {Sizes}} = lists:keyfind(sizes, 1, Acc),
+                NewSizes = lists:keystore(Name, 1, Sizes, {Name, Val}),
+                lists:keystore(sizes, 1, Acc, {sizes, {NewSizes}});
             {?DB_STATS, _} ->
-                []
+                Acc
         end
-    end, erlfdb:wait(MetaFuture)),
+    end, [{sizes, {[]}}], erlfdb:wait(MetaFuture)),
 
     [CProp | MProps].