1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2019. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(disk_log_SUITE). 21 22%%-define(debug, true). 23 24-ifdef(debug). 25-define(format(S, A), io:format(S, A)). 26-define(line, put(line, ?LINE), ). 27-define(privdir(_), "./disk_log_SUITE_priv"). 28-define(datadir(_), "./disk_log_SUITE_data"). 29-define(config(X,Y), foo). 30-define(t,test_server). 31-else. 32-include_lib("common_test/include/ct.hrl"). 33-define(format(S, A), ok). 34-define(privdir(Conf), proplists:get_value(priv_dir, Conf)). 35-define(datadir(Conf), proplists:get_value(data_dir, Conf)). 36-endif. 37 38-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 39 init_per_group/2,end_per_group/2, 40 41 halt_int_inf/1, 42 halt_int_sz_1/1, halt_int_sz_2/1, 43 44 halt_int_ro/1, halt_ext_ro/1, wrap_int_ro/1, 45 wrap_ext_ro/1, halt_trunc/1, halt_misc/1, halt_ro_alog/1, 46 halt_ro_balog/1, halt_ro_crash/1, 47 48 wrap_int_1/1, wrap_int_2/1, inc_wrap_file/1, 49 50 halt_ext_inf/1, 51 52 halt_ext_sz_1/1, halt_ext_sz_2/1, 53 54 wrap_ext_1/1, wrap_ext_2/1, 55 56 head_func/1, plain_head/1, one_header/1, 57 58 wrap_notif/1, full_notif/1, trunc_notif/1, blocked_notif/1, 59 60 new_idx_vsn/1, 61 62 reopen/1, 63 64 block_blocked/1, block_queue/1, block_queue2/1, 65 66 unblock/1, 67 68 open_overwrite/1, open_size/1, open_truncate/1, open_error/1, 69 70 close_race/1, close_block/1, close_deadlock/1, 71 72 error_repair/1, error_log/1, error_index/1, 73 74 chunk/1, 75 76 truncate/1, 77 78 many_users/1, 79 80 info_current/1, 81 82 change_size_before/1, change_size_during/1, 83 change_size_after/1, default_size/1, change_size2/1, 84 change_size_truncate/1, 85 86 change_attribute/1, 87 88 dist_open/1, dist_error_open/1, dist_notify/1, 89 dist_terminate/1, dist_accessible/1, dist_deadlock/1, 90 dist_open2/1, other_groups/1, 91 92 otp_6278/1, otp_10131/1, otp_16768/1]). 93 94-export([head_fun/1, hf/0, lserv/1, 95 measure/0, init_m/1, xx/0, head_exit/0, slow_header/1]). 96 97-export([init_per_testcase/2, end_per_testcase/2]). 98 99-export([try_unblock/1]). 100 101-export([client/4]). 102 103%% error_logger 104-export([init/1, 105 handle_event/2, handle_call/2, handle_info/2, 106 terminate/2]). 107 108-include_lib("kernel/include/file.hrl"). 109-include_lib("kernel/src/disk_log.hrl"). 110 111%% TODO (old): 112%% - global logs 113%% - badarg 114%% - force file:write fail (how?) 115%% - kill logging proc while he is logging 116%% - kill logging node while he is logging 117%% - test chunk_step 118 119%% These are all tests, the list to be returned by all(). 120-define(ALL_TESTS, 121 [halt_int, wrap_int, halt_ext, wrap_ext, read_mode, head, 122 notif, new_idx_vsn, reopen, block, unblock, open, close, 123 error, chunk, truncate, many_users, info, change_size, 124 change_attribute, distribution, otp_6278, otp_10131, otp_16768]). 125 126%% These test cases should be skipped if the VxWorks card is 127%% configured without NFS cache. 128-define(SKIP_NO_CACHE,[distribution]). 129%% These tests should be skipped if the VxWorks card is configured *with* 130%% nfs cache. 131-define(SKIP_LARGE_CACHE,[inc_wrap_file, halt_ext, wrap_ext, read_mode, 132 head, wrap_notif, open_size, error_log, 133 error_index, chunk, 134 change_size_before, change_size_during, 135 change_size_after, default_size]). 136 137 138suite() -> 139 [{ct_hooks,[ts_install_cth]}, 140 {timetrap,{minutes,2}}]. 141 142all() -> 143 [{group, halt_int}, {group, wrap_int}, 144 {group, halt_ext}, {group, wrap_ext}, 145 {group, read_mode}, {group, head}, {group, notif}, 146 new_idx_vsn, reopen, {group, block}, unblock, 147 {group, open}, {group, close}, {group, error}, chunk, 148 truncate, many_users, {group, info}, 149 {group, change_size}, change_attribute, 150 {group, distribution}, otp_6278, otp_10131, otp_16768]. 151 152groups() -> 153 [{halt_int, [], [halt_int_inf, {group, halt_int_sz}]}, 154 {halt_int_sz, [], [halt_int_sz_1, halt_int_sz_2]}, 155 {read_mode, [], 156 [halt_int_ro, halt_ext_ro, wrap_int_ro, wrap_ext_ro, 157 halt_trunc, halt_misc, halt_ro_alog, halt_ro_balog, 158 halt_ro_crash]}, 159 {wrap_int, [], [wrap_int_1, wrap_int_2, inc_wrap_file]}, 160 {halt_ext, [], [halt_ext_inf, {group, halt_ext_sz}]}, 161 {halt_ext_sz, [], [halt_ext_sz_1, halt_ext_sz_2]}, 162 {wrap_ext, [], [wrap_ext_1, wrap_ext_2]}, 163 {head, [], [head_func, plain_head, one_header]}, 164 {notif, [], 165 [wrap_notif, full_notif, trunc_notif, blocked_notif]}, 166 {block, [], [block_blocked, block_queue, block_queue2]}, 167 {open, [], 168 [open_overwrite, open_size, open_truncate, open_error]}, 169 {close, [], [close_race, close_block, close_deadlock]}, 170 {error, [], [error_repair, error_log, error_index]}, 171 {info, [], [info_current]}, 172 {change_size, [], 173 [change_size_before, change_size_during, 174 change_size_after, default_size, change_size2, 175 change_size_truncate]}, 176 {distribution, [], 177 [dist_open, dist_error_open, dist_notify, 178 dist_terminate, dist_accessible, dist_deadlock, 179 dist_open2, other_groups]}]. 180 181init_per_suite(Config) -> 182 Config. 183 184end_per_suite(_Config) -> 185 ok. 186 187init_per_group(_GroupName, Config) -> 188 Config. 189 190end_per_group(_GroupName, Config) -> 191 Config. 192 193 194 195init_per_testcase(_Case, Config) -> 196 Config. 197 198end_per_testcase(_Case, _Config) -> 199 ok. 200 201 202%% Test simple halt disk log, size infinity. 203halt_int_inf(Conf) when is_list(Conf) -> 204 Dir = ?privdir(Conf), 205 ok = disk_log:start(), 206 File = filename:join(Dir, "a.LOG"), 207 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 208 {format,internal}, 209 {file, File}]), 210 simple_log(a), 211 ok = disk_log:close(a), 212 ok = file:delete(File). 213 214 215%% Test simple halt disk log, size defined. 216halt_int_sz_1(Conf) when is_list(Conf) -> 217 Dir = ?privdir(Conf), 218 File = filename:join(Dir, "a.LOG"), 219 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,18000}, 220 {format,internal}, 221 {file, File}]), 222 simple_log(a), 223 ok = disk_log:truncate(a), 224 [] = get_all_terms(a), 225 T1 = mk_bytes(10000), 226 T2 = mk_bytes(5000), 227 ok = disk_log:log(a, T1), 228 case get_all_terms(a) of 229 [T1] -> 230 ok; 231 E1 -> 232 test_server_fail({bad_terms, E1, [T1]}) 233 end, 234 ok = disk_log:log(a, T2), 235 {error, {full, a}} = disk_log:log(a, T1), 236 ok = disk_log:alog(a, T1), 237 case get_all_terms(a) of 238 [T1, T2] -> 239 ok; 240 E2 -> 241 test_server_fail({bad_terms, E2, [T1, T2]}) 242 end, 243 ok = disk_log:close(a), 244 ok = file:delete(File). 245 246%% Test simple halt disk log, size ~8192. 247halt_int_sz_2(Conf) when is_list(Conf) -> 248 Dir = ?privdir(Conf), 249 File1 = filename:join(Dir, "a.LOG"), 250 File2 = filename:join(Dir, "b.LOG"), 251 File3 = filename:join(Dir, "c.LOG"), 252 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,8191}, 253 {format,internal}, 254 {file, File1}]), 255 {ok, b} = disk_log:open([{name,b}, {type,halt}, {size,8192}, 256 {format,internal}, 257 {file, File2}]), 258 {ok, c} = disk_log:open([{name,c}, {type,halt}, {size,8193}, 259 {format,internal}, 260 {file, File3}]), 261 T1 = mk_bytes(8191-16), % 16 is size of header + magics for 1 item 262 T2 = mk_bytes(8192-16), 263 T3 = mk_bytes(8193-16), 264 ok = disk_log:log(a, T1), 265 ok = disk_log:log(b, T2), 266 ok = disk_log:log(c, T3), 267 case get_all_terms(a) of 268 [T1] -> 269 ok; 270 E1 -> 271 test_server_fail({bad_terms, E1, [T1]}) 272 end, 273 case get_all_terms(b) of 274 [T2] -> 275 ok; 276 E2 -> 277 test_server_fail({bad_terms, E2, [T2]}) 278 end, 279 case get_all_terms(c) of 280 [T3] -> 281 ok; 282 E3 -> 283 test_server_fail({bad_terms, E3, [T3]}) 284 end, 285 ok = disk_log:truncate(a), 286 ok = disk_log:truncate(b), 287 {error, {full, a}} = disk_log:log(a, T2), 288 {error, {full, b}} = disk_log:log(b, T3), 289 [] = get_all_terms(a), 290 [] = get_all_terms(b), 291 ok = disk_log:close(a), 292 ok = disk_log:close(b), 293 ok = disk_log:close(c), 294 ok = file:delete(File1), 295 ok = file:delete(File2), 296 ok = file:delete(File3), 297 ok. 298 299 300%% Test simple halt disk log, read only, internal. 301halt_int_ro(Conf) when is_list(Conf) -> 302 Dir = ?privdir(Conf), 303 File = filename:join(Dir, "a.LOG"), 304 305 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 306 {format,internal}, {file, File}]), 307 simple_log(a), 308 ok = disk_log:close(a), 309 310 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 311 {format,internal}, {file, File}, 312 {mode,read_only}]), 313 T1 = "not allowed to write", 314 {error, {read_only_mode, a}} = disk_log:log(a, T1), 315 ok = disk_log:close(a), 316 ok = file:delete(File). 317 318%% Test simple halt disk log, read only, external. 319halt_ext_ro(Conf) when is_list(Conf) -> 320 Dir = ?privdir(Conf), 321 File = filename:join(Dir, "a.LOG"), 322 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 323 {format,external}, {file, File}]), 324 xsimple_log(File, a), 325 ok = disk_log:close(a), 326 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 327 {format,external}, {file, File}, 328 {mode,read_only}]), 329 T1 = "not allowed to write", 330 {error, {read_only_mode, a}} = disk_log:blog(a, T1), 331 ok = disk_log:close(a), 332 ok = file:delete(File). 333 334%% Test simple wrap disk log, read only, internal. 335wrap_int_ro(Conf) when is_list(Conf) -> 336 Dir = ?privdir(Conf), 337 File = filename:join(Dir, "a.LOG"), 338 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 339 {format,internal}, {file, File}]), 340 simple_log(a), 341 ok = disk_log:close(a), 342 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 343 {format,internal}, {file, File}, {mode,read_only}]), 344 T1 = "not allowed to write", 345 {error, {read_only_mode, a}} = disk_log:log(a, T1), 346 ok = disk_log:close(a), 347 del(File, 4). 348 349%% Test simple wrap disk log, read only, external. 350wrap_ext_ro(Conf) when is_list(Conf) -> 351 Dir = ?privdir(Conf), 352 File = filename:join(Dir, "a.LOG"), 353 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 354 {format,external}, {file, File}]), 355 x2simple_log(File ++ ".1", a), 356 ok = disk_log:close(a), 357 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 358 {format,external}, {file, File}, 359 {mode,read_only}]), 360 T1 = "not allowed to write", 361 {error, {read_only_mode, a}} = disk_log:blog(a, T1), 362 {error, {read_only_mode, a}} = disk_log:inc_wrap_file(a), 363 ok = disk_log:close(a), 364 del(File, 4). 365 366%% Test truncation of halt disk log. 367halt_trunc(Conf) when is_list(Conf) -> 368 Dir = ?privdir(Conf), 369 File = filename:join(Dir, "a.LOG"), 370 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 371 {format,internal}, {file, File}]), 372 simple_log(a), 373 ok = disk_log:close(a), 374 {error,{badarg,repair_read_only}} = 375 disk_log:open([{name,a}, {type,halt}, {size,infinity}, 376 {repair, truncate}, {format,internal}, 377 {file, File}, {mode,read_only}]), 378 ok = file:delete(File). 379 380%% Test truncation of halt disk log. 381halt_misc(Conf) when is_list(Conf) -> 382 Dir = ?privdir(Conf), 383 File = filename:join(Dir, "a.LOG"), 384 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 385 {format,internal}, {file, File}]), 386 simple_log(a), 387 ok = disk_log:close(a), 388 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 389 {format,internal}, {file, File}, 390 {mode,read_only}]), 391 T1 = "not allowed to write", 392 {error, {read_only_mode, a}} = disk_log:log(a, T1), 393 {error, {read_only_mode, a}} = disk_log:sync(a), 394 {error, {read_only_mode, a}} = disk_log:reopen(a, "b.LOG"), 395 {error, {read_only_mode, a}} = 396 disk_log:change_header(a, {head,header}), 397 {error, {read_only_mode, a}} = 398 disk_log:change_size(a, infinity), 399 ok = disk_log:close(a), 400 ok = file:delete(File). 401 402%% Test truncation of halt disk log, read only. 403halt_ro_alog(Conf) when is_list(Conf) -> 404 Dir = ?privdir(Conf), 405 File = filename:join(Dir, "a.LOG"), 406 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 407 {format,internal}, {file, File}]), 408 simple_log(a), 409 ok = disk_log:close(a), 410 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 411 {notify,true}, {format,internal}, 412 {file, File}, {mode,read_only}]), 413 T1 = "not allowed to write", 414 ok = disk_log:alog(a, T1), 415 ok = halt_ro_alog_wait_notify(a, T1), 416 ok = disk_log:close(a), 417 ok = file:delete(File). 418 419halt_ro_alog_wait_notify(Log, T) -> 420 Term = term_to_binary(T), 421 receive 422 {disk_log, _, Log,{read_only, [Term]}} -> 423 ok; 424 Other -> 425 Other 426 after 5000 -> 427 failed 428 end. 429 430%% Test truncation of halt disk log, read only. 431halt_ro_balog(Conf) when is_list(Conf) -> 432 Dir = ?privdir(Conf), 433 File = filename:join(Dir, "a.LOG"), 434 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 435 {format,internal}, {file, File}]), 436 simple_log(a), 437 ok = disk_log:close(a), 438 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 439 {notify,true}, {format,external}, 440 {file, File}, {mode,read_only}]), 441 T1 = "not allowed to write", 442 ok = disk_log:balog(a, T1), 443 ok = halt_ro_balog_wait_notify(a, T1), 444 ok = disk_log:close(a), 445 ok = file:delete(File). 446 447halt_ro_balog_wait_notify(Log, T) -> 448 Term = list_to_binary(T), 449 receive 450 {disk_log, _, Log,{read_only, [Term]}} -> 451 ok; 452 Other -> 453 Other 454 after 5000 -> 455 failed 456 end. 457 458%% Test truncation of halt disk log, read only, repair. 459halt_ro_crash(Conf) when is_list(Conf) -> 460 Dir = ?privdir(Conf), 461 File = filename:join(Dir, "a.LOG"), 462 463 file:delete(File), 464 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 465 {format,internal},{file, File}]), 466 simple_log(a), 467 ok = disk_log:close(a), 468 crash(File, 10), 469 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 470 {notify,true}, {format,internal}, 471 {file, File}, {mode,read_only}]), 472 473 Error1 = {error, {read_only_mode, a}} = disk_log:truncate(a), 474 "The disk log" ++ _ = format_error(Error1), 475 476 %% crash/1 sets the length of the first item to something big (2.5 kb). 477 %% In R6B, binary_to_term accepts garbage at the end of the binary, 478 %% which means that the first item is recognized! 479 %% This is how it was before R6B: 480 %% {C1,T1,15} = disk_log:chunk(a,start), 481 %% {C2,T2} = disk_log:chunk(a,C1), 482 {C1,_OneItem,7478} = disk_log:chunk(a,start), 483 {C2, [], 7} = disk_log:chunk(a,C1), 484 eof = disk_log:chunk(a,C2), 485 ok = disk_log:close(a), 486 ok = file:delete(File). 487 488 489 490 491 492%% Test wrap disk log, internal. 493wrap_int_1(Conf) when is_list(Conf) -> 494 Dir = ?privdir(Conf), 495 File = filename:join(Dir, "a.LOG"), 496 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 497 {format,internal}, 498 {file, File}]), 499 [_] = 500 lists:filter(fun(P) -> disk_log:pid2name(P) =/= undefined end, 501 erlang:processes()), 502 simple_log(a), 503 ok = disk_log:close(a), 504 del(File, 4), 505 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 506 {format,internal}, 507 {file, File}]), 508 [] = get_all_terms(a), 509 T1 = mk_bytes(10000), % file 2 510 T2 = mk_bytes(5000), % file 3 511 T3 = mk_bytes(4000), % file 4 512 T4 = mk_bytes(2000), % file 4 513 T5 = mk_bytes(5000), % file 1 514 T6 = mk_bytes(5000), % file 2 515 ok = disk_log:log(a, T1), 516 ok = disk_log:log(a, T2), 517 ok = disk_log:log(a, T3), 518 ok = disk_log:log_terms(a, [T4, T5, T6]), 519 case get_all_terms(a) of 520 [T2,T3,T4,T5,T6] -> 521 ok; 522 E1 -> 523 test_server_fail({bad_terms, E1, [T2,T3,T4,T5,T6]}) 524 end, 525 ok = disk_log:close(a), 526 del(File, 4). 527 528%% Test wrap disk log, internal. 529wrap_int_2(Conf) when is_list(Conf) -> 530 Dir = ?privdir(Conf), 531 File1 = filename:join(Dir, "a.LOG"), 532 File2 = filename:join(Dir, "b.LOG"), 533 File3 = filename:join(Dir, "c.LOG"), 534 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8191,3}}, 535 {format,internal}, 536 {file, File1}]), 537 {ok, b} = disk_log:open([{name,b}, {type,wrap}, {size,{8192,3}}, 538 {format,internal}, 539 {file, File2}]), 540 {ok, c} = disk_log:open([{name,c}, {type,wrap}, {size,{8193,3}}, 541 {format,internal}, 542 {file, File3}]), 543 T1 = mk_bytes(8191-16), % 16 is size of header + magics for 1 item 544 T2 = mk_bytes(8192-16), 545 T3 = mk_bytes(8193-16), 546 ok = disk_log:log(a, T1), 547 ok = disk_log:log(b, T2), 548 ok = disk_log:log(c, T3), 549 case get_all_terms(a) of 550 [T1] -> 551 ok; 552 E1 -> 553 test_server_fail({bad_terms, E1, [T1]}) 554 end, 555 case get_all_terms(b) of 556 [T2] -> 557 ok; 558 E2 -> 559 test_server_fail({bad_terms, E2, [T2]}) 560 end, 561 case get_all_terms(c) of 562 [T3] -> 563 ok; 564 E3 -> 565 test_server_fail({bad_terms, E3, [T3]}) 566 end, 567 ok = disk_log:close(a), 568 ok = disk_log:close(b), 569 ok = disk_log:close(c), 570 del(File1, 3), 571 del(File2, 3), 572 del(File3, 3). 573 574%% Test disk log, force a change to next file. 575inc_wrap_file(Conf) when is_list(Conf) -> 576 Dir = ?privdir(Conf), 577 File1 = filename:join(Dir, "a.LOG"), 578 File2 = filename:join(Dir, "b.LOG"), 579 File3 = filename:join(Dir, "c.LOG"), 580 581 %% Test that halt logs gets an error message 582 {ok, a} = disk_log:open([{name, a}, {type, halt}, 583 {format, internal}, 584 {file, File1}]), 585 ok = disk_log:log(a, "message one"), 586 {error, {halt_log, a}} = disk_log:inc_wrap_file(a), 587 588 %% test an internally formatted wrap log file 589 {ok, b} = disk_log:open([{name, b}, {type, wrap}, {size, {100,3}}, 590 {format, internal}, {head, 'thisisahead'}, 591 {file, File2}]), 592 ok = disk_log:log(b, "message one"), 593 ok = disk_log:inc_wrap_file(b), 594 ok = disk_log:log(b, "message two"), 595 ok = disk_log:inc_wrap_file(b), 596 ok = disk_log:log(b, "message three"), 597 ok = disk_log:inc_wrap_file(b), 598 ok = disk_log:log(b, "message four"), 599 T1 = get_all_terms(b), 600 ['thisisahead', "message two", 601 'thisisahead', "message three", 602 'thisisahead', "message four"] = T1, 603 604 %% test an externally formatted wrap log file 605 {ok, c} = disk_log:open([{name, c}, {type, wrap}, {size, {100,3}}, 606 {format,external}, {head,"this is a head "}, 607 {file, File3}]), 608 ok = disk_log:blog(c, "message one"), 609 ok = disk_log:inc_wrap_file(c), 610 ok = disk_log:blog(c, "message two"), 611 ok = disk_log:inc_wrap_file(c), 612 ok = disk_log:blog(c, "message three"), 613 ok = disk_log:inc_wrap_file(c), 614 ok = disk_log:blog(c, "message four"), 615 ok = disk_log:sync(c), 616 {ok, Fd31} = file:open(File3 ++ ".1", [read]), 617 {ok,"this is a head message four"} = file:read(Fd31, 200), 618 {ok, Fd32} = file:open(File3 ++ ".2", [read]), 619 {ok,"this is a head message two"} = file:read(Fd32, 200), 620 {ok, Fd33} = file:open(File3 ++ ".3", [read]), 621 {ok,"this is a head message three"} = file:read(Fd33, 200), 622 ok = file:close(Fd31), 623 ok = file:close(Fd32), 624 ok = file:close(Fd33), 625 626 ok = disk_log:close(a), 627 ok = disk_log:close(b), 628 ok = disk_log:close(c), 629 ok = file:delete(File1), 630 del(File2, 3), 631 del(File3, 3). 632 633 634 635 636%% Test halt disk log, external, infinity. 637halt_ext_inf(Conf) when is_list(Conf) -> 638 Dir = ?privdir(Conf), 639 File = filename:join(Dir, "a.LOG"), 640 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 641 {format,external}, 642 {file, File}]), 643 xsimple_log(File, a), 644 ok = disk_log:close(a), 645 ok = file:delete(File). 646 647 648%% Test halt disk log, external, size defined. 649halt_ext_sz_1(Conf) when is_list(Conf) -> 650 Dir = ?privdir(Conf), 651 File = filename:join(Dir, "a.LOG"), 652 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,18000}, 653 {format,external}, 654 {file, File}]), 655 xsimple_log(File, a), 656 ok = disk_log:truncate(a), 657 [] = get_list(File, a), 658 {B1, T1} = x_mk_bytes(10000), 659 {B2, T2} = x_mk_bytes(5000), 660 {B3, T3} = x_mk_bytes(1000), 661 ok = disk_log:blog(a, B1), 662 case get_list(File, a) of 663 T1 -> 664 ok; 665 E1 -> 666 test_server_fail({bad_terms, E1, T1}) 667 end, 668 ok = disk_log:blog(a, B2), 669 {error, {full, a}} = disk_log:blog_terms(a, [B3,B3,B1]), 670 ok = disk_log:balog(a, B1), 671 Tmp = T1 ++ T2 ++ T3 ++ T3, 672 case get_list(File, a) of 673 Tmp -> 674 ok; 675 E2 -> 676 test_server_fail({bad_terms, E2, Tmp}) 677 end, 678 ok = disk_log:close(a), 679 ok = file:delete(File). 680 681%% Test halt disk log, external, size defined. 682halt_ext_sz_2(Conf) when is_list(Conf) -> 683 Dir = ?privdir(Conf), 684 File1 = filename:join(Dir, "a.LOG"), 685 File2 = filename:join(Dir, "b.LOG"), 686 File3 = filename:join(Dir, "c.LOG"), 687 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,8191}, 688 {format,external}, 689 {file, File1}]), 690 {ok, b} = disk_log:open([{name,b}, {type,halt}, {size,8192}, 691 {format,external}, 692 {file, File2}]), 693 {ok, c} = disk_log:open([{name,c}, {type,halt}, {size,8193}, 694 {format,external}, 695 {file, File3}]), 696 {B1, T1} = x_mk_bytes(8191), 697 {B2, T2} = x_mk_bytes(8192), 698 {B3, T3} = x_mk_bytes(8193), 699 ok = disk_log:blog(a, B1), 700 ok = disk_log:blog(b, B2), 701 ok = disk_log:blog(c, B3), 702 case get_list(File1, a) of 703 T1 -> 704 ok; 705 E1 -> 706 test_server_fail({bad_terms, E1, T1}) 707 end, 708 case get_list(File2, b) of 709 T2 -> 710 ok; 711 E2 -> 712 test_server_fail({bad_terms, E2, T2}) 713 end, 714 case get_list(File3, c) of 715 T3 -> 716 ok; 717 E3 -> 718 test_server_fail({bad_terms, E3, T3}) 719 end, 720 ok = disk_log:truncate(a), 721 ok = disk_log:truncate(b), 722 {error, {full, a}} = disk_log:blog(a, B2), 723 Error1 = {error, {full, b}} = disk_log:blog(b, B3), 724 "The halt log" ++ _ = format_error(Error1), 725 true = info(b, full, false), 726 [] = get_list(File1, a), 727 [] = get_list(File2, b), 728 ok = disk_log:close(a), 729 ok = disk_log:close(b), 730 ok = disk_log:close(c), 731 ok = file:delete(File1), 732 ok = file:delete(File2), 733 ok = file:delete(File3), 734 ok. 735 736 737%% Test wrap disk log, external, size defined. 738wrap_ext_1(Conf) when is_list(Conf) -> 739 Dir = ?privdir(Conf), 740 File = filename:join(Dir, "a.LOG"), 741 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 742 {format,external}, 743 {file, File}]), 744 x2simple_log(File ++ ".1", a), 745 ok = disk_log:close(a), 746 %% del(File, 4), 747 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8000, 4}}, 748 {format,external}, 749 {file, File}]), 750 {B1, _T1} = x_mk_bytes(10000), % file 2 751 {B2, T2} = x_mk_bytes(5000), % file 3 752 {B3, T3} = x_mk_bytes(4000), % file 4 753 {B4, T4} = x_mk_bytes(2000), % file 4 754 {B5, T5} = x_mk_bytes(5000), % file 1 755 {B6, T6} = x_mk_bytes(5000), % file 2 756 ok = disk_log:blog(a, B1), 757 ok = disk_log:blog(a, B2), 758 ok = disk_log:blog(a, B3), 759 ok = disk_log:blog_terms(a, [B4, B5, B6]), 760 case get_list(File ++ ".3", a) of 761 T2 -> 762 ok; 763 E2 -> 764 test_server_fail({bad_terms, E2, T2}) 765 end, 766 T34 = T3 ++ T4, 767 case get_list(File ++ ".4", a) of 768 T34 -> 769 ok; 770 E34 -> 771 test_server_fail({bad_terms, E34, T34}) 772 end, 773 case get_list(File ++ ".1", a) of 774 T5 -> 775 ok; 776 E5 -> 777 test_server_fail({bad_terms, E5, T5}) 778 end, 779 case get_list(File ++ ".2", a) of 780 T6 -> 781 ok; 782 E6 -> 783 test_server_fail({bad_terms, E6, T6}) 784 end, 785 ok = disk_log:close(a), 786 del(File, 4). 787 788%% Test wrap disk log, external, size defined. 789wrap_ext_2(Conf) when is_list(Conf) -> 790 Dir = ?privdir(Conf), 791 File1 = filename:join(Dir, "a.LOG"), 792 File2 = filename:join(Dir, "b.LOG"), 793 File3 = filename:join(Dir, "c.LOG"), 794 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{8191,3}}, 795 {format,external}, 796 {file, File1}]), 797 {ok, b} = disk_log:open([{name,b}, {type,wrap}, {size,{8192,3}}, 798 {format,external}, 799 {file, File2}]), 800 {ok, c} = disk_log:open([{name,c}, {type,wrap}, {size,{8193,3}}, 801 {format,external}, 802 {file, File3}]), 803 {B1, T1} = x_mk_bytes(8191), 804 {B2, T2} = x_mk_bytes(8192), 805 {B3, T3} = x_mk_bytes(8193), 806 ok = disk_log:blog(a, B1), 807 ok = disk_log:blog(b, B2), 808 ok = disk_log:blog(c, B3), 809 case get_list(File1 ++ ".1", a) of 810 T1 -> 811 ok; 812 E1 -> 813 test_server_fail({bad_terms, E1, T1}) 814 end, 815 case get_list(File2 ++ ".1", b) of 816 T2 -> 817 ok; 818 E2 -> 819 test_server_fail({bad_terms, E2, T2}) 820 end, 821 case get_list(File3 ++ ".1", c) of 822 T3 -> 823 ok; 824 E3 -> 825 test_server_fail({bad_terms, E3, T3}) 826 end, 827 ok = disk_log:close(a), 828 ok = disk_log:close(b), 829 ok = disk_log:close(c), 830 del(File1, 3), 831 del(File2, 3), 832 del(File3, 3), 833 ok. 834 835simple_log(Log) -> 836 T1 = "hej", 837 T2 = hopp, 838 T3 = {tjena, 12}, 839 T4 = mk_bytes(10000), 840 ok = disk_log:log(Log, T1), 841 ok = disk_log:log_terms(Log, [T2, T3]), 842 case get_all_terms(Log) of 843 [T1, T2, T3] -> 844 ok; 845 E1 -> 846 test_server_fail({bad_terms, E1, [T1, T2, T3]}) 847 end, 848 ok = disk_log:log(a, T4), 849 case get_all_terms(Log) of 850 [T1, T2, T3, T4] -> 851 ok; 852 E2 -> 853 test_server_fail({bad_terms, E2, [T1, T2, T3, T4]}) 854 end. 855 856xsimple_log(File, Log) -> 857 T1 = "hej", 858 T2 = list_to_binary("hopp"), 859 T3 = list_to_binary(["sena", list_to_binary("sejer")]), 860 T4 = list_to_binary(By = mk_bytes(10000)), 861 ok = disk_log:blog(Log, T1), 862 ok = disk_log:blog_terms(Log, [T2, T3]), 863 X = "hejhoppsenasejer", 864 X2 = get_list(File, Log), 865 case X2 of 866 X -> ok; 867 Z1 -> test_server_fail({bad_terms, Z1, X2}) 868 end, 869 ok = disk_log:blog(Log, T4), 870 Tmp = get_list(File, Log), 871 case X ++ By of 872 Tmp -> ok; 873 Z2 -> test_server_fail({bad_terms, Z2, X ++ By}) 874 end. 875 876x2simple_log(File, Log) -> 877 T1 = "hej", 878 T2 = list_to_binary("hopp"), 879 T3 = list_to_binary(["sena", list_to_binary("sejer")]), 880 T4 = list_to_binary(By = mk_bytes(1000)), 881 ok = disk_log:blog(Log, T1), 882 ok = disk_log:blog_terms(Log, [T2, T3]), 883 X = "hejhoppsenasejer", 884 X2 = get_list(File, Log), 885 case X2 of 886 X -> ok; 887 Z1 -> test_server_fail({bad_terms, Z1, X2}) 888 end, 889 ok = disk_log:blog(Log, T4), 890 Tmp = get_list(File, Log), 891 case X ++ By of 892 Tmp -> ok; 893 Z2 -> test_server_fail({bad_terms, Z2, X ++ By}) 894 end. 895 896x_mk_bytes(N) -> 897 X = lists:duplicate(N, $a), 898 {list_to_binary(X), X}. 899 900mk_bytes(N) when N > 4 -> 901 X = lists:duplicate(N-4, $a), 902 case byte_size(term_to_binary(X)) of 903 N -> X; 904 Z -> test_server_fail({bad_terms, Z, N}) 905 end. 906 907get_list(File, Log) -> 908 ct:pal(?HI_VERBOSITY, "File ~p~n", [File]), 909 ok = disk_log:sync(Log), 910 {ok, B} = file:read_file(File), 911 binary_to_list(B). 912 913 914get_all_terms(Log, File, Type) -> 915 {ok, _Log} = disk_log:open([{name,Log}, {type,Type}, {size,infinity}, 916 {format,internal}, {file, File}, 917 {mode, read_only}]), 918 Ts = get_all_terms(Log), 919 ok = disk_log:close(Log), 920 Ts. 921 922get_all_terms(Log) -> 923 get_all_terms1(Log, start, []). 924 925get_all_terms1(Log, Cont, Res) -> 926 case disk_log:chunk(Log, Cont) of 927 {error, _R} -> 928 test_server_fail({bad_chunk, Log, Cont}); 929 {Cont2, Terms} -> 930 get_all_terms1(Log, Cont2, Res ++ Terms); 931 eof -> 932 Res 933 end. 934 935get_all_terms_and_bad(Log, File, Type) -> 936 {ok, _Log} = disk_log:open([{name,Log}, {type,Type}, {size,infinity}, 937 {format,internal}, {file, File}, 938 {mode, read_only}]), 939 Ts = get_all_terms_and_bad(Log), 940 ok = disk_log:close(Log), 941 Ts. 942 943get_all_terms_and_bad(Log) -> 944 read_only = info(Log, mode, foo), 945 get_all_terms_and_bad1(Log, start, [], 0). 946 947%% 948get_all_terms_and_bad1(Log, Cont, Res, Bad0) -> 949 case disk_log:chunk(Log, Cont) of 950 {Cont2, Terms} -> 951 get_all_terms_and_bad1(Log, Cont2, Res ++ Terms, Bad0); 952 {Cont2, Terms, Bad} -> 953 get_all_terms_and_bad1(Log, Cont2, Res ++ Terms, Bad0+Bad); 954 eof -> 955 {Res, Bad0} 956 end. 957 958get_all_binary_terms_and_bad(Log, File, Type) -> 959 {ok, _Log} = disk_log:open([{name,Log}, {type,Type}, {size,infinity}, 960 {format,internal}, {file, File}, 961 {mode, read_only}]), 962 Ts = get_all_binary_terms_and_bad(Log), 963 ok = disk_log:close(Log), 964 Ts. 965 966get_all_binary_terms_and_bad(Log) -> 967 read_only = info(Log, mode, foo), 968 get_all_binary_terms_and_bad1(Log, start, [], 0). 969 970%% 971get_all_binary_terms_and_bad1(Log, Cont, Res, Bad0) -> 972 case disk_log:bchunk(Log, Cont) of 973 {Cont2, BinTerms} -> 974 get_all_binary_terms_and_bad1(Log, Cont2, Res ++ BinTerms, Bad0); 975 {Cont2, BinTerms, Bad} -> 976 get_all_binary_terms_and_bad1(Log, Cont2, Res ++ BinTerms, 977 Bad0+Bad); 978 eof -> 979 {Res, Bad0} 980 end. 981 982del(File, 0) -> 983 file:delete(File ++ ".siz"), 984 file:delete(File ++ ".idx"); 985del(File, N) -> 986 file:delete(File ++ "." ++ integer_to_list(N)), 987 del(File, N-1). 988 989test_server_fail(R) -> 990 exit({?MODULE, get(line), R}). 991 992xx() -> 993 File = "a.LOG", 994 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 995 {format,internal}, {file, File}]), 996 W = xwr(a, 400), 997 disk_log:close(a), 998 %% file:delete(File), 999 W. 1000 1001%% old: 6150 1002%% new: 5910 1003xwr(Log, BytesItem) -> 1004 NoW = 1000, 1005 Item1 = mk_bytes(BytesItem), 1006 Item2 = mk_bytes(BytesItem), 1007 Item3 = mk_bytes(BytesItem), 1008 Item4 = mk_bytes(BytesItem), 1009 Item5 = mk_bytes(BytesItem), 1010 Item6 = mk_bytes(BytesItem), 1011 Item7 = mk_bytes(BytesItem), 1012 Item8 = mk_bytes(BytesItem), 1013 Item9 = mk_bytes(BytesItem), 1014 Item0 = mk_bytes(BytesItem), 1015 Term = [Item1,Item2,Item3,Item4,Item5,Item6,Item7,Item8,Item9,Item0], 1016 {W, _} = timer:tc(?MODULE, wr, [Log, Term, NoW]), 1017 W/NoW. 1018 1019measure() -> 1020 proc_lib:start_link(?MODULE, init_m, [self()]). 1021 1022init_m(Par) -> 1023 process_flag(trap_exit, true), 1024 Res = m(), 1025 proc_lib:init_ack(Par, Res). 1026 1027m() -> 1028 {W10, R10, Rep10, C10} = m_halt_int(10), 1029 {W11, R11, Rep11, C11} = m_halt_int(100), 1030 {W12, R12, Rep12, C12} = m_halt_int(400), 1031 {W13, R13, Rep13, C13} = m_halt_int(1000), 1032 {W14, R14, Rep14, C14} = m_halt_int(10000), 1033 {W2, R2, Rep2, C2} = m_wrap_int(400), 1034 {W3, R3, Rep3, C3} = m_many_halt_int(10, 400), 1035 {W4, R4, Rep4, C4} = m_many_halt_int(20, 400), 1036 {W5, R5, Rep5, C5} = m_many_halt_int(10, 1000), 1037 {W6, R6, Rep6, C6} = m_many_halt_int(10, 10), 1038 {W7, R7, Rep7, C7} = m_many_halt_int(20, 10), 1039 1040 io:format("Type of log mysec/write mysec/read" 1041 " mysec/repair byte cpu/write\n"), 1042 io:format("=========== =========== ==========" 1043 " ================= =========\n"), 1044 one_line("halt,int.inf. (10)", W10, R10, Rep10, C10), 1045 one_line("halt,int.inf. (100)", W11, R11, Rep11, C11), 1046 one_line("halt,int.inf. (400)", W12, R12, Rep12, C12), 1047 one_line("halt,int.inf. (1000)", W13, R13, Rep13, C13), 1048 one_line("halt,int.inf. (10000)", W14, R14, Rep14, C14), 1049 one_line("wrap,int. 4. (400)", W2, R2, Rep2, C2), 1050 one_line("halt,int.inf. (10,10)", W6, R6, Rep6, C6), 1051 one_line("halt,int.inf. (20,10)", W7, R7, Rep7, C7), 1052 one_line("halt,int.inf. (10,400)", W3, R3, Rep3, C3), 1053 one_line("halt,int.inf. (20,400)", W4, R4, Rep4, C4), 1054 one_line("halt,int.inf. (10,1000)", W5, R5, Rep5, C5), 1055 io:format("\n"), 1056 io:format("\tWrap log time depends on how often the log wraps, as this\n"), 1057 io:format("\tinvolves opening of new files, which costs alot."), 1058 io:format("\n"). 1059 1060one_line(Txt, W, R, Rep, C) -> 1061 io:format("~.22s ~.10w ~.10w ~.17w ~.9w\n", [Txt, W, R, Rep, C]). 1062 1063m_halt_int(BytesItem) -> 1064 File = "a.LOG", 1065 {ok, a} = disk_log:open([{name,a}, {type,halt}, {size,infinity}, 1066 {format,internal}, {file, File}]), 1067 {T,W} = wr(a, BytesItem), 1068 R = r(a), 1069 [{_,P}] = ets:lookup(?DISK_LOG_NAME_TABLE, a), 1070 exit(P, kill), 1071 receive after 100 -> ok end, 1072 crash(File, 10), 1073 Sz = file_size(File), 1074 Start = start_times(), 1075 {repaired, a, {recovered, Rec}, {badbytes, Bad}} = 1076 disk_log:open([{name,a}, {type,halt}, {size,infinity}, 1077 {format,internal}, {file, File}]), 1078 {_,Rep} = end_times(Start), 1079 io:format("m_halt_int: Rep = ~p, Rec = ~p, Bad = ~p~n", [Rep, Rec, Bad]), 1080 disk_log:close(a), 1081 file:delete(File), 1082 {W,R,1000*Rep/Sz,T}. 1083 1084m_wrap_int(BytesItem) -> 1085 File = "a.LOG", 1086 {ok, a} = disk_log:open([{name,a}, {type,wrap}, {size,{405*1000, 4}}, 1087 {format,internal}, {file, File}]), 1088 {T,W} = wr(a, BytesItem), 1089 R = r(a), 1090 [{_,P}] = ets:lookup(?DISK_LOG_NAME_TABLE, a), 1091 exit(P, kill), 1092 receive after 100 -> ok end, 1093 del(File, 4), 1094 {W,R,'n/a',T}. 1095 1096m_many_halt_int(NoClients, BytesItem) -> 1097 Name = 'log.LOG', 1098 File = "log.LOG", 1099 {ok, _} = disk_log:open([{name,Name}, {type,halt}, 1100 {size,infinity}, 1101 {format,internal}, {file,File}]), 1102 NoW = round(lists:max([lists:min([5000000/BytesItem/NoClients, 1103 50000/NoClients]), 1104 1000])), 1105 {T,W} = many_wr(NoClients, Name, NoW, BytesItem), 1106 ok = disk_log:close(Name), 1107 file:delete(File), 1108 {1000*W/NoW/NoClients,'n/a','n/a',1000*T/NoW/NoClients}. 1109 1110many_wr(NoClients, Log, NoW, BytesItem) -> 1111 Item = mk_bytes(BytesItem), 1112 Fun = fun(Name, _Pid, _I) -> disk_log:log(Name, Item) end, 1113 Start = start_times(), 1114 Pids = spawn_clients(NoClients, client, [self(), Log, NoW, Fun]), 1115 check_clients(Pids), 1116 end_times(Start). 1117 1118wr(Log, BytesItem) -> 1119 NoW = round(lists:max([lists:min([5000000/BytesItem,50000]),1000])), 1120 Item = mk_bytes(BytesItem), 1121 Start = start_times(), 1122 wr(Log, Item, NoW), 1123 {T,W} = end_times(Start), 1124 {1000*T/NoW, 1000*W/NoW}. 1125 1126wr(Log, _Item, 0) -> 1127 disk_log:sync(Log), 1128 ok; 1129wr(Log, Item, N) -> 1130 ok = disk_log:log(Log, Item), 1131 wr(Log, Item, N-1). 1132 1133r(_) -> 1134 nyi. 1135 1136start_times() -> 1137 {T1, _} = statistics(runtime), 1138 {W1, _} = statistics(wall_clock), 1139 {T1, W1}. 1140 1141end_times({T1,W1}) -> 1142 {T2, _} = statistics(runtime), 1143 {W2, _} = statistics(wall_clock), 1144 {T2-T1, W2-W1}. 1145 1146 1147%% Test head parameter. 1148head_func(Conf) when is_list(Conf) -> 1149 Dir = ?privdir(Conf), 1150 File = filename:join(Dir, "a.LOG"), 1151 ets:new(xxx, [named_table, set, public]), 1152 ets:insert(xxx, {wrapc, 0}), 1153 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 1154 {size, {100,4}}, 1155 {head_func, {?MODULE, hf, []}}]), 1156 B = mk_bytes(60), 1157 disk_log:log(a, B), 1158 disk_log:alog(a, B), 1159 disk_log:alog(a, B), 1160 disk_log:log(a, B), 1161 H = [1,2,3], 1162 [{wrapc, 4}] = ets:lookup(xxx, wrapc), 1163 ets:delete(xxx), 1164 case get_all_terms(a) of 1165 [H,B,H,B,H,B,H,B] -> 1166 ok; 1167 E1 -> 1168 test_server_fail({bad_terms, E1, 1169 [H,B,H,B,H,B,H,B]}) 1170 end, 1171 8 = no_written_items(a), 1172 disk_log:close(a), 1173 del(File, 4), 1174 1175 %% invalid header function 1176 {error, {invalid_header, {_, {term}}}} = 1177 disk_log:open([{name, n}, {file, File}, {type, halt}, 1178 {format, external}, 1179 {head_func, {?MODULE, head_fun, [{term}]}}]), 1180 file:delete(File), 1181 1182 {error, {invalid_header, _}} = 1183 disk_log:open([{name, n}, {file, File}, {type, halt}, 1184 {format, external}, 1185 {head_func, {?MODULE, head_fun, [{ok,{term}}]}}]), 1186 file:delete(File), 1187 1188 {ok,n} = 1189 disk_log:open([{name, n}, {file, File}, {type, halt}, 1190 {format, external}, 1191 {head_func, {?MODULE, head_fun, [{ok,<<"head">>}]}}]), 1192 ok = disk_log:close(n), 1193 {ok,<<"head">>} = file:read_file(File), 1194 file:delete(File), 1195 1196 {ok,n} = 1197 disk_log:open([{name, n}, {file, File}, {type, halt}, 1198 {format, external}, 1199 {head_func, {?MODULE, head_fun, [{ok,"head"}]}}]), 1200 ok = disk_log:close(n), 1201 {ok,<<"head">>} = file:read_file(File), 1202 file:delete(File), 1203 1204 Error1 = {error, {badarg, _}} = 1205 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1206 {head_func, {tjo,hej,san}},{size, {100, 4}}]), 1207 "The argument " ++ _ = format_error(Error1), 1208 1209 Error2 = {error, {invalid_header, _}} = 1210 disk_log:open([{name, n}, {file, File}, {type, halt}, 1211 {head_func, {tjo,hej,[san]}}]), 1212 "The disk log header" ++ _ = format_error(Error2), 1213 file:delete(File). 1214 1215 1216head_fun(H) -> 1217 H. 1218 1219hf() -> 1220 ets:update_counter(xxx, wrapc, 1), 1221 {ok, [1,2,3]}. 1222 1223%% Test head parameter. 1224plain_head(Conf) when is_list(Conf) -> 1225 Dir = ?privdir(Conf), 1226 File = filename:join(Dir, "a.LOG"), 1227 H = [1,2,3], 1228 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 1229 {size, {100,4}}, {head, H}]), 1230 %% This one is not "counted". 1231 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 1232 {size, {100,4}}, {head, H}]), 1233 B = mk_bytes(60), 1234 disk_log:log(a, B), 1235 disk_log:alog(a, B), 1236 disk_log:alog(a, B), 1237 disk_log:log(a, B), 1238 case get_all_terms(a) of 1239 [H,B,H,B,H,B,H,B] -> 1240 ok; 1241 E1 -> 1242 test_server_fail({bad_terms, E1, 1243 [H,B,H,B,H,B,H,B]}) 1244 end, 1245 8 = no_written_items(a), 1246 ok = disk_log:close(a), 1247 {error, no_such_log} = disk_log:close(a), 1248 del(File, 4). 1249 1250 1251 1252%% Test that a header is just printed once in a log file. 1253one_header(Conf) when is_list(Conf) -> 1254 Dir = ?privdir(Conf), 1255 File = filename:join(Dir, "a.LOG"), 1256 H = [1,2,3], 1257 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 1258 {size, {100,4}}, {head, H}]), 1259 B = mk_bytes(60), 1260 ok = disk_log:log(a, B), 1261 ok = disk_log:alog(a, B), 1262 ok = disk_log:alog(a, B), 1263 ok = disk_log:log(a, B), 1264 case get_all_terms(a) of 1265 [H,B,H,B,H,B,H,B] -> 1266 ok; 1267 E1 -> 1268 test_server_fail({bad_terms, E1, 1269 [H,B,H,B,H,B,H,B]}) 1270 end, 1271 8 = no_written_items(a), 1272 ok = disk_log:close(a), 1273 del(File, 4), 1274 1275 Fileb = filename:join(Dir, "b.LOG"), 1276 {ok, b} = disk_log:open([{name,b}, {file, Fileb}, {head, H}]), 1277 ok = disk_log:close(b), 1278 {ok, b} = disk_log:open([{name,b}, {file, Fileb}, {head, H}]), 1279 ok = disk_log:log(b, "first log"), 1280 ok = disk_log:alog(b, "second log"), 1281 ok = disk_log:close(b), 1282 {ok, b} = disk_log:open([{name,b}, {file, Fileb}, {head, H}]), 1283 ok = disk_log:alog(b, "3rd log"), 1284 ok = disk_log:log(b, "4th log"), 1285 case get_all_terms(b) of 1286 [H, "first log", "second log", "3rd log", "4th log"] -> 1287 ok; 1288 E2 -> 1289 test_server_fail({bad_terms, E2, 1290 [H, "first log", "second log", 1291 "3rd log", "4th log"]}) 1292 end, 1293 2 = no_written_items(b), 1294 ok = disk_log:close(b), 1295 ok = file:delete(Fileb), 1296 1297 Filec = filename:join(Dir, "c.LOG"), 1298 H2 = "this is a header ", 1299 {ok, c} = disk_log:open([{name,c}, {format, external}, 1300 {file, Filec}, {head, H2}]), 1301 ok = disk_log:close(c), 1302 {ok, c} = disk_log:open([{name,c}, {format, external}, 1303 {file, Filec}, {head, H2}]), 1304 ok = disk_log:blog(c, "first log"), 1305 ok = disk_log:balog(c, "second log"), 1306 ok = disk_log:close(c), 1307 {ok, c} = disk_log:open([{name,c}, {format, external}, 1308 {file, Filec}, {head, H2}]), 1309 ok = disk_log:balog(c, "3rd log"), 1310 ok = disk_log:blog(c, "4th log"), 1311 ok = disk_log:sync(c), 1312 {ok, Fdc} = file:open(Filec, [read]), 1313 {ok,"this is a header first logsecond log3rd log4th log"} = 1314 file:read(Fdc, 200), 1315 ok = file:close(Fdc), 1316 2 = no_written_items(c), 1317 disk_log:close(c), 1318 ok = file:delete(Filec), 1319 ok. 1320 1321 1322 1323%% Test notify parameter, wrap. 1324wrap_notif(Conf) when is_list(Conf) -> 1325 Dir = ?privdir(Conf), 1326 File = filename:join(Dir, "a.LOG"), 1327 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 1328 {size, {100,4}}, {notify, true}]), 1329 B = mk_bytes(60), 1330 disk_log:log(a, B), 1331 disk_log:alog(a, B), 1332 disk_log:alog(a, B), 1333 disk_log:log(a, B), 1334 disk_log:log(a, B), 1335 rec(3, {disk_log, node(), a, {wrap, 0}}), 1336 rec(1, {disk_log, node(), a, {wrap, 1}}), 1337 disk_log:close(a), 1338 del(File, 4). 1339 1340%% Test notify parameter, wrap, filled file. 1341full_notif(Conf) when is_list(Conf) -> 1342 Dir = ?privdir(Conf), 1343 File = filename:join(Dir, "a.LOG"), 1344 file:delete(File), 1345 1346 {ok, a} = disk_log:open([{name, a}, {file, File}, {type, halt}, 1347 {size, 100}, {notify, true}]), 1348 B = mk_bytes(60), 1349 disk_log:log(a, B), 1350 disk_log:alog(a, B), 1351 rec(1, {disk_log, node(), a, full}), 1352 disk_log:close(a), 1353 file:delete(File). 1354 1355%% Test notify parameter, wrap, truncated file. 1356trunc_notif(Conf) when is_list(Conf) -> 1357 Dir = ?privdir(Conf), 1358 File = filename:join(Dir, "a.LOG"), 1359 File2 = filename:join(Dir, "a.DUMP"), 1360 {ok, a} = disk_log:open([{name, a}, {file, File}, {type, halt}, 1361 {size, 100}, {notify, true}]), 1362 B = mk_bytes(60), 1363 disk_log:log(a, B), 1364 disk_log:truncate(a), 1365 rec(1, {disk_log, node(), a, {truncated, 1}}), 1366 disk_log:log(a, B), 1367 ok = disk_log:reopen(a, File2), 1368 rec(1, {disk_log, node(), a, {truncated, 1}}), 1369 disk_log:close(a), 1370 file:delete(File), 1371 file:delete(File2). 1372 1373%% Test notify parameters 'format_external' and 'blocked_log. 1374blocked_notif(Conf) when is_list(Conf) -> 1375 Dir = ?privdir(Conf), 1376 File = filename:join(Dir, "n.LOG"), 1377 No = 4, 1378 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1379 {size, {100,No}}, {notify, true}, 1380 {format, external}]), 1381 B = mk_bytes(60), 1382 Error1 = {error,{format_external,n}} = disk_log:log(n, B), 1383 "The requested operation" ++ _ = format_error(Error1), 1384 ok = disk_log:blog(n, B), 1385 ok = disk_log:alog(n, B), 1386 rec(1, {disk_log, node(), n, {format_external, [term_to_binary(B)]}}), 1387 ok = disk_log:alog_terms(n, [B,B,B,B]), 1388 rec(1, {disk_log, node(), n, {format_external, 1389 lists:map(fun term_to_binary/1, [B,B,B,B])}}), 1390 ok = disk_log:block(n, false), 1391 ok = disk_log:alog(n, B), 1392 rec(1, {disk_log, node(), n, {blocked_log, [term_to_binary(B)]}}), 1393 ok = disk_log:balog(n, B), 1394 rec(1, {disk_log, node(), n, {blocked_log, [list_to_binary(B)]}}), 1395 ok = disk_log:balog_terms(n, [B,B,B,B]), 1396 disk_log:close(n), 1397 rec(1, {disk_log, node(), n, {blocked_log, 1398 lists:map(fun list_to_binary/1, [B,B,B,B])}}), 1399 del(File, No). 1400 1401 1402%% Test the new version of the .idx file. 1403new_idx_vsn(Conf) when is_list(Conf) -> 1404 DataDir = ?datadir(Conf), 1405 PrivDir = ?privdir(Conf), 1406 File = filename:join(PrivDir, "new_vsn.LOG"), 1407 Kurt = filename:join(PrivDir, "kurt.LOG"), 1408 Kurt2 = filename:join(PrivDir, "kurt2.LOG"), 1409 1410 %% Test that a wrap log file can have more than 255 files 1411 {ok, new_vsn} = disk_log:open([{file, File}, {name, new_vsn}, 1412 {type, wrap}, {size, {40, 270}}]), 1413 ok = log(new_vsn, 280), 1414 {ok, Bin} = file:read_file(add_ext(File, "idx")), 1415 <<0,0:32,2,10:32,1:64,1:64,_/binary>> = Bin, 1416 disk_log:close(new_vsn), 1417 del(File, 270), 1418 1419 %% convert a very old version (0) of wrap log file to the new format (2) 1420 copy_wrap_log("kurt.LOG", 4, DataDir, PrivDir), 1421 1422 {repaired, kurt, {recovered, 1}, {badbytes, 0}} = 1423 disk_log:open([{file, Kurt}, {name, kurt}, 1424 {type, wrap}, {size, {40, 4}}]), 1425 ok = disk_log:log(kurt, "this is a logged message number X"), 1426 ok = disk_log:log(kurt, "this is a logged message number Y"), 1427 {ok, BinK} = file:read_file(add_ext(Kurt, "idx")), 1428 <<0,0:32,2,2:32,1:64,1:64,1:64,1:64>> = BinK, 1429 {{40,4}, 2} = disk_log_1:read_size_file_version(Kurt), 1430 disk_log:close(kurt), 1431 del(Kurt, 4), 1432 1433 %% keep the old format (1) 1434 copy_wrap_log("kurt2.LOG", 4, DataDir, PrivDir), 1435 1436 {repaired, kurt2, {recovered, 1}, {badbytes, 0}} = 1437 disk_log:open([{file, Kurt2}, {name, kurt2}, 1438 {type, wrap}, {size, {40, 4}}]), 1439 ok = disk_log:log(kurt2, "this is a logged message number X"), 1440 ok = disk_log:log(kurt2, "this is a logged message number Y"), 1441 {ok, BinK2} = file:read_file(add_ext(Kurt2, "idx")), 1442 <<0,2:32,1:32,1:32,1:32,1:32>> = BinK2, 1443 {{40,4}, 1} = disk_log_1:read_size_file_version(Kurt2), 1444 disk_log:close(kurt2), 1445 del(Kurt2, 4), 1446 1447 ok. 1448 1449%% Test reopen/1 on halt and wrap logs. 1450reopen(Conf) when is_list(Conf) -> 1451 1452 Dir = ?privdir(Conf), 1453 File = filename:join(Dir, "n.LOG"), 1454 NewFile = filename:join(Dir, "nn.LOG"), 1455 B = mk_bytes(60), 1456 1457 file:delete(File), % cleanup 1458 file:delete(NewFile), % cleanup 1459 Q = qlen(), 1460 1461 %% External halt log. 1462 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 1463 {notify, true}, {head, "header"}, 1464 {size, infinity},{format, external}]), 1465 ok = disk_log:blog(n, B), 1466 ok = disk_log:breopen(n, NewFile, "head"), 1467 rec(1, {disk_log, node(), n, {truncated, 2}}), 1468 ok = disk_log:blog(n, B), 1469 ok = disk_log:blog(n, B), 1470 ok = disk_log:breopen(n, NewFile, "head"), 1471 rec(1, {disk_log, node(), n, {truncated, 3}}), 1472 ok = disk_log:close(n), 1473 {ok,BinaryFile} = file:read_file(File), 1474 "head" = binary_to_list(BinaryFile), 1475 file:delete(File), 1476 file:delete(NewFile), 1477 1478 %% Internal halt log. 1479 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 1480 {notify, true}, {head, header}, 1481 {size, infinity}]), 1482 ok = disk_log:log(n, B), 1483 Error1 = {error, {same_file_name, n}} = disk_log:reopen(n, File), 1484 "Current and new" ++ _ = format_error(Error1), 1485 ok = disk_log:reopen(n, NewFile), 1486 rec(1, {disk_log, node(), n, {truncated, 2}}), 1487 ok = disk_log:log(n, B), 1488 ok = disk_log:log(n, B), 1489 ok = disk_log:reopen(n, NewFile), 1490 rec(1, {disk_log, node(), n, {truncated, 3}}), 1491 ok = disk_log:close(n), 1492 [header, _B, _B] = get_all_terms(nn, NewFile, halt), 1493 file:delete(File), 1494 file:delete(NewFile), 1495 1496 %% Internal wrap log. 1497 No = 4, 1498 del(File, No), % cleanup 1499 del(NewFile, No), % cleanup 1500 1501 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1502 {notify, true}, 1503 {head, header}, {size, {100, No}}]), 1504 ok = disk_log:log(n, B), 1505 ok = disk_log:log_terms(n, [B,B,B]), 1506 %% Used to be one message, but now one per wrapped file. 1507 rec(3, {disk_log, node(), n, {wrap, 0}}), 1508 ok = disk_log:log_terms(n, [B]), 1509 rec(1, {disk_log, node(), n, {wrap, 2}}), 1510 ok = disk_log:log_terms(n, [B]), 1511 rec(1, {disk_log, node(), n, {wrap, 2}}), 1512 ok = disk_log:reopen(n, NewFile, new_header), 1513 rec(1, {disk_log, node(), n, {truncated, 8}}), 1514 ok = disk_log:log_terms(n, [B,B]), 1515 rec(1, {disk_log, node(), n, {wrap, 0}}), 1516 ok = disk_log:log_terms(n, [B]), 1517 rec(1, {disk_log, node(), n, {wrap, 0}}), 1518 ok = disk_log:close(n), 1519 [header, _, header, _, header, _, header, _] = 1520 get_all_terms(nn, NewFile, wrap), 1521 [new_header, _, header, _, header, _] = get_all_terms(n, File, wrap), 1522 1523 del(NewFile, No), 1524 file:delete(File ++ ".2"), 1525 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1526 {notify, true}, 1527 {head, header}, {size, {100, No}}]), 1528 %% One file is missing... 1529 ok = disk_log:reopen(n, NewFile), 1530 rec(1, {disk_log, node(), n, {truncated, 6}}), 1531 ok = disk_log:close(n), 1532 1533 del(File, No), 1534 del(NewFile, No), 1535 Q = qlen(), 1536 ok. 1537 1538 1539%% Test block/1 on external and internal logs. 1540block_blocked(Conf) when is_list(Conf) -> 1541 1542 Dir = ?privdir(Conf), 1543 B = mk_bytes(60), 1544 Halt = join(Dir, "halt.LOG"), 1545 1546 %% External logs. 1547 file:delete(Halt), % cleanup 1548 {ok, halt} = disk_log:open([{name, halt}, {type, halt}, 1549 {format, external}, {file, Halt}]), 1550 ok = disk_log:sync(halt), 1551 ok = disk_log:block(halt, false), 1552 Error1 = {error, {blocked_log, halt}} = disk_log:block(halt), 1553 "The blocked disk" ++ _ = format_error(Error1), 1554 {error, {blocked_log, halt}} = disk_log:sync(halt), 1555 {error, {blocked_log, halt}} = disk_log:truncate(halt), 1556 {error, {blocked_log, halt}} = disk_log:change_size(halt, infinity), 1557 {error, {blocked_log, halt}} = 1558 disk_log:change_notify(halt, self(), false), 1559 {error, {blocked_log, halt}} = 1560 disk_log:change_header(halt, {head, header}), 1561 {error, {blocked_log, halt}} = disk_log:reopen(halt, "foo"), 1562 ok = disk_log:close(halt), 1563 1564 {ok, halt} = disk_log:open([{name, halt}, {type, halt}, 1565 {format, external}]), 1566 ok = disk_log:sync(halt), 1567 ok = disk_log:block(halt, true), 1568 {error, {blocked_log, halt}} = disk_log:blog(halt, B), 1569 {error, {blocked_log, halt}} = disk_log:blog(halt, B), 1570 {error, {blocked_log, halt}} = disk_log:block(halt), 1571 {error, {blocked_log, halt}} = disk_log:sync(halt), 1572 {error, {blocked_log, halt}} = disk_log:truncate(halt), 1573 {error, {blocked_log, halt}} = disk_log:change_size(halt, infinity), 1574 {error, {blocked_log, halt}} = 1575 disk_log:change_notify(halt, self(), false), 1576 {error, {blocked_log, halt}} = 1577 disk_log:change_header(halt, {head, header}), 1578 {error, {blocked_log, halt}} = disk_log:reopen(halt, "foo"), 1579 1580 ok = disk_log:unblock(halt), 1581 ok = disk_log:close(halt), 1582 file:delete(Halt), 1583 1584 %% Internal logs. 1585 File = filename:join(Dir, "n.LOG"), 1586 No = 4, 1587 del(File, No), % cleanup 1588 {ok, halt} = disk_log:open([{name, halt}, {file, File}, {type, wrap}, 1589 {size, {100, No}}]), 1590 ok = disk_log:block(halt, true), 1591 eof = disk_log:chunk(halt, start), 1592 Error2 = {error, end_of_log} = disk_log:chunk_step(halt, start, 1), 1593 "An attempt" ++ _ = format_error(Error2), 1594 {error, {blocked_log, halt}} = disk_log:log(halt, B), 1595 {error, {blocked_log, halt}} = disk_log:inc_wrap_file(halt), 1596 ok = disk_log:unblock(halt), 1597 ok = disk_log:block(halt, false), 1598 {error, {blocked_log, halt}} = disk_log:log(halt, B), 1599 {error, {blocked_log, halt}} = disk_log:inc_wrap_file(halt), 1600 Parent = self(), 1601 Pid = 1602 spawn_link(fun() -> 1603 {error, {blocked_log, halt}} = 1604 disk_log:chunk(halt, start), 1605 {error, {blocked_log, halt}} = 1606 disk_log:chunk_step(halt, start, 1), 1607 Parent ! {self(), stopped} 1608 end), 1609 receive {Pid,stopped} -> ok end, 1610 ok = disk_log:close(halt), 1611 del(File, No). 1612 1613%% Run commands from the queue by unblocking. 1614block_queue(Conf) when is_list(Conf) -> 1615 1616 Dir = ?privdir(Conf), 1617 Q = qlen(), 1618 File = filename:join(Dir, "n.LOG"), 1619 No = 4, 1620 del(File, No), % cleanup 1621 B = mk_bytes(60), 1622 1623 Pid = spawn_link(?MODULE, lserv, [n]), 1624 {ok, n} = sync_do(Pid, {open, File}), 1625 1626 ok = disk_log:block(n, true), 1627 async_do(Pid, {blog, B}), 1628 ok = disk_log:unblock(n), 1629 ok = get_reply(), 1630 1 = no_written_items(n), 1631 Error1 = {error,{not_blocked,n}} = disk_log:unblock(n), 1632 "The disk log" ++ _ = format_error(Error1), 1633 1634 ok = disk_log:block(n, true), 1635 async_do(Pid, {balog, "one string"}), 1636 ok = disk_log:unblock(n), 1637 ok = get_reply(), 1638 2 = no_written_items(n), 1639 1640 ok = disk_log:block(n, true), 1641 async_do(Pid, sync), 1642 ok = disk_log:unblock(n), 1643 ok = get_reply(), 1644 1645 ok = disk_log:block(n, true), 1646 async_do(Pid, truncate), 1647 ok = disk_log:unblock(n), 1648 ok = get_reply(), 1649 0 = no_items(n), 1650 1651 ok = disk_log:block(n, true), 1652 async_do(Pid, {block, false}), 1653 ok = disk_log:unblock(n), 1654 ok = get_reply(), 1655 {error, {blocked_log, _}} = disk_log:blog(n, B), 1656 ok = sync_do(Pid, unblock), 1657 1658 ok = disk_log:block(n, true), 1659 async_do(Pid, {change_notify, Pid, true}), 1660 ok = disk_log:unblock(n), 1661 ok = get_reply(), 1662 [{_, true}] = owners(n), 1663 1664 ok = disk_log:block(n, true), 1665 async_do(Pid, {change_notify, Pid, false}), 1666 ok = disk_log:unblock(n), 1667 ok = get_reply(), 1668 [{_, false}] = owners(n), 1669 1670 ok = disk_log:block(n, true), 1671 async_do(Pid, {change_header, {head, header}}), 1672 ok = disk_log:unblock(n), 1673 {error, {badarg, head}} = get_reply(), 1674 1675 ok = disk_log:block(n, true), 1676 async_do(Pid, {change_size, 17}), 1677 ok = disk_log:unblock(n), 1678 {error, {badarg, size}} = get_reply(), 1679 1680 ok = disk_log:block(n, true), 1681 async_do(Pid, inc_wrap_file), 1682 ok = disk_log:unblock(n), 1683 ok = get_reply(), 1684 1685 ok = sync_do(Pid, close), 1686 del(File, No), 1687 1688 _Pid2 = spawn_link(?MODULE, lserv, [n]), 1689 {ok, n} = sync_do(Pid, {int_open, File}), 1690 1691 ok = disk_log:block(n, true), 1692 async_do(Pid, {chunk, start}), 1693 ok = disk_log:unblock(n), 1694 eof = get_reply(), 1695 1696 ok = disk_log:block(n, true), 1697 async_do(Pid, {chunk_step, start, 100}), 1698 ok = disk_log:unblock(n), 1699 {ok, _Cont} = get_reply(), 1700 1701 ok = disk_log:block(n, true), 1702 async_do(Pid, {log,a_term}), 1703 ok = disk_log:unblock(n), 1704 ok = get_reply(), 1705 1 = no_written_items(n), 1706 1707 ok = sync_do(Pid, close), 1708 sync_do(Pid, terminate), 1709 del(File, No), 1710 1711 %% Test of the queue. Three processes involved here. Pid1's block 1712 %% request is queued. Pid2's log requests are put in the queue. 1713 %% When unblock is executed, Pid1's block request is granted. 1714 %% Pid2's log requests are executed when Pid1 unblocks. 1715 %% (This example should show that the pair 'queue' and 'messages' 1716 %% in State does the trick - one does not need a "real" queue.) 1717 P0 = pps(), 1718 Name = n, 1719 Pid1 = spawn_link(?MODULE, lserv, [Name]), 1720 {ok, Name} = sync_do(Pid1, {int_open, File, {1000,2}}), 1721 Pid2 = spawn_link(?MODULE, lserv, [Name]), 1722 {ok, Name} = sync_do(Pid2, {int_open, File, {1000,2}}), 1723 ok = disk_log:block(Name), 1724 async_do(Pid1, {alog,{1,a}}), 1725 ok = get_reply(), 1726 async_do(Pid1, {alog,{2,b}}), 1727 ok = get_reply(), 1728 async_do(Pid1, {alog,{3,c}}), 1729 ok = get_reply(), 1730 async_do(Pid1, {alog,{4,d}}), 1731 ok = get_reply(), 1732 async_do(Pid1, block), 1733 async_do(Pid2, {alog,{5,e}}), 1734 ok = get_reply(), 1735 async_do(Pid2, {alog,{6,f}}), 1736 ok = get_reply(), 1737 ok = disk_log:unblock(Name), 1738 ok = get_reply(), 1739 async_do(Pid2, {alog,{7,g}}), 1740 ok = get_reply(), 1741 async_do(Pid2, {alog,{8,h}}), 1742 ok = get_reply(), 1743 async_do(Pid1, unblock), 1744 ok = get_reply(), 1745 ok = sync_do(Pid1, close), 1746 ok = sync_do(Pid2, close), 1747 sync_do(Pid1, terminate), 1748 sync_do(Pid2, terminate), 1749 Terms = get_all_terms(Name, File, wrap), 1750 true = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g},{8,h}] == Terms, 1751 del(File, 2), 1752 Q = qlen(), 1753 check_pps(P0), 1754 ok. 1755 1756%% OTP-4880. Blocked processes did not get disk_log_stopped message. 1757block_queue2(Conf) when is_list(Conf) -> 1758 Q = qlen(), 1759 P0 = pps(), 1760 Dir = ?privdir(Conf), 1761 File = filename:join(Dir, "n.LOG"), 1762 No = 4, 1763 1764 %% log requests are queued, and processed when the log is closed 1765 Pid = spawn_link(?MODULE, lserv, [n]), 1766 {ok, n} = sync_do(Pid, {open, File}), 1767 ok = sync_do(Pid, block), 1768 %% Asynchronous stuff is ignored. 1769 ok = disk_log:balog_terms(n, [<<"foo">>,<<"bar">>]), 1770 ok = disk_log:balog_terms(n, [<<"more">>,<<"terms">>]), 1771 Parent = self(), 1772 Fun = 1773 fun() -> 1774 {error,no_such_log} = disk_log:sync(n), 1775 receive {disk_log, _, {error, disk_log_stopped}} -> ok end, 1776 Parent ! disk_log_stopped_ok 1777 end, 1778 spawn(Fun), 1779 timer:sleep(500), 1780 ok = sync_do(Pid, close), 1781 receive disk_log_stopped_ok -> ok end, 1782 sync_do(Pid, terminate), 1783 {ok,<<>>} = file:read_file(File ++ ".1"), 1784 del(File, No), 1785 Q = qlen(), 1786 check_pps(P0), 1787 ok. 1788 1789 1790%% Test unblock/1. 1791unblock(Conf) when is_list(Conf) -> 1792 Dir = ?privdir(Conf), 1793 File = filename:join(Dir, "n.LOG"), 1794 No = 1, 1795 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1796 {size, {100,No}}, {notify, true}, 1797 {format, external}]), 1798 ok = disk_log:block(n), 1799 spawn_link(?MODULE, try_unblock, [n]), 1800 timer:sleep(100), 1801 disk_log:close(n), 1802 del(File, No). 1803 1804try_unblock(Log) -> 1805 Error = {error, {not_blocked_by_pid, n}} = disk_log:unblock(Log), 1806 "The disk log" ++ _ = format_error(Error). 1807 1808 1809%% Test open/1 when old files exist. 1810open_overwrite(Conf) when is_list(Conf) -> 1811 1812 Dir = ?privdir(Conf), 1813 File = filename:join(Dir, "n.LOG"), 1814 No = 4, 1815 del(File, No), % cleanup 1816 1817 %% read write 1818 First = "n.LOG.1", 1819 make_file(Dir, First, 8), 1820 1821 Error1 = {error, {not_a_log_file, _}} = 1822 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1823 {format, internal}, {size, {100, No}}]), 1824 "The file" ++ _ = format_error(Error1), 1825 del(File, No), 1826 1827 make_file(Dir, First, 4), 1828 1829 {error, {not_a_log_file, _}} = 1830 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1831 {format, internal}, {size, {100, No}}]), 1832 del(File, No), 1833 1834 make_file(Dir, First, 0), 1835 1836 {error, {not_a_log_file, _}} = 1837 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1838 {format, internal}, {size, {100, No}}]), 1839 %% read only 1840 make_file(Dir, First, 6), 1841 1842 {error, {not_a_log_file, _}} = 1843 disk_log:open([{name, n}, {file, File}, {type, wrap},{mode, read_only}, 1844 {format, internal}, {size, {100, No}}]), 1845 del(File, No), 1846 1847 make_file(Dir, First, 0), 1848 1849 {error, {not_a_log_file, _}} = 1850 disk_log:open([{name, n}, {file, File},{type, wrap}, 1851 {mode, read_only}, {format, internal}, 1852 {size, {100, No}}]), 1853 del(File, No), 1854 1855 {error, _} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1856 {mode, read_only}, 1857 {format, internal},{size, {100, No}}]), 1858 1859 file:delete(File), 1860 {ok,n} = disk_log:open([{name,n},{file,File}, 1861 {mode,read_write},{type,halt}]), 1862 ok = disk_log:close(n), 1863 ok = unwritable(File), 1864 {error, {file_error, File, _}} = 1865 disk_log:open([{name,n},{file,File},{mode,read_write},{type,halt}]), 1866 ok = writable(File), 1867 file:delete(File), 1868 1869 {ok,n} = disk_log:open([{name,n},{file,File},{format,external}, 1870 {mode,read_write},{type,halt}]), 1871 ok = disk_log:close(n), 1872 ok = unwritable(File), 1873 {error, {file_error, File, _}} = 1874 disk_log:open([{name,n},{file,File},{format,external}, 1875 {mode,read_write},{type,halt}]), 1876 ok = writable(File), 1877 file:delete(File), 1878 1879 ok. 1880 1881 1882make_file(Dir, File, N) -> 1883 {ok, F} = file:open(filename:join(Dir, File), 1884 [raw, binary, read, write]), 1885 ok = file:truncate(F), 1886 case N of 1887 0 -> 1888 true; 1889 _Else -> 1890 ok = file:write(F, [lists:seq(1,N)]) 1891 end, 1892 ok = file:close(F). 1893 1894%% Test open/1 option size. 1895open_size(Conf) when is_list(Conf) -> 1896 1897 Dir = ?privdir(Conf), 1898 File = filename:join(Dir, "n.LOG"), 1899 1900 No = 4, 1901 file:delete(File), 1902 del(File, No), % cleanup 1903 1904 %% missing size option 1905 {error, {badarg, size}} = 1906 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1907 {format, internal}]), 1908 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1909 {format, internal},{size, {100, No}}]), 1910 B = mk_bytes(60), 1911 ok = disk_log:log_terms(n, [B, B, B, B]), 1912 ok = disk_log:sync(n), 1913 ok = disk_log:block(n), 1914 1915 %% size option does not match existing size file, read_only 1916 Error1 = {error, {size_mismatch, _, _}} = 1917 disk_log:open([{name, nn}, {file, File}, {type, wrap}, 1918 {mode, read_only}, {format, internal}, 1919 {size, {100, No + 1}}]), 1920 "The given size" ++ _ = format_error(Error1), 1921 {ok, nn} = disk_log:open([{name, nn}, {file, File}, {type, wrap}, 1922 {mode, read_only}, 1923 {format, internal},{size, {100, No}}]), 1924 [_, _, _, _] = get_all_terms1(nn, start, []), 1925 disk_log:close(nn), 1926 1927 ok = disk_log:unblock(n), 1928 ok = disk_log:close(n), 1929 1930 %% size option does not match existing size file, read_write 1931 {error, {size_mismatch, _, _}} = 1932 disk_log:open([{name, nn}, {file, File}, {type, wrap}, 1933 {format, internal}, {size, {100, No + 1}}]), 1934 %% size option does not match existing size file, truncating 1935 {ok, nn} = 1936 disk_log:open([{name, nn}, {file, File}, {type, wrap}, 1937 {repair, truncate}, {format, internal}, 1938 {size, {100, No + 1}}]), 1939 ok = disk_log:close(nn), 1940 1941 del(File, No), 1942 ok. 1943 1944 1945%% Test open/1 with {repair, truncate}. 1946open_truncate(Conf) when is_list(Conf) -> 1947 1948 Dir = ?privdir(Conf), 1949 File = filename:join(Dir, "n.LOG"), 1950 No = 4, 1951 del(File, No), % cleanup 1952 1953 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1954 {format, internal},{size, {100, No}}]), 1955 B = mk_bytes(60), 1956 ok = disk_log:log_terms(n, [B, B, B, B]), 1957 ok = disk_log:close(n), 1958 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1959 {repair,truncate}, 1960 {format, internal},{size, {100, No}}]), 1961 ok = disk_log:close(n), 1962 [] = get_all_terms(n, File, wrap), 1963 del(File, No), 1964 ok. 1965 1966 1967%% Try some invalid open/1 options. 1968open_error(Conf) when is_list(Conf) -> 1969 Dir = ?privdir(Conf), 1970 1971 File = filename:join(Dir, "n.LOG"), 1972 No = 4, 1973 del(File, No), % cleanup 1974 1975 {error, {badarg, name}} = disk_log:open([{file, File}]), 1976 {error, {badarg, file}} = disk_log:open([{name,{foo,bar}}]), 1977 {error, {badarg, [{foo,bar}]}} = disk_log:open([{foo,bar}]), 1978 1979 %% external logs, read_only. 1980 {error, {file_error, _, enoent}} = 1981 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1982 {size, {100,No}}, 1983 {format, external}, {mode, read_only}]), 1984 Error5 = {error, {file_error, _, enoent}} = 1985 disk_log:open([{name, n}, {file, File}, {type, halt}, 1986 {size, 100}, 1987 {format, external}, {mode, read_only}]), 1988 true = lists:prefix("\"" ++ File, format_error(Error5)), 1989 1990 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 1991 {format, external},{size, {100, No}}]), 1992 %% Already owner, ignored. 1993 {ok, n} = 1994 disk_log:open([{name, n}, {file, File}, {type, wrap}, 1995 {format, external}, {size, {100, No}}]), 1996 Error2 = {error, {name_already_open, n}} = 1997 disk_log:open([{name, n}, {file, another_file}, {type, wrap}, 1998 {format, external}, {size, {100, No}}]), 1999 "The disk log" ++ _ = format_error(Error2), 2000 Error1 = {error, {arg_mismatch, notify, false, true}} = 2001 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2002 {format, external}, {size, {100, No}}, {notify, true}]), 2003 "The value" ++ _ = format_error(Error1), 2004 Error3 = {error, {open_read_write, n}} = 2005 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2006 {mode, read_only}, 2007 {format, external}, {size, {100, No}}]), 2008 "The disk log" ++ _ = format_error(Error3), 2009 {error, {badarg, size}} = 2010 disk_log:open([{name, n}, {file, File}, {type, halt}, 2011 {format, external}, {size, {100, No}}]), 2012 {error, {arg_mismatch, type, wrap, halt}} = 2013 disk_log:open([{name, n}, {file, File}, {type, halt}, 2014 {format, external}]), 2015 {error, {arg_mismatch, format, external, internal}} = 2016 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2017 {format, internal}, {size, {100, No}}]), 2018 {error, {arg_mismatch, repair, true, false}} = 2019 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2020 {format, external}, {repair, false}]), 2021 {error, {size_mismatch, {100,4}, {1000,4}}} = 2022 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2023 {format, external}, {size, {1000, No}}]), 2024 {error, {arg_mismatch, head, none, _}} = 2025 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2026 {head, "header"}, 2027 {format, external}, {size, {100, No}}]), 2028 {error, {badarg, size}} = 2029 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2030 {format, external}, {size, 100}]), 2031 2032 ok = disk_log:close(n), 2033 2034 {ok, n} = 2035 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2036 {mode, read_only}, 2037 {format, external}, {size, {100, No}}]), 2038 Error4 = {error, {open_read_only, n}} = 2039 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2040 {mode, read_write}, 2041 {format, external}, {size, {100, No}}]), 2042 "The disk log" ++ _ = format_error(Error4), 2043 ok = disk_log:close(n), 2044 2045 del(File, No). 2046 2047 2048%% Do something quickly after close/1. 2049close_race(Conf) when is_list(Conf) -> 2050 Dir = ?privdir(Conf), 2051 File = filename:join(Dir, "n.LOG"), 2052 No = 1, 2053 del(File, No), % cleanup 2054 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2055 {size, {100,No}}, {notify, true}, 2056 {format, internal}]), 2057 ok = disk_log:close(n), 2058 Error1 = {error, no_such_log} = disk_log:close(n), 2059 "There is no disk" ++ _ = format_error(Error1), 2060 2061 %% Pid1 blocks, Pid2 closes without being suspended. 2062 Pid1 = spawn_link(?MODULE, lserv, [n]), 2063 Pid2 = spawn_link(?MODULE, lserv, [n]), 2064 {ok, n} = sync_do(Pid1, {open, File}), 2065 {ok, n} = sync_do(Pid2, {open, File}), 2066 ok = sync_do(Pid1, block), 2067 [{_, false}, {_, false}] = sync_do(Pid1, owners), 2068 ok = sync_do(Pid2, close), 2069 [{_, false}] = sync_do(Pid1, owners), 2070 ok = sync_do(Pid1, close), 2071 sync_do(Pid1, terminate), 2072 sync_do(Pid2, terminate), 2073 {error, no_such_log} = disk_log:info(n), 2074 2075 %% Pid3 blocks, Pid3 closes. Pid4 should still be ablo to use log. 2076 Pid3 = spawn_link(?MODULE, lserv, [n]), 2077 Pid4 = spawn_link(?MODULE, lserv, [n]), 2078 {ok, n} = sync_do(Pid3, {open, File}), 2079 {ok, n} = sync_do(Pid4, {open, File}), 2080 ok = sync_do(Pid3, block), 2081 ok = sync_do(Pid3, close), 2082 [{_Pid4, false}] = sync_do(Pid4, owners), 2083 sync_do(Pid3, terminate), 2084 sync_do(Pid4, terminate), 2085 {error, no_such_log} = disk_log:info(n), 2086 2087 %% Pid5 blocks, Pid5 terminates. Pid6 should still be ablo to use log. 2088 Pid5 = spawn_link(?MODULE, lserv, [n]), 2089 Pid6 = spawn_link(?MODULE, lserv, [n]), 2090 {ok, n} = sync_do(Pid5, {open, File}), 2091 {ok, n} = sync_do(Pid6, {open, File}), 2092 ok = sync_do(Pid5, block), 2093 sync_do(Pid5, terminate), 2094 [{_Pid6, false}] = sync_do(Pid6, owners), 2095 sync_do(Pid6, terminate), 2096 {error, no_such_log} = disk_log:info(n), 2097 del(File, No), % cleanup 2098 ok. 2099 2100%% Block, unblock, close, terminate. 2101close_block(Conf) when is_list(Conf) -> 2102 2103 Dir = ?privdir(Conf), 2104 File = filename:join(Dir, "n.LOG"), 2105 No = 1, 2106 del(File, No), % cleanup 2107 2108 P0 = pps(), 2109 %% One of two owners terminates. 2110 Pid1 = spawn_link(?MODULE, lserv, [n]), 2111 Pid2 = spawn_link(?MODULE, lserv, [n]), 2112 {ok, n} = sync_do(Pid1, {open, File}), 2113 {ok, n} = sync_do(Pid2, {open, File}), 2114 [_, _] = sync_do(Pid1, owners), 2115 [_, _] = sync_do(Pid2, owners), 2116 0 = sync_do(Pid1, users), 2117 0 = sync_do(Pid2, users), 2118 sync_do(Pid1, terminate), 2119 [_] = sync_do(Pid2, owners), 2120 0 = sync_do(Pid2, users), 2121 sync_do(Pid2, terminate), 2122 {error, no_such_log} = disk_log:info(n), 2123 check_pps(P0), 2124 2125 %% Users terminate (no link...). 2126 Pid3 = spawn_link(?MODULE, lserv, [n]), 2127 Pid4 = spawn_link(?MODULE, lserv, [n]), 2128 {ok, n} = sync_do(Pid3, {open, File, none}), 2129 {ok, n} = sync_do(Pid4, {open, File, none}), 2130 [] = sync_do(Pid3, owners), 2131 [] = sync_do(Pid4, owners), 2132 2 = sync_do(Pid3, users), 2133 2 = sync_do(Pid4, users), 2134 sync_do(Pid3, terminate), 2135 [] = sync_do(Pid4, owners), 2136 2 = sync_do(Pid4, users), 2137 sync_do(Pid4, terminate), 2138 disk_log:close(n), 2139 disk_log:close(n), 2140 {error, no_such_log} = disk_log:info(n), 2141 check_pps(P0), 2142 2143 %% Blocking owner terminates. 2144 Pid5 = spawn_link(?MODULE, lserv, [n]), 2145 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2146 {linkto, none},{size, {100,No}}, 2147 {format, external}]), 2148 {ok, n} = sync_do(Pid5, {open, File}), 2149 ok = sync_do(Pid5, block), 2150 {blocked, true} = status(n), 2151 [_] = owners(n), 2152 sync_do(Pid5, terminate), 2153 ok = status(n), 2154 [] = owners(n), 2155 1 = users(n), 2156 ok = disk_log:close(n), 2157 {error, no_such_log} = disk_log:info(n), 2158 check_pps(P0), 2159 2160 %% Blocking user terminates. 2161 Pid6 = spawn_link(?MODULE, lserv, [n]), 2162 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2163 {size, {100,No}}, {format, external}]), 2164 {ok, n} = sync_do(Pid6, {open, File, none}), 2165 ok = sync_do(Pid6, block), 2166 {blocked, true} = status(n), 2167 [_] = owners(n), 2168 1 = users(n), 2169 sync_do(Pid6, terminate), % very silently... 2170 ok = status(n), 2171 [_] = owners(n), 2172 1 = users(n), 2173 ok = disk_log:close(n), 2174 [] = owners(n), 2175 1 = users(n), 2176 ok = disk_log:close(n), 2177 {error, no_such_log} = disk_log:info(n), 2178 check_pps(P0), 2179 2180 %% Blocking owner terminates. 2181 Pid7 = spawn_link(?MODULE, lserv, [n]), 2182 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2183 {linkto, none}, 2184 {size, {100,No}}, {format, external}]), 2185 {ok, n} = sync_do(Pid7, {open, File}), 2186 ok = sync_do(Pid7, block), 2187 {blocked, true} = status(n), 2188 [_] = owners(n), 2189 1 = users(n), 2190 sync_do(Pid7, terminate), 2191 ok = status(n), 2192 [] = owners(n), 2193 1 = users(n), 2194 ok = disk_log:close(n), 2195 {error, no_such_log} = disk_log:info(n), 2196 check_pps(P0), 2197 2198 %% Two owners, the blocking one terminates. 2199 Pid8 = spawn_link(?MODULE, lserv, [n]), 2200 Pid9 = spawn_link(?MODULE, lserv, [n]), 2201 {ok, n} = sync_do(Pid8, {open, File}), 2202 {ok, n} = sync_do(Pid9, {open, File}), 2203 ok = sync_do(Pid8, block), 2204 {blocked, true} = status(n), 2205 sync_do(Pid8, terminate), 2206 ok = status(n), 2207 [_] = sync_do(Pid9, owners), 2208 0 = sync_do(Pid9, users), 2209 sync_do(Pid9, terminate), 2210 {error, no_such_log} = disk_log:info(n), 2211 check_pps(P0), 2212 2213 %% Blocking user closes. 2214 Pid10 = spawn_link(?MODULE, lserv, [n]), 2215 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2216 {size, {100,No}}, {format, external}]), 2217 {ok, n} = sync_do(Pid10, {open, File, none}), 2218 ok = sync_do(Pid10, block), 2219 {blocked, true} = status(n), 2220 [_] = owners(n), 2221 1 = users(n), 2222 ok = sync_do(Pid10, close), 2223 ok = status(n), 2224 [_] = owners(n), 2225 0 = users(n), 2226 ok = disk_log:close(n), 2227 sync_do(Pid10, terminate), 2228 {error, no_such_log} = disk_log:info(n), 2229 check_pps(P0), 2230 2231 %% Blocking user unblocks and closes. 2232 Pid11 = spawn_link(?MODULE, lserv, [n]), 2233 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2234 {size, {100,No}}, {format, external}]), 2235 {ok, n} = sync_do(Pid11, {open, File, none}), 2236 ok = sync_do(Pid11, block), 2237 {blocked, true} = status(n), 2238 [_] = owners(n), 2239 1 = users(n), 2240 ok = sync_do(Pid11, unblock), 2241 ok = sync_do(Pid11, close), 2242 ok = status(n), 2243 [_] = owners(n), 2244 0 = users(n), 2245 ok = disk_log:close(n), 2246 {error, no_such_log} = disk_log:info(n), 2247 sync_do(Pid11, terminate), 2248 check_pps(P0), 2249 2250 %% Blocking owner closes. 2251 Pid12 = spawn_link(?MODULE, lserv, [n]), 2252 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2253 {linkto, none}, 2254 {size, {100,No}}, {format, external}]), 2255 {ok, n} = sync_do(Pid12, {open, File}), 2256 ok = sync_do(Pid12, block), 2257 {blocked, true} = status(n), 2258 [_] = owners(n), 2259 1 = users(n), 2260 ok = sync_do(Pid12, close), 2261 ok = status(n), 2262 [] = owners(n), 2263 1 = users(n), 2264 ok = disk_log:close(n), 2265 {error, no_such_log} = disk_log:info(n), 2266 sync_do(Pid12, terminate), 2267 check_pps(P0), 2268 2269 %% Blocking owner unblocks and closes. 2270 Pid13 = spawn_link(?MODULE, lserv, [n]), 2271 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2272 {linkto, none}, 2273 {size, {100,No}}, {format, external}]), 2274 {ok, n} = sync_do(Pid13, {open, File}), 2275 ok = sync_do(Pid13, block), 2276 {blocked, true} = status(n), 2277 [_] = owners(n), 2278 1 = users(n), 2279 ok = sync_do(Pid13, unblock), 2280 ok = sync_do(Pid13, close), 2281 ok = status(n), 2282 [] = owners(n), 2283 1 = users(n), 2284 ok = disk_log:close(n), 2285 {error, no_such_log} = disk_log:info(n), 2286 sync_do(Pid13, terminate), 2287 check_pps(P0), 2288 2289 del(File, No), % cleanup 2290 ok. 2291 2292%% OTP-4745. Deadlock with just an ordinary log could happen. 2293close_deadlock(Conf) when is_list(Conf) -> 2294 true = is_alive(), 2295 2296 PrivDir = ?privdir(Conf), 2297 2298 F1 = filename:join(PrivDir, "a.LOG"), 2299 file:delete(F1), 2300 Self = self(), 2301 2302 %% One process opens the log at the same time as another process 2303 %% closes the log. Used to always cause deadlock before OTP-4745. 2304 Name = a, 2305 Fun = fun() -> open_close(Self, Name, F1) end, 2306 P = spawn(Fun), 2307 receive {P, Name} -> ok end, 2308 {ok, L} = disk_log:open([{name,Name},{file,F1}]), 2309 ok = disk_log:close(L), 2310 receive {P, done} -> ok end, 2311 file:delete(F1), 2312 2313 %% One process opens the log at the same time as another process 2314 %% closes the log due to file error while truncating. 2315 %% This test is time dependent, but does not fail when it does not 2316 %% "work". When it works, as it seems to do right now :), the 2317 %% disk_log_server gets {error, no_such_log}, receives the EXIT 2318 %% message caused by truncate, and tries to open the log again. 2319 No = 4, 2320 LDir = F1 ++ ".2", 2321 file:del_dir(LDir), 2322 del(F1, No), 2323 ok = file:make_dir(LDir), 2324 Fun2 = fun() -> open_truncate(Self, Name, F1, No) end, 2325 P2 = spawn(Fun2), 2326 receive {P2, Name} -> ok end, 2327 {ok, L} = disk_log:open([{name, Name}, {file, F1}, {type, wrap}, 2328 {format, external}]), 2329 %% Note: truncate causes the disk log process to terminate. One 2330 %% cannot say if open above happened before, after, or during the 2331 %% termination. The link to the owner is removed before termination. 2332 case disk_log:close(L) of 2333 ok -> ok; 2334 {error,no_such_log} -> 2335 ok 2336 end, 2337 receive {P2, done} -> ok end, 2338 del(F1, No), 2339 file:del_dir(LDir), 2340 2341 %% To the same thing, this time using distributed logs. 2342 %% (Does not seem to work very well, unfortunately.) 2343 FunD = fun() -> open_close_dist(Self, Name, F1) end, 2344 PD = spawn(FunD), 2345 receive {PD, Name} -> ok end, 2346 {[_], []} = disk_log:open([{name,Name},{file,F1}, 2347 {distributed,[node()]}]), 2348 ok = disk_log:close(L), 2349 receive {PD, done} -> ok end, 2350 file:delete(F1), 2351 2352 ok. 2353 2354open_close(Pid, Name, File) -> 2355 {ok, L} = disk_log:open([{name,Name},{file,File}]), 2356 Pid ! {self(), Name}, 2357 ok = disk_log:close(L), 2358 Pid ! {self(), done}. 2359 2360open_truncate(Pid, Name, File, No) -> 2361 {ok, L} = disk_log:open([{name, Name}, {file, File}, {type, wrap}, 2362 {format, external},{size, {100, No}}]), 2363 Pid ! {self(), Name}, 2364 {error, {file_error, _, _}} = disk_log:truncate(L), 2365 %% The file has been closed, the disklog process has terminated. 2366 Pid ! {self(), done}. 2367 2368open_close_dist(Pid, Name, File) -> 2369 {[{_,{ok,L}}], []} = disk_log:open([{name,Name},{file,File}, 2370 {distributed,[node()]}]), 2371 Pid ! {self(), Name}, 2372 ok = disk_log:close(L), 2373 Pid ! {self(), done}. 2374 2375async_do(Pid, Req) -> 2376 Pid ! {self(), Req}, 2377 %% make sure the request is queued 2378 timer:sleep(100). 2379 2380get_reply() -> 2381 receive Reply -> 2382 Reply 2383 end. 2384 2385sync_do(Pid, Req) -> 2386 Pid ! {self(), Req}, 2387 receive 2388 Reply when Req =:= terminate -> 2389 timer:sleep(500), 2390 Reply; 2391 Reply -> 2392 Reply 2393 end. 2394 2395lserv(Log) -> 2396 receive 2397 {From, {open, File}} -> 2398 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2399 {size, {100,1}}, {format, external}]); 2400 {From, {open, File, LinkTo}} -> 2401 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2402 {linkto, LinkTo}, {size, {100,1}}, 2403 {format, external}]); 2404 {From, {int_open, File}} -> 2405 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2406 {size, {100,1}}]); 2407 {From, {int_open, File, Size}} -> 2408 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2409 {size, Size}]); 2410 {From, {dist_open, File, Node}} -> 2411 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2412 {size, {100,1}}, {distributed, [Node]}]); 2413 {From, {dist_open, File, LinkTo, Node}} -> 2414 From ! disk_log:open([{name, Log}, {file, File}, {type, wrap}, 2415 {linkto, LinkTo}, {size, {100,1}}, 2416 {distributed, [Node]}]); 2417 {From, block} -> 2418 From ! disk_log:block(Log); 2419 {From, {block, Bool}} -> 2420 From ! disk_log:block(Log, Bool); 2421 {From, unblock} -> 2422 From ! disk_log:unblock(Log); 2423 {From, close} -> 2424 From ! disk_log:close(Log); 2425 {From, owners} -> 2426 From ! owners(Log); 2427 {From, users} -> 2428 From ! users(Log); 2429 {From, sync} -> 2430 From ! disk_log:sync(Log); 2431 {From, truncate} -> 2432 From ! disk_log:truncate(Log); 2433 {From, terminate} -> 2434 From ! terminated, 2435 exit(normal); 2436 {From, {log, B}} -> 2437 From ! disk_log:log(Log, B); 2438 {From, {blog, B}} -> 2439 From ! disk_log:blog(Log, B); 2440 {From, {alog, B}} -> 2441 From ! disk_log:alog(Log, B); 2442 {From, {balog, B}} -> 2443 From ! disk_log:balog(Log, B); 2444 {From, {change_notify, Pid, Bool}} -> 2445 From ! disk_log:change_notify(Log, Pid, Bool); 2446 {From, {change_header, Header}} -> 2447 From ! disk_log:change_header(Log, Header); 2448 {From, {change_size, Size}} -> 2449 From ! disk_log:change_size(Log, Size); 2450 {From, inc_wrap_file} -> 2451 From ! disk_log:inc_wrap_file(Log); 2452 {From, {chunk, Cont}} -> 2453 From ! disk_log:chunk(Log, Cont); 2454 {From, {chunk_step, Cont, N}} -> 2455 From ! disk_log:chunk_step(Log, Cont, N); 2456 Any -> 2457 io:format("invalid request ~p~n", [Any]), 2458 exit(abnormal) 2459 end, 2460 lserv(Log). 2461 2462 2463%% Error while repairing. 2464error_repair(Conf) when is_list(Conf) -> 2465 %% not all error situations are covered by this test 2466 2467 DataDir = ?datadir(Conf), 2468 PrivDir = ?privdir(Conf), 2469 2470 File = filename:join(PrivDir, "n.LOG"), 2471 No = 4, 2472 file:delete(File), 2473 del(File, No), % cleanup 2474 2475 %% kurt.LOG is not closed and has four logged items, one is recovered 2476 copy_wrap_log("kurt.LOG", "n.LOG", No, DataDir, PrivDir), 2477 {repaired,n,{recovered,1},{badbytes,0}} = 2478 disk_log:open([{name, n}, {file, File}, {type, wrap}, {size,{40,No}}]), 2479 1 = cur_cnt(n), 2480 53 = curb(n), 2481 4 = no_items(n), 2482 ok = disk_log:close(n), 2483 2484 %% temporary repair file cannot be created 2485 copy_wrap_log("kurt.LOG", "n.LOG", No, DataDir, PrivDir), 2486 Dir = File ++ ".4" ++ ".TMP", 2487 ok = file:make_dir(Dir), 2488 P0 = pps(), 2489 {error, {file_error, _, _}} = 2490 disk_log:open([{name, n}, {file, File}, {type, wrap}, {size,{40,4}}]), 2491 check_pps(P0), 2492 del(File, No), 2493 ok = file:del_dir(Dir), 2494 2495 error_logger:add_report_handler(?MODULE, self()), 2496 %% repair a file 2497 P1 = pps(), 2498 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2499 {format, internal}, {size, {40,No}}]), 2500 ok = disk_log:log_terms(n, [{this,is}]), % first file full 2501 ok = disk_log:log_terms(n, [{some,terms}]), % second file full 2502 ok = disk_log:close(n), 2503 BadFile = add_ext(File, 2), % current file 2504 set_opened(BadFile), 2505 crash(BadFile, 28), % the binary is now invalid 2506 {repaired,n,{recovered,0},{badbytes,26}} = 2507 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2508 {format, internal}, {size, {40,No}}]), 2509 ok = disk_log:close(n), 2510 check_pps(P1), 2511 del(File, No), 2512 receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok 2513 after 1000 -> ct:fail(failed) end, 2514 2515 %% yet another repair 2516 P2 = pps(), 2517 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2518 {format, internal}, {size, {4000,No}}]), 2519 ok = disk_log:log_terms(n, [{this,is},{some,terms}]), 2520 ok = disk_log:close(n), 2521 BadFile2 = add_ext(File, 1), % current file 2522 set_opened(BadFile2), 2523 crash(BadFile2, 51), % the second binary is now invalid 2524 {repaired,n,{recovered,1},{badbytes,26}} = 2525 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2526 {format, internal}, {size, {4000,No}}]), 2527 ok = disk_log:close(n), 2528 check_pps(P2), 2529 del(File, No), 2530 receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok 2531 after 1000 -> ct:fail(failed) end, 2532 2533 %% Repair, large term 2534 Big = term_to_binary(lists:duplicate(66000,$a)), 2535 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2536 {format, internal}, {size, {40,No}}]), 2537 ok = disk_log:log_terms(n, [Big]), 2538 ok = disk_log:close(n), 2539 set_opened(add_ext(File, 1)), 2540 {repaired,n,{recovered,1},{badbytes,0}} = 2541 disk_log:open([{name, n}, {file, File}, {type, wrap}, 2542 {format, internal}, {size, {40,No}}]), 2543 {_, [Got]} = disk_log:chunk(n, start), 2544 ok = disk_log:close(n), 2545 Got = Big, 2546 del(File, No), 2547 receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok 2548 after 1000 -> ct:fail(failed) end, 2549 2550 %% A term a little smaller than a chunk, then big terms. 2551 BigSmall = mk_bytes(1024*64-8-12), 2552 file:delete(File), 2553 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2554 {format, internal}]), 2555 ok = disk_log:log_terms(n, [BigSmall, Big, Big]), 2556 ok = disk_log:close(n), 2557 set_opened(File), 2558 FileSize = file_size(File), 2559 crash(File, FileSize-byte_size(Big)-4), 2560 Error1 = {error, {need_repair, _}} = 2561 disk_log:open([{name, n}, {file, File}, {repair, false}, 2562 {type, halt}, {format, internal}]), 2563 "The disk log" ++ _ = format_error(Error1), 2564 {repaired,n,{recovered,2},{badbytes,132013}} = 2565 disk_log:open([{name, n}, {file, File}, {repair, true}, 2566 {type, halt}, {format, internal}]), 2567 ok = disk_log:close(n), 2568 file:delete(File), 2569 receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok 2570 after 1000 -> ct:fail(failed) end, 2571 2572 %% The header is recovered. 2573 {ok,n} = 2574 disk_log:open([{name, n}, {file, File}, {type, halt}, 2575 {format, internal}, 2576 {head_func, {?MODULE, head_fun, [{ok,"head"}]}}]), 2577 ok = disk_log:log_terms(n, [list,'of',terms]), 2578 ["head",list,'of',terms] = get_all_terms(n), 2579 ok = disk_log:close(n), 2580 set_opened(File), 2581 crash(File, 30), 2582 {repaired,n,{recovered,3},{badbytes,16}} = 2583 disk_log:open([{name, n}, {file, File}, {type, halt}, 2584 {format, internal},{repair,true}, {quiet, true}, 2585 {head_func, {?MODULE, head_fun, [{ok,"head"}]}}]), 2586 ["head",'of',terms] = get_all_terms(n), 2587 ok = disk_log:close(n), 2588 error_logger:delete_report_handler(?MODULE), 2589 file:delete(File), 2590 {messages, []} = process_info(self(), messages), 2591 2592 ok. 2593 2594set_opened(File) -> 2595 {ok, Fd} = file:open(File, [raw, binary, read, write]), 2596 ok = file:write(Fd, [?LOGMAGIC, ?OPENED]), 2597 ok = file:close(Fd). 2598 2599%% Error while repairing. 2600error_log(Conf) when is_list(Conf) -> 2601 Dir = ?privdir(Conf), 2602 2603 File = filename:join(Dir, "n.LOG"), 2604 No = 4, 2605 file:delete(File), 2606 del(File, No), % cleanup 2607 LDir = File ++ ".2", 2608 2609 Q = qlen(), 2610 %% dummy just to get all processes "above" disk_log going 2611 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2612 {format, external},{size, {100, No}}]), 2613 ok = disk_log:close(n), 2614 del(File, No), 2615 2616 %% inc_wrap_file fails, the external log is not terminated 2617 P0 = pps(), 2618 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2619 {format, external},{size, {100, No}}]), 2620 ok = file:make_dir(LDir), 2621 {error, {file_error, _, _}} = disk_log:inc_wrap_file(n), 2622 timer:sleep(500), 2623 ok = disk_log:close(n), 2624 del(File, No), 2625 2626 %% inc_wrap_file fails, the internal log is not terminated, ./File.2/ exists 2627 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2628 {format, internal},{size, {100, No}}]), 2629 {error, {file_error, _, _}} = disk_log:inc_wrap_file(n), 2630 ok = disk_log:close(n), 2631 del(File, No), 2632 2633 %% truncate fails, the log is terminated, ./File.2/ exists 2634 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2635 {format, external},{size, {100, No}}]), 2636 {error, {file_error, _, _}} = disk_log:truncate(n), 2637 check_pps(P0), 2638 del(File, No), 2639 2640 %% OTP-4880. 2641 %% reopen (rename) fails, the log is terminated, ./File.2/ exists 2642 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2643 {format, external},{size, 100000}]), 2644 {error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir), 2645 check_pps(P0), 2646 file:delete(File), 2647 2648 B = mk_bytes(60), 2649 2650 %% OTP-4880. reopen a wrap log, rename fails 2651 File2 = filename:join(Dir, "n.LOG2"), 2652 {ok, n} = disk_log:open([{name, n}, {file, File2}, {type, wrap}, 2653 {format, external},{size, {100, No}}]), 2654 ok = disk_log:blog_terms(n, [B,B,B]), 2655 {error, {file_error, _, eisdir}} = disk_log:reopen(n, File), 2656 {error, no_such_log} = disk_log:close(n), 2657 del(File2, No), 2658 del(File, No), 2659 2660 %% log, external wrap log, ./File.2/ exists 2661 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2662 {format, external},{size, {100, No}}]), 2663 {error, {file_error, _, _}} = disk_log:blog_terms(n, [B,B,B]), 2664 ok = disk_log:close(n), 2665 del(File, No), 2666 2667 %% log, internal wrap log, ./File.2/ exists 2668 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2669 {format, internal},{size, {100, No}}]), 2670 {error, {file_error, _, _}} = disk_log:log_terms(n, [B,B,B]), 2671 ok = disk_log:close(n), 2672 del(File, No), 2673 2674 ok = file:del_dir(LDir), 2675 2676 %% can't remove file when changing size 2677 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2678 {format, internal},{size, {100, No}}]), 2679 ok = disk_log:log_terms(n, [B,B,B,B]), 2680 ok = disk_log:change_size(n, {100, No-2}), 2681 Three = File ++ ".3", 2682 ok = file:delete(Three), 2683 ok = file:make_dir(Three), 2684 {error, {file_error, _, _}} = disk_log:log_terms(n, [B,B,B]), 2685 timer:sleep(500), 2686 ok = disk_log:close(n), 2687 ok = file:del_dir(Three), 2688 del(File, No), 2689 Q = qlen(), 2690 ok. 2691 2692%% Test chunk and chunk_step. 2693chunk(Conf) when is_list(Conf) -> 2694 %% See also halt_ro_crash/1 above. 2695 2696 Dir = ?privdir(Conf), 2697 File = filename:join(Dir, "n.LOG"), 2698 No = 4, 2699 B = mk_bytes(60), 2700 BB = mk_bytes(64000), % 64 kB chunks 2701 del(File, No),% cleanup 2702 2703 %% Make sure chunk_step skips the rest of the binary. 2704 %% OTP-3716. This was a bug... 2705 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2706 {format, internal}, {size, {50,No}}]), 2707 %% 1, 2 and 3 on file one, 4 on file two. 2708 ok = disk_log:log_terms(n, [1,2,3,4]), 2709 {I1, [1]} = disk_log:chunk(n, start, 1), 2710 [{node,Node}] = disk_log:chunk_info(I1), 2711 Node = node(), 2712 Error1 = {error, {no_continuation, foobar}} = 2713 disk_log:chunk_info(foobar), 2714 "The term" ++ _ = format_error(Error1), 2715 {ok, I2} = disk_log:chunk_step(n, I1, 1), 2716 {error, {badarg, continuation}} = disk_log:chunk_step(n, foobar, 1), 2717 {I3, [4]} = disk_log:chunk(n, I2, 1), 2718 {ok, I4} = disk_log:chunk_step(n, I3, -1), 2719 {_, [1]} = disk_log:chunk(n, I4, 1), 2720 {error, {badarg, continuation}} = disk_log:bchunk(n, 'begin'), 2721 {Ib1, [Bin1,Bin2]} = disk_log:bchunk(n, start, 2), 2722 1 = binary_to_term(Bin1), 2723 2 = binary_to_term(Bin2), 2724 {ok, Ib2} = disk_log:chunk_step(n, Ib1, 1), 2725 {Ib3, [Bin3]} = disk_log:bchunk(n, Ib2, 1), 2726 4 = binary_to_term(Bin3), 2727 {ok, Ib4} = disk_log:chunk_step(n, Ib3, -1), 2728 {_, [Bin4]} = disk_log:bchunk(n, Ib4, 1), 2729 1 = binary_to_term(Bin4), 2730 {Ib5, [Bin1, Bin2, Bin17]} = disk_log:bchunk(n, start), 2731 3 = binary_to_term(Bin17), 2732 {Ib6, [Bin3]} = disk_log:bchunk(n, Ib5, infinity), 2733 eof = disk_log:bchunk(n, Ib6, infinity), 2734 ok = disk_log:close(n), 2735 del(File, No), % cleanup 2736 2737 %% external log, cannot read chunks 2738 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2739 {format, external}, {size, {100,No}}]), 2740 {error, {badarg, continuation}} = disk_log:chunk(n, 'begin'), 2741 {error, {format_external, n}} = disk_log:chunk(n, start), 2742 Error2 = {error, {not_internal_wrap, n}} = 2743 disk_log:chunk_step(n, start, 1), 2744 "The requested" ++ _ = format_error(Error2), 2745 ok = disk_log:close(n), 2746 del(File, No), 2747 2748 %% wrap, read_write 2749 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2750 {format, internal}, {size, {100,No}}]), 2751 ok = disk_log:log_terms(n, [B,B,B,B]), 2752 {C1, [_]} = disk_log:chunk(n, start), 2753 {C2, [_]} = disk_log:chunk(n, C1), 2754 {C3, [_]} = disk_log:chunk(n, C2), 2755 {C4, [_]} = disk_log:chunk(n, C3, 1), 2756 eof = disk_log:chunk(n, C4), 2757 {C5, [_]} = disk_log:chunk(n, start), 2758 {ok, C6} = disk_log:chunk_step(n, C5, 1), 2759 {C7, [_]} = disk_log:chunk(n, C6), 2760 {ok, C8} = disk_log:chunk_step(n, C7, 1), 2761 {_, [_]} = disk_log:chunk(n, C8), 2762 ok = disk_log:close(n), 2763 2764 %% wrap, read_only 2765 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2766 {mode, read_only}, 2767 {format, internal}, {size, {100,No}}]), 2768 {CC1, [_]} = disk_log:chunk(n, start), 2769 {CC2, [_]} = disk_log:chunk(n, CC1), 2770 {CC3, [_]} = disk_log:chunk(n, CC2), 2771 {CC4, [_]} = disk_log:chunk(n, CC3, 1), 2772 eof = disk_log:chunk(n, CC4), 2773 {CC5, [_]} = disk_log:chunk(n, start), 2774 {ok, CC6} = disk_log:chunk_step(n, CC5, 1), 2775 {CC7, [_]} = disk_log:chunk(n, CC6), 2776 {ok, CC8} = disk_log:chunk_step(n, CC7, 1), 2777 {_, [_]} = disk_log:chunk(n, CC8), 2778 ok = disk_log:close(n), 2779 2780 %% OTP-3716. A bug: {Error, List} and {Error, List, Bad} could be 2781 %% returned from chunk/2. 2782 %% Magic bytes not OK. 2783 %% File header (8 bytes) OK, item header not OK. 2784 InvalidFile = add_ext(File, 1), 2785 crash(InvalidFile, 15), 2786 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2787 {mode, read_only}, 2788 {format, internal}, {size, {100,No}}]), 2789 {_, [], 61} = disk_log:chunk(n, start), 2790 ok = disk_log:close(n), 2791 %% read_write... 2792 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2793 {format, internal}, {size, {100,No}}]), 2794 Error3 = {error, {corrupt_log_file, Culprit}} = 2795 disk_log:chunk(n, start), 2796 "The disk log file" ++ _ = format_error(Error3), 2797 Culprit = InvalidFile, 2798 ok = disk_log:close(n), 2799 del(File, No), 2800 2801 %% Two wrap log files, writing the second one, then reading the first 2802 %% one, where a bogus term resides. 2803 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2804 {format, internal}, {size, {40,No}}]), 2805 ok = disk_log:log_terms(n, [{this,is}]), % first file full 2806 ok = disk_log:log_terms(n, [{some,terms}]), % second file full 2807 2 = curf(n), 2808 BadFile = add_ext(File, 1), 2809 crash(BadFile, 28), % the _binary_ is now invalid 2810 {error, {corrupt_log_file, BFile}} = disk_log:chunk(n, start, 1), 2811 BadFile = BFile, 2812 ok = disk_log:close(n), 2813 %% The same, with a halt log. 2814 file:delete(File), % cleanup 2815 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2816 {format, internal}]), 2817 ok = disk_log:log_terms(n, [{this,is}]), 2818 ok = disk_log:sync(n), 2819 crash(File, 28), % the _binary_ is now invalid 2820 {error, {corrupt_log_file, File2}} = disk_log:chunk(n, start, 1), 2821 crash(File, 10), 2822 {error,{corrupt_log_file,_}} = disk_log:bchunk(n, start, 1), 2823 true = File == File2, 2824 ok = disk_log:close(n), 2825 del(File, No), 2826 2827 %% halt, read_write 2828 file:delete(File), % cleanup 2829 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2830 {format, internal}]), 2831 ok = disk_log:log_terms(n, [BB,BB,BB,BB]), 2832 {D1, [Ch1]} = disk_log:chunk(n, start, 1), 2833 Ch1 = BB, 2834 {D2, [Ch2]} = disk_log:chunk(n, D1, 1), 2835 Ch2 = BB, 2836 {D3, [Ch3]} = disk_log:chunk(n, D2, 1), 2837 Ch3 = BB, 2838 {D4, [Ch4]} = disk_log:chunk(n, D3, 1), 2839 Ch4 = BB, 2840 eof = disk_log:chunk(n, D4), 2841 ok = disk_log:close(n), 2842 2843 %% halt, read_only 2844 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2845 {format, internal},{mode,read_only}]), 2846 {E1, [Ch5]} = disk_log:chunk(n, start, 1), 2847 Ch5 = BB, 2848 {E2, [Ch6]} = disk_log:chunk(n, E1, 1), 2849 Ch6 = BB, 2850 {E3, [Ch7]} = disk_log:chunk(n, E2, 1), 2851 Ch7 = BB, 2852 {E4, [Ch8]} = disk_log:chunk(n, E3, 1), 2853 Ch8 = BB, 2854 eof = disk_log:chunk(n, E4), 2855 ok = disk_log:close(n), 2856 file:delete(File), % cleanup 2857 2858 %% More than 64 kB term. 2859 BBB = term_to_binary(lists:duplicate(66000,$a)), 2860 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2861 {format, internal}]), 2862 ok = disk_log:log_terms(n, [BBB]), 2863 {F1, [BBB1]} = disk_log:chunk(n, start), 2864 BBB1 = BBB, 2865 eof = disk_log:chunk(n, F1), 2866 ok = disk_log:close(n), 2867 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2868 {format, internal}, {mode, read_only}]), 2869 {F1r, [BBB2]} = disk_log:chunk(n, start), 2870 BBB2 = BBB, 2871 eof = disk_log:chunk(n, F1r), 2872 ok = disk_log:close(n), 2873 2874 truncate(File, 8192), 2875 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2876 {format, internal}]), 2877 {error, {corrupt_log_file, _}} = disk_log:chunk(n, start), 2878 ok = disk_log:close(n), 2879 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2880 {format, internal}, {mode, read_only}]), 2881 {K1, [], 8176} = disk_log:chunk(n, start), 2882 eof = disk_log:chunk(n, K1), 2883 ok = disk_log:close(n), 2884 file:delete(File), % cleanup 2885 2886 %% OTP-3716. A bug: eof in the middle of the last element is not ok. 2887 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2888 {format, internal}]), 2889 ok = disk_log:log_terms(n, [B,BB]), 2890 ok = disk_log:close(n), 2891 truncate(File, 80), 2892 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2893 {format, internal}]), 2894 {G1, [_]} = disk_log:chunk(n, start, 1), 2895 {error, {corrupt_log_file, _}} = disk_log:chunk(n, G1, 1), 2896 ok = disk_log:close(n), 2897 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2898 {format, internal}, {mode, read_only}]), 2899 {G1r, [_]} = disk_log:chunk(n, start, 1), 2900 {_, [], 4} = disk_log:chunk(n, G1r, 1), 2901 ok = disk_log:close(n), 2902 file:delete(File), % cleanup 2903 2904 %% Opening a wrap log read-only. The second of four terms is destroyed. 2905 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2906 {format, internal}, {size, {4000,No}}]), 2907 ok = disk_log:log_terms(n, 2908 [{this,is},{some,terms},{on,a},{wrap,file}]), 2909 ok = disk_log:close(n), 2910 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 2911 {format, internal}, {mode, read_only}]), 2912 CrashFile = add_ext(File, 1), 2913 crash(CrashFile, 51), % the binary term {some,terms} is now bad 2914 {H1, [{this,is}], 18} = disk_log:chunk(n, start, 10), 2915 {H2, [{on,a},{wrap,file}]} = disk_log:chunk(n, H1), 2916 eof = disk_log:chunk(n, H2), 2917 ok = disk_log:close(n), 2918 del(File, No), 2919 2920 %% The same as last, but with a halt log. 2921 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2922 {format, internal}, {mode, read_write}]), 2923 ok = disk_log:alog_terms(n, [{this,is},{some,terms}]), 2924 ok = disk_log:log_terms(n, [{on,a},{halt,file}]), 2925 ok = disk_log:close(n), 2926 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2927 {format, internal}, {mode, read_only}]), 2928 crash(File, 51), % the binary term {some,terms} is now bad 2929 {J1, [{this,is}], 18} = disk_log:chunk(n, start, 10), 2930 {J2, [{on,a},{halt,file}]} = disk_log:chunk(n, J1), 2931 eof = disk_log:chunk(n, J2), 2932 ok = disk_log:close(n), 2933 file:delete(File), 2934 2935 %% OTP-7641. Same as last one, but the size of the bad term is 2936 %% less than ?HEADERSz (8) bytes. 2937 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2938 {format, internal}, {mode, read_write}]), 2939 ok = disk_log:alog_terms(n, [{this,is},{s}]), 2940 ok = disk_log:log_terms(n, [{on,a},{halt,file}]), 2941 ok = disk_log:close(n), 2942 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2943 {format, internal}, {mode, read_only}]), 2944 crash(File, 44), % the binary term {s} is now bad 2945 {J11, [{this,is}], 7} = disk_log:chunk(n, start, 10), 2946 {J21, [{on,a},{halt,file}]} = disk_log:chunk(n, J11), 2947 eof = disk_log:chunk(n, J21), 2948 ok = disk_log:close(n), 2949 file:delete(File), 2950 2951 %% Minimal MD5-proctected term, and maximal unprotected term. 2952 %% A chunk ends in the middle of the MD5-sum. 2953 MD5term = mk_bytes(64*1024-8), 2954 NotMD5term = mk_bytes((64*1024-8)-1), 2955 Term2 = mk_bytes((64*1024-8)-16), 2956 MD5L = [MD5term,NotMD5term,Term2,MD5term,MD5term,NotMD5term], 2957 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2958 {format, internal}]), 2959 ok = disk_log:log_terms(n, MD5L), 2960 true = MD5L == get_all_terms(n), 2961 ok = disk_log:close(n), 2962 true = MD5L == get_all_terms(n, File, halt), 2963 crash(File, 21), % the MD5-sum of the first term is now bad 2964 true = {tl(MD5L),64*1024-8} == get_all_terms_and_bad(n, File, halt), 2965 {_,64*1024-8} = get_all_binary_terms_and_bad(n, File, halt), 2966 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 2967 {format, internal}]), 2968 {error, {corrupt_log_file, _}} = disk_log:chunk(n, start), 2969 ok = disk_log:close(n), 2970 file:delete(File), 2971 2972 %% A file with "old" terms (magic word is MAGICINT). 2973 DataDir = ?datadir(Conf), 2974 OldTermsFileOrig = filename:join(DataDir, "old_terms.LOG"), 2975 OldTermsFile = filename:join(Dir, "old_terms.LOG"), 2976 copy_file(OldTermsFileOrig, OldTermsFile), 2977 {[_,_,_,_],0} = get_all_terms_and_bad(n, OldTermsFile, halt), 2978 {ok, n} = disk_log:open([{name, n}, {file, OldTermsFile}, 2979 {type, halt}, {format, internal}]), 2980 [_,_,_,_] = get_all_terms(n), 2981 ok = disk_log:close(n), 2982 file:delete(OldTermsFile), 2983 2984 ok. 2985 2986%% OTP-5558. Keep the contents of index files after disk crash. 2987error_index(Conf) when is_list(Conf) -> 2988 Dir = ?privdir(Conf), 2989 2990 File = filename:join(Dir, "n.LOG"), 2991 IdxFile = File ++ ".idx", 2992 No = 4, 2993 file:delete(File), 2994 del(File, No), % cleanup 2995 2996 Args = [{name,n},{type,wrap},{size,{100,No}},{file,File}], 2997 {ok, n} = disk_log:open(Args), 2998 ok = disk_log:close(n), 2999 Q = qlen(), 3000 P0 = pps(), 3001 ok = file:write_file(IdxFile, <<"abc">>), 3002 {error, {invalid_index_file, _}} = disk_log:open(Args), 3003 {error, {invalid_index_file, _}} = disk_log:open(Args), 3004 {error, {invalid_index_file, _}} = disk_log:open(Args), 3005 3006 del(File, No), 3007 check_pps(P0), 3008 true = (Q == qlen()), 3009 ok. 3010 3011%% Test truncate/1 on halt and wrap logs. 3012truncate(Conf) when is_list(Conf) -> 3013 Dir = ?privdir(Conf), 3014 3015 Q = qlen(), 3016 Halt = join(Dir, "halt.LOG"), 3017 %% Halt logs. 3018 3019 file:delete(Halt), % cleanup 3020 {ok, halt} = disk_log:open([{name, halt}, {type, halt}, {file, Halt}, 3021 {head, header}, {notify, true}]), 3022 infinity = sz(halt), 3023 ok = disk_log:truncate(halt, tjohej), 3024 rec(1, {disk_log, node(), halt, {truncated, 1}}), 3025 ok = disk_log:change_size(halt, 10000), 3026 10000 = sz(halt), 3027 disk_log:close(halt), 3028 [tjohej] = get_all_terms(halt, Halt, halt), 3029 file:delete(Halt), 3030 3031 {ok, halt} = disk_log:open([{name, halt}, {type, halt}, {file, Halt}, 3032 {head, header}, {notify, true}]), 3033 ok = disk_log:truncate(halt), 3034 rec(1, {disk_log, node(), halt, {truncated, 1}}), 3035 disk_log:close(halt), 3036 [header] = get_all_terms(halt, Halt, halt), 3037 file:delete(Halt), 3038 3039 {ok, halt} = disk_log:open([{name, halt}, {type, halt}, 3040 {file, Halt}, {format, external}, 3041 {head, "header"}, {notify, false}]), 3042 ok = disk_log:btruncate(halt, "apa"), 3043 disk_log:close(halt), 3044 3 = file_size(Halt), 3045 file:delete(Halt), 3046 3047 %% Wrap logs. 3048 File = filename:join(Dir, "n.LOG"), 3049 No = 4, 3050 B = mk_bytes(60), 3051 del(File, No), % cleanup 3052 3053 %% Internal with header. 3054 Size = {100, No}, 3055 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3056 {head, header}, {notify, true}, 3057 {size, Size}]), 3058 ok = disk_log:log_terms(n, [B,B,B]), 3059 %% Used to be one message, but now one per wrapped file. 3060 rec(2, {disk_log, node(), n, {wrap, 0}}), 3061 ok = disk_log:truncate(n, apa), 3062 rec(1, {disk_log, node(), n, {truncated, 6}}), 3063 {0, 0} = no_overflows(n), 3064 23 = curb(n), 3065 1 = curf(n), 3066 1 = cur_cnt(n), 3067 true = (Size == sz(n)), 3068 3069 ok = disk_log:log_terms(n, [B, B]), 3070 rec(1, {disk_log, node(), n, {wrap, 0}}), 3071 ok = disk_log:close(n), 3072 [apa, _, header, _] = get_all_terms(n, File, wrap), 3073 del(File, No), 3074 3075 %% Internal without general header. 3076 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3077 {notify, true}, 3078 {size, {100, No}}]), 3079 ok = disk_log:log_terms(n, [B,B,B]), 3080 rec(2, {disk_log, node(), n, {wrap, 0}}), 3081 ok = disk_log:truncate(n, apa), 3082 rec(1, {disk_log, node(), n, {truncated, 3}}), 3083 {0, 0} = no_overflows(n), 3084 23 = curb(n), 3085 1 = curf(n), 3086 1 = cur_cnt(n), 3087 true = (Size == sz(n)), 3088 3089 ok = disk_log:log_terms(n, [B, B]), 3090 rec(1, {disk_log, node(), n, {wrap, 0}}), 3091 ok = disk_log:close(n), 3092 [apa, _, _] = get_all_terms(n, File, wrap), 3093 del(File, No), 3094 3095 %% Internal without any header. 3096 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3097 {notify, true}, 3098 {size, {100, No}}]), 3099 ok = disk_log:log_terms(n, [B,B,B]), 3100 rec(2, {disk_log, node(), n, {wrap, 0}}), 3101 ok = disk_log:truncate(n), 3102 rec(1, {disk_log, node(), n, {truncated, 3}}), 3103 {0, 0} = no_overflows(n), 3104 8 = curb(n), 3105 1 = curf(n), 3106 0 = cur_cnt(n), 3107 true = (Size == sz(n)), 3108 3109 ok = disk_log:log_terms(n, [B, B]), 3110 rec(1, {disk_log, node(), n, {wrap, 0}}), 3111 ok = disk_log:close(n), 3112 [_, _] = get_all_terms(n, File, wrap), 3113 del(File, No), 3114 Q = qlen(), 3115 ok. 3116 3117 3118%% Test many users logging and sync:ing at the same time. 3119many_users(Conf) when is_list(Conf) -> 3120 Dir = ?privdir(Conf), 3121 N = 100, 3122 NoClients = 10, 3123 Fun1 = fun(Name, Pid, I) -> disk_log:log(Name, {Pid, I}) end, 3124 Fun2 = fun(Name, Pid, I) -> ok = disk_log:log(Name, {Pid, I}), 3125 disk_log:sync(Name) end, 3126 {C1, T1} = many(Fun2, NoClients, N, halt, internal, infinity, Dir), 3127 true = lists:duplicate(NoClients, ok) == C1, 3128 true = length(T1) == N*NoClients, 3129 {C2, T2} = many(Fun1, NoClients, N, halt, internal, 1000, Dir), 3130 true = lists:duplicate(NoClients, {error, {full,"log.LOG"}}) == C2, 3131 true = length(T2) > 0, 3132 {C3, T3} = many(Fun2, NoClients, N, wrap, internal, 3133 {300*NoClients,200}, Dir), 3134 true = lists:duplicate(NoClients, ok) == C3, 3135 true = length(T3) == N*NoClients, 3136 ok. 3137 3138many(Fun, NoClients, N, Type, Format, Size, Dir) -> 3139 Name = "log.LOG", 3140 File = filename:join(Dir, Name), 3141 del_files(Size, File), 3142 Q = qlen(), 3143 {ok, _} = disk_log:open([{name,Name}, {type,Type}, {size,Size}, 3144 {format,Format}, {file,File}]), 3145 Pids = spawn_clients(NoClients, client, [self(), Name, N, Fun]), 3146 Checked = check_clients(Pids), 3147 ok = disk_log:close(Name), 3148 Terms = get_all_terms(Name, File, Type), 3149 del_files(Size, File), 3150 Q = qlen(), 3151 {Checked, Terms}. 3152 3153spawn_clients(0, _F, _A) -> 3154 []; 3155spawn_clients(I, F, A) -> 3156 [spawn_link(?MODULE, F, A) | spawn_clients(I-1, F, A)]. 3157 3158check_clients(Pids) -> 3159 lists:map(fun(Pid) -> receive {Pid, Reply} -> Reply end end, Pids). 3160 3161client(From, _Name, 0, _Fun) -> 3162 From ! {self(), ok}; 3163client(From, Name, N, Fun) -> 3164 %% Fun is called N times. 3165 case Fun(Name, self(), N) of 3166 ok -> client(From, Name, N-1, Fun); 3167 Else -> From ! {self(), Else} 3168 end. 3169 3170del_files({_NoBytes,NoFiles}, File) -> 3171 del(File, NoFiles); 3172del_files(_Size, File) -> 3173 file:delete(File). 3174 3175 3176 3177 3178%% Test no_current_{bytes, items} as returned by info/0. 3179info_current(Conf) when is_list(Conf) -> 3180 3181 Dir = ?privdir(Conf), 3182 File = filename:join(Dir, "n.LOG"), 3183 No = 4, 3184 B = mk_bytes(60), 3185 BB = mk_bytes(160), % bigger than a single wrap log file 3186 SB = mk_bytes(10), % much smaller than a single wrap log file 3187 del(File, No),% cleanup 3188 3189 Q = qlen(), 3190 %% Internal with header. 3191 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3192 {head, header}, {size, {100,No}}]), 3193 {26, 1} = {curb(n), cur_cnt(n)}, 3194 {1, 1} = {no_written_items(n), no_items(n)}, 3195 ok = disk_log:log(n, B), 3196 {94, 2} = {curb(n), cur_cnt(n)}, 3197 {2, 2} = {no_written_items(n), no_items(n)}, 3198 ok = disk_log:close(n), 3199 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3200 {notify, true}, 3201 {head, header}, {size, {100,No}}]), 3202 {94, 2} = {curb(n), cur_cnt(n)}, 3203 {0, 2} = {no_written_items(n), no_items(n)}, 3204 ok = disk_log:log(n, B), 3205 rec(1, {disk_log, node(), n, {wrap, 0}}), 3206 {94, 2} = {curb(n), cur_cnt(n)}, 3207 {2, 4} = {no_written_items(n), no_items(n)}, 3208 disk_log:inc_wrap_file(n), 3209 rec(1, {disk_log, node(), n, {wrap, 0}}), 3210 {26, 1} = {curb(n), cur_cnt(n)}, 3211 {3, 4} = {no_written_items(n), no_items(n)}, 3212 ok = disk_log:log_terms(n, [B,B,B]), 3213 %% Used to be one message, but now one per wrapped file. 3214 rec(1, {disk_log, node(), n, {wrap, 0}}), 3215 rec(1, {disk_log, node(), n, {wrap, 2}}), 3216 {94, 2} = {curb(n), cur_cnt(n)}, 3217 {8, 7} = {no_written_items(n), no_items(n)}, 3218 ok = disk_log:log_terms(n, [B]), 3219 rec(1, {disk_log, node(), n, {wrap, 2}}), 3220 ok = disk_log:log_terms(n, [B]), 3221 rec(1, {disk_log, node(), n, {wrap, 2}}), 3222 {94, 2} = {curb(n), cur_cnt(n)}, 3223 {12, 7} = {no_written_items(n), no_items(n)}, 3224 ok = disk_log:log_terms(n, [BB,BB]), 3225 %% Used to be one message, but now one per wrapped file. 3226 rec(2, {disk_log, node(), n, {wrap, 2}}), 3227 {194, 2} = {curb(n), cur_cnt(n)}, 3228 {16, 7} = {no_written_items(n), no_items(n)}, 3229 ok = disk_log:log_terms(n, [SB,SB,SB]), 3230 rec(1, {disk_log, node(), n, {wrap, 2}}), 3231 {80, 4} = {curb(n), cur_cnt(n)}, 3232 {20, 9} = {no_written_items(n), no_items(n)}, 3233 ok = disk_log:close(n), 3234 del(File, No), 3235 3236 %% Internal without header. 3237 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3238 {size, {100,No}}]), 3239 {8, 0} = {curb(n), cur_cnt(n)}, 3240 {0, 0} = {no_written_items(n), no_items(n)}, 3241 ok = disk_log:log(n, B), 3242 {76, 1} = {curb(n), cur_cnt(n)}, 3243 {1, 1} = {no_written_items(n), no_items(n)}, 3244 ok = disk_log:close(n), 3245 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3246 {notify, true}, {size, {100,No}}]), 3247 {76, 1} = {curb(n), cur_cnt(n)}, 3248 {0, 1} = {no_written_items(n), no_items(n)}, 3249 ok = disk_log:log(n, B), 3250 rec(1, {disk_log, node(), n, {wrap, 0}}), 3251 {76, 1} = {curb(n), cur_cnt(n)}, 3252 {1, 2} = {no_written_items(n), no_items(n)}, 3253 disk_log:inc_wrap_file(n), 3254 rec(1, {disk_log, node(), n, {wrap, 0}}), 3255 {8, 0} = {curb(n), cur_cnt(n)}, 3256 {1, 2} = {no_written_items(n), no_items(n)}, 3257 ok = disk_log:log_terms(n, [B,B,B]), 3258 %% Used to be one message, but now one per wrapped file. 3259 rec(1, {disk_log, node(), n, {wrap, 0}}), 3260 rec(1, {disk_log, node(), n, {wrap, 1}}), 3261 {76, 1} = {curb(n), cur_cnt(n)}, 3262 {4, 4} = {no_written_items(n), no_items(n)}, 3263 ok = disk_log:log_terms(n, [B]), 3264 rec(1, {disk_log, node(), n, {wrap, 1}}), 3265 ok = disk_log:log_terms(n, [B]), 3266 rec(1, {disk_log, node(), n, {wrap, 1}}), 3267 {76, 1} = {curb(n), cur_cnt(n)}, 3268 {6, 4} = {no_written_items(n), no_items(n)}, 3269 ok = disk_log:log_terms(n, [BB,BB]), 3270 %% Used to be one message, but now one per wrapped file. 3271 rec(2, {disk_log, node(), n, {wrap, 1}}), 3272 {176, 1} = {curb(n), cur_cnt(n)}, 3273 {8, 4} = {no_written_items(n), no_items(n)}, 3274 ok = disk_log:log_terms(n, [SB,SB,SB]), 3275 rec(1, {disk_log, node(), n, {wrap, 1}}), 3276 {62, 3} = {curb(n), cur_cnt(n)}, 3277 {11, 6} = {no_written_items(n), no_items(n)}, 3278 ok = disk_log:close(n), 3279 del(File, No), 3280 3281 %% External with header. 3282 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3283 {format, external}, {head, "header"}, 3284 {size, {100,No}}]), 3285 {6, 1} = {curb(n), cur_cnt(n)}, 3286 {1, 1} = {no_written_items(n), no_items(n)}, 3287 ok = disk_log:blog(n, B), 3288 {62, 2} = {curb(n), cur_cnt(n)}, 3289 {2, 2} = {no_written_items(n), no_items(n)}, 3290 ok = disk_log:close(n), 3291 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3292 {format, external}, {head, "header"}, 3293 {notify, true}, {size, {100,No}}]), 3294 {62, 2} = {curb(n), cur_cnt(n)}, 3295 {0, 2} = {no_written_items(n), no_items(n)}, 3296 ok = disk_log:blog(n, B), 3297 rec(1, {disk_log, node(), n, {wrap, 0}}), 3298 {62, 2} = {curb(n), cur_cnt(n)}, 3299 {2, 4} = {no_written_items(n), no_items(n)}, 3300 disk_log:inc_wrap_file(n), 3301 rec(1, {disk_log, node(), n, {wrap, 0}}), 3302 {6, 1} = {curb(n), cur_cnt(n)}, 3303 {3, 4} = {no_written_items(n), no_items(n)}, 3304 ok = disk_log:blog_terms(n, [B,B,B]), 3305 %% Used to be one message, but now one per wrapped file. 3306 rec(1, {disk_log, node(), n, {wrap, 0}}), 3307 rec(1, {disk_log, node(), n, {wrap, 2}}), 3308 {62, 2} = {curb(n), cur_cnt(n)}, 3309 {8, 7} = {no_written_items(n), no_items(n)}, 3310 ok = disk_log:blog_terms(n, [B]), 3311 rec(1, {disk_log, node(), n, {wrap, 2}}), 3312 ok = disk_log:blog_terms(n, [B]), 3313 rec(1, {disk_log, node(), n, {wrap, 2}}), 3314 {62, 2} = {curb(n), cur_cnt(n)}, 3315 {12, 7} = {no_written_items(n), no_items(n)}, 3316 ok = disk_log:blog_terms(n, [BB,BB]), 3317 %% Used to be one message, but now one per wrapped file. 3318 rec(2, {disk_log, node(), n, {wrap, 2}}), 3319 {162, 2} = {curb(n), cur_cnt(n)}, 3320 {16, 7} = {no_written_items(n), no_items(n)}, 3321 ok = disk_log:blog_terms(n, [SB,SB,SB]), 3322 3323 rec(1, {disk_log, node(), n, {wrap, 2}}), 3324 {24, 4} = {curb(n), cur_cnt(n)}, 3325 {20, 9} = {no_written_items(n), no_items(n)}, 3326 ok = disk_log:close(n), 3327 del(File, No), 3328 3329 %% External without header. 3330 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3331 {format, external}, {size, {100,No}}]), 3332 {0, 0} = {curb(n), cur_cnt(n)}, 3333 {0, 0} = {no_written_items(n), no_items(n)}, 3334 ok = disk_log:blog(n, B), 3335 {56, 1} = {curb(n), cur_cnt(n)}, 3336 {1, 1} = {no_written_items(n), no_items(n)}, 3337 ok = disk_log:close(n), 3338 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3339 {notify, true}, 3340 {format, external}, {size, {100,No}}]), 3341 {56, 1} = {curb(n), cur_cnt(n)}, 3342 {0, 1} = {no_written_items(n), no_items(n)}, 3343 ok = disk_log:blog(n, B), 3344 rec(1, {disk_log, node(), n, {wrap, 0}}), 3345 {56, 1} = {curb(n), cur_cnt(n)}, 3346 {1, 2} = {no_written_items(n), no_items(n)}, 3347 disk_log:inc_wrap_file(n), 3348 rec(1, {disk_log, node(), n, {wrap, 0}}), 3349 {0, 0} = {curb(n), cur_cnt(n)}, 3350 {1, 2} = {no_written_items(n), no_items(n)}, 3351 ok = disk_log:blog_terms(n, [B,B,B]), 3352 %% Used to be one message, but now one per wrapped file. 3353 rec(1, {disk_log, node(), n, {wrap, 0}}), 3354 rec(1, {disk_log, node(), n, {wrap, 1}}), 3355 {56, 1} = {curb(n), cur_cnt(n)}, 3356 {4, 4} = {no_written_items(n), no_items(n)}, 3357 ok = disk_log:blog_terms(n, [B]), 3358 rec(1, {disk_log, node(), n, {wrap, 1}}), 3359 ok = disk_log:blog_terms(n, [B]), 3360 rec(1, {disk_log, node(), n, {wrap, 1}}), 3361 {56, 1} = {curb(n), cur_cnt(n)}, 3362 {6, 4} = {no_written_items(n), no_items(n)}, 3363 ok = disk_log:blog_terms(n, [BB,BB]), 3364 %% Used to be one message, but now one per wrapped file. 3365 rec(2, {disk_log, node(), n, {wrap, 1}}), 3366 {156, 1} = {curb(n), cur_cnt(n)}, 3367 {8, 4} = {no_written_items(n), no_items(n)}, 3368 ok = disk_log:blog_terms(n, [SB,SB,SB]), 3369 rec(1, {disk_log, node(), n, {wrap, 1}}), 3370 {18, 3} = {curb(n), cur_cnt(n)}, 3371 {11, 6} = {no_written_items(n), no_items(n)}, 3372 ok = disk_log:close(n), 3373 del(File, No), 3374 3375 Q = qlen(), 3376 ok. 3377 3378 3379 3380change_size_before(doc) -> 3381 ["Change size of a wrap log file before we have reached " 3382 "to the file index corresponding to the new size"]; 3383change_size_before(Conf) when is_list(Conf) -> 3384 3385 Log_1_1 = "first log first message", 3386 Log_1_2 = "first log second message", 3387 Log_2_1 = "second log first message", 3388 Log_2_2 = "second log second message", 3389 Log_3_1 = "third log first message", 3390 Log_3_2 = "third log second message", 3391 Log_4_1 = "fourth log first message", 3392 Log_4_2 = "fourth log second message", 3393 Log_5_1 = "fifth log first message", 3394 Log_5_2 = "fifth log second message", 3395 Log_1_2_1 = "first log second round 1", 3396 Log_1_2_2 = "first log second round 2", 3397 3398 3399 Dir = ?privdir(Conf), 3400 File = filename:join(Dir, "a.LOG"), 3401 del(File, 5), 3402 {ok, a} = disk_log:open([{name,a}, {file, File}, 3403 {type, wrap}, {size, {100,5}}]), 3404 disk_log:log(a, Log_1_1), 3405 disk_log:log(a, Log_1_2), 3406 disk_log:log(a, Log_2_1), 3407 disk_log:log(a, Log_2_2), 3408 disk_log:change_size(a, {100, 3}), 3409 [Log_1_1, Log_1_2, 3410 Log_2_1, Log_2_2] = get_all_terms(a), 3411 disk_log:log(a, Log_3_1), 3412 disk_log:log(a, Log_3_2), 3413 disk_log:log(a, Log_1_2_1), 3414 disk_log:log(a, Log_1_2_2), 3415 [Log_2_1, Log_2_2, 3416 Log_3_1, Log_3_2, 3417 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3418 3419 disk_log:close(a), 3420 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3421 {size, {100,3}}]), 3422 [Log_2_1, Log_2_2, 3423 Log_3_1, Log_3_2, 3424 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3425 disk_log:close(a), 3426 del(File, 5), 3427 3428 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3429 {size, {60,5}}, {format, external}]), 3430 disk_log:blog(a, Log_1_1), 3431 disk_log:blog(a, Log_1_2), 3432 disk_log:blog(a, Log_2_1), 3433 disk_log:blog(a, Log_2_2), 3434 disk_log:change_size(a, {60, 3}), 3435 ok = disk_log:sync(a), 3436 {ok, Fd1} = file:open(File ++ ".1", [read]), 3437 Log11_12 = Log_1_1 ++ Log_1_2, 3438 {ok,Log11_12} = file:read(Fd1, 200), 3439 ok = file:close(Fd1), 3440 {ok, Fd2} = file:open(File ++ ".2", [read]), 3441 Log21_22 = Log_2_1 ++ Log_2_2, 3442 {ok,Log21_22} = file:read(Fd2, 200), 3443 ok = file:close(Fd2), 3444 disk_log:blog(a, Log_3_1), 3445 disk_log:blog(a, Log_3_2), 3446 disk_log:blog(a, Log_1_2_1), 3447 disk_log:blog(a, Log_1_2_2), 3448 ok = disk_log:sync(a), 3449 {ok, Fd2a} = file:open(File ++ ".2", [read]), 3450 {ok,Log21_22} = file:read(Fd2a, 200), 3451 ok = file:close(Fd2a), 3452 {ok, Fd3a} = file:open(File ++ ".3", [read]), 3453 Log31_32 = Log_3_1 ++ Log_3_2, 3454 {ok,Log31_32} = file:read(Fd3a, 200), 3455 ok = file:close(Fd3a), 3456 {ok, Fd1a} = file:open(File ++ ".1", [read]), 3457 Log121_122 = Log_1_2_1 ++ Log_1_2_2, 3458 {ok,Log121_122} = file:read(Fd1a, 200), 3459 ok = file:close(Fd1a), 3460 3461 disk_log:close(a), 3462 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3463 {size, {60,3}}, {format, external}]), 3464 {ok, Fd2b} = file:open(File ++ ".2", [read]), 3465 {ok,Log21_22} = file:read(Fd2b, 200), 3466 ok = file:close(Fd2b), 3467 {ok, Fd3b} = file:open(File ++ ".3", [read]), 3468 {ok,Log31_32} = file:read(Fd3b, 200), 3469 ok = file:close(Fd3b), 3470 {ok, Fd1b} = file:open(File ++ ".1", [read]), 3471 {ok,Log121_122} = file:read(Fd1b, 200), 3472 ok = file:close(Fd1b), 3473 disk_log:close(a), 3474 del(File, 5), 3475 3476 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,5}}]), 3477 disk_log:log(a, Log_1_1), 3478 disk_log:log(a, Log_1_2), 3479 disk_log:log(a, Log_2_1), 3480 disk_log:log(a, Log_2_2), 3481 disk_log:change_size(a, {60, 3}), 3482 [Log_1_1, Log_1_2, 3483 Log_2_1, Log_2_2] = get_all_terms(a), 3484 disk_log:log(a, Log_3_1), 3485 disk_log:log(a, Log_1_2_1), 3486 [Log_2_1, Log_2_2, 3487 Log_3_1, 3488 Log_1_2_1] = get_all_terms(a), 3489 3490 disk_log:close(a), 3491 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {60,3}}]), 3492 [Log_2_1, Log_2_2, 3493 Log_3_1, 3494 Log_1_2_1] = get_all_terms(a), 3495 disk_log:close(a), 3496 del(File, 5), 3497 3498 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {60, 3}}]), 3499 disk_log:log(a, Log_1_1), 3500 disk_log:log(a, Log_2_1), 3501 disk_log:change_size(a, {100, 5}), 3502 [Log_1_1, 3503 Log_2_1] = get_all_terms(a), 3504 disk_log:log(a, Log_2_2), 3505 disk_log:log(a, Log_3_1), 3506 disk_log:log(a, Log_3_2), 3507 disk_log:log(a, Log_4_1), 3508 disk_log:log(a, Log_4_2), 3509 disk_log:log(a, Log_5_1), 3510 disk_log:log(a, Log_5_2), 3511 disk_log:log(a, Log_1_2_1), 3512 [Log_2_1, Log_2_2, 3513 Log_3_1, Log_3_2, 3514 Log_4_1, Log_4_2, 3515 Log_5_1, Log_5_2, 3516 Log_1_2_1] = get_all_terms(a), 3517 3518 disk_log:close(a), 3519 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100, 5}}]), 3520 [Log_2_1, Log_2_2, 3521 Log_3_1, Log_3_2, 3522 Log_4_1, Log_4_2, 3523 Log_5_1, Log_5_2, 3524 Log_1_2_1] = get_all_terms(a), 3525 disk_log:close(a), 3526 del(File, 5). 3527 3528 3529 3530%% Change size of a wrap log file while logging to a file index 3531%% between the old and the new size. 3532change_size_during(Conf) when is_list(Conf) -> 3533 3534 Log_1_1 = "first log first message", 3535 Log_1_2 = "first log second message", 3536 Log_2_1 = "second log first message", 3537 Log_2_2 = "second log second message", 3538 Log_3_1 = "third log first message", 3539 Log_3_2 = "third log second message", 3540 Log_4_1 = "fourth log first message", 3541 Log_4_2 = "fourth log second message", 3542 Log_5_1 = "fifth log first message", 3543 Log_5_2 = "fifth log second message", 3544 Log_1_2_1 = "first log second round 1", 3545 Log_1_2_2 = "first log second round 2", 3546 Log_2_2_1 = "second log second round 1", 3547 Log_2_2_2 = "second log second round 2", 3548 Log_3_2_1 = "third log second round 1", 3549 Log_3_2_2 = "third log second round 2", 3550 Log_1_3_1 = "first log third round 1", 3551 Log_1_3_2 = "first log third round 2", 3552 3553 Dir = ?privdir(Conf), 3554 File = filename:join(Dir, "a.LOG"), 3555 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,5}}]), 3556 disk_log:log(a, Log_1_1), 3557 disk_log:log(a, Log_1_2), 3558 disk_log:log(a, Log_2_1), 3559 disk_log:log(a, Log_2_2), 3560 disk_log:log(a, Log_3_1), 3561 disk_log:log(a, Log_3_2), 3562 disk_log:log(a, Log_4_1), 3563 disk_log:log(a, Log_4_2), 3564 disk_log:log(a, Log_5_1), 3565 disk_log:log(a, Log_5_2), 3566 disk_log:log(a, Log_1_1), 3567 disk_log:log(a, Log_1_2), 3568 disk_log:log(a, Log_2_1), 3569 disk_log:log(a, Log_2_2), 3570 disk_log:log(a, Log_3_1), 3571 disk_log:log(a, Log_3_2), 3572 disk_log:log(a, Log_4_1), 3573 disk_log:log(a, Log_4_2), 3574 disk_log:change_size(a, {100, 3}), 3575 [Log_5_1, Log_5_2, 3576 Log_1_1, Log_1_2, 3577 Log_2_1, Log_2_2, 3578 Log_3_1, Log_3_2, 3579 Log_4_1, Log_4_2] = get_all_terms(a), 3580 disk_log:log(a, Log_1_2_1), 3581 disk_log:log(a, Log_1_2_2), 3582 [Log_2_1, Log_2_2, 3583 Log_3_1, Log_3_2, 3584 Log_4_1, Log_4_2, 3585 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3586 3587 disk_log:close(a), 3588 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,3}}]), 3589 [Log_2_1, Log_2_2, 3590 Log_3_1, Log_3_2, 3591 Log_4_1, Log_4_2, 3592 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3593 disk_log:log(a, Log_2_2_1), 3594 disk_log:log(a, Log_2_2_2), 3595 disk_log:log(a, Log_3_2_1), 3596 disk_log:log(a, Log_3_2_2), 3597 disk_log:log(a, Log_1_3_1), 3598 disk_log:log(a, Log_1_3_2), 3599 [Log_2_2_1, Log_2_2_2, 3600 Log_3_2_1, Log_3_2_2, 3601 Log_1_3_1, Log_1_3_2] = get_all_terms(a), 3602 disk_log:close(a), 3603 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,3}}]), 3604 [Log_2_2_1, Log_2_2_2, 3605 Log_3_2_1, Log_3_2_2, 3606 Log_1_3_1, Log_1_3_2] = get_all_terms(a), 3607 disk_log:close(a), 3608 del(File, 5), 3609 3610 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,5}}]), 3611 disk_log:log(a, Log_1_1), 3612 disk_log:log(a, Log_1_2), 3613 disk_log:log(a, Log_2_1), 3614 disk_log:log(a, Log_2_2), 3615 disk_log:log(a, Log_3_1), 3616 disk_log:log(a, Log_3_2), 3617 disk_log:log(a, Log_4_1), 3618 disk_log:log(a, Log_4_2), 3619 disk_log:log(a, Log_5_1), 3620 disk_log:log(a, Log_5_2), 3621 disk_log:log(a, Log_1_1), 3622 disk_log:log(a, Log_1_2), 3623 disk_log:log(a, Log_2_1), 3624 disk_log:log(a, Log_2_2), 3625 disk_log:log(a, Log_3_1), 3626 disk_log:log(a, Log_3_2), 3627 disk_log:log(a, Log_4_1), 3628 disk_log:log(a, Log_4_2), 3629 disk_log:log(a, Log_5_1), 3630 disk_log:log(a, Log_5_2), 3631 disk_log:change_size(a, {100, 3}), 3632 [Log_1_1, Log_1_2, 3633 Log_2_1, Log_2_2, 3634 Log_3_1, Log_3_2, 3635 Log_4_1, Log_4_2, 3636 Log_5_1, Log_5_2] = get_all_terms(a), 3637 disk_log:log(a, Log_1_2_1), 3638 disk_log:log(a, Log_1_2_2), 3639 disk_log:log(a, Log_2_2_1), 3640 disk_log:log(a, Log_2_2_2), 3641 disk_log:log(a, Log_3_2_1), 3642 disk_log:log(a, Log_3_2_2), 3643 disk_log:log(a, Log_1_3_1), 3644 disk_log:log(a, Log_1_3_2), 3645 [Log_2_2_1, Log_2_2_2, 3646 Log_3_2_1, Log_3_2_2, 3647 Log_1_3_1, Log_1_3_2] = get_all_terms(a), 3648 3649 disk_log:close(a), 3650 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, {size, {100,3}}]), 3651 [Log_2_2_1, Log_2_2_2, 3652 Log_3_2_1, Log_3_2_2, 3653 Log_1_3_1, Log_1_3_2] = get_all_terms(a), 3654 disk_log:close(a), 3655 del(File, 5). 3656 3657 3658%% Change size of a wrap log file before we have reached (on the 3659%% second round) to the file index corresponding to the new size. 3660change_size_after(Conf) when is_list(Conf) -> 3661 3662 Log_1_1 = "first log first message", 3663 Log_1_2 = "first log second message", 3664 Log_2_1 = "second log first message", 3665 Log_2_2 = "second log second message", 3666 Log_3_1 = "third log first message", 3667 Log_3_2 = "third log second message", 3668 Log_4_1 = "fourth log first message", 3669 Log_4_2 = "fourth log second message", 3670 Log_5_1 = "fifth log first message", 3671 Log_5_2 = "fifth log second message", 3672 Log_1_2_1 = "first log second round 1", 3673 Log_1_2_2 = "first log second round 2", 3674 3675 Dir = ?privdir(Conf), 3676 File = filename:join(Dir, "a.LOG"), 3677 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3678 {size, {100,5}}]), 3679 disk_log:log(a, Log_1_1), 3680 disk_log:log(a, Log_1_2), 3681 disk_log:log(a, Log_2_1), 3682 disk_log:log(a, Log_2_2), 3683 disk_log:log(a, Log_3_1), 3684 disk_log:log(a, Log_3_2), 3685 disk_log:log(a, Log_4_1), 3686 disk_log:log(a, Log_4_2), 3687 disk_log:log(a, Log_5_1), 3688 disk_log:log(a, Log_5_2), 3689 disk_log:log(a, Log_1_1), 3690 disk_log:log(a, Log_1_2), 3691 disk_log:log(a, Log_2_1), 3692 disk_log:log(a, Log_2_2), 3693 disk_log:change_size(a, {100, 3}), 3694 [Log_3_1,Log_3_2, 3695 Log_4_1, Log_4_2, 3696 Log_5_1, Log_5_2, 3697 Log_1_1, Log_1_2, 3698 Log_2_1, Log_2_2] = get_all_terms(a), 3699 disk_log:log(a, Log_3_1), 3700 disk_log:log(a, Log_3_2), 3701 disk_log:log(a, Log_1_2_1), 3702 disk_log:log(a, Log_1_2_2), 3703 [Log_2_1, Log_2_2, 3704 Log_3_1, Log_3_2, 3705 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3706 3707 disk_log:close(a), 3708 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3709 {size, {100,3}}]), 3710 [Log_2_1, Log_2_2, 3711 Log_3_1, Log_3_2, 3712 Log_1_2_1, Log_1_2_2] = get_all_terms(a), 3713 disk_log:close(a), 3714 del(File, 5), 3715 3716 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3717 {size, {100,5}}]), 3718 disk_log:log(a, Log_1_1), 3719 disk_log:log(a, Log_1_2), 3720 disk_log:log(a, Log_2_1), 3721 disk_log:log(a, Log_2_2), 3722 disk_log:log(a, Log_3_1), 3723 disk_log:log(a, Log_3_2), 3724 disk_log:log(a, Log_4_1), 3725 disk_log:log(a, Log_4_2), 3726 disk_log:log(a, Log_5_1), 3727 disk_log:log(a, Log_5_2), 3728 disk_log:log(a, Log_1_1), 3729 disk_log:log(a, Log_1_2), 3730 disk_log:log(a, Log_2_1), 3731 disk_log:log(a, Log_2_2), 3732 disk_log:change_size(a, {60, 3}), 3733 [Log_3_1,Log_3_2, 3734 Log_4_1, Log_4_2, 3735 Log_5_1, Log_5_2, 3736 Log_1_1, Log_1_2, 3737 Log_2_1, Log_2_2] = get_all_terms(a), 3738 disk_log:log(a, Log_3_1), 3739 disk_log:log(a, Log_1_2_1), 3740 [Log_2_1, Log_2_2, 3741 Log_3_1, 3742 Log_1_2_1] = get_all_terms(a), 3743 3744 disk_log:close(a), 3745 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3746 {size, {60,3}}]), 3747 [Log_2_1, Log_2_2, 3748 Log_3_1, 3749 Log_1_2_1] = get_all_terms(a), 3750 disk_log:close(a), 3751 del(File, 5). 3752 3753 3754 3755%% Open an existing wrap log without size option . 3756default_size(Conf) when is_list(Conf) -> 3757 Dir = ?privdir(Conf), 3758 File = filename:join(Dir, "a.LOG"), 3759 {error, {badarg, size}} = disk_log:open([{name,a}, {file, File}, 3760 {type, wrap}]), 3761 3762 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}, 3763 {size, {100,5}}]), 3764 disk_log:close(a), 3765 3766 {ok, a} = disk_log:open([{name,a}, {file, File}, {type, wrap}]), 3767 {100, 5} = disk_log_1:read_size_file(File), 3768 ok = disk_log:close(a), 3769 del(File, 5). 3770 3771%% Testing change_size/2 a bit more... 3772change_size2(Conf) when is_list(Conf) -> 3773 3774 Dir = ?privdir(Conf), 3775 File = filename:join(Dir, "n.LOG"), 3776 No = 4, 3777 del(File, No), % cleanup 3778 3779 %% External halt. 3780 {ok, n} = disk_log:open([{name, n}, {file, File}, {size, 100000}, 3781 {format, external}, {type, halt}]), 3782 B = mk_bytes(60), % 56 actually... 3783 ok = disk_log:blog_terms(n, [B,list_to_binary(B),B]), 3784 Error1 = {error, {new_size_too_small,n,168}} = 3785 disk_log:change_size(n, 167), 3786 "The current size" ++ _ = format_error(Error1), 3787 ok = disk_log:change_size(n, infinity), 3788 ok = disk_log:change_size(n, 168), 3789 ok = disk_log:close(n), 3790 file:delete(File), % cleanup 3791 3792 %% External wrap. 3793 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3794 {size, {100,No}}, {notify, true}, 3795 {format, external}]), 3796 BB = mk_bytes(160), 3797 ok = disk_log:blog_terms(n, [BB, BB, BB, BB]), % create all files 3798 %% Used to be one message, but now one per wrapped file. 3799 rec(3, {disk_log, node(), n, {wrap, 0}}), 3800 ok = disk_log:blog_terms(n, [BB, BB]), 3801 %% Used to be one message, but now one per wrapped file. 3802 rec(2, {disk_log, node(), n, {wrap, 1}}), 3803 ok = disk_log:change_size(n, {100, 2}), 3804 ok = disk_log:change_size(n, {100, 2}), 3805 {100, 2} = sz(n), 3806 ok = disk_log:balog_terms(n, [BB, BB]), 3807 ok = disk_log:balog_terms(n, [BB]), 3808 ok = disk_log:blog_terms(n, [BB]), 3809 %% Used to be one message, but now one per wrapped file. 3810 rec(4, {disk_log, node(), n, {wrap, 1}}), 3811 ok = disk_log:change_size(n, {100, 4}), 3812 ok = disk_log:close(n), 3813 del(File, No), 3814 3815 %% Internal wrap. 3816 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3817 {size, {100,No}}, {notify, true}, 3818 {format, internal}]), 3819 ok = disk_log:blog_terms(n, [BB, BB, BB, BB]), % create all files 3820 %% Used to be one message, but now one per wrapped file. 3821 rec(3, {disk_log, node(), n, {wrap, 0}}), 3822 ok = disk_log:blog_terms(n, [BB, BB]), 3823 %% Used to be one message, but now one per wrapped file. 3824 rec(2, {disk_log, node(), n, {wrap, 1}}), 3825 ok = disk_log:change_size(n, {100, 2}), 3826 {100, 2} = sz(n), 3827 ok = disk_log:blog_terms(n, [BB, BB, BB, BB]), 3828 %% Used to be one message, but now one per wrapped file. 3829 rec(4, {disk_log, node(), n, {wrap, 1}}), 3830 ok = disk_log:close(n), 3831 del(File, No). 3832 3833%% OTP-3484: truncating index file. 3834change_size_truncate(Conf) when is_list(Conf) -> 3835 3836 Dir = ?privdir(Conf), 3837 File = filename:join(Dir, "bert.LOG"), 3838 No = 3, 3839 B = mk_bytes(60), 3840 3841 %% The problem here is truncation of the index file. One cannot easily 3842 %% check that the index file is correctly updated, but print_index_file() 3843 %% can be used to follow the progress more closely. 3844 3845 %% Part 1. 3846 %% Change the size immediately after creating the log, while there 3847 %% are no log files. This used to write stuff a negative offset 3848 %% from the beginning of the file. 3849 del(File, No+1), 3850 {ok, bert} = disk_log:open([{name,bert}, {type,wrap}, {file, File}, 3851 {notify, true}, {size,{1000,255}}]), 3852 ok = disk_log:change_size(bert,{100,No}), 3853 ok = disk_log:blog(bert, B), 3854 ok = disk_log:blog(bert, B), 3855 rec(1, {disk_log, node(), bert, {wrap, 0}}), 3856 ok = disk_log:blog(bert, B), 3857 rec(1, {disk_log, node(), bert, {wrap, 0}}), 3858 3 = curf(bert), 3859 ok = disk_log:blog(bert, B), 3860 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3861 1 = curf(bert), 3862 ok = disk_log:blog(bert, B), 3863 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3864 ok = disk_log:blog(bert, B), 3865 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3866 3867 ok = disk_log:blog(bert, B), 3868 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3869 ok = disk_log:blog(bert, B), 3870 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3871 ok = disk_log:blog(bert, B), 3872 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3873 3874 %% Three items expected. 3875 %% disk_log_1:print_index_file("bert.LOG.idx"), 3876 3 = curf(bert), 3877 ok = disk_log:change_size(bert,{100,1}), 3878 ok = disk_log:blog(bert, B), 3879 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3880 %% Three items expected. 3881 %% disk_log_1:print_index_file("bert.LOG.idx"), 3882 ok = disk_log:blog(bert, B), 3883 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3884 ok = disk_log:blog(bert, B), 3885 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3886 %% One item expected. 3887 %% disk_log_1:print_index_file("bert.LOG.idx"), 3888 3889 ok = disk_log:blog(bert, B), 3890 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3891 ok = disk_log:close(bert), 3892 del(File, No), 3893 3894 %% Part 2. 3895 %% Change the size twice, the second time while the the effects of 3896 %% the first changed have not yet been handled. Finally close before 3897 %% the index file has been truncated. 3898 3899 del(File, No), 3900 {ok, bert} = disk_log:open([{name,bert}, {type,wrap}, {file, File}, 3901 {notify, true}, {size,{100,No}}]), 3902 ok = disk_log:blog(bert, B), 3903 ok = disk_log:blog(bert, B), 3904 rec(1, {disk_log, node(), bert, {wrap, 0}}), 3905 ok = disk_log:blog(bert, B), 3906 rec(1, {disk_log, node(), bert, {wrap, 0}}), 3907 3908 3 = curf(bert), 3909 ok = disk_log:change_size(bert,{100,No-1}), 3910 3911 ok = disk_log:blog(bert, B), 3912 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3913 3914 1 = curf(bert), 3915 ok = disk_log:change_size(bert,{100,No+1}), 3916 3917 %% Three items expected. 3918 %% disk_log_1:print_index_file("bert.LOG.idx"), 3919 3920 ok = disk_log:blog(bert, B), 3921 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3922 3923 %% Three items expected. 3924 %% disk_log_1:print_index_file("bert.LOG.idx"), 3925 3926 2 = curf(bert), 3927 ok = disk_log:change_size(bert,{100,1}), 3928 3929 %% Three items expected. 3930 %% disk_log_1:print_index_file("bert.LOG.idx"), 3931 3932 ok = disk_log:close(bert), 3933 3934 %% State: .siz is 1, current file is 2, index file size is 3... 3935 3936 {ok, bert} = disk_log:open([{name,bert}, {file, File}, 3937 {type,wrap}, {notify, true}]), 3938 3939 %% Three items expected. 3940 %% disk_log_1:print_index_file("bert.LOG.idx"), 3941 3942 2 = curf(bert), 3943 ok = disk_log:blog(bert, B), 3944 rec(1, {disk_log, node(), bert, {wrap, 1}}), 3945 ok = disk_log:close(bert), 3946 3947 {ok, bert} = disk_log:open([{name,bert}, {file, File}, 3948 {type,wrap}, {notify, true}]), 3949 3950 %% Two items expected. 3951 %% disk_log_1:print_index_file("bert.LOG.idx"), 3952 3953 1 = curf(bert), 3954 ok = disk_log:blog(bert, B), 3955 %% Expect {wrap 0}. Nothing lost now, last wrap notification 3956 %% reported one lost item. 3957 rec(1, {disk_log, node(), bert, {wrap, 0}}), 3958 3959 %% One item expected. 3960 %% disk_log_1:print_index_file("bert.LOG.idx"), 3961 ok = disk_log:close(bert), 3962 3963 del(File, No), 3964 ok. 3965 3966%% Change notify and head. 3967change_attribute(Conf) when is_list(Conf) -> 3968 3969 Dir = ?privdir(Conf), 3970 File = filename:join(Dir, "n.LOG"), 3971 No = 4, 3972 del(File, No), % cleanup 3973 B = mk_bytes(60), 3974 3975 Q = qlen(), 3976 3977 %% test change_notify 3978 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 3979 {size, {100,No}}]), 3980 {ok, n} = disk_log:open([{name, n}]), % ignored... 3981 ok = disk_log:log_terms(n, [B,B]), 3982 {error, {badarg, notify}} = disk_log:change_notify(n, self(), wrong), 3983 ok = disk_log:change_notify(n, self(), false), 3984 ok = disk_log:change_notify(n, self(), true), 3985 Error1 = {error, {not_owner, _}} = 3986 disk_log:change_notify(n, none, true), 3987 "The pid" ++ _ = format_error(Error1), 3988 2 = no_written_items(n), 3989 0 = users(n), 3990 Parent = self(), 3991 Pid = spawn(fun() -> disk_log:close(n), Parent ! {self(),done} end), 3992 receive {Pid, done} -> ok end, 3993 0 = users(n), 3994 1 = length(owners(n)), 3995 3996 %% test change_header 3997 {error, {badarg, head}} = disk_log:change_header(n, none), 3998 {error, {badarg, head}} = 3999 disk_log:change_header(n, {head_func, {1,2,3}}), 4000 ok = disk_log:change_header(n, {head, header}), 4001 ok = disk_log:log(n, B), 4002 rec(1, {disk_log, node(), n, {wrap, 0}}), 4003 4 = no_written_items(n), 4004 ok = disk_log:change_header(n, {head, none}), 4005 ok = disk_log:log(n, B), 4006 rec(1, {disk_log, node(), n, {wrap, 0}}), 4007 5 = no_written_items(n), 4008 ok = disk_log:change_header(n, 4009 {head_func, {?MODULE, head_fun, [{ok,header}]}}), 4010 ok = disk_log:log(n, B), 4011 rec(1, {disk_log, node(), n, {wrap, 1}}), 4012 7 = no_written_items(n), 4013 ok = disk_log:close(n), 4014 {error, no_such_log} = disk_log:close(n), 4015 del(File, No), 4016 file:delete(File), % cleanup 4017 {ok, n} = disk_log:open([{name, n}, {file, File}, {format, external}, 4018 {type, halt}]), 4019 {error, {badarg, head}} = disk_log:change_header(n, {head, header}), 4020 ok = disk_log:change_header(n, {head, "header"}), 4021 ok = disk_log:close(n), 4022 file:delete(File), 4023 4024 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 4025 {size, {100,No}}]), 4026 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 4027 {size, {100,No}}]), 4028 ok = disk_log:change_notify(n, self(), true), 4029 ok = disk_log:change_header(n, {head, tjolahopp}), 4030 {ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap}, 4031 {size, {100,No}}, {notify, true}]), 4032 ok = disk_log:close(n), 4033 {error, no_such_log} = disk_log:info(n), 4034 Q = qlen(), 4035 del(File, No). 4036 4037 4038%% Open a distributed log. 4039dist_open(Conf) when is_list(Conf) -> 4040 PrivDir = ?privdir(Conf), 4041 true = is_alive(), 4042 4043 Q = qlen(), 4044 File = filename:join(PrivDir, "n.LOG"), 4045 File1 = filename:join(PrivDir, "n1.LOG"), 4046 No = 3, 4047 file:delete(File), 4048 del(File, No), % cleanup 4049 del(File1, No), % cleanup 4050 B = mk_bytes(60), 4051 4052 PA = filename:dirname(code:which(?MODULE)), 4053 {ok, Node} = start_node(disk_log, "-pa " ++ PA), 4054 wait_for_ready_net(), 4055 4056 %% open non-distributed on this node: 4057 {ok,n} = disk_log:open([{name, n}, {file, File}, {type, halt}, 4058 {distributed, []}]), 4059 4060 Error1 = {error, {halt_log, n}} = disk_log:inc_wrap_file(n), 4061 "The halt log" ++ _ = format_error(Error1), 4062 ok = disk_log:lclose(n), 4063 file:delete(File), 4064 4065 %% open distributed on this node: 4066 {[_],[]} = disk_log:open([{name, n}, {file, File}, {type, halt}, 4067 {distributed, [node()]}]), 4068 %% the error message is ignored: 4069 ok = disk_log:inc_wrap_file(n), 4070 ok = disk_log:close(n), 4071 file:delete(File), 4072 4073 %% open a wrap log on this node, write something on this node 4074 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4075 {type, wrap}, {size, {50, No}}, 4076 {distributed, [node()]}]), 4077 ok = disk_log:log(n, B), 4078 ok = disk_log:close(n), 4079 4080 %% open a wrap log on this node and aother node, write something 4081 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4082 {type, wrap}, {size, {50, No}}, 4083 {distributed, [node()]}]), 4084 {[_],[]} = disk_log:open([{name, n}, {file, File1}, 4085 {type, wrap}, {size, {50, No}}, 4086 {distributed, [Node]}]), 4087 ok = disk_log:log(n, B), 4088 ok = rpc:call(Node, disk_log, log, [n, B]), 4089 ok = disk_log:close(n), 4090 del(File, No), 4091 del(File1, No), 4092 file:delete(File), 4093 4094 %% open a wrap log on this node and another node, use lclose 4095 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4096 {type, wrap}, {size, {50, No}}, 4097 {distributed, [node()]}]), 4098 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4099 {type, wrap}, {size, {50, No}}, 4100 {distributed, [node()]}, 4101 {linkto,none}]), 4102 {[_],[]} = disk_log:open([{name, n}, {file, File1}, 4103 {type, wrap}, {size, {50, No}}, 4104 {distributed, [Node]}]), 4105 [_, _] = distributed(n), 4106 ok = disk_log:lclose(n, Node), 4107 [_] = distributed(n), 4108 ok = disk_log:lclose(n), 4109 ok = disk_log:lclose(n), 4110 {error, no_such_log} = disk_log:info(n), 4111 del(File, No), 4112 del(File1, No), 4113 file:delete(File), 4114 4115 %% open an invalid log file, and see how error are handled 4116 First = "n.LOG.1", 4117 make_file(PrivDir, First, 8), 4118 4119 {[], [_,_]} = disk_log:open([{name, n}, {file, File}, 4120 {type, wrap}, {size, {50, No}}, 4121 {distributed, [Node,node()]}]), 4122 del(File, No), 4123 file:delete(File), 4124 4125 %% open a wrap on one other node (not on this node) 4126 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4127 {type, wrap}, {size, {50, No}}, 4128 {distributed, [Node]}]), 4129 ok = rpc:call(Node, disk_log, log, [n, B]), 4130 {error, no_such_log} = disk_log:lclose(n), 4131 ok = disk_log:close(n), 4132 4133 Q = qlen(), 4134 4135 {error, no_such_log} = disk_log:info(n), 4136 del(File, No), 4137 file:delete(File), 4138 stop_node(Node), 4139 ok. 4140 4141%% Open a log distributed and not distributed. 4142dist_error_open(Conf) when is_list(Conf) -> 4143 PrivDir = ?privdir(Conf), 4144 true = is_alive(), 4145 4146 Q = qlen(), 4147 File = filename:join(PrivDir, "bert.LOG"), 4148 File1 = filename:join(PrivDir, "bert1.LOG"), 4149 No = 3, 4150 file:delete(File), 4151 del(File, No), % cleanup 4152 del(File1, No), % cleanup 4153 4154 PA = filename:dirname(code:which(?MODULE)), 4155 {ok, Node} = start_node(disk_log, "-pa " ++ PA), 4156 wait_for_ready_net(), 4157 4158 %% open non-distributed on this node: 4159 {ok,n} = disk_log:open([{name, n}, {file, File}, 4160 {type, wrap}, {size, {50, No}}]), 4161 4162 %% trying to open distributed on this node (error): 4163 {[],[Error1={ENode,{error,{node_already_open,n}}}]} = 4164 disk_log:open([{name, n}, {file, File}, 4165 {type, wrap}, {size, {50, No}}, 4166 {distributed, [node()]}]), 4167 true = 4168 lists:prefix(lists:flatten(io_lib:format("~p: The distribution", 4169 [ENode])), 4170 format_error(Error1)), 4171 ok = disk_log:lclose(n), 4172 4173 %% open distributed on this node: 4174 {[_],[]} = disk_log:open([{name, n}, {file, File}, 4175 {type, wrap}, {size, {50, No}}, 4176 {distributed, [node()]}]), 4177 4178 %% trying to open non-distributed on this node (error): 4179 {_,{node_already_open,n}} = 4180 disk_log:open([{name, n}, {file, File}, 4181 {type, wrap}, {size, {50, No}}]), 4182 4183 ok = disk_log:close(n), 4184 Q = qlen(), 4185 4186 del(File, No), 4187 del(File1, No), 4188 file:delete(File), 4189 stop_node(Node), 4190 ok. 4191 4192%% Notification from other node. 4193dist_notify(Conf) when is_list(Conf) -> 4194 PrivDir = ?privdir(Conf), 4195 true = is_alive(), 4196 4197 File = filename:join(PrivDir, "bert.LOG"), 4198 File1 = filename:join(PrivDir, "bert1.LOG"), 4199 No = 3, 4200 B = mk_bytes(60), 4201 file:delete(File), 4202 file:delete(File1), 4203 del(File, No), % cleanup 4204 del(File1, No), 4205 4206 PA = filename:dirname(code:which(?MODULE)), 4207 {ok, Node} = start_node(disk_log, "-pa " ++ PA), 4208 wait_for_ready_net(), 4209 4210 %% opening distributed on this node: 4211 {[_],[]} = disk_log:open([{name, n}, {file, File}, {notify, false}, 4212 {type, wrap}, {size, {50, No}}, 4213 {distributed, [node()]}]), 4214 4215 %% opening distributed on other node: 4216 {[_],[]} = disk_log:open([{name, n}, {file, File1}, 4217 {notify, true}, {linkto, self()}, 4218 {type, wrap}, {size, {50, No}}, 4219 {distributed, [Node]}]), 4220 disk_log:alog(n, B), 4221 disk_log:alog(n, B), 4222 ok = disk_log:sync(n), 4223 rec(1, {disk_log, Node, n, {wrap, 0}}), 4224 ok = disk_log:close(n), 4225 4226 del(File, No), 4227 del(File1, No), 4228 file:delete(File), 4229 stop_node(Node), 4230 ok. 4231 4232%% Terminating nodes with distributed logs. 4233dist_terminate(Conf) when is_list(Conf) -> 4234 Dir = ?privdir(Conf), 4235 true = is_alive(), 4236 4237 File = filename:join(Dir, "n.LOG"), 4238 File1 = filename:join(Dir, "n1.LOG"), 4239 No = 1, 4240 del(File, No), % cleanup 4241 del(File1, No), % cleanup 4242 4243 PA = filename:dirname(code:which(?MODULE)), 4244 {ok, Node} = start_node(disk_log, "-pa " ++ PA), 4245 wait_for_ready_net(), 4246 4247 %% Distributed versions of two of the situations in close_block(/1. 4248 4249 %% One of two owners terminates. 4250 Pid1 = spawn_link(?MODULE, lserv, [n]), 4251 Pid2 = spawn_link(?MODULE, lserv, [n]), 4252 {[{_, {ok, n}}], []} = sync_do(Pid1, {dist_open, File, node()}), 4253 {[{_, {ok, n}}], []} = sync_do(Pid2, {dist_open, File1, Node}), 4254 [_] = sync_do(Pid1, owners), 4255 [_] = sync_do(Pid2, owners), 4256 0 = sync_do(Pid1, users), 4257 0 = sync_do(Pid2, users), 4258 sync_do(Pid1, terminate), 4259 [_] = sync_do(Pid2, owners), 4260 0 = sync_do(Pid2, users), 4261 sync_do(Pid2, terminate), 4262 {error, no_such_log} = disk_log:info(n), 4263 4264 %% Users terminate (no link...). 4265 Pid3 = spawn_link(?MODULE, lserv, [n]), 4266 Pid4 = spawn_link(?MODULE, lserv, [n]), 4267 {[{_, {ok, n}}], []} = 4268 sync_do(Pid3, {dist_open, File, none, node()}), 4269 {[{_, {ok, n}}], []} = 4270 sync_do(Pid4, {dist_open, File1, none, Node}), 4271 [] = sync_do(Pid3, owners), 4272 [] = sync_do(Pid4, owners), 4273 1 = sync_do(Pid3, users), 4274 1 = sync_do(Pid4, users), 4275 sync_do(Pid3, terminate), 4276 [] = sync_do(Pid4, owners), 4277 1 = sync_do(Pid4, users), 4278 sync_do(Pid4, terminate), 4279 ok = disk_log:close(n), % closing all nodes 4280 {error, no_such_log} = disk_log:info(n), 4281 4282 del(File, No), 4283 del(File1, No), 4284 stop_node(Node), 4285 ok. 4286 4287%% Accessible logs on nodes. 4288dist_accessible(Conf) when is_list(Conf) -> 4289 PrivDir = ?privdir(Conf), 4290 4291 true = is_alive(), 4292 4293 F1 = filename:join(PrivDir, "a.LOG"), 4294 file:delete(F1), 4295 F2 = filename:join(PrivDir, "b.LOG"), 4296 file:delete(F2), 4297 F3 = filename:join(PrivDir, "c.LOG"), 4298 file:delete(F3), 4299 F4 = filename:join(PrivDir, "d.LOG"), 4300 file:delete(F1), 4301 F5 = filename:join(PrivDir, "e.LOG"), 4302 file:delete(F2), 4303 F6 = filename:join(PrivDir, "f.LOG"), 4304 file:delete(F3), 4305 4306 {[],[]} = disk_log:accessible_logs(), 4307 {ok, a} = disk_log:open([{name, a}, {type, halt}, {file, F1}]), 4308 {[a],[]} = disk_log:accessible_logs(), 4309 {ok, b} = disk_log:open([{name, b}, {type, halt}, {file, F2}]), 4310 {[a,b],[]} = disk_log:accessible_logs(), 4311 {ok, c} = disk_log:open([{name, c}, {type, halt}, {file, F3}]), 4312 {[a,b,c],[]} = disk_log:accessible_logs(), 4313 4314 PA = filename:dirname(code:which(?MODULE)), 4315 {ok, Node} = start_node(disk_log, "-pa " ++ PA), 4316 wait_for_ready_net(), 4317 4318 {[_],[]} = disk_log:open([{name, a}, {file, F4}, {type, halt}, 4319 {distributed, [Node]}]), 4320 {[a,b,c],[]} = disk_log:accessible_logs(), 4321 {[],[a]} = rpc:call(Node, disk_log, accessible_logs, []), 4322 {[_],[]} = disk_log:open([{name, b}, {file, F5}, {type, halt}, 4323 {distributed, [Node]}]), 4324 {[],[a,b]} = rpc:call(Node, disk_log, accessible_logs, []), 4325 {[_],[]} = disk_log:open([{name, c}, {file, F6}, {type, halt}, 4326 {distributed, [Node]}]), 4327 {[],[a,b,c]} = rpc:call(Node, disk_log, accessible_logs, []), 4328 {[a,b,c],[]} = disk_log:accessible_logs(), 4329 ok = disk_log:close(a), 4330 {[b,c],[a]} = disk_log:accessible_logs(), 4331 ok = disk_log:close(b), 4332 {[c],[a,b]} = disk_log:accessible_logs(), 4333 ok = disk_log:close(b), 4334 {[c],[a]} = disk_log:accessible_logs(), 4335 {[],[a,c]} = rpc:call(Node, disk_log, accessible_logs, []), 4336 ok = disk_log:close(c), 4337 {[],[a,c]} = disk_log:accessible_logs(), 4338 ok = disk_log:close(c), 4339 {[],[a]} = disk_log:accessible_logs(), 4340 {[],[a]} = rpc:call(Node, disk_log, accessible_logs, []), 4341 ok = disk_log:close(a), 4342 {[],[]} = disk_log:accessible_logs(), 4343 {[],[]} = rpc:call(Node, disk_log, accessible_logs, []), 4344 4345 file:delete(F1), 4346 file:delete(F2), 4347 file:delete(F3), 4348 file:delete(F4), 4349 file:delete(F5), 4350 file:delete(F6), 4351 4352 stop_node(Node), 4353 ok. 4354 4355%% OTP-4405. Deadlock between two nodes could happen. 4356dist_deadlock(Conf) when is_list(Conf) -> 4357 PrivDir = ?privdir(Conf), 4358 4359 true = is_alive(), 4360 4361 F1 = filename:join(PrivDir, "a.LOG"), 4362 file:delete(F1), 4363 F2 = filename:join(PrivDir, "b.LOG"), 4364 file:delete(F2), 4365 4366 PA = filename:dirname(code:which(?MODULE)), 4367 {ok, Node1} = start_node(disk_log_node1, "-pa " ++ PA), 4368 {ok, Node2} = start_node(disk_log_node2, "-pa " ++ PA), 4369 wait_for_ready_net(), 4370 4371 Self = self(), 4372 Fun1 = fun() -> dist_dl(Node2, a, F1, Self) end, 4373 Fun2 = fun() -> dist_dl(Node1, b, F2, Self) end, 4374 P1 = spawn(Node1, Fun1), 4375 P2 = spawn(Node2, Fun2), 4376 receive {P1, a} -> ok end, 4377 receive {P2, b} -> ok end, 4378 4379 stop_node(Node1), 4380 stop_node(Node2), 4381 4382 file:delete(F1), 4383 file:delete(F2), 4384 ok. 4385 4386dist_dl(Node, Name, File, Pid) -> 4387 {[{Node,{ok,Log}}], []} = 4388 disk_log:open([{name,Name},{file,File},{distributed,[Node]}]), 4389 timer:sleep(50), % give the nodes chance to exchange pg2 information 4390 ok = disk_log:close(Log), 4391 Pid ! {self(), Name}, 4392 ok. 4393 4394%% OTP-4480. Opening several logs simultaneously. 4395dist_open2(Conf) when is_list(Conf) -> 4396 true = is_alive(), 4397 {ok, _Pg2} = pg2:start(), 4398 4399 dist_open2_1(Conf, 0), 4400 dist_open2_1(Conf, 100), 4401 4402 dist_open2_2(Conf, 0), 4403 dist_open2_2(Conf, 100), 4404 4405 PrivDir = ?privdir(Conf), 4406 Log = n, 4407 4408 %% Open a log three times (very fast). Two of the opening 4409 %% processes will be put on hold (pending). The first one failes 4410 %% to open the log. The second one succeeds, and the third one is 4411 %% attached. 4412 P0 = pps(), 4413 File0 = "n.LOG", 4414 File = filename:join(PrivDir, File0), 4415 make_file(PrivDir, File0, 8), 4416 4417 Parent = self(), 4418 F1 = fun() -> R = disk_log:open([{name, Log}, {file, File}, 4419 {type, halt}, {format,internal}, 4420 {distributed, [node()]}]), 4421 Parent ! {self(), R} 4422 end, 4423 F2 = fun() -> R = disk_log:open([{name, Log}, {file, File}, 4424 {type, halt}, {format,external}, 4425 {distributed, [node()]}]), 4426 Parent ! {self(), R}, 4427 timer:sleep(300) 4428 end, 4429 Pid1 = spawn(F1), 4430 timer:sleep(10), 4431 Pid2 = spawn(F2), 4432 Pid3 = spawn(F2), 4433 4434 receive {Pid1,R1} -> {[],[_]} = R1 end, 4435 receive {Pid2,R2} -> {[_],[]} = R2 end, 4436 receive {Pid3,R3} -> {[_],[]} = R3 end, 4437 4438 timer:sleep(500), 4439 file:delete(File), 4440 check_pps(P0), 4441 4442 %% This time the first process has a naughty head_func. This test 4443 %% does not add very much. Perhaps it should be removed. However, 4444 %% a head_func like this is why it's necessary to have an separate 4445 %% process calling disk_log:internal_open: the server cannot wait 4446 %% for the reply, but the call must be monitored, and this is what 4447 %% is accomplished by having a proxy process. 4448 F3 = fun() -> 4449 R = disk_log:open([{name,Log},{file,File}, 4450 {format,internal}, 4451 {head_func,{?MODULE,head_exit,[]}}, 4452 {type,halt}, {linkto,none}]), 4453 Parent ! {self(), R} 4454 end, 4455 F4 = fun() -> 4456 R = disk_log:open([{name,Log},{file,File}, 4457 {format,internal}, 4458 {type,halt}]), 4459 Parent ! {self(), R} 4460 end, 4461 Pid4 = spawn(F3), 4462 timer:sleep(10), 4463 Pid5 = spawn(F4), 4464 Pid6 = spawn(F4), 4465 %% The timing is crucial here. 4466 R = case receive {Pid4,R4} -> R4 end of 4467 {error, no_such_log} -> 4468 R5 = receive {Pid5, R5a} -> R5a end, 4469 R6 = receive {Pid6, R6a} -> R6a end, 4470 case {R5, R6} of 4471 {{repaired, _, _, _}, {ok, Log}} -> ok; 4472 {{ok, Log}, {repaired, _, _, _}} -> ok; 4473 _ -> test_server_fail({bad_replies, R5, R6}) 4474 end, 4475 ok; 4476 {ok, Log} -> % uninteresting case 4477 receive {Pid5,_R5} -> ok end, 4478 receive {Pid6,_R6} -> ok end, 4479 {comment, 4480 "Timing dependent test did not check anything."} 4481 end, 4482 4483 timer:sleep(100), 4484 {error, no_such_log} = disk_log:close(Log), 4485 file:delete(File), 4486 check_pps(P0), 4487 4488 No = 2, 4489 Log2 = n2, 4490 File2 = filename:join(PrivDir, "b.LOG"), 4491 file:delete(File2), 4492 del(File, No), 4493 4494 %% If a client takes a long time when writing the header, other 4495 %% processes should be able to attach to other log without having to 4496 %% wait. 4497 4498 {ok,Log} = 4499 disk_log:open([{name,Log},{file,File},{type,wrap},{size,{100,No}}]), 4500 Pid = spawn(fun() -> 4501 receive {HeadPid, start} -> ok end, 4502 {ok,Log2} = disk_log:open([{name,Log2},{file,File2}, 4503 {type,halt}]), 4504 HeadPid ! {self(), done} 4505 end), 4506 HeadFunc = {?MODULE, slow_header, [Pid]}, 4507 ok = disk_log:change_header(Log, {head_func, HeadFunc}), 4508 ok = disk_log:inc_wrap_file(Log), % header is written 4509 4510 timer:sleep(100), 4511 ok = disk_log:close(Log), 4512 4513 file:delete(File2), 4514 del(File, No), 4515 check_pps(P0), 4516 4517 R. 4518 4519dist_open2_1(Conf, Delay) -> 4520 Dir = ?privdir(Conf), 4521 File = filename:join(Dir, "n.LOG"), 4522 Log = n, 4523 4524 A0 = [{name,Log},{file,File},{type,halt}], 4525 create_opened_log(File, A0), 4526 P0 = pps(), 4527 4528 Log2 = log2, 4529 File2 = "log2.LOG", 4530 file:delete(File2), 4531 {ok,Log2} = disk_log:open([{name,Log2},{file,File2},{type,halt}]), 4532 4533 Parent = self(), 4534 F = fun() -> 4535 R = disk_log:open(A0), 4536 timer:sleep(Delay), 4537 Parent ! {self(), R} 4538 end, 4539 Pid1 = spawn(F), 4540 timer:sleep(10), 4541 Pid2 = spawn(F), 4542 Pid3 = spawn(F), 4543 {error, no_such_log} = disk_log:log(Log, term), % is repairing now 4544 0 = qlen(), 4545 4546 %% The file is already open, so this will not take long. 4547 {ok,Log2} = disk_log:open([{name,Log2},{file,File2},{type,halt}]), 4548 0 = qlen(), % still repairing 4549 ok = disk_log:close(Log2), 4550 {error, no_such_log} = disk_log:close(Log2), 4551 file:delete(File2), 4552 4553 receive {Pid1,R1} -> {repaired,_,_,_} = R1 end, 4554 receive {Pid2,R2} -> {ok,_} = R2 end, 4555 receive {Pid3,R3} -> {ok,_} = R3 end, 4556 timer:sleep(500), 4557 {error, no_such_log} = disk_log:info(Log), 4558 4559 file:delete(File), 4560 check_pps(P0), 4561 4562 ok. 4563 4564dist_open2_2(Conf, Delay) -> 4565 Dir = ?privdir(Conf), 4566 File = filename:join(Dir, "n.LOG"), 4567 Log = n, 4568 4569 PA = filename:dirname(code:which(?MODULE)), 4570 {ok, Node1} = start_node(disk_log_node2, "-pa " ++ PA), 4571 wait_for_ready_net(), 4572 P0 = pps(), 4573 4574 A0 = [{name,Log},{file,File},{type,halt}], 4575 create_opened_log(File, A0), 4576 4577 Log2 = log2, 4578 File2 = "log2.LOG", 4579 file:delete(File2), 4580 {[{Node1,{ok,Log2}}],[]} = 4581 disk_log:open([{name,Log2},{file,File2},{type,halt}, 4582 {distributed,[Node1]}]), 4583 4584 Parent = self(), 4585 F = fun() -> 4586 %% It would be nice to slow down the repair. head_func 4587 %% cannot be used since it is not called when repairing. 4588 R = disk_log:open([{distributed,[Node1]} | A0]), 4589 timer:sleep(Delay), 4590 Parent ! {self(), R} 4591 end, 4592 %% And {priority, ...} probably has no effect either. 4593 Pid1 = spawn_opt(F, [{priority, low}]), 4594 %% timer:sleep(1), % no guarantee that Pid1 will return {repaired, ...} 4595 Pid2 = spawn_opt(F, [{priority, low}]), 4596 {error, no_such_log} = 4597 disk_log:log(Log, term), % maybe repairing now 4598 0 = qlen(), 4599 4600 %% The file is already open, so this will not take long. 4601 {[{Node1,{ok,Log2}}],[]} = 4602 disk_log:open([{name,Log2},{file,File2},{type,halt}, 4603 {distributed,[Node1]}]), 4604 0 = qlen(), % probably still repairing 4605 ok = disk_log:close(Log2), 4606 file:delete(File2), 4607 4608 receive {Pid1,R1} -> R1 end, 4609 receive {Pid2,R2} -> R2 end, 4610 case {R1, R2} of 4611 {{[{Node1,{repaired,_,_,_}}],[]}, 4612 {[{Node1,{ok,Log}}],[]}} -> ok; 4613 {{[{Node1,{ok,Log}}],[]}, 4614 {[{Node1,{repaired,_,_,_}}],[]}} -> ok 4615 end, 4616 4617 check_pps(P0), 4618 stop_node(Node1), 4619 file:delete(File), 4620 ok. 4621 4622head_exit() -> 4623 process_flag(trap_exit, false), % Don't do like this! 4624 spawn_link(fun() -> exit(helfel) end), 4625 {ok,"123"}. 4626 4627slow_header(Pid) -> 4628 Pid ! {self(), start}, 4629 receive {Pid, done} -> ok end, 4630 {ok, <<>>}. 4631 4632create_opened_log(File, Args) -> 4633 Log = n, 4634 file:delete(File), 4635 {ok, Log} = disk_log:open(Args), 4636 log_terms(Log, 400000), 4637 ok = disk_log:close(Log), 4638 mark(File, ?OPENED), 4639 ok. 4640 4641log_terms(_Log, 0) -> 4642 ok; 4643log_terms(Log, N) when N > 100 -> 4644 Terms = [{term,I} || I <- lists:seq(N-99, N)], 4645 ok = disk_log:log_terms(Log, Terms), 4646 log_terms(Log, N-100); 4647log_terms(Log, N) -> 4648 ok = disk_log:log(Log, {term, N}), 4649 log_terms(Log, N-1). 4650 4651%% OTP-5810. Cope with pg2 groups that are not disk logs. 4652other_groups(Conf) when is_list(Conf) -> 4653 true = is_alive(), 4654 PrivDir = ?privdir(Conf), 4655 4656 File = filename:join(PrivDir, "n.LOG"), 4657 file:delete(File), 4658 4659 {[],[]} = disk_log:accessible_logs(), 4660 {[_],[]} = disk_log:open([{name, n}, {file, File}, {type, halt}, 4661 {distributed, [node()]}]), 4662 {[],[n]} = disk_log:accessible_logs(), 4663 Group = grupp, 4664 pg2:create(Group), 4665 ok = pg2:join(Group, self()), 4666 {[],[n]} = disk_log:accessible_logs(), 4667 [_] = 4668 lists:filter(fun(P) -> disk_log:pid2name(P) =/= undefined end, 4669 erlang:processes()), 4670 pg2:delete(Group), 4671 {[],[n]} = disk_log:accessible_logs(), 4672 ok = disk_log:close(n), 4673 {[],[]} = disk_log:accessible_logs(), 4674 file:delete(File), 4675 4676 ok. 4677 4678%% OTP-6278. open/1 creates no status or crash report. 4679otp_6278(Conf) when is_list(Conf) -> 4680 Dir = ?privdir(Conf), 4681 File = filename:join(Dir, "no_such_dir/no_such_file"), 4682 error_logger:add_report_handler(?MODULE, self()), 4683 {error, {file_error, _, _}} = 4684 disk_log:open([{name,n},{file,File}]), 4685 receive 4686 {crash_report,_Pid,Report} -> 4687 io:format("Unexpected: ~p\n", [Report]), 4688 ct:fail(failed) 4689 after 1000 -> 4690 ok 4691 end, 4692 error_logger:delete_report_handler(?MODULE). 4693 4694%% OTP-10131. head_func type. 4695otp_10131(Conf) when is_list(Conf) -> 4696 Dir = ?privdir(Conf), 4697 Log = otp_10131, 4698 File = filename:join(Dir, lists:concat([Log, ".LOG"])), 4699 HeadFunc = {?MODULE, head_fun, [{ok,"head"}]}, 4700 {ok, Log} = disk_log:open([{name,Log},{file,File}, 4701 {head_func, HeadFunc}]), 4702 HeadFunc = info(Log, head, undef), 4703 HeadFunc2 = {?MODULE, head_fun, [{ok,"head2"}]}, 4704 ok = disk_log:change_header(Log, {head_func, HeadFunc2}), 4705 HeadFunc2 = info(Log, head, undef), 4706 ok = disk_log:close(Log), 4707 ok. 4708 4709%% OTP-16768. Bad number of items with truncate/1. ERL-1312, ERL-1313. 4710otp_16768(Conf) when is_list(Conf) -> 4711 Dir = ?privdir(Conf), 4712 Log = otp_16768, 4713 File = filename:join(Dir, Log), 4714 Header = <<"123456789\n">>, 4715 head_count(Log, File, Header, external, 25), 4716 head_count(Log, File, none, external, 20), 4717 head_count(Log, File, Header, internal, 30), 4718 head_count(Log, File, none, internal, 20), 4719 ok. 4720 4721head_count(Log, File, Header, Format, Expected) -> 4722 del(File, 10), 4723 Content = <<"1234567890123456789\n">>, 4724 HeaderSize = case Header of 4725 none -> 0; 4726 _ -> byte_size(Header) 4727 end, 4728 %% 5 files for the external format, more for the internal format 4729 MaxSizePerFile = HeaderSize + (5 * byte_size(Content)) - 1, 4730 {ok, Log} = disk_log:open([{file, File}, 4731 {name, Log}, 4732 {format, Format}, 4733 {head, Header}, 4734 {size, {MaxSizePerFile, 999}}, 4735 {type, wrap} 4736 ]), 4737 ok = disk_log:truncate(Log), 4738 lists:foreach(fun(_I) -> disk_log:blog(Log, Content) end, 4739 lists:seq(1, 20)), 4740 DiskLogInfo = disk_log:info(Log), 4741 Expected = proplists:get_value(no_items, DiskLogInfo), 4742 ok = disk_log:close(Log). 4743 4744mark(FileName, What) -> 4745 {ok,Fd} = file:open(FileName, [raw, binary, read, write]), 4746 {ok,_} = file:position(Fd, 4), 4747 ok = file:write(Fd, What), 4748 ok = file:close(Fd). 4749 4750crash(File, Where) -> 4751 {ok, Fd} = file:open(File, [read,write]), 4752 file:position(Fd, Where), 4753 ok = file:write(Fd, [10]), 4754 ok = file:close(Fd). 4755 4756unwritable(Fname) -> 4757 {ok, Info} = file:read_file_info(Fname), 4758 Mode = Info#file_info.mode - 8#00200, 4759 file:write_file_info(Fname, Info#file_info{mode = Mode}). 4760 4761writable(Fname) -> 4762 {ok, Info} = file:read_file_info(Fname), 4763 Mode = Info#file_info.mode bor 8#00200, 4764 file:write_file_info(Fname, Info#file_info{mode = Mode}). 4765 4766truncate(File, Where) -> 4767 {ok, Fd} = file:open(File, [read,write]), 4768 file:position(Fd, Where), 4769 ok = file:truncate(Fd), 4770 ok = file:close(Fd). 4771 4772file_size(File) -> 4773 {ok, F} = file:read_file_info(File), 4774 F#file_info.size. 4775 4776copy_wrap_log(FromName, N, FromDir, ToDir) -> 4777 copy_wrap_log(FromName, FromName, N, FromDir, ToDir). 4778 4779copy_wrap_log(FromName, ToName, N, FromDir, ToDir) -> 4780 Fun = fun(E) -> 4781 From = join(FromDir, io_lib:format("~s.~p", [FromName, E])), 4782 To = join(ToDir, io_lib:format("~s.~p", [ToName, E])), 4783 case file:read_file_info(From) of 4784 {ok, _FileInfo} -> 4785 copy_file(From, To); 4786 _Else -> 4787 ok 4788 end 4789 end, 4790 Exts = [idx, siz | lists:seq(1, N)], 4791 lists:foreach(Fun, Exts). 4792 4793-define(BUFSIZE, 8192). 4794 4795copy_file(Src, Dest) -> 4796 %% io:format("copying from ~p to ~p~n", [Src, Dest]), 4797 {ok, InFd} = file:open(Src, [raw, binary, read]), 4798 {ok, OutFd} = file:open(Dest, [raw, binary, write]), 4799 ok = copy_file1(InFd, OutFd), 4800 file:close(InFd), 4801 file:close(OutFd), 4802 ok = file:change_mode(Dest, 8#0666). 4803 4804copy_file1(InFd, OutFd) -> 4805 case file:read(InFd, ?BUFSIZE) of 4806 {ok, Bin} -> 4807 ok = file:write(OutFd, Bin), 4808 copy_file1(InFd, OutFd); 4809 eof -> 4810 ok 4811 end. 4812 4813 4814join(A, B) -> 4815 filename:nativename(filename:join(A, B)). 4816 4817add_ext(Name, Ext) -> 4818 lists:concat([Name, ".", Ext]). 4819 4820log(_Name, 0) -> 4821 ok; 4822log(Name, N) -> 4823 ok = disk_log:log(Name, "this is a logged message number " ++ 4824 integer_to_list(N)), 4825 log(Name, N-1). 4826 4827format_error(E) -> 4828 lists:flatten(disk_log:format_error(E)). 4829 4830check_pps({Ports0,Procs0} = P0) -> 4831 case pps() of 4832 P0 -> 4833 ok; 4834 _ -> 4835 timer:sleep(500), 4836 case pps() of 4837 P0 -> 4838 ok; 4839 {Ports1,Procs1} = P1 -> 4840 case {Ports1 -- Ports0, Procs1 -- Procs0} of 4841 {[], []} -> ok; 4842 {PortsDiff,ProcsDiff} -> 4843 io:format("failure, got ~p~n, expected ~p\n", [P1, P0]), 4844 show("Old port", Ports0 -- Ports1), 4845 show("New port", PortsDiff), 4846 show("Old proc", Procs0 -- Procs1), 4847 show("New proc", ProcsDiff), 4848 ct:fail(failed) 4849 end 4850 end 4851 end. 4852 4853show(_S, []) -> 4854 ok; 4855show(S, [{Pid, Name, InitCall}|Pids]) when is_pid(Pid) -> 4856 io:format("~s: ~w (~w), ~w: ~p~n", 4857 [S, Pid, proc_reg_name(Name), InitCall, 4858 erlang:process_info(Pid)]), 4859 show(S, Pids); 4860show(S, [{Port, _}|Ports]) when is_port(Port)-> 4861 io:format("~s: ~w: ~p~n", [S, Port, erlang:port_info(Port)]), 4862 show(S, Ports). 4863 4864pps() -> 4865 timer:sleep(100), 4866 {port_list(), process_list()}. 4867 4868port_list() -> 4869 [{P,safe_second_element(erlang:port_info(P, name))} || 4870 P <- erlang:ports()]. 4871 4872process_list() -> 4873 [{P,process_info(P, registered_name), 4874 safe_second_element(process_info(P, initial_call))} || 4875 P <- processes(), erlang:is_process_alive(P)]. 4876 4877proc_reg_name({registered_name, Name}) -> Name; 4878proc_reg_name([]) -> no_reg_name. 4879 4880safe_second_element({_,Info}) -> Info; 4881safe_second_element(Other) -> Other. 4882 4883 4884qlen() -> 4885 {_, {_, N}} = lists:keysearch(message_queue_len, 1, process_info(self())), 4886 N. 4887 4888owners(Log) -> 4889%% io:format("owners ~p~n", [info(Log, owners, -1)]), 4890 info(Log, owners, -1). 4891users(Log) -> 4892%% io:format("users ~p~n", [info(Log, users, -1)]), 4893 info(Log, users, -1). 4894status(Log) -> 4895%% io:format("status ~p~n", [info(Log, status, -1)]), 4896 info(Log, status, -1). 4897distributed(Log) -> 4898%% io:format("distributed ~p~n", [info(Log, distributed, -1)]), 4899 info(Log, distributed, -1). 4900no_items(Log) -> 4901%% io:format("no_items ~p~n", [info(Log, no_items, -1)]), 4902 info(Log, no_items, -1). 4903no_written_items(Log) -> 4904%% io:format("no_written_items ~p~n", [info(Log, no_written_items, -1)]), 4905 info(Log, no_written_items, -1). 4906sz(Log) -> 4907%% io:format("sz ~p~n", [info(Log, size, -1)]), 4908 info(Log, size, -1). 4909curb(Log) -> 4910%% io:format("curb ~p~n", [info(Log, no_current_bytes, -1)]), 4911 info(Log, no_current_bytes, -1). 4912curf(Log) -> 4913%% io:format("curf ~p~n", [info(Log, current_file, -1)]), 4914 info(Log, current_file, -1). 4915cur_cnt(Log) -> 4916%% io:format("cur_cnt ~p~n", [info(Log, no_current_items, -1)]), 4917 info(Log, no_current_items, -1). 4918no_overflows(Log) -> 4919%% io:format("no_overflows ~p~n", [info(Log, no_overflows, -1)]), 4920 info(Log, no_overflows, -1). 4921 4922info(Log, What, Undef) -> 4923 case lists:keysearch(What, 1, disk_log:info(Log)) of 4924 {value, {What, Value}} -> Value; 4925 false -> Undef 4926 end. 4927 4928rec(0, _) -> 4929 ok; 4930rec(N, Msg) -> 4931 receive 4932 Msg -> 4933 rec(N-1, Msg) 4934 after 100 -> 4935 test_server_fail({no_msg, N, Msg}) 4936 end. 4937 4938%% Copied from global_SUITE.erl. 4939-define(UNTIL(Seq), loop_until_true(fun() -> Seq end)). 4940 4941loop_until_true(Fun) -> 4942 case Fun() of 4943 true -> 4944 ok; 4945 _ -> 4946 timer:sleep(1000), 4947 loop_until_true(Fun) 4948 end. 4949 4950wait_for_ready_net() -> 4951 Nodes = lists:sort([node() | nodes()]), 4952 ?UNTIL(begin 4953 lists:all(fun(N) -> Nodes =:= get_known(N) end, Nodes) and 4954 lists:all(fun(N) -> 4955 LNs = rpc:call(N, erlang, nodes, []), 4956 Nodes =:= lists:sort([N | LNs]) 4957 end, Nodes) 4958 end). 4959 4960get_known(Node) -> 4961 case catch gen_server:call({global_name_server,Node}, get_known) of 4962 {'EXIT', _} -> 4963 [list, without, nodenames]; 4964 Known -> 4965 lists:sort([Node | Known]) 4966 end. 4967 4968%% Copied from erl_distribution_SUITE.erl: 4969start_node(Name, Param) -> 4970 test_server:start_node(Name, slave, [{args, Param}]). 4971 4972stop_node(Node) -> 4973 test_server:stop_node(Node). 4974 4975%% from(H, [H | T]) -> T; 4976%% from(H, [_ | T]) -> from(H, T); 4977%% from(_H, []) -> []. 4978 4979 4980%%----------------------------------------------------------------- 4981%% The error_logger handler used. 4982%% (Copied from stdlib/test/proc_lib_SUITE.erl.) 4983%%----------------------------------------------------------------- 4984init(Tester) -> 4985 {ok, Tester}. 4986 4987handle_event({error_report, _GL, {Pid, crash_report, Report}}, Tester) -> 4988 Tester ! {crash_report, Pid, Report}, 4989 {ok, Tester}; 4990handle_event({info_msg, _GL, {Pid, F,A}}, Tester) -> 4991 Tester ! {info_msg, Pid, F, A}, 4992 {ok, Tester}; 4993handle_event(_Event, State) -> 4994 {ok, State}. 4995 4996handle_info(_, State) -> 4997 {ok, State}. 4998 4999handle_call(_Query, State) -> {ok, {error, bad_query}, State}. 5000 5001terminate(_Reason, State) -> 5002 State. 5003