Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0402c4a

Browse files
PostgresNode::pid uses the data from "pg_ctl status" output.
1 parent ab28c2e commit 0402c4a

File tree

2 files changed

+130
-31
lines changed

2 files changed

+130
-31
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: 126 additions & 31 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 .consts import \
5557
MAX_LOGICAL_REPLICATION_WORKERS, \
@@ -132,9 +134,6 @@ class PostgresNode(object):
132134
# a max number of node start attempts
133135
_C_MAX_START_ATEMPTS = 5
134136

135-
# a max number of read pid file attempts
136-
_C_MAX_GET_PID_ATEMPTS = 5
137-
138137
def __init__(self, name=None, base_dir=None, port=None, conn_params: ConnectionParams = ConnectionParams(),
139138
bin_dir=None, prefix=None):
140139
"""
@@ -211,40 +210,136 @@ def pid(self):
211210
Return postmaster's PID if node is running, else 0.
212211
"""
213212

214-
nAttempt = 0
215-
pid_file = os.path.join(self.data_dir, PG_PID_FILE)
216-
pid_s: str = None
213+
self__data_dir = self.data_dir
214+
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+
assert type(status_code) == int # noqa: E721
229+
assert type(out) == str # noqa: E721
230+
assert type(error) == str # noqa: E721
231+
232+
# -----------------
233+
if status_code == PG_CTL__STATUS__NODE_IS_STOPPED:
234+
return 0
235+
236+
# -----------------
237+
if status_code == PG_CTL__STATUS__BAD_DATADIR:
238+
return 0
239+
240+
# -----------------
241+
if status_code != PG_CTL__STATUS__OK:
242+
errMsg = "Getting of a node status [data_dir is {0}] failed.".format(self__data_dir)
243+
244+
raise ExecUtilException(
245+
message=errMsg,
246+
command=_params,
247+
exit_code=status_code,
248+
out=out,
249+
error=error,
250+
)
251+
252+
# -----------------
253+
assert status_code == PG_CTL__STATUS__OK
254+
255+
if out == "":
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+
if i == -1:
265+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
266+
out,
267+
_params
268+
)
269+
270+
assert i > 0
271+
assert i < len(out)
272+
assert len(C_PID_PREFIX) <= len(out)
273+
assert i <= len(out) - len(C_PID_PREFIX)
274+
275+
i += len(C_PID_PREFIX)
276+
start_pid_s = i
277+
217278
while True:
218-
if nAttempt == __class__._C_MAX_GET_PID_ATEMPTS:
219-
errMsg = "Can't read postmaster pid file [{0}].".format(pid_file)
220-
raise Exception(errMsg)
279+
if i == len(out):
280+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
281+
out,
282+
_params
283+
)
221284

222-
nAttempt += 1
285+
ch = out[i]
223286

224-
s1 = self.status()
225-
if s1 != NodeStatus.Running:
226-
return 0
287+
if ch == ")":
288+
break
227289

228-
try:
229-
lines = self.os_ops.readlines(pid_file)
230-
except Exception:
231-
s2 = self.status()
232-
if s2 == NodeStatus.Running:
233-
raise
234-
return 0
235-
236-
assert lines is not None # [2025-02-27] OK?
237-
assert type(lines) == list # noqa: E721
238-
if len(lines) == 0:
290+
if ch.isdigit():
291+
i += 1
239292
continue
240293

241-
pid_s = lines[0]
242-
assert type(pid_s) == str # noqa: E721
243-
if len(pid_s) == 0:
244-
continue
294+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
295+
out,
296+
_params
297+
)
298+
assert False
299+
300+
if i == start_pid_s:
301+
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
302+
out,
303+
_params
304+
)
245305

246-
pid = int(pid_s)
247-
return pid
306+
# TODO: Let's verify a length of pid string.
307+
308+
pid = int(out[start_pid_s:i])
309+
310+
if pid == 0:
311+
__class__._throw_error__pg_ctl_returns_a_zero_pid(
312+
out,
313+
_params
314+
)
315+
316+
assert pid != 0
317+
return pid
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+
raise RuntimeError("\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+
raise RuntimeError("\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+
raise RuntimeError("\n".join(errLines))
248343

249344
@property
250345
def auxiliary_pids(self):

0 commit comments

Comments
 (0)