summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Hood <0x6e6562@gmail.com>2008-07-06 00:39:50 +0100
committerBen Hood <0x6e6562@gmail.com>2008-07-06 00:39:50 +0100
commit4dcea129a99d7523a3173358833818a32f0061b3 (patch)
tree683c8585aa8865854ff33d7e3bc1cae78db9633f
parent675869a27714307bce377638dfe8f6a5f069e757 (diff)
downloadrabbitmq-server-4dcea129a99d7523a3173358833818a32f0061b3.tar.gz
Migrated branch bug18752
-rw-r--r--include/rabbit.hrl4
-rw-r--r--src/rabbit_misc.erl2
-rw-r--r--src/rabbit_mnesia.erl4
-rw-r--r--src/rabbit_realm.erl137
-rw-r--r--src/rabbit_ticket.erl34
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},