aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Gudmundsson <[email protected]>2015-09-10 10:09:28 +0200
committerDan Gudmundsson <[email protected]>2015-09-10 10:09:28 +0200
commit027726da70f31541bd3c4813bf464489a808ae91 (patch)
tree22b47c65f19c1e2cd5bf872f50a63ef9c72690a4
parentbfdc9f97f1738d072d09b98a8980b0b59639db0b (diff)
downloadotp-027726da70f31541bd3c4813bf464489a808ae91.tar.gz
otp-027726da70f31541bd3c4813bf464489a808ae91.tar.bz2
otp-027726da70f31541bd3c4813bf464489a808ae91.zip
mnesia: Improve index updates
There is no need to update the index table if a record is updated in non indexed field. This removes one timing glitch where dirty_index_read would return an empty list for records that where updated. There is still an issue with dirty_index_read when updates are made to the index field, it have been reduced but the real table updates are made after the index table references have been added. Originally reported by Nick Marino in erl-questions mailing list, thanks.
-rw-r--r--lib/mnesia/src/mnesia_index.erl27
-rw-r--r--lib/mnesia/test/mnesia_dirty_access_test.erl19
2 files changed, 35 insertions, 11 deletions
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 81ed5a8f1a..0c882c0df6 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -70,17 +70,24 @@ add_index(Index, Tab, Key, Obj, Old) ->
add_index2([{Pos, Ixt} |Tail], bag, Tab, K, Obj, OldRecs) ->
db_put(Ixt, {element(Pos, Obj), K}),
add_index2(Tail, bag, Tab, K, Obj, OldRecs);
-add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs) ->
+add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs0) ->
%% Remove old tuples in index if Tab is updated
- case OldRecs of
- undefined ->
- Old = mnesia_lib:db_get(Tab, K),
- del_ixes(Ixt, Old, Pos, K);
- Old ->
- del_ixes(Ixt, Old, Pos, K)
- end,
- db_put(Ixt, {element(Pos, Obj), K}),
- add_index2(Tail, Type, Tab, K, Obj, OldRecs);
+ OldRecs1 = case OldRecs0 of
+ undefined -> mnesia_lib:db_get(Tab, K);
+ _ -> OldRecs0
+ end,
+ IdxVal = element(Pos, Obj),
+ case [Old || Old <- OldRecs1, element(Pos, Old) =/= IdxVal] of
+ [] when OldRecs1 =:= [] -> %% Write
+ db_put(Ixt, {element(Pos, Obj), K}),
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ [] -> %% when OldRecs1 =/= [] Update without modifying index field
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ OldRecs -> %% Update
+ db_put(Ixt, {element(Pos, Obj), K}),
+ del_ixes(Ixt, OldRecs, Pos, K),
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0)
+ end;
add_index2([], _, _Tab, _K, _Obj, _) -> ok.
delete_index(Index, Tab, K) ->
diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl
index 89aff2b3b8..0d57e5a1b1 100644
--- a/lib/mnesia/test/mnesia_dirty_access_test.erl
+++ b/lib/mnesia/test/mnesia_dirty_access_test.erl
@@ -401,9 +401,26 @@ dirty_index_read(Config, Storage) ->
?match({'EXIT', _}, mnesia:dirty_index_read(Tab, 2, BadValPos)),
?match({'EXIT', _}, mnesia:dirty_index_read(foo, 2, ValPos)),
?match({'EXIT', _}, mnesia:dirty_index_read([], 2, ValPos)),
-
+
+ mnesia:dirty_write({Tab, 5, 1}),
+ ?match(ok, index_read_loop(Tab, 0)),
+
?verify_mnesia(Nodes, []).
+
+index_read_loop(Tab, N) when N =< 1000 ->
+ spawn_link(fun() ->
+ mnesia:transaction(fun() -> mnesia:write({Tab, 5, 1}) end)
+ end),
+ case mnesia:dirty_match_object({Tab, '_', 1}) of
+ [{Tab, 5, 1}] ->
+ index_read_loop(Tab, N+1);
+ Other -> {N, Other}
+ end;
+index_read_loop(_, _) ->
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%