Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:19
erlang
0955-Fix-for-delete_object-at-read-on-a-set-tab...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0955-Fix-for-delete_object-at-read-on-a-set-table.patch of Package erlang
From b1dd0efb565f3eac1e3dbc4b18c2001ad53ea2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Fr=C3=B6berg?= <magnus@klarna.com> Date: Thu, 11 Jun 2020 16:14:26 +0200 Subject: [PATCH] Fix for delete_object at read on a set table On a set table, if the delete_object doesnt delete (due to no match) at commit return whatever is (or is not) stored in source table as a result of a read in the same transaction as the delete_object. And, if a delete already has been done on Oid in the same transaction do not record a delete_object operation on the same Oid. Added delete_object tests on set table and made the existing tests checking more. --- lib/mnesia/src/mnesia.erl | 22 ++-- lib/mnesia/test/mnesia_trans_access_test.erl | 102 +++++++++++++++++-- 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 3f1b173e37..2efe739442 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -788,7 +788,8 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) -> ?ets_match_delete(Store, {Oid, Val, '_'}), ?ets_insert(Store, {Oid, Val, delete_object}); _ -> - case ?ets_match_object(Store, {Oid, '_', write}) of + case ?ets_match_object(Store, {Oid, '_', write}) ++ + ?ets_match_object(Store, {Oid, '_', delete}) of [] -> ?ets_match_delete(Store, {Oid, Val, '_'}), ?ets_insert(Store, {Oid, Val, delete_object}); @@ -1221,19 +1222,28 @@ add_written(Written, Tab, ObjsFun, LockKind) -> add_written_to_bag(Written, ObjsFun(), []); _ when LockKind == read; LockKind == write -> - add_written_to_set(Written); + add_written_to_set(Written, ObjsFun); _ -> - _ = ObjsFun(), % Fall back to request new lock and read from source - add_written_to_set(Written) + %% Fall back to request new lock and read from source + add_written_to_set(Written, ObjsFun()) end. -add_written_to_set(Ws) -> +add_written_to_set(Ws, ObjsOrFun) -> case lists:last(Ws) of {_, _, delete} -> []; {_, Val, write} -> [Val]; - {_, _, delete_object} -> [] + {Oid, _, delete_object} -> + %% May be several 'delete_object' in Ws; need to check if any + %% deleted Val exists in source table; if not return whatever + %% is/is not in the source table (ie as the Val is only deleted + %% if matched at commit this needs to be reflected here) + [Val || Val <- get_objs(ObjsOrFun), + not lists:member({Oid, Val, delete_object}, Ws)] end. +get_objs(ObjsFun) when is_function(ObjsFun) -> ObjsFun(); +get_objs(Objs) when is_list(Objs) -> Objs. + add_written_to_bag([{_, Val, write} | Tail], Objs, Ack) -> add_written_to_bag(Tail, lists:delete(Val, Objs), [Val | Ack]); add_written_to_bag([], Objs, Ack) -> diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl index 723a85fd2c..f488134391 100644 --- a/lib/mnesia/test/mnesia_trans_access_test.erl +++ b/lib/mnesia/test/mnesia_trans_access_test.erl @@ -63,7 +64,7 @@ end_per_testcase(Func, Conf) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> - [write, read, wread, delete, delete_object, + [write, read, wread, delete, delete_object_bag, delete_object_set, match_object, select, select14, all_keys, transaction, {group, nested_activities}, {group, index_tabs}, {group, index_lifecycle}]. @@ -221,14 +222,26 @@ delete(Config) when is_list(Config) -> %% Delete matching record -delete_object(suite) -> []; -delete_object(Config) when is_list(Config) -> +delete_object_bag(suite) -> []; +delete_object_bag(Config) when is_list(Config) -> [Node1] = Nodes = ?acquire_nodes(1, Config), + ?match(ok, delete_object(Node1, bag)), + ?verify_mnesia(Nodes, []). + +delete_object_set(suite) -> []; +delete_object_set(Config) when is_list(Config) -> + [Node1] = Nodes = ?acquire_nodes(1, Config), + ?match(ok, delete_object(Node1, set)), + ?verify_mnesia(Nodes, []). + +delete_object(Node1, Type) -> Tab = delete_object, - Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], + Schema = [{name, Tab}, {type, Type}, + {attributes, [k, v]}, {ram_copies, [Node1]}], ?match({atomic, ok}, mnesia:create_table(Schema)), OneRec = {Tab, 1, 2}, + OtherRec = {Tab, 1, 3}, ?match({aborted, {bad_type, _}}, mnesia:transaction(fun() -> mnesia:delete_object([]) end)), ?match({aborted, {bad_type, _}}, @@ -237,16 +250,88 @@ delete_object(Config) when is_list(Config) -> mnesia:transaction(fun() -> mnesia:delete_object({Tab, 1}) end)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(OneRec) end)), + + %% Delete already existing object ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete_object(OneRec) end)), + mnesia:transaction(fun() -> + [OneRec] = mnesia:read(Tab, 1), + ok = mnesia:delete_object(OneRec), + [] = mnesia:read(Tab, 1), + ok + end)), + ?match([], mnesia:dirty_read(Tab, 1)), + + %% Delete already existing object (written twice) ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete_object(OneRec) end)), + mnesia:transaction(fun() -> + [OneRec] = mnesia:read(Tab, 1), + ok = mnesia:delete_object(OneRec), + [] = mnesia:read(Tab, 1), + ok + end)), + ?match([], mnesia:dirty_read(Tab, 1)), + + %% Delete object written in same transaction + ?match({atomic, ok}, + mnesia:transaction(fun() -> + [] = mnesia:read(Tab, 1), + ok = mnesia:write(OneRec), + ok = mnesia:delete_object(OneRec), + [] = mnesia:read(Tab, 1), + ok + end)), + ?match([], mnesia:dirty_read(Tab, 1)), + + %% Delete other object than written in same transaction + ?match({atomic, ok}, + mnesia:transaction(fun() -> + [] = mnesia:read(Tab, 1), + ok = mnesia:write(OneRec), + ok = mnesia:delete_object(OtherRec), + [OneRec] = mnesia:read(Tab, 1), + ok + end)), + ?match([OneRec], mnesia:dirty_read(Tab, 1)), + + %% Delete other object than already existing + ?match({atomic, ok}, + mnesia:transaction(fun() -> + [OneRec] = mnesia:read(Tab, 1), + ok = mnesia:delete_object(OtherRec), + [OneRec] = mnesia:read(Tab, 1), + ok + end)), + ?match([OneRec], mnesia:dirty_read(Tab, 1)), + + %% Delete object in combination with delete + ?match({atomic, ok}, + mnesia:transaction(fun() -> + [OneRec] = mnesia:read(Tab, 1), + ok = mnesia:delete({Tab, 1}), + ok = mnesia:delete_object(OtherRec), + [] = mnesia:read(Tab, 1), + ok + end)), + ?match([], mnesia:dirty_read(Tab, 1)), + + %% Several delete_object in same transaction (last on non existing record) + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> + [OneRec] = mnesia:read(Tab, 1), + ok = mnesia:delete_object(OneRec), + ok = mnesia:delete_object(OtherRec), + [] = mnesia:read(Tab, 1), + ok + end)), + ?match([], mnesia:dirty_read(Tab, 1)), ?match({'EXIT', {aborted, no_transaction}}, mnesia:delete_object(OneRec)), @@ -255,7 +340,8 @@ delete_object(Config) when is_list(Config) -> ?match({aborted, {bad_type, Tab, _}}, mnesia:transaction(fun() -> mnesia:delete_object({Tab, {['$5']}, 21}) end)), - ?verify_mnesia(Nodes, []). + ?match({atomic, ok}, mnesia:delete_table(Tab)), + ok. %% Read matching records -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor