|
| 1 | +#coding:utf-8 |
| 2 | + |
| 3 | +""" |
| 4 | +ID: n/a |
| 5 | +ISSUE: https://github.com/FirebirdSQL/firebird/issues/6413 |
| 6 | +TITLE: Data pages of newly gbak restored databases should be marked as "swept" |
| 7 | +DESCRIPTION: |
| 8 | +NOTES: |
| 9 | + [17.07.2025] pzotov |
| 10 | + Test adds a table and fill it with some data. |
| 11 | + Then we make b/r and obtain statistics using 'gstat -d ...' |
| 12 | + Output will contain lines like: "Primary pages: 1, secondary pages: 1, swept pages: 1" |
| 13 | + We have to check that in every such line value of primary pages is equal to swept pages |
| 14 | + or it can be greater but NO MORE than for <MAX_NUM_OF_EMPTY_PAGES> because of pages |
| 15 | + allocation algorithm. |
| 16 | +
|
| 17 | + Explained by Vlad, 17.07.2025 16:34. |
| 18 | + Confirmed on 6.0.0.799 |
| 19 | + Checked on 6.0.0.1020 ; 5.0.3.1683 |
| 20 | +""" |
| 21 | +import string |
| 22 | +import locale |
| 23 | +import re |
| 24 | +from io import BytesIO |
| 25 | +from firebird.driver import SrvRestoreFlag |
| 26 | +import pytest |
| 27 | +from firebird.qa import * |
| 28 | + |
| 29 | +init_sql = """ |
| 30 | + set bail on; |
| 31 | + recreate table test(id int generated by default as identity, s varchar(32760)); |
| 32 | + set term ^; |
| 33 | + execute block as |
| 34 | + declare n int = 1000; |
| 35 | + declare i int = 0; |
| 36 | + begin |
| 37 | + while (i < n) do |
| 38 | + begin |
| 39 | + insert into test(s) values(lpad('', rand()*32760, uuid_to_char(gen_uuid()))); |
| 40 | + i = i + 1; |
| 41 | + end |
| 42 | + end^ |
| 43 | + set term ;^ |
| 44 | + commit; |
| 45 | +""" |
| 46 | +db = db_factory(init = init_sql, charset = 'win1251', page_size = 8192) |
| 47 | + |
| 48 | +act = python_act('db') |
| 49 | + |
| 50 | +#----------------------------------------------------------- |
| 51 | + |
| 52 | +REMOVE_PUNCT = str.maketrans('', '', string.punctuation) |
| 53 | +MAX_NUM_OF_EMPTY_PAGES = 7 |
| 54 | +EXPECTED_MSG = f'Expected: no lines with difference between primary and swept pages GREATER than {MAX_NUM_OF_EMPTY_PAGES}' |
| 55 | + |
| 56 | +@pytest.mark.version('>=5.0.3') |
| 57 | +def test_1(act: Action, capsys): |
| 58 | + backup = BytesIO() |
| 59 | + with act.connect_server() as srv: |
| 60 | + srv.database.local_backup(database = act.db.db_path, backup_stream = backup) |
| 61 | + backup.seek(0) |
| 62 | + srv.database.local_restore(backup_stream = backup, database = act.db.db_path, flags = SrvRestoreFlag.REPLACE) |
| 63 | + |
| 64 | + act.gstat(switches=['-d' ], io_enc = locale.getpreferredencoding()) |
| 65 | + # Primary pages: 1, secondary pages: 1, swept pages: 1 |
| 66 | + # 0 1 2 3 4 5 6 7 8 |
| 67 | + p_swept_pages = re.compile(r'Primary pages(:)?\s+\d+.*swept pages(:)?\s+\d+', re.IGNORECASE) |
| 68 | + non_swept_line_indices = [] |
| 69 | + for idx, line in enumerate(act.stdout.splitlines()): |
| 70 | + if p_swept_pages.search(line): |
| 71 | + tokens = line.split() |
| 72 | + if len(tokens) >= 9: |
| 73 | + try: |
| 74 | + primary_pages_count = int(tokens[2].translate(REMOVE_PUNCT)) |
| 75 | + swept_pages_count = int(tokens[8].translate(REMOVE_PUNCT)) |
| 76 | + if primary_pages_count - swept_pages_count > MAX_NUM_OF_EMPTY_PAGES: |
| 77 | + non_swept_line_indices.append( (idx, line) ) |
| 78 | + except ValueError as e: |
| 79 | + print(e.__str__()) |
| 80 | + else: |
| 81 | + print('Line does not contain all expected tokens: "{line=}"') |
| 82 | + |
| 83 | + if non_swept_line_indices: |
| 84 | + print(f'At least one line contains difference between primary and swept pages GREATER than {MAX_NUM_OF_EMPTY_PAGES}:') |
| 85 | + for p in non_swept_line_indices: |
| 86 | + print(f'Line #{p[0]}, text: {p[1].strip()}') |
| 87 | + else: |
| 88 | + print(EXPECTED_MSG) |
| 89 | + |
| 90 | + act.expected_stdout = EXPECTED_MSG |
| 91 | + act.stdout = capsys.readouterr().out |
| 92 | + assert act.clean_stdout == act.clean_expected_stdout |
0 commit comments