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