Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3bb59c6

Browse files
[#235] test_pg_ctl_wait_option detects a port conflict (#257)
This patch must fix a problem in test_pg_ctl_wait_option when his PostgreSQL instance conflicts with another one.For this, we added two new things: - PostgresNodeLogReader - PostgresNodeUtilsPostgresNodeLogReader reads server logs.PostgresNodeUtils provides an utility to detect a port conflict.PostgresNode::start also uses these new classes.
1 parentedd64db commit3bb59c6

File tree

2 files changed

+200
-45
lines changed

2 files changed

+200
-45
lines changed

‎testgres/node.py

Lines changed: 165 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -784,28 +784,6 @@ def _collect_special_files(self):
784784

785785
returnresult
786786

787-
def_collect_log_files(self):
788-
# dictionary of log files + size in bytes
789-
790-
files= [
791-
self.pg_log_file
792-
]# yapf: disable
793-
794-
result= {}
795-
796-
forfinfiles:
797-
# skip missing files
798-
ifnotself.os_ops.path_exists(f):
799-
continue
800-
801-
file_size=self.os_ops.get_file_size(f)
802-
asserttype(file_size)==int# noqa: E721
803-
assertfile_size>=0
804-
805-
result[f]=file_size
806-
807-
returnresult
808-
809787
definit(self,initdb_params=None,cached=True,**kwargs):
810788
"""
811789
Perform initdb for this node.
@@ -1062,22 +1040,6 @@ def slow_start(self, replica=False, dbname='template1', username=None, max_attem
10621040
OperationalError},
10631041
max_attempts=max_attempts)
10641042

1065-
def_detect_port_conflict(self,log_files0,log_files1):
1066-
asserttype(log_files0)==dict# noqa: E721
1067-
asserttype(log_files1)==dict# noqa: E721
1068-
1069-
forfileinlog_files1.keys():
1070-
read_pos=0
1071-
1072-
iffileinlog_files0.keys():
1073-
read_pos=log_files0[file]# the previous size
1074-
1075-
file_content=self.os_ops.read_binary(file,read_pos)
1076-
file_content_s=file_content.decode()
1077-
if'Is another postmaster already running on port'infile_content_s:
1078-
returnTrue
1079-
returnFalse
1080-
10811043
defstart(self,params=[],wait=True,exec_env=None):
10821044
"""
10831045
Starts the PostgreSQL node using pg_ctl if node has not been started.
@@ -1137,8 +1099,7 @@ def LOCAL__raise_cannot_start_node__std(from_exception):
11371099
assertisinstance(self._port_manager,PortManager)
11381100
assert__class__._C_MAX_START_ATEMPTS>1
11391101

1140-
log_files0=self._collect_log_files()
1141-
asserttype(log_files0)==dict# noqa: E721
1102+
log_reader=PostgresNodeLogReader(self,from_beginnig=False)
11421103

11431104
nAttempt=0
11441105
timeout=1
@@ -1154,11 +1115,11 @@ def LOCAL__raise_cannot_start_node__std(from_exception):
11541115
ifnAttempt==__class__._C_MAX_START_ATEMPTS:
11551116
LOCAL__raise_cannot_start_node(e,"Cannot start node after multiple attempts.")
11561117

1157-
log_files1=self._collect_log_files()
1158-
ifnotself._detect_port_conflict(log_files0,log_files1):
1118+
is_it_port_conflict=PostgresNodeUtils.delect_port_conflict(log_reader)
1119+
1120+
ifnotis_it_port_conflict:
11591121
LOCAL__raise_cannot_start_node__std(e)
11601122

1161-
log_files0=log_files1
11621123
logging.warning(
11631124
"Detected a conflict with using the port {0}. Trying another port after a {1}-second sleep...".format(self._port,timeout)
11641125
)
@@ -2192,6 +2153,167 @@ def _escape_config_value(value):
21922153
returnresult
21932154

21942155

2156+
classPostgresNodeLogReader:
2157+
classLogInfo:
2158+
position:int
2159+
2160+
def__init__(self,position:int):
2161+
self.position=position
2162+
2163+
# --------------------------------------------------------------------
2164+
classLogDataBlock:
2165+
_file_name:str
2166+
_position:int
2167+
_data:str
2168+
2169+
def__init__(
2170+
self,
2171+
file_name:str,
2172+
position:int,
2173+
data:str
2174+
):
2175+
asserttype(file_name)==str# noqa: E721
2176+
asserttype(position)==int# noqa: E721
2177+
asserttype(data)==str# noqa: E721
2178+
assertfile_name!=""
2179+
assertposition>=0
2180+
self._file_name=file_name
2181+
self._position=position
2182+
self._data=data
2183+
2184+
@property
2185+
deffile_name(self)->str:
2186+
asserttype(self._file_name)==str# noqa: E721
2187+
assertself._file_name!=""
2188+
returnself._file_name
2189+
2190+
@property
2191+
defposition(self)->int:
2192+
asserttype(self._position)==int# noqa: E721
2193+
assertself._position>=0
2194+
returnself._position
2195+
2196+
@property
2197+
defdata(self)->str:
2198+
asserttype(self._data)==str# noqa: E721
2199+
returnself._data
2200+
2201+
# --------------------------------------------------------------------
2202+
_node:PostgresNode
2203+
_logs:typing.Dict[str,LogInfo]
2204+
2205+
# --------------------------------------------------------------------
2206+
def__init__(self,node:PostgresNode,from_beginnig:bool):
2207+
assertnodeisnotNone
2208+
assertisinstance(node,PostgresNode)
2209+
asserttype(from_beginnig)==bool# noqa: E721
2210+
2211+
self._node=node
2212+
2213+
iffrom_beginnig:
2214+
self._logs=dict()
2215+
else:
2216+
self._logs=self._collect_logs()
2217+
2218+
asserttype(self._logs)==dict# noqa: E721
2219+
return
2220+
2221+
defread(self)->typing.List[LogDataBlock]:
2222+
assertself._nodeisnotNone
2223+
assertisinstance(self._node,PostgresNode)
2224+
2225+
cur_logs:typing.Dict[__class__.LogInfo]=self._collect_logs()
2226+
assertcur_logsisnotNone
2227+
asserttype(cur_logs)==dict# noqa: E721
2228+
2229+
asserttype(self._logs)==dict# noqa: E721
2230+
2231+
result=list()
2232+
2233+
forfile_name,cur_log_infoincur_logs.items():
2234+
asserttype(file_name)==str# noqa: E721
2235+
asserttype(cur_log_info)==__class__.LogInfo# noqa: E721
2236+
2237+
read_pos=0
2238+
2239+
iffile_nameinself._logs.keys():
2240+
prev_log_info=self._logs[file_name]
2241+
asserttype(prev_log_info)==__class__.LogInfo# noqa: E721
2242+
read_pos=prev_log_info.position# the previous size
2243+
2244+
file_content_b=self._node.os_ops.read_binary(file_name,read_pos)
2245+
asserttype(file_content_b)==bytes# noqa: E721
2246+
2247+
#
2248+
# A POTENTIAL PROBLEM: file_content_b may contain an incompleted UTF-8 symbol.
2249+
#
2250+
file_content_s=file_content_b.decode()
2251+
asserttype(file_content_s)==str# noqa: E721
2252+
2253+
next_read_pos=read_pos+len(file_content_b)
2254+
2255+
# It is a research/paranoja check.
2256+
# When we will process partial UTF-8 symbol, it must be adjusted.
2257+
assertcur_log_info.position<=next_read_pos
2258+
2259+
cur_log_info.position=next_read_pos
2260+
2261+
block=__class__.LogDataBlock(
2262+
file_name,
2263+
read_pos,
2264+
file_content_s
2265+
)
2266+
2267+
result.append(block)
2268+
2269+
# A new check point
2270+
self._logs=cur_logs
2271+
2272+
returnresult
2273+
2274+
def_collect_logs(self)->typing.Dict[LogInfo]:
2275+
assertself._nodeisnotNone
2276+
assertisinstance(self._node,PostgresNode)
2277+
2278+
files= [
2279+
self._node.pg_log_file
2280+
]# yapf: disable
2281+
2282+
result=dict()
2283+
2284+
forfinfiles:
2285+
asserttype(f)==str# noqa: E721
2286+
2287+
# skip missing files
2288+
ifnotself._node.os_ops.path_exists(f):
2289+
continue
2290+
2291+
file_size=self._node.os_ops.get_file_size(f)
2292+
asserttype(file_size)==int# noqa: E721
2293+
assertfile_size>=0
2294+
2295+
result[f]=__class__.LogInfo(file_size)
2296+
2297+
returnresult
2298+
2299+
2300+
classPostgresNodeUtils:
2301+
@staticmethod
2302+
defdelect_port_conflict(log_reader:PostgresNodeLogReader)->bool:
2303+
asserttype(log_reader)==PostgresNodeLogReader# noqa: E721
2304+
2305+
blocks=log_reader.read()
2306+
asserttype(blocks)==list# noqa: E721
2307+
2308+
forblockinblocks:
2309+
asserttype(block)==PostgresNodeLogReader.LogDataBlock# noqa: E721
2310+
2311+
if'Is another postmaster already running on port'inblock.data:
2312+
returnTrue
2313+
2314+
returnFalse
2315+
2316+
21952317
classNodeApp:
21962318

21972319
def__init__(self,test_path=None,nodes_to_cleanup=None,os_ops=None):

‎tests/test_testgres_common.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
fromtestgres.nodeimportPgVer
77
fromtestgres.nodeimportPostgresNode
8+
fromtestgres.nodeimportPostgresNodeLogReader
9+
fromtestgres.nodeimportPostgresNodeUtils
810
fromtestgres.utilsimportget_pg_version2
911
fromtestgres.utilsimportfile_tail
1012
fromtestgres.utilsimportget_bin_path2
@@ -883,8 +885,29 @@ def test_backup_wrong_xlog_method(self, node_svc: PostgresNodeService):
883885

884886
deftest_pg_ctl_wait_option(self,node_svc:PostgresNodeService):
885887
assertisinstance(node_svc,PostgresNodeService)
886-
with__class__.helper__get_node(node_svc)asnode:
887-
self.impl__test_pg_ctl_wait_option(node_svc,node)
888+
889+
C_MAX_ATTEMPT=5
890+
891+
nAttempt=0
892+
893+
whileTrue:
894+
ifnAttempt==C_MAX_ATTEMPT:
895+
raiseException("PostgresSQL did not start.")
896+
897+
nAttempt+=1
898+
logging.info("------------------------ NODE #{}".format(
899+
nAttempt
900+
))
901+
902+
with__class__.helper__get_node(node_svc,port=12345)asnode:
903+
ifself.impl__test_pg_ctl_wait_option(node_svc,node):
904+
break
905+
continue
906+
907+
logging.info("OK. Test is passed. Number of attempts is {}".format(
908+
nAttempt
909+
))
910+
return
888911

889912
defimpl__test_pg_ctl_wait_option(
890913
self,
@@ -899,9 +922,18 @@ def impl__test_pg_ctl_wait_option(
899922

900923
node.init()
901924
assertnode.status()==NodeStatus.Stopped
925+
926+
node_log_reader=PostgresNodeLogReader(node,from_beginnig=True)
927+
902928
node.start(wait=False)
903929
nAttempt=0
904930
whileTrue:
931+
ifPostgresNodeUtils.delect_port_conflict(node_log_reader):
932+
logging.info("Node port {} conflicted with another PostgreSQL instance.".format(
933+
node.port
934+
))
935+
returnFalse
936+
905937
ifnAttempt==C_MAX_ATTEMPTS:
906938
#
907939
# [2025-03-11]
@@ -960,6 +992,7 @@ def impl__test_pg_ctl_wait_option(
960992
raiseException("Unexpected node status: {0}.".format(s1))
961993

962994
logging.info("OK. Node is stopped.")
995+
returnTrue
963996

964997
deftest_replicate(self,node_svc:PostgresNodeService):
965998
assertisinstance(node_svc,PostgresNodeService)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp