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

Commit22826e0

Browse files
PostgresNode::pid is improved (#199)
* PostgresNode::pid is improved- We do multiple attempts to read pid file.- We process a case when we see that node is stopped between test and read.- We process a case when pid-file is empty.* PostgresNode::pid is updatedAssert is added.* execute_utility2 is updated (ignore_errors)- New parameters "ignore_errors" is added. Default value is False.- Asserts are added.* PostgresNode::_try_shutdown is rewrited (normalization)* PostgresNode::pid uses the data from "pg_ctl status" output.* PostgresNode::_try_shutdown is correct (return None)This method returns nothing (None).
1 parentde432ed commit22826e0

File tree

2 files changed

+211
-40
lines changed

2 files changed

+211
-40
lines changed

‎testgres/consts.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@
3535

3636
# logical replication settings
3737
LOGICAL_REPL_MAX_CATCHUP_ATTEMPTS=60
38+
39+
PG_CTL__STATUS__OK=0
40+
PG_CTL__STATUS__NODE_IS_STOPPED=3
41+
PG_CTL__STATUS__BAD_DATADIR=4

‎testgres/node.py

Lines changed: 207 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
RECOVERY_CONF_FILE, \
5050
PG_LOG_FILE, \
5151
UTILS_LOG_FILE, \
52-
PG_PID_FILE
52+
PG_CTL__STATUS__OK, \
53+
PG_CTL__STATUS__NODE_IS_STOPPED, \
54+
PG_CTL__STATUS__BAD_DATADIR \
5355

5456
from .constsimport \
5557
MAX_LOGICAL_REPLICATION_WORKERS, \
@@ -208,14 +210,136 @@ def pid(self):
208210
Return postmaster's PID if node is running, else 0.
209211
"""
210212

211-
ifself.status():
212-
pid_file=os.path.join(self.data_dir,PG_PID_FILE)
213-
lines=self.os_ops.readlines(pid_file)
214-
pid=int(lines[0])iflineselseNone
215-
returnpid
213+
self__data_dir=self.data_dir
216214

217-
# for clarity
218-
return0
215+
_params= [
216+
self._get_bin_path('pg_ctl'),
217+
"-D",self__data_dir,
218+
"status"
219+
]# yapf: disable
220+
221+
status_code,out,error=execute_utility2(
222+
self.os_ops,
223+
_params,
224+
self.utils_log_file,
225+
verbose=True,
226+
ignore_errors=True)
227+
228+
asserttype(status_code)==int# noqa: E721
229+
asserttype(out)==str# noqa: E721
230+
asserttype(error)==str# noqa: E721
231+
232+
# -----------------
233+
ifstatus_code==PG_CTL__STATUS__NODE_IS_STOPPED:
234+
return0
235+
236+
# -----------------
237+
ifstatus_code==PG_CTL__STATUS__BAD_DATADIR:
238+
return0
239+
240+
# -----------------
241+
ifstatus_code!=PG_CTL__STATUS__OK:
242+
errMsg="Getting of a node status [data_dir is {0}] failed.".format(self__data_dir)
243+
244+
raiseExecUtilException(
245+
message=errMsg,
246+
command=_params,
247+
exit_code=status_code,
248+
out=out,
249+
error=error,
250+
)
251+
252+
# -----------------
253+
assertstatus_code==PG_CTL__STATUS__OK
254+
255+
ifout=="":
256+
__class__._throw_error__pg_ctl_returns_an_empty_string(
257+
_params
258+
)
259+
260+
C_PID_PREFIX="(PID: "
261+
262+
i=out.find(C_PID_PREFIX)
263+
264+
ifi==-1:
265+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
266+
out,
267+
_params
268+
)
269+
270+
asserti>0
271+
asserti<len(out)
272+
assertlen(C_PID_PREFIX)<=len(out)
273+
asserti<=len(out)-len(C_PID_PREFIX)
274+
275+
i+=len(C_PID_PREFIX)
276+
start_pid_s=i
277+
278+
whileTrue:
279+
ifi==len(out):
280+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
281+
out,
282+
_params
283+
)
284+
285+
ch=out[i]
286+
287+
ifch==")":
288+
break
289+
290+
ifch.isdigit():
291+
i+=1
292+
continue
293+
294+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
295+
out,
296+
_params
297+
)
298+
assertFalse
299+
300+
ifi==start_pid_s:
301+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
302+
out,
303+
_params
304+
)
305+
306+
# TODO: Let's verify a length of pid string.
307+
308+
pid=int(out[start_pid_s:i])
309+
310+
ifpid==0:
311+
__class__._throw_error__pg_ctl_returns_a_zero_pid(
312+
out,
313+
_params
314+
)
315+
316+
assertpid!=0
317+
returnpid
318+
319+
@staticmethod
320+
def_throw_error__pg_ctl_returns_an_empty_string(_params):
321+
errLines= []
322+
errLines.append("Utility pg_ctl returns empty string.")
323+
errLines.append("Command line is {0}".format(_params))
324+
raiseRuntimeError("\n".join(errLines))
325+
326+
@staticmethod
327+
def_throw_error__pg_ctl_returns_an_unexpected_string(out,_params):
328+
errLines= []
329+
errLines.append("Utility pg_ctl returns an unexpected string:")
330+
errLines.append(out)
331+
errLines.append("------------")
332+
errLines.append("Command line is {0}".format(_params))
333+
raiseRuntimeError("\n".join(errLines))
334+
335+
@staticmethod
336+
def_throw_error__pg_ctl_returns_a_zero_pid(out,_params):
337+
errLines= []
338+
errLines.append("Utility pg_ctl returns a zero pid. Output string is:")
339+
errLines.append(out)
340+
errLines.append("------------")
341+
errLines.append("Command line is {0}".format(_params))
342+
raiseRuntimeError("\n".join(errLines))
219343

220344
@property
221345
defauxiliary_pids(self):
@@ -338,41 +462,84 @@ def version(self):
338462
returnself._pg_version
339463

340464
def_try_shutdown(self,max_attempts,with_force=False):
465+
asserttype(max_attempts)==int# noqa: E721
466+
asserttype(with_force)==bool# noqa: E721
467+
assertmax_attempts>0
468+
341469
attempts=0
470+
471+
# try stopping server N times
472+
whileattempts<max_attempts:
473+
attempts+=1
474+
try:
475+
self.stop()
476+
exceptExecUtilException:
477+
continue# one more time
478+
exceptException:
479+
eprint('cannot stop node {}'.format(self.name))
480+
break
481+
482+
return# OK
483+
484+
# If force stopping is enabled and PID is valid
485+
ifnotwith_force:
486+
return
487+
342488
node_pid=self.pid
489+
assertnode_pidisnotNone
490+
asserttype(node_pid)==int# noqa: E721
343491

344-
ifnode_pid>0:
345-
# try stopping server N times
346-
whileattempts<max_attempts:
347-
try:
348-
self.stop()
349-
break# OK
350-
exceptExecUtilException:
351-
pass# one more time
352-
exceptException:
353-
eprint('cannot stop node {}'.format(self.name))
354-
break
355-
356-
attempts+=1
357-
358-
# If force stopping is enabled and PID is valid
359-
ifwith_forceandnode_pid!=0:
360-
# If we couldn't stop the node
361-
p_status_output=self.os_ops.exec_command(cmd=f'ps -o pid= -p{node_pid}',shell=True,ignore_errors=True).decode('utf-8')
362-
ifself.status()!=NodeStatus.Stoppedandp_status_outputandstr(node_pid)inp_status_output:
363-
try:
364-
eprint(f'Force stopping node{self.name} with PID{node_pid}')
365-
self.os_ops.kill(node_pid,signal.SIGKILL,expect_error=False)
366-
exceptException:
367-
# The node has already stopped
368-
pass
369-
370-
# Check that node stopped - print only column pid without headers
371-
p_status_output=self.os_ops.exec_command(f'ps -o pid= -p{node_pid}',shell=True,ignore_errors=True).decode('utf-8')
372-
ifp_status_outputandstr(node_pid)inp_status_output:
373-
eprint(f'Failed to stop node{self.name}.')
374-
else:
375-
eprint(f'Node{self.name} has been stopped successfully.')
492+
ifnode_pid==0:
493+
return
494+
495+
# TODO: [2025-02-28] It is really the old ugly code. We have to rewrite it!
496+
497+
ps_command= ['ps','-o','pid=','-p',str(node_pid)]
498+
499+
ps_output=self.os_ops.exec_command(cmd=ps_command,shell=True,ignore_errors=True).decode('utf-8')
500+
asserttype(ps_output)==str# noqa: E721
501+
502+
ifps_output=="":
503+
return
504+
505+
ifps_output!=str(node_pid):
506+
__class__._throw_bugcheck__unexpected_result_of_ps(
507+
ps_output,
508+
ps_command)
509+
510+
try:
511+
eprint('Force stopping node {0} with PID {1}'.format(self.name,node_pid))
512+
self.os_ops.kill(node_pid,signal.SIGKILL,expect_error=False)
513+
exceptException:
514+
# The node has already stopped
515+
pass
516+
517+
# Check that node stopped - print only column pid without headers
518+
ps_output=self.os_ops.exec_command(cmd=ps_command,shell=True,ignore_errors=True).decode('utf-8')
519+
asserttype(ps_output)==str# noqa: E721
520+
521+
ifps_output=="":
522+
eprint('Node {0} has been stopped successfully.'.format(self.name))
523+
return
524+
525+
ifps_output==str(node_pid):
526+
eprint('Failed to stop node {0}.'.format(self.name))
527+
return
528+
529+
__class__._throw_bugcheck__unexpected_result_of_ps(
530+
ps_output,
531+
ps_command)
532+
533+
@staticmethod
534+
def_throw_bugcheck__unexpected_result_of_ps(result,cmd):
535+
asserttype(result)==str# noqa: E721
536+
asserttype(cmd)==list# noqa: E721
537+
errLines= []
538+
errLines.append("[BUG CHECK] Unexpected result of command ps:")
539+
errLines.append(result)
540+
errLines.append("-----")
541+
errLines.append("Command line is {0}".format(cmd))
542+
raiseRuntimeError("\n".join(errLines))
376543

377544
def_assign_master(self,master):
378545
"""NOTE: this is a private method!"""

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp