6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00
firebird-qa/tests/bugs/core_6348_test.py

266 lines
10 KiB
Python

#coding:utf-8
"""
ID: issue-6589
ISSUE: 6589
TITLE: Wire compression causes freezes
DESCRIPTION:
Test was created at JULY-2020.
Lot of runs of this test *previous* version often showed outcome = 'F' (failed).
Following snapshots were deep tested DURING 15...19-NOV-2021 in order to get reason this:
----------------------------------------
FB | Without fix | With fix
----|-----------------|-----------------
3.x | WI-V3.0.6.33330 | WI-V3.0.6.33332
4.x | WI-V4.0.0.2084 | WI-V4.0.0.2089
It was found out that:
1) there is no sence to compare performance of two possible cases of WireCompression parameter
in one snapshot (i.e. NO sense to set this parameter to false, then change it on true and compare results):
ratio between elapsed time in *all* four snapshots is approximately the same, about 1.20 ... 1.30
(and thus we can not to get difference between snapshots which have and have no fix of this bug).
2) It is NOT enough to see difference in performance by just changing from one snapshot to another.
Data that is used for loading into blob column must have GOOD or EXCELLENT degree of compression.
This is completely opposite to the data which was used in *previous* version of this test (.7z file)
3) One need to carefully choose length of data. If we use string with length >= 4 Mb then snapshots which
have this bug (3.0.6.33330 and 4.0.0.2084) can/will do their work EXTREMELY slow and all further tests
will not be executed because pof job termination (by scheduler when new instance of this job starts).
On the other hand, we must not use too short strings (less than 64 Kb) because otherwise one can not
to see how performance suffers on builds w/o fix.
After lot of runs (on Windows 2008 Server and Windows 10) it was decided to use length from 256 to 512 Kb.
4) There is no sense to measure CPU user_time (for example, using psutil package): all snapshots show almost
equal values of this value.
5) There is no sense to evaluate performance using trace because prepare and executing duration is about 0 ms.
But it must be noted snashots w/o fix have strange delay after PREPARE_STATEMENT and before EXECUTE_STATEMENT_START
actions.
This is example for blob length = 512K and FB 3.0.6.33330:
=====
2021-11-19T23:48:25.4400 ... PREPARE_STATEMENT
insert into test(b) values(?)
0 ms
2021-11-19T23:48:33.6880 ... EXECUTE_STATEMENT_START
insert into test(b) values(?)
2021-11-19T23:48:33.6880 ... EXECUTE_STATEMENT_FINISH
insert into test(b) values(?)
param0 = blob, "0000000000000001"
0 ms, 13 fetch(es), 9 mark(s)
=====
(NOTE on difference between 23:48:25.4400 and 23:48:33.6880 - it is more that 8000 ms!)
6) Bulds with fix can load blob very fast, for about 5...10 ms. Because of this, it was decided to use trivial way
for estimating outcome of this test: if we can load blob with length = <BLOB_LEN_KB> Kb for time less then
<MAX_THRESHOLD_MS> ms then test can be considered as passed (see apropriate settings below).
::: NB :::
Median value of list that has <N_MEASURES> results of measures is used for comparison with <MAX_THRESHOLD_MS>.
NOTE-1
Test temporary changes firebird.conf, so any abnormal termination of it can cause
problems for other tests (which are to be executed after current).
NOTE-2
EXTERNAL script for execution by Python is created here!
Otherwise one can not reproduce problem described in the ticket if original firebird.conf
We have to launch NEW (child) Python process which will run fully separately from current.
19.11.2021: pre-created large binary file which was used for this test not needed anymore and has been deleted.
Checked on:
5.0.0.311 SS: 17.677s; 5.0.0.311 CS: 27.820s.
4.0.1.2660 SS: 17.589s; 4.0.1.2660 CS: 25.918s.
3.0.8.33535 SS: 13.108s; 3.0.8.33535 CS: 21.583s.
JIRA: CORE-6348
"""
import pytest
from firebird.qa import *
db = db_factory()
act = python_act('db')
expected_stdout = """
Median time for loading blob: acceptable.
"""
@pytest.mark.skip('FIXME: firebird.conf')
@pytest.mark.version('>=3.0.7')
def test_1(act: Action):
pytest.fail("Not IMPLEMENTED")
# test_script_1
#---
# import os
# import sys
# import subprocess
# from subprocess import Popen
# import datetime
# import time
# import shutil
# from fdb import services
# from datetime import datetime as dt
# from datetime import timedelta
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
# db_conn.close()
#
# ###########################
# ### S E T T I N G S ###
# ###########################
#
# # Number of measures (how many times we must recreate table and load blob into it):
# N_MEASURES = 20
#
# # Length of generated blob, Kb
# BLOB_LEN_KB = 512
#
# # Max allowed value for median or milliseconds which were spent for loading:
# MAX_THRESHOLD_MS = 500
#
# #--------------------------------------------
#
# def showtime():
# global dt
# return ''.join( (dt.now().strftime("%H:%M:%S.%f")[:11],'.') )
#
# #--------------------------------------------
#
# def median(lst):
# n = len(lst)
# s = sorted(lst)
# return (sum(s[n//2-1:n//2+1])/2.0, s[n//2])[n % 2] if n else None
#
# #--------------------------------------------
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
# #--------------------------------------------
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
# if type(f_names_list[i]) == file:
# del_name = f_names_list[i].name
# elif type(f_names_list[i]) == str:
# del_name = f_names_list[i]
# else:
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# print('type(f_names_list[i])=',type(f_names_list[i]))
# del_name = None
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
# #--------------------------------------------
#
#
# FB_HOME = services.connect(host='localhost', user= user_name, password= user_password).get_home_directory()
# # Resut: FB_HOME is full path to FB instance home (with trailing slash).
#
# if os.name == 'nt':
# # For Windows we assume that client library is always in FB_HOME dir:
# FB_CLNT=os.path.join(FB_HOME, 'fbclient.dll')
# else:
# # For Linux client library will be searched in 'lib' subdirectory of FB_HOME:
# FB_CLNT=os.path.join(FB_HOME, 'lib', 'libfbclient.so' )
#
#
# dts = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
#
# fbconf_cur = os.path.join( FB_HOME, 'firebird.conf')
# fbconf_bak = os.path.join( FB_HOME, 'firebird.'+dts+'.bak')
#
# shutil.copy2( fbconf_cur, fbconf_bak )
#
# f_fbconf=open( fbconf_cur, 'r')
# fbconf_content=f_fbconf.readlines()
# f_fbconf.close()
# for i,s in enumerate( fbconf_content ):
# line = s.lower().lstrip()
# if line.startswith( 'wirecompression'.lower() ):
# fbconf_content[i] = '# [temply commented by fbtest for core_6348.fbt] ' + s
#
# text2app='''
# ### TEMPORARY CHANGED FOR CORE_6348.FBT ###
# WireCompression = true
# ##############################################
# ''' % locals()
#
# fbconf_content += [ os.linesep + x for x in text2app.split( os.linesep ) ]
#
# f_fbconf=open( fbconf_cur, 'w')
# f_fbconf.writelines( fbconf_content )
# flush_and_close( f_fbconf )
#
# external_python_code=''' from __future__ import print_function
# from datetime import datetime as dt
# from datetime import timedelta
# import fdb
# con = fdb.connect( dsn = r'%(dsn)s', user='%(user_name)s', password='%(user_password)s', fb_library_name = r'%(FB_CLNT)s' )
# con.execute_immediate('recreate table test(b blob)')
# con.commit()
#
# da = dt.now()
# cur=con.cursor()
# cur.execute("insert into test(b) values(?)", ('a' * %(BLOB_LEN_KB)s * 1024,) )
# db = dt.now()
#
# diff_ms = (db-da).seconds*1000 + (db-da).microseconds//1000
# print( str(diff_ms) )
#
# cur.close()
# con.commit()
# con.close()
# ''' % dict(globals(), **locals())
#
# f_extern_py = open( os.path.join(context['temp_directory'],'tmp_6348.py'), 'w')
# f_extern_py.write( '\\n'.join( [i.strip() for i in external_python_code.split('\\n')] ) )
# flush_and_close( f_extern_py )
#
# blob_load_elapsed_time = []
# for iter in range(0,N_MEASURES):
#
# f_external_py_log = open( os.path.join(context['temp_directory'],'tmp_6348_py.log' ), 'w')
# subprocess.call( [sys.executable, f_extern_py.name], stdout = f_external_py_log, stderr = subprocess.STDOUT )
# flush_and_close( f_external_py_log )
#
# with open(f_external_py_log.name,'r') as f:
# blob_load_elapsed_time.append( int(f.read().strip()) )
#
#
# cleanup( ( f_extern_py, f_external_py_log ) )
#
# # Restore original content of firebird.conf:
# ##################
# shutil.move( fbconf_bak, fbconf_cur )
#
#
# msg = 'Median time for loading blob: '
# if median(blob_load_elapsed_time) < MAX_THRESHOLD_MS:
# msg += 'acceptable.'
# print(msg)
# else:
# msg += 'INACCEPTABLE, TOO SLOW. Check values for %d measurements:' % N_MEASURES
# print(msg)
# for i,p in enumerate(blob_load_elapsed_time):
# print( '%3d : %12.2f' % (i,p) )
#
# # Cleanup
# #########
# cleanup( ( f_extern_py, f_external_py_log ) )
#
#---