And, most importantly src/couchdb/couch_auth_cache.erl On Wed, Jun 23, 2010 at 8:19 PM, Filipe David Manana <[email protected]>wrote:
> Damien, > > the new files share/www/script/test/auth_cache.js and > src/couchdb/couch_js_functions.hrl are missing in the diff. > > cheers > > > On Wed, Jun 23, 2010 at 8:11 PM, <[email protected]> wrote: > >> Author: damien >> Date: Wed Jun 23 19:11:50 2010 >> New Revision: 957314 >> >> URL: http://svn.apache.org/viewvc?rev=957314&view=rev >> Log: >> Authentication caching, to avoid repeated opening and closing of the users >> database for each request requiring authentication. COUCHDB-807 >> >> Modified: >> couchdb/trunk/etc/couchdb/default.ini.tpl.in >> couchdb/trunk/share/Makefile.am >> couchdb/trunk/share/www/script/couch_tests.js >> couchdb/trunk/share/www/script/test/users_db.js >> couchdb/trunk/src/couchdb/Makefile.am >> couchdb/trunk/src/couchdb/couch_db.erl >> couchdb/trunk/src/couchdb/couch_db.hrl >> couchdb/trunk/src/couchdb/couch_db_updater.erl >> couchdb/trunk/src/couchdb/couch_file.erl >> couchdb/trunk/src/couchdb/couch_httpd_auth.erl >> couchdb/trunk/src/couchdb/couch_httpd_db.erl >> couchdb/trunk/src/couchdb/couch_httpd_oauth.erl >> couchdb/trunk/src/couchdb/couch_server.erl >> couchdb/trunk/src/couchdb/priv/stat_descriptions.cfg.in >> >> Modified: couchdb/trunk/etc/couchdb/default.ini.tpl.in >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/etc/couchdb/default.ini.tpl.in?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/etc/couchdb/default.ini.tpl.in (original) >> +++ couchdb/trunk/etc/couchdb/default.ini.tpl.in Wed Jun 23 19:11:50 2010 >> @@ -31,6 +31,7 @@ include_sasl = true >> authentication_db = _users >> require_valid_user = false >> timeout = 600 ; number of seconds before automatic logout >> +auth_cache_size = 50 ; size is number of cache entries >> >> [query_servers] >> javascript = %bindir%/%couchjs_command_name% >> %localbuilddatadir%/server/main.js >> @@ -55,6 +56,7 @@ httpd={couch_httpd, start_link, []} >> stats_aggregator={couch_stats_aggregator, start, []} >> stats_collector={couch_stats_collector, start, []} >> uuids={couch_uuids, start, []} >> +auth_cache={couch_auth_cache, start_link, []} >> >> [httpd_global_handlers] >> / = {couch_httpd_misc_handlers, handle_welcome_req, <<"Welcome">>} >> >> Modified: couchdb/trunk/share/Makefile.am >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/share/Makefile.am?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/share/Makefile.am (original) >> +++ couchdb/trunk/share/Makefile.am Wed Jun 23 19:11:50 2010 >> @@ -110,6 +110,7 @@ nobase_dist_localdata_DATA = \ >> www/script/test/attachment_names.js \ >> www/script/test/attachment_paths.js \ >> www/script/test/attachment_views.js \ >> + www/script/test/auth_cache.js \ >> www/script/test/basics.js \ >> www/script/test/batch_save.js \ >> www/script/test/bulk_docs.js \ >> >> Modified: couchdb/trunk/share/www/script/couch_tests.js >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_tests.js?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original) >> +++ couchdb/trunk/share/www/script/couch_tests.js [utf-8] Wed Jun 23 >> 19:11:50 2010 >> @@ -35,6 +35,7 @@ loadTest("attachments_multipart.js"); >> loadTest("attachment_names.js"); >> loadTest("attachment_paths.js"); >> loadTest("attachment_views.js"); >> +loadTest("auth_cache.js"); >> loadTest("batch_save.js"); >> loadTest("bulk_docs.js"); >> loadTest("changes.js"); >> >> Modified: couchdb/trunk/share/www/script/test/users_db.js >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/users_db.js?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/share/www/script/test/users_db.js (original) >> +++ couchdb/trunk/share/www/script/test/users_db.js Wed Jun 23 19:11:50 >> 2010 >> @@ -24,8 +24,6 @@ couchTests.users_db = function(debug) { >> // to determine the actual users db name. >> >> function testFun() { >> - usersDb.deleteDb(); >> - >> // test that the validation function is installed >> var ddoc = usersDb.open("_design/_auth"); >> T(ddoc.validate_doc_update); >> @@ -89,10 +87,12 @@ couchTests.users_db = function(debug) { >> >> }; >> >> + usersDb.deleteDb(); >> run_on_modified_server( >> [{section: "couch_httpd_auth", >> - key: "authentication_db", value: "test_suite_users"}], >> + key: "authentication_db", value: usersDb.name}], >> testFun >> ); >> + usersDb.deleteDb(); // cleanup >> >> } >> \ No newline at end of file >> >> Modified: couchdb/trunk/src/couchdb/Makefile.am >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/Makefile.am?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/Makefile.am (original) >> +++ couchdb/trunk/src/couchdb/Makefile.am Wed Jun 23 19:11:50 2010 >> @@ -17,7 +17,7 @@ couchlibdir = $(localerlanglibdir)/couch >> couchincludedir = $(couchlibdir)/include >> couchebindir = $(couchlibdir)/ebin >> >> -couchinclude_DATA = couch_db.hrl >> +couchinclude_DATA = couch_db.hrl couch_js_functions.hrl >> couchebin_DATA = $(compiled_files) >> >> # dist_devdoc_DATA = $(doc_base) $(doc_modules) >> @@ -29,6 +29,7 @@ CLEANFILES = $(compiled_files) $(doc_bas >> source_files = \ >> couch.erl \ >> couch_app.erl \ >> + couch_auth_cache.erl \ >> couch_btree.erl \ >> couch_changes.erl \ >> couch_config.erl \ >> @@ -80,12 +81,13 @@ source_files = \ >> couch_db_updater.erl \ >> couch_work_queue.erl >> >> -EXTRA_DIST = $(source_files) couch_db.hrl >> +EXTRA_DIST = $(source_files) couch_db.hrl couch_js_functions.hrl >> >> compiled_files = \ >> couch.app \ >> couch.beam \ >> couch_app.beam \ >> + couch_auth_cache.beam \ >> couch_btree.beam \ >> couch_changes.beam \ >> couch_config.beam \ >> @@ -194,6 +196,6 @@ endif >> >> # $(ERL) -noshell -run edoc_run files [\"$<\"] >> >> -%.beam: %.erl couch_db.hrl >> +%.beam: %.erl couch_db.hrl couch_js_functions.hrl >> $(ERLC) $(ERLC_FLAGS) ${TEST} $<; >> >> >> Modified: couchdb/trunk/src/couchdb/couch_db.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_db.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_db.erl Wed Jun 23 19:11:50 2010 >> @@ -114,7 +114,7 @@ open_doc(Db, IdOrDocInfo) -> >> open_doc(Db, IdOrDocInfo, []). >> >> open_doc(Db, Id, Options) -> >> - couch_stats_collector:increment({couchdb, database_reads}), >> + increment_stat(Db, {couchdb, database_reads}), >> case open_doc_int(Db, Id, Options) of >> {ok, #doc{deleted=true}=Doc} -> >> case lists:member(deleted, Options) of >> @@ -157,7 +157,7 @@ find_ancestor_rev_pos({RevPos, [RevId|Re >> end. >> >> open_doc_revs(Db, Id, Revs, Options) -> >> - couch_stats_collector:increment({couchdb, database_reads}), >> + increment_stat(Db, {couchdb, database_reads}), >> [{ok, Results}] = open_doc_revs_int(Db, [{Id, Revs}], Options), >> {ok, [apply_open_options(Result, Options) || Result <- Results]}. >> >> @@ -621,7 +621,7 @@ check_dup_atts2(_) -> >> >> >> update_docs(Db, Docs, Options, replicated_changes) -> >> - couch_stats_collector:increment({couchdb, database_writes}), >> + increment_stat(Db, {couchdb, database_writes}), >> DocBuckets = group_alike_docs(Docs), >> >> case (Db#db.validate_doc_funs /= []) orelse >> @@ -647,7 +647,7 @@ update_docs(Db, Docs, Options, replicate >> {ok, DocErrors}; >> >> update_docs(Db, Docs, Options, interactive_edit) -> >> - couch_stats_collector:increment({couchdb, database_writes}), >> + increment_stat(Db, {couchdb, database_writes}), >> AllOrNothing = lists:member(all_or_nothing, Options), >> % go ahead and generate the new revision ids for the documents. >> % separate out the NonRep documents from the rest of the documents >> @@ -959,7 +959,12 @@ init({DbName, Filepath, Fd, Options}) -> >> {ok, UpdaterPid} = gen_server:start_link(couch_db_updater, {self(), >> DbName, Filepath, Fd, Options}, []), >> {ok, #db{fd_ref_counter=RefCntr}=Db} = gen_server:call(UpdaterPid, >> get_db), >> couch_ref_counter:add(RefCntr), >> - couch_stats_collector:track_process_count({couchdb, open_databases}), >> + case lists:member(sys_db, Options) of >> + true -> >> + ok; >> + false -> >> + couch_stats_collector:track_process_count({couchdb, >> open_databases}) >> + end, >> process_flag(trap_exit, true), >> {ok, Db}. >> >> @@ -983,7 +988,9 @@ handle_call({db_updated, NewDb}, _From, >> couch_ref_counter:add(NewRefCntr), >> couch_ref_counter:drop(OldRefCntr) >> end, >> - {reply, ok, NewDb}. >> + {reply, ok, NewDb}; >> +handle_call(get_db, _From, Db) -> >> + {reply, {ok, Db}, Db}. >> >> >> handle_cast(Msg, Db) -> >> @@ -1178,4 +1185,7 @@ make_doc(#db{fd=Fd}=Db, Id, Deleted, Bp, >> }. >> >> >> - >> +increment_stat(#db{is_sys_db = true}, _Stat) -> >> + ok; >> +increment_stat(#db{}, Stat) -> >> + couch_stats_collector:increment(Stat). >> >> Modified: couchdb/trunk/src/couchdb/couch_db.hrl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_db.hrl (original) >> +++ couchdb/trunk/src/couchdb/couch_db.hrl Wed Jun 23 19:11:50 2010 >> @@ -173,7 +173,8 @@ >> user_ctx = #user_ctx{}, >> waiting_delayed_commit = nil, >> revs_limit = 1000, >> - fsync_options = [] >> + fsync_options = [], >> + is_sys_db = false >> }). >> >> >> >> Modified: couchdb/trunk/src/couchdb/couch_db_updater.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db_updater.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_db_updater.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_db_updater.erl Wed Jun 23 19:11:50 >> 2010 >> @@ -35,7 +35,7 @@ init({MainPid, DbName, Filepath, Fd, Opt >> >> Db = init_db(DbName, Filepath, Fd, Header), >> Db2 = refresh_validate_doc_funs(Db), >> - {ok, Db2#db{main_pid=MainPid}}. >> + {ok, Db2#db{main_pid = MainPid, is_sys_db = lists:member(sys_db, >> Options)}}. >> >> >> terminate(_Reason, Db) -> >> >> Modified: couchdb/trunk/src/couchdb/couch_file.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_file.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_file.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_file.erl Wed Jun 23 19:11:50 2010 >> @@ -231,16 +231,14 @@ init({Filepath, Options, ReturnPid, Ref} >> {ok, 0} = file:position(Fd, 0), >> ok = file:truncate(Fd), >> ok = file:sync(Fd), >> - couch_stats_collector:track_process_count( >> - {couchdb, open_os_files}), >> + maybe_track_open_os_files(Options), >> {ok, #file{fd=Fd}}; >> false -> >> ok = file:close(Fd), >> init_status_error(ReturnPid, Ref, file_exists) >> end; >> false -> >> - couch_stats_collector:track_process_count( >> - {couchdb, open_os_files}), >> + maybe_track_open_os_files(Options), >> {ok, #file{fd=Fd}} >> end; >> Error -> >> @@ -252,7 +250,7 @@ init({Filepath, Options, ReturnPid, Ref} >> {ok, Fd_Read} -> >> {ok, Fd} = file:open(Filepath, [read, append, raw, binary]), >> ok = file:close(Fd_Read), >> - couch_stats_collector:track_process_count({couchdb, >> open_os_files}), >> + maybe_track_open_os_files(Options), >> {ok, Length} = file:position(Fd, eof), >> {ok, #file{fd=Fd, eof=Length}}; >> Error -> >> @@ -260,6 +258,13 @@ init({Filepath, Options, ReturnPid, Ref} >> end >> end. >> >> +maybe_track_open_os_files(FileOptions) -> >> + case lists:member(sys_db, FileOptions) of >> + true -> >> + ok; >> + false -> >> + couch_stats_collector:track_process_count({couchdb, >> open_os_files}) >> + end. >> >> terminate(_Reason, _Fd) -> >> ok. >> >> Modified: couchdb/trunk/src/couchdb/couch_httpd_auth.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_auth.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_httpd_auth.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_httpd_auth.erl Wed Jun 23 19:11:50 >> 2010 >> @@ -19,7 +19,6 @@ >> -export([proxy_authentification_handler/1]). >> -export([cookie_auth_header/2]). >> -export([handle_session_req/1]). >> --export([ensure_users_db_exists/1, get_user/1]). >> >> -import(couch_httpd, [header_value/2, send_json/2,send_json/4, >> send_method_not_allowed/2]). >> >> @@ -66,7 +65,7 @@ basic_name_pw(Req) -> >> default_authentication_handler(Req) -> >> case basic_name_pw(Req) of >> {User, Pass} -> >> - case get_user(?l2b(User)) of >> + case couch_auth_cache:get_user_creds(User) of >> nil -> >> throw({unauthorized, <<"Name or password is >> incorrect.">>}); >> UserProps -> >> @@ -156,149 +155,6 @@ proxy_auth_user(Req) -> >> end >> end. >> >> -% maybe we can use hovercraft to simplify running this view query >> -% rename to get_user_from_users_db >> -get_user(UserName) -> >> - case couch_config:get("admins", ?b2l(UserName)) of >> - "-hashed-" ++ HashedPwdAndSalt -> >> - % the name is an admin, now check to see if there is a user doc >> - % which has a matching name, salt, and password_sha >> - [HashedPwd, Salt] = string:tokens(HashedPwdAndSalt, ","), >> - case get_user_props_from_db(UserName) of >> - nil -> >> - [{<<"roles">>, [<<"_admin">>]}, >> - {<<"salt">>, ?l2b(Salt)}, >> - {<<"password_sha">>, ?l2b(HashedPwd)}]; >> - UserProps when is_list(UserProps) -> >> - DocRoles = couch_util:get_value(<<"roles">>, UserProps), >> - [{<<"roles">>, [<<"_admin">> | DocRoles]}, >> - {<<"salt">>, ?l2b(Salt)}, >> - {<<"password_sha">>, ?l2b(HashedPwd)}] >> - end; >> - _Else -> >> - get_user_props_from_db(UserName) >> - end. >> - >> -get_user_props_from_db(UserName) -> >> - DbName = couch_config:get("couch_httpd_auth", "authentication_db"), >> - {ok, Db} = ensure_users_db_exists(?l2b(DbName)), >> - DocId = <<"org.couchdb.user:", UserName/binary>>, >> - try couch_httpd_db:couch_doc_open(Db, DocId, nil, [conflicts]) of >> - #doc{meta=Meta}=Doc -> >> - % check here for conflict state and throw error if >> conflicted >> - case couch_util:get_value(conflicts,Meta,[]) of >> - [] -> >> - {DocProps} = couch_query_servers:json_doc(Doc), >> - case couch_util:get_value(<<"type">>, DocProps) of >> - <<"user">> -> >> - DocProps; >> - _Else -> >> - ?LOG_ERROR("Invalid user doc. Id: >> ~p",[DocId]), >> - nil >> - end; >> - _Else -> >> - throw({unauthorized, <<"User document conflict must >> be resolved before login.">>}) >> - end >> - catch >> - throw:_Throw -> >> - nil >> - after >> - couch_db:close(Db) >> - end. >> - >> -% this should handle creating the ddoc >> -ensure_users_db_exists(DbName) -> >> - case couch_db:open(DbName, [{user_ctx, >> #user_ctx{roles=[<<"_admin">>]}}]) of >> - {ok, Db} -> >> - ensure_auth_ddoc_exists(Db, <<"_design/_auth">>), >> - {ok, Db}; >> - _Error -> >> - {ok, Db} = couch_db:create(DbName, [{user_ctx, >> #user_ctx{roles=[<<"_admin">>]}}]), >> - ensure_auth_ddoc_exists(Db, <<"_design/_auth">>), >> - {ok, Db} >> - end. >> - >> -ensure_auth_ddoc_exists(Db, DDocId) -> >> - try couch_httpd_db:couch_doc_open(Db, DDocId, nil, []) of >> - _Foo -> ok >> - catch >> - _:_Error -> >> - % create the design document >> - {ok, AuthDesign} = auth_design_doc(DDocId), >> - {ok, _Rev} = couch_db:update_doc(Db, AuthDesign, []), >> - ok >> - end. >> - >> -% add the validation function here >> -auth_design_doc(DocId) -> >> - DocProps = [ >> - {<<"_id">>, DocId}, >> - {<<"language">>,<<"javascript">>}, >> - { >> - <<"validate_doc_update">>, >> - <<"function(newDoc, oldDoc, userCtx) { >> - if ((oldDoc || newDoc).type != 'user') { >> - throw({forbidden : 'doc.type must be user'}); >> - } // we only validate user docs for now >> - if (newDoc._deleted === true) { >> - // allow deletes by admins and matching users >> - // without checking the other fields >> - if ((userCtx.roles.indexOf('_admin') != -1) || >> (userCtx.name == oldDoc.name)) { >> - return; >> - } else { >> - throw({forbidden : 'Only admins may delete other >> user docs.'}); >> - } >> - } >> - if (!newDoc.name) { >> - throw({forbidden : 'doc.name is required'}); >> - } >> - if (!(newDoc.roles && (typeof newDoc.roles.length != >> 'undefined') )) { >> - throw({forbidden : 'doc.roles must be an array'}); >> - } >> - if (newDoc._id != 'org.couchdb.user:'+newDoc.name) { >> - throw({forbidden : 'Docid must be of the form >> org.couchdb.user:name'}); >> - } >> - if (oldDoc) { // validate all updates >> - if (oldDoc.name != newDoc.name) { >> - throw({forbidden : 'Usernames may not be >> changed.'}); >> - } >> - } >> - if (newDoc.password_sha && !newDoc.salt) { >> - throw({forbidden : 'Users with password_sha must have >> a salt. See /_utils/script/couch.js for example code.'}); >> - } >> - if (userCtx.roles.indexOf('_admin') == -1) { // not an >> admin >> - if (oldDoc) { // validate non-admin updates >> - if (userCtx.name != newDoc.name) { >> - throw({forbidden : 'You may only update your >> own user document.'}); >> - } >> - // validate role updates >> - var oldRoles = oldDoc.roles.sort(); >> - var newRoles = newDoc.roles.sort(); >> - if (oldRoles.length != newRoles.length) { >> - throw({forbidden : 'Only _admin may edit >> roles'}); >> - } >> - for (var i=0; i < oldRoles.length; i++) { >> - if (oldRoles[i] != newRoles[i]) { >> - throw({forbidden : 'Only _admin may edit >> roles'}); >> - } >> - }; >> - } else if (newDoc.roles.length > 0) { >> - throw({forbidden : 'Only _admin may set roles'}); >> - } >> - } >> - // no system roles in users db >> - for (var i=0; i < newDoc.roles.length; i++) { >> - if (newDoc.roles[i][0] == '_') { >> - throw({forbidden : 'No system roles (starting >> with underscore) in users db.'}); >> - } >> - }; >> - // no system names as names >> - if (newDoc.name[0] == '_') { >> - throw({forbidden : 'Username may not start with >> underscore.'}); >> - } >> - }">> >> - }], >> - {ok, couch_doc:from_json_obj({DocProps})}. >> >> cookie_authentication_handler(#httpd{mochi_req=MochiReq}=Req) -> >> case MochiReq:get_cookie_value("AuthSession") of >> @@ -321,7 +177,7 @@ cookie_authentication_handler(#httpd{moc >> Req; >> SecretStr -> >> Secret = ?l2b(SecretStr), >> - case get_user(?l2b(User)) of >> + case couch_auth_cache:get_user_creds(User) of >> nil -> Req; >> UserProps -> >> UserSalt = couch_util:get_value(<<"salt">>, UserProps, >> <<"">>), >> @@ -403,7 +259,7 @@ handle_session_req(#httpd{method='POST', >> UserName = ?l2b(couch_util:get_value("name", Form, "")), >> Password = ?l2b(couch_util:get_value("password", Form, "")), >> ?LOG_DEBUG("Attempt Login: ~s",[UserName]), >> - User = case get_user(UserName) of >> + User = case couch_auth_cache:get_user_creds(UserName) of >> nil -> []; >> Result -> Result >> end, >> >> Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Wed Jun 23 19:11:50 2010 >> @@ -160,23 +160,13 @@ handle_design_info_req(Req, _Db, _DDoc) >> >> create_db_req(#httpd{user_ctx=UserCtx}=Req, DbName) -> >> ok = couch_httpd:verify_is_server_admin(Req), >> - LDbName = ?b2l(DbName), >> - case couch_config:get("couch_httpd_auth", "authentication_db") of >> - LDbName -> >> - % make sure user's db always has the auth ddoc >> - {ok, Db} = couch_httpd_auth:ensure_users_db_exists(DbName), >> - couch_db:close(Db), >> - DbUrl = absolute_uri(Req, "/" ++ >> couch_util:url_encode(DbName)), >> - send_json(Req, 201, [{"Location", DbUrl}], {[{ok, true}]}); >> - _Else -> >> - case couch_server:create(DbName, [{user_ctx, UserCtx}]) of >> - {ok, Db} -> >> - couch_db:close(Db), >> - DbUrl = absolute_uri(Req, "/" ++ >> couch_util:url_encode(DbName)), >> - send_json(Req, 201, [{"Location", DbUrl}], {[{ok, >> true}]}); >> - Error -> >> - throw(Error) >> - end >> + case couch_server:create(DbName, [{user_ctx, UserCtx}]) of >> + {ok, Db} -> >> + couch_db:close(Db), >> + DbUrl = absolute_uri(Req, "/" ++ couch_util:url_encode(DbName)), >> + send_json(Req, 201, [{"Location", DbUrl}], {[{ok, true}]}); >> + Error -> >> + throw(Error) >> end. >> >> delete_db_req(#httpd{user_ctx=UserCtx}=Req, DbName) -> >> @@ -189,15 +179,6 @@ delete_db_req(#httpd{user_ctx=UserCtx}=R >> end. >> >> do_db_req(#httpd{user_ctx=UserCtx,path_parts=[DbName|_]}=Req, Fun) -> >> - LDbName = ?b2l(DbName), >> - % I hope this lookup is cheap. >> - case couch_config:get("couch_httpd_auth", "authentication_db") of >> - LDbName -> >> - % make sure user's db always has the auth ddoc >> - {ok, ADb} = couch_httpd_auth:ensure_users_db_exists(DbName), >> - couch_db:close(ADb); >> - _Else -> ok >> - end, >> case couch_db:open(DbName, [{user_ctx, UserCtx}]) of >> {ok, Db} -> >> try >> >> Modified: couchdb/trunk/src/couchdb/couch_httpd_oauth.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_oauth.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_httpd_oauth.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_httpd_oauth.erl Wed Jun 23 19:11:50 >> 2010 >> @@ -41,7 +41,7 @@ set_user_ctx(Req, AccessToken) -> >> undefined -> throw({bad_request, unknown_oauth_token}); >> Value -> ?l2b(Value) >> end, >> - case couch_httpd_auth:get_user(Name) of >> + case couch_auth_cache:get_user_creds(Name) of >> nil -> Req; >> User -> >> Roles = couch_util:get_value(<<"roles">>, User, []), >> >> Modified: couchdb/trunk/src/couchdb/couch_server.erl >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_server.erl?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/couch_server.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_server.erl Wed Jun 23 19:11:50 2010 >> @@ -141,6 +141,7 @@ init([]) -> >> ets:new(couch_dbs_by_name, [set, private, named_table]), >> ets:new(couch_dbs_by_pid, [set, private, named_table]), >> ets:new(couch_dbs_by_lru, [ordered_set, private, named_table]), >> + ets:new(couch_sys_dbs, [set, private, named_table]), >> process_flag(trap_exit, true), >> {ok, #server{root_dir=RootDir, >> dbname_regexp=RegExp, >> @@ -180,7 +181,7 @@ maybe_close_lru_db(#server{dbs_open=NumO >> end. >> >> try_close_lru(StartTime) -> >> - LruTime = ets:first(couch_dbs_by_lru), >> + LruTime = get_lru(), >> if LruTime > StartTime -> >> % this means we've looped through all our opened dbs and found >> them >> % all in use. >> @@ -194,6 +195,7 @@ try_close_lru(StartTime) -> >> true = ets:delete(couch_dbs_by_lru, LruTime), >> true = ets:delete(couch_dbs_by_name, DbName), >> true = ets:delete(couch_dbs_by_pid, MainPid), >> + true = ets:delete(couch_sys_dbs, DbName), >> ok; >> false -> >> % this still has referrers. Go ahead and give it a current lru >> time >> @@ -207,11 +209,31 @@ try_close_lru(StartTime) -> >> end >> end. >> >> +get_lru() -> >> + get_lru(ets:first(couch_dbs_by_lru)). >> + >> +get_lru(LruTime) -> >> + [{LruTime, DbName}] = ets:lookup(couch_dbs_by_lru, LruTime), >> + case ets:member(couch_sys_dbs, DbName) of >> + false -> >> + LruTime; >> + true -> >> + [{_, {opened, MainPid, _}}] = ets:lookup(couch_dbs_by_name, >> DbName), >> + case couch_db:is_idle(MainPid) of >> + true -> >> + LruTime; >> + false -> >> + get_lru(ets:next(couch_dbs_by_lru, LruTime)) >> + end >> + end. >> + >> open_async(Server, From, DbName, Filepath, Options) -> >> Parent = self(), >> Opener = spawn_link(fun() -> >> Res = couch_db:start_link(DbName, Filepath, Options), >> - gen_server:call(Parent, {open_result, DbName, Res}, >> infinity), >> + gen_server:call( >> + Parent, {open_result, DbName, Res, Options}, infinity >> + ), >> unlink(Parent), >> case Res of >> {ok, DbReader} -> >> @@ -222,13 +244,20 @@ open_async(Server, From, DbName, Filepat >> end), >> true = ets:insert(couch_dbs_by_name, {DbName, {opening, Opener, >> [From]}}), >> true = ets:insert(couch_dbs_by_pid, {Opener, DbName}), >> - Server#server{dbs_open=Server#server.dbs_open + 1}. >> + DbsOpen = case lists:member(sys_db, Options) of >> + true -> >> + true = ets:insert(couch_sys_dbs, {DbName, true}), >> + Server#server.dbs_open; >> + false -> >> + Server#server.dbs_open + 1 >> + end, >> + Server#server{dbs_open = DbsOpen}. >> >> handle_call({set_max_dbs_open, Max}, _From, Server) -> >> {reply, ok, Server#server{max_dbs_open=Max}}; >> handle_call(get_server, _From, Server) -> >> {reply, {ok, Server}, Server}; >> -handle_call({open_result, DbName, {ok, OpenedDbPid}}, _From, Server) -> >> +handle_call({open_result, DbName, {ok, OpenedDbPid}, Options}, _From, >> Server) -> >> link(OpenedDbPid), >> [{DbName, {opening,Opener,Froms}}] = ets:lookup(couch_dbs_by_name, >> DbName), >> lists:foreach(fun({FromPid,_}=From) -> >> @@ -241,15 +270,28 @@ handle_call({open_result, DbName, {ok, O >> true = ets:delete(couch_dbs_by_pid, Opener), >> true = ets:insert(couch_dbs_by_pid, {OpenedDbPid, DbName}), >> true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}), >> + case lists:member(create, Options) of >> + true -> >> + couch_db_update_notifier:notify({created, DbName}); >> + false -> >> + ok >> + end, >> {reply, ok, Server}; >> -handle_call({open_result, DbName, Error}, _From, Server) -> >> +handle_call({open_result, DbName, Error, Options}, _From, Server) -> >> [{DbName, {opening,Opener,Froms}}] = ets:lookup(couch_dbs_by_name, >> DbName), >> lists:foreach(fun(From) -> >> gen_server:reply(From, Error) >> end, Froms), >> true = ets:delete(couch_dbs_by_name, DbName), >> true = ets:delete(couch_dbs_by_pid, Opener), >> - {reply, ok, Server#server{dbs_open=Server#server.dbs_open - 1}}; >> + DbsOpen = case lists:member(sys_db, Options) of >> + true -> >> + true = ets:delete(couch_sys_dbs, DbName), >> + Server#server.dbs_open; >> + false -> >> + Server#server.dbs_open - 1 >> + end, >> + {reply, ok, Server#server{dbs_open = DbsOpen}}; >> handle_call({open, DbName, Options}, {FromPid,_}=From, Server) -> >> LruTime = now(), >> case ets:lookup(couch_dbs_by_name, DbName) of >> @@ -257,12 +299,17 @@ handle_call({open, DbName, Options}, {Fr >> DbNameList = binary_to_list(DbName), >> case check_dbname(Server, DbNameList) of >> ok -> >> - case maybe_close_lru_db(Server) of >> - {ok, Server2} -> >> - Filepath = get_full_filename(Server, DbNameList), >> - {noreply, open_async(Server2, From, DbName, Filepath, >> Options)}; >> - CloseError -> >> - {reply, CloseError, Server} >> + Path = get_full_filename(Server, DbNameList), >> + case lists:member(sys_db, Options) of >> + true -> >> + {noreply, open_async(Server, From, DbName, Path, >> Options)}; >> + false -> >> + case maybe_close_lru_db(Server) of >> + {ok, Server2} -> >> + {noreply, open_async(Server2, From, DbName, Path, >> Options)}; >> + CloseError -> >> + {reply, CloseError, Server} >> + end >> end; >> Error -> >> {reply, Error, Server} >> @@ -301,21 +348,34 @@ handle_call({delete, DbName, _Options}, >> case check_dbname(Server, DbNameList) of >> ok -> >> FullFilepath = get_full_filename(Server, DbNameList), >> - Server2 = >> + UpdateState = >> case ets:lookup(couch_dbs_by_name, DbName) of >> - [] -> Server; >> + [] -> false; >> [{_, {opening, Pid, Froms}}] -> >> couch_util:shutdown_sync(Pid), >> true = ets:delete(couch_dbs_by_name, DbName), >> true = ets:delete(couch_dbs_by_pid, Pid), >> [gen_server:send_result(F, not_found) || F <- Froms], >> - Server#server{dbs_open=Server#server.dbs_open - 1}; >> + true; >> [{_, {opened, Pid, LruTime}}] -> >> couch_util:shutdown_sync(Pid), >> true = ets:delete(couch_dbs_by_name, DbName), >> true = ets:delete(couch_dbs_by_pid, Pid), >> true = ets:delete(couch_dbs_by_lru, LruTime), >> - Server#server{dbs_open=Server#server.dbs_open - 1} >> + true >> + end, >> + Server2 = case UpdateState of >> + true -> >> + DbsOpen = case ets:member(couch_sys_dbs, DbName) of >> + true -> >> + true = ets:delete(couch_sys_dbs, DbName), >> + Server#server.dbs_open; >> + false -> >> + Server#server.dbs_open - 1 >> + end, >> + Server#server{dbs_open = DbsOpen}; >> + false -> >> + Server >> end, >> >> %% Delete any leftover .compact files. If we don't do this a >> subsequent >> >> Modified: couchdb/trunk/src/couchdb/priv/stat_descriptions.cfg.in >> URL: >> http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/stat_descriptions.cfg.in?rev=957314&r1=957313&r2=957314&view=diff >> >> ============================================================================== >> --- couchdb/trunk/src/couchdb/priv/stat_descriptions.cfg.in (original) >> +++ couchdb/trunk/src/couchdb/priv/stat_descriptions.cfg.in Wed Jun 23 >> 19:11:50 2010 >> @@ -19,6 +19,8 @@ >> {couchdb, open_databases, "number of open databases"}. >> {couchdb, open_os_files, "number of file descriptors CouchDB has open"}. >> {couchdb, request_time, "length of a request inside CouchDB without >> MochiWeb"}. >> +{couchdb, auth_cache_hits, "number of authentication cache hits"}. >> +{couchdb, auth_cache_misses, "number of authentication cache misses"}. >> >> {httpd, bulk_requests, "number of bulk requests"}. >> {httpd, requests, "number of HTTP requests"}. >> >> >> > > > -- > Filipe David Manana, > [email protected] > > "Reasonable men adapt themselves to the world. > Unreasonable men adapt the world to themselves. > That's why all progress depends on unreasonable men." > > -- Filipe David Manana, [email protected] "Reasonable men adapt themselves to the world. Unreasonable men adapt the world to themselves. That's why all progress depends on unreasonable men."
