6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 13:33:07 +01:00
firebird-qa/tests/bugs/gh_6706_test.py

109 lines
3.9 KiB
Python

#coding:utf-8
"""
ID: issue-6706
ISSUE: https://github.com/FirebirdSQL/firebird/issues/6706
TITLE: Memory leak when running EXECUTE STATEMENT with named parameters [CORE6475]
DESCRIPTION:
We create stored procedure with PARAMS_COUNT input parameters.
Then EXECUTE BLOCK is generated with call of this SP via EXECUTE STATEMENT which applies EXCESS modifier to all arguments.
Value of memory_info().rss is obtained (for appropriate server process), then run execute block MEASURES_COUNT times
and after this - again get memory_info().rss value.
Ratio between current and initial values of memory_info().rss must be less than MAX_RATIO.
NOTES:
[17.08.2024] pzotov
1. Problem did exist in FB 4.x up to snapshot 4.0.0.2336.
Commit: https://github.com/FirebirdSQL/firebird/commit/4dfb30a45b767994c074bbfcbb8494b8ada19b33 (23-jan-2021, 15:26)
Before this commit ratio for SS was about 5..6 for SS and about 8..9 for CS.
Since 4.0.0.2341 memory consumption was reduced to ~1.6 ... 1.9
2. Database must be created with FW = ON otherwise ratio for all snapshots is about 1.5 (and this seems weird).
3. Test duration is about 35s.
Checked on 6.0.0.438, 5.0.2.1478, 4.0.6.3142; 4.0.0.2336, 4.0.0.2341.
"""
import psutil
import pytest
from firebird.qa import *
import time
###########################
### S E T T I N G S ###
###########################
# How many input parameters must have procedure:
PARAMS_COUNT = 1000
# How many times we call procedures:
MEASURES_COUNT = 1000
# Maximal value for ratio between
# new and initial memory_info().rss values:
#
MAX_RATIO = 3
#############
db = db_factory(async_write = False)
act = python_act('db')
#--------------------------------------------------------------------
def get_server_pid(con):
with con.cursor() as cur:
cur.execute('select mon$server_pid as p from mon$attachments where mon$attachment_id = current_connection')
fb_pid = int(cur.fetchone()[0])
return fb_pid
#--------------------------------------------------------------------
@pytest.mark.version('>=4.0.0')
def test_1(act: Action, capsys):
with act.db.connect() as con:
sp_ddl = """
create or alter procedure sp_test(
"""
params_lst = '\n'.join( [ (',' if i else '') +f'p_{i} int' for i in range(PARAMS_COUNT) ] )
sp_ddl = '\n'.join( ("create or alter procedure sp_test(", params_lst, ") returns(x int) as begin x = 1; suspend; end") )
con.execute_immediate(sp_ddl)
con.commit()
server_process = psutil.Process(get_server_pid(con))
params_lst = ','.join( [ f':p_{i}' for i in range(PARAMS_COUNT) ] )
passed_args = ','.join( [ f'excess p_{i} := 1' for i in range(PARAMS_COUNT) ] )
srv_memo_rss_init = int(server_process.memory_info().rss / 1024)
srv_memo_vms_init = int(server_process.memory_info().vms / 1024)
cur = con.cursor()
for k in range(MEASURES_COUNT):
es_sql = f"""
execute block returns(x int) as
begin
execute statement ('select p.x * {k} from sp_test({params_lst}) p') ({passed_args})
into x;
suspend;
end
"""
cur.execute(es_sql)
for r in cur:
pass
srv_memo_rss_curr = int(server_process.memory_info().rss / 1024)
srv_memo_vms_curr = int(server_process.memory_info().vms / 1024)
memo_ratio = srv_memo_rss_curr / srv_memo_rss_init
SUCCESS_MSG = 'Ratio between memory values measured before and after loop: acceptable'
if memo_ratio < MAX_RATIO:
print(SUCCESS_MSG)
else:
print( 'Ratio: /* perf_issue_tag */ POOR: %s, more than threshold: %s' % ( '{:.2f}'.format(memo_ratio), '{:.2f}'.format(MAX_RATIO) ) )
act.expected_stdout = SUCCESS_MSG
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout