summaryrefslogtreecommitdiff
path: root/src/couchdb
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2008-12-18 20:30:24 +0000
committerDamien F. Katz <damien@apache.org>2008-12-18 20:30:24 +0000
commit6cc0a3fcaddb3094f8f0fcd5bd51b3e74e70d11c (patch)
tree7c96ea0406ca218dbfb642f260d2b1ba7cf202ad /src/couchdb
parent5018945adf233336e6777e3dd085e565ffc4cccb (diff)
Fixed problem when a crashed db can cause couch_server to crash when it attempts to interact with it. Moved the interaction from couch_server into the caller's process.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@727811 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb')
-rw-r--r--src/couchdb/couch_db.erl12
-rw-r--r--src/couchdb/couch_server.erl64
2 files changed, 44 insertions, 32 deletions
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index 5a51a1ac..6684156f 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -14,7 +14,7 @@
-behaviour(gen_server).
-export([open/2,close/1,create/2,start_compact/1,get_db_info/1]).
--export([open_ref_counted/3,num_refs/1,monitor/1]).
+-export([open_ref_counted/2,num_refs/1,monitor/1]).
-export([update_doc/3,update_docs/4,update_docs/2,update_docs/3,delete_doc/3]).
-export([get_doc_info/2,open_doc/2,open_doc/3,open_doc_revs/4]).
-export([get_missing_revs/2,name/1,doc_to_tree/1,get_update_seq/1]).
@@ -67,8 +67,8 @@ open(DbName, Options) ->
close(#db{fd=Fd}) ->
couch_file:drop_ref(Fd).
-open_ref_counted(MainPid, OpeningPid, UserCtx) ->
- {ok, Db} = gen_server:call(MainPid, {open_ref_counted_instance, OpeningPid}),
+open_ref_counted(MainPid, UserCtx) ->
+ {ok, Db} = gen_server:call(MainPid, {open_ref_counted_instance, self()}),
{ok, Db#db{user_ctx=UserCtx}}.
num_refs(MainPid) ->
@@ -357,8 +357,8 @@ make_first_doc_on_disk(Db, Id, [{_Rev, {IsDel, Sp}} |_]=DocPath) ->
make_doc(Db, Id, IsDel, Sp, Revs).
-write_and_commit(#db{update_pid=UpdatePid}=Db, DocBuckets, Options) ->
-
+write_and_commit(#db{update_pid=UpdatePid, user_ctx=Ctx}=Db, DocBuckets,
+ Options) ->
% flush unwritten binaries to disk.
DocBuckets2 = [[doc_flush_binaries(Doc, Db#db.fd) || Doc <- Bucket] || Bucket <- DocBuckets],
case gen_server:call(UpdatePid, {update_docs, DocBuckets2, Options}, infinity) of
@@ -366,7 +366,7 @@ write_and_commit(#db{update_pid=UpdatePid}=Db, DocBuckets, Options) ->
retry ->
% This can happen if the db file we wrote to was swapped out by
% compaction. Retry writing to the current file
- {ok, Db2} = open_ref_counted(Db#db.main_pid, self(), {[]}),
+ {ok, Db2} = open_ref_counted(Db#db.main_pid, Ctx),
DocBuckets3 = [[doc_flush_binaries(Doc, Db2#db.fd) || Doc <- Bucket] || Bucket <- DocBuckets],
% We only retry once
close(Db2),
diff --git a/src/couchdb/couch_server.erl b/src/couchdb/couch_server.erl
index 08f71f2b..fd185bc8 100644
--- a/src/couchdb/couch_server.erl
+++ b/src/couchdb/couch_server.erl
@@ -63,10 +63,22 @@ sup_start_link() ->
gen_server:start_link({local, couch_server}, couch_server, [], []).
open(DbName, Options) ->
- gen_server:call(couch_server, {open, DbName, Options}).
+ case gen_server:call(couch_server, {open, DbName, Options}) of
+ {ok, MainPid} ->
+ Ctx = proplists:get_value(user_ctx, Options, #user_ctx{}),
+ couch_db:open_ref_counted(MainPid, Ctx);
+ Error ->
+ Error
+ end.
create(DbName, Options) ->
- gen_server:call(couch_server, {create, DbName, Options}).
+ case gen_server:call(couch_server, {create, DbName, Options}) of
+ {ok, MainPid} ->
+ Ctx = proplists:get_value(user_ctx, Options, #user_ctx{}),
+ couch_db:open_ref_counted(MainPid, Ctx);
+ Error ->
+ Error
+ end.
delete(DbName, Options) ->
gen_server:call(couch_server, {delete, DbName, Options}).
@@ -192,15 +204,14 @@ try_close_lru(StartTime) ->
handle_call(get_server, _From, Server) ->
{reply, {ok, Server}, Server};
-handle_call({open, DbName, Options}, {FromPid,_}, Server) ->
+handle_call({open, DbName, Options}, _From, Server) ->
DbNameList = binary_to_list(DbName),
- UserCtx = proplists:get_value(user_ctx, Options, nil),
case check_dbname(Server, DbNameList) of
ok ->
Filepath = get_full_filename(Server, DbNameList),
LruTime = now(),
case ets:lookup(couch_dbs_by_name, DbName) of
- [] ->
+ [] ->
case maybe_close_lru_db(Server) of
{ok, Server2} ->
case couch_db:start_link(DbName, Filepath, Options) of
@@ -209,9 +220,8 @@ handle_call({open, DbName, Options}, {FromPid,_}, Server) ->
true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}),
true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
DbsOpen = Server2#server.current_dbs_open + 1,
- {reply,
- couch_db:open_ref_counted(MainPid, FromPid, UserCtx),
- Server2#server{current_dbs_open=DbsOpen}};
+ {reply, {ok, MainPid},
+ Server2#server{current_dbs_open=DbsOpen}};
Error ->
{reply, Error, Server2}
end;
@@ -222,35 +232,37 @@ handle_call({open, DbName, Options}, {FromPid,_}, Server) ->
true = ets:insert(couch_dbs_by_name, {DbName, {MainPid, LruTime}}),
true = ets:delete(couch_dbs_by_lru, PrevLruTime),
true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
- {reply,
- couch_db:open_ref_counted(MainPid, FromPid, UserCtx),
- Server}
+ {reply, {ok, MainPid}, Server}
end;
Error ->
{reply, Error, Server}
end;
-handle_call({create, DbName, Options}, {FromPid,_}, Server) ->
+handle_call({create, DbName, Options}, _From, Server) ->
DbNameList = binary_to_list(DbName),
- UserCtx = proplists:get_value(user_ctx, Options, nil),
case check_dbname(Server, DbNameList) of
ok ->
Filepath = get_full_filename(Server, DbNameList),
case ets:lookup(couch_dbs_by_name, DbName) of
[] ->
- case couch_db:start_link(DbName, Filepath, [create|Options]) of
- {ok, MainPid} ->
- LruTime = now(),
- true = ets:insert(couch_dbs_by_name, {DbName, {MainPid, LruTime}}),
- true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}),
- true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
- DbsOpen = Server#server.current_dbs_open + 1,
- couch_db_update_notifier:notify({created, DbName}),
- {reply,
- couch_db:open_ref_counted(MainPid, FromPid, UserCtx),
- Server#server{current_dbs_open=DbsOpen}};
- Error ->
- {reply, Error, Server}
+ case maybe_close_lru_db(Server) of
+ {ok, Server2} ->
+ case couch_db:start_link(DbName, Filepath, [create|Options]) of
+ {ok, MainPid} ->
+ LruTime = now(),
+ true = ets:insert(couch_dbs_by_name,
+ {DbName, {MainPid, LruTime}}),
+ true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}),
+ true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
+ DbsOpen = Server2#server.current_dbs_open + 1,
+ couch_db_update_notifier:notify({created, DbName}),
+ {reply, {ok, MainPid},
+ Server2#server{current_dbs_open=DbsOpen}};
+ Error ->
+ {reply, Error, Server2}
+ end;
+ CloseError ->
+ {reply, CloseError, Server}
end;
[_AlreadyRunningDb] ->
{reply, file_exists, Server}