diff options
| author | Damien F. Katz <damien@apache.org> | 2008-12-18 20:30:24 +0000 | 
|---|---|---|
| committer | Damien F. Katz <damien@apache.org> | 2008-12-18 20:30:24 +0000 | 
| commit | 6cc0a3fcaddb3094f8f0fcd5bd51b3e74e70d11c (patch) | |
| tree | 7c96ea0406ca218dbfb642f260d2b1ba7cf202ad | |
| parent | 5018945adf233336e6777e3dd085e565ffc4cccb (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
| -rw-r--r-- | etc/couchdb/local_dev.ini | 3 | ||||
| -rw-r--r-- | src/couchdb/couch_db.erl | 12 | ||||
| -rw-r--r-- | src/couchdb/couch_server.erl | 64 | 
3 files changed, 47 insertions, 32 deletions
diff --git a/etc/couchdb/local_dev.ini b/etc/couchdb/local_dev.ini index f1f2b7a5..d1682d39 100644 --- a/etc/couchdb/local_dev.ini +++ b/etc/couchdb/local_dev.ini @@ -54,3 +54,6 @@ foo = bar  [test]  foo = bar + +[test] +foo = bar 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}  | 
