Commits

Anonymous committed fbc6efe

close connections explicitly when done with them

This is important for the PB client because it holds a socket open in a
gen_server. The link from the webmachine resource to the
riakc_pb_socket is not enough to clean up when the resource finishes,
because it exits with Reason=normal in that case, so the riakc_pb_socket
gen_server lives on.

This adds wrc:disconnect/1, which closes the PB socket, but does nothing
for the HTTP client (since nothing is needed there).

The resources set the 'client' field of their context records or
'disconnected' after closing their client connections, in an effort to
help find bugs where code may try to use a client after it has been
closed.

Comments (0)

Files changed (7)

apps/wriaki/src/article_history.erl

                    [{link, <<"archive">>, '_', false},
 %%%{reduce, {jsanon, time_order_fun()}, <<>>, false}, %TODO: paging
                     {map, {jsanon, summary_fun()}, <<>>, true}]),
+    wrc:disconnect(Client),
     {ok, Results}.
 
 %% code for summary map phase is in priv/mapred/summary_map.js

apps/wriaki/src/session_resource.erl

 -module(session_resource).
 
 -export([init/1,
+         finish_request/2,
          allowed_methods/2,
          expires/2,
          resource_exists/2,
     {ok, Client} = wrc:connect(),
     {ok, #ctx{client=Client}}.
 
+finish_request(RD, Ctx=#ctx{client=C}) ->
+    wrc:disconnect(C),
+    {true, RD, Ctx#ctx{client=disconnected}}.
+
 allowed_methods(RD, Ctx) ->
     {['HEAD','GET','DELETE'], RD, Ctx}.
 

apps/wriaki/src/user_resource.erl

                 wriaki_auth:start_session(RD, User),
             {ok, UC} = wrc:set_client_id(C, username(RD)),
             wrc:put(UC, NewUser),
-            {true, NewRD, NewUser};
+            {true, NewRD, Ctx#ctx{user=NewUser}};
         false ->
             {{halt, 409},
              wrq:set_resp_header(
 edit_mode(RD) ->
     wrq:get_qs_value("edit", RD) /= undefined.
 
-finish_request(RD, Ctx) ->
+finish_request(RD, Ctx=#ctx{client=C}) ->
+    wrc:disconnect(C),
+    DCtx = Ctx#ctx{client=disconnected},
     case wrq:response_code(RD) of
         404 ->
             {ok, Content} = user_404_dtl:render(
              wrq:set_resp_header(
                "Content-type", "text/html; charset=utf-8",
                wrq:set_resp_body(Content, RD)),
-             Ctx};
+             DCtx};
         _ ->
-            {true, RD, Ctx}
+            {true, RD, DCtx}
     end.
             

apps/wriaki/src/wiki_resource.erl

                     true  -> render_404_editor(RD, Ctx);
                     false -> render_404(RD, Ctx)
                 end,
+            wrc:disconnect(NewCtx#ctx.client),
             {true,
              wrq:set_resp_header(
                "Content-type", "text/html; charset=utf-8",
                wrq:set_resp_body(Content, NewRD)),
-             NewCtx};
+             NewCtx#ctx{client=disconnected}};
         _ ->
-            {true, RD, Ctx}
+            wrc:disconnect(Ctx#ctx.client),
+            {true, RD, Ctx#ctx{client=disconnected}}
     end.
 
 render_404_editor(RD, Ctx) ->

apps/wriaki/src/wrc.erl

 -module(wrc).
 
 -export([connect/0, connect/1,
+         disconnect/1,
          ping/1,
          get_client_id/1, set_client_id/2,
          get_server_info/1,
     {ok, #wrc{module = riakc_pb_socket,
               client = C}}.
 
+disconnect(#wrc{module=riakc_pb_socket, client=C}) ->
+    riakc_pb_socket:stop(C);
+disconnect(_WRC) ->
+    ok.
+
 ping(RC) ->
     ?PASS0(RC, ping).
 

apps/wriaki/src/wriaki.erl

     {ok, Client} = wrc:connect(),
     ok = wrc:set_bucket(Client, ?B_ARTICLE,
                         [{allow_mult, true}|search_hook()]),
-    ok = wrc:set_bucket(Client, ?B_HISTORY, [{allow_mult, true}]).
+    ok = wrc:set_bucket(Client, ?B_HISTORY, [{allow_mult, true}]),
+    wrc:disconnect(Client).
 
 search_hook() ->
     case search_enabled() of

apps/wriaki/src/wriaki_auth.erl

 
 check_user_pass(Username, Password) ->
     {ok, Client} = wrc:connect(),
-    case wrc:get(Client, ?B_USER, Username) of
+    LookupResult = wrc:get(Client, ?B_USER, Username),
+    wrc:disconnect(Client),
+    case LookupResult of
         {ok, User} ->
             case user_resource:password_matches(User, Password) of
                 true  -> {ok, User};
                     {ok, UC} = wrc:set_client_id(C, session:get_user(Session)),
                     wrc:put(UC, session:refresh(Session)),
                     {ok, User} = wuser:fetch(UC, session:get_user(Session)),
+                    wrc:disconnect(UC),
                     {{cookie, SessionCookie}, User};
                 false ->
+                    wrc:disconnect(C),
                     false
             end;
         {error, notfound} ->
+            wrc:disconnect(C),
             false
     end.
 
     SessionCookie = wobj:key(Session),
     {ok, C} = wrc:connect(Username),
     ok = wrc:put(C, Session),
+    wrc:disconnect(C),
     {wrq:merge_resp_headers(
       [ mochiweb_cookies:cookie(K, V, [{path, "/"}])
         || {K, V} <- [{?USERNAME_COOKIE, Username},
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.