summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2017-12-16 09:30:29 +0100
committerJan Lehnardt <jan@apache.org>2019-01-19 14:20:06 +0100
commit6c369fecef3c9de5f7ba788362da27b8c12766a7 (patch)
treebab579abcf1c1c54eedb83b4a7e9e8c27e29617b
parentb1d835a9d3ac8e8ad77dea785053cb7a3be3bed6 (diff)
downloadcouchdb-6c369fecef3c9de5f7ba788362da27b8c12766a7.tar.gz
wip
-rw-r--r--src/couch/src/couch_access_native_proc.erl12
-rw-r--r--src/couch/src/couch_btree.erl21
-rw-r--r--src/couch/src/couch_db.erl144
-rw-r--r--src/couch_mrview/src/couch_mrview.erl10
-rw-r--r--src/couch_mrview/src/couch_mrview_updater.erl13
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl6
6 files changed, 199 insertions, 7 deletions
diff --git a/src/couch/src/couch_access_native_proc.erl b/src/couch/src/couch_access_native_proc.erl
index dd01de081..840cf1b19 100644
--- a/src/couch/src/couch_access_native_proc.erl
+++ b/src/couch/src/couch_access_native_proc.erl
@@ -36,7 +36,6 @@
}).
start_link() ->
- couch_log:info("~n~ncouch_access_native_proc: start_link~n~n", []),
gen_server:start_link(?MODULE, [], []).
@@ -49,7 +48,6 @@ prompt(Pid, Data) ->
init(_) ->
- couch_log:info("~n~ncouch_access_native_proc: init~n~n", []),
{ok, #st{}}.
@@ -129,10 +127,16 @@ map_doc(_St, {Doc}) ->
Access when is_list(Access) ->
Id = couch_util:get_value(<<"_id">>, Doc),
Rev = couch_util:get_value(<<"_rev">>, Doc),
+ Seq = couch_util:get_value(<<"_seq">>, Doc),
+ % by-access-id
lists:map(fun(UserOrRole) -> [
[[UserOrRole, Id], Rev]
] end, Access)
- ++ [[]]; %TODO: implement by-access-seq
+ ++
+ % by-access-seq
+ lists:map(fun(UserOrRole) -> [
+ [[UserOrRole, Seq], Rev]
+ ] end, Access);
_Else ->
- [[],[]] % no comprende
+ [[],[]] % no comprende: should not be needed once we implement _access field validation
end.
diff --git a/src/couch/src/couch_btree.erl b/src/couch/src/couch_btree.erl
index daf846ba8..ef2991064 100644
--- a/src/couch/src/couch_btree.erl
+++ b/src/couch/src/couch_btree.erl
@@ -16,6 +16,7 @@
-export([fold/4, full_reduce/1, final_reduce/2, size/1, foldl/3, foldl/4]).
-export([fold_reduce/4, lookup/2, get_state/1, set_options/2]).
-export([extract/2, assemble/3, less/3]).
+-export([full_reduce_with_options/2]).
-include_lib("couch/include/couch_db.hrl").
@@ -34,6 +35,8 @@ assemble(#btree{assemble_kv=Assemble}, Key, Value) ->
less(#btree{less=undefined}, A, B) ->
A < B;
less(#btree{less=Less}, A, B) ->
+ couch_log:info("~n A:~p~n", [A]),
+ couch_log:info("~n B:~p~n", [B]),
Less(A, B).
% pass in 'nil' for State if a new Btree.
@@ -92,11 +95,29 @@ fold_reduce(#btree{root=Root}=Bt, Fun, Acc, Options) ->
throw:{stop, AccDone} -> {ok, AccDone}
end.
+full_reduce_with_options(Bt, Options0) ->
+ CountFun = fun(_SeqStart, PartialReds, 0) ->
+ {ok, couch_btree:final_reduce(Bt, PartialReds)}
+ end,
+ [UserName] = proplists:get_value(start_key, Options0, <<"">>),
+ % couch_log:info("~n Options0:~p~n", [Options0]),
+ % couch_log:info("~n UserName:~p~n", [UserName]),
+ EndKey = {[UserName, {[]}], {[]}},
+ % couch_log:info("~n EndKey:~p~n", [EndKey]),
+ Options = Options0 ++ [
+ {end_key, EndKey}
+ ],
+ couch_log:info("~n Options:~p~n", [Options]),
+ R = fold_reduce(Bt, CountFun, 0, Options),
+ couch_log:info("~n~n R: ~p ~n", [R]),
+ R.
+
full_reduce(#btree{root=nil,reduce=Reduce}) ->
{ok, Reduce(reduce, [])};
full_reduce(#btree{root=Root}) ->
{ok, element(2, Root)}.
+
size(#btree{root = nil}) ->
0;
size(#btree{root = {_P, _Red}}) ->
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 2f63fcfe8..35b5c7978 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -133,6 +133,7 @@
-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch_mrview/include/couch_mrview.hrl").
-include("couch_db_int.hrl").
-define(DBNAME_REGEX,
@@ -576,6 +577,30 @@ get_db_info(Db) ->
ActiveSize = couch_util:get_value(active, SizeInfo, null),
ExternalSize = couch_util:get_value(external, SizeInfo, null),
DiskVersion = couch_db_engine:get_disk_version(Db),
+
+% pre PSE TODO: PORT
+% {ok, FileSize} = couch_file:bytes(Fd),
+% {ok, DbReduction} = couch_btree:full_reduce(IdBtree),
+ % case is_admin(Db) of
+ % true ->
+ % couch_btree:full_reduce(IdBtree);
+ % false ->
+ % UserCtx = get_user_ctx(Db),
+ % UserName = UserCtx#user_ctx.name,
+ % couch_btree:full_reduce_with_options(IdBtree, [{start_key, UserName}])
+ % end,
+% SizeInfo0 = element(3, DbReduction),
+% SizeInfo = case SizeInfo0 of
+% SI when is_record(SI, size_info) ->
+% SI;
+% {AS, ES} ->
+% #size_info{active=AS, external=ES};
+% AS ->
+% #size_info{active=AS}
+% end,
+% ActiveSize = active_size(Db, SizeInfo),
+% DiskVersion = couch_db_header:disk_version(Header),
+
Uuid = case get_uuid(Db) of
undefined -> null;
Uuid0 -> Uuid0
@@ -1458,6 +1483,125 @@ open_write_stream(Db, Options) ->
open_read_stream(Db, AttState) ->
couch_db_engine:open_read_stream(Db, AttState).
+changes_since(Db, StartSeq, Fun, Options, Acc) when is_record(Db, db) ->
+ case couch_db:is_admin(Db) of
+ true -> changes_since_admin(Db#db.seq_tree, StartSeq, Fun, Options, Acc);
+ false -> changes_since_admin(Db#db.seq_tree, StartSeq, Fun, Options, Acc)
+ % false -> changes_since_access(Db, StartSeq, Fun, Options, Acc)
+ end.
+
+% TODO: nicked from couch_mrview, maybe move to couch_mrview.hrl
+-record(mracc, {
+ db,
+ meta_sent=false,
+ total_rows,
+ offset,
+ limit,
+ skip,
+ group_level,
+ doc_info,
+ callback,
+ user_acc,
+ last_go=ok,
+ reduce_fun,
+ update_seq,
+ args
+}).
+
+changes_since_access(Db, StartSeq, Fun, Options, Acc) ->
+ %% query view _access/_by_access_seq
+ %% fudge result to look like changes_since / Fun expect.
+ % query our not yest existing, home-grown _access view.
+ % use query_view for this.
+ DDoc = #doc{ % TODO: dupe: externalise or move into shared function
+ id = <<"_design/_access">>,
+ body = {[
+ {<<"language">>,<<"_access">>},
+ {<<"views">>, {[
+ {<<"_access_by_id">>, {[
+ {<<"map">>, <<"_access/by-id-map">>},
+ {<<"reduce">>, <<"_count">>}
+ ]}},
+ {<<"_access_by_seq">>, {[
+ {<<"map">>, <<"_access/by-seq-map">>},
+ {<<"reduce">>, <<"_count">>}
+ ]}}
+ ]}}
+ ]}
+ },
+ %% add startkey/endkey
+ UserCtx = couch_db:get_user_ctx(Db),
+ UserName = UserCtx#user_ctx.name,
+ Direction = proplists:get_value(dir, Options, fwd),
+ Args0 = #mrargs{
+ direction = Direction,
+ start_key = StartSeq,
+ reduce = false
+ },
+ Args = prefix_startkey_endkey(UserName, Args0, Direction),
+ % filter out the user-prefix from the key, so _all_docs looks normal
+ % this isn’t a separate function because I’m binding Callback0 and I don’t
+ % know the Erlang equivalent of JS’s fun.bind(this, newarg)
+ % also translate view output into by-seq output
+ Callback = fun
+ ({meta, _}, Acc0) ->
+ Acc0;
+ ({row, Props}=Row, Acc0) ->
+ couch_log:info("~nRow: ~p~n~n", [Row]),
+ [_User, Key] = proplists:get_value(key, Props),
+ Row0 = proplists:delete(key, Props),
+ Row = [{key, Key} | Row0],
+ Fun({row, Row}, Acc0);
+ (Row, Acc0) ->
+ couch_log:info("~nRow: ~p~n~n", [Row]),
+ Fun(Row, Acc0)
+ end,
+ VName = <<"_access_by_seq">>,
+ couch_mrview:query_view(Db, DDoc, VName, Args, Callback, #mracc{user_acc = Acc}).
+
+
+% TODO: dupe: externalise or move into shared function
+prefix_startkey_endkey(UserName, Args, fwd) ->
+ #mrargs{start_key=StartKey, end_key=EndKey} = Args,
+ Args#mrargs {
+ start_key = case StartKey of
+ undefined -> [UserName];
+ StartKey -> [UserName, StartKey]
+ end,
+ end_key = case EndKey of
+ undefined -> [UserName, {}];
+ EndKey -> [UserName, EndKey, {}]
+ end
+ };
+prefix_startkey_endkey(UserName, Args, rev) ->
+ #mrargs{start_key=StartKey, end_key=EndKey} = Args,
+ Args#mrargs {
+ end_key = case StartKey of
+ undefined -> [UserName];
+ StartKey -> [UserName, StartKey]
+ end,
+ start_key = case EndKey of
+ undefined -> [UserName, {}];
+ EndKey -> [UserName, EndKey, {}]
+ end
+ }.
+
+
+changes_since_admin(SeqTree, StartSeq, Fun, Options, Acc) ->
+ Wrapper = fun(FullDocInfo, _Offset, Acc2) ->
+ DocInfo = case FullDocInfo of
+ #full_doc_info{} ->
+ couch_doc:to_doc_info(FullDocInfo);
+ #doc_info{} ->
+ FullDocInfo
+ end,
+ couch_log:info("~nDocInfo: ~p~n~n", [DocInfo]),
+ Fun(DocInfo, Acc2)
+ end,
+ {ok, _LastReduction, AccOut} = couch_btree:fold(SeqTree,
+ Wrapper, Acc, [{start_key, StartSeq + 1}] ++ Options),
+ {ok, AccOut}.
+
is_active_stream(Db, StreamEngine) ->
couch_db_engine:is_active_stream(Db, StreamEngine).
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 9469fafca..bea945eb2 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -242,7 +242,6 @@ query_all_docs_access(Db, Args0, Callback0, Acc) ->
]}}
]}
},
- %% add startkey/endkey
UserCtx = couch_db:get_user_ctx(Db),
UserName = UserCtx#user_ctx.name,
% TODO: add roles
@@ -551,7 +550,14 @@ all_docs_fold(Db, #mrargs{direction=Dir, keys=Keys0}=Args, Callback, UAcc) ->
map_fold(Db, View, Args, Callback, UAcc) ->
- {ok, Total} = couch_mrview_util:get_row_count(View),
+ % couch_log:info("~n~n View: ~p~n", [View]),
+ {ok, Total} = case View#mrview.def of
+ <<"_access/by-id-map">> ->
+ couch_mrview_util:get_access_row_count(View, Args#mrargs.start_key);
+ _Else ->
+ couch_mrview_util:get_row_count(View)
+ end,
+ couch_log:info("~n~n Total: ~p~n", [Total]),
Acc = #mracc{
db=Db,
total_rows=Total,
diff --git a/src/couch_mrview/src/couch_mrview_updater.erl b/src/couch_mrview/src/couch_mrview_updater.erl
index 3383b49b6..6d2c2842e 100644
--- a/src/couch_mrview/src/couch_mrview_updater.erl
+++ b/src/couch_mrview/src/couch_mrview_updater.erl
@@ -196,7 +196,18 @@ map_docs(Parent, #mrst{db_name = DbName, idx_name = IdxName} = State0) ->
{erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, []} | Results]};
({Id, Seq, Rev, Doc}, {SeqAcc, Results}) ->
couch_stats:increment_counter([couchdb, mrview, map_doc]),
- {ok, Res} = couch_query_servers:map_doc_raw(QServer, Doc),
+ % couch_log:info("~nIdxName: ~p, Doc: ~p~n~n", [IdxName, Doc]),
+ Doc0 = case IdxName of
+ <<"_design/_access">> ->
+ % splice in seq
+ {Props} = Doc#doc.body,
+ Doc#doc{
+ body = {Props++[{<<"_seq">>, Seq}]}
+ };
+ _Else ->
+ Doc
+ end,
+ {ok, Res} = couch_query_servers:map_doc_raw(QServer, Doc0),
{erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, Res} | Results]}
end,
FoldFun = fun(Docs, Acc) ->
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 4fd82e0af..63d389d37 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -20,6 +20,7 @@
-export([index_file/2, compaction_file/2, open_file/1]).
-export([delete_files/2, delete_index_file/2, delete_compaction_file/2]).
-export([get_row_count/1, all_docs_reduce_to_count/1, reduce_to_count/1]).
+-export([get_access_row_count/2]).
-export([get_view_changes_count/1]).
-export([all_docs_key_opts/1, all_docs_key_opts/2, key_opts/1, key_opts/2]).
-export([fold/4, fold_reduce/4]).
@@ -383,6 +384,11 @@ temp_view_to_ddoc({Props}) ->
]},
couch_doc:from_json_obj(DDoc).
+get_access_row_count(#mrview{btree=Bt}, UserName) ->
+ couch_btree:full_reduce_with_options(Bt, [
+ {start_key, UserName}
+ ]).
+
get_row_count(#mrview{btree=Bt}) ->
Count = case couch_btree:full_reduce(Bt) of