summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2017-02-01 15:15:09 -0600
committerPaul J. Davis <paul.joseph.davis@gmail.com>2017-04-06 12:30:40 -0500
commit8b682a14fa8729a5152362ffb37d54b8deeddfd6 (patch)
tree4fe2e824be38b652a658ef4b7989ae08f38938df
parent4086f6d9539ba74b66c001809794eae02f84374a (diff)
downloadcouchdb-COUCHDB-3288-remove-public-db-record.tar.gz
Remove public access to the db recordCOUCHDB-3288-remove-public-db-record
This completes the removal of public access to the db record from the couch application. The large majority of which is removing direct access to the #db.name, #db.main_pid, and #db.update_seq fields. COUCHDB-3288
-rw-r--r--src/chttpd/src/chttpd_db.erl21
-rw-r--r--src/chttpd/src/chttpd_external.erl22
-rw-r--r--src/chttpd/src/chttpd_show.erl3
-rw-r--r--src/couch/include/couch_db.hrl27
-rw-r--r--src/couch/src/couch_auth_cache.erl17
-rw-r--r--src/couch/src/couch_changes.erl56
-rw-r--r--src/couch/src/couch_compaction_daemon.erl4
-rw-r--r--src/couch/src/couch_db.erl55
-rw-r--r--src/couch/src/couch_db_int.hrl38
-rw-r--r--src/couch/src/couch_db_plugin.erl6
-rw-r--r--src/couch/src/couch_db_updater.erl1
-rw-r--r--src/couch/src/couch_httpd_db.erl12
-rw-r--r--src/couch/src/couch_users_db.erl8
-rw-r--r--src/couch/src/couch_util.erl15
-rw-r--r--src/couch/test/couch_auth_cache_tests.erl2
-rw-r--r--src/couch/test/couch_changes_tests.erl2
-rw-r--r--src/couch/test/couch_db_plugin_tests.erl13
-rw-r--r--src/couch/test/couch_server_tests.erl11
-rw-r--r--src/couch/test/couchdb_compaction_daemon_tests.erl2
-rw-r--r--src/couch/test/couchdb_views_tests.erl21
-rw-r--r--src/couch_index/src/couch_index_server.erl18
-rw-r--r--src/couch_index/src/couch_index_util.erl2
-rw-r--r--src/couch_index/test/couch_index_compaction_tests.erl3
-rw-r--r--src/couch_mrview/src/couch_mrview.erl14
-rw-r--r--src/couch_mrview/src/couch_mrview_compactor.erl7
-rw-r--r--src/couch_mrview/src/couch_mrview_http.erl10
-rw-r--r--src/couch_mrview/src/couch_mrview_show.erl16
-rw-r--r--src/couch_mrview/test/couch_mrview_all_docs_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_changes_since_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_collation_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_compact_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_ddoc_validation_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_index_changes_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_index_info_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_map_views_tests.erl2
-rw-r--r--src/couch_mrview/test/couch_mrview_red_views_tests.erl2
-rw-r--r--src/couch_replicator/src/couch_replicator.erl33
-rw-r--r--src/couch_replicator/src/couch_replicator_api_wrap.erl27
-rw-r--r--src/couch_replicator/src/couch_replicator_manager.erl8
-rw-r--r--src/couch_replicator/src/couch_replicator_utils.erl40
-rw-r--r--src/couch_replicator/src/couch_replicator_worker.erl56
-rw-r--r--src/couch_replicator/test/couch_replicator_compact_tests.erl27
-rw-r--r--src/fabric/include/couch_db_tmp.hrl296
-rw-r--r--src/fabric/src/fabric.erl12
-rw-r--r--src/fabric/src/fabric_rpc.erl113
-rw-r--r--src/fabric/src/fabric_util.erl3
-rw-r--r--src/mango/src/mango_crud.erl2
-rw-r--r--src/mango/src/mango_cursor_text.erl4
-rw-r--r--src/mango/src/mango_httpd.erl3
-rw-r--r--src/mango/src/mango_idx.erl6
-rw-r--r--src/mango/src/mango_idx_text.erl9
-rw-r--r--src/mem3/src/mem3.erl17
-rw-r--r--src/mem3/src/mem3_httpd.erl4
-rw-r--r--src/mem3/src/mem3_nodes.erl10
-rw-r--r--src/mem3/src/mem3_rep.erl12
-rw-r--r--src/mem3/src/mem3_rpc.erl4
-rw-r--r--src/mem3/src/mem3_shards.erl4
57 files changed, 440 insertions, 674 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 37e466908..aed649dc7 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -84,7 +84,7 @@ handle_changes_req1(#httpd{}=Req, Db) ->
#changes_args{filter=Raw, style=Style} = Args0 = parse_changes_query(Req),
ChangesArgs = Args0#changes_args{
filter_fun = couch_changes:configure_filter(Raw, Style, Req, Db),
- db_open_options = [{user_ctx, Db#db.user_ctx}]
+ db_open_options = [{user_ctx, couch_db:get_user_ctx(Db)}]
},
Max = chttpd:chunked_response_buffer_size(),
case ChangesArgs#changes_args.feed of
@@ -253,7 +253,7 @@ handle_view_cleanup_req(Req, Db) ->
handle_design_req(#httpd{
path_parts=[_DbName, _Design, Name, <<"_",_/binary>> = Action | _Rest]
}=Req, Db) ->
- DbName = mem3:dbname(Db#db.name),
+ DbName = mem3:dbname(couch_db:name(Db)),
case ddoc_cache:open(DbName, <<"_design/", Name/binary>>) of
{ok, DDoc} ->
Handler = chttpd_handlers:design_handler(Action, fun bad_action_req/3),
@@ -309,7 +309,8 @@ delete_db_req(#httpd{}=Req, DbName) ->
do_db_req(#httpd{path_parts=[DbName|_], user_ctx=Ctx}=Req, Fun) ->
fabric:get_security(DbName, [{user_ctx,Ctx}]), % calls check_is_reader
- Fun(Req, #db{name=DbName, user_ctx=Ctx}).
+ {ok, Db} = couch_db:clustered_db(DbName, Ctx),
+ Fun(Req, Db).
db_req(#httpd{method='GET',path_parts=[DbName]}=Req, _Db) ->
% measure the time required to generate the etag, see if it's worth it
@@ -767,16 +768,17 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) ->
} = parse_doc_query(Req),
couch_doc:validate_docid(DocId),
+ DbName = couch_db:name(Db),
W = chttpd:qs_value(Req, "w", integer_to_list(mem3:quorum(Db))),
Options = [{user_ctx,Ctx}, {w,W}],
- Loc = absolute_uri(Req, [$/, couch_util:url_encode(Db#db.name),
+ Loc = absolute_uri(Req, [$/, couch_util:url_encode(DbName),
$/, couch_util:url_encode(DocId)]),
RespHeaders = [{"Location", Loc}],
case couch_util:to_list(couch_httpd:header_value(Req, "Content-Type")) of
("multipart/related;" ++ _) = ContentType ->
couch_httpd:check_max_request_length(Req),
- couch_httpd_multipart:num_mp_writers(mem3:n(mem3:dbname(Db#db.name), DocId)),
+ couch_httpd_multipart:num_mp_writers(mem3:n(mem3:dbname(DbName), DocId)),
{ok, Doc0, WaitFun, Parser} = couch_doc:doc_from_multi_part_stream(ContentType,
fun() -> receive_request_data(Req) end),
Doc = couch_doc_from_req(Req, DocId, Doc0),
@@ -833,8 +835,9 @@ db_doc_req(#httpd{method='COPY', user_ctx=Ctx}=Req, Db, SourceDocId) ->
HttpCode = 202
end,
% respond
+ DbName = couch_db:name(Db),
{PartRes} = update_doc_result_to_json(TargetDocId, {ok, NewTargetRev}),
- Loc = absolute_uri(Req, "/" ++ couch_util:url_encode(Db#db.name) ++ "/" ++ couch_util:url_encode(TargetDocId)),
+ Loc = absolute_uri(Req, "/" ++ couch_util:url_encode(DbName) ++ "/" ++ couch_util:url_encode(TargetDocId)),
send_json(Req, HttpCode,
[{"Location", Loc},
{"ETag", "\"" ++ ?b2l(couch_doc:rev_to_str(NewTargetRev)) ++ "\""}],
@@ -1057,8 +1060,8 @@ couch_doc_from_req(Req, DocId, Json) ->
% couch_doc_open(Db, DocId) ->
% couch_doc_open(Db, DocId, nil, []).
-couch_doc_open(#db{} = Db, DocId, Rev, Options0) ->
- Options = [{user_ctx, Db#db.user_ctx} | Options0],
+couch_doc_open(Db, DocId, Rev, Options0) ->
+ Options = [{user_ctx, couch_db:get_user_ctx(Db)} | Options0],
case Rev of
nil -> % open most recent rev
case fabric:open_doc(Db, DocId, Options) of
@@ -1258,7 +1261,7 @@ db_attachment_req(#httpd{method=Method, user_ctx=Ctx}=Req, Db, DocId, FileNamePa
HttpCode = 202
end,
erlang:put(mochiweb_request_recv, true),
- #db{name=DbName} = Db,
+ DbName = couch_db:name(Db),
{Status, Headers} = case Method of
'DELETE' ->
diff --git a/src/chttpd/src/chttpd_external.erl b/src/chttpd/src/chttpd_external.erl
index 4abeecb37..64664b98e 100644
--- a/src/chttpd/src/chttpd_external.erl
+++ b/src/chttpd/src/chttpd_external.erl
@@ -120,16 +120,22 @@ json_req_obj_field(<<"secObj">>, #httpd{user_ctx=UserCtx}, Db, _DocId) ->
get_db_security(Db, UserCtx).
-get_db_info(#db{main_pid = nil} = Db) ->
- fabric:get_db_info(Db);
-get_db_info(#db{} = Db) ->
- couch_db:get_db_info(Db).
+get_db_info(Db) ->
+ case couch_db:is_clustered(Db) of
+ true ->
+ fabric:get_db_info(Db);
+ false ->
+ couch_db:get_db_info(Db)
+ end.
-get_db_security(#db{main_pid = nil}=Db, #user_ctx{}) ->
- fabric:get_security(Db);
-get_db_security(#db{}=Db, #user_ctx{}) ->
- couch_db:get_security(Db).
+get_db_security(Db, #user_ctx{}) ->
+ case couch_db:is_clustered(Db) of
+ true ->
+ fabric:get_security(Db);
+ false ->
+ couch_db:get_security(Db)
+ end.
to_json_terms(Data) ->
diff --git a/src/chttpd/src/chttpd_show.erl b/src/chttpd/src/chttpd_show.erl
index 49fed7b8d..0b45495d0 100644
--- a/src/chttpd/src/chttpd_show.erl
+++ b/src/chttpd/src/chttpd_show.erl
@@ -196,7 +196,8 @@ handle_view_list_req(Req, _Db, _DDoc) ->
handle_view_list(Req, Db, DDoc, LName, {ViewDesignName, ViewName}, Keys) ->
%% Will throw an exception if the _list handler is missing
couch_util:get_nested_json_value(DDoc#doc.body, [<<"lists">>, LName]),
- {ok, VDoc} = ddoc_cache:open(Db#db.name, <<"_design/", ViewDesignName/binary>>),
+ DbName = couch_db:name(Db),
+ {ok, VDoc} = ddoc_cache:open(DbName, <<"_design/", ViewDesignName/binary>>),
CB = fun couch_mrview_show:list_cb/2,
QueryArgs = couch_mrview_http:parse_params(Req, Keys),
Options = [{user_ctx, Req#httpd.user_ctx}],
diff --git a/src/couch/include/couch_db.hrl b/src/couch/include/couch_db.hrl
index e7cd85d09..5abb31660 100644
--- a/src/couch/include/couch_db.hrl
+++ b/src/couch/include/couch_db.hrl
@@ -128,33 +128,6 @@
handler
}).
--record(db, {
- main_pid = nil,
- compactor_pid = nil,
- instance_start_time, % number of microsecs since jan 1 1970 as a binary string
- fd,
- fd_monitor,
- header = couch_db_header:new(),
- committed_update_seq,
- id_tree,
- seq_tree,
- local_tree,
- update_seq,
- name,
- filepath,
- validate_doc_funs = undefined,
- security = [],
- security_ptr = nil,
- user_ctx = #user_ctx{},
- waiting_delayed_commit = nil,
- revs_limit = 1000,
- fsync_options = [],
- options = [],
- compression,
- before_doc_update = nil, % nil | fun(Doc, Db) -> NewDoc
- after_doc_read = nil % nil | fun(Doc, Db) -> NewDoc
-}).
-
-record(view_fold_helper_funs, {
reduce_count,
passed_end,
diff --git a/src/couch/src/couch_auth_cache.erl b/src/couch/src/couch_auth_cache.erl
index 9b00a9d84..54a67947b 100644
--- a/src/couch/src/couch_auth_cache.erl
+++ b/src/couch/src/couch_auth_cache.erl
@@ -289,8 +289,9 @@ reinit_cache(#state{db_mon_ref = Ref, closed = Closed} = State) ->
true = ets:insert(?STATE, {auth_db_name, AuthDbName}),
AuthDb = open_auth_db(),
true = ets:insert(?STATE, {auth_db, AuthDb}),
+ DbPid = couch_db:get_pid(AuthDb),
NewState#state{closed = [Ref|Closed],
- db_mon_ref = erlang:monitor(process, AuthDb#db.main_pid)}.
+ db_mon_ref = erlang:monitor(process, DbPid)}.
add_cache_entry(_, _, _, #state{max_cache_size = 0} = State) ->
@@ -331,13 +332,15 @@ refresh_entries(AuthDb) ->
nil ->
ok;
AuthDb2 ->
- case AuthDb2#db.update_seq > AuthDb#db.update_seq of
+ AuthDbSeq = couch_db:get_update_seq(AuthDb),
+ AuthDb2Seq = couch_db:get_update_seq(AuthDb2),
+ case AuthDb2Seq > AuthDbSeq of
true ->
{ok, _, _} = couch_db:enum_docs_since(
AuthDb2,
- AuthDb#db.update_seq,
+ AuthDbSeq,
fun(DocInfo, _, _) -> refresh_entry(AuthDb2, DocInfo) end,
- AuthDb#db.update_seq,
+ AuthDbSeq,
[]
),
true = ets:insert(?STATE, {auth_db, AuthDb2});
@@ -395,7 +398,9 @@ cache_needs_refresh() ->
nil ->
false;
AuthDb2 ->
- AuthDb2#db.update_seq > AuthDb#db.update_seq
+ AuthDbSeq = couch_db:get_update_seq(AuthDb),
+ AuthDb2Seq = couch_db:get_update_seq(AuthDb2),
+ AuthDb2Seq > AuthDbSeq
end
end,
false
@@ -416,7 +421,7 @@ exec_if_auth_db(Fun) ->
exec_if_auth_db(Fun, DefRes) ->
case ets:lookup(?STATE, auth_db) of
- [{auth_db, #db{} = AuthDb}] ->
+ [{auth_db, AuthDb}] ->
Fun(AuthDb);
_ ->
DefRes
diff --git a/src/couch/src/couch_changes.erl b/src/couch/src/couch_changes.erl
index 52ff39ded..ea7f65c63 100644
--- a/src/couch/src/couch_changes.erl
+++ b/src/couch/src/couch_changes.erl
@@ -78,9 +78,10 @@ handle_changes(Args1, Req, Db0, Type) ->
_ ->
{false, undefined, undefined}
end,
+ DbName = couch_db:name(Db0),
{StartListenerFun, View} = if UseViewChanges ->
{ok, {_, View0, _}, _, _} = couch_mrview_util:get_view(
- Db0#db.name, DDocName, ViewName, #mrargs{}),
+ DbName, DDocName, ViewName, #mrargs{}),
case View0#mrview.seq_btree of
#btree{} ->
ok;
@@ -89,14 +90,14 @@ handle_changes(Args1, Req, Db0, Type) ->
end,
SNFun = fun() ->
couch_event:link_listener(
- ?MODULE, handle_view_event, {self(), DDocName}, [{dbname, Db0#db.name}]
+ ?MODULE, handle_view_event, {self(), DDocName}, [{dbname, DbName}]
)
end,
{SNFun, View0};
true ->
SNFun = fun() ->
couch_event:link_listener(
- ?MODULE, handle_db_event, self(), [{dbname, Db0#db.name}]
+ ?MODULE, handle_db_event, self(), [{dbname, DbName}]
)
end,
{SNFun, undefined}
@@ -111,7 +112,7 @@ handle_changes(Args1, Req, Db0, Type) ->
end,
View2 = if UseViewChanges ->
{ok, {_, View1, _}, _, _} = couch_mrview_util:get_view(
- Db0#db.name, DDocName, ViewName, #mrargs{}),
+ DbName, DDocName, ViewName, #mrargs{}),
View1;
true ->
undefined
@@ -219,11 +220,11 @@ configure_filter("_view", Style, Req, Db) ->
catch _:_ ->
view
end,
- case Db#db.id_tree of
- undefined ->
+ case couch_db:is_clustered(Db) of
+ true ->
DIR = fabric_util:doc_id_and_rev(DDoc),
{fetch, FilterType, Style, DIR, VName};
- _ ->
+ false ->
{FilterType, Style, DDoc, VName}
end;
[] ->
@@ -242,11 +243,11 @@ configure_filter(FilterName, Style, Req, Db) ->
[DName, FName] ->
{ok, DDoc} = open_ddoc(Db, <<"_design/", DName/binary>>),
check_member_exists(DDoc, [<<"filters">>, FName]),
- case Db#db.id_tree of
- undefined ->
+ case couch_db:is_clustered(Db) of
+ true ->
DIR = fabric_util:doc_id_and_rev(DDoc),
{fetch, custom, Style, Req, DIR, FName};
- _ ->
+ false->
{custom, Style, Req, DDoc, FName}
end;
@@ -395,15 +396,19 @@ check_fields(_Fields) ->
throw({bad_request, "Selector error: fields must be JSON array"}).
-open_ddoc(#db{name=DbName, id_tree=undefined}, DDocId) ->
- case ddoc_cache:open_doc(mem3:dbname(DbName), DDocId) of
- {ok, _} = Resp -> Resp;
- Else -> throw(Else)
- end;
open_ddoc(Db, DDocId) ->
- case couch_db:open_doc(Db, DDocId, [ejson_body]) of
- {ok, _} = Resp -> Resp;
- Else -> throw(Else)
+ DbName = couch_db:name(Db),
+ case couch_db:is_clustered(Db) of
+ true ->
+ case ddoc_cache:open_doc(mem3:dbname(DbName), DDocId) of
+ {ok, _} = Resp -> Resp;
+ Else -> throw(Else)
+ end;
+ false ->
+ case couch_db:open_doc(Db, DDocId, [ejson_body]) of
+ {ok, _} = Resp -> Resp;
+ Else -> throw(Else)
+ end
end.
@@ -566,7 +571,7 @@ can_optimize(_, _) ->
send_changes_doc_ids(Db, StartSeq, Dir, Fun, Acc0, {doc_ids, _Style, DocIds}) ->
- Lookups = couch_btree:lookup(Db#db.id_tree, DocIds),
+ Lookups = couch_db:get_full_doc_infos(Db, DocIds),
FullInfos = lists:foldl(fun
({ok, FDI}, Acc) -> [FDI | Acc];
(not_found, Acc) -> Acc
@@ -575,11 +580,9 @@ send_changes_doc_ids(Db, StartSeq, Dir, Fun, Acc0, {doc_ids, _Style, DocIds}) ->
send_changes_design_docs(Db, StartSeq, Dir, Fun, Acc0, {design_docs, _Style}) ->
- FoldFun = fun(FullDocInfo, _, Acc) ->
- {ok, [FullDocInfo | Acc]}
- end,
+ FoldFun = fun(FDI, Acc) -> {ok, [FDI | Acc]} end,
KeyOpts = [{start_key, <<"_design/">>}, {end_key_gt, <<"_design0">>}],
- {ok, _, FullInfos} = couch_btree:fold(Db#db.id_tree, FoldFun, [], KeyOpts),
+ {ok, FullInfos} = couch_db:fold_docs(Db, FoldFun, [], KeyOpts),
send_lookup_changes(FullInfos, StartSeq, Dir, Db, Fun, Acc0).
@@ -640,8 +643,8 @@ keep_sending_changes(Args, Acc0, FirstRound) ->
true ->
case wait_updated(Timeout, TimeoutFun, UserAcc2) of
{updated, UserAcc4} ->
- DbOptions1 = [{user_ctx, Db#db.user_ctx} | DbOptions],
- case couch_db:open(Db#db.name, DbOptions1) of
+ DbOptions1 = [{user_ctx, couch_db:get_user_ctx(Db)} | DbOptions],
+ case couch_db:open(couch_db:name(Db), DbOptions1) of
{ok, Db2} ->
keep_sending_changes(
Args#changes_args{limit=NewLimit},
@@ -665,7 +668,8 @@ keep_sending_changes(Args, Acc0, FirstRound) ->
maybe_refresh_view(_, undefined, undefined) ->
undefined;
maybe_refresh_view(Db, DDocName, ViewName) ->
- {ok, {_, View, _}, _, _} = couch_mrview_util:get_view(Db#db.name, DDocName, ViewName, #mrargs{}),
+ DbName = couch_db:name(Db),
+ {ok, {_, View, _}, _, _} = couch_mrview_util:get_view(DbName, DDocName, ViewName, #mrargs{}),
View.
end_sending_changes(Callback, UserAcc, EndSeq, ResponseType) ->
diff --git a/src/couch/src/couch_compaction_daemon.erl b/src/couch/src/couch_compaction_daemon.erl
index 8f95eb21e..f3b646d29 100644
--- a/src/couch/src/couch_compaction_daemon.erl
+++ b/src/couch/src/couch_compaction_daemon.erl
@@ -319,7 +319,7 @@ can_db_compact(#config{db_frag = Threshold} = Config, Db) ->
{Frag, SpaceRequired} = frag(DbInfo),
couch_log:debug("Fragmentation for database `~s` is ~p%, estimated"
" space for compaction is ~p bytes.",
- [Db#db.name, Frag, SpaceRequired]),
+ [couch_db:name(Db), Frag, SpaceRequired]),
case check_frag(Threshold, Frag) of
false ->
false;
@@ -332,7 +332,7 @@ can_db_compact(#config{db_frag = Threshold} = Config, Db) ->
couch_log:warning("Compaction daemon - skipping database `~s` "
"compaction: the estimated necessary disk space is about ~p"
" bytes but the currently available disk space is ~p bytes.",
- [Db#db.name, SpaceRequired, Free]),
+ [couch_db:name(Db), SpaceRequired, Free]),
false
end
end
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 3a29a3d63..75fc7306e 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -22,6 +22,9 @@
incref/1,
decref/1,
+ clustered_db/2,
+ clustered_db/3,
+
monitor/1,
monitored_by/1,
is_idle/1,
@@ -32,21 +35,28 @@
name/1,
compression/1,
+ get_after_doc_read_fun/1,
+ get_before_doc_update_fun/1,
get_committed_update_seq/1,
get_compacted_seq/1,
+ get_compactor_pid/1,
get_db_info/1,
get_doc_count/1,
get_epochs/1,
+ get_filepath/1,
get_instance_start_time/1,
get_last_purged/1,
get_pid/1,
get_revs_limit/1,
get_security/1,
get_update_seq/1,
+ get_user_ctx/1,
get_uuid/1,
get_purge_seq/1,
+ is_db/1,
is_system_db/1,
+ is_clustered/1,
increment_update_seq/1,
set_revs_limit/2,
@@ -80,6 +90,8 @@
with_stream/3,
+ fold_docs/4,
+ fold_local_docs/4,
enum_docs/4,
enum_docs_reduce_to_count/1,
@@ -113,6 +125,7 @@
-include_lib("couch/include/couch_db.hrl").
+-include("couch_db_int.hrl").
-define(DBNAME_REGEX,
"^[a-z][a-z0-9\\_\\$()\\+\\-\\/]*" % use the stock CouchDB regex
@@ -187,6 +200,12 @@ reopen(#db{main_pid = Pid, fd = Fd, fd_monitor = OldRef, user_ctx = UserCtx}) ->
{ok, NewDb#db{user_ctx = UserCtx, fd_monitor = NewRef}}
end.
+clustered_db(DbName, UserCtx) ->
+ clustered_db(DbName, UserCtx, []).
+
+clustered_db(DbName, UserCtx, SecProps) ->
+ {ok, #db{name = DbName, user_ctx = UserCtx, security = SecProps}}.
+
incref(#db{fd = Fd} = Db) ->
Ref = erlang:monitor(process, Fd),
{ok, Db#db{fd_monitor = Ref}}.
@@ -195,9 +214,19 @@ decref(#db{fd_monitor = Monitor}) ->
erlang:demonitor(Monitor, [flush]),
ok.
+is_db(#db{}) ->
+ true;
+is_db(_) ->
+ false.
+
is_system_db(#db{options = Options}) ->
lists:member(sys_db, Options).
+is_clustered(#db{main_pid = nil}) ->
+ true;
+is_clustered(#db{}) ->
+ false.
+
ensure_full_commit(#db{main_pid=Pid, instance_start_time=StartTime}) ->
ok = gen_server:call(Pid, full_commit, infinity),
{ok, StartTime}.
@@ -378,12 +407,21 @@ increment_update_seq(#db{main_pid=Pid}) ->
purge_docs(#db{main_pid=Pid}, IdsRevs) ->
gen_server:call(Pid, {purge_docs, IdsRevs}).
+get_after_doc_read_fun(#db{after_doc_read = Fun}) ->
+ Fun.
+
+get_before_doc_update_fun(#db{before_doc_update = Fun}) ->
+ Fun.
+
get_committed_update_seq(#db{committed_update_seq=Seq}) ->
Seq.
get_update_seq(#db{update_seq=Seq})->
Seq.
+get_user_ctx(#db{user_ctx = UserCtx}) ->
+ UserCtx.
+
get_purge_seq(#db{}=Db) ->
couch_db_header:purge_seq(Db#db.header).
@@ -410,12 +448,18 @@ get_epochs(#db{}=Db) ->
validate_epochs(Epochs),
Epochs.
+get_filepath(#db{filepath = FilePath}) ->
+ FilePath.
+
get_instance_start_time(#db{instance_start_time = IST}) ->
IST.
get_compacted_seq(#db{}=Db) ->
couch_db_header:compacted_seq(Db#db.header).
+get_compactor_pid(#db{compactor_pid = Pid}) ->
+ Pid.
+
get_db_info(Db) ->
#db{fd=Fd,
header=Header,
@@ -1365,6 +1409,17 @@ enum_docs_since(Db, SinceSeq, InFun, Acc, Options) ->
[{start_key, SinceSeq + 1} | Options]),
{ok, enum_docs_since_reduce_to_count(LastReduction), AccOut}.
+
+fold_docs(Db, InFun, InAcc, Opts) ->
+ Wrapper = fun(FDI, _, Acc) -> InFun(FDI, Acc) end,
+ {ok, _, AccOut} = couch_btree:fold(Db#db.id_tree, Wrapper, InAcc, Opts),
+ {ok, AccOut}.
+
+fold_local_docs(Db, InFun, InAcc, Opts) ->
+ Wrapper = fun(FDI, _, Acc) -> InFun(FDI, Acc) end,
+ {ok, _, AccOut} = couch_btree:fold(Db#db.local_tree, Wrapper, InAcc, Opts),
+ {ok, AccOut}.
+
enum_docs(Db, InFun, InAcc, Options0) ->
{NS, Options} = extract_namespace(Options0),
enum_docs(Db, NS, InFun, InAcc, Options).
diff --git a/src/couch/src/couch_db_int.hrl b/src/couch/src/couch_db_int.hrl
new file mode 100644
index 000000000..fc739b781
--- /dev/null
+++ b/src/couch/src/couch_db_int.hrl
@@ -0,0 +1,38 @@
+% 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.
+
+-record(db, {
+ main_pid = nil,
+ compactor_pid = nil,
+ instance_start_time, % number of microsecs since jan 1 1970 as a binary string
+ fd,
+ fd_monitor,
+ header = couch_db_header:new(),
+ committed_update_seq,
+ id_tree,
+ seq_tree,
+ local_tree,
+ update_seq,
+ name,
+ filepath,
+ validate_doc_funs = undefined,
+ security = [],
+ security_ptr = nil,
+ user_ctx = #user_ctx{},
+ waiting_delayed_commit = nil,
+ revs_limit = 1000,
+ fsync_options = [],
+ options = [],
+ compression,
+ before_doc_update = nil, % nil | fun(Doc, Db) -> NewDoc
+ after_doc_read = nil % nil | fun(Doc, Db) -> NewDoc
+}). \ No newline at end of file
diff --git a/src/couch/src/couch_db_plugin.erl b/src/couch/src/couch_db_plugin.erl
index 774e9e094..740b8121b 100644
--- a/src/couch/src/couch_db_plugin.erl
+++ b/src/couch/src/couch_db_plugin.erl
@@ -32,13 +32,15 @@
validate_dbname(DbName, Normalized, Default) ->
maybe_handle(validate_dbname, [DbName, Normalized], Default).
-before_doc_update(#db{before_doc_update = Fun} = Db, Doc0) ->
+before_doc_update(Db, Doc0) ->
+ Fun = couch_db:get_before_doc_update_fun(Db),
case with_pipe(before_doc_update, [Doc0, Db]) of
[Doc1, _Db] when is_function(Fun) -> Fun(Doc1, Db);
[Doc1, _Db] -> Doc1
end.
-after_doc_read(#db{after_doc_read = Fun} = Db, Doc0) ->
+after_doc_read(Db, Doc0) ->
+ Fun = couch_db:get_after_doc_read_fun(Db),
case with_pipe(after_doc_read, [Doc0, Db]) of
[Doc1, _Db] when is_function(Fun) -> Fun(Doc1, Db);
[Doc1, _Db] -> Doc1
diff --git a/src/couch/src/couch_db_updater.erl b/src/couch/src/couch_db_updater.erl
index 270fffe46..8f6fc352f 100644
--- a/src/couch/src/couch_db_updater.erl
+++ b/src/couch/src/couch_db_updater.erl
@@ -20,6 +20,7 @@
-export([init/1,terminate/2,handle_call/3,handle_cast/2,code_change/3,handle_info/2]).
-include_lib("couch/include/couch_db.hrl").
+-include("couch_db_int.hrl").
-record(comp_header, {
db_header,
diff --git a/src/couch/src/couch_httpd_db.erl b/src/couch/src/couch_httpd_db.erl
index e1af1bfdc..1198a6786 100644
--- a/src/couch/src/couch_httpd_db.erl
+++ b/src/couch/src/couch_httpd_db.erl
@@ -70,7 +70,8 @@ handle_changes_req(#httpd{method='GET'}=Req, Db, ChangesArgs, ChangesFun) ->
handle_changes_req(#httpd{}=Req, _Db, _ChangesArgs, _ChangesFun) ->
couch_httpd:send_method_not_allowed(Req, "GET,HEAD,POST").
-handle_changes_req1(Req, #db{name=DbName}=Db, ChangesArgs, ChangesFun) ->
+handle_changes_req1(Req, Db, ChangesArgs, ChangesFun) ->
+ DbName = couch_db:name(Db),
AuthDbName = ?l2b(config:get("couch_httpd_auth", "authentication_db")),
case AuthDbName of
DbName ->
@@ -287,7 +288,7 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_ensure_full_commit">>]}=Req, Db) -
RequiredSeq > CommittedSeq ->
couch_db:ensure_full_commit(Db);
true ->
- {ok, Db#db.instance_start_time}
+ {ok, couch_db:get_instance_start_time(Db)}
end
end,
send_json(Req, 201, {[
@@ -733,7 +734,8 @@ update_doc_result_to_json(DocId, Error) ->
update_doc(Req, Db, DocId, #doc{deleted=false}=Doc) ->
- Loc = absolute_uri(Req, "/" ++ couch_util:url_encode(Db#db.name) ++ "/" ++ couch_util:url_encode(DocId)),
+ DbName = couch_db:name(Db),
+ Loc = absolute_uri(Req, "/" ++ couch_util:url_encode(DbName) ++ "/" ++ couch_util:url_encode(DocId)),
update_doc(Req, Db, DocId, Doc, [{"Location", Loc}]);
update_doc(Req, Db, DocId, Doc) ->
update_doc(Req, Db, DocId, Doc, []).
@@ -1033,7 +1035,7 @@ db_attachment_req(#httpd{method=Method,mochi_req=MochiReq}=Req, Db, DocId, FileN
[];
_ ->
[{"Location", absolute_uri(Req, "/" ++
- couch_util:url_encode(Db#db.name) ++ "/" ++
+ couch_util:url_encode(couch_db:name(Db)) ++ "/" ++
couch_util:url_encode(DocId) ++ "/" ++
couch_util:url_encode(FileName)
)}]
@@ -1145,7 +1147,7 @@ parse_changes_query(Req, Db) ->
{"descending", "true"} ->
Args#changes_args{dir=rev};
{"since", "now"} ->
- UpdateSeq = couch_util:with_db(Db#db.name, fun(WDb) ->
+ UpdateSeq = couch_util:with_db(couch_db:name(Db), fun(WDb) ->
couch_db:get_update_seq(WDb)
end),
Args#changes_args{since=UpdateSeq};
diff --git a/src/couch/src/couch_users_db.erl b/src/couch/src/couch_users_db.erl
index 6f7b9af73..c7b41f1fc 100644
--- a/src/couch/src/couch_users_db.erl
+++ b/src/couch/src/couch_users_db.erl
@@ -39,8 +39,8 @@
% -> 404 // Not Found
% Else
% -> save_doc
-before_doc_update(Doc, #db{user_ctx = UserCtx} = Db) ->
- #user_ctx{name=Name} = UserCtx,
+before_doc_update(Doc, Db) ->
+ #user_ctx{name=Name} = couch_db:get_user_ctx(Db),
DocName = get_doc_name(Doc),
case (catch couch_db:check_is_admin(Db)) of
ok ->
@@ -108,8 +108,8 @@ after_doc_read(#doc{id = <<?DESIGN_DOC_PREFIX, _/binary>>} = Doc, Db) ->
throw({forbidden,
<<"Only administrators can view design docs in the users database.">>})
end;
-after_doc_read(Doc, #db{user_ctx = UserCtx} = Db) ->
- #user_ctx{name=Name} = UserCtx,
+after_doc_read(Doc, Db) ->
+ #user_ctx{name=Name} = couch_db:get_user_ctx(Db),
DocName = get_doc_name(Doc),
case (catch couch_db:check_is_admin(Db)) of
ok ->
diff --git a/src/couch/src/couch_util.erl b/src/couch/src/couch_util.erl
index 6001ae2e4..d688c126f 100644
--- a/src/couch/src/couch_util.erl
+++ b/src/couch/src/couch_util.erl
@@ -198,7 +198,9 @@ json_apply_field({Key, NewValue}, [{OtherKey, OtherVal} | Headers], Acc) ->
json_apply_field({Key, NewValue}, [], Acc) ->
{[{Key, NewValue}|Acc]}.
-json_user_ctx(#db{name=ShardName, user_ctx=Ctx}) ->
+json_user_ctx(Db) ->
+ ShardName = couch_db:name(Db),
+ Ctx = couch_db:get_user_ctx(Db),
{[{<<"db">>, mem3:dbname(ShardName)},
{<<"name">>,Ctx#user_ctx.name},
{<<"roles">>,Ctx#user_ctx.roles}]}.
@@ -455,9 +457,7 @@ encode_doc_id(Id) ->
url_encode(Id).
-with_db(Db, Fun) when is_record(Db, db) ->
- Fun(Db);
-with_db(DbName, Fun) ->
+with_db(DbName, Fun) when is_binary(DbName) ->
case couch_db:open_int(DbName, [?ADMIN_CTX]) of
{ok, Db} ->
try
@@ -467,6 +467,13 @@ with_db(DbName, Fun) ->
end;
Else ->
throw(Else)
+ end;
+with_db(Db, Fun) ->
+ case couch_db:is_db(Db) of
+ true ->
+ Fun(Db);
+ false ->
+ erlang:error({invalid_db, Db})
end.
rfc1123_date() ->
diff --git a/src/couch/test/couch_auth_cache_tests.erl b/src/couch/test/couch_auth_cache_tests.erl
index 76179dea0..08aecd156 100644
--- a/src/couch/test/couch_auth_cache_tests.erl
+++ b/src/couch/test/couch_auth_cache_tests.erl
@@ -265,7 +265,7 @@ hash_password(Password) ->
shutdown_db(DbName) ->
{ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_CTX]),
ok = couch_db:close(AuthDb),
- couch_util:shutdown_sync(AuthDb#db.main_pid),
+ couch_util:shutdown_sync(couch_db:get_pid(AuthDb)),
ok = timer:sleep(1000).
get_doc_rev(DbName, UserName) ->
diff --git a/src/couch/test/couch_changes_tests.erl b/src/couch/test/couch_changes_tests.erl
index 3c0e5f69a..494d90fe3 100644
--- a/src/couch/test/couch_changes_tests.erl
+++ b/src/couch/test/couch_changes_tests.erl
@@ -645,7 +645,7 @@ should_filter_by_user_ctx({DbName, _}) ->
]}),
ChArgs = #changes_args{filter = "app/valid"},
UserCtx = #user_ctx{name = <<"doc3">>, roles = []},
- DbRec = #db{name = DbName, user_ctx = UserCtx},
+ {ok, DbRec} = couch_db:clustered_db(DbName, UserCtx),
Req = {json_req, {[{
<<"userCtx">>, couch_util:json_user_ctx(DbRec)
}]}},
diff --git a/src/couch/test/couch_db_plugin_tests.erl b/src/couch/test/couch_db_plugin_tests.erl
index ea9b230b1..94dd3dfa5 100644
--- a/src/couch/test/couch_db_plugin_tests.erl
+++ b/src/couch/test/couch_db_plugin_tests.erl
@@ -43,6 +43,7 @@ data_providers() -> [].
data_subscriptions() -> [].
processes() -> [].
notify(_, _, _) -> ok.
+fake_db() -> element(2, couch_db:clustered_db(fake, totes_fake)).
setup() ->
couch_tests:setup([
@@ -133,33 +134,33 @@ validate_dbname_pass() ->
before_doc_update_match() ->
?assertMatch(
{true, [before_doc_update, doc]},
- couch_db_plugin:before_doc_update(#db{}, {true, [doc]})).
+ couch_db_plugin:before_doc_update(fake_db(), {true, [doc]})).
before_doc_update_no_match() ->
?assertMatch(
{false, [doc]},
- couch_db_plugin:before_doc_update(#db{}, {false, [doc]})).
+ couch_db_plugin:before_doc_update(fake_db(), {false, [doc]})).
before_doc_update_throw() ->
?assertThrow(
before_doc_update,
- couch_db_plugin:before_doc_update(#db{}, {fail, [doc]})).
+ couch_db_plugin:before_doc_update(fake_db(), {fail, [doc]})).
after_doc_read_match() ->
?assertMatch(
{true, [after_doc_read, doc]},
- couch_db_plugin:after_doc_read(#db{}, {true, [doc]})).
+ couch_db_plugin:after_doc_read(fake_db(), {true, [doc]})).
after_doc_read_no_match() ->
?assertMatch(
{false, [doc]},
- couch_db_plugin:after_doc_read(#db{}, {false, [doc]})).
+ couch_db_plugin:after_doc_read(fake_db(), {false, [doc]})).
after_doc_read_throw() ->
?assertThrow(
after_doc_read,
- couch_db_plugin:after_doc_read(#db{}, {fail, [doc]})).
+ couch_db_plugin:after_doc_read(fake_db(), {fail, [doc]})).
validate_docid_match() ->
diff --git a/src/couch/test/couch_server_tests.erl b/src/couch/test/couch_server_tests.erl
index c8f8381d7..4fd7ff2ab 100644
--- a/src/couch/test/couch_server_tests.erl
+++ b/src/couch/test/couch_server_tests.erl
@@ -32,8 +32,7 @@ setup(_) ->
setup().
teardown(Db) ->
- (catch couch_db:close(Db)),
- (catch file:delete(Db#db.filepath)).
+ (catch couch_db:close(Db)).
teardown(rename, Db) ->
config:set("couchdb", "enable_database_recovery", "false", false),
@@ -61,7 +60,9 @@ make_test_case(Mod, Funs) ->
{foreachx, fun setup/1, fun teardown/2, [{Mod, Fun} || Fun <- Funs]}
}.
-should_rename_on_delete(_, #db{filepath = Origin, name = DbName}) ->
+should_rename_on_delete(_, Db) ->
+ DbName = couch_db:name(Db),
+ Origin = couch_db:get_filepath(Db),
?_test(begin
?assert(filelib:is_regular(Origin)),
?assertMatch(ok, couch_server:delete(DbName, [])),
@@ -74,7 +75,9 @@ should_rename_on_delete(_, #db{filepath = Origin, name = DbName}) ->
?assert(filelib:is_regular(Renamed))
end).
-should_delete(_, #db{filepath = Origin, name = DbName}) ->
+should_delete(_, Db) ->
+ DbName = couch_db:name(Db),
+ Origin = couch_db:get_filepath(Db),
?_test(begin
?assert(filelib:is_regular(Origin)),
?assertMatch(ok, couch_server:delete(DbName, [])),
diff --git a/src/couch/test/couchdb_compaction_daemon_tests.erl b/src/couch/test/couchdb_compaction_daemon_tests.erl
index 25d9b131e..70e505e91 100644
--- a/src/couch/test/couchdb_compaction_daemon_tests.erl
+++ b/src/couch/test/couchdb_compaction_daemon_tests.erl
@@ -182,7 +182,7 @@ update(DbName) ->
lists:foreach(fun(_) ->
Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
{ok, _} = couch_db:update_docs(Db, [Doc]),
- query_view(Db#db.name)
+ query_view(couch_db:name(Db))
end, lists:seq(1, 200)),
couch_db:close(Db).
diff --git a/src/couch/test/couchdb_views_tests.erl b/src/couch/test/couchdb_views_tests.erl
index f1fddfc1b..02e9d7211 100644
--- a/src/couch/test/couchdb_views_tests.erl
+++ b/src/couch/test/couchdb_views_tests.erl
@@ -340,7 +340,7 @@ couchdb_1283() ->
]}),
{ok, _} = couch_db:update_doc(MDb1, DDoc, []),
ok = populate_db(MDb1, 100, 100),
- query_view(MDb1#db.name, "foo", "foo"),
+ query_view(couch_db:name(MDb1), "foo", "foo"),
ok = couch_db:close(MDb1),
{ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_CTX]),
@@ -350,8 +350,8 @@ couchdb_1283() ->
{ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_CTX]),
ok = couch_db:close(Db3),
- Writer1 = spawn_writer(Db1#db.name),
- Writer2 = spawn_writer(Db2#db.name),
+ Writer1 = spawn_writer(couch_db:name(Db1)),
+ Writer2 = spawn_writer(couch_db:name(Db2)),
?assert(is_process_alive(Writer1)),
?assert(is_process_alive(Writer2)),
@@ -361,16 +361,16 @@ couchdb_1283() ->
%% Below we do exactly the same as couch_mrview:compact holds inside
%% because we need have access to compaction Pid, not a Ref.
- %% {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
+ %% {ok, MonRef} = couch_mrview:compact(MDb1, <<"_design/foo">>,
%% [monitor]),
{ok, Pid} = couch_index_server:get_index(
- couch_mrview_index, MDb1#db.name, <<"_design/foo">>),
+ couch_mrview_index, couch_db:name(MDb1), <<"_design/foo">>),
{ok, CPid} = gen_server:call(Pid, compact),
%% By suspending compaction process we ensure that compaction won't get
%% finished too early to make get_writer_status assertion fail.
erlang:suspend_process(CPid),
MonRef = erlang:monitor(process, CPid),
- Writer3 = spawn_writer(Db3#db.name),
+ Writer3 = spawn_writer(couch_db:name(Db3)),
?assert(is_process_alive(Writer3)),
?assert(is_process_alive(Writer1)),
@@ -526,7 +526,8 @@ view_cleanup(DbName) ->
count_users(DbName) ->
{ok, Db} = couch_db:open_int(DbName, [?ADMIN_CTX]),
- {monitored_by, Monitors} = erlang:process_info(Db#db.main_pid, monitored_by),
+ DbPid = couch_db:get_pid(Db),
+ {monitored_by, Monitors} = erlang:process_info(DbPid, monitored_by),
CouchFiles = [P || P <- Monitors, couch_file:process_info(P) =/= undefined],
ok = couch_db:close(Db),
length(lists:usort(Monitors) -- [self() | CouchFiles]).
@@ -552,7 +553,8 @@ restore_backup_db_file(DbName) ->
{ok, Db} = couch_db:open_int(DbName, []),
ok = couch_db:close(Db),
- exit(Db#db.main_pid, shutdown),
+ DbPid = couch_db:get_pid(Db),
+ exit(DbPid, shutdown),
DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
ok = file:delete(DbFile),
@@ -573,7 +575,8 @@ wait_db_compact_done(_DbName, 0) ->
wait_db_compact_done(DbName, N) ->
{ok, Db} = couch_db:open_int(DbName, []),
ok = couch_db:close(Db),
- case is_pid(Db#db.compactor_pid) of
+ CompactorPid = couch_db:get_compactor_pid(Db),
+ case is_pid(CompactorPid) of
false ->
ok;
true ->
diff --git a/src/couch_index/src/couch_index_server.erl b/src/couch_index/src/couch_index_server.erl
index 4e86f5e80..cbdfbe746 100644
--- a/src/couch_index/src/couch_index_server.erl
+++ b/src/couch_index/src/couch_index_server.erl
@@ -60,14 +60,13 @@ validate(DbName, DDoc) ->
lists:foreach(ValidateFun, EnabledIndexers).
-get_index(Module, #db{name = <<"shards/", _/binary>> = DbName}, DDoc) ->
- case is_record(DDoc, doc) of
- true -> get_index(Module, DbName, DDoc, nil);
- false -> get_index(Module, DbName, DDoc)
- end;
+get_index(Module, <<"shards/", _/binary>> = DbName, DDoc)
+ when is_binary(DbName), is_record(DDoc, doc) ->
+ get_index(Module, DbName, DDoc, nil);
get_index(Module, <<"shards/", _/binary>> = DbName, DDoc) ->
{Pid, Ref} = spawn_monitor(fun() ->
- exit(fabric:open_doc(mem3:dbname(DbName), DDoc, [ejson_body, ?ADMIN_CTX]))
+ OpenOpts = [ejson_body, ?ADMIN_CTX],
+ exit(fabric:open_doc(mem3:dbname(DbName), DDoc, OpenOpts))
end),
receive {'DOWN', Ref, process, Pid, {ok, Doc}} ->
get_index(Module, DbName, Doc, nil);
@@ -77,9 +76,10 @@ get_index(Module, <<"shards/", _/binary>> = DbName, DDoc) ->
erlang:demonitor(Ref, [flush]),
{error, timeout}
end;
-
-get_index(Module, DbName, DDoc) ->
- get_index(Module, DbName, DDoc, nil).
+get_index(Module, DbName, DDoc) when is_binary(DbName) ->
+ get_index(Module, DbName, DDoc, nil);
+get_index(Module, Db, DDoc) ->
+ get_index(Module, couch_db:name(Db), DDoc).
get_index(Module, DbName, DDoc, Fun) when is_binary(DbName) ->
diff --git a/src/couch_index/src/couch_index_util.erl b/src/couch_index/src/couch_index_util.erl
index 5694641ca..dcb33b5b0 100644
--- a/src/couch_index/src/couch_index_util.erl
+++ b/src/couch_index/src/couch_index_util.erl
@@ -25,7 +25,7 @@ root_dir() ->
index_dir(Module, DbName) when is_binary(DbName) ->
DbDir = "." ++ binary_to_list(DbName) ++ "_design",
filename:join([root_dir(), DbDir, Module]);
-index_dir(Module, #db{}=Db) ->
+index_dir(Module, Db) ->
index_dir(Module, couch_db:name(Db)).
diff --git a/src/couch_index/test/couch_index_compaction_tests.erl b/src/couch_index/test/couch_index_compaction_tests.erl
index 0787151ae..18dd9ffe5 100644
--- a/src/couch_index/test/couch_index_compaction_tests.erl
+++ b/src/couch_index/test/couch_index_compaction_tests.erl
@@ -23,7 +23,8 @@ setup() ->
?assertNot(is_opened(Db)),
{Db, IndexerPid}.
-fake_index(#db{name = DbName} = Db) ->
+fake_index(Db) ->
+ DbName = couch_db:name(Db),
ok = meck:new([test_index], [non_strict]),
ok = meck:expect(test_index, init, ['_', '_'], {ok, 10}),
ok = meck:expect(test_index, open, fun(_Db, State) ->
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 088327c45..0f207fb5c 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -360,15 +360,12 @@ get_view_info(Db, DDoc, VName) ->
%% @doc refresh a view index
-refresh(#db{name=DbName}, DDoc) ->
- refresh(DbName, DDoc);
-
-refresh(Db, DDoc) ->
- UpdateSeq = couch_util:with_db(Db, fun(WDb) ->
+refresh(DbName, DDoc) when is_binary(DbName)->
+ UpdateSeq = couch_util:with_db(DbName, fun(WDb) ->
couch_db:get_update_seq(WDb)
end),
- case couch_index_server:get_index(couch_mrview_index, Db, DDoc) of
+ case couch_index_server:get_index(couch_mrview_index, DbName, DDoc) of
{ok, Pid} ->
case catch couch_index:get_state(Pid, UpdateSeq) of
{ok, _} -> ok;
@@ -376,7 +373,10 @@ refresh(Db, DDoc) ->
end;
Error ->
{error, Error}
- end.
+ end;
+
+refresh(Db, DDoc) ->
+ refresh(couch_db:name(Db), DDoc).
compact(Db, DDoc) ->
compact(Db, DDoc, []).
diff --git a/src/couch_mrview/src/couch_mrview_compactor.erl b/src/couch_mrview/src/couch_mrview_compactor.erl
index 9ef79b664..3c30d2fdb 100644
--- a/src/couch_mrview/src/couch_mrview_compactor.erl
+++ b/src/couch_mrview/src/couch_mrview_compactor.erl
@@ -52,10 +52,7 @@ compact(State) ->
CompactFName = couch_mrview_util:compaction_file(DbName, Sig),
{ok, Fd} = couch_mrview_util:open_file(CompactFName),
ESt = couch_mrview_util:reset_index(Db, Fd, State),
-
- {ok, DbReduce} = couch_btree:full_reduce(Db#db.id_tree),
- Count = element(1, DbReduce),
-
+ {ok, Count} = couch_db:get_doc_count(Db),
{ESt, Count}
end),
@@ -290,7 +287,7 @@ swap_compacted(OldState, NewState) ->
unlink(OldState#mrst.fd),
erlang:demonitor(OldState#mrst.fd_monitor, [flush]),
-
+
{ok, NewState#mrst{fd_monitor=Ref}}.
diff --git a/src/couch_mrview/src/couch_mrview_http.erl b/src/couch_mrview/src/couch_mrview_http.erl
index 7e3fd78e3..e5638fe83 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -103,11 +103,11 @@ handle_view_changes_req(#httpd{path_parts=[_,<<"_design">>,DDocName,<<"_view_cha
handle_view_req(#httpd{method='GET',
path_parts=[_, _, DDocName, _, VName, <<"_info">>]}=Req,
Db, _DDoc) ->
-
+ DbName = couch_db:name(Db),
DDocId = <<"_design/", DDocName/binary >>,
- {ok, Info} = couch_mrview:get_view_info(Db#db.name, DDocId, VName),
+ {ok, Info} = couch_mrview:get_view_info(DbName, DDocId, VName),
- FinalInfo = [{db_name, Db#db.name},
+ FinalInfo = [{db_name, DbName},
{ddoc, DDocId},
{view, VName}] ++ Info,
chttpd:send_json(Req, 200, {FinalInfo});
@@ -212,7 +212,7 @@ is_restricted(Db, _) ->
couch_db:is_system_db(Db).
is_public_fields_configured(Db) ->
- DbName = ?b2l(Db#db.name),
+ DbName = ?b2l(couch_db:name(Db)),
case config:get("couch_httpd_auth", "authentication_db", "_users") of
DbName ->
UsersDbPublic = config:get("couch_httpd_auth", "users_db_public", "false"),
@@ -237,7 +237,7 @@ do_all_docs_req(Req, Db, Keys, NS) ->
{ok, Resp} = couch_httpd:etag_maybe(Req, fun() ->
Max = chttpd:chunked_response_buffer_size(),
VAcc0 = #vacc{db=Db, req=Req, threshold=Max},
- DbName = ?b2l(Db#db.name),
+ DbName = ?b2l(couch_db:name(Db)),
UsersDbName = config:get("couch_httpd_auth",
"authentication_db",
"_users"),
diff --git a/src/couch_mrview/src/couch_mrview_show.erl b/src/couch_mrview/src/couch_mrview_show.erl
index 1ebc85b3e..60e8a2c46 100644
--- a/src/couch_mrview/src/couch_mrview_show.erl
+++ b/src/couch_mrview/src/couch_mrview_show.erl
@@ -364,13 +364,17 @@ json_apply_field({Key, NewValue}, [], Acc) ->
% This loads the db info if we have a fully loaded db record, but we might not
% have the db locally on this node, so then load the info through fabric.
-json_req_obj(Req, #db{main_pid=Pid}=Db) when is_pid(Pid) ->
- chttpd_external:json_req_obj(Req, Db);
json_req_obj(Req, Db) ->
- % use a separate process because we're already in a receive loop, and
- % json_req_obj calls fabric:get_db_info()
- spawn_monitor(fun() -> exit(chttpd_external:json_req_obj(Req, Db)) end),
- receive {'DOWN', _, _, _, JsonReq} -> JsonReq end.
+ case couch_db:is_clustered(Db) of
+ true ->
+ % use a separate process because we're already in a receive loop,
+ % and json_req_obj calls fabric:get_db_info()
+ JRO = fun() -> exit(chttpd_external:json_req_obj(Req, Db)) end,
+ spawn_monitor(JRO),
+ receive {'DOWN', _, _, _, JsonReq} -> JsonReq end;
+ false ->
+ chttpd_external:json_req_obj(Req, Db)
+ end.
last_chunk(Req, undefined) ->
chttpd:send_response(Req, 200, [], <<"">>);
diff --git a/src/couch_mrview/test/couch_mrview_all_docs_tests.erl b/src/couch_mrview/test/couch_mrview_all_docs_tests.erl
index 5e352797f..bf8eb7e5b 100644
--- a/src/couch_mrview/test/couch_mrview_all_docs_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_all_docs_tests.erl
@@ -25,7 +25,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_changes_since_tests.erl b/src/couch_mrview/test/couch_mrview_changes_since_tests.erl
index 8b11e3dd0..7e2f321fe 100644
--- a/src/couch_mrview/test/couch_mrview_changes_since_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_changes_since_tests.erl
@@ -25,7 +25,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_collation_tests.erl b/src/couch_mrview/test/couch_mrview_collation_tests.erl
index c4a714d1e..5c8cb54b1 100644
--- a/src/couch_mrview/test/couch_mrview_collation_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_collation_tests.erl
@@ -64,7 +64,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_compact_tests.erl b/src/couch_mrview/test/couch_mrview_compact_tests.erl
index 079639f5d..7cd5de817 100644
--- a/src/couch_mrview/test/couch_mrview_compact_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_compact_tests.erl
@@ -24,7 +24,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_ddoc_validation_tests.erl b/src/couch_mrview/test/couch_mrview_ddoc_validation_tests.erl
index 028e0be11..5ac3e7ecf 100644
--- a/src/couch_mrview/test/couch_mrview_ddoc_validation_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_ddoc_validation_tests.erl
@@ -21,7 +21,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
ddoc_validation_test_() ->
diff --git a/src/couch_mrview/test/couch_mrview_index_changes_tests.erl b/src/couch_mrview/test/couch_mrview_index_changes_tests.erl
index 8f0c296aa..2701e0c22 100644
--- a/src/couch_mrview/test/couch_mrview_index_changes_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_index_changes_tests.erl
@@ -22,7 +22,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
changes_index_test() ->
diff --git a/src/couch_mrview/test/couch_mrview_index_info_tests.erl b/src/couch_mrview/test/couch_mrview_index_info_tests.erl
index 3f88972ea..c994df9d3 100644
--- a/src/couch_mrview/test/couch_mrview_index_info_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_index_info_tests.erl
@@ -28,7 +28,7 @@ setup() ->
teardown({Db, _}) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_map_views_tests.erl b/src/couch_mrview/test/couch_mrview_map_views_tests.erl
index 3a199288d..229af183d 100644
--- a/src/couch_mrview/test/couch_mrview_map_views_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_map_views_tests.erl
@@ -24,7 +24,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_mrview/test/couch_mrview_red_views_tests.erl b/src/couch_mrview/test/couch_mrview_red_views_tests.erl
index 310078597..b83686113 100644
--- a/src/couch_mrview/test/couch_mrview_red_views_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_red_views_tests.erl
@@ -24,7 +24,7 @@ setup() ->
teardown(Db) ->
couch_db:close(Db),
- couch_server:delete(Db#db.name, [?ADMIN_CTX]),
+ couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
diff --git a/src/couch_replicator/src/couch_replicator.erl b/src/couch_replicator/src/couch_replicator.erl
index 7f0c7eecb..1ce2bae88 100644
--- a/src/couch_replicator/src/couch_replicator.erl
+++ b/src/couch_replicator/src/couch_replicator.erl
@@ -477,15 +477,21 @@ handle_call({report_seq_done, Seq, StatsInc}, From,
{noreply, NewState}.
-handle_cast({db_compacted, DbName},
- #rep_state{source = #db{name = DbName} = Source} = State) ->
- {ok, NewSource} = couch_db:reopen(Source),
- {noreply, State#rep_state{source = NewSource}};
-
-handle_cast({db_compacted, DbName},
- #rep_state{target = #db{name = DbName} = Target} = State) ->
- {ok, NewTarget} = couch_db:reopen(Target),
- {noreply, State#rep_state{target = NewTarget}};
+handle_cast({db_compacted, DbName}, State) ->
+ #rep_state{
+ source = Source,
+ target = Target
+ } = State,
+ SourceName = couch_replicator_utils:local_db_name(Source),
+ TargetName = couch_replicator_utils:local_db_name(Target),
+ case DbName of
+ SourceName ->
+ {ok, NewSource} = couch_db:reopen(Source),
+ {noreply, State#rep_state{source = NewSource}};
+ TargetName ->
+ {ok, NewTarget} = couch_db:reopen(Target),
+ {noreply, State#rep_state{target = NewTarget}}
+ end;
handle_cast(checkpoint, State) ->
#rep_state{rep_details = #rep{} = Rep} = State,
@@ -968,10 +974,11 @@ has_session_id(SessionId, [{Props} | Rest]) ->
end.
-db_monitor(#db{} = Db) ->
- couch_db:monitor(Db);
-db_monitor(_HttpDb) ->
- nil.
+db_monitor(#httpdb{}) ->
+ nil;
+db_monitor(Db) ->
+ couch_db:monitor(Db).
+
get_pending_count(St) ->
Rep = St#rep_state.rep_details,
diff --git a/src/couch_replicator/src/couch_replicator_api_wrap.erl b/src/couch_replicator/src/couch_replicator_api_wrap.erl
index e5f625335..09f22cbae 100644
--- a/src/couch_replicator/src/couch_replicator_api_wrap.erl
+++ b/src/couch_replicator/src/couch_replicator_api_wrap.erl
@@ -59,11 +59,11 @@
db_uri(#httpdb{url = Url}) ->
couch_util:url_strip_password(Url);
-db_uri(#db{name = Name}) ->
- db_uri(Name);
+db_uri(DbName) when is_binary(DbName) ->
+ ?b2l(DbName);
-db_uri(DbName) ->
- ?b2l(DbName).
+db_uri(Db) ->
+ db_uri(couch_db:name(Db)).
db_open(Db, Options) ->
@@ -148,10 +148,12 @@ get_db_info(#httpdb{} = Db) ->
fun(200, _, {Props}) ->
{ok, Props}
end);
-get_db_info(#db{name = DbName, user_ctx = UserCtx}) ->
- {ok, Db} = couch_db:open(DbName, [{user_ctx, UserCtx}]),
- {ok, Info} = couch_db:get_db_info(Db),
- couch_db:close(Db),
+get_db_info(Db) ->
+ DbName = couch_db:name(Db),
+ UserCtx = couch_db:get_user_ctx(Db),
+ {ok, InfoDb} = couch_db:open(DbName, [{user_ctx, UserCtx}]),
+ {ok, Info} = couch_db:get_db_info(InfoDb),
+ couch_db:close(InfoDb),
{ok, [{couch_util:to_binary(K), V} || {K, V} <- Info]}.
@@ -171,8 +173,10 @@ get_pending_count(#httpdb{} = Db, Seq) ->
send_req(Db, Options, fun(200, _, {Props}) ->
{ok, couch_util:get_value(<<"pending">>, Props, null)}
end);
-get_pending_count(#db{name=DbName}=Db, Seq) when is_number(Seq) ->
- {ok, CountDb} = couch_db:open(DbName, [{user_ctx, Db#db.user_ctx}]),
+get_pending_count(Db, Seq) when is_number(Seq) ->
+ DbName = couch_db:name(Db),
+ UserCtx = couch_db:get_user_ctx(Db),
+ {ok, CountDb} = couch_db:open(DbName, [{user_ctx, UserCtx}]),
Pending = couch_db:count_changes_since(CountDb, Seq),
couch_db:close(CountDb),
{ok, Pending}.
@@ -184,7 +188,8 @@ get_view_info(#httpdb{} = Db, DDocId, ViewName) ->
{VInfo} = couch_util:get_value(<<"view_index">>, Props, {[]}),
{ok, VInfo}
end);
-get_view_info(#db{name = DbName}, DDocId, ViewName) ->
+get_view_info(Db, DDocId, ViewName) ->
+ DbName = couch_db:name(Db),
{ok, VInfo} = couch_mrview:get_view_info(DbName, DDocId, ViewName),
{ok, [{couch_util:to_binary(K), V} || {K, V} <- VInfo]}.
diff --git a/src/couch_replicator/src/couch_replicator_manager.erl b/src/couch_replicator/src/couch_replicator_manager.erl
index 85dd428f2..48bf7a648 100644
--- a/src/couch_replicator/src/couch_replicator_manager.erl
+++ b/src/couch_replicator/src/couch_replicator_manager.erl
@@ -879,8 +879,8 @@ state_after_error(#rep_state{retries_left = Left, wait = Wait} = State) ->
before_doc_update(#doc{id = <<?DESIGN_DOC_PREFIX, _/binary>>} = Doc, _Db) ->
Doc;
-before_doc_update(#doc{body = {Body}} = Doc, #db{user_ctx=UserCtx} = Db) ->
- #user_ctx{roles = Roles, name = Name} = UserCtx,
+before_doc_update(#doc{body = {Body}} = Doc, Db) ->
+ #user_ctx{roles = Roles, name = Name} = couch_db:get_user_ctx(Db),
case lists:member(<<"_replicator">>, Roles) of
true ->
Doc;
@@ -906,8 +906,8 @@ before_doc_update(#doc{body = {Body}} = Doc, #db{user_ctx=UserCtx} = Db) ->
after_doc_read(#doc{id = <<?DESIGN_DOC_PREFIX, _/binary>>} = Doc, _Db) ->
Doc;
-after_doc_read(#doc{body = {Body}} = Doc, #db{user_ctx=UserCtx} = Db) ->
- #user_ctx{name = Name} = UserCtx,
+after_doc_read(#doc{body = {Body}} = Doc, Db) ->
+ #user_ctx{name = Name} = couch_db:get_user_ctx(Db),
case (catch couch_db:check_is_admin(Db)) of
ok ->
Doc;
diff --git a/src/couch_replicator/src/couch_replicator_utils.erl b/src/couch_replicator/src/couch_replicator_utils.erl
index e96d52a41..17d33342b 100644
--- a/src/couch_replicator/src/couch_replicator_utils.erl
+++ b/src/couch_replicator/src/couch_replicator_utils.erl
@@ -14,6 +14,7 @@
-export([parse_rep_doc/2]).
-export([open_db/1, close_db/1]).
+-export([local_db_name/1]).
-export([start_db_compaction_notifier/2, stop_db_compaction_notifier/1]).
-export([replication_id/2]).
-export([sum_stats/2, is_deleted/1]).
@@ -410,26 +411,33 @@ ssl_verify_options(false, _OTPVersion) ->
%% New db record has Options field removed here to enable smoother dbcore migration
-open_db(#db{name = Name, user_ctx = UserCtx}) ->
- {ok, Db} = couch_db:open(Name, [{user_ctx, UserCtx} | []]),
- Db;
-open_db(HttpDb) ->
- HttpDb.
-
-
-close_db(#db{} = Db) ->
- couch_db:close(Db);
-close_db(_HttpDb) ->
- ok.
-
+open_db(#httpdb{} = HttpDb) ->
+ HttpDb;
+open_db(Db) ->
+ DbName = couch_db:name(Db),
+ UserCtx = couch_db:get_user_ctx(Db),
+ {ok, NewDb} = couch_db:open(DbName, [{user_ctx, UserCtx}]),
+ NewDb.
+
+close_db(#httpdb{}) ->
+ ok;
+close_db(Db) ->
+ couch_db:close(Db).
-start_db_compaction_notifier(#db{name = DbName}, Server) ->
+start_db_compaction_notifier(#httpdb{}, _) ->
+ nil;
+start_db_compaction_notifier(Db, Server) ->
+ DbName = couch_db:name(Db),
{ok, Pid} = couch_event:link_listener(
?MODULE, handle_db_event, Server, [{dbname, DbName}]
),
- Pid;
-start_db_compaction_notifier(_, _) ->
- nil.
+ Pid.
+
+
+local_db_name(#httpdb{}) ->
+ undefined;
+local_db_name(Db) ->
+ couch_db:name(Db).
stop_db_compaction_notifier(nil) ->
diff --git a/src/couch_replicator/src/couch_replicator_worker.erl b/src/couch_replicator/src/couch_replicator_worker.erl
index ee0c45558..1a4e599f4 100644
--- a/src/couch_replicator/src/couch_replicator_worker.erl
+++ b/src/couch_replicator/src/couch_replicator_worker.erl
@@ -67,16 +67,16 @@
-start_link(Cp, #db{} = Source, Target, ChangesManager, _MaxConns) ->
+start_link(Cp, #httpdb{} = Source, Target, ChangesManager, MaxConns) ->
+ gen_server:start_link(
+ ?MODULE, {Cp, Source, Target, ChangesManager, MaxConns}, []);
+
+start_link(Cp, Source, Target, ChangesManager, _MaxConns) ->
Pid = spawn_link(fun() ->
erlang:put(last_stats_report, now()),
queue_fetch_loop(Source, Target, Cp, Cp, ChangesManager)
end),
- {ok, Pid};
-
-start_link(Cp, Source, Target, ChangesManager, MaxConns) ->
- gen_server:start_link(
- ?MODULE, {Cp, Source, Target, ChangesManager, MaxConns}, []).
+ {ok, Pid}.
init({Cp, Source, Target, ChangesManager, MaxConns}) ->
@@ -139,15 +139,23 @@ handle_call(flush, {Pid, _} = From,
{noreply, State2#state{flush_waiter = From}}.
-handle_cast({db_compacted, DbName},
- #state{source = #db{name = DbName} = Source} = State) ->
- {ok, NewSource} = couch_db:reopen(Source),
- {noreply, State#state{source = NewSource}};
-
-handle_cast({db_compacted, DbName},
- #state{target = #db{name = DbName} = Target} = State) ->
- {ok, NewTarget} = couch_db:reopen(Target),
- {noreply, State#state{target = NewTarget}};
+handle_cast({db_compacted, DbName} = Msg, #state{} = State) ->
+ #state{
+ source = Source,
+ target = Target
+ } = State,
+ SourceName = couch_replicator_utils:local_db_name(Source),
+ TargetName = couch_replicator_utils:local_db_name(Target),
+ case DbName of
+ SourceName ->
+ {ok, NewSource} = couch_db:reopen(Source),
+ {noreply, State#state{source = NewSource}};
+ TargetName ->
+ {ok, NewTarget} = couch_db:reopen(Target),
+ {noreply, State#state{target = NewTarget}};
+ _Else ->
+ {stop, {unexpected_async_call, Msg}, State}
+ end;
handle_cast(Msg, State) ->
{stop, {unexpected_async_call, Msg}, State}.
@@ -220,15 +228,15 @@ queue_fetch_loop(Source, Target, Parent, Cp, ChangesManager) ->
Target2 = open_db(Target),
{IdRevs, Stats0} = find_missing(Changes, Target2),
case Source of
- #db{} ->
- Source2 = open_db(Source),
- Stats = local_process_batch(
- IdRevs, Cp, Source2, Target2, #batch{}, Stats0),
- close_db(Source2);
#httpdb{} ->
ok = gen_server:call(Parent, {add_stats, Stats0}, infinity),
remote_process_batch(IdRevs, Parent),
- {ok, Stats} = gen_server:call(Parent, flush, infinity)
+ {ok, Stats} = gen_server:call(Parent, flush, infinity);
+ _Db ->
+ Source2 = open_db(Source),
+ Stats = local_process_batch(
+ IdRevs, Cp, Source2, Target2, #batch{}, Stats0),
+ close_db(Source2)
end,
close_db(Target2),
ok = gen_server:call(Cp, {report_seq_done, ReportSeq, Stats}, infinity),
@@ -245,7 +253,7 @@ local_process_batch([], Cp, Source, Target, #batch{docs = Docs, size = Size}, St
case Target of
#httpdb{} ->
couch_log:debug("Worker flushing doc batch of size ~p bytes", [Size]);
- #db{} ->
+ _Db ->
couch_log:debug("Worker flushing doc batch of ~p docs", [Size])
end,
Stats2 = flush_docs(Target, Docs),
@@ -360,7 +368,7 @@ spawn_writer(Target, #batch{docs = DocList, size = Size}) ->
case {Target, Size > 0} of
{#httpdb{}, true} ->
couch_log:debug("Worker flushing doc batch of size ~p bytes", [Size]);
- {#db{}, true} ->
+ {_Db, true} ->
couch_log:debug("Worker flushing doc batch of ~p docs", [Size]);
_ ->
ok
@@ -422,7 +430,7 @@ maybe_flush_docs(#httpdb{} = Target, Batch, Doc) ->
end
end;
-maybe_flush_docs(#db{} = Target, #batch{docs = DocAcc, size = SizeAcc}, Doc) ->
+maybe_flush_docs(Target, #batch{docs = DocAcc, size = SizeAcc}, Doc) ->
case SizeAcc + 1 of
SizeAcc2 when SizeAcc2 >= ?DOC_BUFFER_LEN ->
couch_log:debug("Worker flushing doc batch of ~p docs", [SizeAcc2]),
diff --git a/src/couch_replicator/test/couch_replicator_compact_tests.erl b/src/couch_replicator/test/couch_replicator_compact_tests.erl
index 7a5a25ab4..5731ff41b 100644
--- a/src/couch_replicator/test/couch_replicator_compact_tests.erl
+++ b/src/couch_replicator/test/couch_replicator_compact_tests.erl
@@ -82,8 +82,8 @@ should_all_processes_be_alive(RepPid, Source, Target) ->
{ok, SourceDb} = reopen_db(Source),
{ok, TargetDb} = reopen_db(Target),
?assert(is_process_alive(RepPid)),
- ?assert(is_process_alive(SourceDb#db.main_pid)),
- ?assert(is_process_alive(TargetDb#db.main_pid))
+ ?assert(is_process_alive(couch_db:get_pid(SourceDb))),
+ ?assert(is_process_alive(couch_db:get_pid(TargetDb)))
end).
should_run_replication(RepPid, RepId, Source, Target) ->
@@ -149,12 +149,12 @@ should_populate_and_compact(RepPid, Source, Target, BatchSize, Rounds) ->
compact_db("source", SourceDb),
?assert(is_process_alive(RepPid)),
- ?assert(is_process_alive(SourceDb#db.main_pid)),
+ ?assert(is_process_alive(couch_db:get_pid(SourceDb))),
wait_for_compaction("source", SourceDb),
compact_db("target", TargetDb),
?assert(is_process_alive(RepPid)),
- ?assert(is_process_alive(TargetDb#db.main_pid)),
+ ?assert(is_process_alive(couch_db:get_pid(TargetDb))),
wait_for_compaction("target", TargetDb),
{ok, SourceDb2} = reopen_db(SourceDb),
@@ -165,14 +165,14 @@ should_populate_and_compact(RepPid, Source, Target, BatchSize, Rounds) ->
compact_db("source", SourceDb2),
?assert(is_process_alive(RepPid)),
- ?assert(is_process_alive(SourceDb2#db.main_pid)),
+ ?assert(is_process_alive(couch_db:get_pid(SourceDb2))),
pause_writer(Writer),
wait_for_compaction("source", SourceDb2),
resume_writer(Writer),
compact_db("target", TargetDb2),
?assert(is_process_alive(RepPid)),
- ?assert(is_process_alive(TargetDb2#db.main_pid)),
+ ?assert(is_process_alive(couch_db:get_pid(TargetDb2))),
pause_writer(Writer),
wait_for_compaction("target", TargetDb2),
resume_writer(Writer)
@@ -248,14 +248,16 @@ should_compare_databases(Source, Target) ->
reopen_db({remote, Db}) ->
reopen_db(Db);
-reopen_db(#db{name=DbName}) ->
- reopen_db(DbName);
-reopen_db(DbName) ->
+reopen_db(DbName) when is_binary(DbName) ->
{ok, Db} = couch_db:open_int(DbName, []),
ok = couch_db:close(Db),
- {ok, Db}.
+ {ok, Db};
+reopen_db(Db) ->
+ reopen_db(couch_db:name(Db)).
-compact_db(Type, #db{name = Name}) ->
+
+compact_db(Type, Db0) ->
+ Name = couch_db:name(Db0),
{ok, Db} = couch_db:open_int(Name, []),
{ok, CompactPid} = couch_db:start_compact(Db),
MonRef = erlang:monitor(process, CompactPid),
@@ -395,7 +397,8 @@ stop_writer(Pid) ->
{reason, "Timeout stopping source database writer"}]})
end.
-writer_loop(#db{name = DbName}, Parent, Counter) ->
+writer_loop(Db0, Parent, Counter) ->
+ DbName = couch_db:name(Db0),
{ok, Data} = file:read_file(?ATTFILE),
maybe_pause(Parent, Counter),
Doc = couch_doc:from_json_obj({[
diff --git a/src/fabric/include/couch_db_tmp.hrl b/src/fabric/include/couch_db_tmp.hrl
deleted file mode 100644
index cd3a047d4..000000000
--- a/src/fabric/include/couch_db_tmp.hrl
+++ /dev/null
@@ -1,296 +0,0 @@
-% 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.
-
--define(LOCAL_DOC_PREFIX, "_local/").
--define(DESIGN_DOC_PREFIX0, "_design").
--define(DESIGN_DOC_PREFIX, "_design/").
-
--define(MIN_STR, <<"">>).
--define(MAX_STR, <<255>>). % illegal utf string
-
--define(JSON_ENCODE(V), couch_util:json_encode(V)).
--define(JSON_DECODE(V), couch_util:json_decode(V)).
-
--define(b2l(V), binary_to_list(V)).
--define(l2b(V), list_to_binary(V)).
-
--define(DEFAULT_ATTACHMENT_CONTENT_TYPE, <<"application/octet-stream">>).
-
--define(LOG_DEBUG(Format, Args), couch_log:debug(Format, Args)).
--define(LOG_INFO(Format, Args), couch_log:notice(Format, Args)).
--define(LOG_ERROR(Format, Args), couch_log:error(Format, Args)).
-
--record(rev_info,
- {
- rev,
- seq = 0,
- deleted = false,
- body_sp = nil % stream pointer
- }).
-
--record(doc_info,
- {
- id = <<"">>,
- high_seq = 0,
- revs = [] % rev_info
- }).
-
--record(full_doc_info,
- {id = <<"">>,
- update_seq = 0,
- deleted = false,
- data_size = 0,
- rev_tree = []
- }).
-
--record(httpd,
- {mochi_req,
- peer,
- method,
- path_parts,
- db_url_handlers,
- user_ctx,
- req_body = undefined,
- design_url_handlers,
- auth,
- default_fun,
- url_handlers
- }).
-
-
--record(doc,
- {
- id = <<"">>,
- revs = {0, []},
-
- % the json body object.
- body = {[]},
-
- atts = [], % attachments
-
- deleted = false,
-
- % key/value tuple of meta information, provided when using special options:
- % couch_db:open_doc(Db, Id, Options).
- meta = []
- }).
-
-
--record(att,
- {
- name,
- type,
- att_len,
- disk_len, % length of the attachment in its identity form
- % (that is, without a content encoding applied to it)
- % differs from att_len when encoding /= identity
- md5= <<>>,
- revpos=0,
- data,
- encoding=identity % currently supported values are:
- % identity, gzip
- % additional values to support in the future:
- % deflate, compress
- }).
-
-
--record(user_ctx,
- {
- name=null,
- roles=[],
- handler
- }).
-
-% This should be updated anytime a header change happens that requires more
-% than filling in new defaults.
-%
-% As long the changes are limited to new header fields (with inline
-% defaults) added to the end of the record, then there is no need to increment
-% the disk revision number.
-%
-% if the disk revision is incremented, then new upgrade logic will need to be
-% added to couch_db_updater:init_db.
-
--define(LATEST_DISK_VERSION, 5).
-
--record(db_header,
- {disk_version = ?LATEST_DISK_VERSION,
- update_seq = 0,
- unused = 0,
- id_tree_state = nil,
- seq_tree_state = nil,
- local_tree_state = nil,
- purge_seq = 0,
- purged_docs = nil,
- security_ptr = nil,
- revs_limit = 1000
- }).
-
--record(db,
- {main_pid = nil,
- update_pid = nil,
- compactor_pid = nil,
- instance_start_time, % number of microsecs since jan 1 1970 as a binary string
- fd,
- fd_monitor,
- header = #db_header{},
- committed_update_seq,
- id_tree,
- seq_tree,
- local_tree,
- update_seq,
- name,
- filepath,
- validate_doc_funs = undefined,
- security = [],
- security_ptr = nil,
- user_ctx = #user_ctx{},
- waiting_delayed_commit = nil,
- revs_limit = 1000,
- fsync_options = [],
- is_sys_db = false
- }).
-
-
--record(view_query_args, {
- start_key,
- end_key,
- start_docid = ?MIN_STR,
- end_docid = ?MAX_STR,
-
- direction = fwd,
- inclusive_end=true, % aka a closed-interval
-
- limit = 10000000000, % Huge number to simplify logic
- skip = 0,
-
- group_level = 0,
-
- view_type = nil,
- include_docs = false,
- stale = false,
- multi_get = false,
- callback = nil,
- list = nil,
- keys = nil,
- sorted = true,
- extra = []
-}).
-
--record(view_fold_helper_funs, {
- reduce_count,
- passed_end,
- start_response,
- send_row
-}).
-
--record(reduce_fold_helper_funs, {
- start_response,
- send_row
-}).
-
--record(extern_resp_args, {
- code = 200,
- stop = false,
- data = <<>>,
- ctype = "application/json",
- headers = [],
- json = nil
-}).
-
--record(group, {
- sig=nil,
- dbname,
- fd=nil,
- name,
- def_lang,
- design_options=[],
- views,
- id_btree=nil,
- current_seq=0,
- purge_seq=0,
- query_server=nil,
- waiting_delayed_commit=nil,
- atts=[]
- }).
-
--record(view,
- {id_num,
- map_names=[],
- def,
- btree=nil,
- reduce_funs=[],
- dbcopies=[],
- options=[]
- }).
-
--record(index_header,
- {seq=0,
- purge_seq=0,
- id_btree_state=nil,
- view_states=nil
- }).
-
--record(http_db, {
- url,
- auth = [],
- resource = "",
- headers = [
- {"User-Agent", "CouchDB/"++couch:version()},
- {"Accept", "application/json"},
- {"Accept-Encoding", "gzip"}
- ],
- qs = [],
- method = get,
- body = nil,
- options = [
- {response_format,binary},
- {inactivity_timeout, 30000}
- ],
- retries = 10,
- pause = 500,
- conn = nil
-}).
-
-% small value used in revision trees to indicate the revision isn't stored
--define(REV_MISSING, []).
-
--record(changes_args, {
- feed = "normal",
- dir = fwd,
- since = "0",
- limit = 1000000000000000,
- style = main_only,
- heartbeat,
- timeout,
- filter,
- include_docs = false
-}).
-
--record(proc, {
- pid,
- lang,
- client = nil,
- ddoc_keys = [],
- prompt_fun,
- set_timeout_fun,
- stop_fun,
- data_fun
-}).
-
--record(leaf, {
- deleted,
- ptr,
- seq,
- size = 0,
- atts = []
-}).
diff --git a/src/fabric/src/fabric.erl b/src/fabric/src/fabric.erl
index f98a5c04a..2b87e461e 100644
--- a/src/fabric/src/fabric.erl
+++ b/src/fabric/src/fabric.erl
@@ -38,7 +38,7 @@
-include_lib("fabric/include/fabric.hrl").
--type dbname() :: (iodata() | #db{}).
+-type dbname() :: (iodata() | tuple()).
-type docid() :: iodata().
-type revision() :: {integer(), binary()}.
-type callback() :: fun((any(), any()) -> {ok | stop, any()}).
@@ -476,10 +476,12 @@ dbname(DbName) when is_list(DbName) ->
list_to_binary(DbName);
dbname(DbName) when is_binary(DbName) ->
DbName;
-dbname(#db{name=Name}) ->
- Name;
-dbname(DbName) ->
- erlang:error({illegal_database_name, DbName}).
+dbname(Db) ->
+ try
+ couch_db:name(Db)
+ catch error:badarg ->
+ erlang:error({illegal_database_name, Db})
+ end.
name(Thing) ->
couch_util:to_binary(Thing).
diff --git a/src/fabric/src/fabric_rpc.erl b/src/fabric/src/fabric_rpc.erl
index 80b110a24..6ba59f206 100644
--- a/src/fabric/src/fabric_rpc.erl
+++ b/src/fabric/src/fabric_rpc.erl
@@ -38,7 +38,8 @@
}).
%% rpc endpoints
-%% call to with_db will supply your M:F with a #db{} and then remaining args
+%% call to with_db will supply your M:F with a Db instance
+%% and then remaining args
%% @equiv changes(DbName, Args, StartSeq, [])
changes(DbName, Args, StartSeq) ->
@@ -76,13 +77,13 @@ changes(DbName, Options, StartVector, DbOptions) ->
args = Args,
options = Options,
pending = couch_db:count_changes_since(Db, StartSeq),
- epochs = get_epochs(Db)
+ epochs = couch_db:get_epochs(Db)
},
try
{ok, #cacc{seq=LastSeq, pending=Pending, epochs=Epochs}} =
couch_db:changes_since(Db, StartSeq, Enum, Opts, Acc0),
rexi:stream_last({complete, [
- {seq, {LastSeq, uuid(Db), owner_of(LastSeq, Epochs)}},
+ {seq, {LastSeq, uuid(Db), couch_db:owner_of(Epochs, LastSeq)}},
{pending, Pending}
]})
after
@@ -225,7 +226,7 @@ get_missing_revs(DbName, IdRevsList, Options) ->
not_found ->
{Id, Revs, []}
end
- end, IdRevsList, couch_btree:lookup(Db#db.id_tree, Ids))};
+ end, IdRevsList, couch_db:get_full_doc_infos(Db, Ids))};
Error ->
Error
end).
@@ -249,8 +250,9 @@ group_info(DbName, DDocId, DbOptions) ->
reset_validation_funs(DbName) ->
case get_or_create_db(DbName, []) of
- {ok, #db{main_pid = Pid}} ->
- gen_server:cast(Pid, {load_validation_funs, undefined});
+ {ok, Db} ->
+ DbPid = couch_db:get_pid(Db),
+ gen_server:cast(DbPid, {load_validation_funs, undefined});
_ ->
ok
end.
@@ -358,7 +360,7 @@ changes_enumerator(DocInfo, Acc) ->
Opts = if Conflicts -> [conflicts | DocOptions]; true -> DocOptions end,
ChangesRow = {change, [
{pending, Pending-1},
- {seq, {Seq, uuid(Db), owner_of(Seq, Epochs)}},
+ {seq, {Seq, uuid(Db), couch_db:owner_of(Epochs, Seq)}},
{id, Id},
{changes, Results},
{deleted, Del} |
@@ -456,78 +458,17 @@ set_io_priority(DbName, Options) ->
ok
end.
-calculate_start_seq(_Db, _Node, Seq) when is_integer(Seq) ->
- Seq;
-calculate_start_seq(Db, Node, {Seq, Uuid}) ->
- % Treat the current node as the epoch node
- calculate_start_seq(Db, Node, {Seq, Uuid, Node});
-calculate_start_seq(Db, _Node, {Seq, Uuid, EpochNode}) ->
- case is_prefix(Uuid, couch_db:get_uuid(Db)) of
- true ->
- case is_owner(EpochNode, Seq, couch_db:get_epochs(Db)) of
- true -> Seq;
- false -> 0
- end;
- false ->
- %% The file was rebuilt, most likely in a different
- %% order, so rewind.
- 0
- end;
-calculate_start_seq(Db, _Node, {replace, OriginalNode, Uuid, Seq}) ->
- case is_prefix(Uuid, couch_db:get_uuid(Db)) of
- true ->
- start_seq(get_epochs(Db), OriginalNode, Seq);
- false ->
+calculate_start_seq(Db, Node, Seq) ->
+ case couch_db:calculate_start_seq(Db, Node, Seq) of
+ N when is_integer(N) ->
+ N;
+ {replace, OriginalNode, Uuid, OriginalSeq} ->
%% Scan history looking for an entry with
%% * target_node == TargetNode
%% * target_uuid == TargetUUID
%% * target_seq =< TargetSeq
%% If such an entry is found, stream from associated source_seq
- mem3_rep:find_source_seq(Db, OriginalNode, Uuid, Seq)
- end.
-
-is_prefix(Pattern, Subject) ->
- binary:longest_common_prefix([Pattern, Subject]) == size(Pattern).
-
-is_owner(Node, Seq, Epochs) ->
- validate_epochs(Epochs),
- Node =:= owner_of(Seq, Epochs).
-
-owner_of(_Seq, []) ->
- undefined;
-owner_of(Seq, [{EpochNode, EpochSeq} | _Rest]) when Seq > EpochSeq ->
- EpochNode;
-owner_of(Seq, [_ | Rest]) ->
- owner_of(Seq, Rest).
-
-get_epochs(Db) ->
- Epochs = couch_db:get_epochs(Db),
- validate_epochs(Epochs),
- Epochs.
-
-start_seq([{OrigNode, EpochSeq} | _], OrigNode, Seq) when Seq > EpochSeq ->
- %% OrigNode is the owner of the Seq so we can safely stream from there
- Seq;
-start_seq([{_, NewSeq}, {OrigNode, _} | _], OrigNode, Seq) when Seq > NewSeq ->
- %% We transferred this file before Seq was written on OrigNode, so we need
- %% to stream from the beginning of the next epoch. Note that it is _not_
- %% necessary for the current node to own the epoch beginning at NewSeq
- NewSeq;
-start_seq([_ | Rest], OrigNode, Seq) ->
- start_seq(Rest, OrigNode, Seq);
-start_seq([], OrigNode, Seq) ->
- erlang:error({epoch_mismatch, OrigNode, Seq}).
-
-validate_epochs(Epochs) ->
- %% Assert uniqueness.
- case length(Epochs) == length(lists:ukeysort(2, Epochs)) of
- true -> ok;
- false -> erlang:error(duplicate_epoch)
- end,
- %% Assert order.
- case Epochs == lists:sort(fun({_, A}, {_, B}) -> B =< A end, Epochs) of
- true -> ok;
- false -> erlang:error(epoch_order)
+ mem3_rep:find_source_seq(Db, OriginalNode, Uuid, OriginalSeq)
end.
uuid(Db) ->
@@ -540,30 +481,6 @@ uuid_prefix_len() ->
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-calculate_start_seq_test() ->
- %% uuid mismatch is always a rewind.
- Hdr1 = couch_db_header:new(),
- Hdr2 = couch_db_header:set(Hdr1, [{epochs, [{node1, 1}]}, {uuid, <<"uuid1">>}]),
- ?assertEqual(0, calculate_start_seq(#db{header=Hdr2}, node1, {1, <<"uuid2">>})),
- %% uuid matches and seq is owned by node.
- Hdr3 = couch_db_header:set(Hdr2, [{epochs, [{node1, 1}]}]),
- ?assertEqual(2, calculate_start_seq(#db{header=Hdr3}, node1, {2, <<"uuid1">>})),
- %% uuids match but seq is not owned by node.
- Hdr4 = couch_db_header:set(Hdr2, [{epochs, [{node2, 2}, {node1, 1}]}]),
- ?assertEqual(0, calculate_start_seq(#db{header=Hdr4}, node1, {3, <<"uuid1">>})),
- %% return integer if we didn't get a vector.
- ?assertEqual(4, calculate_start_seq(#db{}, foo, 4)).
-
-is_owner_test() ->
- ?assertNot(is_owner(foo, 1, [])),
- ?assertNot(is_owner(foo, 1, [{foo, 1}])),
- ?assert(is_owner(foo, 2, [{foo, 1}])),
- ?assert(is_owner(foo, 50, [{bar, 100}, {foo, 1}])),
- ?assert(is_owner(foo, 50, [{baz, 200}, {bar, 100}, {foo, 1}])),
- ?assert(is_owner(bar, 150, [{baz, 200}, {bar, 100}, {foo, 1}])),
- ?assertError(duplicate_epoch, is_owner(foo, 1, [{foo, 1}, {bar, 1}])),
- ?assertError(epoch_order, is_owner(foo, 1, [{foo, 100}, {bar, 200}])).
-
maybe_filtered_json_doc_no_filter_test() ->
Body = {[{<<"a">>, 1}]},
Doc = #doc{id = <<"1">>, revs = {1, [<<"r1">>]}, body = Body},
diff --git a/src/fabric/src/fabric_util.erl b/src/fabric/src/fabric_util.erl
index 7e3f23e68..c5aef0377 100644
--- a/src/fabric/src/fabric_util.erl
+++ b/src/fabric/src/fabric_util.erl
@@ -302,7 +302,8 @@ path_ends_with(Path, Suffix) ->
fake_db(DbName, Opts) ->
{SecProps} = fabric:get_security(DbName), % as admin
UserCtx = couch_util:get_value(user_ctx, Opts, #user_ctx{}),
- #db{name = DbName, security = SecProps, user_ctx = UserCtx}.
+ {ok, Db} = couch_db:clustered_db(DbName, UserCtx, SecProps),
+ Db.
%% test function
kv(Item, Count) ->
diff --git a/src/mango/src/mango_crud.erl b/src/mango/src/mango_crud.erl
index 68c9d6cc4..41a4d143d 100644
--- a/src/mango/src/mango_crud.erl
+++ b/src/mango/src/mango_crud.erl
@@ -111,7 +111,7 @@ maybe_add_user_ctx(Db, Opts) ->
{user_ctx, _} ->
Opts;
false ->
- [{user_ctx, Db#db.user_ctx} | Opts]
+ [{user_ctx, couch_db:get_user_ctx(Db)} | Opts]
end.
diff --git a/src/mango/src/mango_cursor_text.erl b/src/mango/src/mango_cursor_text.erl
index 96e365a49..dfe942c38 100644
--- a/src/mango/src/mango_cursor_text.erl
+++ b/src/mango/src/mango_cursor_text.erl
@@ -50,7 +50,7 @@ create(Db, Indexes, Selector, Opts0) ->
?MANGO_ERROR(multiple_text_indexes)
end,
- Opts = unpack_bookmark(Db#db.name, Opts0),
+ Opts = unpack_bookmark(couch_db:name(Db), Opts0),
DreyfusLimit = get_dreyfus_limit(),
Limit = erlang:min(DreyfusLimit, couch_util:get_value(limit, Opts, mango_opts:default_limit())),
@@ -96,7 +96,7 @@ execute(Cursor, UserFun, UserAcc) ->
},
CAcc = #cacc{
selector = Selector,
- dbname = Db#db.name,
+ dbname = couch_db:name(Db),
ddocid = ddocid(Idx),
idx_name = mango_idx:name(Idx),
bookmark = get_bookmark(Opts),
diff --git a/src/mango/src/mango_httpd.erl b/src/mango/src/mango_httpd.erl
index a08827649..cc6cbd5d8 100644
--- a/src/mango/src/mango_httpd.erl
+++ b/src/mango/src/mango_httpd.erl
@@ -190,7 +190,8 @@ handle_find_req(Req, _Db) ->
set_user_ctx(#httpd{user_ctx=Ctx}, Db) ->
- Db#db{user_ctx=Ctx}.
+ {ok, NewDb} = couch_db:set_user_ctx(Db, Ctx),
+ NewDb.
get_idx_w_opts(Opts) ->
diff --git a/src/mango/src/mango_idx.erl b/src/mango/src/mango_idx.erl
index bc88b970c..1c3924aaa 100644
--- a/src/mango/src/mango_idx.erl
+++ b/src/mango/src/mango_idx.erl
@@ -290,12 +290,12 @@ idx_mod(#idx{type = <<"text">>}) ->
end.
-db_to_name(#db{name=Name}) ->
- Name;
db_to_name(Name) when is_binary(Name) ->
Name;
db_to_name(Name) when is_list(Name) ->
- iolist_to_binary(Name).
+ iolist_to_binary(Name);
+db_to_name(Db) ->
+ couch_db:name(Db).
get_idx_def(Opts) ->
diff --git a/src/mango/src/mango_idx_text.erl b/src/mango/src/mango_idx_text.erl
index ad9d2e8d7..f6120a829 100644
--- a/src/mango/src/mango_idx_text.erl
+++ b/src/mango/src/mango_idx_text.erl
@@ -344,8 +344,9 @@ indexable_fields(Fields, {op_default, _}) ->
[<<"$default">> | Fields].
-maybe_reject_index_all_req({Def}, #db{name=DbName, user_ctx=Ctx}) ->
- User = Ctx#user_ctx.name,
+maybe_reject_index_all_req({Def}, Db) ->
+ DbName = couch_db:name(Db),
+ #user_ctx{name = User} = couch_db:get_user_ctx(Db),
Fields = couch_util:get_value(fields, Def),
case {Fields, forbid_index_all()} of
{all_fields, "true"} ->
@@ -374,7 +375,9 @@ setup() ->
end),
%default index all def that generates {fields, all_fields}
Index = #idx{def={[]}},
- Db = #db{name = <<"testdb">>, user_ctx=#user_ctx{name = <<"u1">>}},
+ DbName = <<"testdb">>,
+ UserCtx = #user_ctx{name = <<"u1">>},
+ {ok, Db} = couch_db:clustered_db(DbName, UserCtx),
{Index, Db}.
diff --git a/src/mem3/src/mem3.erl b/src/mem3/src/mem3.erl
index 405d7e5fa..e9c1473bc 100644
--- a/src/mem3/src/mem3.erl
+++ b/src/mem3/src/mem3.erl
@@ -145,13 +145,13 @@ get_shard(DbName, Node, Range) ->
local_shards(DbName) ->
mem3_shards:local(DbName).
-shard_suffix(#db{name=DbName}) ->
- shard_suffix(DbName);
-shard_suffix(DbName0) ->
+shard_suffix(DbName0) when is_binary(DbName0) ->
Shard = hd(shards(DbName0)),
<<"shards/", _:8/binary, "-", _:8/binary, "/", DbName/binary>> =
Shard#shard.name,
- filename:extension(binary_to_list(DbName)).
+ filename:extension(binary_to_list(DbName));
+shard_suffix(Db) ->
+ shard_suffix(couch_db:name(Db)).
fold_shards(Fun, Acc) ->
mem3_shards:fold(Fun, Acc).
@@ -292,10 +292,11 @@ group_by_range(Shards) ->
% quorum functions
-quorum(#db{name=DbName}) ->
- quorum(DbName);
-quorum(DbName) ->
- n(DbName) div 2 + 1.
+quorum(DbName) when is_binary(DbName) ->
+ n(DbName) div 2 + 1;
+quorum(Db) ->
+ quorum(couch_db:name(Db)).
+
node(#shard{node=Node}) ->
Node;
diff --git a/src/mem3/src/mem3_httpd.erl b/src/mem3/src/mem3_httpd.erl
index 535815862..571f06370 100644
--- a/src/mem3/src/mem3_httpd.erl
+++ b/src/mem3/src/mem3_httpd.erl
@@ -32,7 +32,7 @@ handle_membership_req(#httpd{path_parts=[<<"_membership">>]}=Req) ->
handle_shards_req(#httpd{method='GET',
path_parts=[_DbName, <<"_shards">>]} = Req, Db) ->
- DbName = mem3:dbname(Db#db.name),
+ DbName = mem3:dbname(couch_db:name(Db)),
Shards = mem3:shards(DbName),
JsonShards = json_shards(Shards, dict:new()),
couch_httpd:send_json(Req, {[
@@ -40,7 +40,7 @@ handle_shards_req(#httpd{method='GET',
]});
handle_shards_req(#httpd{method='GET',
path_parts=[_DbName, <<"_shards">>, DocId]} = Req, Db) ->
- DbName = mem3:dbname(Db#db.name),
+ DbName = mem3:dbname(couch_db:name(Db)),
Shards = mem3:shards(DbName, DocId),
{[{Shard, Dbs}]} = json_shards(Shards, dict:new()),
couch_httpd:send_json(Req, {[
diff --git a/src/mem3/src/mem3_nodes.erl b/src/mem3/src/mem3_nodes.erl
index f31891a7b..555389b90 100644
--- a/src/mem3/src/mem3_nodes.erl
+++ b/src/mem3/src/mem3_nodes.erl
@@ -92,7 +92,7 @@ code_change(_OldVsn, #state{}=State, _Extra) ->
initialize_nodelist() ->
DbName = config:get("mem3", "nodes_db", "_nodes"),
{ok, Db} = mem3_util:ensure_exists(DbName),
- {ok, _, Db} = couch_btree:fold(Db#db.id_tree, fun first_fold/3, Db, []),
+ {ok, _} = couch_db:fold_docs(Db, fun first_fold/2, Db, []),
% add self if not already present
case ets:lookup(?MODULE, node()) of
[_] ->
@@ -103,13 +103,13 @@ initialize_nodelist() ->
{ok, _} = couch_db:update_doc(Db, Doc, [])
end,
couch_db:close(Db),
- Db#db.update_seq.
+ couch_db:get_update_seq(Db).
-first_fold(#full_doc_info{id = <<"_design/", _/binary>>}, _, Acc) ->
+first_fold(#full_doc_info{id = <<"_design/", _/binary>>}, Acc) ->
{ok, Acc};
-first_fold(#full_doc_info{deleted=true}, _, Acc) ->
+first_fold(#full_doc_info{deleted=true}, Acc) ->
{ok, Acc};
-first_fold(#full_doc_info{id=Id}=DocInfo, _, Db) ->
+first_fold(#full_doc_info{id=Id}=DocInfo, Db) ->
{ok, #doc{body={Props}}} = couch_db:open_doc(Db, DocInfo, [ejson_body]),
ets:insert(?MODULE, {mem3_util:to_atom(Id), Props}),
{ok, Db}.
diff --git a/src/mem3/src/mem3_rep.erl b/src/mem3/src/mem3_rep.erl
index ad7ac55f5..85d46e2cd 100644
--- a/src/mem3/src/mem3_rep.erl
+++ b/src/mem3/src/mem3_rep.erl
@@ -170,11 +170,11 @@ find_source_seq_int(#doc{body={Props}}, SrcNode0, TgtNode0, TgtUUID, TgtSeq) ->
end.
-repl(#db{name=DbName, seq_tree=Bt}=Db, Acc0) ->
- erlang:put(io_priority, {internal_repl, DbName}),
+repl(Db, Acc0) ->
+ erlang:put(io_priority, {internal_repl, couch_db:name(Db)}),
#acc{seq=Seq} = Acc1 = calculate_start_seq(Acc0#acc{source = Db}),
Fun = fun ?MODULE:changes_enumerator/3,
- {ok, _, Acc2} = couch_btree:fold(Bt, Fun, Acc1, [{start_key, Seq + 1}]),
+ {ok, _, Acc2} = couch_db:enum_docs_since(Db, Seq, Fun, Acc1, []),
{ok, #acc{seq = LastSeq}} = replicate_batch(Acc2),
{ok, couch_db:count_changes_since(Db, LastSeq)}.
@@ -354,10 +354,10 @@ find_repl_doc(SrcDb, TgtUUIDPrefix) ->
end
end,
Options = [{start_key, DocIdPrefix}],
- case couch_btree:fold(SrcDb#db.local_tree, FoldFun, not_found, Options) of
- {ok, _, {TgtUUID, Doc}} ->
+ case couch_db:fold_local_docs(SrcDb, FoldFun, not_found, Options) of
+ {ok, {TgtUUID, Doc}} ->
{ok, TgtUUID, Doc};
- {ok, _, not_found} ->
+ {ok, not_found} ->
{not_found, missing};
Else ->
couch_log:error("Error finding replication doc: ~w", [Else]),
diff --git a/src/mem3/src/mem3_rpc.erl b/src/mem3/src/mem3_rpc.erl
index 93cb99ac9..c2bd58fdf 100644
--- a/src/mem3/src/mem3_rpc.erl
+++ b/src/mem3/src/mem3_rpc.erl
@@ -84,11 +84,11 @@ load_checkpoint_rpc(DbName, SourceNode, SourceUUID) ->
save_checkpoint_rpc(DbName, Id, SourceSeq, NewEntry0, History0) ->
erlang:put(io_priority, {internal_repl, DbName}),
case get_or_create_db(DbName, [?ADMIN_CTX]) of
- {ok, #db{update_seq = TargetSeq} = Db} ->
+ {ok, Db} ->
NewEntry = {[
{<<"target_node">>, atom_to_binary(node(), utf8)},
{<<"target_uuid">>, couch_db:get_uuid(Db)},
- {<<"target_seq">>, TargetSeq}
+ {<<"target_seq">>, couch_db:get_update_seq(Db)}
] ++ NewEntry0},
Body = {[
{<<"seq">>, SourceSeq},
diff --git a/src/mem3/src/mem3_shards.erl b/src/mem3/src/mem3_shards.erl
index c7f33c61f..f99855285 100644
--- a/src/mem3/src/mem3_shards.erl
+++ b/src/mem3/src/mem3_shards.erl
@@ -267,7 +267,7 @@ get_update_seq() ->
DbName = config:get("mem3", "shards_db", "_dbs"),
{ok, Db} = mem3_util:ensure_exists(DbName),
couch_db:close(Db),
- Db#db.update_seq.
+ couch_db:get_update_seq(Db).
listen_for_changes(Since) ->
DbName = config:get("mem3", "shards_db", "_dbs"),
@@ -317,7 +317,7 @@ load_shards_from_disk(DbName) when is_binary(DbName) ->
couch_db:close(Db)
end.
-load_shards_from_db(#db{} = ShardDb, DbName) ->
+load_shards_from_db(ShardDb, DbName) ->
case couch_db:open_doc(ShardDb, DbName, [ejson_body]) of
{ok, #doc{body = {Props}}} ->
Shards = mem3_util:build_ordered_shards(DbName, Props),