1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1996-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: %% 21: -module(mnesia_dirty_access_test). 22: -author('hakan@erix.ericsson.se'). 23: -compile([export_all]). 24: -include("mnesia_test_lib.hrl"). 25: 26: init_per_testcase(Func, Conf) -> 27: mnesia_test_lib:init_per_testcase(Func, Conf). 28: 29: end_per_testcase(Func, Conf) -> 30: mnesia_test_lib:end_per_testcase(Func, Conf). 31: 32: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 33: all() -> 34: [{group, dirty_write}, {group, dirty_read}, 35: {group, dirty_update_counter}, {group, dirty_delete}, 36: {group, dirty_delete_object}, 37: {group, dirty_match_object}, {group, dirty_index}, 38: {group, dirty_iter}, {group, admin_tests}]. 39: 40: groups() -> 41: [{dirty_write, [], 42: [dirty_write_ram, dirty_write_disc, 43: dirty_write_disc_only]}, 44: {dirty_read, [], 45: [dirty_read_ram, dirty_read_disc, 46: dirty_read_disc_only]}, 47: {dirty_update_counter, [], 48: [dirty_update_counter_ram, dirty_update_counter_disc, 49: dirty_update_counter_disc_only]}, 50: {dirty_delete, [], 51: [dirty_delete_ram, dirty_delete_disc, 52: dirty_delete_disc_only]}, 53: {dirty_delete_object, [], 54: [dirty_delete_object_ram, dirty_delete_object_disc, 55: dirty_delete_object_disc_only]}, 56: {dirty_match_object, [], 57: [dirty_match_object_ram, dirty_match_object_disc, 58: dirty_match_object_disc_only]}, 59: {dirty_index, [], 60: [{group, dirty_index_match_object}, 61: {group, dirty_index_read}, 62: {group, dirty_index_update}]}, 63: {dirty_index_match_object, [], 64: [dirty_index_match_object_ram, 65: dirty_index_match_object_disc, 66: dirty_index_match_object_disc_only]}, 67: {dirty_index_read, [], 68: [dirty_index_read_ram, dirty_index_read_disc, 69: dirty_index_read_disc_only]}, 70: {dirty_index_update, [], 71: [dirty_index_update_set_ram, 72: dirty_index_update_set_disc, 73: dirty_index_update_set_disc_only, 74: dirty_index_update_bag_ram, dirty_index_update_bag_disc, 75: dirty_index_update_bag_disc_only]}, 76: {dirty_iter, [], 77: [dirty_iter_ram, dirty_iter_disc, 78: dirty_iter_disc_only]}, 79: {admin_tests, [], 80: [del_table_copy_1, del_table_copy_2, del_table_copy_3, 81: add_table_copy_1, add_table_copy_2, add_table_copy_3, 82: add_table_copy_4, move_table_copy_1, move_table_copy_2, 83: move_table_copy_3, move_table_copy_4]}]. 84: 85: init_per_group(_GroupName, Config) -> 86: Config. 87: 88: end_per_group(_GroupName, Config) -> 89: Config. 90: 91: 92: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 93: %% Write records dirty 94: 95: 96: dirty_write_ram(suite) -> []; 97: dirty_write_ram(Config) when is_list(Config) -> 98: dirty_write(Config, ram_copies). 99: 100: dirty_write_disc(suite) -> []; 101: dirty_write_disc(Config) when is_list(Config) -> 102: dirty_write(Config, disc_copies). 103: 104: dirty_write_disc_only(suite) -> []; 105: dirty_write_disc_only(Config) when is_list(Config) -> 106: dirty_write(Config, disc_only_copies). 107: 108: dirty_write(Config, Storage) -> 109: [Node1] = Nodes = ?acquire_nodes(1, Config), 110: Tab = dirty_write, 111: Def = [{attributes, [k, v]}, {Storage, [Node1]}], 112: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 113: 114: ?match({'EXIT', _}, mnesia:dirty_write([])), 115: ?match({'EXIT', _}, mnesia:dirty_write({Tab, 2})), 116: ?match({'EXIT', _}, mnesia:dirty_write({foo, 2})), 117: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 118: 119: ?match({atomic, ok}, mnesia:transaction(fun() -> 120: mnesia:dirty_write({Tab, 1, 2}) end)), 121: ?verify_mnesia(Nodes, []). 122: 123: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 124: %% Read records dirty 125: 126: 127: dirty_read_ram(suite) -> []; 128: dirty_read_ram(Config) when is_list(Config) -> 129: dirty_read(Config, ram_copies). 130: 131: dirty_read_disc(suite) -> []; 132: dirty_read_disc(Config) when is_list(Config) -> 133: dirty_read(Config, disc_copies). 134: 135: dirty_read_disc_only(suite) -> []; 136: dirty_read_disc_only(Config) when is_list(Config) -> 137: dirty_read(Config, disc_only_copies). 138: 139: dirty_read(Config, Storage) -> 140: [Node1] = Nodes = ?acquire_nodes(1, Config), 141: Tab = dirty_read, 142: Def = [{type, bag}, {attributes, [k, v]}, {Storage, [Node1]}], 143: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 144: 145: ?match({'EXIT', _}, mnesia:dirty_read([])), 146: ?match({'EXIT', _}, mnesia:dirty_read({Tab})), 147: ?match({'EXIT', _}, mnesia:dirty_read({Tab, 1, 2})), 148: ?match([], mnesia:dirty_read({Tab, 1})), 149: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 150: ?match([{Tab, 1, 2}], mnesia:dirty_read({Tab, 1})), 151: ?match(ok, mnesia:dirty_write({Tab, 1, 3})), 152: ?match([{Tab, 1, 2}, {Tab, 1, 3}], mnesia:dirty_read({Tab, 1})), 153: 154: ?match({atomic, [{Tab, 1, 2}, {Tab, 1, 3}]}, 155: mnesia:transaction(fun() -> mnesia:dirty_read({Tab, 1}) end)), 156: 157: ?match(false, mnesia:async_dirty(fun() -> mnesia:is_transaction() end)), 158: ?match(false, mnesia:sync_dirty(fun() -> mnesia:is_transaction() end)), 159: ?match(false, mnesia:ets(fun() -> mnesia:is_transaction() end)), 160: ?match(false, mnesia:activity(async_dirty, fun() -> mnesia:is_transaction() end)), 161: ?match(false, mnesia:activity(sync_dirty, fun() -> mnesia:is_transaction() end)), 162: ?match(false, mnesia:activity(ets, fun() -> mnesia:is_transaction() end)), 163: 164: ?verify_mnesia(Nodes, []). 165: 166: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167: %% Update counter record dirty 168: 169: 170: dirty_update_counter_ram(suite) -> []; 171: dirty_update_counter_ram(Config) when is_list(Config) -> 172: dirty_update_counter(Config, ram_copies). 173: 174: dirty_update_counter_disc(suite) -> []; 175: dirty_update_counter_disc(Config) when is_list(Config) -> 176: dirty_update_counter(Config, disc_copies). 177: 178: dirty_update_counter_disc_only(suite) -> []; 179: dirty_update_counter_disc_only(Config) when is_list(Config) -> 180: dirty_update_counter(Config, disc_only_copies). 181: 182: dirty_update_counter(Config, Storage) -> 183: [Node1] = Nodes = ?acquire_nodes(1, Config), 184: Tab = dirty_update_counter, 185: Def = [{attributes, [k, v]}, {Storage, [Node1]}], 186: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 187: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 188: 189: ?match({'EXIT', _}, mnesia:dirty_update_counter({Tab, 1}, [])), 190: ?match({'EXIT', _}, mnesia:dirty_update_counter({Tab}, 3)), 191: ?match({'EXIT', _}, mnesia:dirty_update_counter({foo, 1}, 3)), 192: ?match(5, mnesia:dirty_update_counter({Tab, 1}, 3)), 193: ?match([{Tab, 1, 5}], mnesia:dirty_read({Tab, 1})), 194: 195: ?match({atomic, 8}, mnesia:transaction(fun() -> 196: mnesia:dirty_update_counter({Tab, 1}, 3) end)), 197: 198: ?match(1, mnesia:dirty_update_counter({Tab, foo}, 1)), 199: ?match([{Tab, foo,1}], mnesia:dirty_read({Tab,foo})), 200: 201: ?match({ok,_}, mnesia:subscribe({table, Tab, detailed})), 202: 203: ?match(2, mnesia:dirty_update_counter({Tab, foo}, 1)), 204: ?match([{Tab, foo,2}], mnesia:dirty_read({Tab,foo})), 205: 206: ?verify_mnesia(Nodes, []). 207: 208: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 209: %% Delete record dirty 210: 211: 212: dirty_delete_ram(suite) -> []; 213: dirty_delete_ram(Config) when is_list(Config) -> 214: dirty_delete(Config, ram_copies). 215: 216: dirty_delete_disc(suite) -> []; 217: dirty_delete_disc(Config) when is_list(Config) -> 218: dirty_delete(Config, disc_copies). 219: 220: dirty_delete_disc_only(suite) -> []; 221: dirty_delete_disc_only(Config) when is_list(Config) -> 222: dirty_delete(Config, disc_only_copies). 223: 224: dirty_delete(Config, Storage) -> 225: [Node1] = Nodes = ?acquire_nodes(1, Config), 226: Tab = dirty_delete, 227: Def = [{type, bag}, {attributes, [k, v]}, {Storage, [Node1]}], 228: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 229: 230: ?match({'EXIT', _}, mnesia:dirty_delete([])), 231: ?match({'EXIT', _}, mnesia:dirty_delete({Tab})), 232: ?match({'EXIT', _}, mnesia:dirty_delete({Tab, 1, 2})), 233: ?match(ok, mnesia:dirty_delete({Tab, 1})), 234: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 235: ?match(ok, mnesia:dirty_delete({Tab, 1})), 236: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 237: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 238: ?match(ok, mnesia:dirty_delete({Tab, 1})), 239: 240: ?match(ok, mnesia:dirty_write({Tab, 1, 2})), 241: ?match({atomic, ok}, mnesia:transaction(fun() -> 242: mnesia:dirty_delete({Tab, 1}) end)), 243: ?verify_mnesia(Nodes, []). 244: 245: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 246: %% Delete matching record dirty 247: 248: 249: dirty_delete_object_ram(suite) -> []; 250: dirty_delete_object_ram(Config) when is_list(Config) -> 251: dirty_delete_object(Config, ram_copies). 252: 253: dirty_delete_object_disc(suite) -> []; 254: dirty_delete_object_disc(Config) when is_list(Config) -> 255: dirty_delete_object(Config, disc_copies). 256: 257: dirty_delete_object_disc_only(suite) -> []; 258: dirty_delete_object_disc_only(Config) when is_list(Config) -> 259: dirty_delete_object(Config, disc_only_copies). 260: 261: dirty_delete_object(Config, Storage) -> 262: [Node1] = Nodes = ?acquire_nodes(1, Config), 263: Tab = dirty_delete_object, 264: Def = [{type, bag}, {attributes, [k, v]}, {Storage, [Node1]}], 265: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 266: 267: OneRec = {Tab, 1, 2}, 268: ?match({'EXIT', _}, mnesia:dirty_delete_object([])), 269: ?match({'EXIT', _}, mnesia:dirty_delete_object({Tab})), 270: ?match({'EXIT', _}, mnesia:dirty_delete_object({Tab, 1})), 271: ?match(ok, mnesia:dirty_delete_object(OneRec)), 272: ?match(ok, mnesia:dirty_write(OneRec)), 273: ?match(ok, mnesia:dirty_delete_object(OneRec)), 274: ?match(ok, mnesia:dirty_write(OneRec)), 275: ?match(ok, mnesia:dirty_write(OneRec)), 276: ?match(ok, mnesia:dirty_delete_object(OneRec)), 277: 278: ?match(ok, mnesia:dirty_write(OneRec)), 279: ?match({atomic, ok}, mnesia:transaction(fun() -> 280: mnesia:dirty_delete_object(OneRec) end)), 281: 282: ?match({'EXIT', {aborted, {bad_type, Tab, _}}}, mnesia:dirty_delete_object(Tab, {Tab, {['_']}, 21})), 283: ?match({'EXIT', {aborted, {bad_type, Tab, _}}}, mnesia:dirty_delete_object(Tab, {Tab, {['$5']}, 21})), 284: 285: ?verify_mnesia(Nodes, []). 286: 287: 288: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289: %% Read matching records dirty 290: 291: 292: dirty_match_object_ram(suite) -> []; 293: dirty_match_object_ram(Config) when is_list(Config) -> 294: dirty_match_object(Config, ram_copies). 295: 296: dirty_match_object_disc(suite) -> []; 297: dirty_match_object_disc(Config) when is_list(Config) -> 298: dirty_match_object(Config, disc_copies). 299: 300: dirty_match_object_disc_only(suite) -> []; 301: dirty_match_object_disc_only(Config) when is_list(Config) -> 302: dirty_match_object(Config, disc_only_copies). 303: 304: dirty_match_object(Config, Storage) -> 305: [Node1] = Nodes = ?acquire_nodes(1, Config), 306: Tab = dirty_match, 307: Def = [{attributes, [k, v]}, {Storage, [Node1]}], 308: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 309: 310: OneRec = {Tab, 1, 2}, 311: OnePat = {Tab, '$1', 2}, 312: ?match([], mnesia:dirty_match_object(OnePat)), 313: ?match(ok, mnesia:dirty_write(OneRec)), 314: ?match([OneRec], mnesia:dirty_match_object(OnePat)), 315: ?match({atomic, [OneRec]}, mnesia:transaction(fun() -> 316: mnesia:dirty_match_object(OnePat) end)), 317: 318: ?match({'EXIT', _}, mnesia:dirty_match_object({foo, '$1', 2})), 319: ?match({'EXIT', _}, mnesia:dirty_match_object({[], '$1', 2})), 320: ?verify_mnesia(Nodes, []). 321: 322: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 323: 324: 325: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 326: %% Dirty read matching records by using an index 327: 328: 329: dirty_index_match_object_ram(suite) -> []; 330: dirty_index_match_object_ram(Config) when is_list(Config) -> 331: dirty_index_match_object(Config, ram_copies). 332: 333: dirty_index_match_object_disc(suite) -> []; 334: dirty_index_match_object_disc(Config) when is_list(Config) -> 335: dirty_index_match_object(Config, disc_copies). 336: 337: dirty_index_match_object_disc_only(suite) -> []; 338: dirty_index_match_object_disc_only(Config) when is_list(Config) -> 339: dirty_index_match_object(Config, disc_only_copies). 340: 341: dirty_index_match_object(Config, Storage) -> 342: [Node1] = Nodes = ?acquire_nodes(1, Config), 343: Tab = dirty_index_match_object, 344: ValPos = 3, 345: BadValPos = ValPos + 1, 346: Def = [{attributes, [k, v]}, {Storage, [Node1]}, {index, [ValPos]}], 347: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 348: 349: ?match([], mnesia:dirty_index_match_object({Tab, '$1', 2}, ValPos)), 350: OneRec = {Tab, 1, 2}, 351: ?match(ok, mnesia:dirty_write(OneRec)), 352: 353: ?match([OneRec], mnesia:dirty_index_match_object({Tab, '$1', 2}, ValPos)), 354: ?match({'EXIT', _}, mnesia:dirty_index_match_object({Tab, '$1', 2}, BadValPos)), 355: ?match({'EXIT', _}, mnesia:dirty_index_match_object({foo, '$1', 2}, ValPos)), 356: ?match({'EXIT', _}, mnesia:dirty_index_match_object({[], '$1', 2}, ValPos)), 357: ?match({atomic, [OneRec]}, mnesia:transaction(fun() -> 358: mnesia:dirty_index_match_object({Tab, '$1', 2}, ValPos) end)), 359: 360: ?verify_mnesia(Nodes, []). 361: 362: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 363: %% Read records by using an index 364: 365: 366: dirty_index_read_ram(suite) -> []; 367: dirty_index_read_ram(Config) when is_list(Config) -> 368: dirty_index_read(Config, ram_copies). 369: 370: dirty_index_read_disc(suite) -> []; 371: dirty_index_read_disc(Config) when is_list(Config) -> 372: dirty_index_read(Config, disc_copies). 373: 374: dirty_index_read_disc_only(suite) -> []; 375: dirty_index_read_disc_only(Config) when is_list(Config) -> 376: dirty_index_read(Config, disc_only_copies). 377: 378: dirty_index_read(Config, Storage) -> 379: [Node1] = Nodes = ?acquire_nodes(1, Config), 380: Tab = dirty_index_read, 381: ValPos = 3, 382: BadValPos = ValPos + 1, 383: Def = [{type, set}, 384: {attributes, [k, v]}, 385: {Storage, [Node1]}, 386: {index, [ValPos]}], 387: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 388: 389: OneRec = {Tab, 1, 2}, 390: ?match([], mnesia:dirty_index_read(Tab, 2, ValPos)), 391: ?match(ok, mnesia:dirty_write(OneRec)), 392: ?match([OneRec], mnesia:dirty_index_read(Tab, 2, ValPos)), 393: ?match({atomic, [OneRec]}, 394: mnesia:transaction(fun() -> mnesia:dirty_index_read(Tab, 2, ValPos) end)), 395: ?match(42, mnesia:dirty_update_counter({Tab, 1}, 40)), 396: ?match([{Tab,1,42}], mnesia:dirty_read({Tab, 1})), 397: ?match([], mnesia:dirty_index_read(Tab, 2, ValPos)), 398: ?match([{Tab, 1, 42}], mnesia:dirty_index_read(Tab, 42, ValPos)), 399: 400: ?match({'EXIT', _}, mnesia:dirty_index_read(Tab, 2, BadValPos)), 401: ?match({'EXIT', _}, mnesia:dirty_index_read(foo, 2, ValPos)), 402: ?match({'EXIT', _}, mnesia:dirty_index_read([], 2, ValPos)), 403: 404: ?verify_mnesia(Nodes, []). 405: 406: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 407: 408: 409: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 410: dirty_index_update_set_ram(suite) -> []; 411: dirty_index_update_set_ram(Config) when is_list(Config) -> 412: dirty_index_update_set(Config, ram_copies). 413: 414: dirty_index_update_set_disc(suite) -> []; 415: dirty_index_update_set_disc(Config) when is_list(Config) -> 416: dirty_index_update_set(Config, disc_copies). 417: 418: dirty_index_update_set_disc_only(suite) -> []; 419: dirty_index_update_set_disc_only(Config) when is_list(Config) -> 420: dirty_index_update_set(Config, disc_only_copies). 421: 422: dirty_index_update_set(Config, Storage) -> 423: [Node1] = Nodes = ?acquire_nodes(1, Config), 424: Tab = index_test, 425: ValPos = v1, 426: ValPos2 = v3, 427: Def = [{attributes, [k, v1, v2, v3]}, 428: {Storage, [Node1]}, 429: {index, [ValPos]}], 430: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 431: 432: Pat1 = {Tab, '$1', 2, '$2', '$3'}, 433: Pat2 = {Tab, '$1', '$2', '$3', '$4'}, 434: 435: Rec1 = {Tab, 1, 2, 3, 4}, 436: Rec2 = {Tab, 2, 2, 13, 14}, 437: Rec3 = {Tab, 1, 12, 13, 14}, 438: Rec4 = {Tab, 4, 2, 13, 14}, 439: 440: ?match([], mnesia:dirty_index_read(Tab, 2, ValPos)), 441: ?match(ok, mnesia:dirty_write(Rec1)), 442: ?match([Rec1], mnesia:dirty_index_read(Tab, 2, ValPos)), 443: 444: ?match(ok, mnesia:dirty_write(Rec2)), 445: R1 = mnesia:dirty_index_read(Tab, 2, ValPos), 446: ?match([Rec1, Rec2], lists:sort(R1)), 447: 448: ?match(ok, mnesia:dirty_write(Rec3)), 449: R2 = mnesia:dirty_index_read(Tab, 2, ValPos), 450: ?match([Rec2], lists:sort(R2)), 451: ?match([Rec2], mnesia:dirty_index_match_object(Pat1, ValPos)), 452: 453: {atomic, R3} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), 454: ?match([Rec3, Rec2], lists:sort(R3)), 455: 456: ?match(ok, mnesia:dirty_write(Rec4)), 457: R4 = mnesia:dirty_index_read(Tab, 2, ValPos), 458: ?match([Rec2, Rec4], lists:sort(R4)), 459: 460: ?match(ok, mnesia:dirty_delete({Tab, 4})), 461: ?match([Rec2], mnesia:dirty_index_read(Tab, 2, ValPos)), 462: 463: ?match({atomic, ok}, mnesia:del_table_index(Tab, ValPos)), 464: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec4) end)), 465: ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), 466: ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos2)), 467: 468: R5 = mnesia:dirty_match_object(Pat2), 469: ?match([Rec3, Rec2, Rec4], lists:sort(R5)), 470: 471: R6 = mnesia:dirty_index_read(Tab, 2, ValPos), 472: ?match([Rec2, Rec4], lists:sort(R6)), 473: ?match([], mnesia:dirty_index_read(Tab, 4, ValPos2)), 474: R7 = mnesia:dirty_index_read(Tab, 14, ValPos2), 475: ?match([Rec3, Rec2, Rec4], lists:sort(R7)), 476: 477: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec1) end)), 478: R8 = mnesia:dirty_index_read(Tab, 2, ValPos), 479: ?match([Rec1, Rec2, Rec4], lists:sort(R8)), 480: ?match([Rec1], mnesia:dirty_index_read(Tab, 4, ValPos2)), 481: R9 = mnesia:dirty_index_read(Tab, 14, ValPos2), 482: ?match([Rec2, Rec4], lists:sort(R9)), 483: 484: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec2) end)), 485: R10 = mnesia:dirty_index_read(Tab, 2, ValPos), 486: ?match([Rec1, Rec4], lists:sort(R10)), 487: ?match([Rec1], mnesia:dirty_index_read(Tab, 4, ValPos2)), 488: ?match([Rec4], mnesia:dirty_index_read(Tab, 14, ValPos2)), 489: 490: ?match(ok, mnesia:dirty_delete({Tab, 4})), 491: R11 = mnesia:dirty_index_read(Tab, 2, ValPos), 492: ?match([Rec1], lists:sort(R11)), 493: ?match([Rec1], mnesia:dirty_index_read(Tab, 4, ValPos2)), 494: ?match([], mnesia:dirty_index_read(Tab, 14, ValPos2)), 495: 496: ?verify_mnesia(Nodes, []). 497: 498: dirty_index_update_bag_ram(suite) -> []; 499: dirty_index_update_bag_ram(Config)when is_list(Config) -> 500: dirty_index_update_bag(Config, ram_copies). 501: 502: dirty_index_update_bag_disc(suite) -> []; 503: dirty_index_update_bag_disc(Config)when is_list(Config) -> 504: dirty_index_update_bag(Config, disc_copies). 505: 506: dirty_index_update_bag_disc_only(suite) -> []; 507: dirty_index_update_bag_disc_only(Config)when is_list(Config) -> 508: dirty_index_update_bag(Config, disc_only_copies). 509: 510: dirty_index_update_bag(Config, Storage) -> 511: [Node1] = Nodes = ?acquire_nodes(1, Config), 512: Tab = index_test, 513: ValPos = v1, 514: ValPos2 = v3, 515: Def = [{type, bag}, 516: {attributes, [k, v1, v2, v3]}, 517: {Storage, [Node1]}, 518: {index, [ValPos]}], 519: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 520: 521: Pat1 = {Tab, '$1', 2, '$2', '$3'}, 522: Pat2 = {Tab, '$1', '$2', '$3', '$4'}, 523: 524: Rec1 = {Tab, 1, 2, 3, 4}, 525: Rec2 = {Tab, 2, 2, 13, 14}, 526: Rec3 = {Tab, 1, 12, 13, 14}, 527: Rec4 = {Tab, 4, 2, 13, 4}, 528: Rec5 = {Tab, 1, 2, 234, 14}, 529: 530: %% Simple Index 531: ?match([], mnesia:dirty_index_read(Tab, 2, ValPos)), 532: ?match(ok, mnesia:dirty_write(Rec1)), 533: ?match([Rec1], mnesia:dirty_index_read(Tab, 2, ValPos)), 534: 535: ?match(ok, mnesia:dirty_delete_object(Rec5)), 536: ?match([Rec1], mnesia:dirty_index_read(Tab, 2, ValPos)), 537: 538: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec2) end)), 539: R1 = mnesia:dirty_index_read(Tab, 2, ValPos), 540: ?match([Rec1, Rec2], lists:sort(R1)), 541: 542: ?match(ok, mnesia:dirty_write(Rec3)), 543: R2 = mnesia:dirty_index_read(Tab, 2, ValPos), 544: ?match([Rec1, Rec2], lists:sort(R2)), 545: 546: R3 = mnesia:dirty_index_match_object(Pat1, ValPos), 547: ?match([Rec1, Rec2], lists:sort(R3)), 548: 549: R4 = mnesia:dirty_match_object(Pat2), 550: ?match([Rec1, Rec3, Rec2], lists:sort(R4)), 551: 552: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec4) end)), 553: R5 = mnesia:dirty_index_read(Tab, 2, ValPos), 554: ?match([Rec1, Rec2, Rec4], lists:sort(R5)), 555: 556: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete({Tab, 4}) end)), 557: R6 = mnesia:dirty_index_read(Tab, 2, ValPos), 558: ?match([Rec1, Rec2], lists:sort(R6)), 559: 560: ?match(ok, mnesia:dirty_delete_object(Rec1)), 561: ?match([Rec2], mnesia:dirty_index_read(Tab, 2, ValPos)), 562: R7 = mnesia:dirty_match_object(Pat2), 563: ?match([Rec3, Rec2], lists:sort(R7)), 564: 565: %% Two indexies 566: ?match({atomic, ok}, mnesia:del_table_index(Tab, ValPos)), 567: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec1) end)), 568: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec4) end)), 569: ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), 570: ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos2)), 571: 572: R8 = mnesia:dirty_index_read(Tab, 2, ValPos), 573: ?match([Rec1, Rec2, Rec4], lists:sort(R8)), 574: 575: R9 = mnesia:dirty_index_read(Tab, 4, ValPos2), 576: ?match([Rec1, Rec4], lists:sort(R9)), 577: R10 = mnesia:dirty_index_read(Tab, 14, ValPos2), 578: ?match([Rec3, Rec2], lists:sort(R10)), 579: 580: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec5) end)), 581: R11 = mnesia:dirty_index_read(Tab, 2, ValPos), 582: ?match([Rec1, Rec5, Rec2, Rec4], lists:sort(R11)), 583: R12 = mnesia:dirty_index_read(Tab, 4, ValPos2), 584: ?match([Rec1, Rec4], lists:sort(R12)), 585: R13 = mnesia:dirty_index_read(Tab, 14, ValPos2), 586: ?match([Rec5, Rec3, Rec2], lists:sort(R13)), 587: 588: ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec1) end)), 589: R14 = mnesia:dirty_index_read(Tab, 2, ValPos), 590: ?match([Rec5, Rec2, Rec4], lists:sort(R14)), 591: ?match([Rec4], mnesia:dirty_index_read(Tab, 4, ValPos2)), 592: R15 = mnesia:dirty_index_read(Tab, 14, ValPos2), 593: ?match([Rec5, Rec3, Rec2], lists:sort(R15)), 594: 595: ?match(ok, mnesia:dirty_delete_object(Rec5)), 596: R16 = mnesia:dirty_index_read(Tab, 2, ValPos), 597: ?match([Rec2, Rec4], lists:sort(R16)), 598: ?match([Rec4], mnesia:dirty_index_read(Tab, 4, ValPos2)), 599: R17 = mnesia:dirty_index_read(Tab, 14, ValPos2), 600: ?match([Rec3, Rec2], lists:sort(R17)), 601: 602: ?match(ok, mnesia:dirty_write(Rec1)), 603: ?match(ok, mnesia:dirty_delete({Tab, 1})), 604: R18 = mnesia:dirty_index_read(Tab, 2, ValPos), 605: ?match([Rec2, Rec4], lists:sort(R18)), 606: ?match([Rec4], mnesia:dirty_index_read(Tab, 4, ValPos2)), 607: R19 = mnesia:dirty_index_read(Tab, 14, ValPos2), 608: ?match([Rec2], lists:sort(R19)), 609: 610: ?verify_mnesia(Nodes, []). 611: 612: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 613: %% Dirty iteration 614: %% dirty_slot, dirty_first, dirty_next 615: 616: 617: dirty_iter_ram(suite) -> []; 618: dirty_iter_ram(Config) when is_list(Config) -> 619: dirty_iter(Config, ram_copies). 620: 621: dirty_iter_disc(suite) -> []; 622: dirty_iter_disc(Config) when is_list(Config) -> 623: dirty_iter(Config, disc_copies). 624: 625: dirty_iter_disc_only(suite) -> []; 626: dirty_iter_disc_only(Config) when is_list(Config) -> 627: dirty_iter(Config, disc_only_copies). 628: 629: dirty_iter(Config, Storage) -> 630: [Node1] = Nodes = ?acquire_nodes(1, Config), 631: Tab = dirty_iter, 632: Def = [{type, bag}, {attributes, [k, v]}, {Storage, [Node1]}], 633: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 634: 635: ?match([], all_slots(Tab)), 636: ?match([], all_nexts(Tab)), 637: 638: Keys = lists:seq(1, 5), 639: Records = [{Tab, A, B} || A <- Keys, B <- lists:seq(1, 2)], 640: lists:foreach(fun(Rec) -> ?match(ok, mnesia:dirty_write(Rec)) end, Records), 641: 642: SortedRecords = lists:sort(Records), 643: ?match(SortedRecords, lists:sort(all_slots(Tab))), 644: ?match(Keys, lists:sort(all_nexts(Tab))), 645: 646: ?match({'EXIT', _}, mnesia:dirty_first(foo)), 647: ?match({'EXIT', _}, mnesia:dirty_next(foo, foo)), 648: ?match({'EXIT', _}, mnesia:dirty_slot(foo, 0)), 649: ?match({'EXIT', _}, mnesia:dirty_slot(foo, [])), 650: ?match({atomic, Keys}, 651: mnesia:transaction(fun() -> lists:sort(all_nexts(Tab)) end)), 652: ?verify_mnesia(Nodes, []). 653: 654: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 655: 656: %% Returns a list of all keys in table 657: all_slots(Tab) -> 658: all_slots(Tab, [], 0). 659: 660: all_slots(_Tab, '$end_of_table', _) -> 661: []; 662: all_slots(Tab, PrevRecords, PrevSlot) -> 663: Records = mnesia:dirty_slot(Tab, PrevSlot), 664: PrevRecords ++ all_slots(Tab, Records, PrevSlot + 1). 665: 666: %% Returns a list of all keys in table 667: 668: all_nexts(Tab) -> 669: FirstKey = mnesia:dirty_first(Tab), 670: all_nexts(Tab, FirstKey). 671: 672: all_nexts(_Tab, '$end_of_table') -> 673: []; 674: all_nexts(Tab, PrevKey) -> 675: Key = mnesia:dirty_next(Tab, PrevKey), 676: [PrevKey] ++ all_nexts(Tab, Key). 677: 678: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 679: 680: update_trans(Tab, Key, Acc) -> 681: Update = 682: fun() -> 683: Res = (catch mnesia:read({Tab, Key})), 684: case Res of 685: [{Tab, Key, Extra, Acc}] -> 686: mnesia:write({Tab,Key,Extra, Acc+1}); 687: Val -> 688: {read, Val, {acc, Acc}} 689: end 690: end, 691: receive 692: {Pid, quit} -> Pid ! {self(), Acc} 693: after 694: 3 -> 695: case catch mnesia:sync_dirty(Update) of 696: ok -> 697: update_trans(Tab, Key, Acc+1); 698: Else -> 699: ?error("Dirty Operation failed on ~p (update no ~p) with ~p~n" 700: "Info w2read ~p w2write ~p w2commit ~p storage ~p ~n", 701: [node(), 702: Acc, 703: Else, 704: mnesia:table_info(Tab, where_to_read), 705: mnesia:table_info(Tab, where_to_write), 706: mnesia:table_info(Tab, where_to_commit), 707: mnesia:table_info(Tab, storage_type)]) 708: end 709: end. 710: 711: del_table_copy_1(suite) -> []; 712: del_table_copy_1(Config) when is_list(Config) -> 713: [_Node1, Node2, _Node3] = Nodes = ?acquire_nodes(3, Config), 714: del_table(Node2, Node2, Nodes). %Called on same Node as deleted 715: del_table_copy_2(suite) -> []; 716: del_table_copy_2(Config) when is_list(Config) -> 717: [Node1, Node2, _Node3] = Nodes = ?acquire_nodes(3, Config), 718: del_table(Node1, Node2, Nodes). %Called from other Node 719: del_table_copy_3(suite) -> []; 720: del_table_copy_3(Config) when is_list(Config) -> 721: [_Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 722: del_table(Node3, Node2, Nodes). %Called from Node w.o. table 723: 724: del_table(CallFrom, DelNode, [Node1, Node2, Node3]) -> 725: Tab = schema_ops, 726: Def = [{disc_only_copies, [Node1]}, {ram_copies, [Node2]}, 727: {attributes, [key, attr1, attr2]}], 728: ?log("Test case removing table from ~w, with ~w~n", [DelNode, Def]), 729: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 730: insert(Tab, 1000), 731: 732: Pid1 = spawn_link(Node1, ?MODULE, update_trans, [Tab, 1, 0]), 733: Pid2 = spawn_link(Node2, ?MODULE, update_trans, [Tab, 2, 0]), 734: Pid3 = spawn_link(Node3, ?MODULE, update_trans, [Tab, 3, 0]), 735: 736: 737: dbg:tracer(process, {fun(Msg,_) -> tracer(Msg) end, void}), 738: %% dbg:n(Node2), 739: %% dbg:n(Node3), 740: %% dbg:tp('_', []), 741: %% dbg:tpl(dets, [timestamp]), 742: dbg:p(Pid1, [m,c,timestamp]), 743: 744: ?match({atomic, ok}, 745: rpc:call(CallFrom, mnesia, del_table_copy, [Tab, DelNode])), 746: 747: Pid1 ! {self(), quit}, R1 = 748: receive {Pid1, Res1} -> Res1 749: after 750: 5000 -> io:format("~p~n",[process_info(Pid1)]),error 751: end, 752: Pid2 ! {self(), quit}, R2 = 753: receive {Pid2, Res2} -> Res2 754: after 755: 5000 -> error 756: end, 757: Pid3 ! {self(), quit}, R3 = 758: receive {Pid3, Res3} -> Res3 759: after 760: 5000 -> error 761: end, 762: verify_oids(Tab, Node1, Node2, Node3, R1, R2, R3), 763: ?verify_mnesia([Node1, Node2, Node3], []). 764: 765: tracer({trace_ts, _, send, Msg, Pid, {_,S,Ms}}) -> 766: io:format("~p:~p ~p >> ~w ~n",[S,Ms,Pid,Msg]); 767: tracer({trace_ts, _, 'receive', Msg, {_,S,Ms}}) -> 768: io:format("~p:~p << ~w ~n",[S,Ms,Msg]); 769: 770: 771: tracer(Msg) -> 772: io:format("UMsg ~p ~n",[Msg]), 773: ok. 774: 775: 776: 777: add_table_copy_1(suite) -> []; 778: add_table_copy_1(Config) when is_list(Config) -> 779: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 780: Def = [{ram_copies, [Node1, Node2]}, 781: {attributes, [key, attr1, attr2]}], 782: add_table(Node1, Node3, Nodes, Def). 783: %% Not so much diff from 1 but I got a feeling of a bug 784: %% should behave exactly the same but just checking the internal ordering 785: add_table_copy_2(suite) -> []; 786: add_table_copy_2(Config) when is_list(Config) -> 787: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 788: Def = [{ram_copies, [Node1, Node2]}, 789: {attributes, [key, attr1, attr2]}], 790: add_table(Node2, Node3, Nodes, Def). 791: add_table_copy_3(suite) -> []; 792: add_table_copy_3(Config) when is_list(Config) -> 793: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 794: Def = [{ram_copies, [Node1, Node2]}, 795: {attributes, [key, attr1, attr2]}], 796: add_table(Node3, Node3, Nodes, Def). 797: add_table_copy_4(suite) -> []; 798: add_table_copy_4(Config) when is_list(Config) -> 799: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 800: Def = [{disc_only_copies, [Node1]}, 801: {attributes, [key, attr1, attr2]}], 802: add_table(Node2, Node3, Nodes, Def). 803: 804: add_table(CallFrom, AddNode, [Node1, Node2, Node3], Def) -> 805: ?log("Test case adding table at ~w, with ~w~n", [AddNode, Def]), 806: Tab = schema_ops, 807: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 808: insert(Tab, 1002), 809: 810: Pid1 = spawn_link(Node1, ?MODULE, update_trans, [Tab, 1, 0]), 811: Pid2 = spawn_link(Node2, ?MODULE, update_trans, [Tab, 2, 0]), 812: Pid3 = spawn_link(Node3, ?MODULE, update_trans, [Tab, 3, 0]), 813: 814: ?match({atomic, ok}, rpc:call(CallFrom, mnesia, add_table_copy, 815: [Tab, AddNode, ram_copies])), 816: Pid1 ! {self(), quit}, R1 = receive {Pid1, Res1} -> Res1 after 5000 -> error end, 817: Pid2 ! {self(), quit}, R2 = receive {Pid2, Res2} -> Res2 after 5000 -> error end, 818: Pid3 ! {self(), quit}, R3 = receive {Pid3, Res3} -> Res3 after 5000 -> error end, 819: verify_oids(Tab, Node1, Node2, Node3, R1, R2, R3), 820: ?verify_mnesia([Node1, Node2, Node3], []). 821: 822: move_table_copy_1(suite) -> []; 823: move_table_copy_1(Config) when is_list(Config) -> 824: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 825: Def = [{ram_copies, [Node1, Node2]}, 826: {attributes, [key, attr1, attr2]}], 827: move_table(Node1, Node1, Node3, Nodes, Def). 828: move_table_copy_2(suite) -> []; 829: move_table_copy_2(Config) when is_list(Config) -> 830: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 831: Def = [{ram_copies, [Node1, Node2]}, 832: {attributes, [key, attr1, attr2]}], 833: move_table(Node2, Node1, Node3, Nodes, Def). 834: move_table_copy_3(suite) -> []; 835: move_table_copy_3(Config) when is_list(Config) -> 836: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 837: Def = [{ram_copies, [Node1, Node2]}, 838: {attributes, [key, attr1, attr2]}], 839: move_table(Node3, Node1, Node3, Nodes, Def). 840: move_table_copy_4(suite) -> []; 841: move_table_copy_4(Config) when is_list(Config) -> 842: [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 843: Def = [{ram_copies, [Node1]}, 844: {attributes, [key, attr1, attr2]}], 845: move_table(Node2, Node1, Node3, Nodes, Def). 846: 847: move_table(CallFrom, FromNode, ToNode, [Node1, Node2, Node3], Def) -> 848: ?log("Test case move table from ~w to ~w, with ~w~n", [FromNode, ToNode, Def]), 849: Tab = schema_ops, 850: ?match({atomic, ok}, mnesia:create_table(Tab, Def)), 851: insert(Tab, 1002), 852: 853: Pid1 = spawn_link(Node1, ?MODULE, update_trans, [Tab, 1, 0]), 854: Pid2 = spawn_link(Node2, ?MODULE, update_trans, [Tab, 2, 0]), 855: Pid3 = spawn_link(Node3, ?MODULE, update_trans, [Tab, 3, 0]), 856: 857: ?match({atomic, ok}, rpc:call(CallFrom, mnesia, move_table_copy, 858: [Tab, FromNode, ToNode])), 859: Pid1 ! {self(), quit}, 860: R1 = receive {Pid1, Res1} -> Res1 after 5000 -> ?error("timeout pid1~n", []) end, 861: Pid2 ! {self(), quit}, 862: R2 = receive {Pid2, Res2} -> Res2 after 5000 -> ?error("timeout pid2~n", []) end, 863: Pid3 ! {self(), quit}, 864: R3 = receive {Pid3, Res3} -> Res3 after 5000 -> ?error("timeout pid3~n", []) end, 865: verify_oids(Tab, Node1, Node2, Node3, R1, R2, R3), 866: ?verify_mnesia([Node1, Node2, Node3], []). 867: 868: % Verify consistency between different nodes 869: % Due to limitations in the current dirty_ops this can wrong from time to time! 870: verify_oids(Tab, N1, N2, N3, R1, R2, R3) -> 871: io:format("DEBUG 1=>~p 2=>~p 3=>~p~n", [R1,R2,R3]), 872: ?match([{_, _, _, R1}], rpc:call(N1, mnesia, dirty_read, [{Tab, 1}])), 873: ?match([{_, _, _, R1}], rpc:call(N2, mnesia, dirty_read, [{Tab, 1}])), 874: ?match([{_, _, _, R1}], rpc:call(N3, mnesia, dirty_read, [{Tab, 1}])), 875: ?match([{_, _, _, R2}], rpc:call(N1, mnesia, dirty_read, [{Tab, 2}])), 876: ?match([{_, _, _, R2}], rpc:call(N2, mnesia, dirty_read, [{Tab, 2}])), 877: ?match([{_, _, _, R2}], rpc:call(N3, mnesia, dirty_read, [{Tab, 2}])), 878: ?match([{_, _, _, R3}], rpc:call(N1, mnesia, dirty_read, [{Tab, 3}])), 879: ?match([{_, _, _, R3}], rpc:call(N2, mnesia, dirty_read, [{Tab, 3}])), 880: ?match([{_, _, _, R3}], rpc:call(N3, mnesia, dirty_read, [{Tab, 3}])). 881: 882: insert(_Tab, 0) -> ok; 883: insert(Tab, N) when N > 0 -> 884: ok = mnesia:sync_dirty(fun() -> false = mnesia:is_transaction(), mnesia:write({Tab, N, N, 0}) end), 885: insert(Tab, N-1). 886: 887: 888: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%