mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 21:43:06 +01:00
109 lines
3.9 KiB
Python
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
|