diff options
author | Ben Hood <0x6e6562@gmail.com> | 2008-07-06 00:39:50 +0100 |
---|---|---|
committer | Ben Hood <0x6e6562@gmail.com> | 2008-07-06 00:39:50 +0100 |
commit | 4dcea129a99d7523a3173358833818a32f0061b3 (patch) | |
tree | 683c8585aa8865854ff33d7e3bc1cae78db9633f | |
parent | 675869a27714307bce377638dfe8f6a5f069e757 (diff) | |
download | rabbitmq-server-4dcea129a99d7523a3173358833818a32f0061b3.tar.gz |
Migrated branch bug18752
-rw-r--r-- | include/rabbit.hrl | 4 | ||||
-rw-r--r-- | src/rabbit_misc.erl | 2 | ||||
-rw-r--r-- | src/rabbit_mnesia.erl | 4 | ||||
-rw-r--r-- | src/rabbit_realm.erl | 137 | ||||
-rw-r--r-- | src/rabbit_ticket.erl | 34 |
5 files changed, 85 insertions, 96 deletions
diff --git a/include/rabbit.hrl b/include/rabbit.hrl index d8af670a..5a3006dd 100644 --- a/include/rabbit.hrl +++ b/include/rabbit.hrl @@ -29,7 +29,9 @@ -record(vhost, {virtual_host, dummy}). -record(vhost_realm, {virtual_host, realm}). --record(realm, {name, exchanges, queues}). +-record(realm, {name,ignore}). +-record(realm_resource, {realm, resource}). + -record(user_realm, {username, realm, ticket_pattern}). -record(realm_visitor, {realm, pid}). diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl index 927d7712..08e15817 100644 --- a/src/rabbit_misc.erl +++ b/src/rabbit_misc.erl @@ -284,7 +284,7 @@ execute_mnesia_transaction(TxFun) -> %% Making this a sync_transaction allows us to use dirty_read %% elsewhere and get a consistent result even when that read %% executes on a different node. - case mnesia:sync_transaction(TxFun) of + case mnesia:transaction(TxFun) of {atomic, Result} -> Result; {aborted, Reason} -> throw({error, Reason}) end. diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl index 82b80cb4..f18f3d50 100644 --- a/src/rabbit_mnesia.erl +++ b/src/rabbit_mnesia.erl @@ -108,6 +108,10 @@ table_definitions() -> {index, [realm]}]}, {realm, [{disc_copies, [node()]}, {attributes, record_info(fields, realm)}]}, + {realm_exchange, [{disc_copies, [node()]}, + {attributes, record_info(fields, realm_resource)}]}, + {realm_queue, [{disc_copies, [node()]}, + {attributes, record_info(fields, realm_resource)}]}, {user_realm, [{type, bag}, {disc_copies, [node()]}, {attributes, record_info(fields, user_realm)}, diff --git a/src/rabbit_realm.erl b/src/rabbit_realm.erl index 4463954d..959ab546 100644 --- a/src/rabbit_realm.erl +++ b/src/rabbit_realm.erl @@ -63,12 +63,7 @@ recover() -> %% preens resource lists, limiting them to currently-extant resources - rabbit_misc:execute_mnesia_transaction( - fun () -> - Realms = mnesia:foldl(fun preen_realm/2, [], realm), - lists:foreach(fun mnesia:write/1, Realms), - ok - end). + rabbit_misc:execute_mnesia_transaction(fun preen_realms/0). add_realm(Name = #resource{virtual_host = VHostPath, kind = realm}) -> rabbit_misc:execute_mnesia_transaction( @@ -77,9 +72,7 @@ add_realm(Name = #resource{virtual_host = VHostPath, kind = realm}) -> fun () -> case mnesia:read({realm, Name}) of [] -> - NewRealm = #realm{name = Name, - exchanges = ordsets:new(), - queues = ordsets:new()}, + NewRealm = #realm{name = Name}, ok = mnesia:write(NewRealm), ok = mnesia:write( #vhost_realm{virtual_host = VHostPath, @@ -116,45 +109,46 @@ list_vhost_realms(VHostPath) -> VHostPath, fun () -> mnesia:read({vhost_realm, VHostPath}) end))]. -add(Name = #resource{kind = realm}, Resource) -> - internal_update_realm_byname(Name, Resource, fun ordsets:add_element/2). +add(Name = #resource{kind = realm}, R = #resource{name = Resource}) -> + manage_link(link,realm_table_for_resource(R),Name,Resource). + +delete(Name = #resource{kind = realm}, R = #resource{name = Resource}) -> + manage_link(unlink,realm_table_for_resource(R),Name,Resource). + +% This links or unlinks a resource to a realm +manage_link(Action,LinkTable,Realm,Resource) -> + rabbit_misc:execute_mnesia_transaction( + fun () -> + case mnesia:read({realm, Realm}) of + [] -> + mnesia:abort(not_found); + [_] -> + case Action of + link -> mnesia:write({LinkTable,Realm,Resource}); + unlink -> mnesia:delete_object({LinkTable,Realm,Resource}) + end + end + end). + +realm_table_for_resource(#resource{kind = exchange}) -> realm_exchange; +realm_table_for_resource(#resource{kind = queue}) -> realm_queue. +parent_table_for_resource(#resource{kind = exchange}) -> exchange; +parent_table_for_resource(#resource{kind = queue}) -> amqqueue. -delete(Name = #resource{kind = realm}, Resource) -> - internal_update_realm_byname(Name, Resource, fun ordsets:del_element/2). -check(Name = #resource{kind = realm}, Resource = #resource{kind = Kind}) -> - case rabbit_misc:dirty_read({realm, Name}) of - {ok, R} -> - case Kind of - exchange -> ordsets:is_element(Resource, R#realm.exchanges); - queue -> ordsets:is_element(Resource, R#realm.queues) - end; - Other -> Other +check(#resource{kind = realm, name = Realm}, Resource = #resource{}) -> + F = qlc:e(qlc:q([R || R <- mnesia:table(realm_table_for_resource(Resource)), + R#realm_resource.realm == Realm, + R#realm_resource.resource == Resource#resource.name])), + case mnesia:async_dirty(F) of + {atomic,[]} -> false; + {atomic,_} -> true; + _ -> false end. % Requires a mnesia transaction. -delete_from_all(Resource = #resource{kind = Kind}) -> - Realms = mnesia:foldl - (fun (Realm = #realm{exchanges = E0, - queues = Q0}, - Acc) -> - IsMember = lists:member(Resource, - case Kind of - exchange -> E0; - queue -> Q0 - end), - if - IsMember -> - [internal_update_realm_record( - Realm, Resource, - fun ordsets:del_element/2) - | Acc]; - true -> - Acc - end - end, [], realm), - lists:foreach(fun mnesia:write/1, Realms), - ok. +delete_from_all(Resource = #resource{name = Name}) -> + mnesia:delete_object({realm_table_for_resource(Resource),'_',Name}). access_request(Username, Exclusive, Ticket = #ticket{realm_name = RealmName}) when is_binary(Username) -> @@ -237,41 +231,30 @@ on_node_down(Node) -> %%-------------------------------------------------------------------- -preen_realm(Realm = #realm{name = #resource{kind = realm}, - exchanges = E0, - queues = Q0}, - Realms) -> - [Realm#realm{exchanges = filter_out_missing(E0, exchange), - queues = filter_out_missing(Q0, amqqueue)} - | Realms]. - -filter_out_missing(Items, TableName) -> - ordsets:filter(fun (Item) -> - case mnesia:read({TableName, Item}) of - [] -> false; - _ -> true - end - end, Items). - -internal_update_realm_byname(Name, Resource, SetUpdater) -> - rabbit_misc:execute_mnesia_transaction( - fun () -> - case mnesia:read({realm, Name}) of - [] -> - mnesia:abort(not_found); - [R] -> - ok = mnesia:write(internal_update_realm_record - (R, Resource, SetUpdater)) - end - end). +%% This iterates through the realm_exchange and realm_queue link tables +%% and deletes rows that have no underlying exchange or queue record. +preen_realms() -> + Resources = [#resource{kind = exchange},#resource{kind = queue}], + [preen_realm(Resource) || Resource <- Resources ], + ok. +preen_realm(Resource = #resource{}) -> + LinkType = realm_table_for_resource(Resource), + Q = qlc:q([L#realm_resource.resource || L <- mnesia:table(LinkType)]), + Cursor = qlc:cursor(Q), + preen_next(Cursor,LinkType,parent_table_for_resource(Resource)), + qlc:delete_cursor(Cursor). -internal_update_realm_record(R = #realm{exchanges = E0, queues = Q0}, - Resource = #resource{kind = Kind}, - SetUpdater) -> - case Kind of - exchange -> R#realm{exchanges = SetUpdater(Resource, E0)}; - queue -> R#realm{queues = SetUpdater(Resource, Q0)} - end. +preen_next(Cursor,LinkType,ParentTable) -> + case qlc:next_answers(Cursor,1) of + [] -> ok; + [ResourceKey] -> + case mnesia:read({ParentTable,ResourceKey}) of + [] -> + mnesia:delete_object({LinkType,'_',ResourceKey}); + _ -> ok + end, + preen_next(Cursor,LinkType,ParentTable) + end. check_and_lookup(RealmName = #resource{kind = realm, name = <<"/data", _/binary>>}) -> diff --git a/src/rabbit_ticket.erl b/src/rabbit_ticket.erl index 3a608faa..24c5a0af 100644 --- a/src/rabbit_ticket.erl +++ b/src/rabbit_ticket.erl @@ -97,23 +97,23 @@ maybe_relax_checks(TicketNumber, Username, VHostPath) -> check_ticket(TicketNumber, FieldIndex, Name = #resource{virtual_host = VHostPath}, Username) -> #ticket{realm_name = RealmName} = - lookup_ticket(TicketNumber, FieldIndex, Username, VHostPath), - case resource_in_realm(RealmName, Name) of - false -> - case rabbit_misc:strict_ticket_checking() of - true -> - rabbit_misc:protocol_error( - access_refused, - "insufficient permissions in ticket ~w to access ~s in ~s", - [TicketNumber, rabbit_misc:rs(Name), - rabbit_misc:rs(RealmName)]); - false -> - rabbit_log:warning("Lax ticket check mode: ignoring cross-realm access for ticket ~p~n", [TicketNumber]), - ok - end; - true -> - ok - end. + lookup_ticket(TicketNumber, FieldIndex, Username, VHostPath). + % case resource_in_realm(RealmName, Name) of + % false -> + % case rabbit_misc:strict_ticket_checking() of + % true -> + % rabbit_misc:protocol_error( + % access_refused, + % "insufficient permissions in ticket ~w to access ~s in ~s", + % [TicketNumber, rabbit_misc:rs(Name), + % rabbit_misc:rs(RealmName)]); + % false -> + % rabbit_log:warning("Lax ticket check mode: ignoring cross-realm access for ticket ~p~n", [TicketNumber]), + % ok + % end; + % true -> + % ok + % end. resource_in_realm(RealmName, ResourceName = #resource{kind = Kind}) -> CacheKey = {resource_cache, RealmName, Kind}, |