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_3625_test.py
2021-11-17 19:43:06 +01:00

236 lines
8.3 KiB
Python

#coding:utf-8
#
# id: bugs.core_3625
# title: MON$IO_STATS doesn't report page writes performed asynchronously (at the AST level)
# decription:
# Thanks to dimitr for suggestions about how this test can be implemented.
# We have to read some part of data from table by "att_watcher", make small change in this table
# by "att_worker" and finaly do commit + once again read this table in "att_watcher".
# Counter mon$page_writes that will be obtained twise by "att_watcher" (before its two changes)
# must differ.
#
# ::: NOTE-1 :::
# We have to analyze counter mon$page_writes for attachment that is called "att_watcher" here,
# despite that it does NOT change any in queried table!
#
# ::: NOTE-2 :::
# Superserver should *not* be processed by this test because page cache is shared between all
# attachments thus counter mon$page_writes is NOT changed in this scenario.
# For this reason in SS we can only "simulate" proper outcome.
# We define server mode (SS/SC/CS) by queries to mon$ tables ana analyzing results, result will
# be stored in variable 'fba'.
#
# Checked on:
# 4.0.0.1740 SC: 1.228s.
# 4.0.0.1714 CS: 8.047s.
# 3.0.5.33221 SC: 2.557s.
# 3.0.6.33236 CS: 1.372s.
# 2.5.9.27149 SC: 0.218s.
# 2.5.9.27143 CS: 0.645s.
#
#
# tracker_id: CORE-3625
# min_versions: ['2.5.2']
# versions: 2.5.2
# qmid: None
import pytest
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DbInfoCode
# version: 2.5.2
# resources: None
substitutions_1 = [('[ ]+', ' ')]
init_script_1 = """
recreate view v_check as
select i.mon$page_writes as iostat_pg_writes
from mon$attachments a
left join mon$io_stats i on a.mon$stat_id = i.mon$stat_id
where
a.mon$attachment_id <> current_connection
and a.mon$remote_protocol is not null
and i.mon$stat_group = 1 -- <<< ATTACHMENTS level
;
recreate table test(x int) ;
insert into test(x) values(1) ;
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
# import os
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
# db_conn.close()
#
# v_check_ddl='''
# recreate view v_check as
# select i.mon$page_writes as iostat_pg_writes
# from mon$attachments a
# left join mon$io_stats i on a.mon$stat_id = i.mon$stat_id
# where
# a.mon$attachment_id <> current_connection
# and a.mon$remote_protocol is not null
# and i.mon$stat_group = 1 -- <<< ATTACHMENTS level
# ;
# '''
#
# # Connection-"worker":
# con1=fdb.connect( dsn = dsn )
# #print(con1.firebird_version)
#
# con1.execute_immediate( v_check_ddl )
# con1.commit()
# con1.execute_immediate('recreate table test(x int)')
# con1.commit()
# con1.execute_immediate('insert into test(x) values(1)')
# con1.commit()
#
# #-------------------------------------------------------
#
# # Connection-"watcher":
# con2=fdb.connect( dsn = dsn )
#
# ###############################################################
# ### G E T S E R V E R M O D E: S S / S C / C S ? ###
# ###############################################################
# cur1 = con1.cursor()
#
# sql_mon_query='''
# select count(distinct a.mon$server_pid), min(a.mon$remote_protocol), max(iif(a.mon$remote_protocol is null,1,0))
# from mon$attachments a
# where a.mon$attachment_id in (%s, %s) or upper(a.mon$user) = upper('%s')
# ''' % (con1.attachment_id, con2.attachment_id, 'cache writer')
#
# cur1.execute( sql_mon_query )
# for r in cur1.fetchall():
# server_cnt=r[0]
# server_pro=r[1]
# cache_wrtr=r[2]
#
# if server_pro == None:
# fba='Embedded'
# elif cache_wrtr == 1:
# fba='SS'
# elif server_cnt == 2:
# fba='CS'
# else:
#
# f1=con1.db_info(fdb.isc_info_fetches)
#
# cur2=con2.cursor()
# cur2.execute('select 1 from rdb$database')
# for r in cur2.fetchall():
# pass
#
# f2=con1.db_info(fdb.isc_info_fetches)
#
# fba = 'SC' if f1 ==f2 else 'SS'
#
# #print('Server mode: ', fba)
# cur1.close()
#
# #########################################################
#
# if fba == 'SS':
# ### !!!!!!!!!!!!! ###
# ################## A C H T U N G ########################
# ### !!!!!!!!!!!!! ###
# ### SUPERSERVER SHOULD *NOT* BE PROCESSED BY THIS TEST ###
# ### COUNTER MON$PAGE_WRITES IS NOT CHANGED DURING RUN, ###
# ### SO WE CAN ONLY "SIMULATE" PROPER OUTCOME FOR THIS! ###
# #############################################################
# page_writes_at_point_2, page_writes_at_point_1 = 0,1
# else:
#
# # Do following in connection-WATCHER:
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# cur2=con2.cursor()
# con1.execute_immediate('update test set x = 2 rows 1')
#
# cur2.execute('select * from v_check') # get FIRST value of mon$page_writes
# for r in cur2:
# page_writes_at_point_1 = r[0]
#
# # Again do in connection-worker: add small change to the data,
# # otherwise watcher will not get any difference in mon$page_writes:
# con1.execute_immediate('update test set x = 3 rows 1')
#
# cur2.execute('select * from test')
# for r in cur2:
# pass # print('query data:', r[0])
#
# con2.commit()
# cur2.execute('select * from v_check') # get SECOND value of mon$page_writes
# for r in cur2:
# page_writes_at_point_2 = r[0]
# cur2.close()
#
#
# con2.close()
# con1.close()
#
# print('PAGE_WRITES DIFFERENCE SIGN: ', abs(page_writes_at_point_2 - page_writes_at_point_1) )
#
#
#---
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5.2')
def test_1(act_1: Action):
with act_1.db.connect() as worker_con, act_1.db.connect() as watcher_con:
worker = worker_con.cursor()
watcher = watcher_con.cursor()
sql_mon_query = f'''
select count(distinct a.mon$server_pid), min(a.mon$remote_protocol), max(iif(a.mon$remote_protocol is null,1,0))
from mon$attachments a
where a.mon$attachment_id in ({worker_con.info.id}, {watcher_con.info.id}) or upper(a.mon$user) = upper('cache writer')
'''
worker.execute(sql_mon_query)
server_cnt, server_pro, cache_wrtr = worker.fetchone()
if server_pro is None:
fba = 'Embedded'
elif cache_wrtr == 1:
fba = 'SS'
elif server_cnt == 2:
fba = 'CS'
else:
f1 = worker_con.info.get_info(DbInfoCode.FETCHES)
watcher.execute('select 1 from rdb$database')
watcher.fetchall()
f1 = worker_con.info.get_info(DbInfoCode.FETCHES)
fba = 'SC' if f1 ==f2 else 'SS'
#
if fba == 'SS':
# SUPERSERVER SHOULD *NOT* BE PROCESSED BY THIS TEST
# COUNTER MON$PAGE_WRITES IS NOT CHANGED DURING RUN,
# SO WE CAN ONLY "SIMULATE" PROPER OUTCOME FOR THIS!
page_writes_at_point_2, page_writes_at_point_1 = 0, 1
else:
# Do following in connection-WATCHER:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
worker_con.execute_immediate('update test set x = 2 rows 1')
watcher.execute('select * from v_check') # get FIRST value of mon$page_writes
page_writes_at_point_1 = watcher.fetchone()[0]
# Again do in connection-worker: add small change to the data,
# otherwise watcher will not get any difference in mon$page_writes:
worker_con.execute_immediate('update test set x = 3 rows 1')
watcher.execute('select * from test')
watcher.fetchall()
watcher_con.commit()
watcher.execute('select * from v_check') # get SECOND value of mon$page_writes
page_writes_at_point_2 = watcher.fetchone()[0]
# PAGE_WRITES DIFFERENCE SIGN: 1
assert abs(page_writes_at_point_2 - page_writes_at_point_1) == 1